From: luukkainen Date: Fri, 5 Jul 2013 10:39:33 +0000 (+0000) Subject: 3D framework (Simca 2012) X-Git-Tag: simantics-1.19.0~8 X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=commitdiff_plain;h=87b3241ec277ba3d8e414b26186a032c9cdcaeed;p=simantics%2F3d.git 3D framework (Simca 2012) refs #4378 git-svn-id: https://www.simantics.org/svn/simantics/3d/trunk@27689 ac1ea38d-2e2b-0410-8846-a27921b304fc --- diff --git a/org.simantics.g3d.csg.ontology/.classpath b/org.simantics.g3d.csg.ontology/.classpath new file mode 100644 index 00000000..8a8f1668 --- /dev/null +++ b/org.simantics.g3d.csg.ontology/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/org.simantics.g3d.csg.ontology/.project b/org.simantics.g3d.csg.ontology/.project new file mode 100644 index 00000000..75a8dd12 --- /dev/null +++ b/org.simantics.g3d.csg.ontology/.project @@ -0,0 +1,34 @@ + + + org.simantics.g3d.csg.ontology + + + + + + org.simantics.graph.builder + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + org.simantics.graph.nature + + diff --git a/org.simantics.g3d.csg.ontology/.settings/org.eclipse.jdt.core.prefs b/org.simantics.g3d.csg.ontology/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000..da2e9609 --- /dev/null +++ b/org.simantics.g3d.csg.ontology/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,8 @@ +#Tue Dec 13 11:35:42 EET 2011 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/org.simantics.g3d.csg.ontology/META-INF/MANIFEST.MF b/org.simantics.g3d.csg.ontology/META-INF/MANIFEST.MF new file mode 100644 index 00000000..7fdef4a2 --- /dev/null +++ b/org.simantics.g3d.csg.ontology/META-INF/MANIFEST.MF @@ -0,0 +1,17 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: CSG Ontology +Bundle-SymbolicName: org.simantics.g3d.csg.ontology +Bundle-Version: 1.0.0.qualifier +Bundle-Vendor: VTT +Require-Bundle: org.eclipse.core.runtime, + org.simantics.g3d.ontology;bundle-version="1.0.0", + org.simantics.layer0;bundle-version="1.0.0", + org.simantics.viewpoint.ontology;bundle-version="1.0.0", + org.simantics.project.ontology;bundle-version="1.0.0", + org.simantics.image2.ontology;bundle-version="1.0.0", + org.simantics.action.ontology;bundle-version="1.0.0", + org.simantics.selectionview.ontology;bundle-version="1.0.0", + org.simantics.simulation.ontology;bundle-version="1.0.0" +Bundle-RequiredExecutionEnvironment: JavaSE-1.6 +Export-Package: org.simantics.g3d.csg.ontology diff --git a/org.simantics.g3d.csg.ontology/build.properties b/org.simantics.g3d.csg.ontology/build.properties new file mode 100644 index 00000000..ecdc7c30 --- /dev/null +++ b/org.simantics.g3d.csg.ontology/build.properties @@ -0,0 +1,5 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + graph.tg diff --git a/org.simantics.g3d.csg.ontology/graph.tg b/org.simantics.g3d.csg.ontology/graph.tg new file mode 100644 index 00000000..5c532de4 Binary files /dev/null and b/org.simantics.g3d.csg.ontology/graph.tg differ diff --git a/org.simantics.g3d.csg.ontology/graph/csg.pgraph b/org.simantics.g3d.csg.ontology/graph/csg.pgraph new file mode 100644 index 00000000..1a0f67c9 --- /dev/null +++ b/org.simantics.g3d.csg.ontology/graph/csg.pgraph @@ -0,0 +1,91 @@ +L0 = +G3D = + +CSG = : L0.Ontology + @L0.new + L0.HasResourceClass "org.simantics.g3d.csg.ontology.CSG" + +CSG.Shape +VP = +CSG = +PROJ = +SIM = +IMAGE = +ACT = +G3D = +SEL = + +CBC = CSG.CSGBrowseContext : VP.BrowseContext + //VP.BrowseContext.IsIncludedIn PROJ.ProjectBrowseContext + @VP.constantImageRule CSG.Union IMAGES.Union + @VP.constantImageRule CSG.Difference IMAGES.Difference + @VP.constantImageRule CSG.Intersection IMAGES.Intersection + @VP.constantImageRule CSG.Primitive IMAGES.Ruby + @VP.constantImageRule CSG.Model IMAGES.Ruby + @VP.relationChildRule CSG.Model G3D.nodes CSG.Shape + @VP.relationChildRule CSG.Shape G3D.nodes CSG.Shape + @VP.relationChildRule PROJ.Project L0.ConsistsOf CSG.Model + +IMAGES = CSG.Images : L0.Library +IMAGES.Union : IMAGE.PngImage + @L0.loadBytes "images/union.png" +IMAGES.Difference : IMAGE.PngImage + @L0.loadBytes "images/difference.png" +IMAGES.Intersection : IMAGE.PngImage + @L0.loadBytes "images/intersection.png" +IMAGES.Ruby : IMAGE.PngImage + @L0.loadBytes "images/ruby.png" + +CBC.ShapeTabContribution () { + public CSG perform(ReadGraph graph) throws DatabaseException { + QueryControl qc = graph.getService(QueryControl.class); + return new CSG(qc.getIndependentGraph(graph)); + } + }); + session.registerService(CSG.class, ret); + } + return ret; + } + +} + diff --git a/org.simantics.g3d.csg/.classpath b/org.simantics.g3d.csg/.classpath new file mode 100644 index 00000000..8a8f1668 --- /dev/null +++ b/org.simantics.g3d.csg/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/org.simantics.g3d.csg/.project b/org.simantics.g3d.csg/.project new file mode 100644 index 00000000..ab3f164f --- /dev/null +++ b/org.simantics.g3d.csg/.project @@ -0,0 +1,28 @@ + + + org.simantics.g3d.csg + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/org.simantics.g3d.csg/.settings/org.eclipse.jdt.core.prefs b/org.simantics.g3d.csg/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000..56c2dc85 --- /dev/null +++ b/org.simantics.g3d.csg/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,8 @@ +#Mon Dec 12 16:51:11 EET 2011 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/org.simantics.g3d.csg/META-INF/MANIFEST.MF b/org.simantics.g3d.csg/META-INF/MANIFEST.MF new file mode 100644 index 00000000..a0a1c81b --- /dev/null +++ b/org.simantics.g3d.csg/META-INF/MANIFEST.MF @@ -0,0 +1,26 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Csg +Bundle-SymbolicName: org.simantics.g3d.csg;singleton:=true +Bundle-Version: 1.0.0.qualifier +Bundle-Activator: org.simantics.g3d.csg.Activator +Bundle-Vendor: VTT +Require-Bundle: org.eclipse.core.runtime, + org.simantics.g3d;bundle-version="1.0.0", + org.simantics.g3d.ontology;bundle-version="1.0.0", + org.simantics.db.layer0;bundle-version="1.1.0", + javax.vecmath;bundle-version="1.5.2", + org.simantics.opencascade;bundle-version="1.0.0", + org.simantics.ui;bundle-version="1.0.0", + vtk;bundle-version="1.0.0", + org.eclipse.ui, + org.simantics.g3d.csg.ontology;bundle-version="1.0.0", + org.simantics.selectionview;bundle-version="1.0.0", + org.eclipse.ui.views;bundle-version="3.5.1", + org.jcae.opencascade;bundle-version="1.0.0", + org.simantics.g3d.vtk;bundle-version="1.0.0", + org.simantics.browsing.ui.common;bundle-version="1.1.0", + org.simantics.objmap2;bundle-version="1.0.0", + org.simantics.opencascade.vtk;bundle-version="1.0.0" +Bundle-RequiredExecutionEnvironment: JavaSE-1.6 +Bundle-ActivationPolicy: lazy diff --git a/org.simantics.g3d.csg/adapters.xml b/org.simantics.g3d.csg/adapters.xml new file mode 100644 index 00000000..cfa703bd --- /dev/null +++ b/org.simantics.g3d.csg/adapters.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.simantics.g3d.csg/build.properties b/org.simantics.g3d.csg/build.properties new file mode 100644 index 00000000..95ac1cc1 --- /dev/null +++ b/org.simantics.g3d.csg/build.properties @@ -0,0 +1,6 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + plugin.xml,\ + adapters.xml diff --git a/org.simantics.g3d.csg/plugin.xml b/org.simantics.g3d.csg/plugin.xml new file mode 100644 index 00000000..d167ef35 --- /dev/null +++ b/org.simantics.g3d.csg/plugin.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/Activator.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/Activator.java new file mode 100644 index 00000000..e2a06515 --- /dev/null +++ b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/Activator.java @@ -0,0 +1,46 @@ +package org.simantics.g3d.csg; + +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.BundleContext; + +public class Activator extends AbstractUIPlugin { + + // The plug-in ID + public static final String PLUGIN_ID = "org.simantics.g3d.csg"; //$NON-NLS-1$ + + // The shared instance + private static Activator plugin; + + /** + * The constructor + */ + public Activator() { + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext) + */ + public void start(BundleContext context) throws Exception { + super.start(context); + plugin = this; + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext) + */ + public void stop(BundleContext context) throws Exception { + plugin = null; + super.stop(context); + } + + /** + * Returns the shared instance + * + * @return the shared instance + */ + public static Activator getDefault() { + return plugin; + } +} diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/actions/AddBooleanOpAction2.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/actions/AddBooleanOpAction2.java new file mode 100644 index 00000000..6d6cff90 --- /dev/null +++ b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/actions/AddBooleanOpAction2.java @@ -0,0 +1,69 @@ +package org.simantics.g3d.csg.actions; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import javax.vecmath.Quat4d; +import javax.vecmath.Vector3d; + +import org.eclipse.jface.action.Action; +import org.simantics.g3d.csg.scenegraph2.CSGparentNode; +import org.simantics.g3d.csg.scenegraph2.CSGrootNode; +import org.simantics.g3d.csg.scenegraph2.ICSGnode; +import org.simantics.utils.ui.ExceptionUtils; + +public class AddBooleanOpAction2 extends Action { + CSGrootNode root; + Class booleanClass; + Collection nodes; + + public AddBooleanOpAction2(CSGrootNode root, Class booleanClass, Collection nodes) { + super(); + String name = booleanClass.getSimpleName(); + if (name.endsWith("Node")) + name = name.substring(0,name.length()-4); + setText(name); + this.booleanClass = booleanClass; + this.nodes = nodes; + this.root = root; + if (nodes.size() != 2) + setEnabled(false); + for (ICSGnode node : nodes) { + if (!node.getParent().equals(root)) + setEnabled(false); + } + } + + @Override + public void run() { + try { + CSGparentNode booleanNode = booleanClass.newInstance(); + Map positions = new HashMap(); + Map orientations = new HashMap(); + for (ICSGnode node : nodes) { + positions.put(node, node.getWorldPosition()); + orientations.put(node, node.getWorldOrientation()); + //root.remChild(node); + node.deattach(); + } + Iterator iter = nodes.iterator(); + booleanNode.addPrimaryChild(iter.next()); + booleanNode.addSecondaryChild(iter.next()); + + String name = root.getUniqueName(booleanNode.getClass().getSimpleName()); + booleanNode.setName(name); + + root.addChild(booleanNode); + for (ICSGnode node : nodes) { + node.setWorldPosition(positions.get(node)); + node.setWorldOrientation(orientations.get(node)); + } + root.getNodeMap().commit(); + } catch (Exception e) { + ExceptionUtils.logAndShowError("Cannot create boolean operation.", e); + } + } + +} diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/actions/AddPrimitiveAction2.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/actions/AddPrimitiveAction2.java new file mode 100644 index 00000000..b3687f39 --- /dev/null +++ b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/actions/AddPrimitiveAction2.java @@ -0,0 +1,35 @@ +package org.simantics.g3d.csg.actions; + +import org.eclipse.jface.action.Action; +import org.simantics.g3d.csg.scenegraph2.CSGnode; +import org.simantics.g3d.csg.scenegraph2.CSGrootNode; +import org.simantics.utils.ui.ExceptionUtils; + +public class AddPrimitiveAction2 extends Action { + + CSGrootNode root; + Class primitiveClass; + public AddPrimitiveAction2(CSGrootNode root, Class primitiveClass) { + super(); + String name = primitiveClass.getSimpleName(); + if (name.endsWith("Node")) + name = name.substring(0,name.length()-4); + setText(name); + this.primitiveClass = primitiveClass; + this.root = root; + } + + @Override + public void run() { + try { + CSGnode node = primitiveClass.newInstance(); + String name = root.getUniqueName(node.getClass().getSimpleName()); + node.setName(name); + root.addChild(node); + root.getNodeMap().commit(); + } catch (Exception e) { + ExceptionUtils.logAndShowError("Cannot create primitive.", e); + } + } + +} diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/actions/SplitBooleanOpAction2.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/actions/SplitBooleanOpAction2.java new file mode 100644 index 00000000..57e7d032 --- /dev/null +++ b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/actions/SplitBooleanOpAction2.java @@ -0,0 +1,49 @@ +package org.simantics.g3d.csg.actions; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import javax.vecmath.Quat4d; +import javax.vecmath.Vector3d; + +import org.eclipse.jface.action.Action; +import org.simantics.g3d.csg.scenegraph2.CSGparentNode; +import org.simantics.g3d.csg.scenegraph2.CSGrootNode; +import org.simantics.g3d.csg.scenegraph2.ICSGnode; + +public class SplitBooleanOpAction2 extends Action { + private CSGrootNode root; + private CSGparentNode booleanOp; + + public SplitBooleanOpAction2(CSGrootNode root, CSGparentNode booleanOp) { + super(); + setText("Split"); + this.booleanOp = booleanOp; + this.root = root; + } + + @Override + public void run() { + Collection nodes = new ArrayList(); + nodes.addAll(booleanOp.getPrimaryChild()); + nodes.addAll(booleanOp.getSecondaryChild()); + Map positions = new HashMap(); + Map orientations = new HashMap(); + for (ICSGnode node : nodes) { + positions.put(node, node.getWorldPosition()); + orientations.put(node, node.getWorldOrientation()); + node.deattach(); + } + for (ICSGnode node : nodes) { + root.addChild(node); + node.setWorldPosition(positions.get(node)); + node.setWorldOrientation(orientations.get(node)); + } + root.remChild(booleanOp); + root.getNodeMap().commit(); + + } + +} diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/adapters/CSGSolidModelAdapter.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/adapters/CSGSolidModelAdapter.java new file mode 100644 index 00000000..30e4991d --- /dev/null +++ b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/adapters/CSGSolidModelAdapter.java @@ -0,0 +1,83 @@ +package org.simantics.g3d.csg.adapters; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import org.eclipse.core.runtime.IAdaptable; +import org.jcae.opencascade.jni.TopoDS_Shape; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.request.Read; +import org.simantics.g3d.csg.scenegraph2.CSGrootNode; +import org.simantics.g3d.csg.scenegraph2.ICSGnode; +import org.simantics.g3d.csg.scenegraph2.SchemaBuilder; +import org.simantics.objmap.graph.IMapping; +import org.simantics.objmap.graph.Mappings; +import org.simantics.objmap.graph.schema.IMappingSchema; +import org.simantics.objmap.structural.IStructuralObject; +import org.simantics.opencascade.SolidModelProvider; +import org.simantics.ui.SimanticsUI; + +public class CSGSolidModelAdapter implements SolidModelProvider, IAdaptable, IStructuralObject { + + private Resource model; + + public CSGSolidModelAdapter(Resource model) { + this.model = model; + } + + @Override + public Collection getModel() throws Exception { + return SimanticsUI.getSession().syncRequest(new Read>() { + @Override + public Collection perform(ReadGraph graph) + throws DatabaseException { + Collection shapes = new ArrayList(); + IMappingSchema schema = SchemaBuilder.getSchema(graph); + IMapping mapping = Mappings.createWithoutListening(schema); + CSGrootNode rootNode = (CSGrootNode)mapping.map(graph, model); + for (ICSGnode node : rootNode.getNodes("child")) { + TopoDS_Shape shape = node.getGeometry(); + if (shape != null) + shapes.add(shape); + } + // FIXME: clear CSG scene-graph + return shapes; + } + }); + + } + + @SuppressWarnings("rawtypes") + @Override + public Object getAdapter(Class adapter) { + if (Resource.class.equals(adapter)) + return model; + return null; + } + + @SuppressWarnings("unchecked") + @Override + public List getContext() { + return Collections.EMPTY_LIST; + } + + @Override + public Resource getType() { + return null; + } + + @Override + public void setContext(List object) { + throw new RuntimeException(); + } + + @Override + public void setType(Resource type) { + throw new RuntimeException(); + } + +} diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/adapters/NodeRemover.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/adapters/NodeRemover.java new file mode 100644 index 00000000..73ce0553 --- /dev/null +++ b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/adapters/NodeRemover.java @@ -0,0 +1,30 @@ +package org.simantics.g3d.csg.adapters; + +import java.util.Map; + +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.WriteGraph; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.layer0.adapter.Remover; + +public class NodeRemover implements Remover { + + //private Resource node; + + public NodeRemover(Resource node) { + //this.node = node; + } + + @Override + public String canRemove(ReadGraph graph, Map aux) + throws DatabaseException { + return "Removing scene-graph nodes from model browser is not supported."; + } + + @Override + public void remove(WriteGraph graph) throws DatabaseException { + + } + +} diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/editor/CSGEditor2.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/editor/CSGEditor2.java new file mode 100644 index 00000000..c1f7c518 --- /dev/null +++ b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/editor/CSGEditor2.java @@ -0,0 +1,429 @@ +package org.simantics.g3d.csg.editor; + +import java.awt.Component; +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.IMenuListener; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.MenuManager; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.DisposeEvent; +import org.eclipse.swt.events.DisposeListener; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.ui.views.contentoutline.IContentOutlinePage; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.common.request.ReadRequest; +import org.simantics.db.exception.DatabaseException; +import org.simantics.g3d.csg.actions.AddBooleanOpAction2; +import org.simantics.g3d.csg.actions.AddPrimitiveAction2; +import org.simantics.g3d.csg.actions.SplitBooleanOpAction2; +import org.simantics.g3d.csg.scenegraph2.BarrelNode; +import org.simantics.g3d.csg.scenegraph2.BoxNode; +import org.simantics.g3d.csg.scenegraph2.CSGparentNode; +import org.simantics.g3d.csg.scenegraph2.CSGrootNode; +import org.simantics.g3d.csg.scenegraph2.ConeNode; +import org.simantics.g3d.csg.scenegraph2.CylinderNode; +import org.simantics.g3d.csg.scenegraph2.DifferenceNode; +import org.simantics.g3d.csg.scenegraph2.EllipticCylinderNode; +import org.simantics.g3d.csg.scenegraph2.ICSGnode; +import org.simantics.g3d.csg.scenegraph2.IntersectionNode; +import org.simantics.g3d.csg.scenegraph2.RectangularSolidNode; +import org.simantics.g3d.csg.scenegraph2.RegularPrismNode; +import org.simantics.g3d.csg.scenegraph2.SchemaBuilder; +import org.simantics.g3d.csg.scenegraph2.SphereNode; +import org.simantics.g3d.csg.scenegraph2.TorusNode; +import org.simantics.g3d.csg.scenegraph2.UnionNode; +import org.simantics.g3d.scenegraph.IG3DNode; +import org.simantics.g3d.scenegraph.NodeMap; +import org.simantics.g3d.scenegraph.base.INode; +import org.simantics.g3d.vtk.action.RemoveAction; +import org.simantics.g3d.vtk.action.RotateAction; +import org.simantics.g3d.vtk.action.TranslateAction; +import org.simantics.g3d.vtk.action.vtkCameraAndSelectorAction; +import org.simantics.g3d.vtk.common.HoverHighlighter; +import org.simantics.g3d.vtk.common.InteractiveVtkPanel; +import org.simantics.g3d.vtk.common.NodeSelectionProvider2; +import org.simantics.g3d.vtk.common.SelectionHighlighter; +import org.simantics.g3d.vtk.common.VTKContentOutlinePage; +import org.simantics.g3d.vtk.shape.vtkShape; +import org.simantics.g3d.vtk.utils.vtkPanelUtil; +import org.simantics.objmap.graph.IMapping; +import org.simantics.objmap.graph.Mappings; +import org.simantics.objmap.graph.schema.IMappingSchema; +import org.simantics.selectionview.StandardPropertyPage; +import org.simantics.ui.workbench.IPropertyPage; +import org.simantics.ui.workbench.IResourceEditorInput; +import org.simantics.ui.workbench.ResourceEditorPart; +import org.simantics.utils.threads.AWTThread; +import org.simantics.utils.threads.ThreadUtils; +import org.simantics.utils.ui.ExceptionUtils; +import org.simantics.utils.ui.SWTAWTComponent; + +import vtk.vtkActor; +import vtk.vtkCameraPass; +import vtk.vtkDefaultPass; +import vtk.vtkLightsPass; +import vtk.vtkRenderPassCollection; +import vtk.vtkRenderer; +import vtk.vtkSequencePass; + +public class CSGEditor2 extends ResourceEditorPart { + private Composite parent; + private Resource input; + private InteractiveVtkPanel panel; + private SWTAWTComponent component; + + private CSGrootNode rootNode; + private IMapping mapping; + + private NodeSelectionProvider2 selectionProvider; + + private vtkCameraAndSelectorAction cameraAction; + private TranslateAction translateAction; + private RotateAction rotateAction; + private RemoveAction removeAction; + + //private ScenegraphOutlinePage outlinePage; + + private CSGNodeMap nodeMap; + + + + @Override + public void createPartControl(Composite parent) { + this.parent = parent; + parent.setLayout (new FillLayout ()); + component = new SWTAWTComponent(parent,SWT.NONE) { + + @Override + protected Component createSwingComponent() { + if (panel == null) { + panel = new InteractiveVtkPanel(); + vtkPanelUtil.registerPanel(panel); + createScene(); + } + return panel; + } + }; + + IResourceEditorInput rei = (IResourceEditorInput)getEditorInput(); + input = rei.getResource(); + + + //IActionBars actionBars = getEditorSite().getActionBars(); + + hookContextMenu(); + + component.syncPopulate(); + + panel.addMouseListener(new java.awt.event.MouseAdapter() { + @Override + public void mouseClicked(final java.awt.event.MouseEvent e) { + if (e.getButton() == java.awt.event.MouseEvent.BUTTON3) { + Display.getDefault().asyncExec(new Runnable() { + public void run() { + contextMenu.setLocation(e.getXOnScreen(), e.getYOnScreen()); + contextMenu.setVisible(true); + } + }); + } + } + }); + + + cameraAction = new vtkCameraAndSelectorAction(panel); + panel.setDefaultAction(cameraAction); + panel.useDefaultAction(); + + try { + getSession().syncRequest(new ReadRequest() { + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public void run(ReadGraph graph) throws DatabaseException { + IMappingSchema schema = SchemaBuilder.getSchema(graph); + mapping = Mappings.createWithListening(schema); + rootNode = (CSGrootNode)mapping.map(graph, input); + nodeMap = new CSGNodeMap(getSession(), mapping, panel,(CSGrootNode)rootNode); + } + }); + + if (rootNode == null) + throw new RuntimeException("Scenegraph loading failed."); + populate(); + + selectionProvider = new NodeSelectionProvider2(this,mapping,nodeMap); + + cameraAction.addSelectionChangedListener(selectionProvider); + + cameraAction.addHoverChangedListener(new HoverHighlighter(panel,nodeMap)); + selectionProvider.addSelectionChangedListener(new SelectionHighlighter(panel,nodeMap)); + + getSite().setSelectionProvider(selectionProvider); + getSite().getPage().addPostSelectionListener(selectionProvider); + + //outlinePage = new ScenegraphOutlinePage(rootNode); + + + parent.addDisposeListener(new DisposeListener() { + + @Override + public void widgetDisposed(DisposeEvent e) { + getSite().getPage().removePostSelectionListener(selectionProvider); + ThreadUtils.asyncExec(AWTThread.getThreadAccess(), new Runnable() { + + @Override + public void run() { + nodeMap.delete(); + vtkPanelUtil.unregisterPanel(panel); + + } + }); + mapping.dispose(); + component.dispose(); + + + } + }); + } catch (DatabaseException e1) { + ExceptionUtils.logAndShowError("Cannot open CSG editor",e1); + return; + } + + translateAction = new TranslateAction(panel,nodeMap); + rotateAction = new RotateAction(panel,nodeMap); + removeAction = new RemoveAction(nodeMap) { + public void setNode(IG3DNode node) { + super.setNode(node); + if (node.getParent() instanceof CSGparentNode) + setEnabled(false); + + } + }; + + + } + + + + + public void populate() { + ThreadUtils.asyncExec(AWTThread.getThreadAccess(), new Runnable() { + + @Override + public void run() { + nodeMap.populate(); + } + }); + + } + + + + @Override + public void setFocus() { + component.setFocus(); + } + + private void createScene() { + vtkRenderer ren1 = panel.GetRenderer(); + + boolean multiPass = false; + if (multiPass) { + + vtkLightsPass lightsPass = new vtkLightsPass(); + vtkDefaultPass defaultPass = new vtkDefaultPass(); + + + vtkRenderPassCollection passes = new vtkRenderPassCollection(); + passes.AddItem(lightsPass); + passes.AddItem(defaultPass); + + vtkSequencePass seq = new vtkSequencePass(); + seq.SetPasses(passes); + + + + vtkCameraPass cameraPass = new vtkCameraPass(); + cameraPass.SetDelegatePass(seq); + + ren1.SetPass(cameraPass); + + } +// ren1.GetRenderWindow().LineSmoothingOn(); +// ren1.GetRenderWindow().PointSmoothingOn(); +// ren1.GetRenderWindow().PolygonSmoothingOn(); +// ren1.GetRenderWindow().SetMultiSamples(2); + + + + ren1.SetBackground2(1,1,1); // background color white + ren1.SetBackground(0.9,0.9,0.9); + ren1.SetGradientBackground(true); + + // vtkActor grid = vtkShape.createGridActor(8,1.0,1|2|4); + vtkActor grid = vtkShape.createGridActor(8,1.0, 2 ); + grid.SetPickable(0); + ren1.AddActor(grid); + panel.addDeletable(grid); + + + + } + + protected Menu contextMenu; + + protected void hookContextMenu() { + MenuManager menuMgr = new MenuManager("#PopupMenu"); + menuMgr.setRemoveAllWhenShown(true); + menuMgr.addMenuListener(new IMenuListener() { + public void menuAboutToShow(IMenuManager manager) { + final IMenuManager m = manager; + List selected = selectionProvider.getSelectedNodes(); + if (selected.size() == 0) { + m.add(new AddPrimitiveAction2(rootNode, BarrelNode.class)); + m.add(new AddPrimitiveAction2(rootNode, BoxNode.class)); + m.add(new AddPrimitiveAction2(rootNode, ConeNode.class)); + m.add(new AddPrimitiveAction2(rootNode, CylinderNode.class)); + m.add(new AddPrimitiveAction2(rootNode, EllipticCylinderNode.class)); + m.add(new AddPrimitiveAction2(rootNode, RectangularSolidNode.class)); + m.add(new AddPrimitiveAction2(rootNode, RegularPrismNode.class)); + m.add(new AddPrimitiveAction2(rootNode, SphereNode.class)); + m.add(new AddPrimitiveAction2(rootNode, TorusNode.class)); + } else if (selected.size() == 1) { + m.add(translateAction); + m.add(rotateAction); + m.add(removeAction); + ICSGnode node = (ICSGnode)selected.get(0); + translateAction.setNode(node); + rotateAction.setNode(node); + removeAction.setNode(node); + if (node instanceof CSGparentNode) { + m.add(new SplitBooleanOpAction2(rootNode,(CSGparentNode)node)); + } + } else if (selected.size() == 2) { + if (selected.get(0).getParent().equals(rootNode) && selected.get(1).getParent().equals(rootNode)) { + Collection nodes = new ArrayList(); + for (IG3DNode n : selected) + nodes.add((ICSGnode)n); + m.add(new AddBooleanOpAction2(rootNode, DifferenceNode.class, nodes)); + m.add(new AddBooleanOpAction2(rootNode, IntersectionNode.class, nodes)); + m.add(new AddBooleanOpAction2(rootNode, UnionNode.class, nodes)); + } + } +// try { +// SimanticsUI.getSession().syncRequest(new ReadRequest() { +// +// @Override +// public void run(ReadGraph graph) throws DatabaseException { +// Layer0 l0 = Layer0.getInstance(graph); +// CSG csg = CSG.getInstance(graph); +// Resource ontology = graph.getResource("http://www.simantics.org/CSG-0.1"); +// +// if (selectionProvider.getSelectedResources().size() == 0) { +// List primitives = new ArrayList(); +// for (Resource r : graph.getObjects(ontology, l0.ConsistsOf)) { +// if (graph.isInheritedFrom(r, csg.Primitive) && !r.equals(csg.Primitive)) { +// primitives.add(new NamedResource((String)graph.getRelatedValue(r, l0.HasName), r)); +// } +// } +// +// Collections.sort(primitives); +// for (NamedResource n : primitives) { +// m.add(new AddPrimitiveAction(graph, n.getResource(),input)); +// } +// } +// if (selectionProvider.getSelectedResources().size() == 2) { +// List booleanOps = new ArrayList(); +// for (Resource r : graph.getObjects(ontology, l0.ConsistsOf)) { +// if (graph.isInheritedFrom(r, csg.BooleanOperation) && !r.equals(csg.BooleanOperation)) { +// booleanOps.add(new NamedResource((String)graph.getRelatedValue(r, l0.HasName), r)); +// } +// } +// +// Collections.sort(booleanOps); +// for (NamedResource n : booleanOps) { +// m.add(new AddBooleanOpAction(graph, n.getResource(), input, selectionProvider.getSelectedResources())); +// } +// } +// if (selectionProvider.getSelectedResources().size() == 1) { +// m.add(translateAction); +// m.add(rotateAction); +// m.add(removeAction); +// Resource selected = selectionProvider.getSelectedResources().get(0); +// translateAction.setNode((IG3DNode2)mapping.get(selected)); +// rotateAction.setNode((IG3DNode2)mapping.get(selected)); +// removeAction.setNode((IG3DNode2)mapping.get(selected)); +// if (graph.isInstanceOf(selected, csg.BooleanOperation)) { +// m.add(new SplitBooleanOpAction(input,selected)); +// } +// +// +// } +// +// } +// }); +// } catch (DatabaseException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } + + } + }); + + contextMenu = menuMgr.createContextMenu(parent); + } + + private IContentOutlinePage createOutline() { + if (rootNode == null || selectionProvider == null) + return null; + IContentOutlinePage outlinePage = new VTKContentOutlinePage(rootNode, selectionProvider); + outlinePage.addSelectionChangedListener(new ISelectionChangedListener() { + + @Override + public void selectionChanged(SelectionChangedEvent event) { + selectionProvider.selectionChanged(event); + } + }); + return outlinePage; + } + + @SuppressWarnings("rawtypes") + @Override + public Object getAdapter(Class adapter) { + if (IPropertyPage.class.equals(adapter)) + return new StandardPropertyPage(getSite(),getPropertyContexts()); + if (IContentOutlinePage.class.equals(adapter)) { + return createOutline(); + } + if (NodeMap.class.equals(adapter)) { + return nodeMap; + } + if (INode.class.equals(adapter)) { + return rootNode; + } + if (IMapping.class.equals(adapter)) { + return mapping; + } + if (InteractiveVtkPanel.class.equals(adapter)) { + return panel; + } + return super.getAdapter(adapter); + } + + public Set getPropertyContexts() { + Set result = new HashSet(); + result.add("http://www.simantics.org/Project-1.0/ProjectBrowseContext"); + return result; + } +} diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/editor/CSGNodeMap.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/editor/CSGNodeMap.java new file mode 100644 index 00000000..17766941 --- /dev/null +++ b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/editor/CSGNodeMap.java @@ -0,0 +1,119 @@ +package org.simantics.g3d.csg.editor; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Set; + +import org.simantics.db.Session; +import org.simantics.g3d.csg.scenegraph2.CSGrootNode; +import org.simantics.g3d.csg.scenegraph2.ICSGnode; +import org.simantics.g3d.scenegraph.base.ParentNode; +import org.simantics.g3d.vtk.common.AbstractVTKNodeMap; +import org.simantics.g3d.vtk.common.InteractiveVtkPanel; +import org.simantics.objmap.graph.IMapping; +import org.simantics.utils.threads.AWTThread; + +import vtk.vtkProp; +import vtk.vtkProp3D; +import vtk.vtkRenderer; + +public class CSGNodeMap extends AbstractVTKNodeMap { + + + + public CSGNodeMap(Session session, IMapping mapping, InteractiveVtkPanel panel, CSGrootNode rootNode) { + super(session, mapping, panel, rootNode); + rootNode.setNodeMap(this); + } + + + @SuppressWarnings("unchecked") + protected void updateActor(ICSGnode node, Set ids) { + //System.out.println("CSGNodeMap.updateActor " + node); + if (node.getParent() instanceof ICSGnode) { + ICSGnode parent = (ICSGnode) node.getParent(); + if (!"child".equals(node.getParentRel())) { + updateActor(parent,null); + return; + } + } + + if (node instanceof ParentNode) { + ParentNode p = (ParentNode)node; + for (ICSGnode n : p.getNodes()) + remActor(n); + } + + remActor(node); + addActor(node); + + } + + @Override + protected Collection getActors(ICSGnode node) { + List props = new ArrayList(); + for (vtkProp3D p : ((ICSGnode)node).getActors()) + props.add(p); + return props; + } + + protected void removeActor(ICSGnode node) { + //System.out.println("CSGNodeMap.removeActor " + node); + remActor(node); + + if (!"child".equals(node.getParentRel())) { + if (node.getParent() instanceof ICSGnode) + updateActor((ICSGnode)node.getParent(),null); + } + } + + protected void addActor(ICSGnode node) { + //System.out.println("CSGNodeMap.addActor " + node); + if (hasActor(node)) + return; + if (Thread.currentThread() != AWTThread.getThreadAccess().getThread()) + throw new RuntimeException("Illegal thread."); + + panel.lock(); + + node.visualize(panel); + + for (vtkProp3D act : node.getActors()) { + nodeToActor.add(node, act); + actorToNode.put(act, node); + } + + panel.unlock(); + + } + + + + private boolean hasActor(ICSGnode node) { + List list = nodeToActor.getValues(node); + if (list == null || list.size() == 0) + return false; + return true; + } + + private void remActor(ICSGnode node) { + if (Thread.currentThread() != AWTThread.getThreadAccess().getThread()) + throw new RuntimeException("Illegal thread."); + + List list = nodeToActor.getValues(node); + if (list != null) { + for (vtkProp obj : list) { + actorToNode.remove(obj); + } + nodeToActor.remove(node); + panel.lock(); + + node.stopVisualize(); + + panel.unlock(); + } + } + + +} diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/BarrelNode.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/BarrelNode.java new file mode 100644 index 00000000..a6c3334b --- /dev/null +++ b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/BarrelNode.java @@ -0,0 +1,116 @@ +package org.simantics.g3d.csg.scenegraph2; + +import org.jcae.opencascade.jni.BRepBuilderAPI_MakeEdge; +import org.jcae.opencascade.jni.BRepBuilderAPI_MakeFace; +import org.jcae.opencascade.jni.BRepBuilderAPI_MakeWire; +import org.jcae.opencascade.jni.BRepPrimAPI_MakeRevol; +import org.jcae.opencascade.jni.GC_MakeArcOfCircle; +import org.jcae.opencascade.jni.GC_MakeSegment; +import org.jcae.opencascade.jni.TopoDS_Edge; +import org.jcae.opencascade.jni.TopoDS_Face; +import org.jcae.opencascade.jni.TopoDS_Shape; +import org.jcae.opencascade.jni.TopoDS_Wire; +import org.simantics.g3d.csg.ontology.CSG; +import org.simantics.g3d.property.annotations.GetPropertyValue; +import org.simantics.g3d.property.annotations.SetPropertyValue; +import org.simantics.objmap.graph.annotations.GraphType; +import org.simantics.objmap.graph.annotations.RelatedGetValue; +import org.simantics.objmap.graph.annotations.RelatedSetValue; + +@GraphType(CSG.URIs.Barrel) +public class BarrelNode extends CSGnode { + + private double r1 = 1.0; + private double r2 = 1.1; + private double h = 1.0; + + + + @RelatedSetValue(CSG.URIs.HasMinorRadius) + @SetPropertyValue(CSG.URIs.HasMinorRadius) + public void setR1(double r1) { + this.r1 = r1; + firePropertyChanged(CSG.URIs.HasMinorRadius); + } + + @RelatedSetValue(CSG.URIs.HasMajorRadius) + @SetPropertyValue(CSG.URIs.HasMajorRadius) + public void setR2(double r2) { + this.r2 = r2; + firePropertyChanged(CSG.URIs.HasMajorRadius); + } + + @RelatedSetValue(CSG.URIs.HasHeight) + @SetPropertyValue(CSG.URIs.HasHeight) + public void setH(double h) { + this.h = h; + firePropertyChanged(CSG.URIs.HasHeight); + } + + @RelatedGetValue(CSG.URIs.HasHeight) + @GetPropertyValue(value=CSG.URIs.HasHeight, name = "Height") + public double getH() { + return h; + } + + @RelatedGetValue(CSG.URIs.HasMinorRadius) + @GetPropertyValue(value=CSG.URIs.HasMinorRadius, name = "Minor Radius") + public double getR1() { + return r1; + } + + @RelatedGetValue(CSG.URIs.HasMajorRadius) + @GetPropertyValue(value=CSG.URIs.HasMajorRadius, name = "Major Radius") + public double getR2() { + return r2; + } + + @Override + public TopoDS_Shape getBaseGeometry() { + if (Math.abs(r1 -r2)< MIN_VALUE) + r2 = r1 + MIN_VALUE; + double p0[] = new double[]{0.0,-h*0.5,0.0}; + double p1[] = new double[]{0.0,-h*0.5,r1}; + double p2[] = new double[]{0.0, 0.0 ,r2}; + double p3[] = new double[]{0.0, h*0.5,r1}; + double p4[] = new double[]{0.0, h*0.5,0.0}; + GC_MakeArcOfCircle m = new GC_MakeArcOfCircle(p1,p2,p3); + GC_MakeSegment s1 = new GC_MakeSegment(p0,p1); + GC_MakeSegment s2 = new GC_MakeSegment(p3,p4); + + BRepBuilderAPI_MakeEdge edge = new BRepBuilderAPI_MakeEdge(s1.value()); + TopoDS_Edge e1 = (TopoDS_Edge)edge.shape(); + edge.delete(); + + edge = new BRepBuilderAPI_MakeEdge(m.value()); + TopoDS_Edge e2 = (TopoDS_Edge)edge.shape(); + edge.delete(); + + edge = new BRepBuilderAPI_MakeEdge(s2.value()); + TopoDS_Edge e3 = (TopoDS_Edge)edge.shape(); + edge.delete(); + + BRepBuilderAPI_MakeWire wire = new BRepBuilderAPI_MakeWire(e1,e2,e3); + TopoDS_Wire w = (TopoDS_Wire)wire.shape(); + wire.delete(); + + BRepBuilderAPI_MakeFace face = new BRepBuilderAPI_MakeFace(w); + TopoDS_Face F = (TopoDS_Face) face.shape(); + face.delete(); + + BRepPrimAPI_MakeRevol revol = new BRepPrimAPI_MakeRevol(F,new double[]{0.0,0.0,0.0,0.0,1.0,0.0}); + TopoDS_Shape shape = revol.shape(); + revol.delete(); + + m.delete(); + s1.delete(); + s2.delete(); + e1.delete(); + e2.delete(); + e3.delete(); + w.delete(); + F.delete(); + return shape; + } + +} diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/BoxNode.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/BoxNode.java new file mode 100644 index 00000000..b1581371 --- /dev/null +++ b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/BoxNode.java @@ -0,0 +1,69 @@ +package org.simantics.g3d.csg.scenegraph2; + +import org.jcae.opencascade.jni.TopoDS_Shape; +import org.simantics.g3d.csg.ontology.CSG; +import org.simantics.g3d.property.annotations.GetPropertyValue; +import org.simantics.g3d.property.annotations.SetPropertyValue; +import org.simantics.objmap.graph.annotations.GraphType; +import org.simantics.objmap.graph.annotations.RelatedGetValue; +import org.simantics.objmap.graph.annotations.RelatedSetValue; +import org.simantics.opencascade.OccTriangulator; + +@GraphType(CSG.URIs.Box) +public class BoxNode extends CSGnode { + + private double sx = 1.0; + private double sy = 1.0; + private double sz = 1.0; + + public BoxNode() { + System.out.println(); + } + + @RelatedSetValue(CSG.URIs.HasXAxisSize) + @SetPropertyValue(CSG.URIs.HasXAxisSize) + public void setSX(double d) { + this.sx = d; + firePropertyChanged(CSG.URIs.HasXAxisSize); + } + + @RelatedSetValue(CSG.URIs.HasYAxisSize) + @SetPropertyValue(CSG.URIs.HasYAxisSize) + public void setSY(double d) { + this.sy = d; + firePropertyChanged(CSG.URIs.HasYAxisSize); + } + + @RelatedSetValue(CSG.URIs.HasZAxisSize) + @SetPropertyValue(CSG.URIs.HasZAxisSize) + public void setSZ(double d) { + this.sz = d; + firePropertyChanged(CSG.URIs.HasZAxisSize); + } + + @RelatedGetValue(CSG.URIs.HasXAxisSize) + @GetPropertyValue(value=CSG.URIs.HasXAxisSize, name = "X Size") + public double getSx() { + return sx; + } + + @RelatedGetValue(CSG.URIs.HasYAxisSize) + @GetPropertyValue(value=CSG.URIs.HasYAxisSize, name = "Y Size") + public double getSy() { + return sy; + } + + @RelatedGetValue(CSG.URIs.HasZAxisSize) + @GetPropertyValue(value=CSG.URIs.HasZAxisSize, name = "Z Size") + public double getSz() { + return sz; + } + + + @Override + public TopoDS_Shape getBaseGeometry() { + return OccTriangulator.makeBox(-sx * 0.5, -sy * 0.5, -sz * 0.5, sx * 0.5, sy * 0.5, sz * 0.5); + } + + +} diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/CSGnode.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/CSGnode.java new file mode 100644 index 00000000..f783d4ee --- /dev/null +++ b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/CSGnode.java @@ -0,0 +1,109 @@ +package org.simantics.g3d.csg.scenegraph2; + +import java.util.Collection; +import java.util.Collections; + +import javax.vecmath.AxisAngle4d; +import javax.vecmath.Quat4d; +import javax.vecmath.Vector3d; + +import org.jcae.opencascade.jni.TopoDS_Shape; +import org.simantics.g3d.property.annotations.GetPropertyValue; +import org.simantics.g3d.property.annotations.SetPropertyValue; +import org.simantics.g3d.scenegraph.G3DNode; +import org.simantics.layer0.Layer0; +import org.simantics.objmap.graph.annotations.RelatedGetValue; +import org.simantics.objmap.graph.annotations.RelatedSetValue; +import org.simantics.opencascade.OccTriangulator; +import org.simantics.opencascade.vtk.vtkSolidObject; +import org.simantics.utils.threads.AWTThread; + +import vtk.vtkPanel; +import vtk.vtkProp3D; +import vtk.vtkRenderer; + +public abstract class CSGnode extends G3DNode implements ICSGnode { + + public static final double MIN_VALUE = 0.001; + + private String name; + + + @RelatedGetValue(Layer0.URIs.HasName) + @GetPropertyValue(value = Layer0.URIs.HasName, tabId = "Default", name = "Name") + public String getName() { + return name; + } + + @RelatedSetValue(Layer0.URIs.HasName) + @SetPropertyValue(Layer0.URIs.HasName) + public void setName(String name) { + if (name == null) + return; + this.name = name; + firePropertyChanged(Layer0.URIs.HasName); + } + + @Override + public String toString() { + return getName(); + } + + + private vtkSolidObject solidObject; + + @Override + public TopoDS_Shape getGeometry() { + TopoDS_Shape shape = getBaseGeometry(); + if (shape == null) + return null; + Quat4d q = getOrientation(); + AxisAngle4d r = new AxisAngle4d(); + r.set(q); + TopoDS_Shape tshape = OccTriangulator.makeRotation(shape, new double[] { 0.0, 0.0, 0.0, r.x, r.y, r.z }, r.angle); + shape.delete(); + shape = tshape; + Vector3d p = getPosition(); + tshape = OccTriangulator.makeTranslation(shape, p.x, p.y, p.z); + shape.delete(); + return tshape; + } + + public void visualize(vtkPanel panel) { + if (solidObject != null) { + solidObject.delete(); + solidObject = null; + } + TopoDS_Shape shape = getGeometry(); + if (shape == null) + return; + solidObject = new vtkSolidObject(panel, shape); + solidObject.visualizeSolid(true, false); + } + + @SuppressWarnings("unchecked") + public Collection getActors() { + if (solidObject == null) + return Collections.EMPTY_LIST; + return solidObject.getActors(); + } + + public void stopVisualize() { + if (solidObject != null) { + if (Thread.currentThread() == AWTThread.getThreadAccess().getThread()) + solidObject.delete(); + else + solidObject.dispose(); + solidObject = null; + } + } + + @Override + public void cleanup() { + stopVisualize(); + super.cleanup(); + } + + + +} diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/CSGparentNode.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/CSGparentNode.java new file mode 100644 index 00000000..dcc564ab --- /dev/null +++ b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/CSGparentNode.java @@ -0,0 +1,308 @@ +package org.simantics.g3d.csg.scenegraph2; + +import java.util.Collection; +import java.util.Collections; + +import javax.vecmath.AxisAngle4d; +import javax.vecmath.Quat4d; +import javax.vecmath.Vector3d; + +import org.jcae.opencascade.jni.TopoDS_Shape; +import org.simantics.g3d.csg.ontology.CSG; +import org.simantics.g3d.math.MathTools; +import org.simantics.g3d.ontology.G3D; +import org.simantics.g3d.property.annotations.GetPropertyValue; +import org.simantics.g3d.property.annotations.PropertyContributor; +import org.simantics.g3d.property.annotations.SetPropertyValue; +import org.simantics.g3d.scenegraph.IG3DNode; +import org.simantics.g3d.scenegraph.base.ParentNode; +import org.simantics.g3d.tools.NodeTools; +import org.simantics.layer0.Layer0; +import org.simantics.objmap.graph.annotations.RelatedElementsAdd; +import org.simantics.objmap.graph.annotations.RelatedElementsGet; +import org.simantics.objmap.graph.annotations.RelatedElementsRem; +import org.simantics.objmap.graph.annotations.RelatedGetValue; +import org.simantics.objmap.graph.annotations.RelatedSetValue; +import org.simantics.opencascade.OccTriangulator; +import org.simantics.opencascade.vtk.vtkSolidObject; +import org.simantics.utils.threads.AWTThread; + +import vtk.vtkPanel; +import vtk.vtkProp3D; + +@PropertyContributor +public abstract class CSGparentNode extends ParentNode implements ICSGnode { + + private String name; + + + @RelatedGetValue(Layer0.URIs.HasName) + @GetPropertyValue(value = Layer0.URIs.HasName, tabId = "Default", name = "Name") + public String getName() { + return name; + } + + @RelatedSetValue(Layer0.URIs.HasName) + @SetPropertyValue(Layer0.URIs.HasName) + public void setName(String name) { + if (name == null) + return; + this.name = name; + firePropertyChanged(Layer0.URIs.HasName); + } + + @Override + public String toString() { + return getName(); + } + + private Vector3d position = new Vector3d(); + private Quat4d orientation = MathTools.getIdentityQuat(); + + @Override + @GetPropertyValue(value = G3D.URIs.hasOrientation, tabId = "Transform", name = "Orientation") + public Quat4d getOrientation() { + return orientation; + } + + @RelatedGetValue(G3D.URIs.hasOrientation) + public double[] getOrientationArr() { + double arr[] = new double[4]; + orientation.get(arr); + return arr; + + } + + @Override + @GetPropertyValue(value = G3D.URIs.hasPosition, tabId = "Transform", name = "Position") + public Vector3d getPosition() { + return position; + } + + @RelatedGetValue(G3D.URIs.hasPosition) + public double[] getPositionArr() { + double arr[] = new double[3]; + position.get(arr); + return arr; + } + + @RelatedElementsAdd(CSG.URIs.hasPrimaryShape) + public void addPrimaryChild(ICSGnode node) { + addNode("primary",node); + } + + @RelatedElementsGet(CSG.URIs.hasPrimaryShape) + public Collection getPrimaryChild() { + return getNodes("primary"); + } + + @RelatedElementsRem(CSG.URIs.hasPrimaryShape) + public void remPrimaryChild(ICSGnode node) { + removeNode("primary", node); + } + + @RelatedElementsAdd(CSG.URIs.hasSecondaryShape) + public void addSecondaryChild(ICSGnode node) { + addNode("secondary",node); + } + + @RelatedElementsGet(CSG.URIs.hasSecondaryShape) + public Collection getSecondaryChild() { + return getNodes("secondary"); + } + + @RelatedElementsRem(CSG.URIs.hasSecondaryShape) + public void remSecondaryChild(ICSGnode node) { + removeNode("secondary", node); + } + + + @RelatedElementsAdd(CSG.URIs.hasChildShape) + public void addChild(ICSGnode node) { + addNode("child",node); + } + + @RelatedElementsGet(CSG.URIs.hasChildShape) + public Collection getChild() { + return getNodes("child"); + } + + @RelatedElementsRem(CSG.URIs.hasChildShape) + public void remChild(ICSGnode node) { + removeNode("child", node); + } + + + + protected TopoDS_Shape getPrimary() { + for (ICSGnode node : getNodes("primary")) + return node.getGeometry(); + return null; + } + + protected TopoDS_Shape getSecondary() { + for (ICSGnode node : getNodes("secondary")) + return node.getGeometry(); + return null; + } + + @Override + public TopoDS_Shape getGeometry() { + TopoDS_Shape shape = getBaseGeometry(); + if (shape == null) + return null; + Quat4d q = getOrientation(); + AxisAngle4d r = new AxisAngle4d(); + r.set(q); + TopoDS_Shape tshape = OccTriangulator.makeRotation(shape, new double[] { 0.0, 0.0, 0.0, r.x, r.y, r.z }, r.angle); + shape.delete(); + shape = tshape; + Vector3d p = getPosition(); + tshape = OccTriangulator.makeTranslation(shape, p.x, p.y, p.z); + shape.delete(); + return tshape; + + } + + + + @Override + @SetPropertyValue(G3D.URIs.hasOrientation) + public void setOrientation(Quat4d orientation) { + assert(orientation != null); + this.orientation = orientation; + + firePropertyChanged(G3D.URIs.hasOrientation); + } + + @Override + @SetPropertyValue(G3D.URIs.hasPosition) + public void setPosition(Vector3d position) { + assert(position != null); + this.position = position; + + firePropertyChanged(G3D.URIs.hasPosition); + } + + @RelatedSetValue(G3D.URIs.hasOrientation) + public void setOrientation(double[] arr) { + if (arr == null) + return; + setOrientation(new Quat4d(arr)); + } + + @RelatedSetValue(G3D.URIs.hasPosition) + public void setPosition(double[] arr) { + if (arr == null) + return; + setPosition(new Vector3d(arr)); + } + + @Override + @GetPropertyValue(value = G3D.URIs.hasWorldPosition, tabId = "Transform", name = "World Position") + public Vector3d getWorldPosition() { + IG3DNode parent = (IG3DNode) getParent(); + if (parent == null) + return position; + return NodeTools.getWorldPosition(parent, new Vector3d(position)); + } + + public Vector3d getWorldPosition(Vector3d localPosition) { + return NodeTools.getWorldPosition(this, localPosition); + } + + + @Override + @GetPropertyValue(value = G3D.URIs.hasWorldOrientation, tabId = "Transform", name = "World Orientation") + public Quat4d getWorldOrientation() { + return getWorldOrientation(new Quat4d(orientation)); + } + + public Quat4d getWorldOrientation(Quat4d localOrientation) { + IG3DNode parent = (IG3DNode)getParent(); + if (parent == null) + return localOrientation; + return NodeTools.getWorldOrientation(parent, localOrientation); + } + + @Override + public Vector3d getLocalPosition(Vector3d worldPosition) { + IG3DNode parent = (IG3DNode)getParent(); + if (parent == null) + return worldPosition; + return NodeTools.getLocalPosition(parent,new Vector3d(worldPosition)); + } + + @Override + public Quat4d getLocalOrientation(Quat4d worldOrientation) { + IG3DNode parent = (IG3DNode)getParent(); + if (parent == null) + return worldOrientation; + return NodeTools.getLocalOrientation(parent, new Quat4d(worldOrientation)); + } + + @Override + @SetPropertyValue(G3D.URIs.hasWorldPosition) + public void setWorldPosition(Vector3d position) { + Vector3d localPos = getLocalPosition(position); + setPosition(localPos); + } + + @Override + @SetPropertyValue(G3D.URIs.hasWorldOrientation) + public void setWorldOrientation(Quat4d orientation) { + Quat4d localOr = getLocalOrientation(orientation); + setOrientation(localOr); + } + + + private vtkSolidObject solidObject; + + + public void visualize(vtkPanel panel) { + if (solidObject != null) { + solidObject.delete(); + solidObject = null; + } + TopoDS_Shape shape = getGeometry(); + if (shape == null) + return; + solidObject = new vtkSolidObject(panel, shape); + solidObject.visualizeSolid(true, false); + } + + @SuppressWarnings("unchecked") + public Collection getActors() { + if (solidObject == null) + return Collections.EMPTY_LIST; + return solidObject.getActors(); + } + + public void stopVisualize() { + if (solidObject != null) { + if (Thread.currentThread() == AWTThread.getThreadAccess().getThread()) + solidObject.delete(); + else + solidObject.dispose(); + solidObject = null; + } + } + + @Override + public void cleanup() { + stopVisualize(); + super.cleanup(); + } + + + @Override + public void remove() { + //FIXME: creating boolean shapes (removing nodes from parent and attaching under boolean shape would destroy the existing hierarchy, if default implementation is used. + super.remove(); + } + + @Override + public Object getAdapter(Class adapter) { + return null; + } +} diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/CSGrootNode.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/CSGrootNode.java new file mode 100644 index 00000000..ac7a5158 --- /dev/null +++ b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/CSGrootNode.java @@ -0,0 +1,157 @@ +package org.simantics.g3d.csg.scenegraph2; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; +import java.util.Stack; + +import javax.vecmath.Quat4d; +import javax.vecmath.Vector3d; + +import org.simantics.g3d.csg.editor.CSGNodeMap; +import org.simantics.g3d.csg.ontology.CSG; +import org.simantics.g3d.math.MathTools; +import org.simantics.g3d.scenegraph.IG3DNode; +import org.simantics.g3d.scenegraph.NodeMap; +import org.simantics.g3d.scenegraph.NodeMapProvider; +import org.simantics.g3d.scenegraph.base.NodeException; +import org.simantics.g3d.scenegraph.base.ParentNode; +import org.simantics.objmap.graph.annotations.GraphType; +import org.simantics.objmap.graph.annotations.RelatedElementsAdd; +import org.simantics.objmap.graph.annotations.RelatedElementsGet; +import org.simantics.objmap.graph.annotations.RelatedElementsRem; + +import vtk.vtkProp; + + +@GraphType(CSG.URIs.Model) +public class CSGrootNode extends ParentNode implements IG3DNode, NodeMapProvider { + + + private CSGNodeMap nodeMap; + + public void setNodeMap(CSGNodeMap nodeMap) { + this.nodeMap = nodeMap; + } + + @Override + public NodeMap getNodeMap() { + return nodeMap; + } + + @Override + public ParentNode getParent() { + return null; + } + + @Override + public ParentNode getRootNode() { + return this; + } + + @RelatedElementsAdd(CSG.URIs.hasChildShape) + public void addChild(ICSGnode node) { + addNode("child",node); + } + + @RelatedElementsGet(CSG.URIs.hasChildShape) + public Collection getChild() { + return getNodes("child"); + } + + @RelatedElementsRem(CSG.URIs.hasChildShape) + public void remChild(ICSGnode node) { + removeNode("child", node); + } + + public javax.vecmath.Quat4d getOrientation() { + return MathTools.getIdentityQuat(); + }; + + @Override + public Vector3d getPosition() { + return new Vector3d(); + } + + @Override + public Quat4d getWorldOrientation() { + return MathTools.getIdentityQuat(); + } + + @Override + public Vector3d getWorldPosition() { + return new Vector3d(); + } + + @Override + public Quat4d getWorldOrientation(Quat4d localOrientation) { + return localOrientation; + } + + @Override + public Vector3d getWorldPosition(Vector3d localPosition) { + return localPosition; + } + + @Override + public Quat4d getLocalOrientation(Quat4d worldOrientation) { + return worldOrientation; + } + + @Override + public Vector3d getLocalPosition(Vector3d worldPosition) { + return worldPosition; + } + + @Override + public void setPosition(Vector3d position) { + throw new NodeException("Cannot set root node position"); + } + + @Override + public void setOrientation(Quat4d orientation) { + throw new NodeException("Cannot set root node orientation"); + } + + @Override + public void setWorldOrientation(Quat4d orientation) { + throw new NodeException("Cannot set root node orientation"); + } + + @Override + public void setWorldPosition(Vector3d position) { + throw new NodeException("Cannot set root node orientation"); + } + + public String getUniqueName(String prefix) { + Set names = new HashSet(); + Stack nodes = new Stack(); + nodes.addAll(getChild()); + while (!nodes.isEmpty()) { + ICSGnode n = nodes.pop(); + names.add(((ICSGnode)n).getName()); + if (n instanceof CSGparentNode) { + nodes.addAll(((CSGparentNode)n).getChild()); + nodes.addAll(((CSGparentNode)n).getPrimaryChild()); + nodes.addAll(((CSGparentNode)n).getSecondaryChild()); + } + } + int i = 1; + while (true) { + String genName = prefix + "_" + i; + if (!names.contains(genName)) + return genName; + i++; + } + } + + + @Override + public Object getAdapter(Class adapter) { + if (NodeMap.class == adapter) + return nodeMap; + return null; + } + + +} diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/ConeNode.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/ConeNode.java new file mode 100644 index 00000000..e392be6d --- /dev/null +++ b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/ConeNode.java @@ -0,0 +1,70 @@ +package org.simantics.g3d.csg.scenegraph2; + +import org.jcae.opencascade.jni.TopoDS_Shape; +import org.simantics.g3d.csg.ontology.CSG; +import org.simantics.g3d.property.annotations.GetPropertyValue; +import org.simantics.g3d.property.annotations.SetPropertyValue; +import org.simantics.objmap.graph.annotations.GraphType; +import org.simantics.objmap.graph.annotations.RelatedGetValue; +import org.simantics.objmap.graph.annotations.RelatedSetValue; +import org.simantics.opencascade.OccTriangulator; + +@GraphType(CSG.URIs.Cone) +public class ConeNode extends CSGnode { + + private double r1 = 1.0; + private double r2 = 0.5; + private double h = 1.0; + + + @RelatedSetValue(CSG.URIs.HasBottomRadius) + @SetPropertyValue(CSG.URIs.HasBottomRadius) + public void setR1(double r1) { + this.r1 = r1; + firePropertyChanged(CSG.URIs.HasBottomRadius); + } + + @RelatedSetValue(CSG.URIs.HasTopRadius) + @SetPropertyValue(CSG.URIs.HasTopRadius) + public void setR2(double r2) { + this.r2 = r2; + firePropertyChanged(CSG.URIs.HasTopRadius); + } + + @RelatedSetValue(CSG.URIs.HasHeight) + @SetPropertyValue(CSG.URIs.HasHeight) + public void setH(double h) { + this.h = h; + firePropertyChanged(CSG.URIs.HasHeight); + } + + @RelatedGetValue(CSG.URIs.HasHeight) + @GetPropertyValue(value=CSG.URIs.HasHeight, name = "Height") + public double getH() { + return h; + } + + @RelatedGetValue(CSG.URIs.HasBottomRadius) + @GetPropertyValue(value=CSG.URIs.HasBottomRadius, name = "Bottom Radius") + public double getR1() { + return r1; + } + + @RelatedGetValue(CSG.URIs.HasTopRadius) + @GetPropertyValue(value=CSG.URIs.HasTopRadius, name = "Top Radius") + public double getR2() { + return r2; + } + + @Override + public TopoDS_Shape getBaseGeometry() { + if (Math.abs(r1-r2) > MIN_VALUE) { +// if (r1 < MIN_VALUE) +// return null; + return OccTriangulator.makeCone(new double[] { 0.0, -h * 0.5, 0.0 }, new double[] { 0.0, 1.0, 0.0 }, r1,r2, h); + } else + return OccTriangulator.makeCylinder(new double[] { 0.0, -h * 0.5, 0.0 }, new double[] { 0.0, 1.0, 0.0 }, r1, h); + } + + +} diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/CylinderNode.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/CylinderNode.java new file mode 100644 index 00000000..d4a3f704 --- /dev/null +++ b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/CylinderNode.java @@ -0,0 +1,49 @@ +package org.simantics.g3d.csg.scenegraph2; + +import org.jcae.opencascade.jni.TopoDS_Shape; +import org.simantics.g3d.csg.ontology.CSG; +import org.simantics.g3d.property.annotations.GetPropertyValue; +import org.simantics.g3d.property.annotations.SetPropertyValue; +import org.simantics.objmap.graph.annotations.GraphType; +import org.simantics.objmap.graph.annotations.RelatedGetValue; +import org.simantics.objmap.graph.annotations.RelatedSetValue; +import org.simantics.opencascade.OccTriangulator; + +@GraphType(CSG.URIs.Cylinder) +public class CylinderNode extends CSGnode { + + private double r = 1.0; + private double h = 1.0; + + @RelatedSetValue(CSG.URIs.HasRadius) + @SetPropertyValue(CSG.URIs.HasRadius) + public void setR(double r) { + this.r = r; + firePropertyChanged(CSG.URIs.HasRadius); + } + + @RelatedSetValue(CSG.URIs.HasHeight) + @SetPropertyValue(CSG.URIs.HasHeight) + public void setH(double h) { + this.h = h; + firePropertyChanged(CSG.URIs.HasHeight); + } + + @RelatedGetValue(CSG.URIs.HasHeight) + @GetPropertyValue(value=CSG.URIs.HasHeight, name = "Height") + public double getH() { + return h; + } + + @RelatedGetValue(CSG.URIs.HasRadius) + @GetPropertyValue(value=CSG.URIs.HasRadius, name = "Radius") + public double getR() { + return r; + } + + @Override + public TopoDS_Shape getBaseGeometry() { + return OccTriangulator.makeCylinder(new double[] { 0.0, -h * 0.5, 0.0 }, new double[] { 0.0, 1.0, 0.0 }, r, h); + } + +} diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/DifferenceNode.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/DifferenceNode.java new file mode 100644 index 00000000..9dce709c --- /dev/null +++ b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/DifferenceNode.java @@ -0,0 +1,29 @@ +package org.simantics.g3d.csg.scenegraph2; + +import org.jcae.opencascade.jni.TopoDS_Shape; +import org.simantics.g3d.csg.ontology.CSG; +import org.simantics.objmap.graph.annotations.GraphType; +import org.simantics.opencascade.OccTriangulator; + +@GraphType(CSG.URIs.Difference) +public class DifferenceNode extends CSGparentNode { + + @Override + public TopoDS_Shape getBaseGeometry() { + TopoDS_Shape prim = getPrimary(); + TopoDS_Shape sec = getSecondary(); + if (prim != null && sec != null) { + TopoDS_Shape res = OccTriangulator.makeCut(prim, sec); + prim.delete(); + sec.delete(); + return res; + } + if (prim != null) + prim.delete(); + if (sec != null) + sec.delete(); + return null; + } + + +} diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/EllipticCylinderNode.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/EllipticCylinderNode.java new file mode 100644 index 00000000..5abecc2b --- /dev/null +++ b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/EllipticCylinderNode.java @@ -0,0 +1,63 @@ +package org.simantics.g3d.csg.scenegraph2; + +import org.jcae.opencascade.jni.TopoDS_Shape; +import org.simantics.g3d.csg.ontology.CSG; +import org.simantics.g3d.property.annotations.GetPropertyValue; +import org.simantics.g3d.property.annotations.SetPropertyValue; +import org.simantics.objmap.graph.annotations.GraphType; +import org.simantics.objmap.graph.annotations.RelatedGetValue; +import org.simantics.objmap.graph.annotations.RelatedSetValue; +import org.simantics.opencascade.OccTriangulator; + +@GraphType(CSG.URIs.EllipticCylinder) +public class EllipticCylinderNode extends CSGnode { + + private double r1 = 0.5; + private double r2 = 1.0; + private double h = 1.0; + + @RelatedSetValue(CSG.URIs.HasMinorRadius) + @SetPropertyValue(CSG.URIs.HasMinorRadius) + public void setR1(double r1) { + this.r1 = r1; + firePropertyChanged(CSG.URIs.HasMinorRadius); + } + + @RelatedSetValue(CSG.URIs.HasMajorRadius) + @SetPropertyValue(CSG.URIs.HasMajorRadius) + public void setR2(double r2) { + this.r2 = r2; + firePropertyChanged(CSG.URIs.HasMajorRadius); + } + + @RelatedSetValue(CSG.URIs.HasHeight) + @SetPropertyValue(CSG.URIs.HasHeight) + public void setH(double h) { + this.h = h; + firePropertyChanged(CSG.URIs.HasHeight); + } + + @RelatedGetValue(CSG.URIs.HasHeight) + @GetPropertyValue(value=CSG.URIs.HasHeight, name = "Height") + public double getH() { + return h; + } + + @RelatedGetValue(CSG.URIs.HasMinorRadius) + @GetPropertyValue(value=CSG.URIs.HasMinorRadius, name = "Minor Radius") + public double getR1() { + return r1; + } + + @RelatedGetValue(CSG.URIs.HasMajorRadius) + @GetPropertyValue(value=CSG.URIs.HasMajorRadius, name = "Major Radius") + public double getR2() { + return r2; + } + + @Override + public TopoDS_Shape getBaseGeometry() { + return OccTriangulator.makeEllipticCylinder(h, r1, r2); + } + +} diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/ICSGnode.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/ICSGnode.java new file mode 100644 index 00000000..76873e8b --- /dev/null +++ b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/ICSGnode.java @@ -0,0 +1,28 @@ +package org.simantics.g3d.csg.scenegraph2; + +import java.util.Collection; + +import org.jcae.opencascade.jni.TopoDS_Shape; +import org.simantics.g3d.scenegraph.IG3DNode; + +import vtk.vtkPanel; +import vtk.vtkProp3D; + +public interface ICSGnode extends IG3DNode { + + + public String getName(); + public void setName(String name); + + public TopoDS_Shape getBaseGeometry(); + + public TopoDS_Shape getGeometry(); + + + public void visualize(vtkPanel panel); + public void stopVisualize(); + + public Collection getActors(); + + public void deattach(); +} diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/IntersectionNode.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/IntersectionNode.java new file mode 100644 index 00000000..738ff0f9 --- /dev/null +++ b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/IntersectionNode.java @@ -0,0 +1,28 @@ +package org.simantics.g3d.csg.scenegraph2; + +import org.jcae.opencascade.jni.TopoDS_Shape; +import org.simantics.g3d.csg.ontology.CSG; +import org.simantics.objmap.graph.annotations.GraphType; +import org.simantics.opencascade.OccTriangulator; + +@GraphType(CSG.URIs.Intersection) +public class IntersectionNode extends CSGparentNode { + + @Override + public TopoDS_Shape getBaseGeometry() { + TopoDS_Shape prim = getPrimary(); + TopoDS_Shape sec = getSecondary(); + if (prim != null && sec != null) { + TopoDS_Shape res =OccTriangulator.makeCommon(prim, sec); + prim.delete(); + sec.delete(); + return res; + } + if (prim != null) + prim.delete(); + if (sec != null) + sec.delete(); + return null; + } + +} diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/RectangularSolidNode.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/RectangularSolidNode.java new file mode 100644 index 00000000..6fb7f105 --- /dev/null +++ b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/RectangularSolidNode.java @@ -0,0 +1,171 @@ +package org.simantics.g3d.csg.scenegraph2; + +import org.jcae.opencascade.jni.BRepBuilderAPI_MakeEdge; +import org.jcae.opencascade.jni.BRepBuilderAPI_MakeWire; +import org.jcae.opencascade.jni.BRepOffsetAPI_ThruSections; +import org.jcae.opencascade.jni.TopoDS_Edge; +import org.jcae.opencascade.jni.TopoDS_Shape; +import org.jcae.opencascade.jni.TopoDS_Wire; +import org.simantics.g3d.csg.ontology.CSG; +import org.simantics.g3d.property.annotations.GetPropertyValue; +import org.simantics.g3d.property.annotations.SetPropertyValue; +import org.simantics.objmap.graph.annotations.GraphType; +import org.simantics.objmap.graph.annotations.RelatedGetValue; +import org.simantics.objmap.graph.annotations.RelatedSetValue; + + +@GraphType(CSG.URIs.RectangularSolid) +public class RectangularSolidNode extends CSGnode { + + double x1 = 0.5; + double x2 = 1.0; + double y = 1.0; + double z1 = 0.5; + double z2 = 1.0; + + + @RelatedSetValue(CSG.URIs.HasXAxisMinimumSize) + @SetPropertyValue(CSG.URIs.HasXAxisMinimumSize) + public void setX1(double d) { + this.x1 = d; + firePropertyChanged(CSG.URIs.HasXAxisMinimumSize); + } + + @RelatedSetValue(CSG.URIs.HasXAxisMaximumSize) + @SetPropertyValue(CSG.URIs.HasXAxisMaximumSize) + public void setX2(double d) { + this.x2 = d; + firePropertyChanged(CSG.URIs.HasXAxisMaximumSize); + } + + @RelatedSetValue(CSG.URIs.HasYAxisSize) + @SetPropertyValue(CSG.URIs.HasYAxisSize) + public void setSY(double d) { + this.y = d; + firePropertyChanged(CSG.URIs.HasYAxisSize); + } + + @RelatedSetValue(CSG.URIs.HasZAxisMinimumSize) + @SetPropertyValue(CSG.URIs.HasZAxisMinimumSize) + public void setZ1(double d) { + this.z1 = d; + firePropertyChanged(CSG.URIs.HasZAxisMinimumSize); + } + + @RelatedSetValue(CSG.URIs.HasZAxisMaximumSize) + @SetPropertyValue(CSG.URIs.HasZAxisMaximumSize) + public void setZ2(double d) { + this.z2 = d; + firePropertyChanged(CSG.URIs.HasZAxisMaximumSize); + } + + @RelatedGetValue(CSG.URIs.HasXAxisMinimumSize) + @GetPropertyValue(value=CSG.URIs.HasXAxisMinimumSize, name = "X Min Size") + public double getX1() { + return x1; + } + + @RelatedGetValue(CSG.URIs.HasXAxisMaximumSize) + @GetPropertyValue(value=CSG.URIs.HasXAxisMaximumSize, name = "X Max Size") + public double getX2() { + return x2; + } + + @RelatedGetValue(CSG.URIs.HasYAxisSize) + @GetPropertyValue(value=CSG.URIs.HasYAxisSize, name = "Y Size") + public double getY() { + return y; + } + + @RelatedGetValue(CSG.URIs.HasZAxisMinimumSize) + @GetPropertyValue(value=CSG.URIs.HasZAxisMinimumSize, name = "Z Min Size") + public double getZ1() { + return z1; + } + + @RelatedGetValue(CSG.URIs.HasZAxisMaximumSize) + @GetPropertyValue(value=CSG.URIs.HasZAxisMaximumSize, name = "Z Max Size") + public double getZ2() { + return z2; + } + + @Override + public TopoDS_Shape getBaseGeometry() { + double x1 = this.x1 *0.5; + double x2 = this.x2 *0.5; + double z1 = this.z1 *0.5; + double z2 = this.z2 *0.5; + double y = this.y * 0.5; + + BRepBuilderAPI_MakeWire wire = new BRepBuilderAPI_MakeWire(); + BRepBuilderAPI_MakeEdge edge = new BRepBuilderAPI_MakeEdge(new double[]{x1,-y,z1},new double[]{x1,-y,-z1}); + TopoDS_Edge top_edge = (TopoDS_Edge)edge.shape(); + wire.add(top_edge); + edge.delete(); + top_edge.delete(); + + edge = new BRepBuilderAPI_MakeEdge(new double[]{x1,-y,-z1},new double[]{-x1,-y,-z1}); + top_edge = (TopoDS_Edge)edge.shape(); + wire.add(top_edge); + edge.delete(); + top_edge.delete(); + + edge = new BRepBuilderAPI_MakeEdge(new double[]{-x1,-y,-z1},new double[]{-x1,-y,z1}); + top_edge = (TopoDS_Edge)edge.shape(); + wire.add(top_edge); + edge.delete(); + top_edge.delete(); + + edge = new BRepBuilderAPI_MakeEdge(new double[]{-x1,-y,z1},new double[]{x1,-y,z1}); + top_edge = (TopoDS_Edge)edge.shape(); + wire.add(top_edge); + edge.delete(); + top_edge.delete(); + + TopoDS_Wire w1 = (TopoDS_Wire)wire.shape(); + wire.delete(); + wire = new BRepBuilderAPI_MakeWire(); + + + edge = new BRepBuilderAPI_MakeEdge(new double[]{x2, y,z2},new double[]{x2, y,-z2}); + top_edge = (TopoDS_Edge)edge.shape(); + wire.add(top_edge); + edge.delete(); + top_edge.delete(); + + edge = new BRepBuilderAPI_MakeEdge(new double[]{x2, y,-z2},new double[]{-x2, y,-z2}); + top_edge = (TopoDS_Edge)edge.shape(); + wire.add(top_edge); + edge.delete(); + top_edge.delete(); + + edge = new BRepBuilderAPI_MakeEdge(new double[]{-x2, y,-z2},new double[]{-x2, y,z2}); + top_edge = (TopoDS_Edge)edge.shape(); + wire.add(top_edge); + edge.delete(); + top_edge.delete(); + + edge = new BRepBuilderAPI_MakeEdge(new double[]{-x2, y,z2},new double[]{x2, y,z2}); + top_edge = (TopoDS_Edge)edge.shape(); + wire.add(top_edge); + edge.delete(); + top_edge.delete(); + + TopoDS_Wire w2 = (TopoDS_Wire)wire.shape(); + wire.delete(); + + BRepOffsetAPI_ThruSections generatorb = new BRepOffsetAPI_ThruSections(true, true); + generatorb.addWire(w1); + generatorb.addWire(w2); + generatorb.build(); + w1.delete(); + w2.delete(); + + TopoDS_Shape shape = generatorb.shape(); + generatorb.delete(); + + return shape; + } + + +} diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/RegularPrismNode.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/RegularPrismNode.java new file mode 100644 index 00000000..ebb9345d --- /dev/null +++ b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/RegularPrismNode.java @@ -0,0 +1,67 @@ +package org.simantics.g3d.csg.scenegraph2; + +import org.jcae.opencascade.jni.TopoDS_Shape; +import org.simantics.g3d.csg.ontology.CSG; +import org.simantics.g3d.property.annotations.GetPropertyValue; +import org.simantics.g3d.property.annotations.SetPropertyValue; +import org.simantics.objmap.graph.annotations.GraphType; +import org.simantics.objmap.graph.annotations.RelatedGetValue; +import org.simantics.objmap.graph.annotations.RelatedSetValue; +import org.simantics.opencascade.OccTriangulator; + +@GraphType(CSG.URIs.RegularPrism) +public class RegularPrismNode extends CSGnode { + + private double r = 1.0; + private double h = 1.0; + private int n = 3; + + @RelatedSetValue(CSG.URIs.HasRadius) + @SetPropertyValue(CSG.URIs.HasRadius) + public void setR(double r) { + this.r = r; + firePropertyChanged(CSG.URIs.HasRadius); + } + + + @RelatedSetValue(CSG.URIs.HasHeight) + @SetPropertyValue(CSG.URIs.HasHeight) + public void setH(double h) { + this.h = h; + firePropertyChanged(CSG.URIs.HasHeight); + } + + @RelatedSetValue(CSG.URIs.HasCorners) + @SetPropertyValue(CSG.URIs.HasCorners) + public void setN(int n) { + if (n < 3) + n = 3; + this.n = n; + firePropertyChanged(CSG.URIs.HasCorners); + } + + @RelatedGetValue(CSG.URIs.HasHeight) + @GetPropertyValue(value=CSG.URIs.HasHeight, name="Height") + public double getH() { + return h; + } + + @RelatedGetValue(CSG.URIs.HasCorners) + @GetPropertyValue(value=CSG.URIs.HasCorners, name="Corners") + public int getN() { + return n; + } + + @RelatedGetValue(CSG.URIs.HasRadius) + @GetPropertyValue(value=CSG.URIs.HasRadius, name="Radius") + public double getR() { + return r; + } + + @Override + public TopoDS_Shape getBaseGeometry() { + return OccTriangulator.makeReqularPrism(h, r, n); + } + + +} diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/SchemaBuilder.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/SchemaBuilder.java new file mode 100644 index 00000000..90999a03 --- /dev/null +++ b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/SchemaBuilder.java @@ -0,0 +1,48 @@ +package org.simantics.g3d.csg.scenegraph2; + +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.request.Read; +import org.simantics.objmap.graph.schema.IMappingSchema; +import org.simantics.objmap.graph.schema.MappingSchemas; +import org.simantics.objmap.graph.schema.SimpleSchema; +import org.simantics.ui.SimanticsUI; + +public class SchemaBuilder { + + public static IMappingSchema getSchema() throws DatabaseException{ + return SimanticsUI.getSession().syncRequest(new Read>() { + @Override + public IMappingSchema perform(ReadGraph g) + throws DatabaseException { + return getSchema(g); + } + }); + } + + public static IMappingSchema getSchema(ReadGraph g) throws DatabaseException{ + try { + SimpleSchema schema = new SimpleSchema(); + schema.addLinkType(MappingSchemas.fromAnnotations(g, BarrelNode.class)); + schema.addLinkType(MappingSchemas.fromAnnotations(g, BoxNode.class)); + schema.addLinkType(MappingSchemas.fromAnnotations(g, ConeNode.class)); + schema.addLinkType(MappingSchemas.fromAnnotations(g, CylinderNode.class)); + schema.addLinkType(MappingSchemas.fromAnnotations(g, DifferenceNode.class)); + schema.addLinkType(MappingSchemas.fromAnnotations(g, EllipticCylinderNode.class)); + schema.addLinkType(MappingSchemas.fromAnnotations(g, IntersectionNode.class)); + schema.addLinkType(MappingSchemas.fromAnnotations(g, RectangularSolidNode.class)); + schema.addLinkType(MappingSchemas.fromAnnotations(g, RegularPrismNode.class)); + schema.addLinkType(MappingSchemas.fromAnnotations(g, SphereNode.class)); + schema.addLinkType(MappingSchemas.fromAnnotations(g, TorusNode.class)); + schema.addLinkType(MappingSchemas.fromAnnotations(g, UnionNode.class)); + schema.addLinkType(MappingSchemas.fromAnnotations(g, CSGrootNode.class)); + return schema; + } catch (IllegalAccessException e) { + throw new DatabaseException(e); + } catch (InstantiationException e) { + throw new DatabaseException(e); + } + } + +} diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/SphereNode.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/SphereNode.java new file mode 100644 index 00000000..a2cc6580 --- /dev/null +++ b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/SphereNode.java @@ -0,0 +1,35 @@ +package org.simantics.g3d.csg.scenegraph2; + +import org.jcae.opencascade.jni.TopoDS_Shape; +import org.simantics.g3d.csg.ontology.CSG; +import org.simantics.g3d.property.annotations.GetPropertyValue; +import org.simantics.g3d.property.annotations.SetPropertyValue; +import org.simantics.objmap.graph.annotations.GraphType; +import org.simantics.objmap.graph.annotations.RelatedGetValue; +import org.simantics.objmap.graph.annotations.RelatedSetValue; +import org.simantics.opencascade.OccTriangulator; + +@GraphType(CSG.URIs.Sphere) +public class SphereNode extends CSGnode { + + private double r = 1.0; + + @RelatedSetValue(CSG.URIs.HasRadius) + @SetPropertyValue(CSG.URIs.HasRadius) + public void setR(double r) { + this.r = r; + firePropertyChanged(CSG.URIs.HasRadius); + } + + @RelatedGetValue(CSG.URIs.HasRadius) + @GetPropertyValue(value=CSG.URIs.HasRadius, name="Radius") + public double getR() { + return r; + } + + @Override + public TopoDS_Shape getBaseGeometry() { + return OccTriangulator.makeSphere(0, 0, 0, r); + } + +} diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/TorusNode.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/TorusNode.java new file mode 100644 index 00000000..a76a5045 --- /dev/null +++ b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/TorusNode.java @@ -0,0 +1,50 @@ +package org.simantics.g3d.csg.scenegraph2; + +import org.jcae.opencascade.jni.TopoDS_Shape; +import org.simantics.g3d.csg.ontology.CSG; +import org.simantics.g3d.property.annotations.GetPropertyValue; +import org.simantics.g3d.property.annotations.SetPropertyValue; +import org.simantics.objmap.graph.annotations.GraphType; +import org.simantics.objmap.graph.annotations.RelatedGetValue; +import org.simantics.objmap.graph.annotations.RelatedSetValue; +import org.simantics.opencascade.OccTriangulator; + +@GraphType(CSG.URIs.Torus) +public class TorusNode extends CSGnode { + + private double r1 = 1.0; + private double r2 = 1.0; + + + @RelatedSetValue(CSG.URIs.HasMinorRadius) + @SetPropertyValue(CSG.URIs.HasMinorRadius) + public void setR1(double r1) { + this.r1 = r1; + firePropertyChanged(CSG.URIs.HasMinorRadius); + } + + @RelatedSetValue(CSG.URIs.HasMajorRadius) + @SetPropertyValue(CSG.URIs.HasMajorRadius) + public void setR2(double r2) { + this.r2 = r2; + firePropertyChanged(CSG.URIs.HasMajorRadius); + } + + @RelatedGetValue(CSG.URIs.HasMinorRadius) + @GetPropertyValue(value=CSG.URIs.HasMinorRadius, name="Minor Radius") + public double getR1() { + return r1; + } + + @RelatedGetValue(CSG.URIs.HasMajorRadius) + @GetPropertyValue(value=CSG.URIs.HasMajorRadius, name="Major Radius") + public double getR2() { + return r2; + } + + @Override + public TopoDS_Shape getBaseGeometry() { + return OccTriangulator.makeTorus(new double[] { 0.0, 0.0, 0.0 }, new double[] { 0.0, 1.0, 0.0 }, r2, r1); + } + +} diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/UnionNode.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/UnionNode.java new file mode 100644 index 00000000..2e9aa2e6 --- /dev/null +++ b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/UnionNode.java @@ -0,0 +1,29 @@ +package org.simantics.g3d.csg.scenegraph2; + +import org.jcae.opencascade.jni.TopoDS_Shape; +import org.simantics.g3d.csg.ontology.CSG; + +import org.simantics.objmap.graph.annotations.GraphType; +import org.simantics.opencascade.OccTriangulator; + +@GraphType(CSG.URIs.Union) +public class UnionNode extends CSGparentNode { + + @Override + public TopoDS_Shape getBaseGeometry() { + TopoDS_Shape prim = getPrimary(); + TopoDS_Shape sec = getSecondary(); + if (prim != null && sec != null) { + TopoDS_Shape res =OccTriangulator.makeFuse(prim, sec); + prim.delete(); + sec.delete(); + return res; + } + if (prim != null) + prim.delete(); + if (sec != null) + sec.delete(); + return null; + } + +} diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/wizard/CSGBRepExportWizard.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/wizard/CSGBRepExportWizard.java new file mode 100644 index 00000000..44a227a7 --- /dev/null +++ b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/wizard/CSGBRepExportWizard.java @@ -0,0 +1,56 @@ +package org.simantics.g3d.csg.wizard; + +import java.util.Deque; + +import org.eclipse.core.runtime.preferences.InstanceScope; +import org.eclipse.jface.operation.IRunnableWithProgress; +import org.eclipse.jface.preference.IPersistentPreferenceStore; +import org.eclipse.ui.preferences.ScopedPreferenceStore; +import org.simantics.g3d.csg.Activator; +import org.simantics.g3d.wizard.ModelExportWizard; +import org.simantics.g3d.wizard.ModelExportWizardPage; + +public class CSGBRepExportWizard extends ModelExportWizard { + + public static final String RECENT_CSG_EXPORT_LOCATIONS = "RECENT_CSG_EXPORT_LOCATIONS"; + public static final String CSG_EXPORT_OVERWRITE = "CSG_EXPORT_OVERWRITE"; + + public CSGBRepExportWizard() { + setWindowTitle("Export CSG Model to Brep"); + setNeedsProgressMonitor(true); + } + + @Override + protected CSGExportModel createExportModel(Deque recentExportPaths) { + return new CSGExportModel(recentExportPaths); + } + + @Override + protected ModelExportWizardPage createExportPage(CSGExportModel exportModel) { + return new CSGExportPage(exportModel); + } + + @Override + protected IRunnableWithProgress createExportRunnable(CSGExportModel exportModel) { + return new CSGBrepModelExporter(exportModel); + } + + @Override + protected String getExportLocationId() { + return RECENT_CSG_EXPORT_LOCATIONS; + } + + @Override + protected String getExportOverwriteId() { + return CSG_EXPORT_OVERWRITE; + } + + + @Override + protected IPersistentPreferenceStore getPreferenceStore() { + return new ScopedPreferenceStore(InstanceScope.INSTANCE, Activator.PLUGIN_ID); + } + + + +} diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/wizard/CSGBrepModelExporter.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/wizard/CSGBrepModelExporter.java new file mode 100644 index 00000000..8e00a3de --- /dev/null +++ b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/wizard/CSGBrepModelExporter.java @@ -0,0 +1,98 @@ +package org.simantics.g3d.csg.wizard; + +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.SubMonitor; +import org.eclipse.jface.operation.IRunnableWithProgress; +import org.jcae.opencascade.jni.TopoDS_Shape; +import org.simantics.Simantics; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.request.Read; +import org.simantics.g3d.csg.scenegraph2.CSGrootNode; +import org.simantics.g3d.csg.scenegraph2.ICSGnode; +import org.simantics.g3d.csg.scenegraph2.SchemaBuilder; +import org.simantics.objmap.graph.IMapping; +import org.simantics.objmap.graph.Mappings; +import org.simantics.objmap.graph.schema.IMappingSchema; +import org.simantics.opencascade.OccTriangulator; + +public class CSGBrepModelExporter implements IRunnableWithProgress { + + CSGExportModel exportModel; + public CSGBrepModelExporter(CSGExportModel exportModel) { + this.exportModel = exportModel; + } + + @Override + public void run(IProgressMonitor monitor) throws InvocationTargetException, + InterruptedException { + SubMonitor progress = SubMonitor.convert(monitor, 50); + SubMonitor mon = progress.newChild(50, SubMonitor.SUPPRESS_NONE); + try { + exportModel(mon); + } catch (IOException e) { + mon.setCanceled(true); + throw new InvocationTargetException(e); + } catch (DatabaseException e) { + mon.setCanceled(true); + throw new InvocationTargetException(e); + } finally { + monitor.done(); + } + + } + + void exportModel(SubMonitor mon) throws IOException, DatabaseException { + int taskSize = 50; + mon.beginTask("Exporting model...", taskSize); + mon.setTaskName("Initializing CSG model..."); + + CSGrootNode rootNode = Simantics.getSessionContext().getSession().syncRequest(new Read() { + @Override + public CSGrootNode perform(ReadGraph graph) + throws DatabaseException { + IMappingSchema schema = SchemaBuilder.getSchema(graph); + IMapping mapping = Mappings.createWithoutListening(schema); + CSGrootNode rootNode = (CSGrootNode) mapping.map(graph,exportModel.getModel().getResource()); + mapping.dispose(); + return rootNode; + } + }); + mon.worked(40); + + mon.setTaskName("Creating solid geometry..."); + List shapes = new ArrayList(); + for (ICSGnode node : rootNode.getChild()) { + TopoDS_Shape shape = node.getGeometry(); + if (shape != null) + shapes.add(shape); + } + if (shapes.size() == 0) { + mon.setTaskName("Nothing to export."); + mon.setCanceled(true); + return; + } + TopoDS_Shape compound = null; + if (shapes.size() > 1) { + OccTriangulator.makeCompound(shapes.toArray(new TopoDS_Shape[shapes.size()])); + for (TopoDS_Shape shape : shapes) + shape.delete(); + } else { + compound = shapes.get(0); + } + + mon.worked(50); + + mon.setTaskName("Writing file..."); + OccTriangulator.exportBREP(compound, exportModel.getExportLocation().getAbsolutePath()); + compound.delete(); + + mon.setWorkRemaining(0); + } +} diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/wizard/CSGExportModel.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/wizard/CSGExportModel.java new file mode 100644 index 00000000..6690a625 --- /dev/null +++ b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/wizard/CSGExportModel.java @@ -0,0 +1,21 @@ +package org.simantics.g3d.csg.wizard; + +import java.util.Deque; + +import org.simantics.g3d.wizard.IExportModel; + +public class CSGExportModel extends IExportModel{ + + + + public CSGExportModel(Deque recentLocations) { + super(); + setRecentLocations(recentLocations); + } + + @Override + public boolean usesFile() { + return true; + } + +} diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/wizard/CSGExportPage.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/wizard/CSGExportPage.java new file mode 100644 index 00000000..c9354d37 --- /dev/null +++ b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/wizard/CSGExportPage.java @@ -0,0 +1,51 @@ +package org.simantics.g3d.csg.wizard; + +import java.util.ArrayList; +import java.util.List; + +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.common.NamedResource; +import org.simantics.db.exception.DatabaseException; +import org.simantics.g3d.csg.ontology.CSG; +import org.simantics.g3d.wizard.ModelExportWizardPage; +import org.simantics.layer0.Layer0; + +public class CSGExportPage extends ModelExportWizardPage { + + + + public CSGExportPage(CSGExportModel model) { + super("Export CSG Model","Define Export Location",null,model); + } + + @Override + public String[] getFilterExtensions() { + return new String[]{"*.brep"}; + } + + @Override + public String[] getFilterNames() { + return new String[]{"OpenCASCADE Brep file"}; + } + + + @Override + protected List getSupportedModels(ReadGraph graph, Resource project) throws DatabaseException { + List models = new ArrayList(); + Layer0 L0 = Layer0.getInstance(graph); + CSG csg = CSG.getInstance(graph); + + for (Resource r : graph.getObjects(project, L0.ConsistsOf)) { + if (graph.isInstanceOf(r, csg.Model)) { + models.add(new NamedResource((String)graph.getRelatedValue(r, L0.HasName), r)); + } + } + return models; + } + + + + + +} diff --git a/org.simantics.g3d.ontology/.classpath b/org.simantics.g3d.ontology/.classpath new file mode 100644 index 00000000..8a8f1668 --- /dev/null +++ b/org.simantics.g3d.ontology/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/org.simantics.g3d.ontology/.project b/org.simantics.g3d.ontology/.project new file mode 100644 index 00000000..43fd9879 --- /dev/null +++ b/org.simantics.g3d.ontology/.project @@ -0,0 +1,34 @@ + + + org.simantics.g3d.ontology + + + + + + org.simantics.graph.builder + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + org.simantics.graph.nature + + diff --git a/org.simantics.g3d.ontology/.settings/org.eclipse.jdt.core.prefs b/org.simantics.g3d.ontology/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000..5c42125f --- /dev/null +++ b/org.simantics.g3d.ontology/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,8 @@ +#Mon Dec 12 12:36:09 EET 2011 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/org.simantics.g3d.ontology/META-INF/MANIFEST.MF b/org.simantics.g3d.ontology/META-INF/MANIFEST.MF new file mode 100644 index 00000000..2ce6eaf6 --- /dev/null +++ b/org.simantics.g3d.ontology/META-INF/MANIFEST.MF @@ -0,0 +1,10 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: G3D Ontology +Bundle-SymbolicName: org.simantics.g3d.ontology +Bundle-Version: 1.0.0.qualifier +Bundle-Vendor: VTT +Require-Bundle: org.eclipse.core.runtime, + org.simantics.layer0;bundle-version="1.0.0" +Bundle-RequiredExecutionEnvironment: JavaSE-1.6 +Export-Package: org.simantics.g3d.ontology diff --git a/org.simantics.g3d.ontology/build.properties b/org.simantics.g3d.ontology/build.properties new file mode 100644 index 00000000..ecdc7c30 --- /dev/null +++ b/org.simantics.g3d.ontology/build.properties @@ -0,0 +1,5 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + graph.tg diff --git a/org.simantics.g3d.ontology/graph.tg b/org.simantics.g3d.ontology/graph.tg new file mode 100644 index 00000000..8c6bb84a Binary files /dev/null and b/org.simantics.g3d.ontology/graph.tg differ diff --git a/org.simantics.g3d.ontology/graph/g3d.pgraph b/org.simantics.g3d.ontology/graph/g3d.pgraph new file mode 100644 index 00000000..fb33af8d --- /dev/null +++ b/org.simantics.g3d.ontology/graph/g3d.pgraph @@ -0,0 +1,63 @@ +L0 = + +G3D = : L0.Ontology + @L0.new + L0.HasResourceClass "org.simantics.g3d.ontology.G3D" + + +G3D.Tuple3D G3D.Orientation + +G3D.hasPosition G3D.Position + +G3D.hasWorldOrientation G3D.Orientation + @L0.tag L0.Abstract + +G3D.hasWorldPosition G3D.Position + @L0.tag L0.Abstract + +G3D.nodes () { + public G3D perform(ReadGraph graph) throws DatabaseException { + QueryControl qc = graph.getService(QueryControl.class); + return new G3D(qc.getIndependentGraph(graph)); + } + }); + session.registerService(G3D.class, ret); + } + return ret; + } + +} + diff --git a/org.simantics.g3d.vtk/.classpath b/org.simantics.g3d.vtk/.classpath new file mode 100644 index 00000000..8a8f1668 --- /dev/null +++ b/org.simantics.g3d.vtk/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/org.simantics.g3d.vtk/.project b/org.simantics.g3d.vtk/.project new file mode 100644 index 00000000..2940db6e --- /dev/null +++ b/org.simantics.g3d.vtk/.project @@ -0,0 +1,28 @@ + + + org.simantics.g3d.vtk + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/org.simantics.g3d.vtk/.settings/org.eclipse.jdt.core.prefs b/org.simantics.g3d.vtk/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000..2bbbf699 --- /dev/null +++ b/org.simantics.g3d.vtk/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,8 @@ +#Thu Mar 29 15:34:08 EEST 2012 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/org.simantics.g3d.vtk/META-INF/MANIFEST.MF b/org.simantics.g3d.vtk/META-INF/MANIFEST.MF new file mode 100644 index 00000000..a3757760 --- /dev/null +++ b/org.simantics.g3d.vtk/META-INF/MANIFEST.MF @@ -0,0 +1,29 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: G3D Vtk integration +Bundle-SymbolicName: org.simantics.g3d.vtk;singleton:=true +Bundle-Version: 1.0.0.qualifier +Bundle-Activator: org.simantics.g3d.vtk.Activator +Bundle-Vendor: VTT +Require-Bundle: org.eclipse.core.runtime, + javax.vecmath;bundle-version="1.5.2", + org.simantics.g3d;bundle-version="1.0.0", + org.eclipse.ui;bundle-version="3.6.2", + org.simantics.db;bundle-version="1.1.0", + org.simantics.selectionview;bundle-version="1.0.0", + org.simantics.db.management;bundle-version="1.1.0", + org.eclipse.ui.views;bundle-version="3.5.1", + org.simantics.objmap2;bundle-version="1.0.0", + org.simantics.db.common;bundle-version="1.1.0", + org.simantics.g3d.ontology;bundle-version="1.0.0", + vtk;bundle-version="5.10.0", + org.simantics.utils.ui;bundle-version="1.1.0" +Bundle-RequiredExecutionEnvironment: JavaSE-1.6 +Bundle-ActivationPolicy: lazy +Export-Package: org.simantics.g3d.vtk.action, + org.simantics.g3d.vtk.common, + org.simantics.g3d.vtk.gizmo, + org.simantics.g3d.vtk.handlers, + org.simantics.g3d.vtk.property, + org.simantics.g3d.vtk.shape, + org.simantics.g3d.vtk.utils diff --git a/org.simantics.g3d.vtk/build.properties b/org.simantics.g3d.vtk/build.properties new file mode 100644 index 00000000..6f20375d --- /dev/null +++ b/org.simantics.g3d.vtk/build.properties @@ -0,0 +1,5 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + plugin.xml diff --git a/org.simantics.g3d.vtk/plugin.xml b/org.simantics.g3d.vtk/plugin.xml new file mode 100644 index 00000000..28e65b6a --- /dev/null +++ b/org.simantics.g3d.vtk/plugin.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/Activator.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/Activator.java new file mode 100644 index 00000000..c8270855 --- /dev/null +++ b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/Activator.java @@ -0,0 +1,40 @@ +package org.simantics.g3d.vtk; + +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.BundleContext; + +public class Activator extends AbstractUIPlugin { + + public static final String PLUGIN_ID = "org.simantics.g3d.vtk"; //$NON-NLS-1$ + + private static Activator plugin; + + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext) + */ + public void start(BundleContext context) throws Exception { + super.start(context); + plugin = this; + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext) + */ + public void stop(BundleContext context) throws Exception { + plugin = null; + super.stop(context); + } + + /** + * Returns the shared instance + * + * @return the shared instance + */ + public static Activator getDefault() { + return plugin; + } + +} diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/action/RemoveAction.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/action/RemoveAction.java new file mode 100644 index 00000000..9bbce073 --- /dev/null +++ b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/action/RemoveAction.java @@ -0,0 +1,42 @@ +package org.simantics.g3d.vtk.action; + +import org.eclipse.jface.action.Action; +import org.simantics.g3d.scenegraph.IG3DNode; +import org.simantics.g3d.scenegraph.structural.IStructuralNode; +import org.simantics.g3d.vtk.Activator; +import org.simantics.g3d.vtk.common.VTKNodeMap; + +public class RemoveAction extends Action { + + private VTKNodeMap nodeMap; + protected IG3DNode node; + + public RemoveAction(VTKNodeMap nodeMap) { + setText("Remove"); + setImageDescriptor(Activator.imageDescriptorFromPlugin("com.famfamfam.silk", "icons/delete.png")); + this.nodeMap = nodeMap; + } + + public void setNode(IG3DNode node) { + this.node = node; + setEnabled(isRemovable(node)); + } + + public boolean isRemovable(IG3DNode node) { + if ((node instanceof IStructuralNode) && ((IStructuralNode)node).isPartOfInstantiatedModel() && !((IStructuralNode)node).isInstantiatedModelRoot()) + return false; + return true; + } + + @Override + public void run() { + + doRemove(node); + nodeMap.commit(); + node = null; + } + + protected void doRemove(IG3DNode node) { + node.remove(); + } +} diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/action/RotateAction.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/action/RotateAction.java new file mode 100644 index 00000000..b2752c4c --- /dev/null +++ b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/action/RotateAction.java @@ -0,0 +1,647 @@ +package org.simantics.g3d.vtk.action; + +import java.awt.Cursor; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; + +import javax.vecmath.AxisAngle4d; +import javax.vecmath.Point3d; +import javax.vecmath.Quat4d; +import javax.vecmath.Vector3d; + +import org.simantics.g3d.math.EulerTools; +import org.simantics.g3d.math.MathTools; +import org.simantics.g3d.math.Ray; +import org.simantics.g3d.math.EulerTools.Order; +import org.simantics.g3d.preferences.PreferenceConstants; +import org.simantics.g3d.scenegraph.IG3DNode; +import org.simantics.g3d.scenegraph.structural.IStructuralNode; +import org.simantics.g3d.vtk.Activator; +import org.simantics.g3d.vtk.common.InteractiveVtkPanel; +import org.simantics.g3d.vtk.common.VTKNodeMap; +import org.simantics.g3d.vtk.gizmo.RotateAxisGizmo; +import org.simantics.g3d.vtk.utils.vtkUtil; +import org.simantics.utils.threads.AWTThread; +import org.simantics.utils.threads.ThreadUtils; + +import vtk.vtkProp; +/** + * FIXME: complete rewrite. + * + * @author Marko Luukkainen + * + */ +public class RotateAction extends vtkAction{ + + public static final int X = 0; + public static final int Y = 1; + public static final int Z = 2; + public static final int P = 3; + + private VTKNodeMap nodeMap; + //private TranslateGizmo gizmo = new TranslateGizmo(); + private RotateAxisGizmo gizmo = new RotateAxisGizmo(); + private IG3DNode node; + + + + private Cursor activeCursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR); + private Cursor dragCursor = Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR); + + + int stepMethod = 1; + Order order = Order.YXZ; + + private int steps; + private double angles[]; + + int index = P; + boolean valid = false; + private boolean worldCoord = true; + //private AxisAngle4d aa = null; + private Quat4d parentWorldOrientation = null; + + //AxisAngle4d rotation = new AxisAngle4d(); + Quat4d worldOrientation = new Quat4d(); + + public void setNode(IG3DNode node) { + this.node = node; + if ((node instanceof IStructuralNode) && ((IStructuralNode)node).isPartOfInstantiatedModel() && !((IStructuralNode)node).isInstantiatedModelRoot()) { + setEnabled(false); + } else { + setEnabled(true); + } + + String set = org.simantics.g3d.Activator.getDefault().getPreferenceStore().getString(PreferenceConstants.ORIENTATION_PRESENTATION); + if (set.equals("aa")) { + stepMethod = 0; + } else if (set.equals("euler")){ + stepMethod = 1; + String eulerOrder = org.simantics.g3d.Activator.getDefault().getPreferenceStore().getString(PreferenceConstants.EULER_ANGLE_ORDER); + try { + order = Order.valueOf(eulerOrder); + } catch (Exception e) { + order = Order.YXZ; + } + } else { + stepMethod = 2; + } + } + + public IG3DNode getNode() { + return node; + } + + public RotateAction(InteractiveVtkPanel panel, VTKNodeMap nodeMap) { + super(panel); + setImageDescriptor(Activator.imageDescriptorFromPlugin("com.famfamfam.silk", "icons/arrow_rotate_clockwise.png")); + setText("Rotate"); + this.nodeMap = nodeMap; + + + steps = 36; + angles = new double[steps+1]; + for (int i = 0; i < angles.length; i++) { + angles[i] = - Math.PI + (Math.PI * i * 2.0 / steps); + } + } + + public void attach() { + if (node == null) + return; + + super.attach(); + ThreadUtils.asyncExec(AWTThread.getThreadAccess(), new Runnable() { + public void run() { + attachUI(); + update(); + } + }); + + + + } + + public void deattach() { + + node = null; + nodeMap.commit(); + deattachUI(); + super.deattach(); + panel.repaint(); + } + + private void attachUI() { + panel.setCursor(activeCursor); + gizmo.attach(panel.GetRenderer()); + } + + private void deattachUI() { + panel.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + gizmo.deattach(); + } + + @Override + public void keyPressed(KeyEvent e) { + if (e.getKeyCode() == KeyEvent.VK_ESCAPE) + panel.useDefaultAction(); + if (valid) + return; + if (e.getKeyCode() == KeyEvent.VK_X) { + if (index != X) + index = X; + else + index = P; + } + if (e.getKeyCode() == KeyEvent.VK_Y) { + if (index != Y) + index = Y; + else + index = P; + } + if (e.getKeyCode() == KeyEvent.VK_Z) { + if (index != Z) + index = Z; + else + index = P; + } + if (e.getKeyCode() == KeyEvent.VK_G) { + worldCoord = !worldCoord; + } + gizmo.setType(index); + panel.repaint(); + } + + @Override + public void keyReleased(KeyEvent e) { + + } + + + + @Override + public void mouseClicked(MouseEvent e) { + if (e.getClickCount() > 1) { + if (isOverNode(e)) { + return; + } + panel.useDefaultAction(); + //if(!gizmo.isPartOf(actor)) + // panel.useDefaultAction(); + + } + } + + @Override + public void mouseEntered(MouseEvent e) { + + } + + @Override + public void mouseExited(MouseEvent e) { + + } + + + + + + public void setWorldCoord(boolean b) { + if (worldCoord == b) + return; + worldCoord = b; + update(); + + } + + + private void update() { + Vector3d nodePos = node.getWorldPosition(); + System.out.println(nodePos); + gizmo.setPosition(nodePos); + if (worldCoord) { + gizmo.setRotation(new AxisAngle4d()); + parentWorldOrientation = null; + } else { + AxisAngle4d aa = new AxisAngle4d(); + parentWorldOrientation = ((IG3DNode)node.getParent()).getWorldOrientation(); + aa.set(parentWorldOrientation); + gizmo.setRotation(aa); + } + + Point3d camPos = new Point3d(panel.GetRenderer().GetActiveCamera().GetPosition()); + Vector3d p = new Vector3d(nodePos); + p.sub(camPos); + + if (parentWorldOrientation != null) { + Quat4d qi = new Quat4d(parentWorldOrientation); + qi.inverse(); + MathTools.rotate(parentWorldOrientation, p, p); + } + if (panel.GetRenderer().GetActiveCamera().GetParallelProjection() == 0) { + double distance = p.length(); + p.negate(); + double fov = panel.GetRenderer().GetActiveCamera().GetViewAngle(); + float s = (float) (Math.sin(fov) * distance * 0.1); + + Vector3d scale = new Vector3d(1., 1., 1.); + +// if (p.x > 0.f) +// scale.x = -1.; +// if (p.y > 0.f) +// scale.y = -1.; +// if (p.z > 0.f) +// scale.z = -1.; + scale.scale(s); + gizmo.setScale(scale); + + } else { + Vector3d scale = new Vector3d(1.f, 1.f, 1.f); + double s = panel.GetRenderer().GetActiveCamera().GetParallelScale() / 5.; +// if (p.x > 0.f) +// scale.x = -1.; +// if (p.y > 0.f) +// scale.y = -1.; +// if (p.z > 0.f) +// scale.z = -1.; + scale.scale(s); + gizmo.setScale(scale); + } + + panel.Render(); + } + + private boolean isOverNode(MouseEvent e) { + vtkProp picked[] = panel.pick(e.getX(), e.getY()); + if (picked !=null) { + for (int i = 0; i < picked.length; i++) { + if (node.equals(nodeMap.getNode(picked[i]))) + return true; + } + } + return false; + } + + + + @Override + public void mousePressed(MouseEvent e) { + if (e.getButton() == MouseEvent.BUTTON1) { + + + if (isOverNode(e)) { + valid = true; + if ((e.getModifiers() & MouseEvent.CTRL_MASK) > 0) { + useStep = true; + } else { + useStep = false; + } + worldOrientation = node.getWorldOrientation(); + doChanges(true, e.getX(), e.getY()); + + panel.setCursor(dragCursor); + } else { + valid = false; + panel.getDefaultAction().mousePressed(e); + panel.setCursor(activeCursor); + } + } else { + panel.getDefaultAction().mousePressed(e); + } + } + + + + @Override + public void mouseReleased(MouseEvent e) { + if (e.getButton() == MouseEvent.BUTTON1) { + valid = false; + worldOrientation = null; + panel.setCursor(activeCursor); + } else { + panel.getDefaultAction().mouseReleased(e); + } + } + + @Override + public void mouseDragged(MouseEvent e) { + if ((e.getModifiersEx() & MouseEvent.BUTTON1_DOWN_MASK) > 0 && valid) { + if ((e.getModifiers() & MouseEvent.CTRL_MASK) > 0) { + useStep = true; + } else { + useStep = false; + } + doChanges(false, e.getX(), e.getY()); + + //nodeMap.modified(node); + update(); + } else { + panel.getDefaultAction().mouseDragged(e); + update(); + } + } + + Vector3d axis = null; + + @Override + public void keyTyped(KeyEvent e) { + if (e.getKeyCode() == KeyEvent.VK_LEFT) { + inputType = InputType.KEY; + axis = new Vector3d(0.0,1.0,0.0); + } else if (e.getKeyCode() == KeyEvent.VK_RIGHT) { + inputType = InputType.KEY; + axis = new Vector3d(0.0,-1.0,0.0); + } else if (e.getKeyCode() ==KeyEvent.VK_UP) { + inputType = InputType.KEY; + axis = new Vector3d(1.0,0.0,0.0); + } else if (e.getKeyCode() == KeyEvent.VK_DOWN) { + inputType = InputType.KEY; + axis = new Vector3d(-1.0,0.0,0.0); + } + } + + public void doChanges(boolean pressed, int x, int y) { + Ray ray = vtkUtil.createMouseRay(panel.GetRenderer(),x, y); + Vector3d p = node.getWorldPosition(); + + if (pressed) { + Vector3d axis = getRotationAxis(); + if (axis != null) { + if (!worldCoord) { + MathTools.rotate(parentWorldOrientation, axis, axis); + } + + + double s[] = new double[2]; + Vector3d i2 = new Vector3d(); + + boolean intersect = MathTools.intersectStraightPlane(ray.pos, ray.dir, p, axis, i2, s); + double dot = Math.abs(ray.dir.dot(axis)); + if (intersect && dot > 0.4) + inputType = InputType.INTERSECT; + else + inputType = InputType.NONINTERSECT; + + + if (inputType == InputType.INTERSECT) { + // picking ray and plane defined by gizmo's center point and + // rotation axis can intersect + // vector from center point to intersection point + i2.sub(p); + // creating vectors i and j that are lying on the plane and + // are perpendicular + // vectors are used to calculate polar coordinate for + // intersection point + j.set(i2); + i.cross(j, axis); + System.out.println("I,J " + i + " " + j); + double angleI = i2.angle(i); + double angleJ = i2.angle(j); + prevAngle = Math.atan2(Math.cos(angleJ), Math.cos(angleI)); + } else { + // picking ray and plane defined by gizmo's center point and + // rotation axis are parallel, + // so we'll use cross product of rotation axis and picking + // ray to detect amount of rotation + i.cross(ray.dir, axis); + MathTools.intersectStraightStraight(ray.pos, ray.dir, p, i, new Vector3d(), new Vector3d(), s); + prevS = s[1]; + } + } + + + } + + if (inputType != InputType.KEY) + axis = getRotationAxis(); + if (axis == null) { + return; + } + Vector3d taxis = null; + if (!worldCoord) { + taxis = new Vector3d(axis); + MathTools.rotate(parentWorldOrientation, axis, axis); + } + System.out.println(inputType); + if (inputType == InputType.INTERSECT) { + + double s[] = new double[2]; + Vector3d i2 = new Vector3d(); + MathTools.intersectStraightPlane(ray.pos, ray.dir, p, axis, i2, s); + i2.sub(p); + double angleI = i2.angle(i); + double angleJ = i2.angle(j); + double angle = Math.atan2(Math.cos(angleJ), Math.cos(angleI)); + System.out.println("Angle " + angle + " i " + angleI + " j " + angleJ + " prev " + prevAngle); + if(!worldCoord) + axis = taxis; + if (useStep) { + + //setOrientation(MathTools.getQuat(rotation)); + AxisAngle4d rot = new AxisAngle4d(axis,angle-prevAngle); + Quat4d qrot = new Quat4d(); + MathTools.getQuat(rot, qrot); + //prevAngle = angle; + qrot.mulInverse(worldOrientation); + + + if (stepMethod == 0) { + rot.set(qrot); + rot.angle = roundAngle(rot.angle); + //qrot.set(rot); + MathTools.getQuat(rot,qrot); + setOrientation(qrot); + } else if (stepMethod == 1){ + + //Vector3d euler = MathTools.getEuler(qrot); + Vector3d euler = EulerTools.getEulerFromQuat(order, qrot); + euler.x = roundAngle(euler.x); + euler.y = roundAngle(euler.y); + euler.z = roundAngle(euler.z); + //Quat4d q = MathTools.getQuat(euler); + Quat4d q = EulerTools.getQuatFromEuler(order, euler); + setOrientation(q); + System.out.println(" (" + MathTools.radToDeg(euler.x) + " " + MathTools.radToDeg(euler.y) + " " + MathTools.radToDeg(euler.z) + ") " + qrot + " "+ q); + } else { + setOrientation(qrot); + } + + } else { + if (worldCoord) { + //G3DTools.multiplyOrientation(mo.getG3DNode(graph).getWorldOrientation(), new AxisAngle4d(axis,angle-prevAngle)); + AxisAngle4d aa = MathTools.getAxisAngle(node.getWorldOrientation()); + AxisAngle4d rot = new AxisAngle4d(axis,angle-prevAngle); + MathTools.multiplyOrientation(aa, rot); + setWorldOrientation(MathTools.getQuat(rot)); + } else { + AxisAngle4d aa = MathTools.getAxisAngle(node.getOrientation()); + AxisAngle4d rot = new AxisAngle4d(axis,angle-prevAngle); + MathTools.multiplyOrientation(aa, rot); + setOrientation(MathTools.getQuat(rot)); + //G3DTools.multiplyOrientation(mo.getG3DNode(graph).getLocalOrientation(), new AxisAngle4d(axis,angle-prevAngle)); + } + prevAngle = angle; + } + + } else if (inputType == InputType.NONINTERSECT){ + + double s[] = new double[2]; + MathTools.intersectStraightStraight(ray.pos, ray.dir, p, i, new Vector3d(), new Vector3d(), s); + if(!worldCoord) + axis = taxis; + if (useStep) { + //setOrientation(MathTools.getQuat(rotation)); + AxisAngle4d rot = new AxisAngle4d(axis,s[1] - prevS); + + Quat4d qrot = new Quat4d(); + //qrot.set(rot); + MathTools.getQuat(rot, qrot); + //prevAngle = angle; + qrot.mulInverse(worldOrientation); + + + if (stepMethod == 0) { + rot.set(qrot); + rot.angle = roundAngle(rot.angle); + //qrot.set(rot); + MathTools.getQuat(rot,qrot); + setOrientation(qrot); + } else if (stepMethod == 1){ + + //Vector3d euler = MathTools.getEuler(qrot); + Vector3d euler = EulerTools.getEulerFromQuat(order, qrot); + euler.x = roundAngle(euler.x); + euler.y = roundAngle(euler.y); + euler.z = roundAngle(euler.z); + //Quat4d q = MathTools.getQuat(euler); + Quat4d q = EulerTools.getQuatFromEuler(order, euler); + setOrientation(q); + System.out.println(" (" + MathTools.radToDeg(euler.x) + " " + MathTools.radToDeg(euler.y) + " " + MathTools.radToDeg(euler.z) + ") " + qrot + " "+ q); + } else { + setOrientation(qrot); + } + prevS = s[1]; + +// G3DTools.setOrientation(mo.getG3DNode(graph).getLocalOrientation(), rotations.get(mo)); +// G3DTools.multiplyOrientation(mo.getG3DNode(graph).getWorldOrientation(), new AxisAngle4d(axis,s[1] - prevS)); +// AxisAngle4d aa = G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation()); +// rotations.put(mo, aa); +// Vector3d euler = MathTools.getEuler(aa); +// euler.x = roundAngle(euler.x); +// euler.y = roundAngle(euler.y); +// euler.z = roundAngle(euler.z); +// aa = MathTools.getFromEuler2(euler); +// prevS = s[1]; +// G3DTools.setOrientation(mo.getG3DNode(graph).getLocalOrientation(), aa); +// Vector3d e = MathTools.getEuler(G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation())); +// e.scale(180.0/Math.PI); +// text += G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation()) + " " + e + " "; + + + } else { + if (worldCoord) { + AxisAngle4d aa = MathTools.getAxisAngle(node.getWorldOrientation()); + AxisAngle4d rot = new AxisAngle4d(axis,s[1] - prevS); + MathTools.multiplyOrientation(aa, rot); + setWorldOrientation(MathTools.getQuat(rot)); + //G3DTools.multiplyOrientation(mo.getG3DNode(graph).getWorldOrientation(), new AxisAngle4d(axis,s[1] - prevS)); + } else { + AxisAngle4d aa = MathTools.getAxisAngle(node.getOrientation()); + AxisAngle4d rot = new AxisAngle4d(axis,s[1] - prevS); + MathTools.multiplyOrientation(aa, rot); + setOrientation(MathTools.getQuat(rot)); + //G3DTools.multiplyOrientation(mo.getG3DNode(graph).getLocalOrientation(), new AxisAngle4d(axis,s[1] - prevS)); + } + //text += G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation()) + " " + MathTools.getEuler(G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation())) + " "; + prevS = s[1]; + + } + + } else { + if (worldCoord) { + AxisAngle4d aa = MathTools.getAxisAngle(node.getWorldOrientation()); + AxisAngle4d rot = new AxisAngle4d(axis,Math.PI * 0.5); + MathTools.multiplyOrientation(aa, rot); + setWorldOrientation(MathTools.getQuat(rot)); + //G3DTools.multiplyOrientation(mo.getG3DNode(graph).getWorldOrientation(), new AxisAngle4d(axis,Math.PI * 0.5)); + } else { + AxisAngle4d aa = MathTools.getAxisAngle(node.getOrientation()); + AxisAngle4d rot = new AxisAngle4d(axis,Math.PI * 0.5); + MathTools.multiplyOrientation(aa, rot); + setOrientation(MathTools.getQuat(rot)); + //G3DTools.multiplyOrientation(mo.getG3DNode(graph).getLocalOrientation(), new AxisAngle4d(axis,Math.PI * 0.5)); + } + // text += G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation()) + " " + MathTools.getEuler(G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation())) + " "; + + } + //setInfoText(text); + + } + + protected void setOrientation(Quat4d q) { + node.setOrientation(q); + } + + protected void setWorldOrientation(Quat4d q) { + node.setWorldOrientation(q); + } + + @Override + public void mouseMoved(MouseEvent e) { + panel.getDefaultAction().mouseMoved(e); + } + + private Vector3d getRotationAxis() { + switch (index) { + case X: + return new Vector3d(1.0, 0.0, 0.0); + case Y: + return new Vector3d(0.0, 1.0, 0.0); + case Z: + return new Vector3d(0.0, 0.0, 1.0); + case P: + Vector3d axis = new Vector3d(panel.GetRenderer().GetActiveCamera() + .GetDirectionOfProjection()); + axis.normalize(); + return axis; + default: + return null; + } + } + + private double prevS = 0.0; + + private Vector3d i = new Vector3d(); + private Vector3d j = new Vector3d(); + private double prevAngle = 0; + + enum InputType{INTERSECT,NONINTERSECT,KEY,NONE}; + InputType inputType; + private boolean useStep = false; + + + + private double roundAngle(double angle) { + while (angle < - Math.PI) + angle += Math.PI*2.0; + while (angle > Math.PI) + angle -= Math.PI*2.0; + + + int index = 0; + while (angle > angles[index]) + index++; + if (index == 0) { + angle = angles[0]; + } else { + double d = angle - angles[index - 1]; + double d2 = angles[index] - angle; + if (d < d2) + angle = angles[index - 1]; + else + angle = angles[index]; + } + return angle; + } + +} diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/action/TranslateAction.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/action/TranslateAction.java new file mode 100644 index 00000000..785e549d --- /dev/null +++ b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/action/TranslateAction.java @@ -0,0 +1,475 @@ +package org.simantics.g3d.vtk.action; + +import java.awt.Cursor; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.math.BigDecimal; + +import javax.vecmath.AxisAngle4d; +import javax.vecmath.Point3d; +import javax.vecmath.Quat4d; +import javax.vecmath.Vector3d; + +import org.simantics.g3d.math.MathTools; +import org.simantics.g3d.math.Ray; +import org.simantics.g3d.scenegraph.IG3DNode; +import org.simantics.g3d.scenegraph.structural.IStructuralNode; +import org.simantics.g3d.vtk.Activator; +import org.simantics.g3d.vtk.common.InteractiveVtkPanel; +import org.simantics.g3d.vtk.common.VTKNodeMap; +import org.simantics.g3d.vtk.gizmo.TranslateAxisGizmo; +import org.simantics.g3d.vtk.utils.vtkUtil; +import org.simantics.utils.threads.AWTThread; +import org.simantics.utils.threads.ThreadUtils; + +import vtk.vtkProp; + +public class TranslateAction extends vtkAction{ + + public static final int X = 0; + public static final int Y = 1; + public static final int Z = 2; + public static final int XY = 3; + public static final int XZ = 4; + public static final int YZ = 5; + public static final int P = 6; + + private VTKNodeMap nodeMap; + //private TranslateGizmo gizmo = new TranslateGizmo(); + private TranslateAxisGizmo gizmo = new TranslateAxisGizmo(); + private IG3DNode node; + + + + private Cursor activeCursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR); + private Cursor dragCursor = Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR); + + public void setNode(IG3DNode node) { + this.node = node; + if ((node instanceof IStructuralNode) && ((IStructuralNode)node).isPartOfInstantiatedModel() && !((IStructuralNode)node).isInstantiatedModelRoot()) { + setEnabled(false); + } else { + setEnabled(true); + } + } + + public IG3DNode getNode() { + return node; + } + + public TranslateAction(InteractiveVtkPanel panel, VTKNodeMap nodeMap) { + super(panel); + setImageDescriptor(Activator.imageDescriptorFromPlugin("com.famfamfam.silk", "icons/arrow_out.png")); + setText("Translate"); + this.nodeMap = nodeMap; + } + + public void attach() { + if (node == null) + return; + + super.attach(); + ThreadUtils.asyncExec(AWTThread.getThreadAccess(), new Runnable() { + public void run() { + attachUI(); + update(); + } + }); + + + + } + + public void deattach() { + + node = null; + nodeMap.commit(); + deattachUI(); + super.deattach(); + panel.repaint(); + } + + private void attachUI() { + panel.setCursor(activeCursor); + gizmo.attach(panel.GetRenderer()); + } + + private void deattachUI() { + panel.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + gizmo.deattach(); + } + + @Override + public void keyPressed(KeyEvent e) { + if (e.getKeyCode() == KeyEvent.VK_ESCAPE) + panel.useDefaultAction(); + if (valid) + return; + if (e.getKeyCode() == KeyEvent.VK_X) { + if (index != X) + index = X; + else + index = P; + } + if (e.getKeyCode() == KeyEvent.VK_Y) { + if (index != Y) + index = Y; + else + index = P; + } + if (e.getKeyCode() == KeyEvent.VK_Z) { + if (index != Z) + index = Z; + else + index = P; + } + if (e.getKeyCode() == KeyEvent.VK_G) { + worldCoord = !worldCoord; + } + gizmo.setType(index); + + update(); + //panel.repaint(); + } + + @Override + public void keyReleased(KeyEvent e) { + + } + + @Override + public void keyTyped(KeyEvent e) { + + } + + @Override + public void mouseClicked(MouseEvent e) { + if (e.getClickCount() > 1) { + if (isOverNode(e)) { + return; + } else { + panel.useDefaultAction(); + } + //if(!gizmo.isPartOf(actor)) + // panel.useDefaultAction(); + + } + } + + private boolean isOverNode(MouseEvent e) { + vtkProp picked[] = panel.pick(e.getX(), e.getY()); + if (picked !=null) { + for (int i = 0; i < picked.length; i++) { + if (node.equals(nodeMap.getNode(picked[i]))) + return true; + } + } + return false; + } + + @Override + public void mouseEntered(MouseEvent e) { + + } + + @Override + public void mouseExited(MouseEvent e) { + + } + + int index = P; + boolean valid = false; + private boolean worldCoord = true; + private AxisAngle4d aa = null; + private Quat4d q = null; + + + public void setWorldCoord(boolean b) { + if (worldCoord == b) + return; + worldCoord = b; + update(); + + } + + + private void update() { + if (node == null) + return; + if (worldCoord) { + gizmo.setRotation(new AxisAngle4d()); + aa = null; + q = null; + } else { + aa = new AxisAngle4d(); + aa.set(((IG3DNode)node.getParent()).getWorldOrientation()); + gizmo.setRotation(aa); + q = new Quat4d(); + MathTools.getQuat(aa, q); + } + + Vector3d nodePos = node.getWorldPosition(); + //System.out.println(nodePos); + gizmo.setPosition(nodePos); + + + Point3d camPos = new Point3d(panel.GetRenderer().GetActiveCamera().GetPosition()); + Vector3d p = new Vector3d(nodePos); + p.sub(camPos); + + if (q != null) { + Quat4d qi = new Quat4d(q); + qi.inverse(); + MathTools.rotate(q, p, p); + } + if (panel.GetRenderer().GetActiveCamera().GetParallelProjection() == 0) { + double distance = p.length(); + p.negate(); + double fov = panel.GetRenderer().GetActiveCamera().GetViewAngle(); + float s = (float) (Math.sin(fov) * distance * 0.1); + + Vector3d scale = new Vector3d(1., 1., 1.); + +// if (p.x > 0.f) +// scale.x = -1.; +// if (p.y > 0.f) +// scale.y = -1.; +// if (p.z > 0.f) +// scale.z = -1.; + scale.scale(s); + gizmo.setScale(scale); + + } else { + Vector3d scale = new Vector3d(1.f, 1.f, 1.f); + double s = panel.GetRenderer().GetActiveCamera().GetParallelScale() / 5.; +// if (p.x > 0.f) +// scale.x = -1.; +// if (p.y > 0.f) +// scale.y = -1.; +// if (p.z > 0.f) +// scale.z = -1.; + scale.scale(s); + gizmo.setScale(scale); + } + + //panel.Render(); + panel.repaint(); + } + + Vector3d prevTranslate = null; + + @Override + public void mousePressed(MouseEvent e) { + if (e.getButton() == MouseEvent.BUTTON1) { + + if (isOverNode(e)) { + prevTranslate = getTranslate(e.getX(), e.getY()); + valid = true; + panel.setCursor(dragCursor); + } else { + valid = false; + panel.getDefaultAction().mousePressed(e); + panel.setCursor(activeCursor); + } + } else { + panel.getDefaultAction().mousePressed(e); + } + //index = gizmo.getTranslateAxis(actor); + //if (index == -1) { + // valid = false; + // panel.getDefaultAction().mousePressed(e); + // return; + //} + //valid = true; + //prevTranslate = getTranslate(e.getX(), e.getY()); + //System.out.println("start translate " + prevTranslate); + } + + + + @Override + public void mouseReleased(MouseEvent e) { + if (e.getButton() == MouseEvent.BUTTON1) { + valid = false; + prevTranslate = null; + panel.setCursor(activeCursor); + } else { + panel.getDefaultAction().mouseReleased(e); + } + } + + @Override + public void mouseDragged(MouseEvent e) { + if ((e.getModifiersEx() & MouseEvent.BUTTON1_DOWN_MASK) > 0 && valid) { + + Vector3d translate = getTranslate(e.getX(), e.getY(), prevTranslate); + //System.out.println("translate " + translate); + if (translate == null) + return; + boolean step = ((e.getModifiers() & MouseEvent.CTRL_MASK) > 0); + if (worldCoord) { + Vector3d pos = new Vector3d(node.getWorldPosition()); + pos.add(translate); + pos = constaints(pos, step); + setWorldPos(pos); + } else { + Vector3d pos = new Vector3d(node.getPosition()); + pos.add(translate); + pos = constaints(pos, step); + setPos(pos); + } + //mapping.rangeModified(node); + + //nodeMap.modified(node); + update(); + } else { + panel.getDefaultAction().mouseDragged(e); + update(); + } + } + + protected void setPos(Vector3d pos) { + node.setPosition(pos); + } + + protected void setWorldPos(Vector3d pos) { + node.setWorldPosition(pos); + } + + private double istep = 10.0; + private int decimals = 2; + + private Vector3d constaints(Vector3d p, boolean step) { + if(!step) + return p; + switch (index) { + case X: + p.x = Math.round(istep * p.x) / istep; + BigDecimal bx = new BigDecimal(p.x); + bx.setScale(decimals, BigDecimal.ROUND_HALF_UP); + p.x = bx.doubleValue(); + break; + case Y: + p.y = Math.round(istep * p.y) / istep; + BigDecimal by = new BigDecimal(p.y); + by.setScale(decimals, BigDecimal.ROUND_HALF_UP); + p.y = by.doubleValue(); + break; + + case Z: + p.z = Math.round(istep * p.z) / istep; + BigDecimal bz = new BigDecimal(p.z); + bz.setScale(decimals, BigDecimal.ROUND_HALF_UP); + p.z = bz.doubleValue(); + break; + } + return p; + } + + @Override + public void mouseMoved(MouseEvent e) { + panel.getDefaultAction().mouseMoved(e); + } + + Vector3d getTranslate(double x, double y) { + return getTranslate(x, y, new Vector3d()); + } + + Vector3d getTranslate(double x, double y, Vector3d offset) { + Vector3d translate = new Vector3d(); + + Ray ray = vtkUtil.createMouseRay(panel.GetRenderer(),x, y); + + Vector3d p = node.getWorldPosition(); + Vector3d dir = null; + + switch (index) { + case P: + Vector3d normal = new Vector3d(panel.GetRenderer().GetActiveCamera().GetDirectionOfProjection()); + if (!worldCoord) { + MathTools.rotate(q, normal, normal); + } + normal.normalize(); + double s[] = new double[1]; + Vector3d r = new Vector3d(); + if (MathTools.intersectStraightPlane(ray.pos, ray.dir, p, normal, r)) { + r.sub(p); + translate.x = r.x; + translate.y = r.y; + translate.z = r.z; + } + break; + + case X : + dir = new Vector3d(1.0,0.0,0.0); + if(!worldCoord) + MathTools.rotate(q, dir, dir); + Vector3d i1 = new Vector3d(); + Vector3d i2 = new Vector3d(); + s = new double[2]; + MathTools.intersectStraightStraight( p, dir,ray.pos, ray.dir, i2, i1,s); + translate.x = s[0]; + + break; + case Y : + dir = new Vector3d(0.0,1.0,0.0); + if(!worldCoord) + MathTools.rotate(q, dir, dir); + i1 = new Vector3d(); + i2 = new Vector3d(); + s = new double[2]; + MathTools.intersectStraightStraight( p, dir,ray.pos, ray.dir, i2, i1,s); + translate.y = s[0]; + break; + case Z : + dir = new Vector3d(0.0,0.0,1.0); + if(!worldCoord) + MathTools.rotate(q, dir, dir); + i1 = new Vector3d(); + i2 = new Vector3d(); + s = new double[2]; + MathTools.intersectStraightStraight( p, dir,ray.pos, ray.dir, i2, i1,s); + translate.z = s[0]; + break; + case XY : + normal = new Vector3d(0.0,0.0,1.0); + if(!worldCoord) + MathTools.rotate(q, normal, normal); + r = new Vector3d(); + if (MathTools.intersectStraightPlane(ray.pos, ray.dir, p, normal, r)) { + r.sub(p); + translate.x = r.x; + translate.y = r.y; + } + break; + case XZ : + normal = new Vector3d(0.0,1.0,0.0); + if(!worldCoord) + MathTools.rotate(q, normal, normal); + r = new Vector3d(); + if (MathTools.intersectStraightPlane(ray.pos, ray.dir, p, normal, r)) { + r.sub(p); + translate.x = r.x; + translate.z = r.z; + } + break; + case YZ : + normal = new Vector3d(1.0,0.0,0.0); + if(!worldCoord) + MathTools.rotate(q, normal, normal); + r = new Vector3d(); + if (MathTools.intersectStraightPlane(ray.pos, ray.dir, p, normal, r)) { + r.sub(p); + translate.y = r.y; + translate.z = r.z; + } + break; + default : + + return null; + } + translate.sub(offset); + return translate; + } + +} diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/action/vtkAction.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/action/vtkAction.java new file mode 100644 index 00000000..d4c127bf --- /dev/null +++ b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/action/vtkAction.java @@ -0,0 +1,88 @@ +package org.simantics.g3d.vtk.action; + +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; + +import org.eclipse.jface.action.Action; +import org.simantics.g3d.vtk.common.InteractiveVtkPanel; + +public abstract class vtkAction extends Action implements KeyListener, MouseListener, MouseMotionListener { + + protected InteractiveVtkPanel panel; + + public vtkAction(InteractiveVtkPanel panel) { + this.panel = panel; + } + + @Override + public void run() { + panel.setActiveAction(this); + } + + + public void attach() { + + panel.addKeyListener(this); + panel.addMouseListener(this); + panel.addMouseMotionListener(this); + + } + + public void deattach() { + panel.removeKeyListener(this); + panel.removeMouseListener(this); + panel.removeMouseMotionListener(this); + } + + @Override + public void keyPressed(KeyEvent e) { + + } + + @Override + public void keyReleased(KeyEvent e) { + + } + + @Override + public void keyTyped(KeyEvent e) { + + } + + public void mouseClicked(java.awt.event.MouseEvent e) { + + }; + + @Override + public void mouseDragged(MouseEvent e) { + + } + + @Override + public void mouseEntered(MouseEvent e) { + + } + + @Override + public void mouseExited(MouseEvent e) { + + } + + @Override + public void mouseMoved(MouseEvent e) { + + } + + @Override + public void mousePressed(MouseEvent e) { + + } + + @Override + public void mouseReleased(MouseEvent e) { + + } +} diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/action/vtkCameraAndSelectorAction.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/action/vtkCameraAndSelectorAction.java new file mode 100644 index 00000000..f6cf7326 --- /dev/null +++ b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/action/vtkCameraAndSelectorAction.java @@ -0,0 +1,371 @@ +package org.simantics.g3d.vtk.action; + +import java.awt.event.InputEvent; +import java.awt.event.MouseEvent; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.ISelectionProvider; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.swt.widgets.Display; +import org.simantics.g3d.tools.AdaptationUtils; +import org.simantics.g3d.vtk.common.InteractiveVtkPanel; + +import vtk.vtkActor; +import vtk.vtkCamera; +import vtk.vtkProp; +import vtk.vtkRenderWindow; +import vtk.vtkRenderer; + +public class vtkCameraAndSelectorAction extends vtkAction implements ISelectionProvider { + + protected vtkRenderer ren; + protected int lastX; + protected int lastY; + protected vtkRenderWindow rw; + protected vtkCamera cam; + protected int InteractionMode = 1; + + public vtkCameraAndSelectorAction(InteractiveVtkPanel panel) { + super(panel); + this.ren = panel.GetRenderer(); + this.rw = panel.GetRenderWindow(); + this.cam = ren.GetActiveCamera(); + } + + public void Lock() { + panel.lock(); + } + + public void UnLock() { + panel.unlock(); + } + + public void InteractionModeRotate() + { + this.InteractionMode = 1; + } + + public void InteractionModeTranslate() + { + this.InteractionMode = 2; + } + + public void InteractionModeZoom() + { + this.InteractionMode = 3; + } + + public void resetCameraClippingRange() { + Lock(); + ren.ResetCameraClippingRange(); + UnLock(); + } + + public void resetCamera() { + Lock(); + ren.ResetCamera(); + UnLock(); + } + + public void mousePressed(MouseEvent e) + { + + if (ren.VisibleActorCount() == 0) return; + rw.SetDesiredUpdateRate(5.0); + lastX = e.getX(); + lastY = e.getY(); + if ((e.getModifiers()==InputEvent.BUTTON2_MASK) || + (e.getModifiers()==(InputEvent.BUTTON1_MASK | InputEvent.SHIFT_MASK))) + { + InteractionModeTranslate(); + } + else if (e.getModifiers()==InputEvent.BUTTON3_MASK) + { + InteractionModeZoom(); + } + else + { + InteractionModeRotate(); + } + } + + public void mouseReleased(MouseEvent e) + { + rw.SetDesiredUpdateRate(0.01); + } + + + + public void mouseDragged(MouseEvent e) + { + if (ren.VisibleActorCount() == 0) return; + int x = e.getX(); + int y = e.getY(); + // rotate + if (this.InteractionMode == 1) + { + cam.Azimuth(lastX - x); + cam.Elevation(y - lastY); + cam.OrthogonalizeViewUp(); + resetCameraClippingRange(); + panel.UpdateLight(); + } + // translate + if (this.InteractionMode == 2) + { + double FPoint[]; + double PPoint[]; + double APoint[] = new double[3]; + double RPoint[]; + double focalDepth; + + // get the current focal point and position + FPoint = cam.GetFocalPoint(); + PPoint = cam.GetPosition(); + + // 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; + 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]; + RPoint[2] = RPoint[2]/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]); + resetCameraClippingRange(); + } + // zoom + if (this.InteractionMode == 3) + { + double zoomFactor; + //double clippingRange[]; + + zoomFactor = Math.pow(1.02,(y - lastY)); + if (cam.GetParallelProjection() == 1) + { + cam.SetParallelScale(cam.GetParallelScale()/zoomFactor); + } + else + { + cam.Dolly(zoomFactor); + resetCameraClippingRange(); + } + } + lastX = x; + lastY = y; + panel.Render(); + } + + + private List selectActors = new ArrayList(); + private List hoverActor = new ArrayList(); + + @Override + public void mouseClicked(MouseEvent e) { + if (!panel.isFocusOwner()) + return; + if (e.getButton() != MouseEvent.BUTTON1) + return; + vtkProp spick[] = panel.pick(e.getX(), e.getY()); + if (spick != null && spick.length > 0) { + for (vtkProp selectActor : spick) { + if (!e.isControlDown()) { + selectActors.clear(); + selectActors.add(selectActor); + } else { + if (selectActors.contains(selectActor)) + selectActors.remove(selectActor); + else + selectActors.add(selectActor); + } + } + fireSelectionChanged(); + } else if (!e.isControlDown()) { + selectActors.clear(); + fireSelectionChanged(); + } + +// if (e.getClickCount() > 1) +// updatePickRay(e.getX(), e.getY()); + + } + +// private void updatePickRay(double x , double y) { +// Ray ray = vtkUtil.createMouseRay(panel.GetRenderer(), x, y); +// +// +// System.out.println(ray.pos + " " + ray.dir); +// vtkPoints linePoints = new vtkPoints(); +// linePoints.InsertPoint(0,ray.pos.x, ray.pos.y, ray.pos.z); +// linePoints.InsertPoint(1, ray.pos.x + ray.dir.x, ray.pos.y + ray.dir.y, ray.pos.z + ray.dir.z); +// vtkLine aLine = new vtkLine(); +// aLine.GetPointIds().SetId(0, 0); +// aLine.GetPointIds().SetId(1, 1); +// vtkUnstructuredGrid aLineGrid = new vtkUnstructuredGrid(); +// aLineGrid.Allocate(1, 1); +// aLineGrid.InsertNextCell(aLine.GetCellType(), aLine.GetPointIds()); +// aLineGrid.SetPoints(linePoints); +// vtkDataSetMapper aLineMapper = new vtkDataSetMapper(); +// aLineMapper.SetInput(aLineGrid); +// vtkActor aLineActor = new vtkActor(); +// aLineActor.SetMapper(aLineMapper); +// aLineActor.GetProperty().SetDiffuseColor(.2, 1, 1); +// +// if (rayActor != null) { +// panel.GetRenderer().RemoveActor(rayActor); +// rayActor.Delete(); +// } +// rayActor = aLineActor; +// panel.GetRenderer().AddActor(rayActor); +// +// linePoints.Delete(); +// aLine.Delete(); +// aLineGrid.Delete(); +// aLineMapper.Delete(); +// panel.repaint(); +// } +// +// private vtkActor rayActor; + + @Override + public void mouseMoved(MouseEvent e) { + lastX = e.getX(); + lastY = e.getY(); + + if (!panel.isFocusOwner()) + return; + List prevHover = new ArrayList(); + prevHover.addAll(hoverActor); + hoverActor.clear(); + vtkProp pick[] = panel.pick(e.getX(),e.getY()); + if (pick != null) { + for (vtkProp p : pick) + hoverActor.add(p); + } + + if (!prevHover.containsAll(hoverActor) || !hoverActor.containsAll(prevHover)) { + fireHoverChanged(); + } + } + + public List getSelectActor() { + return selectActors; + } + + public List getHoverActor() { + return hoverActor; + } + + private List selectionListeners = new ArrayList(); + + @Override + public void addSelectionChangedListener(ISelectionChangedListener listener) { + selectionListeners.add(listener); + } + + @Override + public ISelection getSelection() { + return new StructuredSelection(selectActors); + } + + @Override + public void removeSelectionChangedListener( + ISelectionChangedListener listener) { + selectionListeners.remove(listener); + } + + @Override + public void setSelection(ISelection selection) { + setSelection(selection, false); + + } + + public void setSelection(ISelection selection, boolean fire) { + Collection selectedProps = AdaptationUtils.adaptToCollection(selection, vtkProp.class); + + selectActors.clear(); + selectActors.addAll(selectedProps); + if (fire) + fireSelectionChanged(); + } + + private void fireSelectionChanged() { + Display.getDefault().asyncExec(new Runnable() { + @Override + public void run() { + + SelectionChangedEvent evt = new SelectionChangedEvent(vtkCameraAndSelectorAction.this, new StructuredSelection(selectActors)); + for (ISelectionChangedListener l :selectionListeners) { + l.selectionChanged(evt); + } + + } + }); + } + + + private List hoverListeners = new ArrayList(); + + + public void addHoverChangedListener(ISelectionChangedListener listener) { + hoverListeners.add(listener); + } + + + public ISelection getHoverSelection() { + return new StructuredSelection(hoverActor); + } + + public void removeHoverChangedListener( + ISelectionChangedListener listener) { + hoverListeners.remove(listener); + } + + private void fireHoverChanged() { + Display.getDefault().asyncExec(new Runnable() { + @Override + public void run() { + StructuredSelection sel = null; + if (hoverActor == null) + sel = new StructuredSelection(); + else + sel = new StructuredSelection(hoverActor); + SelectionChangedEvent evt = new SelectionChangedEvent(vtkCameraAndSelectorAction.this, sel); + for (ISelectionChangedListener l :hoverListeners) { + l.selectionChanged(evt); + } + + } + }); + } + + +} diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/AbstractVTKNodeMap.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/AbstractVTKNodeMap.java new file mode 100644 index 00000000..144138a5 --- /dev/null +++ b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/AbstractVTKNodeMap.java @@ -0,0 +1,490 @@ +package org.simantics.g3d.vtk.common; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Stack; + +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.Session; +import org.simantics.db.WriteGraph; +import org.simantics.db.common.request.ReadRequest; +import org.simantics.db.common.request.WriteRequest; +import org.simantics.db.exception.DatabaseException; +import org.simantics.g3d.ontology.G3D; +import org.simantics.g3d.scenegraph.IG3DNode; +import org.simantics.g3d.scenegraph.RenderListener; +import org.simantics.g3d.scenegraph.base.INode; +import org.simantics.g3d.scenegraph.base.NodeListener; +import org.simantics.g3d.scenegraph.base.ParentNode; +import org.simantics.objmap.graph.IMapping; +import org.simantics.objmap.graph.IMappingListener; +import org.simantics.utils.datastructures.Callback; +import org.simantics.utils.datastructures.MapList; +import org.simantics.utils.datastructures.MapSet; +import org.simantics.utils.datastructures.Pair; +import org.simantics.utils.ui.ExceptionUtils; + +import vtk.vtkProp; + +public abstract class AbstractVTKNodeMap implements VTKNodeMap, IMappingListener, RenderListener, NodeListener{ + + private static final boolean DEBUG = false; + + protected Session session; + protected IMapping mapping; + protected InteractiveVtkPanel panel; + + protected MapList nodeToActor = new MapList(); + protected Map actorToNode = new HashMap(); + + protected ParentNode rootNode; + + public AbstractVTKNodeMap(Session session, IMapping mapping, InteractiveVtkPanel panel, ParentNode rootNode) { + this.session = session; + this.mapping = mapping; + this.panel = panel; + this.rootNode = rootNode; + panel.addListener(this); + mapping.addMappingListener(this); + rootNode.addListener(this); + } + + + protected abstract void addActor(E node); + protected abstract void removeActor(E node); + protected abstract void updateActor(E node,Set ids); + + public void repaint() { + panel.repaint(); + } + + public void populate() { + for (E node : rootNode.getNodes()) { + receiveAdd(node, node.getParentRel(),true); + } + repaint(); + } + + @Override + public INode getNode(vtkProp prop) { + return actorToNode.get(prop); + } + + @SuppressWarnings("unchecked") + @Override + public Collection getRenderObjects(INode node) { + return nodeToActor.getValues((E)node); + } + + @SuppressWarnings("unchecked") + @Override + public ParentNode getRootNode() { + return (ParentNode)rootNode; + } + + + + @Override + public boolean isChangeTracking() { + return changeTracking; + } + + @Override + public void setChangeTracking(boolean enabled) { + changeTracking = enabled; + } + + private boolean changeTracking = true; + + protected Object syncMutex = new Object(); + + + private List> added = new ArrayList>(); + private List> removed = new ArrayList>(); + //private List> updated = new ArrayList>(); + private MapSet updated = new MapSet.Hash(); + + private boolean rangeModified = false; + + @SuppressWarnings("unchecked") + @Override + public void updateRenderObjectsFor(INode node) { + List toDelete = new ArrayList(); + for (vtkProp prop : nodeToActor.getValues((E)node)) { + if (prop.GetVTKId() != 0) { + panel.GetRenderer().RemoveActor(prop); + //prop.Delete(); + toDelete.add(prop); + } + actorToNode.remove(prop); + } + nodeToActor.remove((E)node); + Collection coll = getActors((E)node); + if (coll == null) + return; + for (vtkProp prop : coll) { + nodeToActor.add((E)node,prop); + actorToNode.put(prop, (E)node); + toDelete.remove(prop); + } + for (vtkProp p : toDelete) + p.Delete(); + } + + protected abstract Collection getActors(E node); + + @SuppressWarnings("unchecked") + private void receiveAdd(E node, String id, boolean db) { + if (DEBUG) System.out.println("receiveAdd " + node + " " + id + " " + db); + synchronized (syncMutex) { + for (Pair n : added) { + if (n.first.equals(node)) + return; + } + if (changeTracking) { + mapping.rangeModified((E)node.getParent()); + } + added.add(new Pair(node, id)); + rangeModified = true; + } + panel.repaint(); + } + + @SuppressWarnings("unchecked") + private void receiveRemove(E node, String id, boolean db) { + if (DEBUG) System.out.println("receiveRemove " + node + " " + id + " " + db); + synchronized (syncMutex) { + for (Pair n : removed) { + if (n.first.equals(node)) + return; + } + if (changeTracking && !db) + mapping.rangeModified((E)node.getParent()); + removed.add(new Pair(node, id)); + rangeModified = true; + } + panel.repaint(); + } + + @SuppressWarnings("unchecked") + private void receiveUpdate(E node, String id, boolean db) { + if (DEBUG) System.out.println("receiveUpdate " + node + " " + id + " " + db); + synchronized (syncMutex) { +// for (Pair n : updated) { +// if (n.first.equals(node)) +// return; +// } + if (changeTracking && !db) + mapping.rangeModified(node); + //updated.add(new Pair(node, id)); + updated.add(node, id); + rangeModified = true; + } + panel.repaint(); + } + + private boolean graphUpdates = false; + private Set graphModified = new HashSet(); + + private boolean requestCommit = false; + + @Override + public void commit() { + requestCommit = true; + } + + protected void doCommit() { + session.asyncRequest(new WriteRequest() { + + @Override + public void perform(WriteGraph graph) throws DatabaseException { + commit(graph); + } + + }, new Callback() { + + @Override + public void run(DatabaseException parameter) { + if (parameter != null) + ExceptionUtils.logAndShowError("Cannot commit editor changes", parameter); + } + }); + } + + protected void commit(WriteGraph graph) throws DatabaseException { + synchronized(syncMutex) { + if (DEBUG) System.out.println("Commit"); + graphUpdates = true; + mapping.updateDomain(graph); + graphUpdates = false; + } + } + + @Override + public void domainModified() { + if (graphUpdates) + return; + if (DEBUG)System.out.println("domainModified"); + session.asyncRequest(new ReadRequest() { + + @SuppressWarnings("unchecked") + @Override + public void run(ReadGraph graph) throws DatabaseException { + update(graph); + } + }); + + } + + protected void update(ReadGraph graph) throws DatabaseException { + synchronized (syncMutex) { + graphUpdates = true; + for (Object domainObject : mapping.getDomainModified()) { + E rangeObject = mapping.get(domainObject); + if (rangeObject != null) + graphModified.add(rangeObject); + } + mapping.updateRange(graph); + graphModified.clear(); + graphUpdates = false; + } + + if (mapping.isRangeModified()) + commit(); + } + + @Override + public void rangeModified() { + //System.out.println("rangeModified"); + + } + + @Override + public void postRender() { + // Commit changes if + // 1. Commit has been requested + // 2. There are no pending changes that should be processed in preRender() + if (requestCommit && !rangeModified) { // FIXME : not thread safe. + requestCommit = false; + doCommit(); + } + } + + List> rem = new ArrayList>(); + List> add = new ArrayList>(); + MapSet mod = new MapSet.Hash(); + Set propagation = new HashSet(); + Stack stack = new Stack(); + + + @Override + public synchronized void preRender() { + updateCycle(); + } + + @SuppressWarnings("unchecked") + protected void updateCycle() { + rem.clear(); + add.clear(); + mod.clear(); + propagation.clear(); + + synchronized (syncMutex) { + rem.addAll(removed); + add.addAll(added); + for (E e : updated.getKeys()) { + for (String s : updated.getValues(e)) { + mod.add(e, s); + } + } + + removed.clear(); + added.clear(); + updated.clear(); + } + + for (Pair n : rem) { + stopListening(n.first); + removeActor(n.first); + + } + + for (Pair n : add) { + addActor(n.first); + listen(n.first); + } + + for (E e : mod.getKeys()) { + Set ids = mod.getValues(e); + if (ids.contains(G3D.URIs.hasPosition) || ids.contains(G3D.URIs.hasOrientation)) { + if (!propagation.contains(e)) + propagation.add(e); + } + } + + if (propagation.size() > 0) { + stack.clear(); + stack.addAll(propagation); + propagation.clear(); + while (!stack.isEmpty()) { + E node = stack.pop(); + if (propagation.contains(node)) + continue; + propagation.add(node); + for (NodeListener l : node.getListeners()) { + if (l == this) { + //changeTracking = false; + //l.propertyChanged(node, G3D.URIs.hasPosition); + //changeTracking = true; + } else { + l.propertyChanged(node, G3D.URIs.hasWorldPosition); + } + } + if (node instanceof ParentNode) { + stack.addAll(((ParentNode)node).getNodes()); + } + } + } + +// synchronized (syncMutex) { +// rem.addAll(removed); +// add.addAll(added); +// //mod.addAll(updated); +// for (E e : updated.getKeys()) { +// for (String s : updated.getValues(e)) +// mod.add(e, s); +// } +// +// removed.clear(); +// added.clear(); +// updated.clear(); +// } + + for (E e : mod.getKeys()) { + Set ids = mod.getValues(e); + updateActor(e,ids); + } + + + for (Pair n : rem) { + for (NodeListener l : nodeListeners) + l.nodeRemoved(null, n.first, n.second); + } + for (Pair n : add) { + for (NodeListener l : nodeListeners) + l.nodeAdded(n.first.getParent(), n.first, n.second); + } +// for (Pair n : mod) { +// for (NodeListener l : nodeListeners) +// l.propertyChanged(n.first, n.second); +// } + for (E e : mod.getKeys()) { + for (NodeListener l : nodeListeners) + for (String s : mod.getValues(e)) + l.propertyChanged(e, s); + } + synchronized (syncMutex) { + if (added.isEmpty() && removed.isEmpty() && updated.getKeys().size() == 0) + rangeModified = false; + } + } + + @SuppressWarnings("unchecked") + private void listen(INode node) { + node.addListener(this); + if (node instanceof ParentNode) { + ParentNode parentNode = (ParentNode)node; + for (INode n : parentNode.getNodes()) + listen(n); + } + } + + private void stopListening(INode node) { + node.removeListener(this); + if (node instanceof ParentNode) { + @SuppressWarnings("unchecked") + ParentNode parentNode = (ParentNode)node; + for (INode n : parentNode.getNodes()) + stopListening(n); + } + } + + @SuppressWarnings("unchecked") + @Override + public void propertyChanged(INode node, String id) { + //receiveUpdate((E)node, id, graphUpdates); + receiveUpdate((E)node, id, graphModified.contains(node)); + + } + + @SuppressWarnings("unchecked") + @Override + public void nodeAdded(ParentNode node, INode child, + String rel) { + if (DEBUG) System.out.println("Node added " + child + " parent " + node); + //receiveAdd((E)child, rel ,graphUpdates); + receiveAdd((E)child, rel ,graphModified.contains(node)); + + } + + @SuppressWarnings("unchecked") + @Override + public void nodeRemoved(ParentNode node, INode child, + String rel) { + if (DEBUG) System.out.println("Node removed " + child + " parent " + node); + //receiveRemove((E)child, rel, graphUpdates); + receiveRemove((E)child, rel, graphModified.contains(node)); + + //FIXME : sometimes removed structural models cause ObjMap to add their children again. + // removing the listener here prevents corruption of visual model, but better fix is needed. + stopListening(child); + } + + @Override + public void delete() { + changeTracking = false; + panel.removeListener(this); + mapping.removeMappingListener(this); + + List nodes = new ArrayList(nodeToActor.getKeySize()); + nodes.addAll(nodeToActor.getKeys()); + for (E node : nodes) { + node.removeListener(this); + removeActor(node); + node.cleanup(); + } + for (vtkProp prop : actorToNode.keySet()) { + if (prop.GetVTKId() != 0) + prop.Delete(); + } + actorToNode.clear(); + nodeToActor.clear(); + + } + + + private List nodeListeners = new ArrayList(); + @Override + public void addListener(NodeListener listener) { + nodeListeners.add(listener); + + } + + @Override + public void removeListener(NodeListener listener) { + nodeListeners.remove(listener); + + } + + public IMapping getMapping() { + return mapping; + } + + +} diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/ActorHighlighter.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/ActorHighlighter.java new file mode 100644 index 00000000..92473f79 --- /dev/null +++ b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/ActorHighlighter.java @@ -0,0 +1,10 @@ +package org.simantics.g3d.vtk.common; + +import org.simantics.g3d.scenegraph.NodeHighlighter.HighlightEventType; + +import vtk.vtkProp; + +public interface ActorHighlighter { + + public void highlightActor(vtkProp prop, HighlightEventType type); +} diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/HoverHighlighter.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/HoverHighlighter.java new file mode 100644 index 00000000..832a3b00 --- /dev/null +++ b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/HoverHighlighter.java @@ -0,0 +1,44 @@ +package org.simantics.g3d.vtk.common; + +import org.eclipse.jface.viewers.ISelection; +import org.simantics.g3d.scenegraph.IG3DNode; +import org.simantics.g3d.scenegraph.NodeHighlighter; +import org.simantics.g3d.scenegraph.NodeHighlighter.HighlightEventType; + +import vtk.vtkPanel; + +public class HoverHighlighter extends SelectionHighlighter { + + + public HoverHighlighter(vtkPanel panel, VTKNodeMap nodeMap) { + super(panel, nodeMap); + + } + + protected void highlight(ISelection s) { + highlight(s, HighlightEventType.Hover, HighlightEventType.ClearHover); + } + + protected void hilight(IG3DNode node, HighlightEventType type) { + if (node instanceof NodeHighlighter) { + ((NodeHighlighter)node).highlight(type); + return; + } + if (type == HighlightEventType.Hover) { + setSelectedColor(node); + } else if (type == HighlightEventType.ClearHover) { + setDefaultColor(node); + } + } + + protected void setDefaultColor(IG3DNode node) { + double color[] = new double[]{0,0,0}; + setColor(node, true, color); + } + + protected void setSelectedColor(IG3DNode node) { + double color[] = new double[]{1,0,1}; + setColor(node, true, color); + } + +} diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/InteractiveVtkPanel.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/InteractiveVtkPanel.java new file mode 100644 index 00000000..40fe6c67 --- /dev/null +++ b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/InteractiveVtkPanel.java @@ -0,0 +1,402 @@ +package org.simantics.g3d.vtk.common; + +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.util.ArrayList; +import java.util.List; + +import org.simantics.g3d.scenegraph.RenderListener; +import org.simantics.g3d.vtk.action.vtkAction; + +import vtk.vtkAbstractPicker; +import vtk.vtkAreaPicker; +import vtk.vtkAssemblyNode; +import vtk.vtkAssemblyPath; +import vtk.vtkCellPicker; +import vtk.vtkGenericRenderWindowInteractor; +import vtk.vtkInteractorStyleTrackballCamera; +import vtk.vtkObjectBase; +import vtk.vtkPanel; +import vtk.vtkPointPicker; +import vtk.vtkProp; +import vtk.vtkProp3DCollection; +import vtk.vtkPropCollection; +import vtk.vtkPropPicker; +import vtk.vtkScenePicker; + +public class InteractiveVtkPanel extends vtkPanel { + + protected vtkGenericRenderWindowInteractor iren; + + + public vtkGenericRenderWindowInteractor getRenderWindowInteractor() { + return this.iren; + } + private static final long serialVersionUID = 2815073937537950615L; + + + public InteractiveVtkPanel() { + super(); + iren = new vtkGenericRenderWindowInteractor(); + iren.SetRenderWindow(rw); + iren.TimerEventResetsTimerOff(); + iren.SetSize(200, 200); + iren.ConfigureEvent(); + vtkInteractorStyleTrackballCamera style = new vtkInteractorStyleTrackballCamera(); + iren.SetInteractorStyle(style); + addDeletable(style); + addDeletable(iren); + } + + @Override + public void mouseClicked(MouseEvent e) { + + } + + @Override + public void mouseMoved(MouseEvent e) { + + } + + @Override + public void mouseEntered(MouseEvent e) { + super.mouseEntered(e); + } + + @Override + public void mouseExited(MouseEvent e) { + + } + + @Override + public void mousePressed(MouseEvent e) { + + } + + @Override + public void mouseDragged(MouseEvent e) { + + } + + @Override + public void mouseReleased(MouseEvent e) { + + } + + @Override + public void keyPressed(KeyEvent e) { + + } + + @Override + public void keyTyped(KeyEvent e) { + + } + + public void setSize(int x, int y) { + if (windowset == 1) { + Lock(); + rw.SetSize(x, y); + iren.SetSize(x, y); + iren.ConfigureEvent(); + UnLock(); + } + } + + private vtkScenePicker scenePicker; + + int pickType = 4; + + public int getPickType() { + return pickType; + } + + public void setPickType(int pickType) { + this.pickType = pickType; + } + + public vtkProp[] pick(int x, int y) { + + +// vtkPicker picker = new vtkPicker(); +// vtkAbstractPicker picker = new vtkAbstractPicker(); +// picker.Pick(x, rw.GetSize()[1] - y, ren); +// // see page 60 of VTK user's guide +// + if (pickType == 0) { + + vtkPropPicker picker = new vtkPropPicker(); + Lock(); + picker.PickProp(x, rw.GetSize()[1] - y, ren); + + UnLock(); + + vtkAssemblyPath apath = picker.GetPath(); + return processPick(picker, apath); + + } else if (pickType == 1) { + if (scenePicker == null) { + scenePicker = new vtkScenePicker(); + scenePicker.SetRenderer(ren); + scenePicker.EnableVertexPickingOn(); + + } + Lock(); + + vtkAssemblyPath apath = ren.PickProp(x, rw.GetSize()[1] - y); + //int vertexId = scenePicker.GetVertexId(new int[]{x, rw.GetSize()[1] - y}); + + UnLock(); + + if (apath != null) { + apath.InitTraversal(); +// System.out.println("Pick, actors " + apath.GetNumberOfItems() ); +// for (int i = 0; i < apath.GetNumberOfItems(); i++) { +// vtkAssemblyNode node = apath.GetNextNode(); +// vtkProp test = (vtkProp) node.GetViewProp(); +// System.out.println(test.GetClassName()); +// } + + vtkAssemblyNode node = apath.GetLastNode(); + vtkProp test = (vtkProp) node.GetViewProp(); + apath.Delete(); + node.Delete(); + return new vtkProp[]{test}; + + } + + } else if (pickType == 2) { + vtkPointPicker picker = new vtkPointPicker(); + picker.SetTolerance(2.0/(double)rw.GetSize()[0]); + Lock(); + picker.Pick(new double[]{x, rw.GetSize()[1] - y,0}, ren); + UnLock(); + + vtkAssemblyPath apath = picker.GetPath(); + return processPick(picker, apath); + } else if (pickType == 3) { + vtkAreaPicker picker = new vtkAreaPicker(); + Lock(); + picker.Pick(new double[]{x, rw.GetSize()[1] - y,0}, ren); + //picker.AreaPick(x-1, rw.GetSize()[1] - y-1,x+1,rw.GetSize()[1] - y+1, ren); + UnLock(); + vtkAssemblyPath apath = picker.GetPath(); + return processPick(picker, apath); + } else if (pickType == 4) { + vtkCellPicker picker = new vtkCellPicker(); + picker.SetTolerance(2.0/(double)rw.GetSize()[0]); + Lock(); + picker.Pick(new double[]{x, rw.GetSize()[1] - y,0}, ren); + UnLock(); + vtkAssemblyPath apath = picker.GetPath(); + return processPick(picker, apath); + } + + return null; + } + + public vtkProp[] pick2(int x, int y) { + + +// vtkPicker picker = new vtkPicker(); +// vtkAbstractPicker picker = new vtkAbstractPicker(); +// picker.Pick(x, rw.GetSize()[1] - y, ren); +// // see page 60 of VTK user's guide +// + if (pickType == 0) { + + vtkPropPicker picker = new vtkPropPicker(); + Lock(); + picker.PickProp(x, rw.GetSize()[1] - y, ren); + + UnLock(); + vtkPropCollection coll = picker.GetPickList(); + return processPick(picker, coll); + + } else if (pickType == 1) { + if (scenePicker == null) { + scenePicker = new vtkScenePicker(); + scenePicker.SetRenderer(ren); + scenePicker.EnableVertexPickingOn(); + + } + Lock(); + + + vtkAssemblyPath apath = ren.PickProp(x, rw.GetSize()[1] - y); + + UnLock(); + + if (apath != null) { + apath.InitTraversal(); + + + vtkAssemblyNode node = apath.GetLastNode(); + vtkProp test = (vtkProp) node.GetViewProp(); + apath.Delete(); + node.Delete(); + return new vtkProp[]{test}; + + } + + } else if (pickType == 2) { + vtkPointPicker picker = new vtkPointPicker(); + picker.SetTolerance(2.0/(double)rw.GetSize()[0]); + Lock(); + picker.Pick(new double[]{x, rw.GetSize()[1] - y,0}, ren); + UnLock(); + vtkProp3DCollection coll = picker.GetProp3Ds(); + return processPick(picker, coll); + } else if (pickType == 3) { + vtkAreaPicker picker = new vtkAreaPicker(); + Lock(); + picker.Pick(new double[]{x, rw.GetSize()[1] - y,0}, ren); + //picker.AreaPick(x-1, rw.GetSize()[1] - y-1,x+1,rw.GetSize()[1] - y+1, ren); + UnLock(); + vtkProp3DCollection coll = picker.GetProp3Ds(); + return processPick(picker, coll); + } else if (pickType == 4) { + vtkCellPicker picker = new vtkCellPicker(); + picker.SetTolerance(2.0/(double)rw.GetSize()[0]); + Lock(); + picker.Pick(new double[]{x, rw.GetSize()[1] - y,0}, ren); + UnLock(); + vtkProp3DCollection coll = picker.GetProp3Ds(); + return processPick(picker, coll); + } + + return null; + } + + private vtkProp[] processPick(vtkAbstractPicker picker, vtkAssemblyPath apath) { +// double[] pickPos = picker.GetPickPosition(); + picker.Delete(); + if (apath != null) { + apath.InitTraversal(); + vtkProp result[] = new vtkProp[apath.GetNumberOfItems()]; + for (int i = apath.GetNumberOfItems()-1; i >= 0; i--) { + vtkAssemblyNode node = apath.GetNextNode(); + vtkProp test = (vtkProp) node.GetViewProp(); +// System.out.println("Picked: " + test.GetClassName() + " " + test.GetVTKId()); + result[i] = test; + node.Delete(); + } + apath.Delete(); + return result; + + } + return null; + } + + private vtkProp[] processPick(vtkAbstractPicker picker, vtkPropCollection coll) { +// double[] pickPos = picker.GetPickPosition(); + picker.Delete(); + if (coll != null) { + coll.InitTraversal(); + vtkProp result[] = new vtkProp[coll.GetNumberOfItems()]; + for (int i = coll.GetNumberOfItems()-1; i >= 0; i--) { + vtkProp test = coll.GetNextProp(); + +// System.out.println("Picked: " + test.GetClassName() + " " + test.GetVTKId()); + result[i] = test; + + } + coll.Delete(); + return result; + + } + return null; + } + + + private vtkAction defaultAction; + private vtkAction currentAction; + + public void setActiveAction(vtkAction action) { + if (action.equals(currentAction)) + return; + if (currentAction != null) + currentAction.deattach(); + currentAction = action; + if (action != null) + action.attach(); + } + + public void setDefaultAction(vtkAction defaultAction) { + this.defaultAction = defaultAction; + } + + public void useDefaultAction() { + setActiveAction(defaultAction); + } + + public vtkAction getDefaultAction() { + return defaultAction; + } + + + @Override + public synchronized void Render() { + //System.out.println("Render " + rendering); + if (rendering) + return; + + firePreRender(); + super.Render(); + firePostRender(); + } + + + public void addListener(RenderListener l) { + listeners.add(l); + } + + public void removeListener(RenderListener l) { + listeners.remove(l); + } + + private List listeners = new ArrayList(); + + List list = new ArrayList(); + + private void firePreRender() { + if (listeners.size() > 0) { + list.addAll(listeners); + for (RenderListener l : list) + l.preRender(); + list.clear(); + } + } + + private void firePostRender() { + if (listeners.size() > 0) { + list.addAll(listeners); + for (RenderListener l : list) + l.postRender(); + list.clear(); + } + } + + + private List deletable = new ArrayList(); + + public void addDeletable(vtkObjectBase o) { + deletable.add(o); + } + + public void removeDeletable (vtkObjectBase o) { + deletable.remove(o); + } + + @Override + public void Delete() { + for (vtkObjectBase o : deletable) { + if (o.GetVTKId() != 0) { + o.Delete(); + } + } + deletable.clear(); + + super.Delete(); + } +} diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/NodeSelectionProvider2.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/NodeSelectionProvider2.java new file mode 100644 index 00000000..8c9347cf --- /dev/null +++ b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/NodeSelectionProvider2.java @@ -0,0 +1,144 @@ +package org.simantics.g3d.vtk.common; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.ISelectionProvider; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.ISelectionListener; +import org.eclipse.ui.IWorkbenchPart; +import org.simantics.db.Resource; +import org.simantics.g3d.scenegraph.IG3DNode; +import org.simantics.g3d.scenegraph.base.INode; +import org.simantics.g3d.tools.AdaptationUtils; +import org.simantics.objmap.graph.IMapping; +import org.simantics.objmap.structural.StructuralResource; + +import vtk.vtkProp; + +public class NodeSelectionProvider2 implements ISelectionProvider, ISelectionChangedListener, ISelectionListener{ + private ISelection selection = new StructuredSelection(); + private List listeners = new ArrayList(); + + List selectedNodes = new ArrayList(); // selection is ordered + //List selectedResources = new ArrayList(); + List> selectedItems = new ArrayList>(); + + IEditorPart part; + IMapping mapping; + VTKNodeMap nodeMap; + + public NodeSelectionProvider2(IEditorPart part, IMapping mapping, VTKNodeMap nodeMap) { + this.part = part; + this.mapping = mapping; + this.nodeMap = nodeMap; + } + + @Override + public void addSelectionChangedListener( + ISelectionChangedListener listener) { + listeners.add(listener); + } + + @Override + public void removeSelectionChangedListener( + ISelectionChangedListener listener) { + listeners.remove(listener); + } + + @Override + public ISelection getSelection() { + return selection; + } + + @Override + public void setSelection(ISelection selection) { + + } + + // events coming from vtk + @Override + public void selectionChanged(SelectionChangedEvent event) { + ISelection s = event.getSelection(); + + processSelection(s); + fireSelectionChanged(event.getSource()); + } + + @SuppressWarnings("unchecked") + private void processSelection(ISelection s) { + selectedNodes.clear(); + selectedItems.clear(); + + Collection selectedActors = AdaptationUtils.adaptToCollection(s, vtkProp.class); + if (selectedActors.size() > 0) { + for (vtkProp a : selectedActors) { + IG3DNode node = (IG3DNode)nodeMap.getNode((vtkProp)a); + if (node == null) + continue; + if (!selectedNodes.contains(node)) + selectedNodes.add(node); + DBObject r = mapping.inverseGet((JavaObject)node); + selectedItems.add(new VTKSelectionItem(a, node,r)); + } + } else { + Collection selectedNds = AdaptationUtils.adaptToCollection(s, IG3DNode.class); + for (INode node : selectedNds) { + if (!selectedNodes.contains(node)) + selectedNodes.add((IG3DNode)node); + DBObject r = mapping.inverseGet((JavaObject)node); + selectedItems.add(new VTKSelectionItem(null, (IG3DNode)node,r)); + } + } + + + selection = new StructuredSelection(selectedItems); + } + + private void fireSelectionChanged(Object source) { + SelectionChangedEvent evt = new SelectionChangedEvent((ISelectionProvider)source, selection); + for (ISelectionChangedListener l : listeners) { + l.selectionChanged(evt); + } + } + + + + // events coming from workbench + @Override + public void selectionChanged(IWorkbenchPart part, ISelection selection) { + if (part == this.part) + return; + processSelection(selection); + + } + + public List getSelectedNodes() { + return selectedNodes; + } + + @SuppressWarnings("unchecked") + public List getSelectedResources() { + + List list = new ArrayList(); + for (VTKSelectionItem i : selectedItems) { + DBObject r = (DBObject)i.getAdapter(Resource.class); + if (r == null) + r = (DBObject)i.getAdapter(StructuralResource.class); + if (r == null) + continue; + if (!list.contains(r)) + list.add(r); + } + return list; + } + + protected INode getNode(DBObject r) { + return (INode)mapping.get(r); + } +} diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/SelectionHighlighter.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/SelectionHighlighter.java new file mode 100644 index 00000000..0cbcac2d --- /dev/null +++ b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/SelectionHighlighter.java @@ -0,0 +1,188 @@ +package org.simantics.g3d.vtk.common; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.simantics.g3d.scenegraph.IG3DNode; +import org.simantics.g3d.scenegraph.NodeHighlighter; +import org.simantics.g3d.scenegraph.NodeHighlighter.HighlightEventType; +import org.simantics.g3d.scenegraph.NodeHighlighter.HighlightObjectType; +import org.simantics.g3d.scenegraph.base.INode; +import org.simantics.g3d.tools.AdaptationUtils; +import org.simantics.utils.threads.AWTThread; +import org.simantics.utils.threads.ThreadUtils; + +import vtk.vtkActor; +import vtk.vtkAlgorithm; +import vtk.vtkAlgorithmOutput; +import vtk.vtkFeatureEdges; +import vtk.vtkMapper; +import vtk.vtkPanel; +import vtk.vtkProp; +import vtk.vtkProperty; + +public class SelectionHighlighter implements ISelectionChangedListener{ + + + + vtkPanel panel; + VTKNodeMap nodeMap; + + List selectedNodes = new ArrayList(); + List selectedActors = new ArrayList(); + + HighlightObjectType type = HighlightObjectType.Node; + + public SelectionHighlighter(vtkPanel panel, VTKNodeMap nodeMap) { + this.panel = panel; + this.nodeMap = nodeMap; + } + + @Override + public void selectionChanged(SelectionChangedEvent event) { + final ISelection s = event.getSelection(); + + if (Thread.currentThread().equals(AWTThread.getThreadAccess().getThread())) + highlight(s); + else { + ThreadUtils.asyncExec(AWTThread.getThreadAccess(), new Runnable() { + @Override + public void run() { + highlight(s); + //System.out.println(this.getClass().getName() + " highlight "); + panel.Render(); + //panel.repaint(); + } + }); + } + + } + + protected void hilight(IG3DNode node, HighlightEventType type) { + if (node instanceof NodeHighlighter) { + ((NodeHighlighter)node).highlight(type); + return; + } + if (type == HighlightEventType.Selection) { + setSelectedColor(node); + } else if (type == HighlightEventType.ClearSelection) { + setDefaultColor(node); + } + } + + protected void hilight(vtkActor actor, HighlightEventType type) { + if (type == HighlightEventType.Selection) { + setColor(actor,false,new double[]{1,0,0}); + setColor(actor,true,new double[]{1,0,1}); + } else if (type == HighlightEventType.ClearSelection) { + setColor(actor,false,new double[]{1,1,0}); + setColor(actor,true,new double[]{0,0,0}); + } + } + + protected void highlight(ISelection s) { + highlight(s, HighlightEventType.Selection, HighlightEventType.ClearSelection); + } + + protected void highlight(ISelection s, HighlightEventType apply, HighlightEventType clear) { + + boolean changed = false; + if (type == HighlightObjectType.Node) { + Collection currentSelectedNodes = AdaptationUtils.adaptToCollection(s,IG3DNode.class);//getSelectedNodes(currentSelectedActors); + if (currentSelectedNodes.size() == 0) { + Collection currentSelectedActors = AdaptationUtils.adaptToCollection(s, vtkProp.class); + currentSelectedNodes = getSelectedNodes(currentSelectedActors); + } + for (IG3DNode node : selectedNodes) { + if (!currentSelectedNodes.contains(node)) { + hilight(node, clear); + changed = true; + } + } + for (IG3DNode node : currentSelectedNodes) { + if (!selectedNodes.contains(node)) { + hilight(node, apply); + changed = true; + } + } + selectedNodes.clear(); + selectedNodes.addAll(currentSelectedNodes); + //selectedNodes = currentSelectedNodes; + + } else { + + Collection currentSelectedActors = AdaptationUtils.adaptToCollection(s, vtkActor.class); + + for (vtkActor act : selectedActors) { + if (!currentSelectedActors.contains(act)) { + hilight(act,clear); + changed = true; + } + } + for (vtkActor act : currentSelectedActors) { + if (!selectedActors.contains(act)) { + hilight(act,apply); + changed = true; + } + } + selectedActors.clear(); + selectedActors.addAll(currentSelectedActors); + } + if (changed) { + panel.repaint(); + } + } + + protected List getSelectedNodes(Collection selectedActors) { + List currentSelectedNodes = new ArrayList(); + + for (vtkProp a : selectedActors) { + INode node = nodeMap.getNode((vtkProp)a); + if (node == null || !(node instanceof IG3DNode)) + continue; + if (!currentSelectedNodes.contains(node)) + currentSelectedNodes.add((IG3DNode)node); + } + return currentSelectedNodes; + } + + protected void setDefaultColor(IG3DNode node) { + double color[] = new double[]{1,1,0}; + setColor(node, false, color); + } + + protected void setSelectedColor(IG3DNode node) { + double color[] = new double[]{1,0,0}; + setColor(node, false, color); + } + + + protected void setColor(IG3DNode node, boolean edge, double color[]) { + for (vtkProp prop : nodeMap.getRenderObjects(node)) { + if (prop instanceof vtkActor) { + vtkActor act = (vtkActor)prop; + setColor(act, edge, color); + } + } + } + + protected void setColor(vtkActor act, boolean edge, double color[]) { + + vtkMapper mapper = act.GetMapper(); + vtkAlgorithmOutput out = mapper.GetInputConnection(0, 0); + vtkAlgorithm producer = out.GetProducer(); + boolean isEdge = (producer instanceof vtkFeatureEdges); + producer.Delete(); + if (isEdge == edge) { + vtkProperty property = act.GetProperty(); + property.SetColor(color); + property.Delete(); + } + out.Delete(); + mapper.Delete(); + } +} diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/VTKContentOutlinePage.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/VTKContentOutlinePage.java new file mode 100644 index 00000000..7c64fec0 --- /dev/null +++ b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/VTKContentOutlinePage.java @@ -0,0 +1,81 @@ +package org.simantics.g3d.vtk.common; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.swt.widgets.Composite; +import org.simantics.g3d.scenegraph.IG3DNode; +import org.simantics.g3d.scenegraph.base.INode; +import org.simantics.g3d.scenegraph.base.ParentNode; +import org.simantics.g3d.tools.AdaptationUtils; +import org.simantics.g3d.ui.ScenegraphOutlinePage; + +public class VTKContentOutlinePage extends ScenegraphOutlinePage{ + private NodeSelectionProvider2 provider; + + public VTKContentOutlinePage(ParentNode rootNode, NodeSelectionProvider2 provider) { + super(rootNode); + this.provider = provider; + } + + private boolean outsideSelection = false; + + @Override + public void createControl(Composite parent) { + + super.createControl(parent); + + provider.addSelectionChangedListener(new ISelectionChangedListener() { + + @Override + public void selectionChanged(SelectionChangedEvent event) { + Object source = event.getSource(); + if (source == VTKContentOutlinePage.this) + return; + ISelection s = event.getSelection(); + Collection nodes = AdaptationUtils.adaptToCollection(s, INode.class); + outsideSelection = true; + getTreeViewer().setSelection(new StructuredSelection(nodes.toArray()),true); + outsideSelection = false; + + } + }); + } + + List selectedNodes = new ArrayList(); + + @SuppressWarnings("unchecked") + @Override + protected void fireSelectionChanged(ISelection selection) { + if (outsideSelection) + return; + // TreeViewer provides selected object in tree order, not in selected order. + Collection selectedUnsortedNodes = AdaptationUtils.adaptToCollection(selection, INode.class); + List toRemove = new ArrayList(); + for (INode node : selectedNodes) { + if (!selectedUnsortedNodes.contains(node)) + toRemove.add(node); + } + for (INode node : toRemove) + selectedNodes.remove(node); + for (INode node : selectedUnsortedNodes) { + if (!selectedNodes.contains(node)) + selectedNodes.add(node); + } + + List> selectedItems = new ArrayList>(); + for (INode node : selectedNodes) { + DBObject r = provider.mapping.inverseGet((JavaObject)node); + selectedItems.add(new VTKSelectionItem(null, (IG3DNode)node, r)); + } + + super.fireSelectionChanged(new StructuredSelection(selectedItems)); + } + + +} diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/VTKNodeMap.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/VTKNodeMap.java new file mode 100644 index 00000000..055d0373 --- /dev/null +++ b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/VTKNodeMap.java @@ -0,0 +1,11 @@ +package org.simantics.g3d.vtk.common; + +import org.simantics.g3d.scenegraph.NodeMap; + +import vtk.vtkProp; + +public interface VTKNodeMap extends NodeMap{ + + + +} diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/VTKSelectionItem.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/VTKSelectionItem.java new file mode 100644 index 00000000..5bbbebc1 --- /dev/null +++ b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/VTKSelectionItem.java @@ -0,0 +1,95 @@ +package org.simantics.g3d.vtk.common; + +import org.eclipse.core.runtime.IAdaptable; +import org.simantics.db.Resource; +import org.simantics.g3d.scenegraph.IG3DNode; +import org.simantics.g3d.scenegraph.base.INode; +import org.simantics.objmap.structural.StructuralResource; + +import vtk.vtkProp; + +public class VTKSelectionItem implements IAdaptable{ + + private vtkProp prop; + private IG3DNode node; + private DBObject resource; + + //private VTKpropSet actors; + + + public VTKSelectionItem(vtkProp prop, IG3DNode node, DBObject res) { + this.prop = prop; + this.node = node; + this.resource = res; + } + +// public VTKSelectionItem(Resource res, Collection actors) { +// this.resource = res; +// this.actors = new VTKpropSet(); +// this.actors.addAll(actors); +// } +// +// public VTKSelectionItem(Resource res, vtkProp... actors) { +// this.resource = res; +// this.actors = new VTKpropSet(); +// for (vtkProp a : actors) +// this.actors.add(a); +// } + + @SuppressWarnings("rawtypes") + @Override + public Object getAdapter(Class adapter) { + if (adapter == Resource.class) + if (resource instanceof Resource) + return resource; + else + return null; + if (adapter == StructuralResource.class) + if (resource instanceof StructuralResource) + return resource; + else + return null; + if (adapter == vtkProp.class) + return prop; + if (adapter == IG3DNode.class) + return node; + if (adapter == INode.class) + return node; + return null; + } + +// @SuppressWarnings("rawtypes") +// @Override +// public Object getAdapter(Class adapter) { +// if (adapter == Resource.class) +// return resource; +// if (adapter == VTKpropSet.class) +// return actors; +// return null; +// } + +// public Resource getResource() { +// return resource; +// } +// +// public VTKpropSet getActors() { +// return actors; +// } + + @SuppressWarnings("rawtypes") + @Override + public boolean equals(Object obj) { + if (obj == null) + return false; + if (obj.getClass() != this.getClass()) + return false; + VTKSelectionItem other = (VTKSelectionItem)obj; + if (prop != null) + return prop.equals(other.prop); + if (node != null) + return node.equals(other.node); + return resource.equals(other.resource); + //return resource.equals(other.resource); + + } +} diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/gizmo/RotateAxisGizmo.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/gizmo/RotateAxisGizmo.java new file mode 100644 index 00000000..266a73c2 --- /dev/null +++ b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/gizmo/RotateAxisGizmo.java @@ -0,0 +1,69 @@ +package org.simantics.g3d.vtk.gizmo; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import javax.vecmath.Point3d; + +import org.simantics.g3d.vtk.action.RotateAction; +import org.simantics.g3d.vtk.shape.vtkShape; + +import vtk.vtkActor; +import vtk.vtkProp; + +public class RotateAxisGizmo extends vtkGizmo{ + + private List parts = new ArrayList(); + int type = -1; + + + @Override + public Collection getGizmo() { + for (vtkProp p : parts) + p.Delete(); + parts.clear(); + double l = 100; + double w = 3; + switch (type) { + case RotateAction.X:{ + vtkActor lineActorX = vtkShape.createLineActor(new Point3d(-l,0,0), new Point3d(l,0,0)); + lineActorX.GetProperty().SetColor(1, 0, 0); + lineActorX.GetProperty().SetLineWidth(w); + lineActorX.GetProperty().Delete(); + parts.add(lineActorX); + break; + } + case RotateAction.Y: { + vtkActor lineActorY = vtkShape.createLineActor(new Point3d(0,-l,0), new Point3d(0,l,0)); + lineActorY.GetProperty().SetColor(0, 1, 0); + lineActorY.GetProperty().SetLineWidth(w); + lineActorY.GetProperty().Delete(); + parts.add(lineActorY); + break; + } + case RotateAction.Z: { + vtkActor lineActorZ = vtkShape.createLineActor(new Point3d(0,0,-l), new Point3d(0,0,l)); + lineActorZ.GetProperty().SetColor(0, 0, 1); + lineActorZ.GetProperty().SetLineWidth(w); + lineActorZ.GetProperty().Delete(); + parts.add(lineActorZ); + break; + } + default: { + + } + } + return parts; + } + + public void setType(int type) { + if (this.type == type) + return; + this.type = type; + deattachActors(); + attachActors(); + } + + +} diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/gizmo/TranslateAxisGizmo.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/gizmo/TranslateAxisGizmo.java new file mode 100644 index 00000000..d5632903 --- /dev/null +++ b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/gizmo/TranslateAxisGizmo.java @@ -0,0 +1,108 @@ +package org.simantics.g3d.vtk.gizmo; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import javax.vecmath.Point3d; + +import org.simantics.g3d.vtk.action.TranslateAction; +import org.simantics.g3d.vtk.shape.vtkShape; + +import vtk.vtkActor; +import vtk.vtkProp; + +public class TranslateAxisGizmo extends vtkGizmo{ + + private List parts = new ArrayList(); + int type = -1; + + + @Override + public Collection getGizmo() { + for (vtkProp p : parts) + p.Delete(); + parts.clear(); + double l = 100; + double w = 3; + switch (type) { + case TranslateAction.X:{ + vtkActor lineActorX = vtkShape.createLineActor(new Point3d(-l,0,0), new Point3d(l,0,0)); + lineActorX.GetProperty().SetColor(1, 0, 0); + lineActorX.GetProperty().SetLineWidth(w); + lineActorX.GetProperty().Delete(); + parts.add(lineActorX); + break; + } + case TranslateAction.Y: { + vtkActor lineActorY = vtkShape.createLineActor(new Point3d(0,-l,0), new Point3d(0,l,0)); + lineActorY.GetProperty().SetColor(0, 1, 0); + lineActorY.GetProperty().SetLineWidth(w); + lineActorY.GetProperty().Delete(); + parts.add(lineActorY); + break; + } + case TranslateAction.Z: { + vtkActor lineActorZ = vtkShape.createLineActor(new Point3d(0,0,-l), new Point3d(0,0,l)); + lineActorZ.GetProperty().SetColor(0, 0, 1); + lineActorZ.GetProperty().SetLineWidth(w); + lineActorZ.GetProperty().Delete(); + parts.add(lineActorZ); + break; + } + case TranslateAction.XY: { + vtkActor lineActorX = vtkShape.createLineActor(new Point3d(-l,0,0), new Point3d(l,0,0)); + lineActorX.GetProperty().SetColor(1, 0, 0); + lineActorX.GetProperty().SetLineWidth(w); + lineActorX.GetProperty().Delete(); + parts.add(lineActorX); + vtkActor lineActorY = vtkShape.createLineActor(new Point3d(0,-l,0), new Point3d(0,l,0)); + lineActorY.GetProperty().SetColor(0, 1, 0); + lineActorY.GetProperty().SetLineWidth(w); + lineActorY.GetProperty().Delete(); + parts.add(lineActorY); + break; + } + case TranslateAction.XZ: { + vtkActor lineActorX = vtkShape.createLineActor(new Point3d(-l,0,0), new Point3d(l,0,0)); + lineActorX.GetProperty().SetColor(1, 0, 0); + lineActorX.GetProperty().Delete(); + parts.add(lineActorX); + vtkActor lineActorZ = vtkShape.createLineActor(new Point3d(0,0,-l), new Point3d(0,0,l)); + lineActorZ.GetProperty().SetColor(0, 0, 1); + lineActorZ.GetProperty().Delete(); + parts.add(lineActorZ); + break; + } + case TranslateAction.YZ: { + vtkActor lineActorY = vtkShape.createLineActor(new Point3d(0,-l,0), new Point3d(0,l,0)); + lineActorY.GetProperty().SetColor(0, 1, 0); + lineActorY.GetProperty().SetLineWidth(w); + lineActorY.GetProperty().Delete(); + parts.add(lineActorY); + vtkActor lineActorZ = vtkShape.createLineActor(new Point3d(0,0,-l), new Point3d(0,0,l)); + lineActorZ.GetProperty().SetColor(0, 0, 1); + lineActorZ.GetProperty().SetLineWidth(w); + lineActorZ.GetProperty().Delete(); + parts.add(lineActorZ); + break; + } + default: { + + } + } + return parts; + } + + public void setType(int type) { + if (this.type == type) + return; + this.type = type; + if (getRenderer() != null) { + deattachActors(); + attachActors(); + } + } + + +} diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/gizmo/TranslateGizmo.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/gizmo/TranslateGizmo.java new file mode 100644 index 00000000..724452f3 --- /dev/null +++ b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/gizmo/TranslateGizmo.java @@ -0,0 +1,372 @@ +package org.simantics.g3d.vtk.gizmo; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import vtk.vtkActor; +import vtk.vtkDataSetMapper; +import vtk.vtkPoints; +import vtk.vtkPolyData; +import vtk.vtkProp; +import vtk.vtkTriangle; + +public class TranslateGizmo extends vtkGizmo { + + + + private List parts; + + @Override + public Collection getGizmo() { + if (parts == null) { + parts = new ArrayList(); + + + float size = 2.f; + float sizeD2 = 1.f; + float offset = 0.2f; + + double[] colorX = new double[]{0.5,0.0,0.0}; + double[] colorY = new double[]{0.0,0.5,0.0}; + double[] colorZ = new double[]{0.0,0.0,0.5}; + + double[] colorXY = add(colorX, colorY); + double[] colorXZ = add(colorX, colorZ); + double[] colorYZ = add(colorY, colorZ); + double[] colorP = add(colorX,colorY,colorZ); + + vtkActor actorX = new vtkActor(); + vtkActor actorY = new vtkActor(); + vtkActor actorZ = new vtkActor(); + vtkActor actorXY = new vtkActor(); + vtkActor actorXZ = new vtkActor(); + vtkActor actorYZ = new vtkActor(); + vtkActor actorP = new vtkActor(); + + actorX.GetProperty().SetColor(colorX); + actorY.GetProperty().SetColor(colorY); + actorZ.GetProperty().SetColor(colorZ); + actorXY.GetProperty().SetColor(colorXY); + actorXZ.GetProperty().SetColor(colorXZ); + actorYZ.GetProperty().SetColor(colorYZ); + actorP.GetProperty().SetColor(colorP); + + actorX.GetProperty().SetOpacity(0.5); + actorY.GetProperty().SetOpacity(0.5); + actorZ.GetProperty().SetOpacity(0.5); + actorXY.GetProperty().SetOpacity(0.5); + actorXZ.GetProperty().SetOpacity(0.5); + actorYZ.GetProperty().SetOpacity(0.5); + actorP.GetProperty().SetOpacity(0.5); + + actorX.GetProperty().BackfaceCullingOff(); + actorY.GetProperty().BackfaceCullingOff(); + actorZ.GetProperty().BackfaceCullingOff(); + actorXY.GetProperty().BackfaceCullingOff(); + actorXZ.GetProperty().BackfaceCullingOff(); + actorYZ.GetProperty().BackfaceCullingOff(); + actorP.GetProperty().BackfaceCullingOff(); + + actorX.SetPickable(1); + actorY.SetPickable(1); + actorZ.SetPickable(1); + actorXY.SetPickable(1); + actorXZ.SetPickable(1); + actorYZ.SetPickable(1); + actorP.SetPickable(1); + + + actorX.GetProperty().LightingOff(); + actorY.GetProperty().LightingOff(); + actorZ.GetProperty().LightingOff(); + actorXY.GetProperty().LightingOff(); + actorXZ.GetProperty().LightingOff(); + actorYZ.GetProperty().LightingOff(); + actorP.GetProperty().LightingOff(); + + + vtkTriangle triangle = new vtkTriangle(); + + // X + vtkPolyData actorXData = new vtkPolyData(); + actorXData.Allocate(6, 6); + + triangle.GetPointIds().SetId(0, 0); + triangle.GetPointIds().SetId(1, 1); + triangle.GetPointIds().SetId(2, 3); + actorXData.InsertNextCell(triangle.GetCellType(), triangle.GetPointIds()); + triangle.GetPointIds().SetId(0, 1); + triangle.GetPointIds().SetId(1, 2); + triangle.GetPointIds().SetId(2, 3); + actorXData.InsertNextCell(triangle.GetCellType(), triangle.GetPointIds()); + triangle.GetPointIds().SetId(0, 0); + triangle.GetPointIds().SetId(1, 3); + triangle.GetPointIds().SetId(2, 5); + actorXData.InsertNextCell(triangle.GetCellType(), triangle.GetPointIds()); + triangle.GetPointIds().SetId(0, 3); + triangle.GetPointIds().SetId(1, 4); + triangle.GetPointIds().SetId(2, 5); + actorXData.InsertNextCell(triangle.GetCellType(), triangle.GetPointIds()); + + vtkPoints partPoints = new vtkPoints(); + partPoints.InsertPoint(0, new double[]{size,0.,0.}); + partPoints.InsertPoint(1, new double[]{size-offset,offset,0.}); + partPoints.InsertPoint(2, new double[]{sizeD2-offset,offset,0.}); + partPoints.InsertPoint(3, new double[]{sizeD2,0.,0.}); + partPoints.InsertPoint(4, new double[]{sizeD2-offset,0.,offset}); + partPoints.InsertPoint(5, new double[]{size-offset,0.,offset}); + actorXData.SetPoints(partPoints); + partPoints.Delete(); + + // Y + vtkPolyData actorYData = new vtkPolyData(); + actorYData.Allocate(6, 6); + + triangle.GetPointIds().SetId(0, 0); + triangle.GetPointIds().SetId(1, 1); + triangle.GetPointIds().SetId(2, 3); + actorYData.InsertNextCell(triangle.GetCellType(), triangle.GetPointIds()); + triangle.GetPointIds().SetId(0, 1); + triangle.GetPointIds().SetId(1, 2); + triangle.GetPointIds().SetId(2, 3); + actorYData.InsertNextCell(triangle.GetCellType(), triangle.GetPointIds()); + triangle.GetPointIds().SetId(0, 0); + triangle.GetPointIds().SetId(1, 3); + triangle.GetPointIds().SetId(2, 5); + actorYData.InsertNextCell(triangle.GetCellType(), triangle.GetPointIds()); + triangle.GetPointIds().SetId(0, 3); + triangle.GetPointIds().SetId(1, 4); + triangle.GetPointIds().SetId(2, 5); + actorYData.InsertNextCell(triangle.GetCellType(), triangle.GetPointIds()); + + partPoints = new vtkPoints(); + partPoints.InsertPoint(0, new double[]{0., size, 0.}); + partPoints.InsertPoint(1, new double[]{offset, size - offset, 0.}); + partPoints.InsertPoint(2, new double[]{offset, sizeD2 - offset, 0.}); + partPoints.InsertPoint(3, new double[]{0., sizeD2, 0.}); + partPoints.InsertPoint(4, new double[]{0., sizeD2 - offset, offset}); + partPoints.InsertPoint(5, new double[]{0., size - offset, offset}); + actorYData.SetPoints(partPoints); + partPoints.Delete(); + + // Z + vtkPolyData actorZData = new vtkPolyData(); + actorZData.Allocate(6, 6); + + triangle.GetPointIds().SetId(0, 0); + triangle.GetPointIds().SetId(1, 1); + triangle.GetPointIds().SetId(2, 3); + actorZData.InsertNextCell(triangle.GetCellType(), triangle.GetPointIds()); + triangle.GetPointIds().SetId(0, 1); + triangle.GetPointIds().SetId(1, 2); + triangle.GetPointIds().SetId(2, 3); + actorZData.InsertNextCell(triangle.GetCellType(), triangle.GetPointIds()); + triangle.GetPointIds().SetId(0, 0); + triangle.GetPointIds().SetId(1, 3); + triangle.GetPointIds().SetId(2, 5); + actorZData.InsertNextCell(triangle.GetCellType(), triangle.GetPointIds()); + triangle.GetPointIds().SetId(0, 3); + triangle.GetPointIds().SetId(1, 4); + triangle.GetPointIds().SetId(2, 5); + actorZData.InsertNextCell(triangle.GetCellType(), triangle.GetPointIds()); + + partPoints = new vtkPoints(); + partPoints.InsertPoint(0, new double[]{0., 0.,size}); + partPoints.InsertPoint(1, new double[]{offset, 0., size - offset}); + partPoints.InsertPoint(2, new double[]{offset, 0., sizeD2 - offset}); + partPoints.InsertPoint(3, new double[]{0., 0., sizeD2}); + partPoints.InsertPoint(4, new double[]{0., offset, sizeD2 - offset}); + partPoints.InsertPoint(5, new double[]{0., offset, size - offset}); + actorZData.SetPoints(partPoints); + partPoints.Delete(); + + // XY + vtkPolyData actorXYData = new vtkPolyData(); + actorXYData.Allocate(4, 4); + + triangle.GetPointIds().SetId(0, 2); + triangle.GetPointIds().SetId(1, 1); + triangle.GetPointIds().SetId(2, 3); + actorXYData.InsertNextCell(triangle.GetCellType(), triangle.GetPointIds()); + triangle.GetPointIds().SetId(0, 0); + triangle.GetPointIds().SetId(1, 1); + triangle.GetPointIds().SetId(2, 3); + actorXYData.InsertNextCell(triangle.GetCellType(), triangle.GetPointIds()); + + partPoints = new vtkPoints(); + partPoints.InsertPoint(0, new double[]{offset, size-offset, 0.f}); + partPoints.InsertPoint(1, new double[]{offset, sizeD2 - offset, 0.f}); + partPoints.InsertPoint(2, new double[]{sizeD2 - offset, offset, 0.f}); + partPoints.InsertPoint(3, new double[]{size-offset, offset, 0.f}); + actorXYData.SetPoints(partPoints); + partPoints.Delete(); + + // XZ + vtkPolyData actorXZData = new vtkPolyData(); + actorXZData.Allocate(4, 4); + + triangle.GetPointIds().SetId(0, 2); + triangle.GetPointIds().SetId(1, 1); + triangle.GetPointIds().SetId(2, 3); + actorXZData.InsertNextCell(triangle.GetCellType(), triangle.GetPointIds()); + triangle.GetPointIds().SetId(0, 0); + triangle.GetPointIds().SetId(1, 1); + triangle.GetPointIds().SetId(2, 3); + actorXZData.InsertNextCell(triangle.GetCellType(), triangle.GetPointIds()); + + partPoints = new vtkPoints(); + partPoints.InsertPoint(0, new double[]{offset, 0.f, size-offset}); + partPoints.InsertPoint(1, new double[]{offset, 0.f, sizeD2 - offset}); + partPoints.InsertPoint(2, new double[]{sizeD2 - offset, 0.f, offset}); + partPoints.InsertPoint(3, new double[]{size-offset, 0.f, offset}); + actorXZData.SetPoints(partPoints); + partPoints.Delete(); + + // YZ + vtkPolyData actorYZData = new vtkPolyData(); + actorYZData.Allocate(4, 4); + + triangle.GetPointIds().SetId(0, 2); + triangle.GetPointIds().SetId(1, 1); + triangle.GetPointIds().SetId(2, 3); + actorYZData.InsertNextCell(triangle.GetCellType(), triangle.GetPointIds()); + triangle.GetPointIds().SetId(0, 0); + triangle.GetPointIds().SetId(1, 1); + triangle.GetPointIds().SetId(2, 3); + actorYZData.InsertNextCell(triangle.GetCellType(), triangle.GetPointIds()); + + partPoints = new vtkPoints(); + partPoints.InsertPoint(0, new double[]{0.f,offset, size-offset}); + partPoints.InsertPoint(1, new double[]{0.f,offset, sizeD2 - offset}); + partPoints.InsertPoint(2, new double[]{0.f,sizeD2 - offset, offset}); + partPoints.InsertPoint(3, new double[]{0.f,size-offset, offset}); + + actorYZData.SetPoints(partPoints); + partPoints.Delete(); + + vtkPolyData actorPData = new vtkPolyData(); + actorPData.Allocate(10, 10); + + triangle.GetPointIds().SetId(0, 0); + triangle.GetPointIds().SetId(1, 1); + triangle.GetPointIds().SetId(2, 2); + actorPData.InsertNextCell(triangle.GetCellType(), triangle.GetPointIds()); + triangle.GetPointIds().SetId(0, 0); + triangle.GetPointIds().SetId(1, 2); + triangle.GetPointIds().SetId(2, 3); + actorPData.InsertNextCell(triangle.GetCellType(), triangle.GetPointIds()); + triangle.GetPointIds().SetId(0, 0); + triangle.GetPointIds().SetId(1, 3); + triangle.GetPointIds().SetId(2, 4); + actorPData.InsertNextCell(triangle.GetCellType(), triangle.GetPointIds()); + triangle.GetPointIds().SetId(0, 0); + triangle.GetPointIds().SetId(1, 4); + triangle.GetPointIds().SetId(2, 5); + actorPData.InsertNextCell(triangle.GetCellType(), triangle.GetPointIds()); + triangle.GetPointIds().SetId(0, 0); + triangle.GetPointIds().SetId(1, 5); + triangle.GetPointIds().SetId(2, 6); + actorPData.InsertNextCell(triangle.GetCellType(), triangle.GetPointIds()); + triangle.GetPointIds().SetId(0, 0); + triangle.GetPointIds().SetId(1, 6); + triangle.GetPointIds().SetId(2, 7); + actorPData.InsertNextCell(triangle.GetCellType(), triangle.GetPointIds()); + triangle.GetPointIds().SetId(0, 0); + triangle.GetPointIds().SetId(1, 7); + triangle.GetPointIds().SetId(2, 8); + actorPData.InsertNextCell(triangle.GetCellType(), triangle.GetPointIds()); + triangle.GetPointIds().SetId(0, 0); + triangle.GetPointIds().SetId(1, 8); + triangle.GetPointIds().SetId(2, 9); + actorPData.InsertNextCell(triangle.GetCellType(), triangle.GetPointIds()); + triangle.GetPointIds().SetId(0, 0); + triangle.GetPointIds().SetId(1, 9); + triangle.GetPointIds().SetId(2, 1); + actorPData.InsertNextCell(triangle.GetCellType(), triangle.GetPointIds()); + + partPoints = new vtkPoints(); + partPoints.InsertPoint(0, new double[]{0.f, 0.f, 0.f}); + partPoints.InsertPoint(1, new double[]{sizeD2, 0.f, 0.f}); + partPoints.InsertPoint(2, new double[]{sizeD2 - offset, offset, 0.f}); + partPoints.InsertPoint(3, new double[]{offset, sizeD2 - offset, 0.f}); + partPoints.InsertPoint(4, new double[]{0.f, sizeD2, 0.f}); + partPoints.InsertPoint(5, new double[]{0.f, sizeD2 - offset, offset}); + partPoints.InsertPoint(6, new double[]{0.f, offset, sizeD2-offset}); + partPoints.InsertPoint(7, new double[]{0.f, 0.f, sizeD2}); + partPoints.InsertPoint(8, new double[]{offset, 0.f, sizeD2-offset}); + partPoints.InsertPoint(9, new double[]{sizeD2-offset, 0.f, offset}); + actorPData.SetPoints(partPoints); + partPoints.Delete(); + + + vtkDataSetMapper partMapper = new vtkDataSetMapper(); + partMapper.SetInput(actorXData); + partMapper.ScalarVisibilityOn(); + actorX.SetMapper(partMapper); + partMapper.Delete(); + + partMapper = new vtkDataSetMapper(); + partMapper.SetInput(actorYData); + partMapper.ScalarVisibilityOn(); + actorY.SetMapper(partMapper); + partMapper.Delete(); + + partMapper = new vtkDataSetMapper(); + partMapper.SetInput(actorZData); + partMapper.ScalarVisibilityOn(); + actorZ.SetMapper(partMapper); + partMapper.Delete(); + + partMapper = new vtkDataSetMapper(); + partMapper.SetInput(actorXYData); + partMapper.ScalarVisibilityOn(); + actorXY.SetMapper(partMapper); + partMapper.Delete(); + + partMapper = new vtkDataSetMapper(); + partMapper.SetInput(actorXZData); + partMapper.ScalarVisibilityOn(); + actorXZ.SetMapper(partMapper); + partMapper.Delete(); + + partMapper = new vtkDataSetMapper(); + partMapper.SetInput(actorYZData); + partMapper.ScalarVisibilityOn(); + actorYZ.SetMapper(partMapper); + partMapper.Delete(); + + partMapper = new vtkDataSetMapper(); + partMapper.SetInput(actorPData); + partMapper.ScalarVisibilityOn(); + actorP.SetMapper(partMapper); + partMapper.Delete(); + + + actorXData.Delete(); + actorYData.Delete(); + actorZData.Delete(); + actorXYData.Delete(); + actorXZData.Delete(); + actorYZData.Delete(); + actorPData.Delete(); + + parts.add(actorX); + parts.add(actorY); + parts.add(actorZ); + parts.add(actorXY); + parts.add(actorXZ); + parts.add(actorYZ); + parts.add(actorP); + } + return parts; + } + + public int getTranslateAxis(vtkActor actor) { + if (actor == null) + return -1; + return parts.indexOf(actor); + } + + +} diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/gizmo/vtkGizmo.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/gizmo/vtkGizmo.java new file mode 100644 index 00000000..e559a716 --- /dev/null +++ b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/gizmo/vtkGizmo.java @@ -0,0 +1,132 @@ +package org.simantics.g3d.vtk.gizmo; + +import java.util.Collection; + +import javax.vecmath.AxisAngle4d; +import javax.vecmath.Tuple3d; +import javax.vecmath.Vector3d; + +import org.simantics.g3d.gizmo.Gizmo; +import org.simantics.g3d.math.MathTools; + +import vtk.vtkProp; +import vtk.vtkProp3D; +import vtk.vtkRenderer; + +public abstract class vtkGizmo implements Gizmo { + + private vtkRenderer ren1; + private Collection gizmo; + + private Tuple3d position; + private AxisAngle4d orientation; + private Tuple3d scale; + + @Override + public void attach(Object renderingPart) { + if (ren1 != null) + throw new RuntimeException("Gizmo is attached"); + ren1 = (vtkRenderer)renderingPart; + attachActors(); + } + + @Override + public void deattach() { + if (ren1 == null) + throw new RuntimeException("Gizmo is not attached"); + deattachActors(); + ren1 = null; + } + + public boolean isAttached() { + return (ren1 != null); + } + + protected void attachActors() { + gizmo = getGizmo(); + for (vtkProp p : gizmo) { + ren1.AddActor(p); + } + if (position != null) + setPosition(position); + if (orientation != null) + setRotation(orientation); + if (scale != null) + setScale(scale); + } + + protected void deattachActors() { + for (vtkProp p : gizmo) { + ren1.RemoveActor(p); + } + } + + @Override + public boolean isPartOf(vtkProp pickedObject) { + for (vtkProp prop : gizmo) { + if (prop.equals(pickedObject)) + return true; + } + return false; + } + + public void setPosition(Tuple3d position) { + this.position = position; + for (vtkProp p : gizmo) { + ((vtkProp3D)p).SetPosition(position.x, position.y, position.z); + } + } + + public void setRotation(AxisAngle4d q) { + this.orientation = q; + for (vtkProp p : gizmo) { + ((vtkProp3D)p).SetOrientation(0,0,0); + ((vtkProp3D)p).RotateWXYZ(MathTools.radToDeg(q.angle), q.x, q.y, q.z); + } + } + + + public void setScale(Tuple3d s) { + this.scale = s; + for (vtkProp p : gizmo) { + ((vtkProp3D)p).SetScale(s.x, s.y, s.z); + } + } + + public void setScale(double s) { + this.scale = new Vector3d(s,s,s); + for (vtkProp p : gizmo) { + ((vtkProp3D)p).SetScale(s, s, s); + } + } + + public abstract Collection getGizmo(); + +// public double[] add(double[] color1, double[] color2) { +// double[] result = new double[]{color1[0]+color2[0],color1[1],+color2[1],color1[2]+color2[2]}; +// return result; +// } +// +// public double[] add(double[] color1, double[] color2, double[] color3) { +// double[] result = new double[]{color1[0]+color2[0]+color3[0],color1[1],+color2[1]+color3[1],color1[2]+color2[2]+color3[2]}; +// return result; +// } + + public double[] add(double[]... color) { + double result[] = new double[]{0,0,0}; + for (double c[] : color) { + for (int i = 0; i < 3; i++) + result[i] += c[i]; + } + + return result; + } + + + public vtkRenderer getRenderer() { + return ren1; + } + + + +} diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/handlers/CameraPositionHandler.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/handlers/CameraPositionHandler.java new file mode 100644 index 00000000..da31a243 --- /dev/null +++ b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/handlers/CameraPositionHandler.java @@ -0,0 +1,66 @@ +package org.simantics.g3d.vtk.handlers; + +import java.util.HashMap; +import java.util.Map; + +import javax.vecmath.Vector3d; + +import org.eclipse.core.commands.AbstractHandler; +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.vtk.common.InteractiveVtkPanel; +import org.simantics.utils.threads.AWTThread; +import org.simantics.utils.threads.ThreadUtils; + +public class CameraPositionHandler extends AbstractHandler { + + + private Map cameraPos = new HashMap(); + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + + final IWorkbenchPart ap = HandlerUtil.getActiveEditor(event); + final InteractiveVtkPanel panel = (InteractiveVtkPanel)ap.getAdapter(InteractiveVtkPanel.class); + + String param = event.getParameter("org.simantics.g3d.viewDirection"); + String vals[] = param.split(","); + final Vector3d direction = new Vector3d(Double.parseDouble(vals[0]),Double.parseDouble(vals[1]),Double.parseDouble(vals[2])); + + + ThreadUtils.asyncExec(AWTThread.getThreadAccess(), new Runnable() { + + @Override + public void run() { + + Vector3d focal = new Vector3d(panel.GetRenderer().GetActiveCamera().GetFocalPoint()); + Vector3d pos = new Vector3d(panel.GetRenderer().GetActiveCamera().GetPosition()); + cameraPos.put(panel, pos); + Vector3d dir = new Vector3d(pos); + dir.sub(focal); + double distance = dir.length(); + + dir.set(direction); + dir.scale(distance); + dir.add(focal); + panel.GetRenderer().GetActiveCamera().SetPosition(dir.x, dir.y, dir.z); + if (Math.abs(direction.dot(new Vector3d(0,1,0))) < 0.95) + panel.GetRenderer().GetActiveCamera().SetViewUp(0, 1, 0); + else + panel.GetRenderer().GetActiveCamera().SetViewUp(1, 0, 0); + + panel.GetRenderer().ResetCameraClippingRange(); + + panel.UpdateLight(); + panel.repaint(); + } + }); + + return null; + + } + + +} diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/handlers/ParallelPerspectiveHandler.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/handlers/ParallelPerspectiveHandler.java new file mode 100644 index 00000000..7400308d --- /dev/null +++ b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/handlers/ParallelPerspectiveHandler.java @@ -0,0 +1,71 @@ +package org.simantics.g3d.vtk.handlers; + +import java.util.HashMap; +import java.util.Map; + +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.vtk.common.InteractiveVtkPanel; +import org.simantics.utils.threads.AWTThread; +import org.simantics.utils.threads.ThreadUtils; + +public class ParallelPerspectiveHandler extends AbstractHandler { + + + private Map cameraPos = new HashMap(); + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + Command command = event.getCommand(); + boolean oldValue = HandlerUtil.toggleCommandState(command); + final boolean activate = !oldValue; + + final IWorkbenchPart ap = HandlerUtil.getActiveEditor(event); + final InteractiveVtkPanel panel = (InteractiveVtkPanel)ap.getAdapter(InteractiveVtkPanel.class); + + ThreadUtils.asyncExec(AWTThread.getThreadAccess(), new Runnable() { + + @Override + public void run() { + if (activate){ + Vector3d focal = new Vector3d(panel.GetRenderer().GetActiveCamera().GetFocalPoint()); + Vector3d pos = new Vector3d(panel.GetRenderer().GetActiveCamera().GetPosition()); + cameraPos.put(panel, pos); + Vector3d dir = new Vector3d(pos); + dir.sub(focal); + dir.normalize(); + dir.scale(100); + dir.add(focal); + panel.GetRenderer().GetActiveCamera().SetPosition(dir.x, dir.y, dir.z); + + + panel.GetRenderer().GetActiveCamera().SetParallelProjection(1); + panel.GetRenderer().ResetCameraClippingRange(); + } else { + panel.GetRenderer().GetActiveCamera().SetParallelProjection(0); + Vector3d pos = cameraPos.get(panel); + if (pos != null) { + panel.GetRenderer().GetActiveCamera().SetPosition(pos.x, pos.y, pos.z); + } + panel.GetRenderer().ResetCameraClippingRange(); + + } + panel.UpdateLight(); + panel.repaint(); + + } + }); + + return null; + + } + + + +} diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/preferences/CloseMethod.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/preferences/CloseMethod.java new file mode 100644 index 00000000..e360bef4 --- /dev/null +++ b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/preferences/CloseMethod.java @@ -0,0 +1,7 @@ +package org.simantics.g3d.vtk.preferences; + +public enum CloseMethod { + ON_CLOSE, + ON_LAST_CLOSE, + NO_CLOSE +} diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/preferences/PreferenceConstants.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/preferences/PreferenceConstants.java new file mode 100644 index 00000000..c172d548 --- /dev/null +++ b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/preferences/PreferenceConstants.java @@ -0,0 +1,10 @@ +package org.simantics.g3d.vtk.preferences; + +/** + * Constant definitions for plug-in preferences + */ +public class PreferenceConstants { + + public static final String CLOSE_METHOD = "closeMethod"; + +} diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/preferences/PreferenceInitializer.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/preferences/PreferenceInitializer.java new file mode 100644 index 00000000..24b27ca5 --- /dev/null +++ b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/preferences/PreferenceInitializer.java @@ -0,0 +1,23 @@ +package org.simantics.g3d.vtk.preferences; + +import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer; +import org.eclipse.jface.preference.IPreferenceStore; + +import org.simantics.g3d.vtk.Activator; + +/** + * Class used to initialize default preference values. + */ +public class PreferenceInitializer extends AbstractPreferenceInitializer { + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer#initializeDefaultPreferences() + */ + public void initializeDefaultPreferences() { + IPreferenceStore store = Activator.getDefault().getPreferenceStore(); + store.setDefault(PreferenceConstants.CLOSE_METHOD, CloseMethod.ON_LAST_CLOSE.toString()); + } + +} diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/preferences/VTKPreferencePage.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/preferences/VTKPreferencePage.java new file mode 100644 index 00000000..0639b882 --- /dev/null +++ b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/preferences/VTKPreferencePage.java @@ -0,0 +1,56 @@ +package org.simantics.g3d.vtk.preferences; + +import org.eclipse.jface.preference.*; +import org.eclipse.ui.IWorkbenchPreferencePage; +import org.eclipse.ui.IWorkbench; +import org.simantics.g3d.vtk.Activator; + +/** + * This class represents a preference page that + * is contributed to the Preferences dialog. By + * subclassing FieldEditorPreferencePage, we + * can use the field support built into JFace that allows + * us to create a page that is small and knows how to + * save, restore and apply itself. + *

+ * This page is used to modify preferences only. They + * are stored in the preference store that belongs to + * the main plug-in class. That way, preferences can + * be accessed directly via the preference store. + */ + +public class VTKPreferencePage + extends FieldEditorPreferencePage + implements IWorkbenchPreferencePage { + + public VTKPreferencePage() { + super(GRID); + setPreferenceStore(Activator.getDefault().getPreferenceStore()); + setDescription("VTK Preferences (DEBUG)"); + } + + /** + * Creates the field editors. Field editors are abstractions of + * the common GUI blocks needed to manipulate various types + * of preferences. Each field editor knows how to save and + * restore itself. + */ + public void createFieldEditors() { + addField(new RadioGroupFieldEditor( + PreferenceConstants.CLOSE_METHOD, + "When to close VTK", + 1, + new String[][] { { "On &Editor Close", CloseMethod.ON_CLOSE.toString() }, + { "On &Last Editor Close", CloseMethod.ON_LAST_CLOSE.toString() }, + { "&Closing Disabled", CloseMethod.NO_CLOSE.toString() } + }, getFieldEditorParent())); + + } + + /* (non-Javadoc) + * @see org.eclipse.ui.IWorkbenchPreferencePage#init(org.eclipse.ui.IWorkbench) + */ + public void init(IWorkbench workbench) { + } + +} \ No newline at end of file diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/property/VTKPropertyTabContributor.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/property/VTKPropertyTabContributor.java new file mode 100644 index 00000000..32e26353 --- /dev/null +++ b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/property/VTKPropertyTabContributor.java @@ -0,0 +1,110 @@ +package org.simantics.g3d.vtk.property; + +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionProvider; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.IWorkbenchSite; +import org.simantics.db.management.ISessionContext; +import org.simantics.selectionview.IPropertyTab; +import org.simantics.selectionview.PropertyTabContributor; +import org.simantics.utils.threads.AWTThread; +import org.simantics.utils.threads.ThreadUtils; + +import vtk.vtkActor; +import vtk.vtkAlgorithm; +import vtk.vtkAlgorithmOutput; +import vtk.vtkMapper; +import vtk.vtkProp; + +public class VTKPropertyTabContributor implements PropertyTabContributor{ + + public org.simantics.selectionview.IPropertyTab create(Composite parent, IWorkbenchSite site, ISessionContext context, Object input) { + IPropertyTab tab = new VTKPropertyTab((vtkProp)input); + tab.createControl(parent, context); + return tab; + }; + + + public class VTKPropertyTab implements IPropertyTab { + private Composite composite; + private Text text; + private vtkProp prop; + + public VTKPropertyTab(vtkProp prop) { + this.prop = prop; + } + + @Override + public void createControl(Composite parent, ISessionContext context) { + + composite = new Composite(parent, SWT.NONE); + composite.setLayout(new FillLayout()); + text = new Text(composite, SWT.MULTI | SWT.V_SCROLL | SWT.H_SCROLL | SWT.READ_ONLY); + ThreadUtils.asyncExec(AWTThread.getThreadAccess(), new Runnable() { + + @Override + public void run() { + String string = ""; + if (prop instanceof vtkActor) { + vtkActor act = (vtkActor)prop; + vtkMapper mapper = act.GetMapper(); + vtkAlgorithmOutput out = mapper.GetInputConnection(0, 0); + vtkAlgorithm producer = out.GetProducer(); + string += producer.GetClassName() +"\n"; + out.Delete(); + mapper.Delete(); + producer.Delete(); + } + string += prop.Print(); + final String s = string; + Display.getDefault().asyncExec(new Runnable() { + @Override + public void run() { + if (!text.isDisposed()) + text.setText(s); + } + }); + } + });; + + + } + + @Override + public void requestFocus() { + composite.setFocus(); + } + + @Override + public void dispose() { + composite.dispose(); + } + + @Override + public boolean isDisposed() { + return composite.isDisposed(); + } + + @Override + public Control getControl() { + return composite; + } + + @Override + public void setInput(ISessionContext context, ISelection selection, + boolean force) { + + } + + @Override + public ISelectionProvider getSelectionProvider() { + return null; + } + } + +} diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/shape/DualHeadArrowActor.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/shape/DualHeadArrowActor.java new file mode 100644 index 00000000..518eb514 --- /dev/null +++ b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/shape/DualHeadArrowActor.java @@ -0,0 +1,297 @@ +package org.simantics.g3d.vtk.shape; + +import javax.vecmath.AxisAngle4d; +import javax.vecmath.Matrix4d; +import javax.vecmath.Point3d; +import javax.vecmath.Vector3d; + +import org.simantics.g3d.math.MathTools; +import org.simantics.utils.threads.AWTThread; +import org.simantics.utils.threads.ThreadUtils; + +import vtk.vtkActor; +import vtk.vtkAssembly; +import vtk.vtkConeSource; +import vtk.vtkLineSource; +import vtk.vtkLinearTransform; +import vtk.vtkMatrix4x4; +import vtk.vtkPolyDataMapper; +import vtk.vtkProp3D; +import vtk.vtkRenderer; +import vtk.vtkTextActor; +import vtk.vtkTubeFilter; + +public class DualHeadArrowActor extends vtkAssembly implements IvtkVisualObject{ + + private vtkRenderer ren; + private Vector3d axisDir = new Vector3d(1,0,0); + private vtkTextActor tactor; + private vtkActor tubeActor; + private vtkActor coneActor; + private vtkActor coneActor2; + private boolean rendered = false; + + public DualHeadArrowActor(vtkRenderer _ren, String label) { + super(); + ren = _ren; + createAxis(label); + } + + public DualHeadArrowActor(vtkRenderer _ren, String label, Vector3d dir) { + super(); + ren = _ren; + this.axisDir = dir; + if (dir.lengthSquared() < MathTools.NEAR_ZERO) + throw new IllegalArgumentException("Direction vector length must mer larger than zero"); + createAxis(label); + } + + public void createAxis(String label) { + double coneScale = 0.3 * axisDir.length(); + Vector3d coneOffset = new Vector3d(axisDir); + coneOffset.normalize(); + coneOffset.scale(coneScale*0.5); + + vtkLineSource line = new vtkLineSource(); + //line.SetPoint1(0.0,0.0,0.0); + line.SetPoint1(coneOffset.x,coneOffset.y,coneOffset.z); + line.SetPoint2(axisDir.x-coneOffset.x,axisDir.y-coneOffset.y,axisDir.z-coneOffset.z); + + tactor = new vtkTextActor(); + + tactor.SetInput(label); + + tactor.SetTextScaleModeToNone(); + tactor.GetTextProperty().SetColor(0.0, 0.0, 0.0); + tactor.GetTextProperty().ShadowOff(); + tactor.GetTextProperty().ItalicOff(); + tactor.GetTextProperty().BoldOff(); + + tactor.GetTextProperty().Delete(); + + tactor.SetMaximumLineHeight(0.25); + + tactor.SetPickable(0); + + vtkTubeFilter tube = new vtkTubeFilter(); + tube.SetInput(line.GetOutput()); + tube.SetRadius(0.05 * axisDir.length()); + tube.SetNumberOfSides(8); + + vtkPolyDataMapper tubeMapper = new vtkPolyDataMapper(); + tubeMapper.SetInput(tube.GetOutput()); + + tubeActor = new vtkActor(); + tubeActor.SetMapper(tubeMapper); + tubeActor.PickableOff(); + + int coneRes = 12; + + + + + // --- x-Cone + vtkConeSource cone = new vtkConeSource(); + cone.SetResolution(coneRes); + vtkPolyDataMapper coneMapper = new vtkPolyDataMapper(); + coneMapper.SetInput(cone.GetOutput()); + coneActor = new vtkActor(); + coneActor.SetMapper(coneMapper); + coneActor.GetProperty().SetColor(1, 0, 0); + coneActor.SetScale(coneScale, coneScale, coneScale); + coneActor.SetPosition(axisDir.x-coneOffset.x,axisDir.y-coneOffset.y,axisDir.z-coneOffset.z); + coneActor.SetPickable(0); + + AxisAngle4d aa = MathTools.createRotation(new Vector3d(1,0,0), axisDir); + if (aa != null) + coneActor.RotateWXYZ(MathTools.radToDeg(aa.angle), aa.x, aa.y, aa.z); + + + coneActor2 = new vtkActor(); + coneActor2.SetMapper(coneMapper); + coneActor2.GetProperty().SetColor(1, 0, 0); + coneActor2.SetScale(coneScale, coneScale, coneScale); + coneActor2.SetPosition(coneOffset.x,coneOffset.y,coneOffset.z); + coneActor2.SetPickable(0); + + aa = MathTools.createRotation(new Vector3d(-1,0,0), axisDir); + if (aa != null) + coneActor2.RotateWXYZ(MathTools.radToDeg(aa.angle), aa.x, aa.y, aa.z); + + this.AddPart(tubeActor); + this.AddPart(coneActor); + this.AddPart(coneActor2); + + tube.GetOutput().Delete(); + cone.GetOutput().Delete(); + line.GetOutput().Delete(); + + tubeMapper.Delete(); + tube.Delete(); + cone.Delete(); + line.Delete(); + + coneMapper.Delete(); + + coneActor.GetProperty().Delete(); + coneActor2.GetProperty().Delete(); + } + + public void addToRenderer() { + if (rendered) + return; + rendered = true; + + ren.AddActor2D(tactor); + + ren.AddActor(this); + } + + public void removeFromRenderer() { + if (!rendered) + return; + rendered = false; + ren.RemoveActor2D(tactor); + ren.RemoveActor(this); + } + + public boolean isRendered() { + return rendered; + } + + public void setAxesVisibility(boolean ison) { + this.SetVisibility(ison ? 1 : 0); + tactor.SetVisibility(ison ? 1 : 0); + } + + public void setLabelVisibility(boolean ison) { + tactor.SetVisibility(ison ? 1 : 0); + } + + double mat[] = new double[16]; + Matrix4d m = new Matrix4d(); + private void updateTextLoc() { + tactor.GetPositionCoordinate().SetCoordinateSystemToWorld(); + + + GetMatrix(mat); + MathTools.set(m,mat); + Point3d p = new Point3d(axisDir.x*0.5, axisDir.y*0.5,axisDir.z*0.5); + m.transform(p); + tactor.GetPositionCoordinate().SetValue(p.x, p.y, p.z); + + tactor.GetPositionCoordinate().Delete(); + } + + @Override + public void SetPickable(int id0) { + super.SetPickable(id0); + tubeActor.SetPickable(id0); + coneActor.SetPickable(id0); + coneActor2.SetPickable(id0); + } + + @Override + public void SetOrientation(double id0, double id1, double id2) { + super.SetOrientation(id0, id1, id2); + updateTextLoc(); + } + + @Override + public void RotateWXYZ(double id0, double id1, double id2, double id3) { + super.RotateWXYZ(id0, id1, id2, id3); + updateTextLoc(); + } + + @Override + public void SetPosition(double[] id0) { + super.SetPosition(id0); + updateTextLoc(); + } + + @Override + public void SetPosition(double id0, double id1, double id2) { + super.SetPosition(id0, id1, id2); + updateTextLoc(); + } + + @Override + public void SetOrientation(double[] id0) { + super.SetOrientation(id0); + updateTextLoc(); + } + + @Override + public void SetScale(double id0) { + super.SetScale(id0); + updateTextLoc(); + } + + @Override + public void SetScale(double id0, double id1, double id2) { + super.SetScale(id0, id1, id2); + updateTextLoc(); + } + + @Override + public void SetScale(double[] id0) { + super.SetScale(id0); + updateTextLoc(); + } + + public void SetColor(double r, double g, double b) { + coneActor.GetProperty().SetColor(r, g, b); + coneActor2.GetProperty().SetColor(r, g, b); + tubeActor.GetProperty().SetColor(r, g, b); + coneActor.GetProperty().Delete(); + coneActor2.GetProperty().Delete(); + tubeActor.GetProperty().Delete(); + } + + public void SetTextColor(double r, double g, double b) { + tactor.GetTextProperty().SetColor(r, g, b); + tactor.GetTextProperty().Delete(); + } + + @Override + public void SetUserMatrix(vtkMatrix4x4 id0) { + super.SetUserMatrix(id0); + updateTextLoc(); + } + + @Override + public void SetUserTransform(vtkLinearTransform id0) { + super.SetUserTransform(id0); + updateTextLoc(); + } + + @Override + public void Delete() { + ren.RemoveActor(tactor); + ren.RemoveActor(tubeActor); + ren.RemoveActor(coneActor); + ren.RemoveActor(coneActor2); + tactor.Delete(); + tubeActor.Delete(); + coneActor.Delete(); + coneActor2.Delete(); + super.Delete(); + } + + public void dispose() { + ThreadUtils.asyncExec(AWTThread.getThreadAccess(), new Runnable() { + + @Override + public void run() { + removeFromRenderer(); + Delete(); + } + }); + } + + @Override + public vtkProp3D getVtkProp() { + return this; + } + +} diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/shape/IvtkVisualObject.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/shape/IvtkVisualObject.java new file mode 100644 index 00000000..148435c0 --- /dev/null +++ b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/shape/IvtkVisualObject.java @@ -0,0 +1,12 @@ +package org.simantics.g3d.vtk.shape; + +import vtk.vtkProp3D; + +public interface IvtkVisualObject { + + + public void addToRenderer() ; + public void removeFromRenderer(); + public boolean isRendered(); + public vtkProp3D getVtkProp(); +} diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/shape/MeshActor.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/shape/MeshActor.java new file mode 100644 index 00000000..f7564119 --- /dev/null +++ b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/shape/MeshActor.java @@ -0,0 +1,86 @@ +package org.simantics.g3d.vtk.shape; + +import javax.vecmath.Vector3d; + +import org.simantics.g3d.shape.Color4d; +import org.simantics.g3d.shape.Mesh; + +import vtk.vtkActor; +import vtk.vtkDataSetMapper; +import vtk.vtkIdList; +import vtk.vtkPoints; +import vtk.vtkPolyData; +import vtk.vtkPolyDataMapper; +import vtk.vtkPolyDataNormals; +import vtk.vtkTriangle; +import vtk.vtkUnsignedCharArray; + +public class MeshActor extends vtkActor { + + public void setMesh(Mesh mesh) { + + vtkPolyDataMapper mapper = new vtkPolyDataMapper(); + + vtkPolyData polyData = new vtkPolyData(); + polyData.Allocate(mesh.getIndices().size()/3, mesh.getIndices().size()/3); + + vtkTriangle triangle = new vtkTriangle(); + vtkIdList list = triangle.GetPointIds(); + for (int i = 0; i < mesh.getIndices().size(); i+=3) { + list.SetId(0, mesh.getIndices().get(i)); + list.SetId(1, mesh.getIndices().get(i+1)); + list.SetId(2, mesh.getIndices().get(i+2)); + polyData.InsertNextCell(triangle.GetCellType(), list); + } + list.Delete(); + triangle.Delete(); + + + vtkPoints points = new vtkPoints(); + for (int i = 0; i < mesh.getVertices().size(); i++) { + Vector3d p = mesh.getVertices().get(i); + points.InsertPoint(i, p.x, p.y, p.z); + } + + polyData.SetPoints(points); + points.Delete(); + + if (mesh.getColors() != null) { + vtkUnsignedCharArray colors = new vtkUnsignedCharArray(); + colors.SetName("Colors"); + colors.SetNumberOfComponents(3); + colors.SetNumberOfTuples(mesh.getColors().size()); + for (int i = 0; i < mesh.getColors().size(); i++) { + Color4d c = mesh.getColors().get(i); + colors.InsertTuple3(i, 255.0* c.x, 255.0 * c.y, 255.0 * c.z); + } + polyData.GetPointData().AddArray(colors); + colors.Delete(); + + } + + boolean computeNormals = true; + if (computeNormals) { + vtkPolyDataNormals normals = new vtkPolyDataNormals(); + normals.SetInput(polyData); + mapper.SetInputConnection(normals.GetOutputPort()); + normals.GetOutputPort().Delete(); + normals.Delete(); + } else { + mapper.SetInput(polyData); + } + + if (mesh.getColors() != null) { + mapper.ScalarVisibilityOn(); + mapper.SetScalarModeToUsePointFieldData(); + mapper.SelectColorArray("Colors"); + } + + SetMapper(mapper); + mapper.Delete(); + polyData.GetPointData().Delete(); + polyData.Delete(); + + } + +} diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/shape/axesActor.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/shape/axesActor.java new file mode 100644 index 00000000..8a95751d --- /dev/null +++ b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/shape/axesActor.java @@ -0,0 +1,353 @@ +package org.simantics.g3d.vtk.shape; + +import javax.vecmath.Matrix4d; +import javax.vecmath.Point3d; + +import org.simantics.g3d.math.MathTools; +import org.simantics.utils.threads.AWTThread; +import org.simantics.utils.threads.ThreadUtils; + +import vtk.vtkActor; +import vtk.vtkAssembly; +import vtk.vtkAxes; +import vtk.vtkConeSource; +import vtk.vtkLinearTransform; +import vtk.vtkMatrix4x4; +import vtk.vtkPolyDataMapper; +import vtk.vtkProp3D; +import vtk.vtkRenderer; +import vtk.vtkTextActor; +import vtk.vtkTubeFilter; + +public class axesActor extends vtkAssembly implements IvtkVisualObject{ + + private vtkRenderer ren; + private double axisLength = 0.8; + private vtkTextActor xactor, yactor, zactor; + private vtkActor tubeActor; + private vtkActor xconeActor; + private vtkActor yconeActor; + private vtkActor zconeActor; + private boolean rendered = false; + + public axesActor(vtkRenderer _ren) { + super(); + ren = _ren; + createAxes(); + } + + public axesActor(vtkRenderer _ren, double axisLength) { + super(); + ren = _ren; + this.axisLength = axisLength; + createAxes(); + } + + public void createAxes() { + vtkAxes axes = new vtkAxes(); + axes.SetOrigin(0, 0, 0); + axes.SetScaleFactor(axisLength); + + xactor = new vtkTextActor(); + yactor = new vtkTextActor(); + zactor = new vtkTextActor(); + + xactor.SetInput("X"); + yactor.SetInput("Y"); + zactor.SetInput("Z"); + +// xactor.SetTextScaleModeToViewport(); +// yactor.SetTextScaleModeToViewport(); +// zactor.SetTextScaleModeToViewport(); + xactor.SetTextScaleModeToNone(); + yactor.SetTextScaleModeToNone(); + zactor.SetTextScaleModeToNone(); + + xactor.GetTextProperty().SetColor(0.0, 0.0, 0.0); + xactor.GetTextProperty().ShadowOff(); + xactor.GetTextProperty().ItalicOff(); + xactor.GetTextProperty().BoldOff(); + + yactor.GetTextProperty().SetColor(0.0, 0.0, 0.0); + yactor.GetTextProperty().ShadowOff(); + yactor.GetTextProperty().ItalicOff(); + yactor.GetTextProperty().BoldOff(); + + zactor.GetTextProperty().SetColor(0.0, 0.0, 0.0); + zactor.GetTextProperty().ShadowOff(); + zactor.GetTextProperty().ItalicOff(); + zactor.GetTextProperty().BoldOff(); + + xactor.GetTextProperty().Delete(); + yactor.GetTextProperty().Delete(); + zactor.GetTextProperty().Delete(); + + xactor.SetMaximumLineHeight(0.25); + yactor.SetMaximumLineHeight(0.25); + zactor.SetMaximumLineHeight(0.25); + + xactor.SetPickable(0); + yactor.SetPickable(0); + zactor.SetPickable(0); + + vtkTubeFilter tube = new vtkTubeFilter(); + tube.SetInput(axes.GetOutput()); + tube.SetRadius(0.05 * axisLength); + tube.SetNumberOfSides(8); + + vtkPolyDataMapper tubeMapper = new vtkPolyDataMapper(); + tubeMapper.SetInput(tube.GetOutput()); + + tubeActor = new vtkActor(); + tubeActor.SetMapper(tubeMapper); + tubeActor.PickableOff(); + + int coneRes = 12; + double coneScale = 0.3 * axisLength; + + // --- x-Cone + vtkConeSource xcone = new vtkConeSource(); + xcone.SetResolution(coneRes); + vtkPolyDataMapper xconeMapper = new vtkPolyDataMapper(); + xconeMapper.SetInput(xcone.GetOutput()); + xconeActor = new vtkActor(); + xconeActor.SetMapper(xconeMapper); + xconeActor.GetProperty().SetColor(1, 0, 0); + xconeActor.SetScale(coneScale, coneScale, coneScale); + xconeActor.SetPosition(axisLength, 0.0, 0.0); + xconeActor.SetPickable(0); + + // --- y-Cone + vtkConeSource ycone = new vtkConeSource(); + ycone.SetResolution(coneRes); + vtkPolyDataMapper yconeMapper = new vtkPolyDataMapper(); + yconeMapper.SetInput(ycone.GetOutput()); + yconeActor = new vtkActor(); + yconeActor.SetMapper(yconeMapper); + yconeActor.GetProperty().SetColor(1, 1, 0); + yconeActor.RotateZ(90); + yconeActor.SetScale(coneScale, coneScale, coneScale); + yconeActor.SetPosition(0.0, axisLength, 0.0); + yconeActor.SetPickable(0); + + // --- z-Cone + vtkConeSource zcone = new vtkConeSource(); + zcone.SetResolution(coneRes); + vtkPolyDataMapper zconeMapper = new vtkPolyDataMapper(); + zconeMapper.SetInput(zcone.GetOutput()); + zconeActor = new vtkActor(); + zconeActor.SetMapper(zconeMapper); + zconeActor.GetProperty().SetColor(0, 1, 0); + zconeActor.RotateY(-90); + zconeActor.SetScale(coneScale, coneScale, coneScale); + zconeActor.SetPosition(0.0, 0.0, axisLength); + zconeActor.SetPickable(0); + + + this.AddPart(tubeActor); + this.AddPart(xconeActor); + this.AddPart(yconeActor); + this.AddPart(zconeActor); + + tube.GetOutput().Delete(); + xcone.GetOutput().Delete(); + ycone.GetOutput().Delete(); + zcone.GetOutput().Delete(); + axes.GetOutput().Delete(); + axes.Delete(); + tubeMapper.Delete(); + tube.Delete(); + xcone.Delete(); + ycone.Delete(); + zcone.Delete(); + xconeMapper.Delete(); + yconeMapper.Delete(); + zconeMapper.Delete(); + + xconeActor.GetProperty().Delete(); + yconeActor.GetProperty().Delete(); + zconeActor.GetProperty().Delete(); + } + + public void addToRenderer() { + if (rendered) + return; + rendered = true; + + ren.AddActor2D(xactor); + ren.AddActor2D(yactor); + ren.AddActor2D(zactor); + + + ren.AddActor(this); + } + + public void removeFromRenderer() { + if (!rendered) + return; + rendered = false; + ren.RemoveActor2D(xactor); + ren.RemoveActor2D(yactor); + ren.RemoveActor2D(zactor); + ren.RemoveActor(this); + } + + public boolean isRendered() { + return rendered; + } + + public void setAxesVisibility(boolean ison) { + this.SetVisibility(ison ? 1 : 0); + xactor.SetVisibility(ison ? 1 : 0); + yactor.SetVisibility(ison ? 1 : 0); + zactor.SetVisibility(ison ? 1 : 0); + } + + private boolean labelVisible = true; + + public void setLabelVisibility(boolean ison) { + xactor.SetVisibility(ison ? 1 : 0); + yactor.SetVisibility(ison ? 1 : 0); + zactor.SetVisibility(ison ? 1 : 0); + labelVisible = ison; + if (labelVisible) + updateTextLoc(); + } + + Matrix4d m = new Matrix4d(); + double mat[] = new double[16]; + Point3d x = new Point3d(); + Point3d y = new Point3d(); + Point3d z = new Point3d(); + + private void updateTextLoc() { + if (!labelVisible) + return; + xactor.GetPositionCoordinate().SetCoordinateSystemToWorld(); + yactor.GetPositionCoordinate().SetCoordinateSystemToWorld(); + zactor.GetPositionCoordinate().SetCoordinateSystemToWorld(); + + GetMatrix(mat); + MathTools.set(m, mat); + x.set(axisLength, 0,0); + y.set(0,axisLength, 0); + z.set(0,0,axisLength); + + m.transform(x); + m.transform(y); + m.transform(z); + xactor.GetPositionCoordinate().SetValue(x.x, x.y, x.z); + yactor.GetPositionCoordinate().SetValue(y.x, y.y, y.z); + zactor.GetPositionCoordinate().SetValue(z.x, z.y, z.z); + + xactor.GetPositionCoordinate().Delete(); + yactor.GetPositionCoordinate().Delete(); + zactor.GetPositionCoordinate().Delete(); + } + + @Override + public void SetPickable(int id0) { + super.SetPickable(id0); + tubeActor.SetPickable(id0); + xconeActor.SetPickable(id0); + yconeActor.SetPickable(id0); + zconeActor.SetPickable(id0); + + } + + @Override + public void SetOrientation(double id0, double id1, double id2) { + super.SetOrientation(id0, id1, id2); + updateTextLoc(); + } + + @Override + public void RotateWXYZ(double id0, double id1, double id2, double id3) { + super.RotateWXYZ(id0, id1, id2, id3); + updateTextLoc(); + } + + @Override + public void SetPosition(double[] id0) { + super.SetPosition(id0); + updateTextLoc(); + } + + @Override + public void SetPosition(double id0, double id1, double id2) { + super.SetPosition(id0, id1, id2); + updateTextLoc(); + } + + @Override + public void SetOrientation(double[] id0) { + super.SetOrientation(id0); + updateTextLoc(); + } + + @Override + public void SetScale(double id0) { + super.SetScale(id0); + updateTextLoc(); + } + + @Override + public void SetScale(double id0, double id1, double id2) { + super.SetScale(id0, id1, id2); + updateTextLoc(); + } + + @Override + public void SetScale(double[] id0) { + super.SetScale(id0); + updateTextLoc(); + } + + @Override + public void SetUserMatrix(vtkMatrix4x4 id0) { + super.SetUserMatrix(id0); + updateTextLoc(); + } + + @Override + public void SetUserTransform(vtkLinearTransform id0) { + super.SetUserTransform(id0); + updateTextLoc(); + } + + @Override + public void Delete() { + ren.RemoveActor(xactor); + ren.RemoveActor(yactor); + ren.RemoveActor(zactor); + ren.RemoveActor(tubeActor); + ren.RemoveActor(xconeActor); + ren.RemoveActor(yconeActor); + ren.RemoveActor(xconeActor); + xactor.Delete(); + yactor.Delete(); + zactor.Delete(); + tubeActor.Delete(); + xconeActor.Delete(); + yconeActor.Delete(); + zconeActor.Delete(); + super.Delete(); + } + + public void dispose() { + ThreadUtils.asyncExec(AWTThread.getThreadAccess(), new Runnable() { + + @Override + public void run() { + removeFromRenderer(); + Delete(); + } + }); + } + + @Override + public vtkProp3D getVtkProp() { + return this; + } + +} diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/shape/axesSphereActor.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/shape/axesSphereActor.java new file mode 100644 index 00000000..2fc50d5c --- /dev/null +++ b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/shape/axesSphereActor.java @@ -0,0 +1,374 @@ +package org.simantics.g3d.vtk.shape; + +import javax.vecmath.Matrix4d; +import javax.vecmath.Point3d; + +import org.simantics.g3d.math.MathTools; +import org.simantics.utils.threads.AWTThread; +import org.simantics.utils.threads.ThreadUtils; + +import vtk.vtkActor; +import vtk.vtkAssembly; +import vtk.vtkAxes; +import vtk.vtkConeSource; +import vtk.vtkLinearTransform; +import vtk.vtkMatrix4x4; +import vtk.vtkPolyDataMapper; +import vtk.vtkProp3D; +import vtk.vtkRenderer; +import vtk.vtkSphereSource; +import vtk.vtkTextActor; +import vtk.vtkTubeFilter; + +public class axesSphereActor extends vtkAssembly implements IvtkVisualObject{ + + private vtkRenderer ren; + private double axisLength = 0.8; + private vtkTextActor xactor, yactor, zactor; + private vtkActor tubeActor; + private vtkActor xconeActor; + private vtkActor yconeActor; + private vtkActor zconeActor; + private vtkActor oBallActor; + private boolean rendered = false; + + public axesSphereActor(vtkRenderer _ren) { + super(); + ren = _ren; + createAxes(); + } + + public axesSphereActor(vtkRenderer _ren, double axisLength) { + super(); + ren = _ren; + this.axisLength = axisLength; + createAxes(); + } + + public void createAxes() { + vtkAxes axes = new vtkAxes(); + axes.SetOrigin(0, 0, 0); + axes.SetScaleFactor(axisLength); + + + + vtkTubeFilter tube = new vtkTubeFilter(); + tube.SetInput(axes.GetOutput()); + tube.SetRadius(0.05 * axisLength); + tube.SetNumberOfSides(8); + + vtkPolyDataMapper tubeMapper = new vtkPolyDataMapper(); + tubeMapper.SetInput(tube.GetOutput()); + + tubeActor = new vtkActor(); + tubeActor.SetMapper(tubeMapper); + tubeActor.PickableOff(); + + int coneRes = 12; + double coneScale = 0.3 * axisLength; + + // --- x-Cone + vtkConeSource xcone = new vtkConeSource(); + xcone.SetResolution(coneRes); + vtkPolyDataMapper xconeMapper = new vtkPolyDataMapper(); + xconeMapper.SetInput(xcone.GetOutput()); + xconeActor = new vtkActor(); + xconeActor.SetMapper(xconeMapper); + xconeActor.GetProperty().SetColor(1, 0, 0); + xconeActor.SetScale(coneScale, coneScale, coneScale); + xconeActor.SetPosition(axisLength, 0.0, 0.0); + xconeActor.SetPickable(0); + + // --- y-Cone + vtkConeSource ycone = new vtkConeSource(); + ycone.SetResolution(coneRes); + vtkPolyDataMapper yconeMapper = new vtkPolyDataMapper(); + yconeMapper.SetInput(ycone.GetOutput()); + yconeActor = new vtkActor(); + yconeActor.SetMapper(yconeMapper); + yconeActor.GetProperty().SetColor(1, 1, 0); + yconeActor.RotateZ(90); + yconeActor.SetScale(coneScale, coneScale, coneScale); + yconeActor.SetPosition(0.0, axisLength, 0.0); + yconeActor.SetPickable(0); + + // --- z-Cone + vtkConeSource zcone = new vtkConeSource(); + zcone.SetResolution(coneRes); + vtkPolyDataMapper zconeMapper = new vtkPolyDataMapper(); + zconeMapper.SetInput(zcone.GetOutput()); + zconeActor = new vtkActor(); + zconeActor.SetMapper(zconeMapper); + zconeActor.GetProperty().SetColor(0, 1, 0); + zconeActor.RotateY(-90); + zconeActor.SetScale(coneScale, coneScale, coneScale); + zconeActor.SetPosition(0.0, 0.0, axisLength); + zconeActor.SetPickable(0); + + vtkSphereSource ball = new vtkSphereSource(); + ball.SetRadius(axisLength * 0.3); + ball.SetPhiResolution(6); + ball.SetThetaResolution(8); + vtkPolyDataMapper ballMapper = new vtkPolyDataMapper(); + ballMapper.SetInput(ball.GetOutput()); + oBallActor = new vtkActor(); + oBallActor.SetMapper(ballMapper); + oBallActor.GetProperty().SetColor(0, 0, 1); + oBallActor.SetPickable(0); + + + this.AddPart(tubeActor); + this.AddPart(xconeActor); + this.AddPart(yconeActor); + this.AddPart(zconeActor); + this.AddPart(oBallActor); + + tube.GetOutput().Delete(); + xcone.GetOutput().Delete(); + ycone.GetOutput().Delete(); + zcone.GetOutput().Delete(); + axes.GetOutput().Delete(); + ball.GetOutput().Delete(); + axes.Delete(); + tube.Delete(); + xcone.Delete(); + ycone.Delete(); + zcone.Delete(); + ball.Delete(); + tubeMapper.Delete(); + xconeMapper.Delete(); + yconeMapper.Delete(); + zconeMapper.Delete(); + ballMapper.Delete(); + + xconeActor.GetProperty().Delete(); + yconeActor.GetProperty().Delete(); + zconeActor.GetProperty().Delete(); + oBallActor.GetProperty().Delete(); + + + xactor = new vtkTextActor(); + yactor = new vtkTextActor(); + zactor = new vtkTextActor(); + + xactor.SetInput("X"); + yactor.SetInput("Y"); + zactor.SetInput("Z"); + +// xactor.SetTextScaleModeToViewport(); +// yactor.SetTextScaleModeToViewport(); +// zactor.SetTextScaleModeToViewport(); + xactor.SetTextScaleModeToNone(); + yactor.SetTextScaleModeToNone(); + zactor.SetTextScaleModeToNone(); + + xactor.GetTextProperty().SetColor(0.0, 0.0, 0.0); + xactor.GetTextProperty().ShadowOff(); + xactor.GetTextProperty().ItalicOff(); + xactor.GetTextProperty().BoldOff(); + + yactor.GetTextProperty().SetColor(0.0, 0.0, 0.0); + yactor.GetTextProperty().ShadowOff(); + yactor.GetTextProperty().ItalicOff(); + yactor.GetTextProperty().BoldOff(); + + zactor.GetTextProperty().SetColor(0.0, 0.0, 0.0); + zactor.GetTextProperty().ShadowOff(); + zactor.GetTextProperty().ItalicOff(); + zactor.GetTextProperty().BoldOff(); + + xactor.GetTextProperty().Delete(); + yactor.GetTextProperty().Delete(); + zactor.GetTextProperty().Delete(); + + xactor.SetMaximumLineHeight(0.25); + yactor.SetMaximumLineHeight(0.25); + zactor.SetMaximumLineHeight(0.25); + + xactor.SetPickable(0); + yactor.SetPickable(0); + zactor.SetPickable(0); + } + + public void addToRenderer() { + if (rendered) + return; + rendered = true; + + ren.AddActor2D(xactor); + ren.AddActor2D(yactor); + ren.AddActor2D(zactor); + + + ren.AddActor(this); + } + + public void removeFromRenderer() { + if (!rendered) + return; + rendered = false; + ren.RemoveActor2D(xactor); + ren.RemoveActor2D(yactor); + ren.RemoveActor2D(zactor); + ren.RemoveActor(this); + } + + public boolean isRendered() { + return rendered; + } + + public void setAxesVisibility(boolean ison) { + this.SetVisibility(ison ? 1 : 0); + xactor.SetVisibility(ison ? 1 : 0); + yactor.SetVisibility(ison ? 1 : 0); + zactor.SetVisibility(ison ? 1 : 0); + } + + private boolean labelVisible = true; + public void setLabelVisibility(boolean ison) { + xactor.SetVisibility(ison ? 1 : 0); + yactor.SetVisibility(ison ? 1 : 0); + zactor.SetVisibility(ison ? 1 : 0); + labelVisible = ison; + if (labelVisible) + updateTextLoc(); + } + + Matrix4d m = new Matrix4d(); + double mat[] = new double[16]; + Point3d x = new Point3d(); + Point3d y = new Point3d(); + Point3d z = new Point3d(); + + private void updateTextLoc() { + if (!labelVisible) + return; + xactor.GetPositionCoordinate().SetCoordinateSystemToWorld(); + yactor.GetPositionCoordinate().SetCoordinateSystemToWorld(); + zactor.GetPositionCoordinate().SetCoordinateSystemToWorld(); + + GetMatrix(mat); + MathTools.set(m, mat); + x.set(axisLength, 0,0); + y.set(0,axisLength, 0); + z.set(0,0,axisLength); + + m.transform(x); + m.transform(y); + m.transform(z); + xactor.GetPositionCoordinate().SetValue(x.x, x.y, x.z); + yactor.GetPositionCoordinate().SetValue(y.x, y.y, y.z); + zactor.GetPositionCoordinate().SetValue(z.x, z.y, z.z); + + xactor.GetPositionCoordinate().Delete(); + yactor.GetPositionCoordinate().Delete(); + zactor.GetPositionCoordinate().Delete(); + } + + @Override + public void SetPickable(int id0) { + super.SetPickable(id0); + tubeActor.SetPickable(id0); + xconeActor.SetPickable(id0); + yconeActor.SetPickable(id0); + zconeActor.SetPickable(id0); + oBallActor.SetPickable(id0); + + } + + @Override + public void SetOrientation(double id0, double id1, double id2) { + super.SetOrientation(id0, id1, id2); + updateTextLoc(); + } + + @Override + public void RotateWXYZ(double id0, double id1, double id2, double id3) { + super.RotateWXYZ(id0, id1, id2, id3); + updateTextLoc(); + } + + @Override + public void SetPosition(double[] id0) { + super.SetPosition(id0); + updateTextLoc(); + } + + @Override + public void SetPosition(double id0, double id1, double id2) { + super.SetPosition(id0, id1, id2); + updateTextLoc(); + } + + @Override + public void SetOrientation(double[] id0) { + super.SetOrientation(id0); + updateTextLoc(); + } + + @Override + public void SetScale(double id0) { + super.SetScale(id0); + updateTextLoc(); + } + + @Override + public void SetScale(double id0, double id1, double id2) { + super.SetScale(id0, id1, id2); + updateTextLoc(); + } + + @Override + public void SetScale(double[] id0) { + super.SetScale(id0); + updateTextLoc(); + } + + @Override + public void SetUserMatrix(vtkMatrix4x4 id0) { + super.SetUserMatrix(id0); + updateTextLoc(); + } + + @Override + public void SetUserTransform(vtkLinearTransform id0) { + super.SetUserTransform(id0); + updateTextLoc(); + } + + @Override + public void Delete() { + ren.RemoveActor(xactor); + ren.RemoveActor(yactor); + ren.RemoveActor(zactor); + ren.RemoveActor(tubeActor); + ren.RemoveActor(xconeActor); + ren.RemoveActor(yconeActor); + ren.RemoveActor(xconeActor); + xactor.Delete(); + yactor.Delete(); + zactor.Delete(); + tubeActor.Delete(); + xconeActor.Delete(); + yconeActor.Delete(); + zconeActor.Delete(); + super.Delete(); + } + + public void dispose() { + ThreadUtils.asyncExec(AWTThread.getThreadAccess(), new Runnable() { + + @Override + public void run() { + removeFromRenderer(); + Delete(); + } + }); + } + + @Override + public vtkProp3D getVtkProp() { + return this; + } + +} diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/shape/axesSphereActor2.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/shape/axesSphereActor2.java new file mode 100644 index 00000000..84f4cf96 --- /dev/null +++ b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/shape/axesSphereActor2.java @@ -0,0 +1,228 @@ +package org.simantics.g3d.vtk.shape; + +import javax.vecmath.AxisAngle4d; +import javax.vecmath.Matrix4d; +import javax.vecmath.Point3d; +import javax.vecmath.Vector3d; + +import org.simantics.g3d.math.MathTools; +import org.simantics.g3d.shape.Color4d; +import org.simantics.g3d.shape.Cone; +import org.simantics.g3d.shape.Cylinder; +import org.simantics.g3d.shape.Mesh; +import org.simantics.g3d.shape.Sphere; + +import vtk.vtkLinearTransform; +import vtk.vtkMatrix4x4; +import vtk.vtkRenderer; +import vtk.vtkTextActor; + +public class axesSphereActor2 extends MeshActor{ + + private double axisLength; + private vtkRenderer ren; + private vtkTextActor xactor, yactor, zactor; + + public axesSphereActor2(vtkRenderer ren, double size) { + int res = 16; + axisLength = size; + this.ren = ren; + Mesh cone_x = Cone.create(size*0.3, res); + Mesh cone_y = Cone.create(size*0.3, res); + Mesh cone_z = Cone.create(size*0.3, res); + cone_x.rotate(MathTools.getQuat(new AxisAngle4d(0,0,-1,Math.PI*0.5))); + cone_z.rotate(MathTools.getQuat(new AxisAngle4d(1,0,0,Math.PI*0.5))); + cone_x.translate(new Vector3d(size,0,0)); + cone_y.translate(new Vector3d(0,size,0)); + cone_z.translate(new Vector3d(0,0,size)); + + Mesh tube_x = Cylinder.create(MathTools.ORIGIN, new Vector3d(size,0,0), size*0.1, res); + Mesh tube_y = Cylinder.create(MathTools.ORIGIN, new Vector3d(0,size,0), size*0.1, res); + Mesh tube_z = Cylinder.create(MathTools.ORIGIN, new Vector3d(0,0,size), size*0.1, res); + + Mesh sphere = Sphere.create(size*0.3, res, res*2/3); + + Color4d x_col = new Color4d(1,0,0,1); + Color4d y_col = new Color4d(1,1,0,1); + Color4d z_col = new Color4d(0,1,0,1); + Color4d o_col = new Color4d(0,0,1,1); + + cone_x.setColor(x_col); + tube_x.setColor(x_col); + cone_y.setColor(y_col); + tube_y.setColor(y_col); + cone_z.setColor(z_col); + tube_z.setColor(z_col); + sphere.setColor(o_col); + + sphere.add(cone_x); + sphere.add(tube_x); + sphere.add(cone_y); + sphere.add(tube_y); + sphere.add(cone_z); + sphere.add(tube_z); + + setMesh(sphere); + + + + xactor = new vtkTextActor(); + yactor = new vtkTextActor(); + zactor = new vtkTextActor(); + + xactor.SetInput("X"); + yactor.SetInput("Y"); + zactor.SetInput("Z"); + + xactor.SetTextScaleModeToNone(); + yactor.SetTextScaleModeToNone(); + zactor.SetTextScaleModeToNone(); + + xactor.GetTextProperty().SetColor(0.0, 0.0, 0.0); + xactor.GetTextProperty().ShadowOff(); + xactor.GetTextProperty().ItalicOff(); + xactor.GetTextProperty().BoldOff(); + + yactor.GetTextProperty().SetColor(0.0, 0.0, 0.0); + yactor.GetTextProperty().ShadowOff(); + yactor.GetTextProperty().ItalicOff(); + yactor.GetTextProperty().BoldOff(); + + zactor.GetTextProperty().SetColor(0.0, 0.0, 0.0); + zactor.GetTextProperty().ShadowOff(); + zactor.GetTextProperty().ItalicOff(); + zactor.GetTextProperty().BoldOff(); + + xactor.GetTextProperty().Delete(); + yactor.GetTextProperty().Delete(); + zactor.GetTextProperty().Delete(); + + xactor.SetMaximumLineHeight(0.25); + yactor.SetMaximumLineHeight(0.25); + zactor.SetMaximumLineHeight(0.25); + + xactor.SetPickable(0); + yactor.SetPickable(0); + zactor.SetPickable(0); + } + + private boolean labelVisible = false; + public void setLabelVisibility(boolean ison) { + if (ison == labelVisible) + return; + labelVisible = ison; + if (labelVisible) { + ren.AddActor2D(xactor); + ren.AddActor2D(yactor); + ren.AddActor2D(zactor); + updateTextLoc(); + } else { + ren.RemoveActor2D(xactor); + ren.RemoveActor2D(yactor); + ren.RemoveActor2D(zactor); + } + + } + + Matrix4d m = new Matrix4d(); + double mat[] = new double[16]; + Point3d x = new Point3d(); + Point3d y = new Point3d(); + Point3d z = new Point3d(); + + private void updateTextLoc() { + if (!labelVisible) + return; + xactor.GetPositionCoordinate().SetCoordinateSystemToWorld(); + yactor.GetPositionCoordinate().SetCoordinateSystemToWorld(); + zactor.GetPositionCoordinate().SetCoordinateSystemToWorld(); + + GetMatrix(mat); + MathTools.set(m, mat); + x.set(axisLength, 0,0); + y.set(0,axisLength, 0); + z.set(0,0,axisLength); + + m.transform(x); + m.transform(y); + m.transform(z); + xactor.GetPositionCoordinate().SetValue(x.x, x.y, x.z); + yactor.GetPositionCoordinate().SetValue(y.x, y.y, y.z); + zactor.GetPositionCoordinate().SetValue(z.x, z.y, z.z); + + xactor.GetPositionCoordinate().Delete(); + yactor.GetPositionCoordinate().Delete(); + zactor.GetPositionCoordinate().Delete(); + } + + @Override + public void SetOrientation(double id0, double id1, double id2) { + super.SetOrientation(id0, id1, id2); + updateTextLoc(); + } + + @Override + public void RotateWXYZ(double id0, double id1, double id2, double id3) { + super.RotateWXYZ(id0, id1, id2, id3); + updateTextLoc(); + } + + @Override + public void SetPosition(double[] id0) { + super.SetPosition(id0); + updateTextLoc(); + } + + @Override + public void SetPosition(double id0, double id1, double id2) { + super.SetPosition(id0, id1, id2); + updateTextLoc(); + } + + @Override + public void SetOrientation(double[] id0) { + super.SetOrientation(id0); + updateTextLoc(); + } + + @Override + public void SetScale(double id0) { + super.SetScale(id0); + updateTextLoc(); + } + + @Override + public void SetScale(double id0, double id1, double id2) { + super.SetScale(id0, id1, id2); + updateTextLoc(); + } + + @Override + public void SetScale(double[] id0) { + super.SetScale(id0); + updateTextLoc(); + } + + @Override + public void SetUserMatrix(vtkMatrix4x4 id0) { + super.SetUserMatrix(id0); + updateTextLoc(); + } + + @Override + public void SetUserTransform(vtkLinearTransform id0) { + super.SetUserTransform(id0); + updateTextLoc(); + } + + @Override + public void Delete() { + ren.RemoveActor(xactor); + ren.RemoveActor(yactor); + ren.RemoveActor(zactor); + xactor.Delete(); + yactor.Delete(); + zactor.Delete(); + super.Delete(); + } +} diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/shape/axisActor.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/shape/axisActor.java new file mode 100644 index 00000000..caf48d42 --- /dev/null +++ b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/shape/axisActor.java @@ -0,0 +1,268 @@ +package org.simantics.g3d.vtk.shape; + +import javax.vecmath.AxisAngle4d; +import javax.vecmath.Matrix4d; +import javax.vecmath.Point3d; +import javax.vecmath.Vector3d; + +import org.simantics.g3d.math.MathTools; +import org.simantics.utils.threads.AWTThread; +import org.simantics.utils.threads.ThreadUtils; + +import vtk.vtkActor; +import vtk.vtkAssembly; +import vtk.vtkConeSource; +import vtk.vtkLineSource; +import vtk.vtkLinearTransform; +import vtk.vtkMatrix4x4; +import vtk.vtkPolyDataMapper; +import vtk.vtkProp3D; +import vtk.vtkRenderer; +import vtk.vtkTextActor; +import vtk.vtkTubeFilter; + +public class axisActor extends vtkAssembly implements IvtkVisualObject{ + + private vtkRenderer ren; + private Vector3d axisDir = new Vector3d(1,0,0); + private vtkTextActor tactor; + private vtkActor tubeActor; + private vtkActor coneActor; + private boolean rendered = false; + + public axisActor(vtkRenderer _ren, String label) { + super(); + ren = _ren; + createAxis(label); + } + + public axisActor(vtkRenderer _ren, String label, Vector3d dir) { + super(); + ren = _ren; + this.axisDir = dir; + createAxis(label); + } + + public void createAxis(String label) { + vtkLineSource line = new vtkLineSource(); + line.SetPoint1(0.0,0.0,0.0); + line.SetPoint2(axisDir.x,axisDir.y,axisDir.z); + + tactor = new vtkTextActor(); + + tactor.SetInput(label); + + tactor.SetTextScaleModeToNone(); + tactor.GetTextProperty().SetColor(0.0, 0.0, 0.0); + tactor.GetTextProperty().ShadowOff(); + tactor.GetTextProperty().ItalicOff(); + tactor.GetTextProperty().BoldOff(); + + tactor.GetTextProperty().Delete(); + + tactor.SetMaximumLineHeight(0.25); + + tactor.SetPickable(0); + + vtkTubeFilter tube = new vtkTubeFilter(); + tube.SetInput(line.GetOutput()); + tube.SetRadius(0.05 * axisDir.length()); + tube.SetNumberOfSides(8); + + vtkPolyDataMapper tubeMapper = new vtkPolyDataMapper(); + tubeMapper.SetInput(tube.GetOutput()); + + tubeActor = new vtkActor(); + tubeActor.SetMapper(tubeMapper); + tubeActor.PickableOff(); + + int coneRes = 12; + double coneScale = 0.3 * axisDir.length(); + + // --- x-Cone + vtkConeSource cone = new vtkConeSource(); + cone.SetResolution(coneRes); + vtkPolyDataMapper coneMapper = new vtkPolyDataMapper(); + coneMapper.SetInput(cone.GetOutput()); + coneActor = new vtkActor(); + coneActor.SetMapper(coneMapper); + coneActor.GetProperty().SetColor(1, 0, 0); + coneActor.SetScale(coneScale, coneScale, coneScale); + coneActor.SetPosition(axisDir.x,axisDir.y,axisDir.z); + coneActor.SetPickable(0); + + AxisAngle4d aa = MathTools.createRotation(new Vector3d(1,0,0), new Vector3d(axisDir)); + if (aa != null) + coneActor.RotateWXYZ(MathTools.radToDeg(aa.angle), aa.x, aa.y, aa.z); + + this.AddPart(tubeActor); + this.AddPart(coneActor); + + tube.GetOutput().Delete(); + cone.GetOutput().Delete(); + line.GetOutput().Delete(); + + tubeMapper.Delete(); + tube.Delete(); + cone.Delete(); + line.Delete(); + + coneMapper.Delete(); + + coneActor.GetProperty().Delete(); + } + + public void addToRenderer() { + if (rendered) + return; + rendered = true; + + ren.AddActor2D(tactor); + + ren.AddActor(this); + } + + public void removeFromRenderer() { + if (!rendered) + return; + rendered = false; + ren.RemoveActor2D(tactor); + ren.RemoveActor(this); + } + + public boolean isRendered() { + return rendered; + } + + public void setAxesVisibility(boolean ison) { + this.SetVisibility(ison ? 1 : 0); + tactor.SetVisibility(ison ? 1 : 0); + } + + public void setLabelVisibility(boolean ison) { + tactor.SetVisibility(ison ? 1 : 0); + } + + double mat[] = new double[16]; + Matrix4d m = new Matrix4d(); + Point3d p = new Point3d(); + private void updateTextLoc() { + tactor.GetPositionCoordinate().SetCoordinateSystemToWorld(); + + + GetMatrix(mat); + MathTools.set(m, mat); + p.set(axisDir.x, axisDir.y,axisDir.z); + m.transform(p); + tactor.GetPositionCoordinate().SetValue(p.x, p.y, p.z); + + tactor.GetPositionCoordinate().Delete(); + } + + @Override + public void SetPickable(int id0) { + super.SetPickable(id0); + tubeActor.SetPickable(id0); + coneActor.SetPickable(id0); + } + + @Override + public void SetOrientation(double id0, double id1, double id2) { + super.SetOrientation(id0, id1, id2); + updateTextLoc(); + } + + @Override + public void RotateWXYZ(double id0, double id1, double id2, double id3) { + super.RotateWXYZ(id0, id1, id2, id3); + updateTextLoc(); + } + + @Override + public void SetPosition(double[] id0) { + super.SetPosition(id0); + updateTextLoc(); + } + + @Override + public void SetPosition(double id0, double id1, double id2) { + super.SetPosition(id0, id1, id2); + updateTextLoc(); + } + + @Override + public void SetOrientation(double[] id0) { + super.SetOrientation(id0); + updateTextLoc(); + } + + @Override + public void SetScale(double id0) { + super.SetScale(id0); + updateTextLoc(); + } + + @Override + public void SetScale(double id0, double id1, double id2) { + super.SetScale(id0, id1, id2); + updateTextLoc(); + } + + @Override + public void SetScale(double[] id0) { + super.SetScale(id0); + updateTextLoc(); + } + + public void SetColor(double r, double g, double b) { + coneActor.GetProperty().SetColor(r, g, b); + tubeActor.GetProperty().SetColor(r, g, b); + coneActor.GetProperty().Delete(); + tubeActor.GetProperty().Delete(); + } + + public void SetTextColor(double r, double g, double b) { + tactor.GetTextProperty().SetColor(r, g, b); + tactor.GetTextProperty().Delete(); + } + + @Override + public void SetUserMatrix(vtkMatrix4x4 id0) { + super.SetUserMatrix(id0); + updateTextLoc(); + } + + @Override + public void SetUserTransform(vtkLinearTransform id0) { + super.SetUserTransform(id0); + updateTextLoc(); + } + + @Override + public void Delete() { + ren.RemoveActor(tactor); + ren.RemoveActor(tubeActor); + ren.RemoveActor(coneActor); + tactor.Delete(); + tubeActor.Delete(); + coneActor.Delete(); + super.Delete(); + } + + public void dispose() { + ThreadUtils.asyncExec(AWTThread.getThreadAccess(), new Runnable() { + + @Override + public void run() { + removeFromRenderer(); + Delete(); + } + }); + } + + @Override + public vtkProp3D getVtkProp() { + return this; + } + +} diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/shape/vtkShape.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/shape/vtkShape.java new file mode 100644 index 00000000..636fb8f7 --- /dev/null +++ b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/shape/vtkShape.java @@ -0,0 +1,184 @@ +package org.simantics.g3d.vtk.shape; + +import javax.vecmath.Tuple3d; + +import vtk.vtkActor; +import vtk.vtkDataSetMapper; +import vtk.vtkLine; +import vtk.vtkPoints; +import vtk.vtkPolyLine; +import vtk.vtkUnstructuredGrid; + +public class vtkShape { + + /** + * Creates a grid shaped actor. + * + * @param size number of grid lines + * @param space distance between grid lines + * @param axes bitmask of axes: 1:x, 2:y, 4:z + * @return vtkActor representing a grid. + */ + public static vtkActor createGridActor(int size, double space, int axes) { + int gridCount = 0; + if ((axes & 0x1) > 0) { + gridCount++; + } + if ((axes & 0x2) > 0) { + gridCount++; + } + if ((axes & 0x4) > 0) { + gridCount++; + } + int pointCount = (size+1) * 2 * 2 * gridCount; + vtkPoints linePoints = new vtkPoints(); + linePoints.SetNumberOfPoints(pointCount); + + + double max = space * (double)size * 0.5; + double min = -max; + int base = 0; + if ((axes & 0x1) > 0) { + for (int i = 0; i <= size; i++) { + double s = min + ((double)i) * space; + linePoints.InsertPoint(base + i*2 ,0.0, s, min); + linePoints.InsertPoint(base + i*2+1,0.0, s, max); + i++; + if (i > size) + break; + s = min + ((double)i) * space; + linePoints.InsertPoint(base + i*2 ,0.0, s, max); + linePoints.InsertPoint(base + i*2+1,0.0, s, min); + } + base += (size+1)*2; + for (int i = 0; i <= size; i++) { + double s = min + ((double)i) * space; + linePoints.InsertPoint(base + i*2 , 0.0, max, s); + linePoints.InsertPoint(base + i*2+1, 0.0, min, s); + i++; + if (i > size) + break; + s = min + ((double)i) * space; + linePoints.InsertPoint(base + i*2 , 0.0, min, s); + linePoints.InsertPoint(base + i*2+1, 0.0, max, s); + } + base += (size+1)*2; + } + if ((axes & 0x4) > 0) { + for (int i = 0; i <= size; i++) { + double s = min + ((double)i) * space; + linePoints.InsertPoint(base + i*2 ,s, min, 0.0); + linePoints.InsertPoint(base + i*2+1,s, max, 0.0); + i++; + if (i > size) + break; + s = min + ((double)i) * space; + linePoints.InsertPoint(base + i*2 ,s, max, 0.0); + linePoints.InsertPoint(base + i*2+1,s, min, 0.0); + } + base += (size+1)*2; + for (int i = 0; i <= size; i++) { + double s = min + ((double)i) * space; + linePoints.InsertPoint(base + i*2 ,max, s, 0.0); + linePoints.InsertPoint(base + i*2+1,min, s, 0.0); + i++; + if (i > size) + break; + s = min + ((double)i) * space; + linePoints.InsertPoint(base + i*2 ,min, s, 0.0); + linePoints.InsertPoint(base + i*2+1,max, s, 0.0); + } + base += (size+1)*2; + } + if ((axes & 0x2) > 0) { + for (int i = 0; i <= size; i++) { + double s = min + ((double)i) * space; + linePoints.InsertPoint(base + i*2 ,s, 0.0, min); + linePoints.InsertPoint(base + i*2+1,s, 0.0, max); + i++; + if (i > size) + break; + s = min + ((double)i) * space; + linePoints.InsertPoint(base + i*2 ,s, 0.0, max); + linePoints.InsertPoint(base + i*2+1,s, 0.0, min); + } + base += (size+1)*2; + for (int i = 0; i <= size; i++) { + double s = min + ((double)i) * space; + linePoints.InsertPoint(base + i*2 ,max, 0.0, s); + linePoints.InsertPoint(base + i*2+1,min, 0.0, s); + i++; + if (i > size) + break; + s = min + ((double)i) * space; + linePoints.InsertPoint(base + i*2 ,min, 0.0, s); + linePoints.InsertPoint(base + i*2+1,max, 0.0, s); + } + base += (size+1)*2; + } + + + //vtkLine aLine = new vtkLine(); + vtkPolyLine aLine = new vtkPolyLine(); + aLine.GetPointIds().SetNumberOfIds(pointCount); + for (int i = 0; i < pointCount; i++) { + aLine.GetPointIds().SetId(i, i); + } + + + vtkUnstructuredGrid aLineGrid = new vtkUnstructuredGrid(); + aLineGrid.Allocate(pointCount, pointCount); + aLineGrid.InsertNextCell(aLine.GetCellType(), aLine.GetPointIds()); + aLineGrid.SetPoints(linePoints); + vtkDataSetMapper aLineMapper = new vtkDataSetMapper(); + aLineMapper.SetInput(aLineGrid); + vtkActor aLineActor = new vtkActor(); + aLineActor.SetMapper(aLineMapper); + + linePoints.Delete(); + aLine.GetPointIds().Delete(); + aLine.Delete(); + aLineGrid.Delete(); + aLineMapper.Delete(); + + aLineActor.GetProperty().SetColor(0, 0, 0); + aLineActor.GetProperty().Delete(); + + return aLineActor; + } + + /** + * Creates a line. + * + * @param p1 + * @param p2 + * @return + */ + public static vtkActor createLineActor(Tuple3d p1, Tuple3d p2) { + vtkPoints linePoints = new vtkPoints(); + linePoints.SetNumberOfPoints(2); + linePoints.InsertPoint(0,p1.x, p1.y, p1.z); + linePoints.InsertPoint(1,p2.x, p2.y, p2.z); + vtkLine aLine = new vtkLine(); + aLine.GetPointIds().SetId(0, 0); + aLine.GetPointIds().SetId(1, 1); + vtkUnstructuredGrid aLineGrid = new vtkUnstructuredGrid(); + aLineGrid.Allocate(1, 1); + aLineGrid.InsertNextCell(aLine.GetCellType(), aLine.GetPointIds()); + aLineGrid.SetPoints(linePoints); + vtkDataSetMapper aLineMapper = new vtkDataSetMapper(); + aLineMapper.SetInput(aLineGrid); + vtkActor aLineActor = new vtkActor(); + aLineActor.SetMapper(aLineMapper); + //aLineActor.GetProperty().SetDiffuseColor(.2, 1, 1); + + linePoints.Delete(); + aLine.GetPointIds().Delete(); + aLine.Delete(); + aLineGrid.Delete(); + aLineMapper.Delete(); + + return aLineActor; + } + +} diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/utils/vtkEffect.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/utils/vtkEffect.java new file mode 100644 index 00000000..0d00c2a9 --- /dev/null +++ b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/utils/vtkEffect.java @@ -0,0 +1,362 @@ +package org.simantics.g3d.vtk.utils; + +import javax.vecmath.AxisAngle4d; +import javax.vecmath.Vector3d; + +import org.simantics.g3d.math.MathTools; +import org.simantics.g3d.vtk.shape.IvtkVisualObject; + +import vtk.vtkActor; +import vtk.vtkCamera; +import vtk.vtkContourFilter; +import vtk.vtkDataObject; +import vtk.vtkOutlineFilter; +import vtk.vtkOutlineSource; +import vtk.vtkPolyData; +import vtk.vtkPolyDataMapper; +import vtk.vtkPolyDataSilhouette; +import vtk.vtkProp3D; +import vtk.vtkRenderWindow; +import vtk.vtkRenderer; +import vtk.vtkTransform; +import vtk.vtkTransformPolyDataFilter; +import vtk.vtkWindowToImageFilter; + +public class vtkEffect { + + private static vtkRenderer tmpRenderer; + + public static vtkRenderer getRenderer() { + if (tmpRenderer == null) + tmpRenderer = new vtkRenderer(); + return tmpRenderer; + } + public static vtkActor createContour(vtkProp3D tmpProp) { + + vtkRenderer tmpRenderer = getRenderer(); + tmpRenderer.SetBackground(1,1,1); + + + if (tmpProp instanceof IvtkVisualObject) { + ((IvtkVisualObject)tmpProp).addToRenderer(); + } else { + tmpRenderer.AddActor(tmpProp); + } + + if (tmpProp instanceof vtkActor) { + ((vtkActor)tmpProp).GetProperty().SetColor(0, 0, 0); + } + + + double bounds_data[] = tmpProp.GetBounds(); + double center_data[] = tmpProp.GetCenter(); + + tmpRenderer.ResetCamera(); + tmpRenderer.GetActiveCamera().SetParallelProjection(1); + + vtkRenderWindow tmpRenderWindow = new vtkRenderWindow(); + tmpRenderWindow.SetOffScreenRendering(1); + tmpRenderWindow.AddRenderer(tmpRenderer); + tmpRenderWindow.Render(); + + vtkWindowToImageFilter windowToImageFilter = new vtkWindowToImageFilter(); + windowToImageFilter.SetInput(tmpRenderWindow); + windowToImageFilter.SetMagnification(2); + windowToImageFilter.Update(); + + vtkContourFilter contourFilter = new vtkContourFilter(); + contourFilter.SetInputConnection(windowToImageFilter.GetOutputPort()); + + contourFilter.SetValue(0, 255); + contourFilter.Update(); + + vtkPolyData contour = contourFilter.GetOutput(); + + double bounds_contour[] = new double[6]; + double center_contour[] = new double[3]; + double trans_x=0., trans_y=0., trans_z=0., ratio_x=0., ratio_y=0.; + contour.GetBounds(bounds_contour); + + ratio_x = (bounds_data[1]-bounds_data[0])/(bounds_contour[1]-bounds_contour[0]); + ratio_y = (bounds_data[3]-bounds_data[2])/(bounds_contour[3]-bounds_contour[2]); + + vtkTransform transform1 = new vtkTransform(); + transform1.Scale(ratio_x,ratio_y,1); + + vtkTransformPolyDataFilter tFilter1 = new vtkTransformPolyDataFilter(); + tFilter1.SetInput(contour); + tFilter1.SetTransform(transform1); + tFilter1.Update(); + + contour = tFilter1.GetOutput(); + + contour.GetCenter(center_contour); + trans_x = center_data[0]-center_contour[0]; + trans_y = center_data[1]-center_contour[1]; + trans_z = center_data[2]-center_contour[2]; + + vtkTransform transform2 = new vtkTransform(); + transform2.Translate( trans_x, trans_y, trans_z); + + vtkTransformPolyDataFilter tFilter2 = new vtkTransformPolyDataFilter(); + tFilter2.SetInput(contour); + tFilter2.SetTransform(transform2); + tFilter2.Update(); + + contour = tFilter2.GetOutput(); + + vtkPolyDataMapper mapper = new vtkPolyDataMapper(); + mapper.SetInput(contour); + + + vtkActor actor =new vtkActor(); + actor.SetMapper(mapper); + actor.GetProperty().SetLineWidth(2.); + + tmpRenderer.RemoveActor(tmpProp); + + tFilter1.Delete(); + tFilter2.Delete(); + contour.Delete(); + contourFilter.Delete(); + mapper.Delete(); + tmpRenderWindow.Delete(); + transform1.Delete(); + transform2.Delete(); + windowToImageFilter.Delete(); + + return actor; + } + + public static vtkActor createContour(vtkProp3D tmpProp, vtkRenderer ren) { + + vtkRenderer tmpRenderer = getRenderer(); + tmpRenderer.SetBackground(1,1,1); + + + if (tmpProp instanceof IvtkVisualObject) { + ((IvtkVisualObject)tmpProp).addToRenderer(); + } else { + tmpRenderer.AddActor(tmpProp); + } + + if (tmpProp instanceof vtkActor) { + ((vtkActor)tmpProp).GetProperty().SetColor(0, 0, 0); + } + + + //double bounds_data[] = tmpProp.GetBounds(); + double center_data[] = tmpProp.GetCenter(); + + tmpRenderer.ResetCamera(); + + vtkCamera camera = ren.GetActiveCamera(); + + vtkCamera tmpCamera = tmpRenderer.GetActiveCamera(); + tmpCamera.SetParallelProjection(camera.GetParallelProjection()); + + + Vector3d pos = new Vector3d(camera.GetPosition()); + Vector3d foc = new Vector3d(camera.GetFocalPoint()); + Vector3d dir = new Vector3d(); + dir.sub(pos,foc); + double l = dir.length(); +// dir.scale(1.0/l); +// +// +// +// +// dir.scale(2.0); +// Vector3d tmpFoc = new Vector3d(tmpCamera.GetFocalPoint()); +// tmpFoc.add(dir); +// tmpCamera.SetPosition(tmpFoc.x,tmpFoc.y,tmpFoc.z); +// tmpCamera.SetRoll(camera.GetRoll()); + + tmpCamera.DeepCopy(camera); + //tmpCamera.SetModelTransformMatrix(camera.GetModelTransformMatrix()); + tmpCamera.UpdateViewport(tmpRenderer); + + vtkRenderWindow tmpRenderWindow = new vtkRenderWindow(); + tmpRenderWindow.SetOffScreenRendering(1); + tmpRenderWindow.AddRenderer(tmpRenderer); + tmpRenderWindow.Render(); + + vtkWindowToImageFilter windowToImageFilter = new vtkWindowToImageFilter(); + windowToImageFilter.SetInput(tmpRenderWindow); + windowToImageFilter.SetMagnification(2); + windowToImageFilter.Update(); + + vtkContourFilter contourFilter = new vtkContourFilter(); + contourFilter.SetInputConnection(windowToImageFilter.GetOutputPort()); + + contourFilter.SetValue(0, 255); + contourFilter.Update(); + + vtkPolyData contour = contourFilter.GetOutput(); + + + double or[] = camera.GetOrientationWXYZ(); + AxisAngle4d aa = new AxisAngle4d(); + aa.angle = -MathTools.degToRad(or[0]); + aa.x = or[1]; + aa.y = or[2]; + aa.z = or[3]; + + vtkTransform transform0 = new vtkTransform(); + transform0.RotateWXYZ(MathTools.radToDeg(aa.angle), aa.x, aa.y, aa.z); + + vtkTransformPolyDataFilter tFilter0 = new vtkTransformPolyDataFilter(); + tFilter0.SetInput(contour); + tFilter0.SetTransform(transform0); + tFilter0.Update(); + + contour.Delete(); + contour = tFilter0.GetOutput(); + + double bounds_contour[] = new double[6]; + + double trans_x=0., trans_y=0., trans_z=0., ratio_x=0.002, ratio_y=0.002, ratio_z=0.002; + contour.GetBounds(bounds_contour); +// +// ratio_x = (bounds_data[1]-bounds_data[0])/(bounds_contour[1]-bounds_contour[0]); +// ratio_y = (bounds_data[3]-bounds_data[2])/(bounds_contour[3]-bounds_contour[2]); +// ratio_z = (bounds_data[5]-bounds_data[4])/(bounds_contour[5]-bounds_contour[4]); + ratio_x = l*0.0008; + ratio_y = l*0.0008; + ratio_z = l*0.0008; + + + System.out.println(ratio_x + " " + ratio_y); + + +// + vtkTransform transform1 = new vtkTransform(); + transform1.Scale(ratio_x,ratio_y,ratio_z); + + vtkTransformPolyDataFilter tFilter1 = new vtkTransformPolyDataFilter(); + tFilter1.SetInput(contour); + tFilter1.SetTransform(transform1); + tFilter1.Update(); + + contour.Delete(); + contour = tFilter1.GetOutput(); + + double center_contour[] = new double[3]; + contour.GetCenter(center_contour); + trans_x = center_data[0]-center_contour[0]; + trans_y = center_data[1]-center_contour[1]; + trans_z = center_data[2]-center_contour[2]; +// + System.out.println(trans_x + " " + trans_y + " " + trans_z); +// + vtkTransform transform2 = new vtkTransform(); + transform2.Translate( trans_x, trans_y, trans_z); + + vtkTransformPolyDataFilter tFilter2 = new vtkTransformPolyDataFilter(); + tFilter2.SetInput(contour); + tFilter2.SetTransform(transform2); + tFilter2.Update(); + + contour.Delete(); + contour = tFilter2.GetOutput(); + + vtkPolyDataMapper mapper = new vtkPolyDataMapper(); + mapper.SetInput(contour); + + + vtkActor actor =new vtkActor(); + actor.SetMapper(mapper); + actor.GetProperty().SetLineWidth(2.); + actor.GetProperty().SetColor(0,0,1); + actor.GetProperty().Delete(); + + tmpRenderer.RemoveActor(tmpProp); + + tFilter0.Delete(); + tFilter1.Delete(); + tFilter2.Delete(); + contour.Delete(); + contourFilter.Delete(); + mapper.Delete(); + tmpRenderWindow.Delete(); + transform0.Delete(); + transform1.Delete(); + transform2.Delete(); + windowToImageFilter.GetOutputPort().Delete(); + windowToImageFilter.Delete(); + + ren.AddActor(actor); + +// vtkMatrix4x4 m = camera.GetModelTransformMatrix(); +// m.Invert(); +// actor.SetUserMatrix(m); + //m.Delete(); + //actor.SetPosition(trans_x,trans_y, trans_z); + //actor.RotateWXYZ(MathTools.radToDeg(aa.angle), aa.x, aa.y, aa.z); + // + return actor; + } + + public static vtkActor createSilhouette(vtkRenderer ren, vtkDataObject data) { + + + vtkPolyDataSilhouette silhouette = new vtkPolyDataSilhouette(); + + silhouette.SetInput(data); + silhouette.SetCamera(ren.GetActiveCamera()); + silhouette.SetEnableFeatureAngle(0); + vtkPolyDataMapper mapper = new vtkPolyDataMapper(); + + mapper.SetInputConnection(silhouette.GetOutputPort()); + + vtkActor actor = new vtkActor(); + actor.SetMapper(mapper); + + silhouette.GetOutputPort().Delete(); + silhouette.Delete(); + mapper.Delete(); + + return actor; + } + + public static vtkActor createOutline(vtkDataObject data) { + vtkOutlineFilter filter = new vtkOutlineFilter(); + filter.SetInput(data); + vtkPolyDataMapper mapper = new vtkPolyDataMapper(); + mapper.SetInputConnection(filter.GetOutputPort()); + + vtkActor actor = new vtkActor(); + actor.SetMapper(mapper); + + filter.GetOutputPort().Delete(); + filter.Delete(); + mapper.Delete(); + + return actor; + } + + public static vtkActor createOutline(vtkProp3D prop) { + + double bounds[] = prop.GetBounds(); + + vtkOutlineSource source = new vtkOutlineSource(); + source.SetBounds(bounds); + + vtkOutlineFilter filter = new vtkOutlineFilter(); + filter.SetInput(source.GetOutput()); + vtkPolyDataMapper mapper = new vtkPolyDataMapper(); + mapper.SetInputConnection(filter.GetOutputPort()); + + vtkActor actor = new vtkActor(); + actor.SetMapper(mapper); + + source.GetOutput().Delete(); + source.Delete(); + filter.GetOutputPort().Delete(); + filter.Delete(); + mapper.Delete(); + + actor.SetPickable(0); + return actor; + } +} diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/utils/vtkPanelUtil.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/utils/vtkPanelUtil.java new file mode 100644 index 00000000..eb0e727e --- /dev/null +++ b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/utils/vtkPanelUtil.java @@ -0,0 +1,79 @@ +package org.simantics.g3d.vtk.utils; + +import java.util.ArrayList; +import java.util.List; + +import org.simantics.g3d.vtk.Activator; +import org.simantics.g3d.vtk.preferences.CloseMethod; +import org.simantics.g3d.vtk.preferences.PreferenceConstants; +import org.simantics.utils.threads.AWTThread; + +import vtk.vtkCamera; +import vtk.vtkObject; +import vtk.vtkPanel; +import vtk.vtkReferenceInformation; +import vtk.vtkRenderWindow; +import vtk.vtkRenderer; + +public class vtkPanelUtil { + + private static List activePanels = new ArrayList(); + private static List waitingToDeletePanels = new ArrayList(); + + public static void registerPanel(vtkPanel panel) { + activePanels.add(panel); + } + + public static void unregisterPanel(vtkPanel panel) { + assert (Thread.currentThread() == AWTThread.getThreadAccess().getThread()); + if (!activePanels.remove(panel)) + return; + CloseMethod method = getCloseMethod(); + if (method == CloseMethod.ON_LAST_CLOSE) { + waitingToDeletePanels.add(panel); + + if (activePanels.size() == 0) { + cleanup(); + } + } else if (method == CloseMethod.ON_CLOSE) { + dPanel(panel); + vtkGC(); + } else if (method == CloseMethod.NO_CLOSE) { + waitingToDeletePanels.add(panel); + } + } + + public static CloseMethod getCloseMethod() { + return CloseMethod.valueOf(Activator.getDefault().getPreferenceStore().getString(PreferenceConstants.CLOSE_METHOD)); + } + + private static void cleanup() { + + for (vtkPanel p : waitingToDeletePanels) { + dPanel(p); + } + waitingToDeletePanels.clear(); + vtkGC(); + } + + private static void vtkGC() { + vtkReferenceInformation info = vtkObject.JAVA_OBJECT_MANAGER.gc(true); + System.out.println("Referenced objects when closing editor: " + info.getTotalNumberOfObjects() + "\n"); + System.out.println(info.listRemovedReferenceToString()); + System.out.println(info.listKeptReferenceToString()); + } + + + private static void dPanel(vtkPanel panel) { + panel.lock(); + vtkCamera camera = panel.GetRenderer().GetActiveCamera(); + vtkRenderer ren = panel.GetRenderer(); + vtkRenderWindow win = panel.GetRenderWindow(); + win.SetForceMakeCurrent(); + panel.Delete(); + panel = null; + camera.Delete(); + ren.Delete(); + win.Delete(); + } +} diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/utils/vtkUtil.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/utils/vtkUtil.java new file mode 100644 index 00000000..639d894e --- /dev/null +++ b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/utils/vtkUtil.java @@ -0,0 +1,119 @@ +package org.simantics.g3d.vtk.utils; + +import java.util.Collection; + +import javax.vecmath.AxisAngle4d; +import javax.vecmath.Matrix4d; +import javax.vecmath.Point2d; +import javax.vecmath.Point3d; +import javax.vecmath.Quat4d; +import javax.vecmath.Tuple3d; +import javax.vecmath.Vector3d; + +import org.simantics.g3d.math.MathTools; +import org.simantics.g3d.math.Ray; + +import vtk.vtkMatrix4x4; +import vtk.vtkProp3D; +import vtk.vtkRenderer; + +public class vtkUtil { + + public static Ray createMouseRay(vtkRenderer ren1, double x, double y) { + Point2d screenPos = new Point2d(x,y); + Point3d worldCoords = getWorldCoordinates(ren1, screenPos, 0); + Point3d worldCoords2 = getWorldCoordinates(ren1, screenPos, 1); + Vector3d dir = new Vector3d(worldCoords2); + dir.sub(worldCoords); + return new Ray(worldCoords, dir); + } + + public static Point3d getWorldCoordinates(vtkRenderer ren1, Point2d screenPosition, double zPos) { + + ren1.SetDisplayPoint(screenPosition.x, ren1.GetSize()[1]-screenPosition.y, zPos); + ren1.DisplayToWorld(); + double world[] = ren1.GetWorldPoint(); + + return new Point3d(world); + + } + + public static Point2d getScreenCoordinates(vtkRenderer ren1, Tuple3d worldPos) { + ren1.SetWorldPoint(worldPos.x, worldPos.y, worldPos.z, 0.0); + ren1.WorldToDisplay(); + double screen[] = ren1.GetDisplayPoint(); + + return new Point2d(screen); + + } + + public static Matrix4d getMatrix(vtkMatrix4x4 ptm) { + Matrix4d mat = new Matrix4d(); + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + mat.setElement(i, j, ptm.GetElement(i, j)); + } + } + + return mat; + } + + public static vtkMatrix4x4 getMatrix(Matrix4d m) { + vtkMatrix4x4 mat= new vtkMatrix4x4(); + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + mat.SetElement(i, j, m.getElement(i, j)); + } + } + return mat; + } + + public static void updateTransform(Collection props, Vector3d pos, Quat4d q) { + AxisAngle4d aa = new AxisAngle4d(); + aa.set(q); + updateTransform(props, pos, aa); + } + + public static void updateTransform(vtkProp3D actor, double pos[], AxisAngle4d aa) { + actor.SetOrientation(0, 0, 0); + actor.RotateWXYZ(MathTools.radToDeg(aa.angle), aa.x, aa.y, aa.z); + actor.SetPosition(pos); + } + + public static void updateTransform(vtkProp3D actor, AxisAngle4d aa) { + actor.SetOrientation(0, 0, 0); + actor.RotateWXYZ(MathTools.radToDeg(aa.angle), aa.x, aa.y, aa.z); + } + + + public static void updateTransform(Collection props, Vector3d pos, AxisAngle4d aa) { + for (vtkProp3D actor : props) { + actor.SetOrientation(0, 0, 0); + actor.RotateWXYZ(MathTools.radToDeg(aa.angle), aa.x, aa.y, aa.z); + actor.SetPosition(pos.x, pos.y, pos.z); + } + } + + public static void updateTransform(Collection props, Vector3d pos, AxisAngle4d aa, double scale) { + for (vtkProp3D actor : props) { + actor.SetOrientation(0, 0, 0); + actor.RotateWXYZ(MathTools.radToDeg(aa.angle), aa.x, aa.y, aa.z); + actor.SetScale(scale); + actor.SetPosition(pos.x,pos.y,pos.z); + } + } + + public static void updateTransform(vtkProp3D actor, Vector3d pos, AxisAngle4d aa, double scale) { + actor.SetOrientation(0, 0, 0); + actor.RotateWXYZ(MathTools.radToDeg(aa.angle), aa.x, aa.y, aa.z); + actor.SetScale(scale); + actor.SetPosition(pos.x,pos.y,pos.z); + } + + public static void updateTransform(vtkProp3D actor, Vector3d pos, AxisAngle4d aa, double scalex, double scaley, double scalez) { + actor.SetOrientation(0, 0, 0); + actor.RotateWXYZ(MathTools.radToDeg(aa.angle), aa.x, aa.y, aa.z); + actor.SetScale(scalex,scaley, scalez); + actor.SetPosition(pos.x,pos.y,pos.z); + } +} diff --git a/org.simantics.g3d/.classpath b/org.simantics.g3d/.classpath new file mode 100644 index 00000000..b07aadd1 --- /dev/null +++ b/org.simantics.g3d/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/org.simantics.g3d/.project b/org.simantics.g3d/.project new file mode 100644 index 00000000..1345a9f0 --- /dev/null +++ b/org.simantics.g3d/.project @@ -0,0 +1,28 @@ + + + org.simantics.g3d + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/org.simantics.g3d/.settings/org.eclipse.jdt.core.prefs b/org.simantics.g3d/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000..76b52a10 --- /dev/null +++ b/org.simantics.g3d/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,8 @@ +#Mon Dec 12 12:35:07 EET 2011 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/org.simantics.g3d/META-INF/MANIFEST.MF b/org.simantics.g3d/META-INF/MANIFEST.MF new file mode 100644 index 00000000..48e2983e --- /dev/null +++ b/org.simantics.g3d/META-INF/MANIFEST.MF @@ -0,0 +1,37 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: G3D +Bundle-SymbolicName: org.simantics.g3d;singleton:=true +Bundle-Version: 1.0.0.qualifier +Bundle-Activator: org.simantics.g3d.Activator +Bundle-Vendor: VTT +Require-Bundle: org.eclipse.core.runtime, + javax.vecmath;bundle-version="1.5.2", + org.simantics.g3d.ontology;bundle-version="1.0.0", + org.simantics.db.layer0;bundle-version="1.1.0", + org.eclipse.jface;bundle-version="3.6.2", + org.eclipse.ui;bundle-version="3.6.2", + org.eclipse.ui.views;bundle-version="3.5.1", + org.simantics.browsing.ui.swt;bundle-version="1.1.0", + org.simantics.db.management;bundle-version="1.1.0", + org.simantics.selectionview;bundle-version="1.0.0", + gnu.trove2;bundle-version="2.0.4", + org.simantics.objmap2;bundle-version="1.0.0", + org.eclipse.nebula.widgets.tablecombo;bundle-version="1.0.0", + org.simantics.ui;bundle-version="1.0.0" +Bundle-RequiredExecutionEnvironment: JavaSE-1.6 +Bundle-ActivationPolicy: lazy +Export-Package: org.simantics.g3d, + org.simantics.g3d.gizmo, + org.simantics.g3d.math, + org.simantics.g3d.preferences, + org.simantics.g3d.property, + org.simantics.g3d.property.annotations, + org.simantics.g3d.scenegraph, + org.simantics.g3d.scenegraph.base, + org.simantics.g3d.scenegraph.structural, + org.simantics.g3d.shape, + org.simantics.g3d.toolbar, + org.simantics.g3d.tools, + org.simantics.g3d.ui, + org.simantics.g3d.wizard diff --git a/org.simantics.g3d/adapters.xml b/org.simantics.g3d/adapters.xml new file mode 100644 index 00000000..5194e72e --- /dev/null +++ b/org.simantics.g3d/adapters.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/org.simantics.g3d/build.properties b/org.simantics.g3d/build.properties new file mode 100644 index 00000000..6f20375d --- /dev/null +++ b/org.simantics.g3d/build.properties @@ -0,0 +1,5 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + plugin.xml diff --git a/org.simantics.g3d/help-isv/arrow.png b/org.simantics.g3d/help-isv/arrow.png new file mode 100644 index 00000000..464e75f9 Binary files /dev/null and b/org.simantics.g3d/help-isv/arrow.png differ diff --git a/org.simantics.g3d/help-isv/introduction.mediawiki b/org.simantics.g3d/help-isv/introduction.mediawiki new file mode 100644 index 00000000..40d5ad8e --- /dev/null +++ b/org.simantics.g3d/help-isv/introduction.mediawiki @@ -0,0 +1,6 @@ +=Introduction= +Simantics 3D framework (G3D) provides a set of tools for developing 3D modelling environment on top of Simantics. + +The framework is rendering library neutral. Currently supported are: +* [http://www.vtk.org|VTK] +* [http://www.jmonkeyengine.org|jMonkeyEngine] \ No newline at end of file diff --git a/org.simantics.g3d/help-isv/print-style.css b/org.simantics.g3d/help-isv/print-style.css new file mode 100644 index 00000000..a77c1e10 --- /dev/null +++ b/org.simantics.g3d/help-isv/print-style.css @@ -0,0 +1,7 @@ +@media screen { + body { width: 780px; } +} + +@media print { + html { font-size: 10pt; } +} diff --git a/org.simantics.g3d/help-isv/style.css b/org.simantics.g3d/help-isv/style.css new file mode 100644 index 00000000..d86b54bc --- /dev/null +++ b/org.simantics.g3d/help-isv/style.css @@ -0,0 +1,37 @@ + + /* following font face declarations need to be removed for DBCS */ + body, h1, h2, h3, h4, h5, h6, p, table, td, caption, th, ul, ol, dl, li, dd, dt {font-family: Arial, Helvetica, sans-serif; color: #000000 } + pre, code, tt { font-family: "Courier New", Courier, monospace;} + /* end font face declarations */ + + body { font-size: 83%; background: #FFFFFF; margin-bottom: 1em } + h1 { font-size: 180%; margin-top: 5px; margin-bottom: 1px } + h2 { font-size: 140%; margin-top: 25px; margin-bottom: 3px } + h3 { font-size: 110%; margin-top: 20px; margin-bottom: 3px } + h4 { font-size: 100%; margin-top: 20px; margin-bottom: 3px; font-style: italic } + p { margin-top: 10px; margin-bottom: 10px } + pre { font-size: 93%; margin-left: 6; color: #4444CC } + img.border { border:1px dashed } + pre.solid { border:1px solid #333; background: #eee; padding: 3px; margin: 3px; } + pre.dotted { font-size: 93%; margin-left: 6; padding: 1em;border: 1px dashed #2f6fab;color: black;background-color: #f9f9f9;line-height: 1.1em; } + code, tt { font-size: 93%; } + table { font-size: 100% } /* needed for quirks mode */ + a:link { color: #0000FF } + a:hover { color: #000080 } + a:visited { text-decoration: underline } + + + ul { margin-top: 4px; margin-bottom: 4px; list-style-image: url("arrow.png"); margin-left: 25px; } + li { margin-left: 0; margin-bottom: 4px; padding: 0; /* margin between bullet and content */ } + ol { margin-top: 10px; margin-bottom: 10px; } + + + dl { margin-top: 10px; margin-bottom: 10px; } + dt { margin-top: 5px; margin-bottom: 5px; font-weight: bold; } + dd { margin-top: 5px; margin-bottom: 5px; } + strong { font-weight: bold} + em { font-style: italic} + var { font-style: italic} + div.revision { border-left-style: solid; border-left-width: thin; + border-left-color: #7B68EE; padding-left:5 } + th { font-weight: bold } diff --git a/org.simantics.g3d/help-isv/toc.xml b/org.simantics.g3d/help-isv/toc.xml new file mode 100644 index 00000000..9147ca1f --- /dev/null +++ b/org.simantics.g3d/help-isv/toc.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/org.simantics.g3d/plugin.xml b/org.simantics.g3d/plugin.xml new file mode 100644 index 00000000..fe6ae1f1 --- /dev/null +++ b/org.simantics.g3d/plugin.xml @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.simantics.g3d/schema/toolbarCommand.exsd b/org.simantics.g3d/schema/toolbarCommand.exsd new file mode 100644 index 00000000..ef457892 --- /dev/null +++ b/org.simantics.g3d/schema/toolbarCommand.exsd @@ -0,0 +1,149 @@ + + + + + + + + + [Enter description of this extension point.] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Used with radio buttons. + + + + + + + + + + + + + + + + + + + + + + [Enter the first release in which this extension point appears.] + + + + + + + + + [Enter extension point usage example here.] + + + + + + + + + [Enter API information here.] + + + + + + + + + [Enter information about supplied implementation of this extension point.] + + + + + diff --git a/org.simantics.g3d/src/org/simantics/g3d/Activator.java b/org.simantics.g3d/src/org/simantics/g3d/Activator.java new file mode 100644 index 00000000..d485b71b --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/Activator.java @@ -0,0 +1,47 @@ +package org.simantics.g3d; + +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.BundleContext; + +public class Activator extends AbstractUIPlugin { + + // The plug-in ID + public static final String PLUGIN_ID = "org.simantics.g3d"; //$NON-NLS-1$ + + // The shared instance + private static Activator plugin; + + /** + * The constructor + */ + public Activator() { + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext) + */ + public void start(BundleContext context) throws Exception { + super.start(context); + plugin = this; + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext) + */ + public void stop(BundleContext context) throws Exception { + plugin = null; + super.stop(context); + } + + /** + * Returns the shared instance + * + * @return the shared instance + */ + public static Activator getDefault() { + return plugin; + } + +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/adapters/NodeRemover.java b/org.simantics.g3d/src/org/simantics/g3d/adapters/NodeRemover.java new file mode 100644 index 00000000..ce2453b0 --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/adapters/NodeRemover.java @@ -0,0 +1,30 @@ +package org.simantics.g3d.adapters; + +import java.util.Map; + +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.WriteGraph; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.layer0.adapter.Remover; + +public class NodeRemover implements Remover { + + //private Resource node; + + public NodeRemover(Resource node) { + //this.node = node; + } + + @Override + public String canRemove(ReadGraph graph, Map aux) + throws DatabaseException { + return "Removing scene-graph nodes from model browser is not supported."; + } + + @Override + public void remove(WriteGraph graph) throws DatabaseException { + + } + +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/gizmo/Gizmo.java b/org.simantics.g3d/src/org/simantics/g3d/gizmo/Gizmo.java new file mode 100644 index 00000000..6fc57200 --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/gizmo/Gizmo.java @@ -0,0 +1,17 @@ +package org.simantics.g3d.gizmo; + +import javax.vecmath.AxisAngle4d; +import javax.vecmath.Tuple3d; + +public interface Gizmo { + + + public boolean isPartOf(T pickedObject); + + + public void attach(Object renderingPart); + public void deattach(); + + public void setPosition(Tuple3d position); + public void setRotation(AxisAngle4d q); +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/math/EulerTools.java b/org.simantics.g3d/src/org/simantics/g3d/math/EulerTools.java new file mode 100644 index 00000000..4545ccb3 --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/math/EulerTools.java @@ -0,0 +1,394 @@ +package org.simantics.g3d.math; + +import javax.vecmath.AxisAngle4d; +import javax.vecmath.Quat4d; +import javax.vecmath.Vector3d; + +public class EulerTools { + + public enum Order { + XYX, XYZ, XZX, XZY, YXY, YXZ, YZX, YZY, ZXY, ZXZ, ZYX, ZYZ + }; + + public static Quat4d getQuatFromEuler(Order order, Vector3d a) { + return getQuatFromEuler(order, a.x, a.y, a.z); + } + + public static Quat4d getQuatFromEuler(Order order, double a1, double a2, double a3) { + Quat4d q1 = new Quat4d(); + Quat4d q2 = new Quat4d(); + Quat4d q3 = new Quat4d(); + switch (order) { + case XYX: + q1.set(new AxisAngle4d(1.0, 0.0, 0.0, a1)); + q2.set(new AxisAngle4d(0.0, 1.0, 0.0, a2)); + q3.set(new AxisAngle4d(1.0, 0.0, 0.0, a3)); + break; + case XYZ: + q1.set(new AxisAngle4d(1.0, 0.0, 0.0, a1)); + q2.set(new AxisAngle4d(0.0, 1.0, 0.0, a2)); + q3.set(new AxisAngle4d(0.0, 0.0, 1.0, a3)); + break; + case XZX: + q1.set(new AxisAngle4d(1.0, 0.0, 0.0, a1)); + q2.set(new AxisAngle4d(0.0, 0.0, 1.0, a2)); + q3.set(new AxisAngle4d(1.0, 0.0, 0.0, a3)); + break; + case XZY: + q1.set(new AxisAngle4d(1.0, 0.0, 0.0, a1)); + q2.set(new AxisAngle4d(0.0, 0.0, 1.0, a2)); + q3.set(new AxisAngle4d(0.0, 1.0, 0.0, a3)); + break; + case YXY: + q1.set(new AxisAngle4d(0.0, 1.0, 0.0, a1)); + q2.set(new AxisAngle4d(1.0, 0.0, 0.0, a2)); + q3.set(new AxisAngle4d(0.0, 1.0, 0.0, a3)); + break; + case YXZ: + q1.set(new AxisAngle4d(0.0, 1.0, 0.0, a1)); + q2.set(new AxisAngle4d(1.0, 0.0, 0.0, a2)); + q3.set(new AxisAngle4d(0.0, 0.0, 1.0, a3)); + break; + case YZX: + q1.set(new AxisAngle4d(0.0, 1.0, 0.0, a1)); + q2.set(new AxisAngle4d(0.0, 0.0, 1.0, a2)); + q3.set(new AxisAngle4d(1.0, 0.0, 0.0, a3)); + break; + case YZY: + q1.set(new AxisAngle4d(0.0, 1.0, 0.0, a1)); + q2.set(new AxisAngle4d(0.0, 0.0, 1.0, a2)); + q3.set(new AxisAngle4d(0.0, 1.0, 0.0, a3)); + break; + case ZXY: + q1.set(new AxisAngle4d(0.0, 0.0, 1.0, a1)); + q2.set(new AxisAngle4d(1.0, 0.0, 0.0, a2)); + q3.set(new AxisAngle4d(0.0, 1.0, 0.0, a3)); + break; + case ZXZ: + q1.set(new AxisAngle4d(0.0, 0.0, 1.0, a1)); + q2.set(new AxisAngle4d(1.0, 0.0, 0.0, a2)); + q3.set(new AxisAngle4d(0.0, 0.0, 1.0, a3)); + break; + case ZYX: + q1.set(new AxisAngle4d(0.0, 0.0, 1.0, a1)); + q2.set(new AxisAngle4d(0.0, 1.0, 0.0, a2)); + q3.set(new AxisAngle4d(1.0, 0.0, 0.0, a3)); + break; + case ZYZ: + q1.set(new AxisAngle4d(0.0, 0.0, 1.0, a1)); + q2.set(new AxisAngle4d(0.0, 1.0, 0.0, a2)); + q3.set(new AxisAngle4d(0.0, 0.0, 1.0, a3)); + break; + } + q1.mul(q2); + q1.mul(q3); + return q1; + } + + /** + * See http://noelhughes.net/uploads/quat_2_euler_paper_ver3.pdf + * @param order + * @param q + * @return + */ + public static Vector3d getEulerFromQuat(Order order, Quat4d q) { + Vector3d euler = new Vector3d(); + +// Vector3d v1 = new Vector3d(); +// Vector3d v2 = new Vector3d(); + Vector3d v3 = new Vector3d(); + Vector3d v3n = new Vector3d(); + + switch (order) { + case XYX: +// v1.x = 1.0; +// v2.y = 1.0; + v3.x = 1.0; + v3n.y = 1.0; + break; + case XYZ: +// v1.x = 1.0; +// v2.y = 1.0; + v3.z = 1.0; + v3n.x = 1.0; + break; + case XZX: +// v1.x = 1.0; +// v2.z = 1.0; + v3.x = 1.0; + v3n.y = 1.0; + break; + case XZY: +// v1.x = 1.0; +// v2.z = 1.0; + v3.y = 1.0; + v3n.z = 1.0; + break; + case YXY: +// v1.y = 1.0; +// v2.x = 1.0; + v3.y = 1.0; + v3n.z = 1.0; + break; + case YXZ: +// v1.y = 1.0; +// v2.x = 1.0; + v3.z = 1.0; + v3n.x = 1.0; + break; + case YZX: +// v1.y = 1.0; +// v2.z = 1.0; + v3.x = 1.0; + v3n.y = 1.0; + break; + case YZY: +// v1.y = 1.0; +// v2.z = 1.0; + v3.y = 1.0; + v3n.z = 1.0; + break; + case ZXY: +// v1.z = 1.0; +// v2.x = 1.0; + v3.y = 1.0; + v3n.z = 1.0; + break; + case ZXZ: +// v1.z = 1.0; +// v2.x = 1.0; + v3.z = 1.0; + v3n.x = 1.0; + break; + case ZYX: +// v1.z = 1.0; +// v2.y = 1.0; + v3.x = 1.0; + v3n.y = 1.0; + break; + case ZYZ: +// v1.z = 1.0; +// v2.y = 1.0; + v3.z = 1.0; + v3n.x = 1.0; + break; + } + Vector3d v3r = new Vector3d(); + MathTools.rotate(q, v3, v3r); + v3r.normalize(); + + switch (order) { + + case XZX: + euler.x = Math.atan2(v3r.z, v3r.y); + euler.y = Math.acos(v3r.x); + break; + case YXY: + euler.x = Math.atan2(v3r.x, v3r.z); + euler.y = Math.acos(v3r.y); + break; + case ZYZ: + euler.x = Math.atan2(v3r.y, v3r.x); + euler.y = Math.acos(v3r.z); + break; + + case XZY: + euler.x = Math.atan2(v3r.z, v3r.y); + euler.y = -Math.asin(v3r.x); + break; + case YXZ: + euler.x = Math.atan2(v3r.x, v3r.z); + euler.y = -Math.asin(v3r.y); + break; + case ZYX: + euler.x = Math.atan2(v3r.y, v3r.x); + euler.y = -Math.asin(v3r.z); + break; + + case XYX: + euler.x = Math.atan2(v3r.y, -v3r.z); + //euler.x = Math.atan2(v3r.y, -v3r.x); + euler.y = Math.acos(v3r.x); + break; + case YZY: + euler.x = Math.atan2(v3r.z, -v3r.x); + //euler.x = Math.atan2(v3r.z, -v3r.y); + euler.y = Math.acos(v3r.y); + break; + case ZXZ: + euler.x = Math.atan2(v3r.x, -v3r.y); + //euler.x = Math.atan2(v3r.x, -v3r.z); + euler.y = Math.acos(v3r.z); + break; + + case XYZ: + euler.x = Math.atan2(-v3r.y, v3r.z); + euler.y = Math.asin(v3r.x); + break; + case YZX: + euler.x = Math.atan2(-v3r.z, v3r.x); + euler.y = Math.asin(v3r.y); + break; + case ZXY: + euler.x = Math.atan2(-v3r.x, v3r.y); + euler.y = Math.asin(v3r.z); + break; + } + + Quat4d q1 = new Quat4d(); + q1.w = Math.cos(euler.x*0.5); + Quat4d q2 = new Quat4d(); + q2.w = Math.cos(euler.y*0.5); + + switch (order) { + case XYX: + case XYZ: + case XZX: + case XZY: + q1.x = Math.sin(euler.x*0.5); + break; + case YXY: + case YXZ: + case YZX: + case YZY: + q1.y = Math.sin(euler.x*0.5); + break; + case ZXY: + case ZXZ: + case ZYX: + case ZYZ: + q1.z = Math.sin(euler.x*0.5); + break; + } + + switch (order) { + case YXY: + case YXZ: + case ZXY: + case ZXZ: + q2.x = Math.sin(euler.y*0.5); + break; + case XYX: + case XYZ: + case ZYX: + case ZYZ: + q2.y = Math.sin(euler.y*0.5); + break; + case XZX: + case XZY: + case YZX: + case YZY: + q2.z = Math.sin(euler.y*0.5); + break; + } + + Quat4d q12 = new Quat4d(); + q12.mul(q1, q2); + + Vector3d v3n12 = new Vector3d(); + Vector3d v3ng = new Vector3d(); + MathTools.rotate(q12, v3n, v3n12); + MathTools.rotate(q, v3n, v3ng); + + double dot = v3n12.dot(v3ng); + dot = MathTools.clamp(-1.0, 1.0, dot); + euler.z = Math.abs(Math.acos(dot)); + Vector3d vc = new Vector3d(); + vc.cross(v3n12, v3ng); + euler.z *= Math.signum(vc.dot(v3r)); + + return euler; + } + + + public static void main(String args[]) { + + boolean all = false; + boolean allOrder = false; + if (all) { + testAll(); + } else if (allOrder) { + test(Order.YXZ); + } else { + //test(Order.ZXY,30,60,45); + //test(Order.YXZ,30,0,0); + //test(Order.YXZ,30,90,60); + test(Order.YXZ,300,240,360); + } + } + + private static void testAll() { + double start = 0.0; + double end = 90.0; + double step = 30.0; + for (double a1 = start; a1 <= end; a1+= step) { + double r1 = MathTools.degToRad(a1); + for (double a2 = start; a2 <= end; a2+= step) { + double r2 = MathTools.degToRad(a2); + for (double a3 = start; a3 <= end; a3+= step) { + double r3 = MathTools.degToRad(a3); + for (Order order : Order.values()) { + Quat4d q = EulerTools.getQuatFromEuler(order, r1, r2, r3); + Vector3d a = EulerTools.getEulerFromQuat(order, q); + Quat4d q2 = EulerTools.getQuatFromEuler(order, a.x,a.y,a.z); + a.x = MathTools.radToDeg(a.x); + a.y = MathTools.radToDeg(a.y); + a.z = MathTools.radToDeg(a.z); + System.out.println(toString(a1) +" " + toString(a2) + " " + toString(a3) + " " + order + "\t" + toString(a) + "\t" + toString(q) + "\t" + toString(q2)); + } + } + } + } + } + + private static void test(Order order) { + double start = 0.0; + double end = 360.0; + double step = 30.0; + for (double a1 = start; a1 <= end; a1+= step) { + double r1 = MathTools.degToRad(a1); + for (double a2 = start; a2 <= end; a2+= step) { + double r2 = MathTools.degToRad(a2); + for (double a3 = start; a3 <= end; a3+= step) { + double r3 = MathTools.degToRad(a3); + + Quat4d q = EulerTools.getQuatFromEuler(order, r1, r2, r3); + Vector3d a = EulerTools.getEulerFromQuat(order, q); + Quat4d q2 = EulerTools.getQuatFromEuler(order, a.x,a.y,a.z); + a.x = MathTools.radToDeg(a.x); + a.y = MathTools.radToDeg(a.y); + a.z = MathTools.radToDeg(a.z); + + System.out.println(toString(a1) +" " + toString(a2) + " " + toString(a3) + " " + order + "\t" + toString(a) + "\t" + toString(q) + "\t" + toString(q2)); + } + } + } + } + + private static String toString(double d) { + return String.format("%1$6.2f", d); + } + + private static String toString(Vector3d v) { + return "("+toString(v.x) +", "+ toString(v.y) + ", " + toString(v.z) +")"; + } + + private static String toString(Quat4d v) { + return "("+toString(v.x) +", "+ toString(v.y) + ", " + toString(v.z) + ", " + toString(v.w) +")"; + } + + private static void test(Order order, double deg1, double deg2, double deg3) { + double r1 = MathTools.degToRad(deg1); + double r2 = MathTools.degToRad(deg2); + double r3 = MathTools.degToRad(deg3); + + Quat4d q = EulerTools.getQuatFromEuler(order, r1, r2, r3); + Vector3d a = EulerTools.getEulerFromQuat(order, q); + Quat4d q2 = EulerTools.getQuatFromEuler(order, a.x,a.y,a.z); + a.x = MathTools.radToDeg(a.x); + a.y = MathTools.radToDeg(a.y); + a.z = MathTools.radToDeg(a.z); + System.out.println(toString(deg1) +" " + toString(deg2) + " " + toString(deg3) + " " + order + "\t" + toString(a) + "\t" + toString(q) + "\t" + toString(q2)); + + } +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/math/MathTools.java b/org.simantics.g3d/src/org/simantics/g3d/math/MathTools.java new file mode 100644 index 00000000..0bfac8f1 --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/math/MathTools.java @@ -0,0 +1,849 @@ +package org.simantics.g3d.math; + +import javax.vecmath.AxisAngle4d; +import javax.vecmath.Matrix3d; +import javax.vecmath.Matrix4d; +import javax.vecmath.Quat4d; +import javax.vecmath.Tuple3d; +import javax.vecmath.Tuple4d; +import javax.vecmath.Vector2f; +import javax.vecmath.Vector3d; + +import org.simantics.g3d.math.EulerTools.Order; + + +/** + * Some useful geometry related math functions. Beware, methods may modify their input parameters! + * + * @author Marko Luukkainen + * + */ +public class MathTools { + + public static double NEAR_ZERO = 0.0000001; + public static double NEAR_HALF = 0.4999999; + + public static final Vector3d Z_AXIS = new Vector3d(0.0,0.0,1.0); + public static final Vector3d Y_AXIS = new Vector3d(0.0,1.0,0.0); + public static final Vector3d X_AXIS = new Vector3d(1.0,0.0,0.0); + public static final Vector3d ORIGIN = new Vector3d(0.0,0.0,0.0); + + final static double EPS = 1.0e-12; + + + public static boolean equals(double d1, double d2) { + return Math.abs(d1-d2) < EPS; + } + + public static boolean equals(Tuple3d p1, Tuple3d p2) { + return distanceSquared(p1, p2) < NEAR_ZERO; + } + + public static boolean equals(Tuple4d p1, Tuple4d p2) { + return distanceSquared(p1, p2) < NEAR_ZERO; + } + + public static double distance(Tuple3d p1, Tuple3d p2) { + double dx, dy, dz; + + dx = p2.x - p1.x; + dy = p2.y - p1.y; + dz = p2.z - p1.z; + return Math.sqrt(dx*dx+dy*dy+dz*dz); + } + + public static double distance(Tuple4d p1, Tuple4d p2) { + double dx, dy, dz, dw; + + dx = p2.x - p1.x; + dy = p2.y - p1.y; + dz = p2.z - p1.z; + dw = p2.w - p1.w; + return Math.sqrt(dx*dx+dy*dy+dz*dz+dw*dw); + } + + public static double distanceSquared(Tuple3d p1, Tuple3d p2) { + double dx, dy, dz; + + dx = p2.x - p1.x; + dy = p2.y - p1.y; + dz = p2.z - p1.z; + return dx*dx+dy*dy+dz*dz; + } + + public static double distanceSquared(Tuple4d p1, Tuple4d p2) { + double dx, dy, dz, dw; + + dx = p2.x - p1.x; + dy = p2.y - p1.y; + dz = p2.z - p1.z; + dw = p2.w - p1.w; + return dx*dx+dy*dy+dz*dz+dw*dw; + } + + public static boolean isValid(Tuple3d t) { + return !(Double.isInfinite(t.x) || Double.isNaN(t.x) || + Double.isInfinite(t.y) || Double.isNaN(t.y) || + Double.isInfinite(t.z) || Double.isNaN(t.z)); + } + + public static Vector3d closestPointOnEdge(Vector3d point, Vector3d edgePoint1, Vector3d edgePoint2) { + point.sub(edgePoint1); + Vector3d v = new Vector3d(edgePoint2); + v.sub(edgePoint1); + double t = v.dot(point); + t /= v.lengthSquared(); + if (t <= 0.0f) + return edgePoint1; + if (t >= 1.0f) + return edgePoint2; + v.scale(t); + v.add(edgePoint1); + return v; + } + + public static Vector3d closestPointOnStraight(Tuple3d point, Tuple3d straightPoint, Vector3d straightDir) { + Vector3d v = new Vector3d(point); + v.sub(straightPoint); + double t = straightDir.dot(v); + t /= straightDir.lengthSquared(); + v.set(straightDir); + v.scale(t); + v.add(straightPoint); + return v; + } + + public static Vector3d closestPointOnStraight(Tuple3d point, Tuple3d straightPoint, Vector3d straightDir, double u[]) { + Vector3d v = new Vector3d(point); + v.sub(straightPoint); + u[0] = straightDir.dot(v); + u[0] /= straightDir.lengthSquared(); + v.set(straightDir); + v.scale(u[0]); + v.add(straightPoint); + return v; + } + + public static double distanceFromPlane(Vector3d point, Vector3d planeNormal, Tuple3d planePoint) { + point.sub(planePoint); + + return planeNormal.dot(point); + } + + public static double distanceFromPlane(Vector3d point, Vector3d planeNormal, float d) { + return (planeNormal.dot(point) + d); + } + + public static boolean intersectStraightPlane(Tuple3d linePoint, Vector3d lineDir, Tuple3d planePoint, Vector3d planeNormal, Tuple3d intersectPoint) { + intersectPoint.set(planePoint); + intersectPoint.sub(linePoint); + double u = planeNormal.dot(new Vector3d(intersectPoint)); + double v = planeNormal.dot(lineDir); + if (Math.abs(v) < NEAR_ZERO) + return false; + u /= v; + intersectPoint.set(lineDir); + intersectPoint.scale(u); + intersectPoint.add(linePoint); + return true; + } + + public static boolean intersectStraightPlane(Tuple3d linePoint, Vector3d lineDir, Tuple3d planePoint, Vector3d planeNormal, Vector3d intersectPoint, double[] u) { + intersectPoint.set(planePoint); + intersectPoint.sub(linePoint); + u[0] = planeNormal.dot(intersectPoint); + double v = planeNormal.dot(lineDir); + if (Math.abs(v) < NEAR_ZERO) + return false; + u[0] /= v; + intersectPoint.set(lineDir); + intersectPoint.scale(u[0]); + intersectPoint.add(linePoint); + return true; + } + + public static boolean intersectLineLine(Tuple3d l1_start,Tuple3d l1_end,Tuple3d l2_start,Tuple3d l2_end,Tuple3d l1_pos, Tuple3d l2_pos) { + Vector3d p13 = new Vector3d(); + Vector3d p43 = new Vector3d(); + Vector3d p21 = new Vector3d(); + double d1343,d4321,d1321,d4343,d2121; + double numer,denom; + p13.sub(l1_start, l2_start); + p43.sub(l2_end,l2_start); + if (Math.abs(p43.x) < NEAR_ZERO && Math.abs(p43.y) < NEAR_ZERO && Math.abs(p43.z) < NEAR_ZERO) + return false; + p21.sub(l1_end,l1_start); + if (Math.abs(p21.x) < NEAR_ZERO && Math.abs(p21.y) < NEAR_ZERO && Math.abs(p21.z) < NEAR_ZERO) + return false; + + d1343 = p13.dot(p43); + d4321 = p43.dot(p21); + d1321 = p13.dot(p21); + d4343 = p43.lengthSquared(); + d2121 = p21.lengthSquared(); + + denom = d2121 * d4343 - d4321 * d4321; + if (Math.abs(denom) < NEAR_ZERO) + return false; + numer = d1343 * d4321 - d1321 * d4343; + + double mua = numer / denom; + double mub = (d1343 + d4321 * mua) / d4343; + + l1_pos.x = l1_start.x + mua * p21.x; + l1_pos.y = l1_start.y + mua * p21.y; + l1_pos.z = l1_start.z + mua * p21.z; + l2_pos.x = l2_start.x + mub * p43.x; + l2_pos.y = l2_start.y + mub * p43.y; + l2_pos.z = l2_start.z + mub * p43.z; + + return true; + } + + public static boolean intersectStraightStraight(Tuple3d p1,Vector3d p21,Tuple3d p3,Vector3d p43,Tuple3d pa,Tuple3d pb) { + Vector3d p13 = new Vector3d(); + + double d1343,d4321,d1321,d4343,d2121; + double numer,denom; + + p13.sub(p1, p3); + if (Math.abs(p43.x) < NEAR_ZERO && Math.abs(p43.y) < NEAR_ZERO && Math.abs(p43.z) < NEAR_ZERO) + return false; + if (Math.abs(p21.x) < NEAR_ZERO && Math.abs(p21.y) < NEAR_ZERO && Math.abs(p21.z) < NEAR_ZERO) + return false; + + d1343 = p13.dot(p43); + d4321 = p43.dot(p21); + d1321 = p13.dot(p21); + d4343 = p43.lengthSquared(); + d2121 = p21.lengthSquared(); + + denom = d2121 * d4343 - d4321 * d4321; + if (Math.abs(denom) < NEAR_ZERO) + return false; + numer = d1343 * d4321 - d1321 * d4343; + + double mua = numer / denom; + double mub = (d1343 + d4321 * mua) / d4343; + + pa.x = p1.x + mua * p21.x; + pa.y = p1.y + mua * p21.y; + pa.z = p1.z + mua * p21.z; + pb.x = p3.x + mub * p43.x; + pb.y = p3.y + mub * p43.y; + pb.z = p3.z + mub * p43.z; + + return true; + } + + /** + * Calculate the line segment PaPb that is the shortest route between + * two lines P1P2 and P3P4. Calculate also the values of mua and mub where + * Pa = P1 + mua (P2 - P1) + * Pb = P3 + mub (P4 - P3) + * @param p1 + * @param p21 + * @param p3 + * @param p43 + * @param pa + * @param pb + * @param mu + * @return + */ + public static boolean intersectStraightStraight(Tuple3d p1,Vector3d p21,Tuple3d p3,Vector3d p43,Tuple3d pa,Tuple3d pb, double mu[]) { + Vector3d p13 = new Vector3d(); + + double d1343,d4321,d1321,d4343,d2121; + double numer,denom; + double EPS = 0.001; + p13.sub(p1, p3); + if (Math.abs(p43.x) < EPS && Math.abs(p43.y) < EPS && Math.abs(p43.z) < EPS) + return false; + if (Math.abs(p21.x) < EPS && Math.abs(p21.y) < EPS && Math.abs(p21.z) < EPS) + return false; + + d1343 = p13.dot(p43); + d4321 = p43.dot(p21); + d1321 = p13.dot(p21); + d4343 = p43.lengthSquared(); + d2121 = p21.lengthSquared(); + + denom = d2121 * d4343 - d4321 * d4321; + if (Math.abs(denom) < EPS) + return false; + numer = d1343 * d4321 - d1321 * d4343; + + mu[0] = numer / denom; + mu[1] = (d1343 + d4321 * mu[0]) / d4343; + + pa.x = p1.x + mu[0] * p21.x; + pa.y = p1.y + mu[0] * p21.y; + pa.z = p1.z + mu[0] * p21.z; + pb.x = p3.x + mu[1] * p43.x; + pb.y = p3.y + mu[1] * p43.y; + pb.z = p3.z + mu[1] * p43.z; + + return true; + } + + + + public static void rotate(Quat4d q, Tuple3d in, Tuple3d out) { + // p' = q * p * q' + double tw = - q.x*in.x - q.y*in.y - q.z*in.z; + double tx = q.w*in.x + q.y*in.z - q.z*in.y; + double ty = q.w*in.y - q.x*in.z + q.z*in.x; + double tz = q.w*in.z + q.x*in.y - q.y*in.x ; + + //temp * q' -> x = -x, y = -y z = -z + //out.w = tw*q.w + tx*q.x + ty*q.y + tz*q.z; + out.x = -tw*q.x + tx*q.w - ty*q.z + tz*q.y; + out.y = -tw*q.y + tx*q.z + ty*q.w - tz*q.x; + out.z = -tw*q.z - tx*q.y + ty*q.x + tz*q.w; + } + + public static void getMatrix(Quat4d quat, Matrix3d m) { + m.m00 = 1.0f - 2.0 * (quat.y * quat.y + quat.z * quat.z); + m.m01 = 2.0 * (quat.x * quat.y + quat.w * quat.z); + m.m02 = 2.0 * (quat.x * quat.z - quat.w * quat.y); + m.m10 = 2.0 * (quat.x * quat.y - quat.w * quat.z); + m.m11 = 1.0 - 2.0f * (quat.x * quat.x + quat.z * quat.z); + m.m12 = 2.0 * (quat.y * quat.z + quat.w * quat.x); + m.m20 = 2.0 * (quat.x * quat.z + quat.w * quat.y); + m.m21 = 2.0 * (quat.y * quat.z - quat.w * quat.x); + m.m22 = 1.0 - 2.0f * (quat.x * quat.x + quat.y * quat.y); + + } + + + private static double q[] = new double[3]; + private static int nxt[] = { 1, 2, 0 }; + /** + * Converts Matrix to Quaternion + * + * Note: non-thread safe. + * + * @param mat + * @param quat + */ + public static void getQuat(Matrix3d mat, Quat4d quat) { + double tr = mat.m00 + mat.m11 + mat.m22; + if (tr > 0.0) { + double s = Math.sqrt(tr + 1.0); + quat.w = 0.5 * s; + s = 0.5 / s; + quat.x = (mat.m21 - mat.m12) * s; + quat.y = (mat.m02 - mat.m20) * s; + quat.z = (mat.m10 - mat.m01) * s; + } else { + int i = 0, j, k; + if (mat.m11 > mat.m00) + i = 1; + if (mat.m22 > mat.getElement(i, i)) + i = 2; + + + j = nxt[i]; + k = nxt[j]; + + double s = Math.sqrt((mat.getElement(i, i) - (mat.getElement(j, j) + mat.getElement(k, k))) + 1.0); + + q[i] = s * 0.5; + + if (Math.abs(s) > 0.001) + s = 0.5 / s; + + quat.w = (mat.getElement(k, j) - mat.getElement(j, k)) * s; + q[j] = (mat.getElement(j, i) + mat.getElement(i, j)) * s; + q[k] = (mat.getElement(k, i) + mat.getElement(i, k)) * s; + + quat.x = q[0]; + quat.y = q[1]; + quat.z = q[2]; + } + } + + public static Quat4d getQuat(Matrix3d mat) { + Quat4d q = new Quat4d(); + getQuat(mat, q); + return q; + } + + public static AxisAngle4d getFromPseudoEuler(Vector3d euler) { + AxisAngle4d aa = new AxisAngle4d(); + aa.angle = euler.length(); + Vector3d normal = new Vector3d(euler); + if (aa.angle > NEAR_ZERO) { + normal.normalize(); + aa.x = normal.x; + aa.y = normal.y; + aa.z = normal.z; + } else { + aa.x = 1.0; + aa.y = 0.0; + aa.z = 0.0; + } + + return aa; + } + + public static Vector3d getPseudoEuler(AxisAngle4d aa) { + Vector3d euler = new Vector3d(aa.x,aa.y,aa.z); + euler.scale(aa.angle); + return euler; + } + + + public static void getQuat(Vector3d euler, Quat4d quat) { + Quat4d q = EulerTools.getQuatFromEuler(Order.YXZ, euler.y,euler.x,euler.z); + quat.set(q); + // http://en.wikipedia.org/wiki/Rotation_formalisms_in_three_dimensions#Conversion_formulae_between_formalisms + // Using the x-convention, the 3-1-3 Euler angles phi, theta and psi (around the Z, X and again the Z-axis) +// quat.x = -Math.cos((euler.x - euler.z)*0.5)*Math.sin(euler.y*0.5); +// quat.y = -Math.sin((euler.x - euler.z)*0.5)*Math.sin(euler.y*0.5); +// quat.z = -Math.sin((euler.x + euler.z)*0.5)*Math.cos(euler.y*0.5); +// quat.w = Math.sin((euler.x + euler.z)*0.5)*Math.cos(euler.y*0.5); + + // http://www.euclideanspace.com/maths/geometry/rotations/conversions/eulerToQuaternion/index.htm + // Y, Z, X order +// double c1 = Math.cos(euler.y*0.5); +// double s1 = Math.sin(euler.y*0.5); +// double c2 = Math.cos(euler.z*0.5); +// double s2 = Math.sin(euler.z*0.5); +// double c3 = Math.cos(euler.x*0.5); +// double s3 = Math.sin(euler.x*0.5); +// double c1c2 = c1*c2; +// double s1s2 = s1*s2; +// quat.w =c1c2*c3 - s1s2*s3; +// quat.x =c1c2*s3 + s1s2*c3; +// quat.y =s1*c2*c3 + c1*s2*s3; +// quat.z =c1*s2*c3 - s1*c2*s3; + +// Quat4d q2 = EulerTools.getQuatFromEuler(Order.YZX, euler.y,euler.z,euler.x); +// System.out.println("Q " + quat + " Q2 " + q2); +// double c1 = Math.cos(euler.y); +// double s1 = Math.sin(euler.y); +// double c2 = Math.cos(euler.z); +// double s2 = Math.sin(euler.z); +// double c3 = Math.cos(euler.x); +// double s3 = Math.sin(euler.x); +// quat.w = Math.sqrt(1.0 + c1 * c2 + c1*c3 - s1 * s2 * s3 + c2*c3) / 2.0; +// double w4 = (4.0 * quat.w); +// quat.x = (c2 * s3 + c1 * s3 + s1 * s2 * c3) / w4 ; +// quat.y = (s1 * c2 + s1 * c3 + c1 * s2 * s3) / w4 ; +// quat.z = (-s1 * s3 + c1 * s2 * c3 +s2) / w4 ; + } + + + + + public static void getEuler(Quat4d quat,Vector3d euler) { + Vector3d e = EulerTools.getEulerFromQuat(Order.YXZ, quat); + euler.x = e.y; + euler.y = e.x; + euler.z = e.z; + + // http://en.wikipedia.org/wiki/Rotation_formalisms_in_three_dimensions#Conversion_formulae_between_formalisms +// euler.x = Math.atan2(quat.x * quat.z + quat.y* quat.w, quat.y*quat.z - quat.x * quat.w); +// euler.y = Math.acos(-square(quat.x) - square(quat.y) + square(quat.z) + square(quat.w)); +// euler.z = -Math.atan2(quat.x * quat.z - quat.y* quat.w, quat.y*quat.z + quat.x * quat.w); + + // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToEuler/index.htm + // Y, Z, X order +// double test = quat.x * quat.y + quat.z * quat.w; +// if (test > NEAR_HALF) { +// euler.y = 2.0 * Math.atan2(quat.x,quat.w); +// euler.z = Math.PI * 0.5; +// euler.x = 0.0; +// } else if (test < -NEAR_HALF) { +// euler.y = -2.0 * Math.atan2(quat.x,quat.w); +// euler.z = -Math.PI * 0.5; +// euler.x = 0.0; +// } else { +// double sqx = square(quat.x); +// double sqy = square(quat.y); +// double sqz = square(quat.z); +// euler.y = Math.atan2(2.0*(quat.y*quat.w-quat.x*quat.z), 1.0 - 2.0*(sqy-sqz)); +// euler.z = Math.asin(2.0*test); +// euler.x = Math.atan2(2.0*(quat.x*quat.w-quat.y*quat.z), 1.0 - 2.0*(sqx-sqz)); +// System.out.println(euler + " " + EulerTools.getEulerFromQuat(Order.YXZ, quat) + " " + quat); +// } +// double sqw = quat.w*quat.w; +// double sqx = quat.x*quat.x; +// double sqy = quat.y*quat.y; +// double sqz = quat.z*quat.z; +// double unit = sqx + sqy + sqz + sqw; // if normalised is one, otherwise is correction factor +// double test = quat.x*quat.y + quat.z*quat.w; +// if (test > 0.499*unit) { // singularity at north pole +// euler.y = 2 * Math.atan2(quat.x,quat.w); +// euler.z = Math.PI/2; +// euler.x = 0; +// return; +// } +// if (test < -0.499*unit) { // singularity at south pole +// euler.y = -2 * Math.atan2(quat.x,quat.w); +// euler.z = -Math.PI/2; +// euler.x = 0; +// return; +// } +// euler.y = Math.atan2(2*quat.y*quat.w-2*quat.x*quat.z , sqx - sqy - sqz + sqw); +// euler.z = Math.asin(2*test/unit); +// euler.x = Math.atan2(2*quat.x*quat.w-2*quat.y*quat.z , -sqx + sqy - sqz + sqw); + } + + public static Quat4d getQuat(Vector3d euler) { + Quat4d q = new Quat4d(); + getQuat(euler,q); + return q; + } + + + public static Vector3d getEuler(Quat4d quat) { + Vector3d v = new Vector3d(); + getEuler(quat, v); + return v; + } + + public static Quat4d getQuat(AxisAngle4d aa) { + Quat4d q = new Quat4d(); + getQuat(aa, q); + return q; + } + + public static AxisAngle4d getAxisAngle(Quat4d q) { + AxisAngle4d aa = new AxisAngle4d(); + aa.set(q); + return aa; + } + + public static Quat4d getIdentityQuat() { + return new Quat4d(0, 0, 0, 1); + } + + public static void getQuat(AxisAngle4d aa, Quat4d q) { + double mag,amag; + // Quat = cos(theta/2) + sin(theta/2)(roation_axis) + + amag = Math.sqrt( aa.x*aa.x + aa.y*aa.y + aa.z*aa.z); + if( amag < NEAR_ZERO ) { + q.w = 1.0; + q.x = 0.0; + q.y = 0.0; + q.z = 0.0; + } else { + amag = 1.0/amag; + double a2 = aa.angle * 0.5; + mag = Math.sin(a2); + q.w = Math.cos(a2); + q.x = aa.x*amag*mag; + q.y = aa.y*amag*mag; + q.z = aa.z*amag*mag; + } + } + + + /* + * Cohen-Sutherland + */ + + private static final int IN = 0; + private static final int LEFT = 1; + private static final int RIGHT = 2; + private static final int BOTTOM = 4; + private static final int TOP = 8; + + + private static int bitcode(Vector2f p1, Vector2f min, Vector2f max) { + int code = IN; + if (p1.x < min.x) + code |= LEFT; + else if (p1.x > max.x) + code |= RIGHT; + if (p1.y < min.y) + code |= BOTTOM; + else if (p1.y > max.y) + code |= TOP; + return code; + } + + public static boolean clipLineRectangle(Vector2f p1,Vector2f p2, Vector2f min, Vector2f max, Vector2f r1, Vector2f r2) { + while (true) { + int o1 = bitcode(p1, min, max); + int o2 = bitcode(p2, min, max); + int and = o1 & o2; + int or = o1 | o2; + if (and != IN) { + return false; + } + if (or == IN) { + r1.set(p1); + r2.set(p2); + return true; + } + if (o1 == IN) { + Vector2f t = p1; + p1 = p2; + p2 = t; + int t2 = o1; + o1 = o2; + o2 = t2; + } + if ((o1 & TOP) != IN) { + float t = (max.y - p1.y) / (p2.y - p1.y); + p1.x += t * (p2.x - p1.x); + p1.y = max.y; + } else if ((o1 & BOTTOM) != IN) { + float t = (min.y - p1.y) / (p2.y - p1.y); + p1.x += t * (p2.x - p1.x); + p1.y = min.y; + } else if ((o1 & LEFT) != IN) { + float t = (min.x - p1.x) / (p2.x - p1.x); + p1.y += t * (p2.y - p1.y); + p1.x = min.x; + } else if ((o1 & RIGHT) != IN) { + float t = (max.x - p1.x) / (p2.x - p1.x); + p1.y += t * (p2.y - p1.y); + p1.x = max.x; + } else { + throw new RuntimeException("Error in clipping code"); + } + } + + } + + public static double square(double d) { + return d * d; + } + + + public static void multiplyOrientation(AxisAngle4d aa, AxisAngle4d rot) { + Quat4d q1 = new Quat4d(); + getQuat(aa, q1); + Quat4d q2 = new Quat4d(); + getQuat(rot, q2); + q2.mul(q1); + rot.set(q2); + } + + public static double radToDeg(double rad) { + return (rad / Math.PI) * 180.0; + } + + public static double degToRad(double deg) { + return (deg / 180.0) * Math.PI; + } + + public static double clamp(double min, double max,double v) { + if (v < min) + return min; + if (v > max) + return max; + return v; + } + + public static AxisAngle4d createRotation(Vector3d original, Vector3d rotated) { + AxisAngle4d result = new AxisAngle4d(); + if (createRotation(original, rotated, result)) + return result; + return null; + } + + + public static void setIdentity(Quat4d q) { + q.w = 1.0; + q.x = 0.0; + q.y = 0.0; + q.z = 0.0; + } + + public static void setIdentity(AxisAngle4d aa) { + aa.angle = 0.0; + aa.x = 0.0; + aa.y = 1.0; + aa.z = 0.0; + } + + public static void set(Matrix3d mat, double m00, double m01, double m02, + double m10, double m11, double m12, double m20, double m21, + double m22) { + mat.m00 = m00; + mat.m01 = m01; + mat.m02 = m02; + + mat.m10 = m10; + mat.m11 = m11; + mat.m12 = m12; + + mat.m20 = m20; + mat.m21 = m21; + mat.m22 = m22; + } + + public static void set(Matrix4d mat, double[] v) { + mat.m00 = v[0]; + mat.m01 = v[1]; + mat.m02 = v[2]; + mat.m03 = v[3]; + + mat.m10 = v[4]; + mat.m11 = v[5]; + mat.m12 = v[6]; + mat.m13 = v[7]; + + mat.m20 = v[8]; + mat.m21 = v[9]; + mat.m22 = v[10]; + mat.m23 = v[11]; + + mat.m30 = v[12]; + mat.m31 = v[13]; + mat.m32 = v[14]; + mat.m33 = v[15]; + + } + + public static boolean createRotation(Vector3d original, Vector3d rotated, AxisAngle4d result) { + + if (rotated.lengthSquared() > 0.01) + rotated.normalize(); + else + return false; + double d = original.dot(rotated); + if (d > 0.9999) { + // original and rotated are parallel, pointing at the same direction + result.angle = 0.0; + result.x = 0.0; + result.y = 1.0; + result.z = 0.0; + } else if (d < -0.9999) { + // original and rotated are parallel, pointing at the opposite direction + Vector3d a = Z_AXIS; + if (Math.abs(a.dot(original)) > 0.8 ) + a = Y_AXIS; + result.set(a, Math.PI); + } else { + double angle = original.angle(rotated); + Vector3d axis = new Vector3d(); + axis.cross(original, rotated); + result.set(axis,angle); + } + return true; + } + + public static boolean createRotation(Vector3d original, Vector3d rotated, Quat4d result) { + + if (rotated.lengthSquared() > 0.01) + rotated.normalize(); + else + return false; + double d = original.dot(rotated); + if (d > 0.9999) { + // original and rotated are parallel, pointing at the same direction + result.w = 1.0; + result.x = 0.0; + result.y = 0.0; + result.z = 0.0; + } else if (d < -0.9999) { + // original and rotated are parallel, pointing at the opposite direction + Vector3d a = Z_AXIS; + if (Math.abs(a.dot(original)) > 0.8 ) + a = Y_AXIS; + getQuat(a, Math.PI, result); + + } else { + double angle = original.angle(rotated); + Vector3d axis = new Vector3d(); + axis.cross(original, rotated); + getQuat(axis, angle, result); + } + return true; + } + + public static void getQuat(Vector3d axis, double angle, Quat4d q) + { + double mag,amag; + // Quat = cos(theta/2) + sin(theta/2)(roation_axis) + + amag = Math.sqrt( axis.x*axis.x + axis.y*axis.y + axis.z*axis.z); + if( amag < EPS ) { + q.w = 1.0; + q.x = 0.0; + q.y = 0.0; + q.z = 0.0; + } else { + amag = 1.0/amag; + double a2 = angle*0.5; + mag = Math.sin(a2); + q.w = Math.cos(a2); + q.x = axis.x*amag*mag; + q.y = axis.y*amag*mag; + q.z = axis.z*amag*mag; + } + + } + + /** + * Linear interpolation of quaternions. Result IS set to q1. + * @param q1 + * @param q2 + * @param alpha + */ + public static void lip(Quat4d q1, Quat4d q2, double alpha) { + double s1 = 1.0 - alpha; + double s2 = alpha; + q1.scale(s1); + mad(q1,q2,s2); + q1.normalize(); + } + + public static double dot(Quat4d q1, Quat4d q2) { + return q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w; + } + + public static void mad(Tuple3d q1, Tuple3d q2, double s2) { + q1.x += q2.x * s2; + q1.y += q2.y * s2; + q1.z += q2.z * s2; + } + + public static void mad(Quat4d q1, Quat4d q2, double s2) { + q1.x += q2.x * s2; + q1.y += q2.y * s2; + q1.z += q2.z * s2; + q1.w += q2.w * s2; + } + + /** + * Slerp + * + * Sets results to q1. Modifies q2. + * + * @param q1 + * @param q2 + * @param alpha + */ + public static void sip(Quat4d q1, Quat4d q2, double alpha) { + double cosom = dot(q1,q2); + if (cosom < 0.0) { + cosom = -cosom; + q2.negate(); + } + + if (cosom > 0.9999) { + q2.sub(q1); + q2.scale(alpha); + q1.add(q2); + q1.normalize(); + return; + } + double theta_0 = Math.acos(cosom); + double theta = theta_0 * alpha; + Quat4d t = new Quat4d(q1); + t.scale(-cosom); + t.add(q2); + t.normalize(); + t.scale(Math.sin(theta)); + q1.scale(Math.cos(theta)); + q1.add(t); + } +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/math/Ray.java b/org.simantics.g3d/src/org/simantics/g3d/math/Ray.java new file mode 100644 index 00000000..10d8f4ab --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/math/Ray.java @@ -0,0 +1,15 @@ +package org.simantics.g3d.math; + +import javax.vecmath.Point3d; +import javax.vecmath.Vector3d; + +public class Ray { + public Point3d pos; + public Vector3d dir; + + public Ray(Point3d pos, Vector3d dir) { + this.pos = pos; + this.dir = dir; + } + +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/HasCollectionAdder.java b/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/HasCollectionAdder.java new file mode 100644 index 00000000..36460822 --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/HasCollectionAdder.java @@ -0,0 +1,13 @@ +package org.simantics.g3d.objmap.annotations; + +import java.lang.annotation.Annotation; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.ANNOTATION_TYPE) +public @interface HasCollectionAdder { + Class value(); +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/HasCollectionRemover.java b/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/HasCollectionRemover.java new file mode 100644 index 00000000..1e66907c --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/HasCollectionRemover.java @@ -0,0 +1,13 @@ +package org.simantics.g3d.objmap.annotations; + +import java.lang.annotation.Annotation; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.ANNOTATION_TYPE) +public @interface HasCollectionRemover { + Class value(); +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/HasCollectionRuleFactory.java b/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/HasCollectionRuleFactory.java new file mode 100644 index 00000000..9943ee8b --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/HasCollectionRuleFactory.java @@ -0,0 +1,14 @@ +package org.simantics.g3d.objmap.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.simantics.g3d.objmap.rules.factory.ICollectionRuleFactory; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.ANNOTATION_TYPE) +public @interface HasCollectionRuleFactory { + Class value(); +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/HasGetSetRuleFactory.java b/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/HasGetSetRuleFactory.java new file mode 100644 index 00000000..fa38fad2 --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/HasGetSetRuleFactory.java @@ -0,0 +1,14 @@ +package org.simantics.g3d.objmap.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.simantics.g3d.objmap.rules.factory.IGetSetRuleFactory; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.ANNOTATION_TYPE) +public @interface HasGetSetRuleFactory { + Class value(); +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/HasSetter.java b/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/HasSetter.java new file mode 100644 index 00000000..2967cc75 --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/HasSetter.java @@ -0,0 +1,13 @@ +package org.simantics.g3d.objmap.annotations; + +import java.lang.annotation.Annotation; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.ANNOTATION_TYPE) +public @interface HasSetter { + Class value(); +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/RelatedElementsAdd.java b/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/RelatedElementsAdd.java new file mode 100644 index 00000000..b796aead --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/RelatedElementsAdd.java @@ -0,0 +1,12 @@ +package org.simantics.g3d.objmap.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface RelatedElementsAdd { + String value(); +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/RelatedElementsGet.java b/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/RelatedElementsGet.java new file mode 100644 index 00000000..eb33e0d9 --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/RelatedElementsGet.java @@ -0,0 +1,18 @@ +package org.simantics.g3d.objmap.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.simantics.g3d.objmap.annotations.factories.RelatedElementsRuleFactory; + + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +@HasCollectionRuleFactory(RelatedElementsRuleFactory.class) +@HasCollectionAdder(RelatedElementsAdd.class) +@HasCollectionRemover(RelatedElementsRem.class) +public @interface RelatedElementsGet { + String value(); +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/RelatedElementsRem.java b/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/RelatedElementsRem.java new file mode 100644 index 00000000..921ddaf5 --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/RelatedElementsRem.java @@ -0,0 +1,13 @@ +package org.simantics.g3d.objmap.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface RelatedElementsRem { + String value(); +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/RelatedGetObj.java b/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/RelatedGetObj.java new file mode 100644 index 00000000..0b1c61da --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/RelatedGetObj.java @@ -0,0 +1,17 @@ +package org.simantics.g3d.objmap.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.simantics.g3d.objmap.annotations.factories.RelatedGetSetObjRuleFactory; + + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +@HasGetSetRuleFactory(RelatedGetSetObjRuleFactory.class) +@HasSetter(RelatedSetObj.class) +public @interface RelatedGetObj { + String value(); +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/RelatedGetValue.java b/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/RelatedGetValue.java new file mode 100644 index 00000000..1f39513e --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/RelatedGetValue.java @@ -0,0 +1,20 @@ +package org.simantics.g3d.objmap.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.simantics.g3d.objmap.annotations.factories.RelatedGetSetValueRuleFactory; +import org.simantics.objmap.rules.adapters.IdentityAdapter; +import org.simantics.objmap.rules.adapters.ValueAdapter; + + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +@HasGetSetRuleFactory(RelatedGetSetValueRuleFactory.class) +@HasSetter(RelatedSetValue.class) +public @interface RelatedGetValue { + String value(); + Class adapter() default IdentityAdapter.class; +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/RelatedSetObj.java b/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/RelatedSetObj.java new file mode 100644 index 00000000..440985b2 --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/RelatedSetObj.java @@ -0,0 +1,13 @@ +package org.simantics.g3d.objmap.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface RelatedSetObj { + String value(); +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/RelatedSetValue.java b/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/RelatedSetValue.java new file mode 100644 index 00000000..e1520187 --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/RelatedSetValue.java @@ -0,0 +1,13 @@ +package org.simantics.g3d.objmap.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface RelatedSetValue { + String value(); +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/factories/RelatedElementsRuleFactory.java b/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/factories/RelatedElementsRuleFactory.java new file mode 100644 index 00000000..1f535add --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/factories/RelatedElementsRuleFactory.java @@ -0,0 +1,42 @@ +package org.simantics.g3d.objmap.annotations.factories; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; + +import org.simantics.db.ReadGraph; +import org.simantics.db.exception.DatabaseException; +import org.simantics.g3d.objmap.annotations.RelatedElementsAdd; +import org.simantics.g3d.objmap.annotations.RelatedElementsGet; +import org.simantics.g3d.objmap.annotations.RelatedElementsRem; +import org.simantics.g3d.objmap.rules.factory.ICollectionRuleFactory; +import org.simantics.g3d.objmap.rules.range.CollectionAccessor; +import org.simantics.objmap.IMappingRule; +import org.simantics.objmap.rules.MappedElementsRule; +import org.simantics.objmap.rules.domain.RelatedObjectsAccessor; + +public class RelatedElementsRuleFactory implements ICollectionRuleFactory { + + @Override + public IMappingRule create(ReadGraph g, Annotation annotation, + Method getter, Method adder, Method remover) + throws DatabaseException { + RelatedElementsGet getterAnn = (RelatedElementsGet)annotation; + return new MappedElementsRule(new RelatedObjectsAccessor(g.getResource(getterAnn.value()),true), + new CollectionAccessor(getter, adder, remover)); + } + + @Override + public boolean isAdder(Annotation getterAnnotation, Annotation annotation) { + RelatedElementsGet getterAnn = (RelatedElementsGet)getterAnnotation; + RelatedElementsAdd adderAnn = (RelatedElementsAdd)annotation; + return getterAnn.value().equals(adderAnn.value()); + } + + @Override + public boolean isRemover(Annotation getterAnnotation, Annotation annotation) { + RelatedElementsGet getterAnn = (RelatedElementsGet)getterAnnotation; + RelatedElementsRem adderAnn = (RelatedElementsRem)annotation; + return getterAnn.value().equals(adderAnn.value()); + } + +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/factories/RelatedGetSetObjRuleFactory.java b/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/factories/RelatedGetSetObjRuleFactory.java new file mode 100644 index 00000000..3f75b03c --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/factories/RelatedGetSetObjRuleFactory.java @@ -0,0 +1,44 @@ +package org.simantics.g3d.objmap.annotations.factories; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; + +import org.simantics.db.ReadGraph; +import org.simantics.db.exception.DatabaseException; +import org.simantics.g3d.objmap.annotations.RelatedGetObj; +import org.simantics.g3d.objmap.annotations.RelatedGetValue; +import org.simantics.g3d.objmap.annotations.RelatedSetObj; +import org.simantics.g3d.objmap.annotations.RelatedSetValue; +import org.simantics.g3d.objmap.rules.factory.IGetSetRuleFactory; +import org.simantics.g3d.objmap.rules.range.GetSetObjectAccessor; +import org.simantics.objmap.IMappingRule; +import org.simantics.objmap.rules.MappedElementRule; +import org.simantics.objmap.rules.domain.RelatedObjectAccessor; + +/** + * Rule factory for mapped object using Getter/Setter-methods. + * + * @author Marko Luukkainen + * + */ +public class RelatedGetSetObjRuleFactory implements IGetSetRuleFactory { + + @Override + public IMappingRule create(ReadGraph g, Annotation annotation, + Method getter, Method setter) + throws DatabaseException { + RelatedGetObj getterAnn = (RelatedGetObj)annotation; + return new MappedElementRule(new RelatedObjectAccessor(g.getResource(getterAnn.value())), + new GetSetObjectAccessor(getter, setter)); + } + + @Override + public boolean isSetter(Annotation getterAnnotation, Annotation annotation) { + RelatedGetObj getterAnn = (RelatedGetObj)getterAnnotation; + RelatedSetObj setterAnn = (RelatedSetObj)annotation; + return getterAnn.value().equals(setterAnn.value()); + } + + + +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/factories/RelatedGetSetValueRuleFactory.java b/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/factories/RelatedGetSetValueRuleFactory.java new file mode 100644 index 00000000..273f2b97 --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/factories/RelatedGetSetValueRuleFactory.java @@ -0,0 +1,100 @@ +package org.simantics.g3d.objmap.annotations.factories; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; + +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.exception.DatabaseException; +import org.simantics.g3d.objmap.annotations.RelatedGetValue; +import org.simantics.g3d.objmap.annotations.RelatedSetValue; +import org.simantics.g3d.objmap.rules.factory.IGetSetRuleFactory; +import org.simantics.g3d.objmap.rules.range.GetSetValueAccessor; +import org.simantics.layer0.Layer0; +import org.simantics.objmap.IMappingRule; +import org.simantics.objmap.rules.ValueRule; +import org.simantics.objmap.rules.adapters.IdentityAdapter; +import org.simantics.objmap.rules.adapters.ValueAdapter; +import org.simantics.objmap.rules.domain.RelatedValueAccessor; +import org.simantics.objmap.rules.range.AdaptedRangeAccessor; +import org.simantics.objmap.rules.range.IRangeAccessor; + +/** + * Rule factory for mapped value using Getter/Setter-methods. + * + * @author Marko Luukkainen + * + */ +public class RelatedGetSetValueRuleFactory implements IGetSetRuleFactory { + + @Override + public IMappingRule create(ReadGraph g, Annotation annotation, + Method getter, Method setter) + throws DatabaseException { + RelatedGetValue getterAnn = (RelatedGetValue)annotation; + + Class adapterClass = getterAnn.adapter(); + IRangeAccessor rangeAccessor = new GetSetValueAccessor(getter, setter); + Resource valueType; + if (adapterClass == IdentityAdapter.class) { + valueType = dataTypeOfClass(g, getter.getReturnType()); + } else { + try{ + ValueAdapter adapter = adapterClass.newInstance(); + rangeAccessor = new AdaptedRangeAccessor(rangeAccessor, adapter); + valueType = adapter.rangeTypeToDomainType(g, getter.getReturnType()); + } catch (InstantiationException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + return new ValueRule(new RelatedValueAccessor(g.getResource(getterAnn.value()), valueType), + rangeAccessor); + } + + @Override + public boolean isSetter(Annotation getterAnnotation, Annotation annotation) { + RelatedGetValue getterAnn = (RelatedGetValue)getterAnnotation; + RelatedSetValue setterAnn = (RelatedSetValue)annotation; + return getterAnn.value().equals(setterAnn.value()); + } + + public static Resource dataTypeOfClass(ReadGraph g, Class clazz) { + Layer0 b = Layer0.getInstance(g); + if(clazz.equals(Double.class) || clazz.equals(double.class)) + return b.Double; + else if(clazz.equals(String.class)) + return b.String; + else if(clazz.equals(Integer.class) || clazz.equals(int.class)) + return b.Integer; + else if(clazz.equals(Float.class) || clazz.equals(float.class)) + return b.Float; + else if(clazz.equals(Boolean.class) || clazz.equals(boolean.class)) + return b.Boolean; + else if(clazz.equals(Long.class) || clazz.equals(long.class)) + return b.Long; + else if(clazz.equals(Byte.class) || clazz.equals(byte.class)) + return b.Byte; + + else if(clazz.equals(double[].class)) + return b.DoubleArray; + else if(clazz.equals(int[].class)) + return b.IntegerArray; + else if(clazz.equals(byte[].class)) + return b.ByteArray; + else if(clazz.equals(float[].class)) + return b.FloatArray; + else if(clazz.equals(boolean[].class)) + return b.BooleanArray; + else if(clazz.equals(String[].class)) + return b.StringArray; + else if(clazz.equals(long[].class)) + return b.LongArray; + else { + System.out.println("Couldn't find a data type for " + clazz); + return null; + } + } + +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/objmap/rules/factory/ICollectionRuleFactory.java b/org.simantics.g3d/src/org/simantics/g3d/objmap/rules/factory/ICollectionRuleFactory.java new file mode 100644 index 00000000..d7176f1e --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/objmap/rules/factory/ICollectionRuleFactory.java @@ -0,0 +1,14 @@ +package org.simantics.g3d.objmap.rules.factory; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; + +import org.simantics.db.ReadGraph; +import org.simantics.db.exception.DatabaseException; +import org.simantics.objmap.IMappingRule; + +public interface ICollectionRuleFactory { + IMappingRule create(ReadGraph g, Annotation annotation, Method getter, Method adder, Method remover) throws DatabaseException; + boolean isAdder(Annotation getterAnnotation, Annotation annotation); + boolean isRemover(Annotation getterAnnotation, Annotation annotation); +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/objmap/rules/factory/IGetSetRuleFactory.java b/org.simantics.g3d/src/org/simantics/g3d/objmap/rules/factory/IGetSetRuleFactory.java new file mode 100644 index 00000000..f5218cd9 --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/objmap/rules/factory/IGetSetRuleFactory.java @@ -0,0 +1,13 @@ +package org.simantics.g3d.objmap.rules.factory; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; + +import org.simantics.db.ReadGraph; +import org.simantics.db.exception.DatabaseException; +import org.simantics.objmap.IMappingRule; + +public interface IGetSetRuleFactory { + IMappingRule create(ReadGraph g, Annotation annotation, Method getter, Method setter) throws DatabaseException; + boolean isSetter(Annotation getterAnnotation, Annotation annotation); +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/objmap/rules/range/CollectionAccessor.java b/org.simantics.g3d/src/org/simantics/g3d/objmap/rules/range/CollectionAccessor.java new file mode 100644 index 00000000..896b697f --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/objmap/rules/range/CollectionAccessor.java @@ -0,0 +1,80 @@ +package org.simantics.g3d.objmap.rules.range; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collection; + +import org.simantics.objmap.MappingException; +import org.simantics.objmap.rules.range.IRangeAccessor; + +/** + * Accessor for mapped collections. + * Uses three methods: + * - Getter: returns the collection. + * - Adder: adds one item into the collection. + * - Remover: removes one item from the collection. + * + * @author Marko Luukkainen + * + * @param + */ +public class CollectionAccessor implements IRangeAccessor> { + + private Method getter; + private Method adder; + private Method remover; + + public CollectionAccessor(Method getter, Method adder, Method remover) { + this.getter = getter; + this.adder = adder; + this.remover = remover; + } + + @SuppressWarnings("unchecked") + public java.util.Collection get(Object element) throws org.simantics.objmap.MappingException { + try { + return (Collection) getter.invoke(element); + } catch (IllegalArgumentException e) { + throw new MappingException(e); + } catch (IllegalAccessException e) { + throw new MappingException(e); + } catch (InvocationTargetException e) { + throw new MappingException(e); + } + }; + + @Override + public boolean set(Object element, Collection value) + throws MappingException { + java.util.Collection current = get(element); + Collection adding = new ArrayList(); + Collection removing = new ArrayList(); + for (T e : current) { + if (!value.contains(e)) + removing.add(e); + } + for (T e : value) { + if (!current.contains(e)) + adding.add(e); + } + + try { + for (T e : removing) { + remover.invoke(element, e); + } + + for (T e : adding) { + adder.invoke(element, e); + } + } catch (IllegalArgumentException e) { + throw new MappingException(e); + } catch (IllegalAccessException e) { + throw new MappingException(e); + } catch (InvocationTargetException e) { + throw new MappingException(e); + } + return true; + + } +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/objmap/rules/range/GetSetObjectAccessor.java b/org.simantics.g3d/src/org/simantics/g3d/objmap/rules/range/GetSetObjectAccessor.java new file mode 100644 index 00000000..8ceda89d --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/objmap/rules/range/GetSetObjectAccessor.java @@ -0,0 +1,58 @@ +package org.simantics.g3d.objmap.rules.range; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import org.simantics.objmap.MappingException; +import org.simantics.objmap.rules.range.IRangeAccessor; + +/** + * Accessor for mapped objects. Uses two methods: + * - Getter: returns the current object. + * - Setter: sets the current object. The object may be null. + * + * @author Marko Luukkainen + * + * @param + */ +public class GetSetObjectAccessor implements IRangeAccessor { + + private Method getter; + private Method setter; + + + public GetSetObjectAccessor(Method getter, Method setter) { + this.getter = getter; + this.setter = setter; + + } + + @SuppressWarnings("unchecked") + public T get(Object element) throws org.simantics.objmap.MappingException { + try { + return (T) getter.invoke(element); + } catch (IllegalArgumentException e) { + throw new MappingException(e); + } catch (IllegalAccessException e) { + throw new MappingException(e); + } catch (InvocationTargetException e) { + throw new MappingException(e); + } + }; + + @Override + public boolean set(Object element, T value) + throws MappingException { + try { + setter.invoke(element, value); + } catch (IllegalArgumentException e) { + throw new MappingException(e); + } catch (IllegalAccessException e) { + throw new MappingException(e); + } catch (InvocationTargetException e) { + throw new MappingException(e); + } + return true; + + } +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/objmap/rules/range/GetSetValueAccessor.java b/org.simantics.g3d/src/org/simantics/g3d/objmap/rules/range/GetSetValueAccessor.java new file mode 100644 index 00000000..f7da6538 --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/objmap/rules/range/GetSetValueAccessor.java @@ -0,0 +1,73 @@ +package org.simantics.g3d.objmap.rules.range; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import org.simantics.objmap.MappingException; +import org.simantics.objmap.rules.range.IRangeAccessor; + +/** + * Accessor for mapped value. Uses two methods: + * - Getter: returns the current value. + * - Setter: sets the current value. The value may be null. (if setter parameter is primitive, null value is not mapped). + * + * @author Marko Luukkainen + * + * @param + */ +public class GetSetValueAccessor implements IRangeAccessor { + + private Method getter; + private Method setter; + private boolean primitive; + + public GetSetValueAccessor(Method getter, Method setter) { + this.getter = getter; + this.setter = setter; + this.primitive = setter.getParameterTypes()[0].isPrimitive(); + } + + @SuppressWarnings("unchecked") + public T get(Object element) throws org.simantics.objmap.MappingException { + try { + return (T) getter.invoke(element); + } catch (IllegalArgumentException e) { + throw new MappingException(e); + } catch (IllegalAccessException e) { + throw new MappingException(e); + } catch (InvocationTargetException e) { + throw new MappingException(e); + } + }; + + @Override + public boolean set(Object element, T value) + throws MappingException { + if (value == null && primitive) + return false; + if (equal(get(element),value)) + return false; + try { + setter.invoke(element, value); + } catch (IllegalArgumentException e) { + throw new MappingException(e); + } catch (IllegalAccessException e) { + throw new MappingException(e); + } catch (InvocationTargetException e) { + throw new MappingException(e); + } + return true; + + } + + private boolean equal(Object v1, Object v2) { + if (v1 == null) { + if (v2 == null) + return true; + return false; + } else if (v2 == null) { + return false; + } + return v1.equals(v2); + } +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/objmap/schema/AdaptedLinkType.java b/org.simantics.g3d/src/org/simantics/g3d/objmap/schema/AdaptedLinkType.java new file mode 100644 index 00000000..8a580f07 --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/objmap/schema/AdaptedLinkType.java @@ -0,0 +1,71 @@ +package org.simantics.g3d.objmap.schema; + +//import org.apache.log4j.Logger; +import org.eclipse.core.runtime.IAdaptable; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.WriteGraph; +import org.simantics.db.exception.DatabaseException; +import org.simantics.objmap.IFunction; +import org.simantics.objmap.ILinkType; +import org.simantics.objmap.MappingException; + +/** + * A link type that is associated with adaptable resource (ReadGraph.getAdapter(Resource,Class)). + * The adapted object must implement IAdaptable interface for returning the original Resource. + * + * @author Marko Luukkainen + * + */ +public class AdaptedLinkType implements ILinkType { + + + //static Logger LOGGER = Logger.getLogger("org.simantics.objmap"); + + Resource domainType; + Class rangeType; + + + public AdaptedLinkType(Resource domainType, Class rangeType) { + this.domainType = domainType; + this.rangeType = rangeType; + } + + @Override + public Resource createDomainElement(WriteGraph g, Object rangeElement) + throws MappingException { + try { + IAdaptable adaptable = (IAdaptable)rangeElement; + Resource res = (Resource)adaptable.getAdapter(Resource.class); + if (res == null) + throw new NullPointerException(); + return res; + } catch (Exception e) { + throw new MappingException("Adapted object must implement IAdaptable interface to return the source Resource.", e); + } + + } + + @Override + public Object createRangeElement(ReadGraph g, Resource domainElement) + throws MappingException { + try { + return g.adapt(domainElement, rangeType); + } catch (DatabaseException e) { + throw new MappingException(e); + } + } + + @Override + public boolean updateDomain(WriteGraph g, IFunction map, + Resource domainElement, Object rangeElement) + throws MappingException { + return false; + } + @Override + public boolean updateRange(ReadGraph g, IFunction map, + Resource domainElement, Object rangeElement) + throws MappingException { + return false; + } +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/objmap/schema/DefaultSchema.java b/org.simantics.g3d/src/org/simantics/g3d/objmap/schema/DefaultSchema.java new file mode 100644 index 00000000..43ed22fd --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/objmap/schema/DefaultSchema.java @@ -0,0 +1,96 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.g3d.objmap.schema; + +import gnu.trove.THashMap; + +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.common.utils.NameUtils; +import org.simantics.db.exception.DatabaseException; +import org.simantics.objmap.ILinkType; +import org.simantics.objmap.IMappingSchema; +import org.simantics.objmap.MappingException; +import org.simantics.objmap.schema.SimpleLinkType; + +/** + * + */ +public class DefaultSchema implements IMappingSchema { + + THashMap domainLinkTypes = + new THashMap(); + THashMap, ILinkType> rangeLinkTypes = + new THashMap, ILinkType>(); + + public void addLinkType(SimpleLinkType linkType) { + domainLinkTypes.put(linkType.domainType, linkType); + rangeLinkTypes.put(linkType.rangeType, linkType); + } + + public void addLinkType(AdaptedLinkType linkType) { + domainLinkTypes.put(linkType.domainType, linkType); + rangeLinkTypes.put(linkType.rangeType, linkType); + } + + @Override + public ILinkType linkTypeOfDomainElement(ReadGraph g, Resource element) throws MappingException { + try { + + for(Resource type : g.getTypes(element)) { + + ILinkType linkType = domainLinkTypes.get(type); + if(linkType != null) return linkType; + + } + + throw new MappingException("Didn't find a link type for " + + NameUtils.getSafeName(g, element) + "."); + + } catch (DatabaseException e) { + throw new MappingException(e); + } + } + + @Override + public ILinkType linkTypeOfRangeElement(Object element) throws MappingException { + ILinkType type = rangeLinkTypes.get(element.getClass()); + if(type == null) { + for (Class clazz : element.getClass().getInterfaces()) { + type = rangeLinkTypes.get(clazz); + if (type != null) + return type; + + } + throw new MappingException("Didn't find a link type for " + element + "."); + } + return type; + } + + + public ILinkType linkTypeOfDomainType(ReadGraph g, Resource type) { + return domainLinkTypes.get(type); + } + + public ILinkType linkTypeOfRangeType(Class clazz) { + ILinkType type = rangeLinkTypes.get(clazz); + if(type == null) { + for (Class c : clazz.getInterfaces()) { + type = rangeLinkTypes.get(clazz); + if (type != null) + return type; + + } + } + return null; + } +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/objmap/schema/MappingSchemas.java b/org.simantics.g3d/src/org/simantics/g3d/objmap/schema/MappingSchemas.java new file mode 100644 index 00000000..0b69d595 --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/objmap/schema/MappingSchemas.java @@ -0,0 +1,166 @@ +package org.simantics.g3d.objmap.schema; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collection; + +import org.simantics.db.ReadGraph; +import org.simantics.db.exception.DatabaseException; +import org.simantics.g3d.objmap.annotations.HasCollectionAdder; +import org.simantics.g3d.objmap.annotations.HasCollectionRemover; +import org.simantics.g3d.objmap.annotations.HasCollectionRuleFactory; +import org.simantics.g3d.objmap.annotations.HasGetSetRuleFactory; +import org.simantics.g3d.objmap.annotations.HasSetter; +import org.simantics.g3d.objmap.rules.factory.ICollectionRuleFactory; +import org.simantics.g3d.objmap.rules.factory.IGetSetRuleFactory; +import org.simantics.objmap.ILinkType; +import org.simantics.objmap.IMappingRule; +import org.simantics.objmap.annotations.GraphType; +import org.simantics.objmap.annotations.RelatedValue; +import org.simantics.objmap.annotations.meta.HasClassRuleFactory; +import org.simantics.objmap.annotations.meta.HasFieldRuleFactory; +import org.simantics.objmap.annotations.meta.HasMethodRuleFactory; +import org.simantics.objmap.schema.SimpleLinkType; + +public class MappingSchemas { + /** + * Creates a new SimpleLinkType based on the annotations in the given class. + * @throws IllegalAccessException + * @throws InstantiationException + * @see GraphType + * @see RelatedValue + */ + public static SimpleLinkType fromAnnotations(ReadGraph g, Class clazz) throws DatabaseException, InstantiationException, IllegalAccessException { + GraphType graphType = clazz.getAnnotation(GraphType.class); + + ArrayList rules = new ArrayList(); + collectRulesFromAnnotations(g, clazz, rules); + + return new SimpleLinkType( + g.getResource(graphType.value()), + clazz, rules); + } + + public static void collectRulesFromAnnotations(ReadGraph g, Class clazz, Collection rules) throws DatabaseException, InstantiationException, IllegalAccessException { + Class superclass = clazz.getSuperclass(); + if(superclass != null) + collectRulesFromAnnotations(g, superclass, rules); + + for(Annotation annotation : clazz.getAnnotations()) { + HasClassRuleFactory factory = + annotation.annotationType().getAnnotation(HasClassRuleFactory.class); + if(factory != null) { + rules.add(factory.value().newInstance() + .create(g, annotation, clazz)); + } + } + + for(Field f : clazz.getDeclaredFields()) { + f.setAccessible(true); + + for(Annotation annotation : f.getAnnotations()) { + HasFieldRuleFactory factory = + annotation.annotationType().getAnnotation(HasFieldRuleFactory.class); + if(factory != null) { + rules.add(factory.value().newInstance() + .create(g, annotation, f)); + } + } + } + + for(Method m : clazz.getDeclaredMethods()) { + m.setAccessible(true); + + for(Annotation annotation : m.getAnnotations()) { + HasMethodRuleFactory factory = + annotation.annotationType().getAnnotation(HasMethodRuleFactory.class); + if(factory != null) { + rules.add(factory.value().newInstance().create(g, annotation, m)); + } + } + } + + for (Method m : clazz.getDeclaredMethods()) { + m.setAccessible(true); + for (Annotation annotation : m.getAnnotations()) { + Class annotationType = annotation.annotationType(); + HasGetSetRuleFactory factory = + annotationType.getAnnotation(HasGetSetRuleFactory.class); + if (factory != null) { + + HasSetter setterAnnType = annotationType.getAnnotation(HasSetter.class); + + Class setterAnn = setterAnnType.value(); + + IGetSetRuleFactory ruleFactory = factory.value().newInstance(); + + Method getter = m; + Method setter = null; + + for (Method m2 : clazz.getDeclaredMethods()) { + Annotation set = m2.getAnnotation(setterAnn); + if (set != null && ruleFactory.isSetter(annotation, set)) + setter = m2; + } + + rules.add(ruleFactory.create(g, annotation, getter, setter)); + } + + } + } + + for (Method m : clazz.getDeclaredMethods()) { + m.setAccessible(true); + for (Annotation annotation : m.getAnnotations()) { + Class annotationType = annotation.annotationType(); + HasCollectionRuleFactory factory = + annotationType.getAnnotation(HasCollectionRuleFactory.class); + if (factory != null) { + + HasCollectionAdder adderAnnType = annotationType.getAnnotation(HasCollectionAdder.class); + HasCollectionRemover removerAnnType = annotationType.getAnnotation(HasCollectionRemover.class); + + Class adderAnn = adderAnnType.value(); + Class removerAnn = removerAnnType.value(); + + ICollectionRuleFactory ruleFactory = factory.value().newInstance(); + + Method getter = m; + Method adder = null; + Method remover = null; + + for (Method m2 : clazz.getDeclaredMethods()) { + Annotation add = m2.getAnnotation(adderAnn); + Annotation rem = m2.getAnnotation(removerAnn); + if (add != null && ruleFactory.isAdder(annotation, add)) + adder = m2; + if (rem != null && ruleFactory.isRemover(annotation, rem)) + remover = m2; + } + + + + rules.add(ruleFactory.create(g, annotation, getter,adder,remover)); + } + + } + } + } + + /** + * Creates a new SimpleLinkType based on the annotations in the given class. + * @throws IllegalAccessException + * @throws InstantiationException + * @see GraphType + * @see RelatedValue + */ + public static AdaptedLinkType fromAdaptable(ReadGraph g, String type, Class clazz) throws DatabaseException, InstantiationException, IllegalAccessException { + + + return new AdaptedLinkType(g.getResource(type), clazz); + } + + +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/preferences/G3DPreferencePage.java b/org.simantics.g3d/src/org/simantics/g3d/preferences/G3DPreferencePage.java new file mode 100644 index 00000000..7f90aebe --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/preferences/G3DPreferencePage.java @@ -0,0 +1,79 @@ +package org.simantics.g3d.preferences; + +import org.eclipse.jface.preference.*; +import org.eclipse.ui.IWorkbenchPreferencePage; +import org.eclipse.ui.IWorkbench; +import org.simantics.g3d.Activator; +import org.simantics.g3d.math.EulerTools.Order; + +/** + * This class represents a preference page that + * is contributed to the Preferences dialog. By + * subclassing FieldEditorPreferencePage, we + * can use the field support built into JFace that allows + * us to create a page that is small and knows how to + * save, restore and apply itself. + *

+ * This page is used to modify preferences only. They + * are stored in the preference store that belongs to + * the main plug-in class. That way, preferences can + * be accessed directly via the preference store. + */ + +public class G3DPreferencePage + extends FieldEditorPreferencePage + implements IWorkbenchPreferencePage { + + public G3DPreferencePage() { + super(GRID); + setPreferenceStore(Activator.getDefault().getPreferenceStore()); + setDescription("3D modelling prederences"); + } + + /** + * Creates the field editors. Field editors are abstractions of + * the common GUI blocks needed to manipulate various types + * of preferences. Each field editor knows how to save and + * restore itself. + */ + public void createFieldEditors() { + addField(new RadioGroupFieldEditor( + PreferenceConstants.ORIENTATION_PRESENTATION, + "OrientationPresentation", 1, + new String[][] { { "&Quaternion", "quat" }, + { "&Axis-Angle", "aa" },{ "&Euler", "euler" } }, getFieldEditorParent())); + String[][] eulerOrders = new String[Order.values().length][2]; + for (int i = 0; i < Order.values().length; i++) { + eulerOrders[i][0] = Order.values()[i].toString(); + eulerOrders[i][1] = Order.values()[i].name(); + } + addField(new RadioGroupFieldEditor( + PreferenceConstants.EULER_ANGLE_ORDER, + "Euler Angle Order", 1, + eulerOrders, getFieldEditorParent())); +// addField(new DirectoryFieldEditor(PreferenceConstants.P_PATH, +// "&Directory preference:", getFieldEditorParent())); +// addField( +// new BooleanFieldEditor( +// PreferenceConstants.P_BOOLEAN, +// "&An example of a boolean preference", +// getFieldEditorParent())); +// +// addField(new RadioGroupFieldEditor( +// PreferenceConstants.P_CHOICE, +// "An example of a multiple-choice preference", +// 1, +// new String[][] { { "&Choice 1", "choice1" }, { +// "C&hoice 2", "choice2" } +// }, getFieldEditorParent())); +// addField( +// new StringFieldEditor(PreferenceConstants.P_STRING, "A &text preference:", getFieldEditorParent())); + } + + /* (non-Javadoc) + * @see org.eclipse.ui.IWorkbenchPreferencePage#init(org.eclipse.ui.IWorkbench) + */ + public void init(IWorkbench workbench) { + } + +} \ No newline at end of file diff --git a/org.simantics.g3d/src/org/simantics/g3d/preferences/PreferenceConstants.java b/org.simantics.g3d/src/org/simantics/g3d/preferences/PreferenceConstants.java new file mode 100644 index 00000000..92eda41a --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/preferences/PreferenceConstants.java @@ -0,0 +1,19 @@ +package org.simantics.g3d.preferences; + +/** + * Constant definitions for plug-in preferences + */ +public class PreferenceConstants { + + public static final String ORIENTATION_PRESENTATION = "orientationPresentationPreference"; + public static final String EULER_ANGLE_ORDER = "eulerAngleOrderPreference"; + +// public static final String P_PATH = "pathPreference"; +// +// public static final String P_BOOLEAN = "booleanPreference"; +// +// public static final String P_CHOICE = "choicePreference"; +// +// public static final String P_STRING = "stringPreference"; + +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/preferences/PreferenceInitializer.java b/org.simantics.g3d/src/org/simantics/g3d/preferences/PreferenceInitializer.java new file mode 100644 index 00000000..7f1743a5 --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/preferences/PreferenceInitializer.java @@ -0,0 +1,28 @@ +package org.simantics.g3d.preferences; + +import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer; +import org.eclipse.jface.preference.IPreferenceStore; + +import org.simantics.g3d.Activator; +import org.simantics.g3d.math.EulerTools.Order; + +/** + * Class used to initialize default preference values. + */ +public class PreferenceInitializer extends AbstractPreferenceInitializer { + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer#initializeDefaultPreferences() + */ + public void initializeDefaultPreferences() { + IPreferenceStore store = Activator.getDefault().getPreferenceStore(); + store.setDefault(PreferenceConstants.ORIENTATION_PRESENTATION, "aa"); + store.setDefault(PreferenceConstants.EULER_ANGLE_ORDER, Order.YXZ.toString()); +// store.setDefault(PreferenceConstants.P_BOOLEAN, true); +// store.setDefault(PreferenceConstants.P_CHOICE, "choice2"); +// store.setDefault(PreferenceConstants.P_STRING,"Default value"); + } + +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/property/AnnotatedPropertyTabContributorFactory.java b/org.simantics.g3d/src/org/simantics/g3d/property/AnnotatedPropertyTabContributorFactory.java new file mode 100644 index 00000000..461319eb --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/property/AnnotatedPropertyTabContributorFactory.java @@ -0,0 +1,1297 @@ +package org.simantics.g3d.property; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.eclipse.jface.layout.GridDataFactory; +import org.eclipse.jface.viewers.AbstractTableViewer; +import org.eclipse.jface.viewers.CellEditor; +import org.eclipse.jface.viewers.CellEditor.LayoutData; +import org.eclipse.jface.viewers.CellLabelProvider; +import org.eclipse.jface.viewers.CellNavigationStrategy; +import org.eclipse.jface.viewers.ColumnViewer; +import org.eclipse.jface.viewers.ColumnViewerEditor; +import org.eclipse.jface.viewers.ColumnViewerEditorActivationEvent; +import org.eclipse.jface.viewers.ColumnViewerEditorActivationListener; +import org.eclipse.jface.viewers.ColumnViewerEditorActivationStrategy; +import org.eclipse.jface.viewers.ColumnViewerEditorDeactivationEvent; +import org.eclipse.jface.viewers.EditingSupport; +import org.eclipse.jface.viewers.FocusCellOwnerDrawHighlighter; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.ISelectionProvider; +import org.eclipse.jface.viewers.IStructuredContentProvider; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.TableViewerColumn; +import org.eclipse.jface.viewers.TableViewerFocusCellManager; +import org.eclipse.jface.viewers.TextCellEditor; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.viewers.ViewerCell; +import org.eclipse.jface.viewers.ViewerColumn; +import org.eclipse.jface.viewers.ViewerRow; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.TableEditor; +import org.eclipse.swt.events.TraverseEvent; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Item; +import org.eclipse.swt.widgets.TableColumn; +import org.eclipse.swt.widgets.TableItem; +import org.eclipse.ui.IWorkbenchSite; +import org.simantics.db.management.ISessionContext; +import org.simantics.g3d.property.annotations.CompoundGetPropertyValue; +import org.simantics.g3d.property.annotations.CompoundSetPropertyValue; +import org.simantics.g3d.property.annotations.GetPropertyValue; +import org.simantics.g3d.property.annotations.PropertyTabBlacklist; +import org.simantics.g3d.property.annotations.SetPropertyValue; +import org.simantics.g3d.scenegraph.IG3DNode; +import org.simantics.g3d.scenegraph.NodeMap; +import org.simantics.g3d.scenegraph.NodeMapProvider; +import org.simantics.g3d.scenegraph.base.INode; +import org.simantics.g3d.scenegraph.base.NodeListener; +import org.simantics.g3d.scenegraph.base.ParentNode; +import org.simantics.g3d.scenegraph.structural.IStructuralNode; +import org.simantics.g3d.tools.AdaptationUtils; +import org.simantics.selectionview.IPropertyTab; +import org.simantics.selectionview.IPropertyTab2; +import org.simantics.utils.datastructures.Callback; +import org.simantics.utils.datastructures.MapList; + +public class AnnotatedPropertyTabContributorFactory implements PropertyTabContributorFactory { + + private static final boolean DEBUG = false; + + @SuppressWarnings("unchecked") + @Override + public List getContributors(Object input) { + Map items = new LinkedHashMap(); + List blacklist = new ArrayList(); + try { + collectItems(input.getClass(), items); + collectBlacklist(input.getClass(), blacklist); + } catch (InstantiationException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IllegalAccessException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + if (items.size() == 0) + return Collections.EMPTY_LIST; + + MapList tabMap = new MapList(); + List tabs = new ArrayList(); + for (String id : items.keySet()) { + IPropertyItem item = items.get(id); + tabMap.add(item.getTabId(), item); + if (!tabs.contains(item.getTabId())) { + tabs.add(item.getTabId()); + //System.out.println(item.tabId + " " + item.name + " " + item.id); + } + } + for (String s : blacklist) { + tabs.remove(s); + } + + List contributors = new ArrayList(tabs.size()); + for (String tabId : tabs) { + contributors.add(new AnnotatedPropertyTabContributor(tabId, tabMap.getValues(tabId))); + } + + return contributors; + } + + + private static void collectItems(Class clazz, Map items) throws InstantiationException, IllegalAccessException { + Class superclass = clazz.getSuperclass(); + if(superclass != null) + collectItems(superclass, items); + + for (Method m : clazz.getDeclaredMethods()) { + m.setAccessible(true); + for (Annotation annotation : m.getAnnotations()) { + if (annotation.annotationType().equals(GetPropertyValue.class)) { + GetPropertyValue get = (GetPropertyValue)annotation; + PropertyItem item = (PropertyItem)items.get(get.value()); + if (item == null) { + item = new PropertyItem(get.value()); + items.put(item.id, item); + } + + item.getter = m; + item.manipulatorClass = get.manipulator().newInstance().get(m,null); + + item.tabId = get.tabId(); + + item.name = get.name(); + + + } else if (annotation.annotationType().equals(SetPropertyValue.class)) { + SetPropertyValue set = (SetPropertyValue)annotation; + PropertyItem item = (PropertyItem)items.get(set.value()); + if (item == null) { + item = new PropertyItem(set.value()); + items.put(item.id, item); + } + + item.setter = m; + } else if (annotation.annotationType().equals(CompoundGetPropertyValue.class)) { + CompoundGetPropertyValue get = (CompoundGetPropertyValue)annotation; + CompoundPropertyItem item = (CompoundPropertyItem)items.get(get.value()); + if (item == null) { + item = new CompoundPropertyItem(get.value()); + items.put(item.id, item); + } + + item.getter = m; + item.manipulatorFactory = get.manipulator().newInstance(); + + item.tabId = get.tabId(); + + item.name = get.name(); + } else if (annotation.annotationType().equals(CompoundSetPropertyValue.class)) { + CompoundSetPropertyValue set = (CompoundSetPropertyValue)annotation; + CompoundPropertyItem item = (CompoundPropertyItem)items.get(set.value()); + if (item == null) { + item = new CompoundPropertyItem(set.value()); + items.put(item.id, item); + } + + item.setter = m; + } + } + } + + + } + + private static void collectBlacklist(Class clazz, List blacklist) throws InstantiationException, IllegalAccessException { + Class superclass = clazz.getSuperclass(); + if(superclass != null) + collectBlacklist(superclass, blacklist); + + PropertyTabBlacklist ann = clazz.getAnnotation(PropertyTabBlacklist.class); + if (ann == null) + return; + String s = ann.value(); + if (s == null) + return; + if (s.length() == 0) + return; + for (String item : s.split(";")) { + blacklist.add(item); + } + + + } + + private static Map createManipulators(CompoundPropertyItem item, Object obj) { + try { + + Map map = (Map)item.getter.invoke(obj); + Map result = new HashMap(); + for (String key : map.keySet()) { + MethodWithMapValueProvider provider = new MethodWithMapValueProvider(item.getter, item.setter, key); + Class clazz = item.manipulatorFactory.get(null,map.get(key)); + PropertyManipulator manipulator = clazz.getConstructor(ValueProvider.class,Object.class).newInstance(provider,obj); + PropertyItem i = new PropertyItem(item.id+"."+key); + i.getter = item.getter; + i.setter = item.setter; + i.name = key; + i.tabId = item.tabId; + result.put(i,manipulator); + } + return result; + } catch (Exception e) { + e.printStackTrace(); + return Collections.EMPTY_MAP; + } + + } + + private static PropertyManipulator createManipulator(PropertyItem item, Object obj) { + try { + MethodValueProvider provider = new MethodValueProvider(item.getter, item.setter); + PropertyManipulator manipulator = item.manipulatorClass.getConstructor(ValueProvider.class,Object.class).newInstance(provider,obj); + return manipulator; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + private static interface IPropertyItem { + public String getTabId(); + } + + private static class PropertyItem implements IPropertyItem{ + private String id; + private String name; + private String tabId; + private Method getter; + private Method setter; + private Class manipulatorClass; + + + public PropertyItem(String id) { + if (id == null) + throw new NullPointerException(); + this.id = id; + } + + @Override + public int hashCode() { + return id.hashCode(); + } + + @Override + public String getTabId() { + return tabId; + } + } + + private static class CompoundPropertyItem implements IPropertyItem{ + private String id; + private String name; + private String tabId; + private Method getter; + private Method setter; + private PropertyManipulatorFactory manipulatorFactory; + + + public CompoundPropertyItem(String id) { + if (id == null) + throw new NullPointerException(); + this.id = id; + } + + @Override + public int hashCode() { + return id.hashCode(); + } + + @Override + public String getTabId() { + return tabId; + } + } + + private static class AnnotatedPropertyTabContributor implements PropertyTabContributor { + private String id; + List items; + + public AnnotatedPropertyTabContributor(String id, List items) { + if (id == null) + throw new NullPointerException(); + this.id = id; + this.items = items; + } + + @Override + public IPropertyTab create(Composite parent, IWorkbenchSite site, + ISessionContext context, Object input) { + AnnotatedPropertyTab tab = new AnnotatedPropertyTab(id, items); + tab.createControl(parent, context); + return tab; + } + + @Override + public String getId() { + return id; + } + + } + + private static class AnnotatedPropertyTab implements IPropertyTab2, NodeListener { + //private String id; + List contibutedItems; + List resolvedItems = new ArrayList(); + private Map manipulators = new HashMap(); + + private TableViewer viewer; + + private IG3DNode node; + private NodeMap nodeMap; + + private List valueColumns = new ArrayList(); + + public AnnotatedPropertyTab(String id, List items) { + //this.id = id; + this.contibutedItems = items; + + + } + + @Override + public void createControl(Composite parent, ISessionContext context) { + //parent.setLayout(new FillLayout()); + viewer = new TableViewer(parent, SWT.FULL_SELECTION | SWT.SINGLE); + + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, true).applyTo(viewer.getTable()); + + //viewer.setLabelProvider(new AnnotatedTableLabelProvider(object)) + + viewer.setContentProvider(new PropertyItemContentsProvider()); + + TableViewerColumn name = new TableViewerColumn(viewer, SWT.LEFT); + //TableViewerColumn value = new TableViewerColumn(viewer, SWT.LEFT); + name.setLabelProvider(new PropertyItemNameProvider()); + //value.setLabelProvider(new PropertyValueLabelProvider(null)); + name.getColumn().setText("Property"); + //value.getColumn().setText("Value"); + name.getColumn().setWidth(200); + //value.getColumn().setWidth(200); + name.getViewer().addSelectionChangedListener(new ISelectionChangedListener() { + + @Override + public void selectionChanged(SelectionChangedEvent event) { + PropertyItem item = AdaptationUtils.adaptToSingle(event.getSelection(),PropertyItem.class); + if (item != null) { + PropertyManipulator manipulator = manipulators.get(item);//createManipulator(item, null); + for (int i = 0; i < valueColumns.size(); i++) { + TableViewerColumn c = valueColumns.get(i); + if (i < manipulator.getValueCount()) { + c.getColumn().setText(manipulator.getDescription(i)); + } else { + c.getColumn().setText(""); + } + } + } + + } + }); + + int valueCount = 0; + for (IPropertyItem item : contibutedItems) { + if (item instanceof PropertyItem) { + PropertyManipulator manipulator = createManipulator((PropertyItem)item, null); + if (manipulator == null) + continue; + if (valueCount < manipulator.getValueCount()) + valueCount = manipulator.getValueCount(); + } else if (item instanceof CompoundPropertyItem) { + if (valueCount < 1) + valueCount = 1; + } + } + for (int i = 0; i < valueCount; i++) { + TableViewerColumn value = new TableViewerColumn(viewer, SWT.LEFT); + //value.getColumn().setText("Value " + (i+1)); + value.getColumn().setText(""); + value.getColumn().setWidth(200); + valueColumns.add(value); + //value.setEditingSupport(new ) + } + viewer.getTable().setHeaderVisible(true); + viewer.getTable().setLinesVisible(true); + viewer.addSelectionChangedListener(new ISelectionChangedListener() { + + @Override + public void selectionChanged(SelectionChangedEvent event) { + PropertyItem item = AdaptationUtils.adaptToSingle(event.getSelection(), PropertyItem.class); + selectedItem = item; + if (!manipulators.get(selectedItem).getEditMode()) + manipulators.get(selectedItem).setEditMode(true); + + + for (IPropertyItem i : delayedUpdate) { + if (!i.equals(selectedItem)) { + manipulators.get(i).setEditMode(false); + viewer.update(i,null); + } + } + if (delayedUpdate.contains(selectedItem)) { + delayedUpdate.clear(); + delayedUpdate.add(selectedItem); + } else { + delayedUpdate.clear(); + } + } + }); + + CellNavigationStrategy nStrategy = new CellNavigationStrategy() { + private ViewerCell internalFindSelectedCell( + ColumnViewer viewer, ViewerCell currentSelectedCell, + Event event) { + switch (event.keyCode) { + case SWT.ARROW_UP: + if (currentSelectedCell != null) { + return getNeighbor(currentSelectedCell, + ViewerCell.ABOVE, false); + } + break; + case SWT.ARROW_DOWN: + if (currentSelectedCell != null) { + return getNeighbor(currentSelectedCell, + ViewerCell.BELOW, false); + } + break; + case SWT.ARROW_LEFT: + if (currentSelectedCell != null) { + return getNeighbor(currentSelectedCell, + ViewerCell.LEFT, true); + } + break; + case SWT.ARROW_RIGHT: + if (currentSelectedCell != null) { + return getNeighbor(currentSelectedCell, + ViewerCell.RIGHT, true); + } + break; + } + return null; + } + + public ViewerCell findSelectedCell(ColumnViewer viewer, + ViewerCell currentSelectedCell, Event event) { + ViewerCell cell = internalFindSelectedCell(viewer, + currentSelectedCell, event); + if (cell != null) { + TableColumn t = AnnotatedPropertyTab.this.viewer.getTable().getColumn( + cell.getColumnIndex()); + AnnotatedPropertyTab.this.viewer.getTable().showColumn(t); + } + return cell; + } + }; + + TableViewerFocusCellManager focusCellManager = new TableViewerFocusCellManager( + viewer, new FocusCellOwnerDrawHighlighter(viewer)); + try { + Field f = focusCellManager.getClass().getSuperclass() + .getDeclaredField("navigationStrategy"); + f.setAccessible(true); + f.set(focusCellManager, nStrategy); + } catch (SecurityException e) { + e.printStackTrace(); + } catch (NoSuchFieldException e) { + e.printStackTrace(); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + ColumnViewerEditorActivationStrategy actSupport = new ColumnViewerEditorActivationStrategy( + viewer) { + protected boolean isEditorActivationEvent( + ColumnViewerEditorActivationEvent event) { + return event.eventType == ColumnViewerEditorActivationEvent.TRAVERSAL + || event.eventType == ColumnViewerEditorActivationEvent.MOUSE_DOUBLE_CLICK_SELECTION + || (event.eventType == ColumnViewerEditorActivationEvent.KEY_PRESSED && event.keyCode == SWT.CR) + || event.eventType == ColumnViewerEditorActivationEvent.PROGRAMMATIC; + } + }; + TableViewerEditor.create(viewer, focusCellManager, actSupport, + ColumnViewerEditor.TABBING_HORIZONTAL + | ColumnViewerEditor.TABBING_MOVE_TO_ROW_NEIGHBOR + | ColumnViewerEditor.TABBING_VERTICAL + | ColumnViewerEditor.KEYBOARD_ACTIVATION); + viewer.getColumnViewerEditor().addEditorActivationListener( + new ColumnViewerEditorActivationListener() { + public void afterEditorActivated( + ColumnViewerEditorActivationEvent event) { + } + + public void afterEditorDeactivated( + ColumnViewerEditorDeactivationEvent event) { + } + + public void beforeEditorActivated( + ColumnViewerEditorActivationEvent event) { + ViewerCell cell = (ViewerCell) event.getSource(); + viewer.getTable().showColumn( + viewer.getTable().getColumn(cell.getColumnIndex())); + } + + public void beforeEditorDeactivated( + ColumnViewerEditorDeactivationEvent event) { + } + }); + } + + + + + private IPropertyItem selectedItem = null; + private Set delayedUpdate = new HashSet(); + + + @Override + public void setInput(ISessionContext context, ISelection selection, + boolean force) { + Collection nodes = AdaptationUtils.adaptToCollection(selection, IG3DNode.class); + if (nodes.size() != 1) { + if (node != null) { + node.removeListener(this); + node = null; + } + return; + } + IG3DNode n = nodes.iterator().next(); + if (node != null) { + if (!node.equals(n)) { + node.removeListener(this); + setInput(n); + } + } else { + setInput(n); + } + } + + + + private void setInput(IG3DNode node) { + this.node = node; + this.node.addListener(this); + // resolve nodemap + IG3DNode n = node; + while (true) { + if (n == null) { + nodeMap = null; + break; + } + if (n instanceof NodeMapProvider) { + nodeMap = ((NodeMapProvider) n).getNodeMap(); + if (nodeMap != null) + break; + } + n = (IG3DNode)n.getParent(); + } + boolean readOnly = (node instanceof IStructuralNode && ((IStructuralNode)node).isPartOfInstantiatedModel() && !((IStructuralNode)node).isInstantiatedModelRoot()); + // create label providers + PropertyValueLabelProvider2 p = new PropertyValueLabelProvider2(this); + int index = 0; + for (TableViewerColumn c : valueColumns) { + c.setLabelProvider(p); + if (!readOnly) { + PropertyEditingSupport support = new PropertyEditingSupport(this, viewer, index++, nodeMap); + c.setEditingSupport(support); + } + } + resolvedItems.clear(); + manipulators.clear(); + for (IPropertyItem item : contibutedItems) { + if (item instanceof PropertyItem) { + resolvedItems.add((PropertyItem)item); + manipulators.put((PropertyItem)item, createManipulator((PropertyItem)item, node)); + } + else { + CompoundPropertyItem compound = (CompoundPropertyItem)item; + Map manipulators = createManipulators(compound, node); + for (PropertyItem i : manipulators.keySet()) { + resolvedItems.add(i); + this.manipulators.put(i, manipulators.get(i)); + } + } + } + + viewer.getTable().setEnabled(!readOnly); + viewer.setInput(resolvedItems); + } + + @Override + public void requestFocus() { + viewer.getTable().forceFocus(); + } + + @Override + public void dispose() { + if (node != null) { + node.removeListener(this); + node = null; + } + + } + + @Override + public Control getControl() { + return viewer.getTable(); + } + + @Override + public ISelectionProvider getSelectionProvider() { + return null; + } + + @Override + public boolean isDisposed() { + return viewer.getTable().isDisposed(); + } + + @Override + public void nodeAdded(ParentNode node, + INode child, String rel) { + + } + + @Override + public void nodeRemoved(ParentNode node, + INode child, String rel) { + + } + + @Override + public void propertyChanged(INode node, final String id) { +// for (final PropertyItem item : items) { +// if (item.id.equals(id)) { +// Display.getDefault().asyncExec(new Runnable() { +// +// @Override +// public void run() { +// viewer.update(item, null); +// +// } +// }); +// } +// } + if (Thread.currentThread() == Display.getDefault().getThread()) { + if (DEBUG)System.out.println("Viewer refresh " + id); + for (PropertyItem item : resolvedItems) + if (!item.equals(selectedItem)) + viewer.refresh(item); + if (selectedItem != null) + delayedUpdate.add(selectedItem); + } else if (!editing){ + // running delayed refresh when a cell editor is active would cancel cell editing. + Display.getDefault().asyncExec(new Runnable() { + @Override + public void run() { + if (viewer.getTable().isDisposed()) { + if (AnnotatedPropertyTab.this.node != null) + AnnotatedPropertyTab.this.node.removeListener(AnnotatedPropertyTab.this); + return; + } + if (DEBUG) System.out.println("Viewer threaded refresh " + id); + for (PropertyItem item : resolvedItems) + if (!item.equals(selectedItem)) + viewer.refresh(item); + if (selectedItem != null) + delayedUpdate.add(selectedItem); + + } + }); + } else { + for (PropertyItem item : resolvedItems) { + delayedUpdate.add(item); + } + } + + } + + + + + + @Override + public void updatePartName(Callback updateCallback) { + if (node != null) + updateCallback.run(node.toString()); + + } + + public PropertyManipulator getManipulator(PropertyItem item) { + return manipulators.get(item); + } + + private boolean editing = false; + + public void setEditing(boolean editing) { + this.editing = editing; + } + } + + + + private static class PropertyEditingSupport extends EditingSupport { + AnnotatedPropertyTab tab; + int index; + NodeMap nodeMap; + TableViewer viewer; + CellEditor editor; + + public PropertyEditingSupport(AnnotatedPropertyTab tab, TableViewer viewer, int index, NodeMap nodeMap) { + super(viewer); + this.tab = tab; + this.index = index; + this.viewer = viewer; + this.nodeMap = nodeMap; + } + + @Override + protected boolean canEdit(Object element) { + PropertyItem item = (PropertyItem)element; + if (tab.getManipulator(item).getValueCount() <= index) + return false; + return (item.setter != null); + } + + @Override + protected CellEditor getCellEditor(Object element) { + + if (tab.getManipulator((PropertyItem)element).getValueCount() <= index) + return null; + if (editor == null) + editor = new TextCellEditor(viewer.getTable(),SWT.NONE) { + @Override + public void activate() { + tab.setEditing(true); + } + + @Override + public void deactivate() { + super.deactivate(); + tab.setEditing(false); + } + }; + if (DEBUG)System.err.println("CELL EDITOR: " + element); + return editor; + } + + @Override + protected Object getValue(Object element) { + PropertyItem item = (PropertyItem)element; + PropertyManipulator manipulator = tab.getManipulator(item);//createManipulator(item, obj); + if (manipulator.getValueCount() <= index) + return null; + Object value = manipulator.getValue(index); + return value; + } + + @Override + protected void setValue(Object element, Object value) { + + PropertyItem item = (PropertyItem)element; + PropertyManipulator manipulator = tab.getManipulator(item);//createManipulator(item, obj); + if (manipulator.getValueCount() <= index) + throw new IllegalAccessError("Editing value in index " + index + " is not allowed."); + if (DEBUG)System.err.println("CELL SET VALUE: " + element + " " + value); + manipulator.setValue((String)value,index); + viewer.refresh(item); + nodeMap.commit(); + + } + + + + } + + private static class PropertyItemNameProvider extends CellLabelProvider { + + + @Override + public void update(ViewerCell cell) { + PropertyItem item = (PropertyItem)cell.getElement(); + + if (item.name.length() > 0) + cell.setText(item.name); + else + cell.setText(item.id); + + + } + } + + private static class PropertyValueLabelProvider2 extends CellLabelProvider { + AnnotatedPropertyTab tab; + //private Object object; + + public PropertyValueLabelProvider2(AnnotatedPropertyTab tab) { + this.tab = tab; + } + + @Override + public void update(ViewerCell cell) { + PropertyItem item = (PropertyItem)cell.getElement(); + int index = cell.getColumnIndex() -1; + PropertyManipulator manipulator = tab.getManipulator(item);//createManipulator(item, object); + if (manipulator.getValueCount() <= index) + return; + cell.setText(manipulator.getValue(index)); + } + } + + private static class PropertyItemContentsProvider implements IStructuredContentProvider { + @SuppressWarnings("unchecked") + @Override + public Object[] getElements(Object inputElement) { + List items = (List)inputElement; + return items.toArray(); + } + + @Override + public void dispose() { + + } + + @Override + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + + } + } + + + + private static ViewerCell getNeighbor(ViewerCell currentCell, + int directionMask, boolean sameLevel) { + ViewerRow row; + if ((directionMask & ViewerCell.ABOVE) == ViewerCell.ABOVE) { + row = currentCell.getViewerRow().getNeighbor(ViewerRow.ABOVE, + sameLevel); + } else if ((directionMask & ViewerCell.BELOW) == ViewerCell.BELOW) { + row = currentCell.getViewerRow().getNeighbor(ViewerRow.BELOW, + sameLevel); + } else { + row = currentCell.getViewerRow(); + } + if (row != null) { + int columnIndex; + columnIndex = getVisualIndex(row, currentCell.getColumnIndex()); + int modifier = 0; + if ((directionMask & ViewerCell.LEFT) == ViewerCell.LEFT) { + modifier = -1; + } else if ((directionMask & ViewerCell.RIGHT) == ViewerCell.RIGHT) { + modifier = 1; + } + columnIndex += modifier; + if (columnIndex >= 0 && columnIndex < row.getColumnCount()) { + ViewerCell cell = getCellAtVisualIndex(row, columnIndex); + if (cell != null) { + while (cell != null + && columnIndex < row.getColumnCount() - 1 + && columnIndex > 0) { + if (isVisible(cell)) { + break; + } + columnIndex += modifier; + cell = getCellAtVisualIndex(row, columnIndex); + if (cell == null) { + break; + } + } + } + return cell; + } + } + return null; + } + + + + public static class TableViewerEditor extends ColumnViewerEditor { + /** + * This viewer's table editor. + */ + private TableEditor tableEditor; + private TableViewerFocusCellManager focusCellManager; + private int feature; + + /** + * @param viewer + * the viewer the editor is attached to + * @param focusCellManager + * the cell focus manager if one used or null + * @param editorActivationStrategy + * the strategy used to decide about the editor activation + * @param feature + * the feature mask + */ + TableViewerEditor(TableViewer viewer, + TableViewerFocusCellManager focusCellManager, + ColumnViewerEditorActivationStrategy editorActivationStrategy, + int feature) { + super(viewer, editorActivationStrategy, feature); + this.feature = feature; + tableEditor = new TableEditor(viewer.getTable()); + this.focusCellManager = focusCellManager; + } + + /** + * Create a customized editor with focusable cells + * + * @param viewer + * the viewer the editor is created for + * @param focusCellManager + * the cell focus manager if one needed else + * null + * @param editorActivationStrategy + * activation strategy to control if an editor activated + * @param feature + * bit mask controlling the editor + *

    + *
  • {@link ColumnViewerEditor#DEFAULT}
  • + *
  • {@link ColumnViewerEditor#TABBING_CYCLE_IN_ROW}
  • + *
  • {@link ColumnViewerEditor#TABBING_HORIZONTAL}
  • + *
  • + * {@link ColumnViewerEditor#TABBING_MOVE_TO_ROW_NEIGHBOR}
  • + *
  • {@link ColumnViewerEditor#TABBING_VERTICAL}
  • + *
+ * @see #create(TableViewer, ColumnViewerEditorActivationStrategy, int) + */ + public static void create(TableViewer viewer, + TableViewerFocusCellManager focusCellManager, + ColumnViewerEditorActivationStrategy editorActivationStrategy, + int feature) { + TableViewerEditor editor = new TableViewerEditor(viewer, + focusCellManager, editorActivationStrategy, feature); + viewer.setColumnViewerEditor(editor); + if (focusCellManager != null) { + try { + Method m = focusCellManager.getClass().getSuperclass() + .getDeclaredMethod("init", null); + m.setAccessible(true); + m.invoke(focusCellManager, null); + } catch (SecurityException e) { + e.printStackTrace(); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } catch (NoSuchMethodException e) { + e.printStackTrace(); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } + // focusCellManager.init(); + } + } + + /** + * Create a customized editor whose activation process is customized + * + * @param viewer + * the viewer the editor is created for + * @param editorActivationStrategy + * activation strategy to control if an editor activated + * @param feature + * bit mask controlling the editor + *
    + *
  • {@link ColumnViewerEditor#DEFAULT}
  • + *
  • {@link ColumnViewerEditor#TABBING_CYCLE_IN_ROW}
  • + *
  • {@link ColumnViewerEditor#TABBING_HORIZONTAL}
  • + *
  • + * {@link ColumnViewerEditor#TABBING_MOVE_TO_ROW_NEIGHBOR}
  • + *
  • {@link ColumnViewerEditor#TABBING_VERTICAL}
  • + *
+ */ + public static void create(TableViewer viewer, + ColumnViewerEditorActivationStrategy editorActivationStrategy, + int feature) { + create(viewer, null, editorActivationStrategy, feature); + } + + protected void setEditor(Control w, Item item, int columnNumber) { + tableEditor.setEditor(w, (TableItem) item, columnNumber); + } + + protected void setLayoutData(LayoutData layoutData) { + tableEditor.grabHorizontal = layoutData.grabHorizontal; + tableEditor.horizontalAlignment = layoutData.horizontalAlignment; + tableEditor.minimumWidth = layoutData.minimumWidth; + } + + public ViewerCell getFocusCell() { + if (focusCellManager != null) { + return focusCellManager.getFocusCell(); + } + return super.getFocusCell(); + } + + protected void updateFocusCell(ViewerCell focusCell, + ColumnViewerEditorActivationEvent event) { + // Update the focus cell when we activated the editor with these 2 + // events + if (event.eventType == ColumnViewerEditorActivationEvent.PROGRAMMATIC + || event.eventType == ColumnViewerEditorActivationEvent.TRAVERSAL) { + if (focusCellManager != null) { + try { + if (DEBUG)System.err.println("FOCUS CELL: " + focusCell); + + Method m = AbstractTableViewer.class.getDeclaredMethod( + "getSelectionFromWidget", null); + m.setAccessible(true); + List l = (List) m.invoke(getViewer(), null); + if (focusCellManager != null) { + m = focusCellManager + .getClass() + .getSuperclass() + .getDeclaredMethod("setFocusCell", + new Class[] { ViewerCell.class }); + m.setAccessible(true); + m.invoke(focusCellManager, + new Object[] { focusCell }); + } + if (!l.contains(focusCell.getElement())) { + getViewer().setSelection( + new StructuredSelection(focusCell + .getElement())); + } + } catch (SecurityException e) { + e.printStackTrace(); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } catch (NoSuchMethodException e) { + e.printStackTrace(); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } + } + } + } + + protected void processTraverseEvent(int columnIndex, ViewerRow row, + TraverseEvent event) { + ViewerCell cell2edit = null; + if (event.detail == SWT.TRAVERSE_TAB_PREVIOUS) { + event.doit = false; + if ((event.stateMask & SWT.CTRL) == SWT.CTRL + && (feature & TABBING_VERTICAL) == TABBING_VERTICAL) { + cell2edit = searchCellAboveBelow(row, getViewer(), + columnIndex, true); + } else if ((feature & TABBING_HORIZONTAL) == TABBING_HORIZONTAL) { + cell2edit = searchPreviousCell(row, + row.getCell(columnIndex), row.getCell(columnIndex), + getViewer()); + } + } else if (event.detail == SWT.TRAVERSE_TAB_NEXT) { + event.doit = false; + if ((event.stateMask & SWT.CTRL) == SWT.CTRL + && (feature & TABBING_VERTICAL) == TABBING_VERTICAL) { + cell2edit = searchCellAboveBelow(row, getViewer(), + columnIndex, false); + } else if ((feature & TABBING_HORIZONTAL) == TABBING_HORIZONTAL) { + cell2edit = searchNextCell(row, row.getCell(columnIndex), + row.getCell(columnIndex), getViewer()); + } + } + if (DEBUG) System.err.println("NEXT CELL: " + cell2edit); + if (cell2edit != null) { + getViewer().getControl().setRedraw(false); + ColumnViewerEditorActivationEvent acEvent = new ColumnViewerEditorActivationEvent( + cell2edit, event); + try { + Method m = ColumnViewer.class + .getDeclaredMethod( + "triggerEditorActivationEvent", + new Class[] { ColumnViewerEditorActivationEvent.class }); + m.setAccessible(true); + m.invoke(getViewer(), new Object[] { acEvent }); + } catch (SecurityException e) { + e.printStackTrace(); + } catch (NoSuchMethodException e) { + e.printStackTrace(); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } + getViewer().getControl().setRedraw(true); + } + } + + private ViewerCell searchCellAboveBelow(ViewerRow row, + ColumnViewer viewer, int columnIndex, boolean above) { + ViewerCell rv = null; + ViewerRow newRow = null; + if (above) { + newRow = row.getNeighbor(ViewerRow.ABOVE, false); + } else { + newRow = row.getNeighbor(ViewerRow.BELOW, false); + } + try { + if (newRow != null) { + Method m = ColumnViewer.class.getDeclaredMethod( + "getViewerColumn", new Class[] { int.class }); + m.setAccessible(true); + ViewerColumn column = (ViewerColumn) m.invoke(viewer, + new Object[] { new Integer(columnIndex) }); + m = ViewerColumn.class.getDeclaredMethod( + "getEditingSupport", null); + m.setAccessible(true); + EditingSupport es = (EditingSupport) m.invoke(column, null); + if (column != null && es != null) { + m = EditingSupport.class.getDeclaredMethod("canEdit", + new Class[] { Object.class }); + m.setAccessible(true); + Boolean b = (Boolean) m.invoke(es, + new Object[] { newRow.getItem().getData() }); + if (b.booleanValue()) { + rv = newRow.getCell(columnIndex); + } + } else { + rv = searchCellAboveBelow(newRow, viewer, columnIndex, + above); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + return rv; + } + + private ViewerCell searchPreviousCell(ViewerRow row, + ViewerCell currentCell, ViewerCell originalCell, + ColumnViewer viewer) { + ViewerCell rv = null; + ViewerCell previousCell; + if (currentCell != null) { + previousCell = getNeighbor(currentCell, ViewerCell.LEFT, true); + } else { + if (row.getColumnCount() != 0) { + previousCell = row.getCell(getCreationIndex(row, + row.getColumnCount() - 1)); + } else { + previousCell = row.getCell(0); + } + } + // No endless loop + if (originalCell.equals(previousCell)) { + return null; + } + if (previousCell != null) { + if (isCellEditable(viewer, previousCell)) { + rv = previousCell; + } else { + rv = searchPreviousCell(row, previousCell, originalCell, + viewer); + } + } else { + if ((feature & TABBING_CYCLE_IN_ROW) == TABBING_CYCLE_IN_ROW) { + rv = searchPreviousCell(row, null, originalCell, viewer); + } else if ((feature & TABBING_MOVE_TO_ROW_NEIGHBOR) == TABBING_MOVE_TO_ROW_NEIGHBOR) { + ViewerRow rowAbove = row + .getNeighbor(ViewerRow.ABOVE, false); + if (rowAbove != null) { + rv = searchPreviousCell(rowAbove, null, originalCell, + viewer); + } + } + } + return rv; + } + + private ViewerCell searchNextCell(ViewerRow row, + ViewerCell currentCell, ViewerCell originalCell, + ColumnViewer viewer) { + ViewerCell rv = null; + ViewerCell nextCell; + if (currentCell != null) { + nextCell = getNeighbor(currentCell, ViewerCell.RIGHT, true); + } else { + nextCell = row.getCell(getCreationIndex(row, 0)); + } + // No endless loop + if (originalCell.equals(nextCell)) { + return null; + } + if (nextCell != null) { + if (isCellEditable(viewer, nextCell)) { + rv = nextCell; + } else { + rv = searchNextCell(row, nextCell, originalCell, viewer); + } + } else { + if ((feature & TABBING_CYCLE_IN_ROW) == TABBING_CYCLE_IN_ROW) { + rv = searchNextCell(row, null, originalCell, viewer); + } else if ((feature & TABBING_MOVE_TO_ROW_NEIGHBOR) == TABBING_MOVE_TO_ROW_NEIGHBOR) { + ViewerRow rowBelow = row + .getNeighbor(ViewerRow.BELOW, false); + if (rowBelow != null) { + rv = searchNextCell(rowBelow, null, originalCell, + viewer); + } + } + } + return rv; + } + + private boolean isCellEditable(ColumnViewer viewer, ViewerCell cell) { + try { + Method m = ColumnViewer.class.getDeclaredMethod( + "getViewerColumn", new Class[] { int.class }); + m.setAccessible(true); + ViewerColumn column = (ViewerColumn) m.invoke(viewer, + new Object[] { new Integer(cell.getColumnIndex()) }); + m = ViewerColumn.class.getDeclaredMethod("getEditingSupport", + null); + m.setAccessible(true); + EditingSupport es = (EditingSupport) m.invoke(column, null); + if (column != null && es != null) { + m = EditingSupport.class.getDeclaredMethod("canEdit", + new Class[] { Object.class }); + m.setAccessible(true); + // return true; + Boolean b = (Boolean) m.invoke(es, + new Object[] { cell.getElement() }); + return b.booleanValue(); + } + } catch (Exception e) { + e.printStackTrace(); + } + return false; + } + } + + // Reimplementation of ViewerCell-Methods + private static int getVisualIndex(ViewerRow row, int creationIndex) { + TableItem item = (TableItem) row.getItem(); + int[] order = item.getParent().getColumnOrder(); + for (int i = 0; i < order.length; i++) { + if (order[i] == creationIndex) { + return i; + } + } + return creationIndex; + } + + private static int getCreationIndex(ViewerRow row, int visualIndex) { + TableItem item = (TableItem) row.getItem(); + if (item != null && !item.isDisposed() /* + * && hasColumns() && + * isValidOrderIndex + * (visualIndex) + */) { + return item.getParent().getColumnOrder()[visualIndex]; + } + return visualIndex; + } + + private static ViewerCell getCellAtVisualIndex(ViewerRow row, + int visualIndex) { + return getCell(row, getCreationIndex(row, visualIndex)); + } + + private static boolean isVisible(ViewerCell cell) { + return getWidth(cell) > 0; + } + + private static int getWidth(ViewerCell cell) { + TableItem item = (TableItem) cell.getViewerRow().getItem(); + return item.getParent().getColumn(cell.getColumnIndex()).getWidth(); + } + + private static ViewerCell getCell(ViewerRow row, int index) { + return row.getCell(index); + } + + +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/property/BooleanPropertyManipulator.java b/org.simantics.g3d/src/org/simantics/g3d/property/BooleanPropertyManipulator.java new file mode 100644 index 00000000..88a74440 --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/property/BooleanPropertyManipulator.java @@ -0,0 +1,69 @@ +package org.simantics.g3d.property; + + +public class BooleanPropertyManipulator implements PropertyManipulator { + + ValueProvider provider; + Object input; + + boolean editMode; + String editValue = null; + + public BooleanPropertyManipulator(ValueProvider provider, Object input) { + this.provider = provider; + this.input = input; + } + + @Override + public int getValueCount() { + return 1; + } + + @Override + public String getDescription(int i) { + if (i == 0) + return "Value"; + return null; + } + + @Override + public String getValue(int i) { + if (editMode) + return editValue; + try { + return provider.getValue(input).toString(); + } catch (Exception e) { + return null; + } + } + + @Override + public String setValue(String value, int i) { + try { + editValue = value; + provider.setValue(input, Boolean.parseBoolean(value)); + } catch (Exception e) { + return e.getMessage(); + } + return null; + } + + @Override + public boolean getEditMode() { + return editMode; + } + + @Override + public void setEditMode(boolean b) { + editMode = b; + if (editMode) { + try { + editValue = provider.getValue(input).toString(); + } catch (Exception e) { + + } + } + + } + +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/property/DefaultPropertyManipulatorFactory.java b/org.simantics.g3d/src/org/simantics/g3d/property/DefaultPropertyManipulatorFactory.java new file mode 100644 index 00000000..c6074f27 --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/property/DefaultPropertyManipulatorFactory.java @@ -0,0 +1,38 @@ +package org.simantics.g3d.property; + +import java.lang.reflect.Method; + +import javax.vecmath.Quat4d; +import javax.vecmath.Vector3d; + +public class DefaultPropertyManipulatorFactory implements PropertyManipulatorFactory { + + @Override + public Class get(Method get, Object value) { + Class returnValue = null; + if (get != null) + returnValue = get.getReturnType(); + else + returnValue = value.getClass(); + if (Double.class.equals(returnValue)) + return DoublePropertyManipulator.class; + if (Vector3d.class.equals(returnValue)) + return VectorPropertyManipulator.class; + if (Quat4d.class.equals(returnValue)) + return QuatPropertyManipulator.class; + if (String.class.equals(returnValue)) + return StringPropertyManipulator.class; + if (Integer.class.equals(returnValue)) + return IntegerPropertyManipulator.class; + if (Boolean.class.equals(returnValue)) + return BooleanPropertyManipulator.class; + if(double.class.equals(returnValue)) + return DoublePropertyManipulator.class; + if(int.class.equals(returnValue)) + return IntegerPropertyManipulator.class; + if(boolean.class.equals(returnValue)) + return BooleanPropertyManipulator.class; + throw new RuntimeException("Cannot handle value " + returnValue.getName() + " for method " + get); + } + +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/property/DoublePropertyManipulator.java b/org.simantics.g3d/src/org/simantics/g3d/property/DoublePropertyManipulator.java new file mode 100644 index 00000000..7f120b27 --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/property/DoublePropertyManipulator.java @@ -0,0 +1,69 @@ +package org.simantics.g3d.property; + +import java.lang.reflect.Method; + +public class DoublePropertyManipulator implements PropertyManipulator { + + ValueProvider provider; + Object input; + + boolean editMode; + String editValue = null; + + public DoublePropertyManipulator(ValueProvider provider, Object input) { + this.provider = provider; + this.input = input; + } + + @Override + public int getValueCount() { + return 1; + } + + @Override + public String getDescription(int i) { + if (i == 0) + return "Value"; + return null; + } + + @Override + public String getValue(int i) { + if (editMode) + return editValue; + try { + return provider.getValue(input).toString(); + } catch (Exception e) { + return null; + } + } + + @Override + public String setValue(String value, int i) { + try { + editValue = value; + provider.setValue(input, Double.parseDouble(value)); + } catch (Exception e) { + return e.getMessage(); + } + return null; + } + + @Override + public boolean getEditMode() { + return editMode; + } + + @Override + public void setEditMode(boolean b) { + editMode = b; + if (editMode) { + try { + editValue = provider.getValue(input).toString(); + } catch (Exception e) { + + } + } + + } +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/property/IntegerPropertyManipulator.java b/org.simantics.g3d/src/org/simantics/g3d/property/IntegerPropertyManipulator.java new file mode 100644 index 00000000..b6243baf --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/property/IntegerPropertyManipulator.java @@ -0,0 +1,69 @@ +package org.simantics.g3d.property; + + +public class IntegerPropertyManipulator implements PropertyManipulator { + + ValueProvider provider; + Object input; + + boolean editMode; + String editValue = null; + + public IntegerPropertyManipulator(ValueProvider provider, Object input) { + this.provider = provider; + this.input = input; + } + + @Override + public int getValueCount() { + return 1; + } + + @Override + public String getDescription(int i) { + if (i == 0) + return "Value"; + return null; + } + + @Override + public String getValue(int i) { + if (editMode) + return editValue; + try { + return provider.getValue(input).toString(); + } catch (Exception e) { + return null; + } + } + + @Override + public String setValue(String value, int i) { + try { + editValue = value; + provider.setValue(input, Integer.parseInt(value)); + } catch (Exception e) { + return e.getMessage(); + } + return null; + } + + @Override + public boolean getEditMode() { + return editMode; + } + + @Override + public void setEditMode(boolean b) { + editMode = b; + if (editMode) { + try { + editValue = provider.getValue(input).toString(); + } catch (Exception e) { + + } + } + + } + +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/property/MethodValueProvider.java b/org.simantics.g3d/src/org/simantics/g3d/property/MethodValueProvider.java new file mode 100644 index 00000000..b75a1eb2 --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/property/MethodValueProvider.java @@ -0,0 +1,23 @@ +package org.simantics.g3d.property; + +import java.lang.reflect.Method; + +public class MethodValueProvider implements ValueProvider { + + Method getter; + Method setter; + + public MethodValueProvider(Method getter, Method setter) { + this.getter = getter; + this.setter = setter; + } + + @Override + public Object getValue(Object obj) throws Exception{ + return getter.invoke(obj); + } + @Override + public void setValue(Object obj, Object value) throws Exception { + setter.invoke(obj,value); + } +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/property/MethodWithMapValueProvider.java b/org.simantics.g3d/src/org/simantics/g3d/property/MethodWithMapValueProvider.java new file mode 100644 index 00000000..256de3ac --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/property/MethodWithMapValueProvider.java @@ -0,0 +1,31 @@ +package org.simantics.g3d.property; + +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +public class MethodWithMapValueProvider implements ValueProvider { + + Method getter; + Method setter; + String key; + + public MethodWithMapValueProvider(Method getter, Method setter, String key) { + this.getter = getter; + this.setter = setter; + this.key = key; + } + + @Override + public Object getValue(Object obj) throws Exception{ + Map map = (Map)getter.invoke(obj); + return map.get(key); + } + @Override + public void setValue(Object obj, Object value) throws Exception { + Map map = new HashMap(); + map.putAll((Map)getter.invoke(obj)); + map.put(key, value); + setter.invoke(obj,map); + } +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/property/PropertyManipulator.java b/org.simantics.g3d/src/org/simantics/g3d/property/PropertyManipulator.java new file mode 100644 index 00000000..3a502004 --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/property/PropertyManipulator.java @@ -0,0 +1,50 @@ +package org.simantics.g3d.property; + +/** + * Interfaces for manipulating properties. + * + * @author Marko Luukkainen + * + */ +public interface PropertyManipulator { + + /** + * Returns number of individual values. + * @return + */ + int getValueCount(); + + /** + * Returns value at given index. + * @param i + * @return + */ + String getValue(int i); + + /** + * Sets value at given index. + * @param i + * @return + */ + String setValue(String value, int i); + + /** + * Returns description of a value at given index. The description is shown in the table header. + * @param i + * @return + */ + String getDescription(int i); + + /** + * Gets edit mode status. + * @return + */ + boolean getEditMode(); + + /** + * Sets edit mode status. + * @param b + */ + void setEditMode(boolean b); + +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/property/PropertyManipulatorFactory.java b/org.simantics.g3d/src/org/simantics/g3d/property/PropertyManipulatorFactory.java new file mode 100644 index 00000000..8f6a91aa --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/property/PropertyManipulatorFactory.java @@ -0,0 +1,9 @@ +package org.simantics.g3d.property; + +import java.lang.reflect.Method; + +public interface PropertyManipulatorFactory { + + public Class get(Method get, Object value); + +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/property/PropertyTabContributor.java b/org.simantics.g3d/src/org/simantics/g3d/property/PropertyTabContributor.java new file mode 100644 index 00000000..18a3a7f2 --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/property/PropertyTabContributor.java @@ -0,0 +1,6 @@ +package org.simantics.g3d.property; + +public interface PropertyTabContributor extends org.simantics.selectionview.PropertyTabContributor{ + + public String getId(); +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/property/PropertyTabContributorFactory.java b/org.simantics.g3d/src/org/simantics/g3d/property/PropertyTabContributorFactory.java new file mode 100644 index 00000000..3b0e7ef5 --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/property/PropertyTabContributorFactory.java @@ -0,0 +1,10 @@ +package org.simantics.g3d.property; + +import java.util.List; + + +public interface PropertyTabContributorFactory { + + + public List getContributors(Object input); +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/property/PropertyTabUtil.java b/org.simantics.g3d/src/org/simantics/g3d/property/PropertyTabUtil.java new file mode 100644 index 00000000..4d006eea --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/property/PropertyTabUtil.java @@ -0,0 +1,35 @@ +package org.simantics.g3d.property; + +import java.util.Collections; +import java.util.List; + +import org.simantics.g3d.property.annotations.PropertyContributor; + +public class PropertyTabUtil { + + + @SuppressWarnings("unchecked") + public static List getContributors(Object input) { + PropertyTabContributorFactory factory = resolveFactory(input.getClass()); + if (factory == null) + return Collections.EMPTY_LIST; + return factory.getContributors(input); + } + + private static PropertyTabContributorFactory resolveFactory(Class clazz) { + PropertyContributor contributor = clazz.getAnnotation(PropertyContributor.class); + if (contributor != null) + try { + return contributor.value().newInstance(); + } catch (InstantiationException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + Class superClass = clazz.getSuperclass(); + if (superClass != null) + return resolveFactory(superClass); + return null; + } + +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/property/QuatPropertyManipulator.java b/org.simantics.g3d/src/org/simantics/g3d/property/QuatPropertyManipulator.java new file mode 100644 index 00000000..ca792ef7 --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/property/QuatPropertyManipulator.java @@ -0,0 +1,265 @@ +package org.simantics.g3d.property; + +import javax.vecmath.AxisAngle4d; +import javax.vecmath.Quat4d; +import javax.vecmath.Vector3d; + +import org.simantics.g3d.Activator; +import org.simantics.g3d.math.EulerTools; +import org.simantics.g3d.math.EulerTools.Order; +import org.simantics.g3d.math.MathTools; +import org.simantics.g3d.preferences.PreferenceConstants; + +public class QuatPropertyManipulator implements PropertyManipulator { + + ValueProvider provider; + protected Object input; + + enum EditType {QUATERNION,AXIS_ANGLE,EULER}; + + EditType type = EditType.QUATERNION; + Order order; + + boolean editMode; + Object editValue = null; + + public QuatPropertyManipulator(ValueProvider provider, Object input) { + this.provider = provider; + this.input = input; + + String set = Activator.getDefault().getPreferenceStore().getString(PreferenceConstants.ORIENTATION_PRESENTATION); + if ("quat".equals(set)) { + type = EditType.QUATERNION; + } else if ("aa".equals(set)) { + type = EditType.AXIS_ANGLE; + } else if ("euler".equals(set)) { + type = EditType.EULER; + String eulerOrder = Activator.getDefault().getPreferenceStore().getString(PreferenceConstants.EULER_ANGLE_ORDER); + order = Order.valueOf(eulerOrder); + if (order == null) + order = Order.YXZ; + } + } + + @Override + public String getDescription(int i) { + switch (type) { + case QUATERNION: + if (i == 0) + return "X"; + if (i == 1) + return "Y"; + if (i == 2) + return "Z"; + if (i == 3) + return "W"; + break; + case AXIS_ANGLE: + if (i == 0) + return "X"; + if (i == 1) + return "Y"; + if (i == 2) + return "Z"; + if (i == 3) + return "Angle"; + break; + case EULER: + if (i > 3) + return null; + return order.toString().substring(i, i+1); + default: + break; + } + return null; + } + + @Override + public int getValueCount() { + switch (type) { + case QUATERNION: + return 4; + case AXIS_ANGLE: + return 4; + case EULER: + return 3; + default: + break; + } + return 0; + } + + @Override + public String getValue(int i) { + try { + Quat4d q = (Quat4d) provider.getValue(input); + double d = 0; + switch (type) { + case QUATERNION: + if (editMode) + q = (Quat4d)editValue; + else + q = new Quat4d(q); + + if (i == 0) + d = q.x; + if (i == 1) + d = q.y; + if (i == 2) + d = q.z; + if (i == 3) + d = q.w; + break; + + case AXIS_ANGLE: { + AxisAngle4d aa; + if (editMode) + aa = (AxisAngle4d)editValue; + else { + aa = new AxisAngle4d(); + aa.set(q); + } + if (i == 0) + d = aa.x; + if (i == 1) + d = aa.y; + if (i == 2) + d = aa.z; + if (i == 3) + d = MathTools.radToDeg(aa.angle); + break; + } + case EULER: { + Vector3d aa; + if (editMode) + aa = (Vector3d)editValue; + else + aa = EulerTools.getEulerFromQuat(order, q);//MathTools.getEuler(q); + if (i == 0) + d = aa.x; + if (i == 1) + d = aa.y; + if (i == 2) + d = aa.z; + d = MathTools.radToDeg(d); + } + + default: + break; + } + return Double.toString(d); + } catch (Exception e) { + return null; + } + } + + + + @Override + public String setValue(String value, int i) { + try { + Double d = Double.parseDouble(value); + Quat4d q = (Quat4d) provider.getValue(input); + switch (type) { + case QUATERNION: + if (editMode) + q = (Quat4d)editValue; + else + q = new Quat4d(q); + + if (i == 0) + q.x = d; + if (i == 1) + q.y = d; + if (i == 2) + q.z = d; + if (i == 3) + q.w = d; + break; + case AXIS_ANGLE: { + AxisAngle4d aa; + if (editMode) + aa = (AxisAngle4d) editValue; + else { + aa = new AxisAngle4d(); + aa.set(q); + } + if (i == 0) + aa.x = d; + if (i == 1) + aa.y = d; + if (i == 2) + aa.z = d; + if (i == 3) + aa.angle = MathTools.degToRad(d); + q = new Quat4d(); + MathTools.getQuat(aa,q); + break; + } + case EULER: { + Vector3d e; + if (editMode) + e = (Vector3d)editValue; + else + e = EulerTools.getEulerFromQuat(order, q);//MathTools.getEuler(q); + d = MathTools.degToRad(d); + if (i == 0) + e.x = d; + if (i == 1) + e.y = d; + if (i == 2) + e.z = d; + q = EulerTools.getQuatFromEuler(order, e);//MathTools.getQuat(e); + } + default: + break; + } + q.normalize(); + setValue(q); + } catch (Exception e) { + return e.getMessage(); + } + return null; + } + + protected void setValue(Quat4d q) throws Exception { + provider.setValue(input, q); + } + + private void storeEditValue() { + try { + Quat4d q = (Quat4d) provider.getValue(input); + switch (type) { + case QUATERNION: + editValue = q; + break; + case AXIS_ANGLE: + AxisAngle4d aa = new AxisAngle4d(); + aa.set(q); + editValue = aa; + break; + case EULER: + Vector3d e = EulerTools.getEulerFromQuat(order, q); + editValue = e; + break; + } + } catch (Exception e) { + + } + } + + @Override + public boolean getEditMode() { + return editMode; + } + + @Override + public void setEditMode(boolean b) { + editMode = b; + if (editMode) { + storeEditValue(); + } + + } + +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/property/StringPropertyManipulator.java b/org.simantics.g3d/src/org/simantics/g3d/property/StringPropertyManipulator.java new file mode 100644 index 00000000..8e6cb46b --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/property/StringPropertyManipulator.java @@ -0,0 +1,69 @@ +package org.simantics.g3d.property; + +import java.lang.reflect.Method; + +public class StringPropertyManipulator implements PropertyManipulator { + + ValueProvider provider; + Object input; + + boolean editMode; + String editValue = null; + + public StringPropertyManipulator(ValueProvider provider, Object input) { + this.provider = provider; + this.input = input; + } + + @Override + public int getValueCount() { + return 1; + } + + @Override + public String getDescription(int i) { + if (i == 0) + return "Value"; + return null; + } + + @Override + public String getValue(int i) { + if (editMode) + return editValue; + try { + return provider.getValue(input).toString(); + } catch (Exception e) { + return null; + } + } + + @Override + public String setValue(String value, int i) { + try { + editValue = value; + provider.setValue(input, value); + } catch (Exception e) { + return e.getMessage(); + } + return null; + } + + @Override + public boolean getEditMode() { + return editMode; + } + + @Override + public void setEditMode(boolean b) { + editMode = b; + if (editMode) { + try { + editValue = provider.getValue(input).toString(); + } catch (Exception e) { + + } + } + + } +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/property/ValueProvider.java b/org.simantics.g3d/src/org/simantics/g3d/property/ValueProvider.java new file mode 100644 index 00000000..38ce9e1b --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/property/ValueProvider.java @@ -0,0 +1,9 @@ +package org.simantics.g3d.property; + +public interface ValueProvider { + + + Object getValue(Object obj) throws Exception; + void setValue(Object obj, Object value) throws Exception; + +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/property/VectorPropertyManipulator.java b/org.simantics.g3d/src/org/simantics/g3d/property/VectorPropertyManipulator.java new file mode 100644 index 00000000..84095eda --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/property/VectorPropertyManipulator.java @@ -0,0 +1,103 @@ +package org.simantics.g3d.property; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import javax.vecmath.Vector3d; + +public class VectorPropertyManipulator implements PropertyManipulator { + + ValueProvider provider; + protected Object input; + + boolean editMode; + Vector3d editValue = null; + + public VectorPropertyManipulator(ValueProvider provider, Object input) { + this.provider = provider; + this.input = input; + } + + @Override + public int getValueCount() { + return 3; + } + + @Override + public String getDescription(int i) { + if (i == 0) + return "X"; + if (i == 1) + return "Y"; + if (i == 2) + return "Z"; + return null; + } + + @Override + public String getValue(int i) { + try { + Vector3d v = _getValue(); + if (v == null) + return null; + if (i == 0) + return Double.toString(v.x); + if (i == 1) + return Double.toString(v.y); + if (i == 2) + return Double.toString(v.z); + return null; + } catch (Exception e) { + return null; + } + } + + @Override + public String setValue(String value, int i) { + try { + Double d = Double.parseDouble(value); + Vector3d v = _getValue(); + v = new Vector3d(v.x, v.y, v.z); + if (i == 0) + v.x = d; + if (i == 1) + v.y = d; + if (i == 2) + v.z = d; + editValue = v; + setValue(v); + } catch (Exception e) { + return e.getMessage(); + } + return null; + } + + protected void setValue(Vector3d v) throws Exception { + provider.setValue(input, v); + } + + private Vector3d _getValue() throws Exception{ + if (editMode) + return editValue; + return (Vector3d) provider.getValue(input); + } + + @Override + public boolean getEditMode() { + return editMode; + } + + @Override + public void setEditMode(boolean b) { + editMode = b; + if (editMode) { + try { + editValue = (Vector3d) provider.getValue(input); + } catch (Exception e) { + + } + } + + } + +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/property/annotations/CompoundGetPropertyValue.java b/org.simantics.g3d/src/org/simantics/g3d/property/annotations/CompoundGetPropertyValue.java new file mode 100644 index 00000000..a241d5ec --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/property/annotations/CompoundGetPropertyValue.java @@ -0,0 +1,18 @@ +package org.simantics.g3d.property.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.simantics.g3d.property.DefaultPropertyManipulatorFactory; +import org.simantics.g3d.property.PropertyManipulatorFactory; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface CompoundGetPropertyValue { + String value(); + String name() default ""; + String tabId() default "Default"; + Class manipulator() default DefaultPropertyManipulatorFactory.class; +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/property/annotations/CompoundSetPropertyValue.java b/org.simantics.g3d/src/org/simantics/g3d/property/annotations/CompoundSetPropertyValue.java new file mode 100644 index 00000000..067b5ce1 --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/property/annotations/CompoundSetPropertyValue.java @@ -0,0 +1,12 @@ +package org.simantics.g3d.property.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface CompoundSetPropertyValue { + String value(); +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/property/annotations/GetPropertyValue.java b/org.simantics.g3d/src/org/simantics/g3d/property/annotations/GetPropertyValue.java new file mode 100644 index 00000000..d79fb9a3 --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/property/annotations/GetPropertyValue.java @@ -0,0 +1,18 @@ +package org.simantics.g3d.property.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.simantics.g3d.property.DefaultPropertyManipulatorFactory; +import org.simantics.g3d.property.PropertyManipulatorFactory; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface GetPropertyValue { + String value(); + String name() default ""; + String tabId() default "Default"; + Class manipulator() default DefaultPropertyManipulatorFactory.class; +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/property/annotations/PropertyContributor.java b/org.simantics.g3d/src/org/simantics/g3d/property/annotations/PropertyContributor.java new file mode 100644 index 00000000..148b6eae --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/property/annotations/PropertyContributor.java @@ -0,0 +1,15 @@ +package org.simantics.g3d.property.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.simantics.g3d.property.AnnotatedPropertyTabContributorFactory; +import org.simantics.g3d.property.PropertyTabContributorFactory; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface PropertyContributor { + Class value() default AnnotatedPropertyTabContributorFactory.class; +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/property/annotations/PropertyTabBlacklist.java b/org.simantics.g3d/src/org/simantics/g3d/property/annotations/PropertyTabBlacklist.java new file mode 100644 index 00000000..7178a5c2 --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/property/annotations/PropertyTabBlacklist.java @@ -0,0 +1,13 @@ +package org.simantics.g3d.property.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface PropertyTabBlacklist { + String value() default ""; +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/property/annotations/SetPropertyValue.java b/org.simantics.g3d/src/org/simantics/g3d/property/annotations/SetPropertyValue.java new file mode 100644 index 00000000..b5ad4da1 --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/property/annotations/SetPropertyValue.java @@ -0,0 +1,12 @@ +package org.simantics.g3d.property.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface SetPropertyValue { + String value(); +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/scenegraph/G3DNode.java b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/G3DNode.java new file mode 100644 index 00000000..714e7a5b --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/G3DNode.java @@ -0,0 +1,149 @@ +package org.simantics.g3d.scenegraph; + +import javax.vecmath.Quat4d; +import javax.vecmath.Vector3d; + +import org.simantics.g3d.ontology.G3D; +import org.simantics.g3d.property.annotations.GetPropertyValue; +import org.simantics.g3d.property.annotations.PropertyContributor; +import org.simantics.g3d.property.annotations.SetPropertyValue; +import org.simantics.g3d.scenegraph.base.INode; +import org.simantics.g3d.scenegraph.base.Node; +import org.simantics.g3d.tools.NodeTools; +import org.simantics.objmap.graph.annotations.RelatedGetValue; +import org.simantics.objmap.graph.annotations.RelatedSetValue; + + +@PropertyContributor +public class G3DNode extends Node implements IG3DNode { + + private Vector3d position = new Vector3d(); + private Quat4d orientation = new Quat4d(0,0,0,1); + + @Override + @GetPropertyValue(value = G3D.URIs.hasOrientation, tabId = "Transform", name = "Orientation") + public Quat4d getOrientation() { + return orientation; + } + + @RelatedGetValue(G3D.URIs.hasOrientation) + public double[] getOrientationArr() { + double arr[] = new double[4]; + orientation.get(arr); + return arr; + + } + + @Override + @GetPropertyValue(value = G3D.URIs.hasPosition, tabId = "Transform", name = "Position") + public Vector3d getPosition() { + return position; + } + + @RelatedGetValue(G3D.URIs.hasPosition) + public double[] getPositionArr() { + double arr[] = new double[3]; + position.get(arr); + return arr; + } + + @Override + @SetPropertyValue(G3D.URIs.hasOrientation) + public void setOrientation(Quat4d orientation) { + assert(orientation != null); + this.orientation = orientation; + + firePropertyChanged(G3D.URIs.hasOrientation); + } + + @RelatedSetValue(G3D.URIs.hasOrientation) + public void setOrientation(double[] arr) { + if (arr == null) + return; + setOrientation(new Quat4d(arr)); + } + + @Override + @SetPropertyValue(G3D.URIs.hasPosition) + public void setPosition(Vector3d position) { + assert(position != null); + this.position = position; + + firePropertyChanged(G3D.URIs.hasPosition); + } + + @RelatedSetValue(G3D.URIs.hasPosition) + public void setPosition(double[] arr) { + if (arr == null) + return; + setPosition(new Vector3d(arr)); + } + + @Override + @GetPropertyValue(value = G3D.URIs.hasWorldPosition, tabId = "Transform", name = "World Position") + public Vector3d getWorldPosition() { + IG3DNode parent = (IG3DNode)getParent(); + if (parent == null) + return position; + return NodeTools.getWorldPosition(parent, new Vector3d(position)); + } + + + public Vector3d getWorldPosition(Vector3d localPosition) { + return NodeTools.getWorldPosition(this,localPosition); + } + + + @Override + @GetPropertyValue(value = G3D.URIs.hasWorldOrientation, tabId = "Transform", name = "World Orientation") + public Quat4d getWorldOrientation() { + return getWorldOrientation(new Quat4d(orientation)); + } + + public Quat4d getWorldOrientation(Quat4d localOrientation) { + IG3DNode parent = (IG3DNode)getParent(); + if (parent == null) + return localOrientation; + return NodeTools.getWorldOrientation(parent, localOrientation); + } + + @Override + public Vector3d getLocalPosition(Vector3d worldPosition) { + IG3DNode parent = (IG3DNode)getParent(); + if (parent == null) + return worldPosition; + return NodeTools.getLocalPosition(parent,new Vector3d(worldPosition)); + } + + @Override + public Quat4d getLocalOrientation(Quat4d worldOrientation) { + IG3DNode parent = (IG3DNode)getParent(); + if (parent == null) + return worldOrientation; + return NodeTools.getLocalOrientation(parent, new Quat4d(worldOrientation)); + } + + @Override + @SetPropertyValue(G3D.URIs.hasWorldPosition) + public void setWorldPosition(Vector3d position) { + Vector3d localPos = getLocalPosition(position); + setPosition(localPos); + } + + @Override + @SetPropertyValue(G3D.URIs.hasWorldOrientation) + public void setWorldOrientation(Quat4d orientation) { + Quat4d localOr = getLocalOrientation(orientation); + setOrientation(localOr); + } + + @Override + public Object getAdapter(Class adapter) { + if (INode.class == adapter) + return this; + if (IG3DNode.class == adapter) + return this; + return null; + } + +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/scenegraph/G3DparentNode.java b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/G3DparentNode.java new file mode 100644 index 00000000..8e5cc81b --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/G3DparentNode.java @@ -0,0 +1,138 @@ +package org.simantics.g3d.scenegraph; + +import javax.vecmath.Quat4d; +import javax.vecmath.Vector3d; + +import org.simantics.g3d.math.MathTools; +import org.simantics.g3d.ontology.G3D; +import org.simantics.g3d.property.annotations.GetPropertyValue; +import org.simantics.g3d.property.annotations.SetPropertyValue; +import org.simantics.g3d.scenegraph.base.ParentNode; +import org.simantics.g3d.tools.NodeTools; +import org.simantics.objmap.graph.annotations.RelatedGetValue; +import org.simantics.objmap.graph.annotations.RelatedSetValue; + + +public class G3DparentNode extends ParentNode implements IG3DNode{ + private Vector3d position = new Vector3d(); + private Quat4d orientation = MathTools.getIdentityQuat(); + + + @Override + @GetPropertyValue(value = G3D.URIs.hasOrientation, tabId = "Transform", name = "Orientation") + public Quat4d getOrientation() { + return orientation; + } + + @RelatedGetValue(G3D.URIs.hasOrientation) + public double[] getOrientationArr() { + double arr[] = new double[4]; + orientation.get(arr); + return arr; + + } + + @Override + @GetPropertyValue(value = G3D.URIs.hasPosition, tabId = "Transform", name = "Position") + public Vector3d getPosition() { + return position; + } + + @RelatedGetValue(G3D.URIs.hasPosition) + public double[] getPositionArr() { + double arr[] = new double[3]; + position.get(arr); + return arr; + } + + @Override + @SetPropertyValue(G3D.URIs.hasOrientation) + public void setOrientation(Quat4d orientation) { + assert(orientation != null); + this.orientation = orientation; + } + + @Override + @SetPropertyValue(G3D.URIs.hasPosition) + public void setPosition(Vector3d position) { + assert(position != null); + this.position = position; + } + + @RelatedSetValue(G3D.URIs.hasOrientation) + public void setOrientation(double[] arr) { + if (arr == null) + return; + setOrientation(new Quat4d(arr)); + } + + @RelatedSetValue(G3D.URIs.hasPosition) + public void setPosition(double[] arr) { + if (arr == null) + return; + setPosition(new Vector3d(arr)); + } + + @Override + @GetPropertyValue(value = G3D.URIs.hasWorldPosition, tabId = "Transform", name = "World Position") + public Vector3d getWorldPosition() { + IG3DNode parent = (IG3DNode)getParent(); + if (parent == null) + return position; + return NodeTools.getWorldPosition(parent, new Vector3d(position)); + } + + + public Vector3d getWorldPosition(Vector3d localPosition) { + return NodeTools.getWorldPosition(this,localPosition); + } + + + @Override + @GetPropertyValue(value = G3D.URIs.hasWorldOrientation, tabId = "Transform", name = "World Orientation") + public Quat4d getWorldOrientation() { + return getWorldOrientation(new Quat4d(orientation)); + } + + public Quat4d getWorldOrientation(Quat4d localOrientation) { + IG3DNode parent = (IG3DNode)getParent(); + if (parent == null) + return localOrientation; + return NodeTools.getWorldOrientation(parent, localOrientation); + } + + @Override + public Vector3d getLocalPosition(Vector3d worldPosition) { + IG3DNode parent = (IG3DNode)getParent(); + if (parent == null) + return worldPosition; + return NodeTools.getLocalPosition(parent,new Vector3d(worldPosition)); + } + + @Override + public Quat4d getLocalOrientation(Quat4d worldOrientation) { + IG3DNode parent = (IG3DNode)getParent(); + if (parent == null) + return worldOrientation; + return NodeTools.getLocalOrientation(parent, new Quat4d(worldOrientation)); + } + + @Override + @SetPropertyValue(G3D.URIs.hasWorldPosition) + public void setWorldPosition(Vector3d position) { + Vector3d localPos = getLocalPosition(position); + setPosition(localPos); + } + + @Override + @SetPropertyValue(G3D.URIs.hasWorldOrientation) + public void setWorldOrientation(Quat4d orientation) { + Quat4d localOr = getLocalOrientation(orientation); + setOrientation(localOr); + } + + @Override + public Object getAdapter(Class adapter) { + return null; + } +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/scenegraph/IG3DNode.java b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/IG3DNode.java new file mode 100644 index 00000000..4d54a281 --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/IG3DNode.java @@ -0,0 +1,35 @@ +package org.simantics.g3d.scenegraph; + +import javax.vecmath.Quat4d; +import javax.vecmath.Vector3d; + +import org.eclipse.core.runtime.IAdaptable; +import org.simantics.g3d.scenegraph.base.INode; + + +public interface IG3DNode extends INode, IAdaptable { + + + + public Vector3d getPosition(); + public void setPosition(Vector3d position); + + public Quat4d getOrientation(); + public void setOrientation(Quat4d orientation); + + public Vector3d getWorldPosition(); + public Quat4d getWorldOrientation(); + + public Vector3d getWorldPosition(Vector3d localPosition); + public Quat4d getWorldOrientation(Quat4d localOrientation); + + + public Vector3d getLocalPosition(Vector3d worldPosition); + public Quat4d getLocalOrientation(Quat4d worldOrientation); + + public void setWorldPosition(Vector3d position); + public void setWorldOrientation(Quat4d orientation); + + + +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/scenegraph/NodeHighlighter.java b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/NodeHighlighter.java new file mode 100644 index 00000000..155813c8 --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/NodeHighlighter.java @@ -0,0 +1,10 @@ +package org.simantics.g3d.scenegraph; + + +public interface NodeHighlighter { + + public static enum HighlightObjectType{Actor, Node}; + public static enum HighlightEventType{Selection, Hover, ClearSelection, ClearHover}; + + public void highlight(HighlightEventType type); +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/scenegraph/NodeMap.java b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/NodeMap.java new file mode 100644 index 00000000..d4f12da3 --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/NodeMap.java @@ -0,0 +1,48 @@ +package org.simantics.g3d.scenegraph; + +import java.util.Collection; + +import org.simantics.g3d.scenegraph.base.INode; +import org.simantics.g3d.scenegraph.base.NodeListener; +import org.simantics.g3d.scenegraph.base.ParentNode; + +public interface NodeMap { + + public Collection getRenderObjects(INode node); + + public void updateRenderObjectsFor(INode node); + + public INode getNode(T t); + + public ParentNode getRootNode(); + + /** + * Commit changes to the database. + */ + public void commit(); + + + /** + * Deletes (Disposes) the map. + */ + public void delete(); + + + /** + * Track changes that are going to be committed into the database. + * + * Disabling change tracking causes commit() to do nothing. + * @param enabled + */ + public void setChangeTracking(boolean enabled); + public boolean isChangeTracking(); + + + /** + * Add listener for all scene-graph events. + * @param listener + */ + public void addListener(NodeListener listener); + + public void removeListener(NodeListener listener); +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/scenegraph/NodeMapProvider.java b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/NodeMapProvider.java new file mode 100644 index 00000000..f44701e7 --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/NodeMapProvider.java @@ -0,0 +1,6 @@ +package org.simantics.g3d.scenegraph; + +public interface NodeMapProvider { + + public NodeMap getNodeMap(); +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/scenegraph/RenderListener.java b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/RenderListener.java new file mode 100644 index 00000000..af997a02 --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/RenderListener.java @@ -0,0 +1,6 @@ +package org.simantics.g3d.scenegraph; + +public interface RenderListener { + public void preRender(); + public void postRender(); +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/scenegraph/base/INode.java b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/base/INode.java new file mode 100644 index 00000000..dc03564a --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/base/INode.java @@ -0,0 +1,55 @@ +package org.simantics.g3d.scenegraph.base; + +import java.util.List; + + + + + +public interface INode { + + /** + * + * @return unique node identifier + */ + public Long getId(); + + /** + * @return root node of the scene graph or null if this node is + * not part of a properly rooted scene graph hierarchy + */ + public ParentNode getRootNode(); + + /** + * @return Parent node reference or null if not set + */ + public ParentNode getParent(); + + public String getParentRel(); + /** + * Set parent node. This method is for scene graph internal use only and + * should not be called outside the scene graph structure. This method + * simply sets the parent node parent field, and does not affect on parent + * node (i.e., should be called only from parent node). + */ + public void setParent(ParentNode parent, String name); + + /** + * Perform cleanup for this node and for the child nodes. Any resources + * (including child nodes) related to this node are unusable after this + * operation. This method is for scene graph internal use only, thus should + * not be called outside the scene graph structure. + */ + public void cleanup(); + /** + * Remove this node and its children from the scene graph. + */ + public void remove(); + + + public void addListener(NodeListener listener); + public void removeListener(NodeListener listener); + + public List getListeners(); + +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/scenegraph/base/Node.java b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/base/Node.java new file mode 100644 index 00000000..f2b9fe0f --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/base/Node.java @@ -0,0 +1,88 @@ +package org.simantics.g3d.scenegraph.base; + +import java.util.ArrayList; +import java.util.List; + + +public abstract class Node implements INode { + public transient static long IDCOUNTER = 1; + protected transient ParentNode parent = null; + protected transient String parentName = null; + protected Long id = IDCOUNTER++; + + + public Long getId() { + return id; + } + + + public ParentNode getParent() { + return parent; + } + + + @Override + public String getParentRel() { + return parentName; + } + + public void setParent(ParentNode parent, String name) { + this.parent = parent; + this.parentName = name; + } + + public ParentNode getRootNode() { + return parent != null ? parent.getRootNode() : null; + } + + public void remove() { + if (parent != null) { + parent.removeNode(parentName, this); + } + } + + public void deattach() { + if (parent != null) { + parent.deattachNode(parentName, this); + } + } + + public void init() { + } + + public void cleanup() { + if (parent != null) { + parent.removeNode(parentName, this); + } + } + + @Override + public String toString() { + return getClass().getSimpleName(); + } + + protected List listeners = new ArrayList(); + + @Override + public void addListener(NodeListener listener) { + if (!listeners.contains(listener)) + listeners.add(listener); + } + + @Override + public void removeListener(NodeListener listener) { + listeners.remove(listener); + } + + @Override + public List getListeners() { + return listeners; + } + + protected void firePropertyChanged(String id) { + for (NodeListener listener : listeners) { + listener.propertyChanged(this, id); + } + } + +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/scenegraph/base/NodeException.java b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/base/NodeException.java new file mode 100644 index 00000000..409a9894 --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/base/NodeException.java @@ -0,0 +1,14 @@ +package org.simantics.g3d.scenegraph.base; + +public class NodeException extends RuntimeException{ + + private static final long serialVersionUID = -6067907301659268L; + + public NodeException(String message) { + super(message); + } + + public NodeException(String message, Exception e) { + super(message,e); + } +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/scenegraph/base/NodeListener.java b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/base/NodeListener.java new file mode 100644 index 00000000..8131608e --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/base/NodeListener.java @@ -0,0 +1,29 @@ +package org.simantics.g3d.scenegraph.base; + + +public interface NodeListener { + + /** + * Event occurring when a node's property is changed + * @param node + * @param child + * @param rel + */ + public void propertyChanged(INode node, String id); + + /** + * Event occurring when a new node is added to the scene-graph + * @param node + * @param child + * @param rel + */ + public void nodeAdded(ParentNode node, INode child, String rel); + + /** + * Event occurring when a node is removed from the scene-graph + * @param nodeThe node, which contained the removed node. + * @param child The removed node. + * @param rel + */ + public void nodeRemoved(ParentNode node, INode child, String rel); +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/scenegraph/base/ParentNode.java b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/base/ParentNode.java new file mode 100644 index 00000000..68112177 --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/base/ParentNode.java @@ -0,0 +1,153 @@ +package org.simantics.g3d.scenegraph.base; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.simantics.utils.datastructures.MapList; + +public abstract class ParentNode extends Node { + + private MapList children = new MapList(); + + public synchronized void addNode(String relName, T child) { + if (child.getParent() != null) + child.getParent().removeNode(child.getParentRel(), child); + + child.setParent(this, relName); + children.add(relName, (T) child); + + childrenChanged(); + fireNodeAdded(child, relName); + } + + /** + * Removes child node and it's hierarchy. + * @param relName + * @param child + * @return + */ + @SuppressWarnings("unchecked") + public synchronized final boolean removeNode(String relName, INode child) { + if (children.remove(relName, (T) child)) { + fireNodeRemoved(child, relName); + child.remove(); + child.setParent(null, null); + return true; + } + return false; + } + + /** + * Removes child node. The child nodes hierarchy is left intact. + * @param relName + * @param child + * @return + */ + @SuppressWarnings("unchecked") + public synchronized final boolean deattachNode(String relName, INode child) { + if (children.remove(relName, (T) child)) { + fireNodeRemoved(child, relName); + child.setParent(null, null); + return true; + } + return false; + } + + public synchronized final boolean removeNodes(String relName) { + List nodes = children.getValues(relName); + for (T child : nodes) { + if (children.remove(relName, (T) child)) { + fireNodeRemoved(child, relName); + child.remove(); + child.setParent(null, null); + + } + } + return nodes.size() > 0; + } + + public synchronized final void removeNodes() { + synchronized (children) { + boolean changed = false; + for (String key : children.getKeys()) { + for (T child : children.getValues(key)) { + if (child != null) { + changed = true; + if (child instanceof ParentNode) { + ((ParentNode) child).removeNodes(); + } + child.cleanup(); + child.setParent(null, null); + // if (propertyChangeListener != null) { + // propertyChangeListener.propertyChange(new + // PropertyChangeEvent(this, + // "children["+child.getId()+"]", child.getClass(), + // NULL)); // "children" is a special field name + // } + } + } + } + children.clear(); + if (changed) + childrenChanged(); + } + } + + public synchronized List getNodes(String rel) { + return children.getValues(rel); + } + + public synchronized List getNodes() { + List result = new ArrayList(); + for (String s : children.getKeys()) + result.addAll(children.getValues(s)); + return result; + } + + protected void childrenChanged() { + } + + + @Override + public void remove() { + synchronized (children) { + List toRemove = new ArrayList(); + + for (String key : children.getKeys()) { + + for (T child : children.getValues(key)) { + if (child != null) { + toRemove.add(child); + } + } + } + + for (T n : toRemove) { + n.remove(); + } + + children.clear(); + if (toRemove.size() > 0) + childrenChanged(); + super.remove(); + + } + } + + + + + protected void fireNodeAdded(INode node, String rel) { + for (NodeListener listener : listeners) { + listener.nodeAdded(this, node, rel); + } + } + + protected void fireNodeRemoved(INode node, String rel) { + for (NodeListener listener : listeners) { + listener.nodeRemoved(this, node, rel); + } + } + +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/scenegraph/structural/ComponentNode.java b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/structural/ComponentNode.java new file mode 100644 index 00000000..0cbdddd1 --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/structural/ComponentNode.java @@ -0,0 +1,259 @@ +package org.simantics.g3d.scenegraph.structural; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import org.simantics.g3d.ontology.G3D; +import org.simantics.g3d.property.annotations.GetPropertyValue; +import org.simantics.g3d.property.annotations.SetPropertyValue; +import org.simantics.g3d.scenegraph.base.Node; +import org.simantics.layer0.Layer0; +import org.simantics.objmap.graph.annotations.RelatedGetValue; +import org.simantics.objmap.graph.annotations.RelatedSetValue; +import org.simantics.objmap.structural.IStructuralObject; +import org.simantics.utils.datastructures.MapList; + +public abstract class ComponentNode extends Node implements IComponentNode{ + + + private String name; + + + @RelatedGetValue(Layer0.URIs.HasName) + @GetPropertyValue(value = Layer0.URIs.HasName, tabId = "Default", name = "Name") + public String getName() { + return name; + } + + @RelatedSetValue(Layer0.URIs.HasName) + @SetPropertyValue(Layer0.URIs.HasName) + public void setName(String name) { + if (name == null) + return; + this.name = name; + firePropertyChanged(Layer0.URIs.HasName); + } + + @Override + public String toString() { + return getName(); + } + + public boolean isPartOfInstantiatedModel() { + return ctx.size() > 0; + } + + public boolean isExposed() { + if (ctx.size() == 0) + return true; + return getPublishedBy().contains(ctx.get(0)); + } + + @Override + public boolean isInstantiatedModelRoot() { + return ctx.size() == 1 && this.equals(ctx.get(0)); + } + + @Override + public boolean isPublishable() { + return !isPartOfInstantiatedModel(); + } + + private List ctx = new ArrayList(1); + @Override + public List getContext() { + return ctx; + } + + @Override + public void setContext(List object) { + ctx = object; + } + + private List publisher = new ArrayList(1); + + + + protected abstract boolean isValidConnectionId(String id); + + @Override + public void connectionChanged(T c, T2 node, boolean add) { + + } + + @Override + public void addPublishedBy(IStructuralNode node) { + publisher.add(node); + firePropertyChanged(G3D.URIs.publishes); + } + + @Override + public Collection getPublishedBy() { + return publisher; + } + + @Override + public void removePublishedBy(IStructuralNode node) { + if (publisher.remove(node)) + firePropertyChanged(G3D.URIs.publishes); + } + + + @Override + public List getConnections(String id) { + List list = new ArrayList(); + list.addAll(connections.getValues(id)); + list.addAll(connections.getValues(id+"/str")); + return list; + } + + public List getAllConnectedNodes() { + List list = new ArrayList(); + for (T c : getAllConnections()) { + T2 node = (T2)c.getOther(this); + if (node != null) + list.add(node); + } + return list; + } + + + @Override + public void addConnection(String id, T c) { + assert(isValidConnectionId(id)); + if (!isPartOfInstantiatedModel()) + _addConnection(id, c); + else + _addConnection(id+"/str", c); + } + + @Override + public void removeConnection(String id, T c) { + assert(isValidConnectionId(id)); + if (!isPartOfInstantiatedModel()) + _removeConnection(id, c); + else + _removeConnection(id+"/str", c); + } + + @Override + public void removeConnection(String id) { + assert(isValidConnectionId(id)); + if (!isPartOfInstantiatedModel()) + _removeConnection(id); + else + _removeConnection(id+"/str"); + } + + private MapList connections = new MapList(); + + + protected void _addConnection(String id, T c) { + connections.add(id, c); + c.addConnect(this); + firePropertyChanged(id); + } + + protected void _addStrConnection(String id, T c) { + _addConnection(id+"/str", c); + } + + protected MapList _getConnections() { + return connections; + } + + protected List _getConnections(String id) { + return connections.getValues(id); + } + + protected List _getStrConnections(String id) { + return _getConnections(id+"/str"); + } + + protected void _removeConnection(String id, T c) { + if (connections.remove(id, c)) { + c.remove(); + firePropertyChanged(id); + } + } + + protected void _removeConnection(String id) { + List conns = new ArrayList(); + conns.addAll(_getConnections(id)); + for (T c : conns) { + _removeConnection(id, c); + } + } + + protected void _removeStrConnection(String id, T c) { + _removeConnection(id+"/str", c); + } + + public List getAllConnections() { + List list = new ArrayList(); + List keys = new ArrayList(); + keys.addAll(connections.getKeys()); + Collections.sort(keys); + for (String s : keys) + list.addAll(connections.getValues(s)); + return list; + } + + public void removeConnection(T c) { + String keys[] = connections.getKeys(new String[connections.getKeySize()]); + for (String s : keys) { + if (connections.contains(s, c)) + _removeConnection(s, c); + } + } + + public List getConnectedNodes(String id) { + List list = new ArrayList(); + for (T c : getConnections(id)) { + T2 node = (T2)c.getOther(this); + if (node != null) + list.add(node); + } + return list; + } + + @Override + public String getConnectionId(T c) { + for (String s : connections.getKeys()) { + if (connections.contains(s, c)) { + if (!s.endsWith("/str")) + return s; + return s.substring(0, s.length()-4); + } + } + return null; + } + + @Override + public Collection getConnectionIds(T2 node) { + Collection ids = new ArrayList(); + for (String s : connections.getKeys()) { + for (T c : connections.getValues(s)) { + if (node.equals(c.getOther(this))) { + if (!s.endsWith("/str")) + ids.add(s); + else + ids.add(s.substring(0, s.length()-4)); + } + } + } + return ids; + } + + @Override + public void remove() { + List connections = getAllConnections(); + for (T c : connections) { + removeConnection(c); + } + super.remove(); + + } +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/scenegraph/structural/Connection.java b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/structural/Connection.java new file mode 100644 index 00000000..9f96205b --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/structural/Connection.java @@ -0,0 +1,76 @@ +package org.simantics.g3d.scenegraph.structural; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.simantics.db.Resource; +import org.simantics.objmap.structural.IStructuralObject; + +@SuppressWarnings("rawtypes") +public abstract class Connection implements IStructuralObject{ + + + private List connects = new ArrayList(); + + + public void addConnect(T node) { + if (!connects.contains(node)) + connects.add(node); + fireChanged(node,true); + } + + protected void fireChanged(T node, boolean add){ + for (IComponentNode n : connects) { + n.connectionChanged(this,node,add); + } + } + + public Collection getConnected() { + return connects; + } + + public void removeConnect(T node) { + connects.remove(node); + fireChanged(node,false); + } + + public void remove() { + List toRemove = new ArrayList(connects.size()); + toRemove.addAll(connects); + for (IComponentNode node : toRemove) { + node.removeConnection(this); + } + } + + public T getOther(T node) { + if (connects.size() != 2) + return null; + if (connects.get(0).equals(node)) + return connects.get(1); + else if (connects.get(1).equals(node)) + return connects.get(0); + return null; + } + + @Override + public void setType(Resource type) { + + } + + @Override + public Resource getType() { + return null; + } + + private List ctx = new ArrayList(1); + @Override + public List getContext() { + return ctx; + } + + @Override + public void setContext(List object) { + ctx = object; + } +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/scenegraph/structural/G3DComponentNode.java b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/structural/G3DComponentNode.java new file mode 100644 index 00000000..d9a6777f --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/structural/G3DComponentNode.java @@ -0,0 +1,259 @@ +package org.simantics.g3d.scenegraph.structural; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import org.simantics.g3d.ontology.G3D; +import org.simantics.g3d.property.annotations.GetPropertyValue; +import org.simantics.g3d.property.annotations.SetPropertyValue; +import org.simantics.g3d.scenegraph.G3DNode; +import org.simantics.layer0.Layer0; +import org.simantics.objmap.graph.annotations.RelatedGetValue; +import org.simantics.objmap.graph.annotations.RelatedSetValue; +import org.simantics.objmap.structural.IStructuralObject; +import org.simantics.utils.datastructures.MapList; + +public abstract class G3DComponentNode extends G3DNode implements IComponentNode{ + + + private String name; + + + @RelatedGetValue(Layer0.URIs.HasName) + @GetPropertyValue(value = Layer0.URIs.HasName, tabId = "Default", name = "Name") + public String getName() { + return name; + } + + @RelatedSetValue(Layer0.URIs.HasName) + @SetPropertyValue(Layer0.URIs.HasName) + public void setName(String name) { + if (name == null) + return; + this.name = name; + firePropertyChanged(Layer0.URIs.HasName); + } + + @Override + public String toString() { + return getName(); + } + + public boolean isPartOfInstantiatedModel() { + return ctx.size() > 0; + } + + public boolean isExposed() { + if (ctx.size() == 0) + return true; + return getPublishedBy().contains(ctx.get(0)); + } + + @Override + public boolean isInstantiatedModelRoot() { + return ctx.size() == 1 && this.equals(ctx.get(0)); + } + + @Override + public boolean isPublishable() { + return !isPartOfInstantiatedModel(); + } + + private List ctx = new ArrayList(1); + @Override + public List getContext() { + return ctx; + } + + @Override + public void setContext(List object) { + ctx = object; + } + + private List publisher = new ArrayList(1); + + + + protected abstract boolean isValidConnectionId(String id); + + @Override + public void connectionChanged(T c, T2 node, boolean add) { + + } + + @Override + public void addPublishedBy(IStructuralNode node) { + publisher.add(node); + firePropertyChanged(G3D.URIs.publishes); + } + + @Override + public Collection getPublishedBy() { + return publisher; + } + + @Override + public void removePublishedBy(IStructuralNode node) { + if (publisher.remove(node)) + firePropertyChanged(G3D.URIs.publishes); + } + + + @Override + public List getConnections(String id) { + List list = new ArrayList(); + list.addAll(connections.getValues(id)); + list.addAll(connections.getValues(id+"/str")); + return list; + } + + public List getAllConnectedNodes() { + List list = new ArrayList(); + for (T c : getAllConnections()) { + T2 node = (T2)c.getOther(this); + if (node != null) + list.add(node); + } + return list; + } + + + @Override + public void addConnection(String id, T c) { + assert(isValidConnectionId(id)); + if (!isPartOfInstantiatedModel()) + _addConnection(id, c); + else + _addConnection(id+"/str", c); + } + + @Override + public void removeConnection(String id, T c) { + assert(isValidConnectionId(id)); + if (!isPartOfInstantiatedModel()) + _removeConnection(id, c); + else + _removeConnection(id+"/str", c); + } + + @Override + public void removeConnection(String id) { + assert(isValidConnectionId(id)); + if (!isPartOfInstantiatedModel()) + _removeConnection(id); + else + _removeConnection(id+"/str"); + } + + private MapList connections = new MapList(); + + + protected void _addConnection(String id, T c) { + connections.add(id, c); + c.addConnect(this); + firePropertyChanged(id); + } + + protected void _addStrConnection(String id, T c) { + _addConnection(id+"/str", c); + } + + protected MapList _getConnections() { + return connections; + } + + protected List _getConnections(String id) { + return connections.getValues(id); + } + + protected List _getStrConnections(String id) { + return _getConnections(id+"/str"); + } + + protected void _removeConnection(String id, T c) { + if (connections.remove(id, c)) { + c.remove(); + firePropertyChanged(id); + } + } + + protected void _removeConnection(String id) { + List conns = new ArrayList(); + conns.addAll(_getConnections(id)); + for (T c : conns) { + _removeConnection(id, c); + } + } + + protected void _removeStrConnection(String id, T c) { + _removeConnection(id+"/str", c); + } + + public List getAllConnections() { + List list = new ArrayList(); + List keys = new ArrayList(); + keys.addAll(connections.getKeys()); + Collections.sort(keys); + for (String s : keys) + list.addAll(connections.getValues(s)); + return list; + } + + public void removeConnection(T c) { + String keys[] = connections.getKeys(new String[connections.getKeySize()]); + for (String s : keys) { + if (connections.contains(s, c)) + _removeConnection(s, c); + } + } + + public List getConnectedNodes(String id) { + List list = new ArrayList(); + for (T c : getConnections(id)) { + T2 node = (T2)c.getOther(this); + if (node != null) + list.add(node); + } + return list; + } + + @Override + public String getConnectionId(T c) { + for (String s : connections.getKeys()) { + if (connections.contains(s, c)) { + if (!s.endsWith("/str")) + return s; + return s.substring(0, s.length()-4); + } + } + return null; + } + + @Override + public Collection getConnectionIds(T2 node) { + Collection ids = new ArrayList(); + for (String s : connections.getKeys()) { + for (T c : connections.getValues(s)) { + if (node.equals(c.getOther(this))) { + if (!s.endsWith("/str")) + ids.add(s); + else + ids.add(s.substring(0, s.length()-4)); + } + } + } + return ids; + } + + @Override + public void remove() { + List connections = getAllConnections(); + for (T c : connections) { + removeConnection(c); + } + super.remove(); + + } +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/scenegraph/structural/G3DStructuralParentNode.java b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/structural/G3DStructuralParentNode.java new file mode 100644 index 00000000..7a99b8c1 --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/structural/G3DStructuralParentNode.java @@ -0,0 +1,171 @@ +package org.simantics.g3d.scenegraph.structural; + +import java.util.Collection; + +import javax.vecmath.Quat4d; +import javax.vecmath.Vector3d; + +import org.simantics.g3d.math.MathTools; +import org.simantics.g3d.ontology.G3D; +import org.simantics.g3d.property.annotations.GetPropertyValue; +import org.simantics.g3d.property.annotations.SetPropertyValue; +import org.simantics.g3d.scenegraph.IG3DNode; +import org.simantics.g3d.scenegraph.base.INode; +import org.simantics.g3d.scenegraph.base.NodeException; +import org.simantics.g3d.tools.NodeTools; +import org.simantics.objmap.graph.annotations.RelatedGetValue; +import org.simantics.objmap.graph.annotations.RelatedSetValue; + +public abstract class G3DStructuralParentNode extends StructuralParentNode implements IG3DNode{ + private Vector3d position = new Vector3d(); + private Quat4d orientation = MathTools.getIdentityQuat(); + + + @GetPropertyValue(value = G3D.URIs.hasOrientation, tabId = "Transform", name = "Orientation") + public Quat4d getOrientation() { + if (getParent() == null) + return MathTools.getIdentityQuat(); + return orientation; + }; + + @Override + @GetPropertyValue(value = G3D.URIs.hasPosition, tabId = "Transform", name = "Position") + public Vector3d getPosition() { + if (getParent() == null) + return MathTools.ORIGIN; + return position; + } + + @Override + @GetPropertyValue(value = G3D.URIs.hasWorldOrientation, tabId = "Transform", name = "World Orientation") + public Quat4d getWorldOrientation() { + if (getParent() == null) + return MathTools.getIdentityQuat(); + return getWorldOrientation(orientation); + } + + @Override + @GetPropertyValue(value = G3D.URIs.hasWorldPosition, tabId = "Transform", name = "World Position") + public Vector3d getWorldPosition() { + IG3DNode parent = (IG3DNode)getParent(); + if (parent == null) + return MathTools.ORIGIN; + return NodeTools.getWorldPosition(parent, new Vector3d(position)); + } + + @Override + public Quat4d getWorldOrientation(Quat4d localOrientation) { + IG3DNode parent = (IG3DNode)getParent(); + if (parent == null) + return localOrientation; + return NodeTools.getWorldOrientation(parent, localOrientation); + } + + + public Vector3d getWorldPosition(Vector3d localPosition) { + return NodeTools.getWorldPosition(this,localPosition); + } + + @Override + public Quat4d getLocalOrientation(Quat4d worldOrientation) { + IG3DNode parent = (IG3DNode)getParent(); + if (parent == null) + return worldOrientation; + return NodeTools.getLocalOrientation(parent, new Quat4d(worldOrientation)); + } + + @Override + public Vector3d getLocalPosition(Vector3d worldPosition) { + IG3DNode parent = (IG3DNode)getParent(); + if (parent == null) + return worldPosition; + return NodeTools.getLocalPosition(parent,new Vector3d(worldPosition)); + } + + @Override + @SetPropertyValue(G3D.URIs.hasPosition) + public void setPosition(Vector3d position) { + this.position = position; + firePropertyChanged(G3D.URIs.hasPosition); + } + + @Override + @SetPropertyValue(G3D.URIs.hasOrientation) + public void setOrientation(Quat4d orientation) { + this.orientation = orientation; + firePropertyChanged(G3D.URIs.hasOrientation); + } + + @Override + @SetPropertyValue(G3D.URIs.hasWorldOrientation) + public void setWorldOrientation(Quat4d orientation) { + if (getParent() == null) + throw new NodeException("Cannot set root node orientation"); + Quat4d localOr = getLocalOrientation(orientation); + setOrientation(localOr); + } + + @Override + @SetPropertyValue(G3D.URIs.hasWorldPosition) + public void setWorldPosition(Vector3d position) { + if (getParent() == null) + throw new NodeException("Cannot set root node position"); + Vector3d localPos = getLocalPosition(position); + setPosition(localPos); + } + + + + @RelatedGetValue(G3D.URIs.hasOrientation) + public double[] getOrientationArr() { + double arr[] = new double[4]; + orientation.get(arr); + return arr; + + } + + @RelatedGetValue(G3D.URIs.hasPosition) + public double[] getPositionArr() { + double arr[] = new double[3]; + position.get(arr); + return arr; + } + + @RelatedSetValue(G3D.URIs.hasOrientation) + public void setOrientation(double[] arr) { + if (arr == null) + return; + setOrientation(new Quat4d(arr)); + } + + @RelatedSetValue(G3D.URIs.hasPosition) + public void setPosition(double[] arr) { + if (arr == null) + return; + setPosition(new Vector3d(arr)); + } + + + protected void _addStrNode(String id, T child) { + addNode(id+"/str", child); + } + + protected boolean _removeStrNode(String id, T child) { + return removeNode(id+"/str", child); + } + + protected Collection _getStrNodes(String id) { + return getNodes(id+"/str"); + } + + public Object getAdapter(Class adapter) { + if (INode.class == adapter) + return this; + if (IG3DNode.class == adapter) + return this; + return null; + } + + + +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/scenegraph/structural/IComponentNode.java b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/structural/IComponentNode.java new file mode 100644 index 00000000..ac482b18 --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/structural/IComponentNode.java @@ -0,0 +1,25 @@ +package org.simantics.g3d.scenegraph.structural; + +import java.util.Collection; +import java.util.List; + + +@SuppressWarnings("rawtypes") +public interface IComponentNode extends IStructuralNode{ + + public List getAllConnections(); + //public void addConnection(Connection c); + public void removeConnection(T c); + public void connectionChanged(T c, T2 node, boolean add); + + public List getConnections(String id); + public void addConnection(String id,T c); + public void removeConnection(String id,T c); + public void removeConnection(String id); + + public String getConnectionId(T c); + public Collection getConnectionIds(T2 node); + public List getAllConnectedNodes(); + public List getConnectedNodes(String id); + +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/scenegraph/structural/IStructuralNode.java b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/structural/IStructuralNode.java new file mode 100644 index 00000000..612ea6dd --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/structural/IStructuralNode.java @@ -0,0 +1,22 @@ +package org.simantics.g3d.scenegraph.structural; + +import java.util.Collection; + +import org.simantics.g3d.scenegraph.base.INode; +import org.simantics.objmap.structural.IStructuralObject; + +public interface IStructuralNode extends INode, IStructuralObject { + + public String getName(); + + public boolean isPartOfInstantiatedModel(); + public boolean isExposed(); + public boolean isInstantiatedModelRoot(); + public boolean isPublishable(); + + + + public Collection getPublishedBy(); + public void addPublishedBy(IStructuralNode node); + public void removePublishedBy(IStructuralNode node); +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/scenegraph/structural/IStructuralRootNode.java b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/structural/IStructuralRootNode.java new file mode 100644 index 00000000..b1589931 --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/structural/IStructuralRootNode.java @@ -0,0 +1,43 @@ +package org.simantics.g3d.scenegraph.structural; + +import java.util.Collection; + +import org.simantics.layer0.Layer0; +import org.simantics.objmap.graph.annotations.RelatedElementsAdd; +import org.simantics.objmap.graph.annotations.RelatedElementsGet; +import org.simantics.objmap.graph.annotations.RelatedElementsRem; +import org.simantics.objmap.structural.annotations.TypeRelatedElementsAdd; +import org.simantics.objmap.structural.annotations.TypeRelatedElementsGet; +import org.simantics.objmap.structural.annotations.TypeRelatedElementsRem; + +public interface IStructuralRootNode extends IStructuralNode { + + @RelatedElementsAdd(Layer0.URIs.ConsistsOf) + public void addComponent(IStructuralNode node); + @RelatedElementsGet(Layer0.URIs.ConsistsOf) + public Collection getComponent(); + @RelatedElementsRem(Layer0.URIs.ConsistsOf) + public void removeComponent(IStructuralNode node); + + @TypeRelatedElementsAdd(Layer0.URIs.ConsistsOf) + public void addTypeComponent(IStructuralNode node); + @TypeRelatedElementsGet(Layer0.URIs.ConsistsOf) + public Collection getTypeComponent(); + @TypeRelatedElementsRem(Layer0.URIs.ConsistsOf) + public void removeTypeComponent(IStructuralNode node); + + @RelatedElementsAdd(Layer0.URIs.DomainOf) + public void addPublished(IStructuralNode node); + @RelatedElementsGet(Layer0.URIs.DomainOf) + public Collection getPublished(); + @RelatedElementsRem(Layer0.URIs.DomainOf) + public void removePublished(IStructuralNode node); + + @TypeRelatedElementsAdd(Layer0.URIs.DomainOf) + public void addTypePublished(IStructuralNode node); + @TypeRelatedElementsGet(Layer0.URIs.DomainOf) + public Collection getTypePublished(); + @TypeRelatedElementsRem(Layer0.URIs.DomainOf) + public void removeTypePublished(IStructuralNode node); + +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/scenegraph/structural/StructuralParentNode.java b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/structural/StructuralParentNode.java new file mode 100644 index 00000000..d5e41a5c --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/structural/StructuralParentNode.java @@ -0,0 +1,99 @@ +package org.simantics.g3d.scenegraph.structural; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.simantics.g3d.ontology.G3D; +import org.simantics.g3d.property.annotations.GetPropertyValue; +import org.simantics.g3d.property.annotations.SetPropertyValue; +import org.simantics.g3d.scenegraph.base.ParentNode; +import org.simantics.layer0.Layer0; +import org.simantics.objmap.graph.annotations.RelatedGetValue; +import org.simantics.objmap.graph.annotations.RelatedSetValue; +import org.simantics.objmap.structural.IStructuralObject; + +public abstract class StructuralParentNode extends ParentNode implements IStructuralNode{ + + private String name; + + + @RelatedGetValue(Layer0.URIs.HasName) + @GetPropertyValue(value = Layer0.URIs.HasName, tabId = "Default", name = "Name") + public String getName() { + return name; + } + + @RelatedSetValue(Layer0.URIs.HasName) + @SetPropertyValue(Layer0.URIs.HasName) + public void setName(String name) { + if (name == null) + return; + this.name = name; + firePropertyChanged(Layer0.URIs.HasName); + } + + @Override + public String toString() { + return getName(); + } + + public boolean isPartOfInstantiatedModel() { + return ctx.size() > 0; + } + + public boolean isExposed() { + if (ctx.size() == 0) + return true; + return getPublishedBy().contains(ctx.get(0)); + } + + @Override + public boolean isInstantiatedModelRoot() { + return ctx.size() == 1 && this.equals(ctx.get(0)); + } + + @Override + public boolean isPublishable() { + return !isPartOfInstantiatedModel(); + } + + private List ctx = new ArrayList(1); + @Override + public List getContext() { + return ctx; + } + + @Override + public void setContext(List object) { + ctx = object; + } + + private List publisher = new ArrayList(1); + + @Override + public void addPublishedBy(IStructuralNode node) { + publisher.add(node); + firePropertyChanged(G3D.URIs.publishes); + } + + @Override + public Collection getPublishedBy() { + return publisher; + } + + @Override + public void removePublishedBy(IStructuralNode node) { + if (publisher.remove(node)) + firePropertyChanged(G3D.URIs.publishes); + } + + @Override + public void remove() { + IStructuralRootNode root = (IStructuralRootNode)getRootNode(); + if (root.getPublished().contains(this)) + root.removePublished(this); + + super.remove(); + } +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/shape/Color4d.java b/org.simantics.g3d/src/org/simantics/g3d/shape/Color4d.java new file mode 100644 index 00000000..5578d850 --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/shape/Color4d.java @@ -0,0 +1,30 @@ +package org.simantics.g3d.shape; + +import javax.vecmath.Tuple4d; +import javax.vecmath.Tuple4f; + +public class Color4d extends Tuple4d{ + + private static final long serialVersionUID = -4217159803441535837L; + + public Color4d() { + super(); + } + + public Color4d(double x, double y, double z, double w) { + super(x, y, z, w); + } + + public Color4d(double[] t) { + super(t); + } + + public Color4d(Tuple4d t1) { + super(t1); + } + + public Color4d(Tuple4f t1) { + super(t1); + } + +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/shape/Cone.java b/org.simantics.g3d/src/org/simantics/g3d/shape/Cone.java new file mode 100644 index 00000000..19f9200f --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/shape/Cone.java @@ -0,0 +1,64 @@ +package org.simantics.g3d.shape; + +import java.util.ArrayList; +import java.util.List; + +import javax.vecmath.AxisAngle4d; +import javax.vecmath.Vector3d; + +import org.simantics.g3d.math.MathTools; + +public class Cone { + + public static Mesh create(double radius, int s) { + if (s < 3 || radius < MathTools.NEAR_ZERO) + throw new IllegalArgumentException(); + List vertices = new ArrayList(s+2); + List normals = new ArrayList(vertices.size()); + List indices = new ArrayList(); + + vertices.add(new Vector3d(0.0,0.0,0.0)); + normals.add(new Vector3d(0.0,-1.0,0.0)); + vertices.add(new Vector3d(0.0,radius*2.0,0.0)); + normals.add(new Vector3d(0.0,1.0,0.0)); + + Vector3d v = new Vector3d(radius,0,0); + for (int i = 0; i < s; i++) { + AxisAngle4d aa = new AxisAngle4d(0,1,0,((double)i/(double)s)*Math.PI * 2); + Vector3d t = new Vector3d(); + MathTools.rotate(MathTools.getQuat(aa), v, t); + vertices.add(t); + Vector3d n = new Vector3d(t); + n.normalize(); + normals.add(n); + } + + for (int i = 0; i < s; i++) { + indices.add(0); + + if (i < s - 1) + indices.add(i + 3); + else + indices.add(2); + indices.add(i + 2); + } + + for (int i = 0; i < s; i++) { + indices.add(1); + indices.add(i + 2); + if (i < s - 1) + indices.add(i + 3); + else + indices.add(2); + + } + return new Mesh(vertices,normals,indices); + + } + + public static void main(String arg[]) { + Mesh s1 = create(1.0, 3); + Mesh s2 = create(1.0, 4); + System.out.println("debug " + s1 + "\n" + s2); + } +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/shape/Cylinder.java b/org.simantics.g3d/src/org/simantics/g3d/shape/Cylinder.java new file mode 100644 index 00000000..870abce0 --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/shape/Cylinder.java @@ -0,0 +1,23 @@ +package org.simantics.g3d.shape; + +import java.util.ArrayList; +import java.util.List; + +import javax.vecmath.Vector3d; + +public class Cylinder { + + public static Mesh create(Vector3d start, Vector3d dir, double r, int s) { + Tube tube = new Tube(); + tube.setResolution(s); + tube.setRadius(r); + List vertices = new ArrayList(); + vertices.add(start); + Vector3d t = new Vector3d(start); + t.add(dir); + vertices.add(dir); + tube.setVertices(vertices); + return tube.create(); + } + +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/shape/Mesh.java b/org.simantics.g3d/src/org/simantics/g3d/shape/Mesh.java new file mode 100644 index 00000000..83aa3607 --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/shape/Mesh.java @@ -0,0 +1,137 @@ +package org.simantics.g3d.shape; + +import java.util.ArrayList; +import java.util.List; + +import javax.vecmath.Quat4d; +import javax.vecmath.Vector3d; + +import org.simantics.g3d.math.MathTools; + +public class Mesh { + private List vertices; + private List normals; + private List colors; + private List indices; + + + public Mesh(List vertices, List normals, + List colors, List indices) { + this.vertices = vertices; + this.normals = normals; + this.colors = colors; + this.indices = indices; + } + + public Mesh(List vertices, List normals, List indices) { + this.vertices = vertices; + this.normals = normals; + this.indices = indices; + } + + public Mesh(List vertices, List indices) { + this.vertices = vertices; + this.indices = indices; + } + + public List getVertices() { + return vertices; + } + + public List getNormals() { + return normals; + } + + public List getIndices() { + return indices; + } + + public List getColors() { + return colors; + } + + public void createNormals() { + normals = new ArrayList(vertices.size()); + for (int i = 0; i < vertices.size(); i++) { + normals.add(new Vector3d()); + } + Vector3d v1 = new Vector3d(); + Vector3d v2 = new Vector3d(); + Vector3d v3 = new Vector3d(); + Vector3d t1 = new Vector3d(); + Vector3d t2 = new Vector3d(); + Vector3d n = new Vector3d(); + for (int i = 0; i < indices.size(); i+=3) { + v1.set(vertices.get(i)); + v2.set(vertices.get(i+1)); + v3.set(vertices.get(i+2)); + t1.sub(v3,v1); + t2.sub(v2,v1); + n.cross(t2, t1); + normals.get(i).add(n); + normals.get(i+1).add(n); + normals.get(i+2).add(n); + } + for (int i = 0; i < normals.size(); i++) { + normals.get(i).normalize(); + } + } + + public void translate(Vector3d v) { + for (int i = 0; i < vertices.size(); i++) { + vertices.get(i).add(v); + } + } + + public void rotate(Quat4d q) { + Vector3d t = new Vector3d(); + for (int i = 0; i < vertices.size(); i++) { + MathTools.rotate(q, vertices.get(i), t); + vertices.get(i).set(t); + } + + if (normals != null) { + for (int i = 0; i < normals.size(); i++) { + MathTools.rotate(q, normals.get(i), t); + t.normalize(); + normals.get(i).set(t); + } + } + } + + public void setColor(Color4d color) { + colors = new ArrayList(vertices.size()); + for (int i = 0; i < vertices.size(); i++) { + colors.add(color); + } + } + + public void add(Mesh mesh) { + int vindex = vertices.size(); + int triIndex = indices.size(); + vertices.addAll(mesh.getVertices()); + indices.addAll(mesh.indices); + for (int i = triIndex; i < indices.size(); i++) { + indices.set(i, indices.get(i)+vindex); + } + if (normals != null) { + boolean hasNormals = true; + if (mesh.getNormals() == null) { + mesh.createNormals(); + hasNormals = false; + } + normals.addAll(mesh.getNormals()); + if (!hasNormals) + mesh.normals = null; + } + if (colors != null) { + if (mesh.getColors() != null) { + colors.addAll(mesh.getColors()); + } else { + for (int i = 0; i < mesh.getVertices().size(); i++) { + colors.add(new Color4d(1,1,1,0)); + } + } + } + } +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/shape/Sphere.java b/org.simantics.g3d/src/org/simantics/g3d/shape/Sphere.java new file mode 100644 index 00000000..63f91826 --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/shape/Sphere.java @@ -0,0 +1,94 @@ +package org.simantics.g3d.shape; + +import java.util.ArrayList; +import java.util.List; + +import javax.vecmath.AxisAngle4d; +import javax.vecmath.Vector3d; + +import org.simantics.g3d.math.MathTools; + +public class Sphere { + + public static Mesh create(double radius, int s, int p) { + if (s < 3 || p < 3 || radius < MathTools.NEAR_ZERO) + throw new IllegalArgumentException(); + List vertices = new ArrayList((s-2)*p + 2); + List normals = new ArrayList(vertices.size()); + List indices = new ArrayList(((s-3)*p*2 + p * 2)*3); + Vector3d v = new Vector3d(0.0,-radius,0.0); + Vector3d vp = new Vector3d(); + for (int ip = 0; ip < p; ip++) { + if (ip == 0) { + vertices.add(new Vector3d(0.0,-radius,0.0)); + } else if (ip == p - 1) { + vertices.add(new Vector3d(0.0, radius,0.0)); + int off = 1 + (ip-2)*s; + for (int is = 0; is < s; is++) { + indices.add(vertices.size() - 1); + indices.add(is+off); + if (is < s -1) + indices.add(is+off+1); + else + indices.add(off); + + + } + } else { + AxisAngle4d aa = new AxisAngle4d(1, 0, 0, ((double)ip/(double)(p-1))*Math.PI); + MathTools.rotate(MathTools.getQuat(aa), v, vp); + for (int is = 0; is < s; is++) { + aa = new AxisAngle4d(0, 1, 0, ((double)is/(double)s)*Math.PI*2); + Vector3d vs = new Vector3d(); + MathTools.rotate(MathTools.getQuat(aa), vp, vs); + vertices.add(vs); + } + if (ip == 1) { + for (int is = 0; is < s; is++) { + indices.add(0); + if (is < s -1) + indices.add(is+2); + else + indices.add(1); + indices.add(is+1); + } + } else { + int off = 1 + (ip-1)*s; + for (int is = 0; is < s-1; is++) { + indices.add(off + is - s); + indices.add(off + is+1); + indices.add(off + is); + + + indices.add(off + is - s); + indices.add(off + is + 1 - s); + indices.add(off + is + 1); + + } + indices.add(off - 1); + indices.add(off); + indices.add(off + s - 1); + + indices.add(off -1); + indices.add(off - s); + indices.add(off); + + } + } + } + for (int i = 0; i < vertices.size(); i++) { + Vector3d n = new Vector3d(vertices.get(i)); + n.normalize(); + normals.add(n); + } + + return new Mesh(vertices,normals,indices); + + } + + public static void main(String arg[]) { + Mesh s1 = create(1.0, 3, 3); + Mesh s2 = create(1.0, 4, 4); + System.out.println("debug " + s1 + " " + s2); + } +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/shape/Tube.java b/org.simantics.g3d/src/org/simantics/g3d/shape/Tube.java new file mode 100644 index 00000000..958993ed --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/shape/Tube.java @@ -0,0 +1,173 @@ +package org.simantics.g3d.shape; + +import java.util.ArrayList; +import java.util.List; + +import javax.vecmath.AxisAngle4d; +import javax.vecmath.Vector3d; + +import org.simantics.g3d.math.MathTools; + + +public class Tube { + List vertices; + List colors; + List radiis; + Double radius = 1.0; + int resolution = 8; + + + public void setResolution(int resolution) { + if (resolution > 2) + this.resolution = resolution; + } + + public void setVertices(List vertices) { + this.vertices = vertices; + } + + public void setColors(List colors) { + this.colors = colors; + } + + public void setRadiis(List radiis) { + this.radiis = radiis; + } + + public void setRadius(Double radius) { + this.radius = radius; + } + + + + public Mesh create() { + if (vertices.size() < 2 ) + throw new IllegalArgumentException("Tube must have at least two vertices"); + + Vector3d t = new Vector3d(); + + for (int i = 0; i < vertices.size() - 1; i++) { + t.set(vertices.get(i+1)); + t.sub(vertices.get(i)); + if (t.lengthSquared() < 0.0001) + throw new IllegalArgumentException("vertices at index " + i + " are too close to each other"); + } + + List points = new ArrayList(vertices.size()*resolution); + List normals = new ArrayList(vertices.size()*resolution); + + for (int i = 0; i < vertices.size(); i++) { + createCircle(i,points,normals); + } + + int index[] = new int[(vertices.size()-1)*resolution*6]; + + createIndices(index); + List indices = new ArrayList(); + for (int i = 0; i < index.length; i++) { + indices.add(index[i]); + } + + + + vertices.clear(); + if (colors != null) + colors.clear(); + if (radiis != null) + radiis.clear(); + + return new Mesh(points, normals, indices); + + } + + private void createCircle(int i, List points, List normals) { + final Vector3d up = new Vector3d(0,1,0); + final Vector3d up2 = new Vector3d(0,0,1); + Vector3d p = vertices.get(i); + Vector3d t = getTangent(i); + Vector3d n = new Vector3d(); + if (up.dot(t) < 0.99) { + n.cross(up, t); + } else { + n.cross(up2, t); + } + n.normalize(); + if (radiis != null) { + n.scale(radiis.get(i)); + } else { + n.scale(radius); + } + + for (int index = 0; index < resolution; index ++) { + Vector3d v; + if (index == 0) { + v = new Vector3d(n); + + } else { + AxisAngle4d aa = new AxisAngle4d(t, (Math.PI * 2 * (double)index)/(double)resolution); + v = new Vector3d(); + MathTools.rotate(MathTools.getQuat(aa), n, v); + } + //int vIndex = (i*resolution + index)*3; + Vector3d pt = new Vector3d(p); + pt.add(v); + //points.set(vIndex, pt); + points.add(pt); + v.normalize(); + //normals.set(vIndex, v); + normals.add(v); + } + } + + private Vector3d getTangent(int i) { + Vector3d p,n; + if (i == 0) { + p = vertices.get(0); + n = vertices.get(1); + } else if (i == vertices.size() - 1) { + p = vertices.get(i-1); + n = vertices.get(i); + } else { + p = vertices.get(i-1); + n = vertices.get(i+1); + } + n = new Vector3d(n); + n.sub(p); + n.normalize(); + return n; + } + + private void createIndices(int index[]) { + for (int c = 0; c < vertices.size() - 1; c++) { + for (int s = 0; s < resolution; s++) { + int ii = (c * resolution + s) * 6; + int iv = c*resolution + s; + + /* + iv+1 ---- iv + resolution + 1 + | /| + |/ | + iv ---- iv + resolution + */ + if (s < resolution - 1) { + index[ii+2] = iv; + index[ii+1] = iv+resolution; + index[ii+0] = iv+resolution+1; + + index[ii+5] = iv; + index[ii+4] = iv+resolution+1; + index[ii+3] = iv+1; + } else { + index[ii+2] = iv; + index[ii+1] = iv+resolution; + index[ii+0] = iv+1; + + index[ii+5] = iv; + index[ii+4] = iv+1; + index[ii+3] = iv+1-resolution; + } + } + } + } + +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/toolbar/CommandStateRegistry.java b/org.simantics.g3d/src/org/simantics/g3d/toolbar/CommandStateRegistry.java new file mode 100644 index 00000000..abb92f9e --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/toolbar/CommandStateRegistry.java @@ -0,0 +1,151 @@ +package org.simantics.g3d.toolbar; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.core.commands.Command; +import org.eclipse.core.commands.State; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.commands.ICommandService; +import org.eclipse.ui.handlers.IHandlerService; +import org.eclipse.ui.handlers.RadioState; +import org.eclipse.ui.handlers.RegistryToggleState; + +/** + * Registry for storing command states separately for each IEditorPart + * + * TODO : how to change toggle/radios state from editor? + * TODO : how to update visible buttons (ToolbarContributor) + * + * @author Marko Luukkainen + * + */ +public class CommandStateRegistry { + + + private static CommandStateRegistry instance; + + + public static CommandStateRegistry getInstance() { + if (instance == null) + instance = new CommandStateRegistry(); + return instance; + } + + + + private Map> toggleStates = new HashMap>(); + private Map defaultToggleStates = new HashMap(); + + private Map defaultRadioStates = new HashMap(); + private Map> radioStates = new HashMap>(); + + private ICommandService service; + private IHandlerService handlerService; + + private CommandStateRegistry() { + service = (ICommandService) PlatformUI.getWorkbench().getService(ICommandService.class); + handlerService = (IHandlerService) PlatformUI.getWorkbench().getService(IHandlerService.class); + } + + /** + * Stores default state for a command. + * + * Note: uses current state as default. + * + * @param commandId + */ + public void storeDefaultState(String commandId) { + Command command = service.getCommand(commandId); + State toggleState = command.getState(RegistryToggleState.STATE_ID); + State radioState = command.getState(RadioState.STATE_ID); + if (toggleState != null) { + if (!defaultToggleStates.containsKey(commandId)) + defaultToggleStates.put(commandId, getToggleState(command)); + } else if (radioState != null) { + String value = (String) radioState.getValue(); + if (!defaultRadioStates.containsKey(commandId)) + defaultRadioStates.put(commandId, value); + } else { + throw new IllegalArgumentException("Command " + commandId + " does not have a state"); + } + } + /** + * Stores toggle state of a command. + * @param part + * @param commandId + * @param checked + */ + public void setEditorState(IWorkbenchPart part, String commandId, boolean checked) { + Map editorStates = toggleStates.get(part); + if (editorStates == null) { + editorStates = new HashMap(); + toggleStates.put(part, editorStates); + } + editorStates.put(commandId, checked); + } + + /** + * Stores radio state of a command. + * @param part + * @param commandId + * @param value + */ + public void setEditorState(IWorkbenchPart part, String commandId, String value) { + Map editorStates = radioStates.get(part); + if (editorStates == null) { + editorStates = new HashMap(); + radioStates.put(part, editorStates); + } + editorStates.put(commandId, value); + } + + public Map getDefaultToggleStates() { + return defaultToggleStates; + } + + public Map getDefaultRadioStates() { + return defaultRadioStates; + } + + public Map getEditorToggleStates(IWorkbenchPart part) { + return toggleStates.get(part); + } + + public Map getEditorRadioStates(IWorkbenchPart part) { + return radioStates.get(part); + } + + public Boolean getToggleState(IWorkbenchPart part, String commandId) { + if (part == null) + return defaultToggleStates.get(commandId); + Map editorStates = toggleStates.get(part); + if (editorStates == null) { + return defaultToggleStates.get(commandId); + } + return editorStates.get(commandId); + } + + public String getRadioState(IWorkbenchPart part, String commandId) { + if (part == null) + return defaultRadioStates.get(commandId); + Map editorStates = radioStates.get(part); + if (editorStates == null) { + return defaultRadioStates.get(commandId); + } + return editorStates.get(commandId); + } + + public void clearStates(IWorkbenchPart part) { + toggleStates.remove(part); + radioStates.remove(part); + } + + private boolean getToggleState(Command command) { + State toggleState = command.getState(RegistryToggleState.STATE_ID); + return (Boolean)toggleState.getValue(); + } + + +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/toolbar/ToolBarCommandRegistry.java b/org.simantics.g3d/src/org/simantics/g3d/toolbar/ToolBarCommandRegistry.java new file mode 100644 index 00000000..2e94d3bb --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/toolbar/ToolBarCommandRegistry.java @@ -0,0 +1,126 @@ +package org.simantics.g3d.toolbar; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IExtension; +import org.eclipse.core.runtime.IExtensionPoint; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.dynamichelpers.ExtensionTracker; +import org.eclipse.core.runtime.dynamichelpers.IExtensionChangeHandler; +import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker; +import org.eclipse.core.runtime.dynamichelpers.IFilter; +import org.simantics.g3d.Activator; + + + + + +public class ToolBarCommandRegistry implements IExtensionChangeHandler { + private final static String NAMESPACE = Activator.PLUGIN_ID; + + private final static String EP_NAME = "toolbarCommand"; + + private ExtensionTracker tracker; + + private List extensions = new ArrayList(); + + + private static ToolBarCommandRegistry INSTANCE; + + public static synchronized ToolBarCommandRegistry getInstance() { + if (INSTANCE == null) + INSTANCE = new ToolBarCommandRegistry(); + return INSTANCE; + } + + public static synchronized void dispose() { + if (INSTANCE != null) { + INSTANCE.close(); + INSTANCE = null; + } + } + + public ToolBarCommandRegistry() { + tracker = new ExtensionTracker(); + + IExtensionPoint ep = Platform.getExtensionRegistry().getExtensionPoint(NAMESPACE,EP_NAME); + loadExtensions(ep.getConfigurationElements()); + + IFilter filter = ExtensionTracker.createExtensionPointFilter(ep); + tracker.registerHandler(this, filter); + } + + private void close() { + tracker.close(); + tracker = null; + extensions.clear(); + } + + public synchronized List getExtensions() { + return Collections.unmodifiableList(extensions); + } + + private synchronized void loadExtensions(IConfigurationElement[] elements) { + for (IConfigurationElement el : elements) { + String commandId = el.getAttribute("commandId"); + + ToolbarCommandExtension ext = new ToolbarCommandExtension(commandId); + ext.toolbarId = el.getAttribute("toolbarId"); + ext.image = el.getAttribute("image"); + ext.name = el.getAttribute("name"); + ext.type = el.getAttribute("type"); + ext.value = el.getAttribute("value"); + ext.contributorId = el.getContributor().getName(); + tracker.registerObject(el.getDeclaringExtension(), ext, IExtensionTracker.REF_STRONG); + extensions.add(ext); + + } + } + + @Override + public void addExtension(IExtensionTracker tracker, IExtension extension) { + loadExtensions(extension.getConfigurationElements()); + } + + @Override + public synchronized void removeExtension(IExtension extension, Object[] objects) { + for (Object o : objects) { + ToolbarCommandExtension ext = (ToolbarCommandExtension) o; + tracker.unregisterObject(extension, ext); + extensions.remove(ext); + } + } + + public synchronized List getExtensions(String toolbarId) { + List list = new ArrayList(); + for (ToolbarCommandExtension ext : extensions) + if (ext.toolbarId.equals(toolbarId)) + list.add(ext); + return list; + + } + + public class ToolbarCommandExtension { + public String commandId; + public String toolbarId; + public String name; + public String type; + public String value; + public String image; + public String contributorId; + public ToolbarCommandExtension(String commandId) { + super(); + this.commandId = commandId; + } + + @Override + public String toString() { + return "ToolbarCommandExtension, commandId= " + commandId + " toolbarId= " + toolbarId + " type= " + type + " value= " + value + " contributor= " + contributorId; + } + } + + +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/toolbar/ToolbarContributor.java b/org.simantics.g3d/src/org/simantics/g3d/toolbar/ToolbarContributor.java new file mode 100644 index 00000000..9f87b327 --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/toolbar/ToolbarContributor.java @@ -0,0 +1,482 @@ +package org.simantics.g3d.toolbar; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.eclipse.core.commands.Command; +import org.eclipse.core.commands.CommandEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.commands.ICommandListener; +import org.eclipse.core.commands.State; +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.ActionContributionItem; +import org.eclipse.jface.action.IContributionItem; +import org.eclipse.jface.action.ICoolBarManager; +import org.eclipse.jface.action.IToolBarManager; +import org.eclipse.jface.action.ToolBarContributionItem; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.nebula.widgets.tablecombo.TableCombo; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.TableItem; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IPartListener; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.commands.ICommandService; +import org.eclipse.ui.handlers.HandlerUtil; +import org.eclipse.ui.handlers.IHandlerService; +import org.eclipse.ui.handlers.RadioState; +import org.eclipse.ui.handlers.RegistryToggleState; +import org.eclipse.ui.menus.WorkbenchWindowControlContribution; +import org.eclipse.ui.part.EditorActionBarContributor; +import org.simantics.db.common.utils.ErrorLogger; +import org.simantics.g3d.Activator; +import org.simantics.g3d.toolbar.ToolBarCommandRegistry.ToolbarCommandExtension; +import org.simantics.utils.datastructures.MapList; + + +/** + * EditorBarContributor, which tracks toggle states separately for each command. + * + * @see org.simantics.g3d.toolbarCommand Extension Point + * + * @author Marko Luukkainen + * + * + * + * TODO : test radio buttons. + * TODO : configuring the position of buttons. + * + */ +public abstract class ToolbarContributor extends EditorActionBarContributor implements ICommandListener, IPartListener { + + private static final String PLATFORM = "platform:/plugin/"; + + private IEditorPart activePart; + private Set parts = new HashSet(); + IToolBarManager mgr; + + + ICommandService service; + IHandlerService handlerService; + List items = new ArrayList(); + MapList actions = new MapList(); + + CommandStateRegistry stateRegistry; + + private Map menus = new HashMap(); + + public ToolbarContributor() { + service = (ICommandService) PlatformUI.getWorkbench().getService(ICommandService.class); + handlerService = (IHandlerService) PlatformUI.getWorkbench().getService(IHandlerService.class); + stateRegistry = CommandStateRegistry.getInstance(); + } + + public abstract String getToolbarId(); + + public void contributeToCoolBar(ICoolBarManager coolBarManager) { + IContributionItem toolBar = coolBarManager.find(getToolbarId()); + if (toolBar instanceof ToolBarContributionItem) + mgr = ((ToolBarContributionItem) toolBar).getToolBarManager(); + if (mgr == null) + return; + + createCommands(); + + mgr.markDirty(); + + } + + private void createCommands() { + for (ToolbarCommandExtension ext : ToolBarCommandRegistry.getInstance().getExtensions(getToolbarId())) { + addCommand(ext); + } + } + + private void addCommand(ToolbarCommandExtension ext) { + String commandId = ext.commandId; + Command command = service.getCommand(commandId); + + String type = ext.type; + + State toggleState = command.getState(RegistryToggleState.STATE_ID); + State radioState = command.getState(RadioState.STATE_ID); + + String name = ext.name; + + + ImageDescriptor image = getImage(ext); + + CommandAction a = null; + if (type.equals("toggle") && toggleState != null) { + a = new CommandCheckboxAction(command,name,image); + + stateRegistry.storeDefaultState(commandId); + } else if (radioState != null && ext.value != null) { + stateRegistry.storeDefaultState(commandId); + if (type.equals("radio")) { + a = new CommandRadioAction(command,name,ext.value,image); + } else if (type.equals("combo")) { + a = new CommandRadioAction(command,name,ext.value,image); + ComboContribution combo = menus.get(commandId); + if (combo == null) { + combo = new ComboContribution(); + menus.put(commandId, combo); + items.add(combo); + mgr.add(combo); + a.getCommand().addCommandListener(this); + } + actions.add(commandId,a); + combo.addAction(a); + return; + } + } else if (type.equals("push")) { + a = new CommandPushAction(command,name,image); + } else { + ErrorLogger.defaultLogError(ext + " is not valid."); + return; + } + a.getCommand().addCommandListener(this); + IContributionItem item = new ActionContributionItem(a); + actions.add(commandId,a); + items.add(item); + mgr.add(item); + } + + private ImageDescriptor getImage(ToolbarCommandExtension ext) { + ImageDescriptor image = null; + if (ext.image != null) { + String plugin = null; + String file = null; + if (ext.image.startsWith(PLATFORM)) { + String s = ext.image.substring(PLATFORM.length()); + int i = s.indexOf("/"); + plugin = s.substring(0,i); + file = s.substring(i+1); + } else { + plugin = ext.contributorId; + file = ext.image; + } + image = Activator.imageDescriptorFromPlugin(plugin, file); + } + return image; + } + + + + @Override + public void commandChanged(CommandEvent commandEvent) { + if (commandEvent.isHandledChanged()||commandEvent.isEnabledChanged()) { + Command command = commandEvent.getCommand(); + String commandId = command.getId(); + for (CommandAction a : actions.getValues(commandId)) { + a.setEnabled(command.isHandled() && command.isEnabled()); + } + } + } + + @Override + public void setActiveEditor(IEditorPart targetEditor) { + if (targetEditor == activePart) + return; + setContext(targetEditor); + } + + private void setContext(IEditorPart part) { + this.activePart = part; + if (!parts.contains(activePart)) { + activePart.getSite().getPage().addPartListener(this); + } + if (part != null) { + for (String commandId : actions.getKeys()) { + for (CommandAction a : actions.getValues(commandId)) { + a.setEnabled(true); + } + } + updateActionBars(part); + } else { + for (String commandId : actions.getKeys()) { + for (CommandAction a : actions.getValues(commandId)) { + a.setEnabled(false); + } + } + } + } + + private void updateActionBars(IEditorPart part) { + restoreActionStates(); + part.getEditorSite().getActionBars().updateActionBars(); + } + + @Override + public void dispose() { + if (mgr != null) { + for (IContributionItem item : items) { + mgr.remove(item); + item.dispose(); + } + mgr.markDirty(); + mgr.update(true); + if (activePart != null) { + activePart.getEditorSite().getActionBars().updateActionBars(); + } + + for (String commandId : actions.getKeys()) { + for (CommandAction a : actions.getValues(commandId)) { + a.getCommand().removeCommandListener(this); + } + } + actions.clear(); + } + + super.dispose(); + activePart = null; + } + + + private void storeRadioActionState(CommandRadioAction action, boolean checked) { + if (activePart == null) + return; + stateRegistry.setEditorState(activePart, action.getCommandId(), action.getValue()); + } + + private void storeToggleActionState(CommandAction action, boolean checked) { + if (activePart == null) + return; + stateRegistry.setEditorState(activePart, action.getCommandId(), checked); + } + + private void restoreActionStates() { + if (activePart == null) + return; + // toggles + Map defaultToggleStates = stateRegistry.getDefaultToggleStates(); + for (String commandId : defaultToggleStates.keySet()) { + for (CommandAction a : actions.getValues(commandId)) { + a.setChecked(defaultToggleStates.get(commandId)); + } + } + Map editorStates = stateRegistry.getEditorToggleStates(activePart);//toggleStates.get(activePart); + if (editorStates != null) { + for (String commandId : editorStates.keySet()) { + for (CommandAction a : actions.getValues(commandId)) { + a.setChecked(editorStates.get(commandId)); + } + } + } + // radios + Map defaultRadioStates = stateRegistry.getDefaultRadioStates(); + for (String commandId : defaultRadioStates.keySet()) { + String defaultValue = defaultRadioStates.get(commandId); + for (CommandAction a : actions.getValues(commandId)) { + CommandRadioAction r = (CommandRadioAction)a; + r.setChecked(r.getValue().equals(defaultValue)); + } + } + + Map editorRadioStates = stateRegistry.getEditorRadioStates(activePart);//radioStates.get(activePart); + if (editorRadioStates != null) { + for (String commandId : editorRadioStates.keySet()) { + String defaultValue = editorRadioStates.get(commandId); + for (CommandAction a : actions.getValues(commandId)) { + CommandRadioAction r = (CommandRadioAction)a; + r.setChecked(r.getValue().equals(defaultValue)); + } + } + } + + for (ComboContribution c : menus.values()) { + c.updateSelection(); + } + + + } + + @Override + public void partActivated(IWorkbenchPart part) { + + } + + @Override + public void partBroughtToTop(IWorkbenchPart part) { + + } + + @Override + public void partClosed(IWorkbenchPart part) { + parts.remove(part); + stateRegistry.clearStates(part); + part.getSite().getPage().removePartListener(this); + } + + @Override + public void partDeactivated(IWorkbenchPart part) { + + } + + @Override + public void partOpened(IWorkbenchPart part) { + + } + + private boolean getToggleState(Command command) { + State toggleState = command.getState(RegistryToggleState.STATE_ID); + return (Boolean)toggleState.getValue(); + } + + private abstract class CommandAction extends Action { + private Command command; + + public CommandAction(Command command, String name, ImageDescriptor image, int style) { + super(name,style); + this.command = command; + if (image != null) + setImageDescriptor(image); + } + + @Override + public void run() { + try { + handlerService.executeCommand(command.getId(), null); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public Command getCommand() { + return command; + } + + public String getCommandId() { + return command.getId(); + } + } + + private class CommandCheckboxAction extends CommandAction { + + public CommandCheckboxAction(Command command, String name, ImageDescriptor image) { + super(command,name,image,Action.AS_CHECK_BOX); + + } + + @Override + public void run() { + boolean checked = isChecked(); + storeToggleActionState(this, checked); + try { + if (checked == getToggleState(getCommand())) + HandlerUtil.toggleCommandState(getCommand()); + } catch (ExecutionException e) { + e.printStackTrace(); + } + super.run(); + } + + } + + private class CommandRadioAction extends CommandAction { + + private String value; + + public CommandRadioAction(Command command, String name, String value, ImageDescriptor image) { + super(command,name,image,Action.AS_RADIO_BUTTON); + this.value = value; + } + + @Override + public void run() { + boolean checked = isChecked(); + storeRadioActionState(this, checked); + try { + HandlerUtil.updateRadioState(getCommand(), value); + } catch (ExecutionException e) { + e.printStackTrace(); + return; + } + super.run(); + } + + public String getValue() { + return value; + } + + } + + private class CommandPushAction extends CommandAction { + + public CommandPushAction(Command command, String name, ImageDescriptor image) { + super(command,name,image,Action.AS_PUSH_BUTTON); + } + + } + + private class ComboContribution extends WorkbenchWindowControlContribution { + private TableCombo combo; + + private List actions = new ArrayList(); + + @Override + protected Control createControl(Composite parent) { + Composite container = new Composite(parent, SWT.NONE); + GridLayout glContainer = new GridLayout(1, false); + glContainer.marginTop = 0; + glContainer.marginHeight = 0; + glContainer.marginWidth = 0; + container.setLayout(glContainer); + GridData glReader = new GridData(SWT.FILL, SWT.FILL, false, false, 1, 1); + combo = new TableCombo(container, SWT.BORDER | SWT.READ_ONLY); + combo.setLayoutData(glReader); + + for (Action a : actions) { + TableItem item = new TableItem(combo.getTable(), SWT.NONE); + item.setText(a.getText()); + if (a.getImageDescriptor() != null) + item.setImage(a.getImageDescriptor().createImage()); + } + + combo.addSelectionListener(new SelectionListener() { + + @Override + public void widgetSelected(SelectionEvent e) { + int index = combo.getSelectionIndex(); + if (index == -1) + return; + actions.get(index).run(); + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) { + + } + }); + updateSelection(); + return container; + } + + public void addAction(Action a) { + actions.add(a); + } + + void updateSelection() { + if (combo == null) + return; + for (int i = 0; i < actions.size(); i++) { + if (actions.get(i).isChecked()) { + combo.select(i); + return; + } + } + } + } + +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/tools/AdaptationUtils.java b/org.simantics.g3d/src/org/simantics/g3d/tools/AdaptationUtils.java new file mode 100644 index 00000000..5902b0ab --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/tools/AdaptationUtils.java @@ -0,0 +1,89 @@ +package org.simantics.g3d.tools; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; + +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.simantics.utils.Container; + +/** + * @author Antti Villberg + * @author Marko Luukkainen + * + * TODO: merge to os.ui.utils. + */ +public class AdaptationUtils { + /** + * + * @param o + * @param clazz + * @return object of given class or null + */ + @SuppressWarnings("unchecked") + public static T adaptToSingle(Object o, Class clazz) { + if (o instanceof IStructuredSelection) { + IStructuredSelection iss = (IStructuredSelection) o; + if (iss.size() != 1) + return null; + Object element = iss.getFirstElement(); + return adaptToSingle(element, clazz); + } else if (o instanceof Collection) { + Collection c = (Collection) o; + if (c.size() != 1) + return null; + Object element = c.iterator().next(); + return adaptToSingle(element, clazz); + } else if (o instanceof IAdaptable) { + IAdaptable a = (IAdaptable) o; + return (T)a.getAdapter(clazz); + } else if (clazz.isInstance(o)) { + return (T)o; + } else if (o instanceof Container) { + Object obj = ((Container) o).get(); + if (obj == o) + return null; + return adaptToSingle(obj, clazz); + } + return null; + } + /** + * + * @param o + * @param clazz + * @return collection of objects of given class. + */ + @SuppressWarnings("unchecked") + public static Collection adaptToCollection(Object o, Class clazz) { + if (clazz.isInstance(o)) { + return Collections.singletonList((T)o); + } else if (o instanceof IStructuredSelection) { + IStructuredSelection iss = (IStructuredSelection) o; + return adaptToCollection(iss.toArray(), clazz); + } else if (o instanceof Collection) { + Collection c = (Collection) o; + return adaptToCollection(c.toArray(), clazz); + } else if (o instanceof IAdaptable) { + IAdaptable a = (IAdaptable) o; + return Collections.singletonList((T)a.getAdapter(clazz)); + } else if (o instanceof Container) { + Object obj = ((Container) o).get(); + if (obj == o) + return Collections.EMPTY_LIST; + return adaptToCollection(obj, clazz); + } + return Collections.EMPTY_LIST; + } + + public static Collection adaptToCollection(Object arr[], Class clazz) { + Collection result = new ArrayList(); + for (Object o : arr) { + Collection tColl = adaptToCollection(o, clazz); + for (T t : tColl) + if (t != null && !result.contains(t)) + result.add(t); + } + return result; + } +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/tools/Constraint.java b/org.simantics.g3d/src/org/simantics/g3d/tools/Constraint.java new file mode 100644 index 00000000..901eaf94 --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/tools/Constraint.java @@ -0,0 +1,20 @@ +package org.simantics.g3d.tools; + +import java.util.ArrayList; +import java.util.List; + +import javax.vecmath.Point3d; +import javax.vecmath.Vector3d; + +public class Constraint { + + public Constraint() { + points = new ArrayList(); + dirs = new ArrayList(); + } + + public List points; + public List dirs; + +} + diff --git a/org.simantics.g3d/src/org/simantics/g3d/tools/ConstraintDetector.java b/org.simantics.g3d/src/org/simantics/g3d/tools/ConstraintDetector.java new file mode 100644 index 00000000..e6297538 --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/tools/ConstraintDetector.java @@ -0,0 +1,407 @@ +package org.simantics.g3d.tools; + +import java.util.ArrayList; +import java.util.List; + +import javax.vecmath.Point3d; +import javax.vecmath.Vector3d; + +import org.simantics.g3d.math.MathTools; +import org.simantics.g3d.scenegraph.IG3DNode; +import org.simantics.g3d.shape.Color4d; + +public abstract class ConstraintDetector { + + private static final int X = 0; + private static final int Y = 1; + private static final int Z = 2; + + +// private ThreeDimensionalEditorBase editor; + //private G3DNode constraintReference = null; + private IG3DNode constraintReference = null; + private ArrayList constraintPoints = new ArrayList(); + private ArrayList constraintDirections = new ArrayList(); +// private MaterialState ms; + + private Color4d xColor = new Color4d(1.f,0.f,0.f,1.f); + private Color4d yColor = new Color4d(0.f,1.f,0.f,1.f); + private Color4d zColor = new Color4d(0.f,0.f,1.f,1.f); + + +// public ConstraintDetector(ThreeDimensionalEditorBase editor) { +// this.editor = editor; +// ms = editor.getRenderingComponent().getDisplaySystem().getRenderer().createMaterialState(); +// ms.setEmissive(new ColorRGBA(1.f,1.f,1.f,1.f)); +// ms.setColorMaterial(MaterialState.CM_EMISSIVE); +// } + + + public void clearConstraints() { + //System.out.println("ConstraintDetector.clearConstraints()"); + constraintPoints.clear(); + constraintDirections.clear(); + } + + private void updateConstraints() { + clearConstraints(); + if (constraintReference == null) + return; + Constraint c = (Constraint)constraintReference.getAdapter(Constraint.class); + if (c == null) + return; + constraintPoints.addAll(c.points); + constraintDirections.addAll(c.dirs); + } + + + public ArrayList getConstraintPoints() { + return constraintPoints; + } + + public ArrayList getConstraintDirections() { + return constraintDirections; + } + + public void updateConstraintReference(IG3DNode node) { + if (constraintReference != null && !constraintReference.equals(node)) { + constraintReference = node; + updateConstraints(); + } else if (node != null){ + constraintReference = node; + updateConstraints(); + } + + } + + public void addContraintPoint(Point3d p) { + //System.out.println("ConstraintDetector.addConstraintPoint() " + p); + constraintPoints.add(p); + } + + public void addContraintDirection(Vector3d v) { + //System.out.println("ConstraintDetector.addConstraintDirection() " + v); + constraintDirections.add(v); + } + + private double snapAngle = 0.1; + private String snapString = ""; + +// private ArrayList constraintHighlights = new ArrayList(); + + public Point3d getSnappedPoint(Vector3d pickPoint, Vector3d pickDir, Vector3d requestedPoint) { + + + Vector3d snappedPoint = new Vector3d(); + Vector3d t = new Vector3d(); + Point3d currentPoint = null; + // TODO : snap to closest angle + for (Vector3d constraintDir : constraintDirections) { + + MathTools.intersectStraightStraight(pickPoint,pickDir, requestedPoint, constraintDir, t, snappedPoint); + t.sub(snappedPoint); + if (t.lengthSquared() < snapAngle) { + + snapString += "Angle snap "; + currentPoint = new Point3d(snappedPoint); + break; + } + } + if (currentPoint != null) { + Vector3d dir = new Vector3d(currentPoint); + dir.sub(requestedPoint); + Point3d p = getPointSnap(requestedPoint, dir); + if (p != null) + currentPoint = p; + } else { + List distances = new ArrayList(); + List snapPoints = new ArrayList(); + List snapStrings = new ArrayList(); + List snapColors = new ArrayList(); + for (Point3d constraintPoint : constraintPoints) { + distances.clear(); + snapPoints.clear(); + snapStrings.clear(); + MathTools.intersectStraightStraight(new Vector3d(constraintPoint), new Vector3d(1.0, 0.0, 0.0), + pickPoint, pickDir, snappedPoint, t); + t.sub(snappedPoint); + double distance = t.lengthSquared(); + if (distance < snapAngle) { + distances.add(distance); + snapPoints.add(new Point3d(snappedPoint)); + snapStrings.add("Point x-snap "); + snapColors.add(xColor); + } + MathTools.intersectStraightStraight(new Vector3d(constraintPoint), new Vector3d(0.0, 1.0, 0.0), + pickPoint, pickDir, snappedPoint, t); + t.sub(snappedPoint); + distance = t.lengthSquared(); + if (distance < snapAngle) { + distances.add(distance); + snapPoints.add(new Point3d(snappedPoint)); + snapStrings.add("Point y-snap "); + snapColors.add(yColor); + } + MathTools.intersectStraightStraight(new Vector3d(constraintPoint), new Vector3d(0.0, 0.0, 1.0), + pickPoint, pickDir, snappedPoint, t); + t.sub(snappedPoint); + distance = t.lengthSquared(); + if (distance < snapAngle) { + distances.add(distance); + snapPoints.add(new Point3d(snappedPoint)); + snapStrings.add("Point z-snap "); + snapColors.add(zColor); + + } + if (distances.size() > 0) { + if (distances.size() > 1) { + // more than one axes snape + Vector3d ref = MathTools.closestPointOnStraight(constraintPoint, new Point3d(pickPoint), pickDir); + ref.sub(constraintPoint); + distance = ref.lengthSquared(); + if (distance < snapAngle) { + // we are close enought to point, so we'll just snap there + currentPoint = new Point3d(constraintPoint); + snapString += "Point snap "; + } else { + // select the closest of axes snap to + int min = 0; + for (int i = 1; i < distances.size(); i++) { + if (distances.get(i) < distances.get(min)) + min = i; + } + currentPoint = snapPoints.get(min); + addConstrainLineHighlight(currentPoint, constraintPoint,snapColors.get(min)); + snapString += snapStrings.get(min); + } + } else { + // only one of the axes snaps + currentPoint = snapPoints.get(0); + addConstrainLineHighlight(currentPoint, constraintPoint,snapColors.get(0)); + snapString += snapStrings.get(0); + } + break; + } + } + } + return currentPoint; + + } + + public abstract void clearConstraintHighlights(); + protected abstract void addConstrainLineHighlight(Point3d p1, Point3d p2, Color4d color); + protected abstract void addConstrainPlaneHighlight(Point3d p1, Point3d p2, int axis); + +// public void clearConstraintHighlights() { +// snapString = ""; +// +// for (Geometry s : constraintHighlights) +// s.removeFromParent(); +// +// constraintHighlights.clear(); +// } +// +// private void addConstrainLineHighlight(Point3d p1, Point3d p2, Color4d color) { +// +// float coord[] = new float[6]; +// ColorRGBA colors[] = new ColorRGBA[2]; +// colors[0] = color; +// colors[1] = color; +// coord[0] = (float)p1.x; +// coord[1] = (float)p1.y; +// coord[2] = (float)p1.z; +// coord[3] = (float)p2.x; +// coord[4] = (float)p2.y; +// coord[5] = (float)p2.z; +// Line shape = new Line("",BufferUtils.createFloatBuffer(coord),null,BufferUtils.createFloatBuffer(colors),null); +// editor.getRenderingComponent().getNoShadowRoot().attachChild(shape); +// shape.setRenderState(ms); +// constraintHighlights.add(shape); +// } +// +// private void addConstrainPlaneHighlight(Point3d p1, Point3d p2, int axis) { +// +// float coord[] = new float[9]; +// ColorRGBA colors[] = new ColorRGBA[3]; +// coord[0] = (float)p1.x; +// coord[1] = (float)p1.y; +// coord[2] = (float)p1.z; +// switch (axis) { +// case X: +// coord[3] = (float)p1.x; +// coord[4] = (float)p1.y; +// coord[5] = (float)p2.z; +// colors[0] = colors[1] = colors[2] = xColor; +// break; +// case Y: +// coord[3] = (float)p1.x; +// coord[4] = (float)p1.y; +// coord[5] = (float)p2.z; +// colors[0] = colors[1] = colors[2] = yColor; +// break; +// case Z: +// coord[3] = (float)p1.x; +// coord[4] = (float)p2.y; +// coord[5] = (float)p2.z; +// colors[0] = colors[1] = colors[2] = zColor; +// break; +// +// } +// coord[6] = (float)p2.x; +// coord[7] = (float)p2.y; +// coord[8] = (float)p2.z; +// Line shape = new Line("",BufferUtils.createFloatBuffer(coord),null,BufferUtils.createFloatBuffer(colors),null); +// shape.setMode(Line.CONNECTED); +// editor.getRenderingComponent().getNoShadowRoot().attachChild(shape); +// shape.setRenderState(ms); +// constraintHighlights.add(shape); +// } + + /** + * Snaps position to axis-aligned planes defined by constraint points + * Form of position is p+v, meaning that the position that is snapped is requestedPoint + requestedDir + * @param requestedPoint one part of the position to be snapped + * @param requestedDir second part of the position to be snapped and direction that the position is allowed to move + * @return + */ + public Point3d getPointSnap(Vector3d requestedPoint, Vector3d requestedDir) { + + Vector3d snappedPoint = new Vector3d(); + Point3d currentPoint = null; + double u[] = new double[1]; + List p1s = new ArrayList(); + List p2s = new ArrayList(); + List axes = new ArrayList(); + + for (Point3d constraintPoint : constraintPoints) { + boolean snap = false; + + if (MathTools.intersectStraightPlane(requestedPoint, requestedDir, new Vector3d(constraintPoint), getAxialVector(X), snappedPoint,u) && Math.abs(1.0 - u[0]) < snapAngle) { + currentPoint = new Point3d(snappedPoint); + //snapString += "Point/Plane x-snap "; + snap = true; + //addConstrainPlaneHighlight(constraintPoint, currentPoint,X); + p1s.add(constraintPoint); + p2s.add(currentPoint); + axes.add(X); + } + + if (MathTools.intersectStraightPlane(requestedPoint, requestedDir, new Vector3d(constraintPoint), getAxialVector(Y), snappedPoint,u) && Math.abs(1.0 - u[0]) < snapAngle) { + currentPoint = new Point3d(snappedPoint); + //snapString += "Point/Plane y-snap "; + snap = true; + //addConstrainPlaneHighlight(constraintPoint, currentPoint,Y); + p1s.add(constraintPoint); + p2s.add(currentPoint); + axes.add(Y); + } + + if (MathTools.intersectStraightPlane(requestedPoint, requestedDir, new Vector3d(constraintPoint), getAxialVector(Z), snappedPoint,u) && Math.abs(1.0 - u[0]) < snapAngle) { + currentPoint = new Point3d(snappedPoint); + //snapString += "Point/Plane z-snap "; + snap = true; + //addConstrainPlaneHighlight(constraintPoint, currentPoint,Z); + p1s.add(constraintPoint); + p2s.add(currentPoint); + axes.add(Z); + } + if (snap) + break; + } + if (p1s.size() == 0) + return null; + if (p1s.size() == 1) { + snapString += "Point/Plane "; + switch (axes.get(0)) { + case X: + snapString += "x"; + break; + case Y: + snapString += "y"; + break; + case Z: + snapString += "z"; + break; + } + snapString += "-snap "; + addConstrainPlaneHighlight(p1s.get(0), p2s.get(0),axes.get(0)); + return currentPoint; + } else if (p1s.size() == 3){ + // all axial planes are intersecting, snapping point must be the constraint point + // all constraint points are the same, so just pick the first in the list + snapString += "Point/Point "; + return p1s.get(0); + } else { + Vector3d dir = new Vector3d(); + dir.cross(getAxialVector(axes.get(0)), getAxialVector(axes.get(1))); + currentPoint = new Point3d(MathTools.closestPointOnStraight(currentPoint, p1s.get(0), dir)); + addConstrainLineHighlight(p1s.get(0), currentPoint, xColor); + snapString += "Point/Line "; + return currentPoint; + } + + } + + private Vector3d getAxialVector(int axis) { + switch (axis) { + case X: + return new Vector3d(1.0,0.0,0.0); + case Y: + return new Vector3d(0.0,1.0,0.0); + case Z: + return new Vector3d(0.0,0.0,1.0); + } + throw new RuntimeException("Unknown axis " + axis); + } + + /** + * Snaps the position to axis-aligned planes defined by constraint points + * @param requestedPoint point that is snapped + * @param requestedDir direction that point is allowed to move + * @return + */ + + public Point3d getPointSnap2(Vector3d requestedPoint, Vector3d requestedDir) { + + Vector3d snappedPoint = new Vector3d(); + Point3d currentPoint = null; + double u[] = new double[1]; + //System.out.println(requestedPoint + " " + requestedDir); + for (Point3d constraintPoint : constraintPoints) { + boolean snap = false; + //System.out.print(constraintPoint + " "); + if (MathTools.intersectStraightPlane(requestedPoint, requestedDir, new Vector3d(constraintPoint), new Vector3d(1.0,0.0,0.0), snappedPoint,u) && Math.abs(u[0]) < snapAngle) { + currentPoint = new Point3d(snappedPoint); + snapString += "Point/Plane x-snap "; + snap = true; + addConstrainPlaneHighlight(constraintPoint, currentPoint,X); + //System.out.print(" x " + u[0]); + } + + if (MathTools.intersectStraightPlane(requestedPoint, requestedDir, new Vector3d(constraintPoint), new Vector3d(0.0,1.0,0.0), snappedPoint,u) && Math.abs(u[0]) < snapAngle) { + currentPoint = new Point3d(snappedPoint); + snapString += "Point/Plane y-snap "; + snap = true; + addConstrainPlaneHighlight(constraintPoint, currentPoint,Y); + //System.out.print(" y " + u[0]); + } + + + if (MathTools.intersectStraightPlane(requestedPoint, requestedDir, new Vector3d(constraintPoint), new Vector3d(0.0,0.0,1.0), snappedPoint,u) && Math.abs(u[0]) < snapAngle) { + currentPoint = new Point3d(snappedPoint); + snapString += "Point/Plane z-snap "; + snap = true; + addConstrainPlaneHighlight(constraintPoint, currentPoint,Z); + //System.out.print(" z " + u[0]); + } + //System.out.println(); + if (snap) + break; + } + return currentPoint; + } + + public String getSnapString() { + return snapString; + } +} \ No newline at end of file diff --git a/org.simantics.g3d/src/org/simantics/g3d/tools/DummyConstraintDetector.java b/org.simantics.g3d/src/org/simantics/g3d/tools/DummyConstraintDetector.java new file mode 100644 index 00000000..b79a91cb --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/tools/DummyConstraintDetector.java @@ -0,0 +1,24 @@ +package org.simantics.g3d.tools; + +import javax.vecmath.Point3d; + +import org.simantics.g3d.shape.Color4d; + +public class DummyConstraintDetector extends ConstraintDetector { + + @Override + protected void addConstrainLineHighlight(Point3d p1, Point3d p2, Color4d color) { + + } + + @Override + protected void addConstrainPlaneHighlight(Point3d p1, Point3d p2, int axis) { + + } + + @Override + public void clearConstraintHighlights() { + + } + +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/tools/NodeTools.java b/org.simantics.g3d/src/org/simantics/g3d/tools/NodeTools.java new file mode 100644 index 00000000..233fbacd --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/tools/NodeTools.java @@ -0,0 +1,125 @@ +package org.simantics.g3d.tools; + +import javax.vecmath.Matrix4d; +import javax.vecmath.Quat4d; +import javax.vecmath.Vector3d; + +import org.simantics.g3d.math.MathTools; +import org.simantics.g3d.scenegraph.IG3DNode; + +public class NodeTools { + + public static Vector3d getWorldPosition(IG3DNode node, Vector3d localPosition) { + Vector3d v = new Vector3d(localPosition); + MathTools.rotate(node.getOrientation(), v, v); + v.add(node.getPosition()); + + IG3DNode parent = (IG3DNode)node.getParent(); + if (parent == null) + return v; + return getWorldPosition(parent,v); + } + + public static Vector3d getWorldPosition(IG3DNode node) { + IG3DNode parent = (IG3DNode)node.getParent(); + if (parent == null) + return node.getPosition(); + return NodeTools.getWorldPosition(parent,new Vector3d(node.getPosition())); + } + + public static Quat4d getWorldOrientation(IG3DNode node, Quat4d localOrientation) { + Quat4d q = new Quat4d(); + q.set(node.getOrientation()); + Quat4d q2 = new Quat4d(); + q2.set(localOrientation); + q.mul(q2); + + IG3DNode parent = (IG3DNode)node.getParent(); + if (parent == null) + return q; + return getWorldOrientation(parent,q); + } + + public static Quat4d getWorldOrientation(IG3DNode node) { + IG3DNode parent = (IG3DNode)node.getParent(); + if (parent == null) + return node.getOrientation(); + return NodeTools.getWorldOrientation(parent, node.getOrientation()); + } + + + public static Vector3d getLocalPosition(IG3DNode node, Vector3d worldCoord) { + + IG3DNode parent = (IG3DNode)node.getParent(); + if (parent == null) {// this is a root node ( has no transformation) + return worldCoord; + } + + Vector3d local = getLocalPosition(parent,worldCoord); + local.sub(node.getPosition()); + + Quat4d q = new Quat4d(); + q.set(node.getOrientation()); + q.inverse(); + MathTools.rotate(q, local, local); + + return local; + } + + public static Quat4d getLocalOrientation(IG3DNode node, Quat4d worldRot) { + + IG3DNode parent = (IG3DNode) node.getParent(); + if (parent == null) // this is a rootnode ( has no transformation) + return worldRot; + Quat4d local = getLocalOrientation(parent, worldRot); + Quat4d q = new Quat4d(); + q.set(node.getOrientation()); + q.inverse(); + Quat4d q2 = new Quat4d(); + q2.set(local); + q.mul(q2); + local.set(q); + + return local; + } + + public static Matrix4d getWorldTransformation(IG3DNode node) { + Vector3d pos = node.getWorldPosition(); + Quat4d q = node.getWorldOrientation(); + + Matrix4d m1 = new Matrix4d(); + Matrix4d m2 = new Matrix4d(); + m1.set(pos); + m2.set(q); + m1.mul(m2); + return m1; + } + + public static Matrix4d getWorldOrientationMat(IG3DNode node) { + Quat4d q = node.getWorldOrientation(); + + Matrix4d m2 = new Matrix4d(); + m2.set(q); + return m2; + } + + public static Vector3d getPosition(IG3DNode relative, IG3DNode node) { + Vector3d wp = getWorldPosition(node); + return getLocalPosition(relative, wp); + } + + public static Quat4d getOrientation(IG3DNode relative, IG3DNode node) { + Quat4d wo = getWorldOrientation(node); + return getLocalOrientation(relative, wo); + } + + public static void setPosition(IG3DNode relative, IG3DNode node, Vector3d position) { + Vector3d wp = getWorldPosition(relative,position); + node.setWorldPosition(wp); + } + + public static void setOrientation(IG3DNode relative, IG3DNode node, Quat4d orientation) { + Quat4d wo = getWorldOrientation(relative,orientation); + node.setWorldOrientation(wo); + } +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/tools/PluginTools.java b/org.simantics.g3d/src/org/simantics/g3d/tools/PluginTools.java new file mode 100644 index 00000000..d20fa85a --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/tools/PluginTools.java @@ -0,0 +1,28 @@ +package org.simantics.g3d.tools; + +import java.io.File; +import java.net.URL; + +import org.eclipse.core.runtime.FileLocator; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; +import org.osgi.framework.Bundle; + +public class PluginTools { + + public static String getAbsolutePath(Bundle inBundle, String fullpath) { + IPath path = new Path(fullpath); + URL u = FileLocator.find(inBundle, path, null); + if (u != null) { + try { + u = FileLocator.resolve(u); + if ("file".equals(u.getProtocol())) { + return new File(u.getFile()).getAbsolutePath(); + } + } catch (Exception e) { + } + } + return null; + } + +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/ui/SceneGraphDebugger.java b/org.simantics.g3d/src/org/simantics/g3d/ui/SceneGraphDebugger.java new file mode 100644 index 00000000..1eb4b311 --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/ui/SceneGraphDebugger.java @@ -0,0 +1,217 @@ +package org.simantics.g3d.ui; + +import org.eclipse.jface.layout.TreeColumnLayout; +import org.eclipse.jface.viewers.CellLabelProvider; +import org.eclipse.jface.viewers.ColumnWeightData; +import org.eclipse.jface.viewers.TreeViewer; +import org.eclipse.jface.viewers.TreeViewerColumn; +import org.eclipse.jface.viewers.ViewerCell; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.ui.IPartListener2; +import org.eclipse.ui.IPartService; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.IWorkbenchPartReference; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.part.ViewPart; +import org.simantics.g3d.scenegraph.base.INode; +import org.simantics.objmap.graph.IMapping; +import org.simantics.objmap.structural.IStructuralObject; + +public class SceneGraphDebugger extends ViewPart { + + private TreeViewer viewer; + + private boolean linkToPart = true; + + IWorkbenchPart lastPart; + + private IMapping mapping; + + public SceneGraphDebugger() { + // TODO Auto-generated constructor stub + } + + @Override + public void createPartControl(Composite parent) { + + viewer = new TreeViewer(parent,SWT.SINGLE|SWT.FULL_SELECTION); + + TreeColumnLayout layout = new TreeColumnLayout(); + parent.setLayout(layout); + + viewer.setContentProvider(new ScenegraphOutlinePage.ScenegraphContentProvider()); + viewer.getTree().setHeaderVisible(true); + + TreeViewerColumn nameColumn = new TreeViewerColumn(viewer, SWT.LEFT); + nameColumn.setLabelProvider(new CellLabelProvider() { + + @Override + public void update(ViewerCell cell) { + cell.setText(cell.getElement().toString()); + } + }); + + TreeViewerColumn typeColumn = new TreeViewerColumn(viewer, SWT.LEFT); + typeColumn.setLabelProvider(new CellLabelProvider() { + + @Override + public void update(ViewerCell cell) { + cell.setText(cell.getElement().getClass().getSimpleName()); + } + }); + + TreeViewerColumn contextColumn = new TreeViewerColumn(viewer, SWT.LEFT); + contextColumn.setLabelProvider(new CellLabelProvider() { + + @Override + public void update(ViewerCell cell) { + if (!(cell.getElement() instanceof IStructuralObject)) + cell.setText("N/A"); + else { + IStructuralObject o = (IStructuralObject)cell.getElement(); + if (o.getContext() != null) { + cell.setText(o.getContext().toString()); + } else { + cell.setText("none"); + } + + } + + } + }); + + TreeViewerColumn mappingColumn = new TreeViewerColumn(viewer, SWT.LEFT); + mappingColumn.setLabelProvider(new CellLabelProvider() { + + @Override + public void update(ViewerCell cell) { + if (mapping == null) + cell.setText("N/A"); + else { + Object o = mapping.inverseGet(cell.getElement()); + if (o != null) { + cell.setText(o.toString()); + } else { + cell.setText("none"); + } + + } + + } + }); + + nameColumn.getColumn().setText("Name"); + typeColumn.getColumn().setText("Type"); + contextColumn.getColumn().setText("Context"); + mappingColumn.getColumn().setText("Mapping"); + + layout.setColumnData(nameColumn.getColumn(), new ColumnWeightData(10, true)); + layout.setColumnData(typeColumn.getColumn(), new ColumnWeightData(10, true)); + layout.setColumnData(contextColumn.getColumn(), new ColumnWeightData(10, true)); + layout.setColumnData(mappingColumn.getColumn(), new ColumnWeightData(10, true)); + + IPartService partService = (IPartService) getSite().getService(IPartService.class); + partService.addPartListener(partListener); + + } + + @Override + public void setFocus() { + viewer.getTree().setFocus(); + } + + protected void refresh() { + IWorkbenchPart part = null; + try { + IWorkbenchWindow window = getSite().getWorkbenchWindow(); + if (window == null) + return; + IWorkbenchPage page = window.getActivePage(); + if (page == null) + return; + part = page.getActiveEditor(); + if (part == null) + return; + } finally { + if (part == null) { + setContentDescription("No scene graph nodes available."); + // TODO: Show info page instead of tree view. + } + } + + refresh(part); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + protected boolean refresh(IWorkbenchPart part) { + if (viewer.getTree().isDisposed()) { + IPartService partService = (IPartService) getSite().getService(IPartService.class); + partService.removePartListener(partListener); + return false; + } + boolean foundInput = false; + try { + Object obj = null; + if (part != null) { + obj = part.getAdapter(INode.class); + } + + if (obj != null) { + mapping = (IMapping)part.getAdapter(IMapping.class); + if (!viewer.getTree().isDisposed()) + viewer.setInput(obj); + foundInput = true; + } + lastPart = part; + return foundInput; + } finally { + if (!foundInput) { + setContentDescription("No scene graph nodes available."); + // TODO: Show info page instead of tree view. + } + } + } + + IPartListener2 partListener = new IPartListener2() { + @Override + public void partVisible(IWorkbenchPartReference partRef) { + } + @Override + public void partOpened(IWorkbenchPartReference partRef) { + } + @Override + public void partInputChanged(IWorkbenchPartReference partRef) { + } + @Override + public void partHidden(IWorkbenchPartReference partRef) { + } + @Override + public void partDeactivated(IWorkbenchPartReference partRef) { + } + @Override + public void partClosed(IWorkbenchPartReference partRef) { + if (linkToPart) { + IWorkbenchPart part = partRef.getPart(false); + if (part != null) + refresh(null); + } + } + @Override + public void partBroughtToTop(IWorkbenchPartReference partRef) { + } + @Override + public void partActivated(IWorkbenchPartReference partRef) { + if (linkToPart) { + IWorkbenchPart part = partRef.getPart(false); + if (part != null) { + if (part != lastPart) { + refresh(part); + } + } + } + } + }; + +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/ui/ScenegraphOutlinePage.java b/org.simantics.g3d/src/org/simantics/g3d/ui/ScenegraphOutlinePage.java new file mode 100644 index 00000000..71e1c683 --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/ui/ScenegraphOutlinePage.java @@ -0,0 +1,195 @@ +package org.simantics.g3d.ui; + +import java.util.HashSet; +import java.util.Set; + +import org.eclipse.jface.viewers.ITreeContentProvider; +import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.jface.viewers.TreeViewer; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.views.contentoutline.ContentOutlinePage; +import org.simantics.g3d.scenegraph.base.INode; +import org.simantics.g3d.scenegraph.base.NodeListener; +import org.simantics.g3d.scenegraph.base.ParentNode; + +public class ScenegraphOutlinePage extends ContentOutlinePage implements NodeListener { + + private ParentNode rootNode; + + public ScenegraphOutlinePage(ParentNode rootNode) { + if (rootNode == null) + throw new NullPointerException(); + this.rootNode = rootNode; + } + + + @Override + public void createControl(Composite parent) { + super.createControl(parent); + if (rootNode == null) + return; + TreeViewer viewer = getTreeViewer(); + createProviders(viewer); + viewer.setInput(rootNode); + listen(rootNode); + } + + protected void createProviders(TreeViewer viewer) { + viewer.setContentProvider(new ScenegraphContentProvider()); + viewer.setLabelProvider(new ScenegraphLabelProvider()); + } + + + + @SuppressWarnings("unchecked") + protected void listen(INode node) { + node.addListener(this); + if (node instanceof ParentNode) { + ParentNode parentNode = (ParentNode)node; + for (INode n : parentNode.getNodes()) + listen(n); + } + } + + @SuppressWarnings("unchecked") + protected void stopListening(INode node) { + node.removeListener(this); + if (node instanceof ParentNode) { + ParentNode parentNode = (ParentNode)node; + for (INode n : parentNode.getNodes()) + stopListening(n); + } + } + + @Override + public void propertyChanged(INode node, String id) { + refershViewer(node); + } + + @Override + public void nodeAdded(ParentNode node, INode child, + String rel) { + listen(child); + refershViewer(node); + } + + + + @Override + public void nodeRemoved(ParentNode node, INode child, + String rel) { + stopListening(child); + refershViewer(node); + } + + //private Queue toRefresh = new LinkedList(); + private Set toRefresh = new HashSet(); + private NodeUpdater updater; + + protected void refershViewer(final INode node) { + if (getTreeViewer() == null) + return; + synchronized (toRefresh) { + toRefresh.add(node); + if (updater != null) + return; + } + + updater = new NodeUpdater(); + Display.getDefault().asyncExec(updater); + } + + private class NodeUpdater implements Runnable { + @Override + public void run() { + if (getTreeViewer().getTree().isDisposed()) { + updater =null; + return; + } + int count = 0; + // limit the amount of refreshes. + while (count < 100) { + INode node = null; + synchronized (toRefresh) { + // if the queue becomes too long, refresh the whole tree +// if (toRefresh.size() > 100) { +// toRefresh.clear(); +// getTreeViewer().refresh(); +// updater = null; +// return; +// } + + //node = toRefresh.poll(); + if (toRefresh.size() > 0) { + node = toRefresh.iterator().next(); + toRefresh.remove(node); + } + if (node == null) { + updater = null; + return; + } + } + getTreeViewer().refresh(node); + count++; + } + if (toRefresh.size() > 0) { + Display.getDefault().asyncExec(this); + } + } + } + + public static class ScenegraphContentProvider implements ITreeContentProvider { + + public ScenegraphContentProvider() { + + } + + @Override + public Object[] getChildren(Object parentElement) { + if (parentElement instanceof ParentNode) { + ParentNode parentNode = (ParentNode)parentElement; + return parentNode.getNodes().toArray(); + } + return new Object[0]; + } + + @Override + public Object[] getElements(Object inputElement) { + return getChildren(inputElement); + } + + @Override + public Object getParent(Object element) { + if (element instanceof INode) { + INode node = (INode) element; + return node.getParent(); + } + return null; + } + + @Override + public boolean hasChildren(Object element) { + if (element instanceof ParentNode) { + ParentNode parentNode = (ParentNode)element; + return parentNode.getNodes().size() > 0; + } + return false; + } + + @Override + public void dispose() { + + } + + @Override + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + + } + } + + public class ScenegraphLabelProvider extends LabelProvider { + + } +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/wizard/IExportModel.java b/org.simantics.g3d/src/org/simantics/g3d/wizard/IExportModel.java new file mode 100644 index 00000000..f313d23d --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/wizard/IExportModel.java @@ -0,0 +1,60 @@ +package org.simantics.g3d.wizard; + +import java.io.File; +import java.util.Deque; + +import org.simantics.db.common.NamedResource; + +public abstract class IExportModel { + + File exportLocation; + NamedResource model; + boolean overwrite; + + Deque recentLocations; + + Object selection; + + public void setModel(NamedResource model) { + this.model = model; + } + + public NamedResource getModel() { + return model; + } + + public void setOverwrite(boolean overwrite) { + this.overwrite = overwrite; + } + + public boolean isOverwrite() { + return overwrite; + } + + + public void setExportLocation(File exportLocation) { + this.exportLocation = exportLocation; + } + + public File getExportLocation() { + return exportLocation; + } + + public abstract boolean usesFile(); + + public Deque getRecentLocations() { + return recentLocations; + } + + public void setRecentLocations(Deque recentLocations) { + this.recentLocations = recentLocations; + } + + public Object getSelection() { + return selection; + } + + public void setSelection(Object selection) { + this.selection = selection; + } +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/wizard/ModelExportWizard.java b/org.simantics.g3d/src/org/simantics/g3d/wizard/ModelExportWizard.java new file mode 100644 index 00000000..27214c93 --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/wizard/ModelExportWizard.java @@ -0,0 +1,215 @@ +package org.simantics.g3d.wizard; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.util.Deque; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.Set; +import java.util.TreeSet; + +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.operation.IRunnableWithProgress; +import org.eclipse.jface.preference.IPersistentPreferenceStore; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.wizard.Wizard; +import org.eclipse.jface.wizard.WizardPage; +import org.eclipse.ui.IExportWizard; +import org.eclipse.ui.IMemento; +import org.eclipse.ui.IWorkbench; +import org.simantics.db.management.ISessionContext; +import org.simantics.project.IProject; +import org.simantics.project.ProjectKeys; +import org.simantics.ui.SimanticsUI; +import org.simantics.utils.ui.ErrorLogger; +import org.simantics.utils.ui.ExceptionUtils; +import org.simantics.utils.ui.workbench.StringMemento; + +public abstract class ModelExportWizard extends Wizard implements IExportWizard { + + private static final int MAX_RECENT_EXPORT_PATHS = 10; + Deque recentExportPaths; + boolean overwrite; + + T exportModel; + + protected abstract T createExportModel(Deque recentExportPaths); + + protected abstract ModelExportWizardPage createExportPage(T exportModel); + + protected abstract IPersistentPreferenceStore getPreferenceStore(); + + protected abstract IRunnableWithProgress createExportRunnable(T exportModel); + + protected abstract String getExportLocationId(); + protected abstract String getExportOverwriteId(); + + @Override + public void init(IWorkbench workbench, IStructuredSelection selection) { + readPreferences(); + + ISessionContext ctx = SimanticsUI.getSessionContext(); + if (ctx == null) + return; + IProject project = ctx.getHint(ProjectKeys.KEY_PROJECT); + if (project == null) + return; + + exportModel = createExportModel(recentExportPaths); + exportModel.setSelection(selection.getFirstElement()); + exportModel.setOverwrite(overwrite); + } + + @Override + public void addPages() { + super.addPages(); + if (exportModel != null) { + addPage(createExportPage(exportModel)); + } + } + + + + @Override + public boolean performFinish() { + try { + recentExportPaths.addFirst(exportModel.getExportLocation().getAbsolutePath()); + removeDuplicates(recentExportPaths); + if (recentExportPaths.size() > MAX_RECENT_EXPORT_PATHS) + recentExportPaths.pollLast(); + + writePreferences(); + } catch (IOException e) { + ErrorLogger.defaultLogError("Failed to write preferences", e); + } + + if (exportModel.usesFile()) { + + File outputFile = exportModel.getExportLocation(); + + if (outputFile.exists()) { + if (!outputFile.isFile()) { + MessageDialog.openError(getShell(), "File Problem", "Output target is not a file " + outputFile.getAbsolutePath()); + return false; + } + if (!exportModel.isOverwrite()) { + boolean ok = MessageDialog.openConfirm(getShell(), "Overwrite", "A file by the name " + outputFile.getAbsolutePath() + " contains files.\n\nDo you want to overwrite the files?"); + if (!ok) { + return false; + } + if (!outputFile.delete()) { + MessageDialog.openError(getShell(), "Delete Problem", "Could not overwrite previously existing file " + outputFile.getAbsolutePath()); + return false; + } + } + } + } else { + File outputFolder = exportModel.getExportLocation(); + + if (outputFolder.exists()) { + if (!outputFolder.isDirectory()) { + MessageDialog.openError(getShell(), "Folder Problem", "Output target is not a folder " + outputFolder.getAbsolutePath()); + return false; + } + String files[] = outputFolder.list(); + if (files.length > 0) { + if (!exportModel.isOverwrite()) { + boolean ok = MessageDialog.openConfirm(getShell(), "Overwrite", "A folder by the name " + outputFolder.getAbsolutePath() + " contains files.\n\nDo you want to overwrite the files?"); + if (!ok) { + return false; + } + } + } + + } else { + if (!outputFolder.mkdir()) { + MessageDialog.openError(getShell(), "Folder Problem", "Could not create new folder " + outputFolder); + return false; + } + } + } + + try { + getContainer().run(true, true,createExportRunnable(exportModel)); + } catch (InvocationTargetException e) { + Throwable t = e.getTargetException(); + WizardPage cp = (WizardPage) getContainer().getCurrentPage(); + if (t instanceof IOException) { + ErrorLogger.defaultLogError("An I/O problem occurred while exporting the model. See exception for details.", t); + cp.setErrorMessage("An I/O problem occurred while exporting the model.\n\nMessage: " + e.getMessage()); + } else { + ErrorLogger.defaultLogError("Unexpected exception while exporting the model. See exception for details.", t); + cp.setErrorMessage("Unexpected exception while exporting the model. See error log for details.\n\nMessage: " + e.getMessage()); + } + return false; + } catch (InterruptedException e) { + ExceptionUtils.logAndShowError(e); + return false; + } + + return true; + } + + + + + private boolean readPreferences() { + IPreferenceStore store = getPreferenceStore(); + + String recentPathsPref = store.getString(getExportLocationId()); + recentExportPaths = decodePaths(recentPathsPref); + overwrite = store.getBoolean(getExportOverwriteId()); + + return true; + } + + private void writePreferences() throws IOException { + IPersistentPreferenceStore store = getPreferenceStore(); + + store.putValue(getExportLocationId(), encodePaths(recentExportPaths)); + store.setValue(getExportOverwriteId(), exportModel.isOverwrite()); + + if (store.needsSaving()) + store.save(); + } + + private static final String TAG_PATH = "path"; + private static final String ATTR_NAME = "name"; + + + public static Deque decodePaths(String recentPathsPref) { + Deque result = new LinkedList(); + try { + StringMemento sm = new StringMemento(recentPathsPref); + for (IMemento m : sm.getChildren(TAG_PATH)) { + String name = m.getString(ATTR_NAME); + if (name != null && !name.isEmpty()) + result.add(name); + } + } catch (IllegalArgumentException e) { + } + return result; + } + + public static String encodePaths(Deque recentPaths) { + StringMemento sm = new StringMemento(); + for (String path : recentPaths) { + IMemento m = sm.createChild(TAG_PATH); + m.putString(ATTR_NAME, path); + } + return sm.toString(); + } + + public static void removeDuplicates(Iterable iter) { + // Remove duplicates + Set dups = new TreeSet(String.CASE_INSENSITIVE_ORDER); + for (Iterator it = iter.iterator(); it.hasNext();) { + String path = it.next(); + if (!dups.add(path)) { + it.remove(); + } + } + } +} diff --git a/org.simantics.g3d/src/org/simantics/g3d/wizard/ModelExportWizardPage.java b/org.simantics.g3d/src/org/simantics/g3d/wizard/ModelExportWizardPage.java new file mode 100644 index 00000000..95e384b7 --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/wizard/ModelExportWizardPage.java @@ -0,0 +1,285 @@ +package org.simantics.g3d.wizard; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.eclipse.jface.layout.GridDataFactory; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.wizard.WizardPage; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.CCombo; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.DirectoryDialog; +import org.eclipse.swt.widgets.FileDialog; +import org.eclipse.swt.widgets.Label; +import org.simantics.Simantics; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.common.NamedResource; +import org.simantics.db.common.request.ReadRequest; +import org.simantics.db.exception.DatabaseException; +import org.simantics.layer0.Layer0; +import org.simantics.ui.utils.ResourceAdaptionUtils; + + +public abstract class ModelExportWizardPage extends WizardPage{ + T exportData; + + CCombo model; + CCombo exportLocation; + + boolean exportToFile = true; + + private List models = new ArrayList(); + + private Button overwrite; + + + + public ModelExportWizardPage(String pageName, String title, ImageDescriptor titleImage, T data) { + super(pageName, title, titleImage); + this.exportData = data; + exportToFile = data.usesFile(); + } + + protected abstract List getSupportedModels(ReadGraph graph, Resource project) throws DatabaseException; + + public String[] getFilterExtensions() { + return new String[0]; + } + + public String[] getFilterNames() { + return new String[0]; + } + + @Override + public void createControl(Composite parent) { + Composite container = new Composite(parent, SWT.NONE); + { + GridLayout layout = new GridLayout(); + layout.horizontalSpacing = 20; + layout.verticalSpacing = 10; + layout.numColumns = 3; + container.setLayout(layout); + } + + new Label(container, SWT.NONE).setText("Exported &model:"); + model = new CCombo(container, SWT.BORDER); + { + model.setEditable(false); + model.setText(""); + model.setToolTipText("Selects the model to export."); + GridDataFactory.fillDefaults().grab(true, false).span(2, 1).applyTo(model); + model.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + exportData.setModel(((NamedResource) model.getData(Integer.toString(model.getSelectionIndex())))); + validatePage(); + } + }); + + } + if (exportToFile) { + new Label(container, SWT.NONE).setText("&Target file:"); + exportLocation = new CCombo(container, SWT.BORDER); + { + exportLocation.setText(""); + GridDataFactory.fillDefaults().grab(true, false).span(1, 1).applyTo(exportLocation); + exportLocation.addModifyListener(new ModifyListener(){ + @Override + public void modifyText(ModifyEvent e) { + validatePage(); + } + }); + } + Button browseFileButton = new Button(container, SWT.PUSH); + { + browseFileButton.setText("Browse..."); + browseFileButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false)); + browseFileButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + FileDialog dialog = new FileDialog(getShell(), SWT.SAVE); + dialog.setText("Choose Export Target File"); + dialog.setFilterExtensions(getFilterExtensions()); + dialog.setFilterNames(getFilterNames()); + String loc = exportLocation.getText(); + dialog.setFilterPath(loc); + String file = dialog.open(); + if (file == null) + return; + exportLocation.setText(file); + validatePage(); + } + }); + } + + + + + } else { + new Label(container, SWT.NONE).setText("&Target folder:"); + exportLocation = new CCombo(container, SWT.BORDER); + { + exportLocation.setText(""); + GridDataFactory.fillDefaults().grab(true, false).span(1, 1).applyTo(exportLocation); + exportLocation.addModifyListener(new ModifyListener(){ + @Override + public void modifyText(ModifyEvent e) { + validatePage(); + } + }); + } + Button browseFileButton = new Button(container, SWT.PUSH); + { + browseFileButton.setText("Browse..."); + browseFileButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false)); + browseFileButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + DirectoryDialog dialog = new DirectoryDialog(getShell(), SWT.SAVE); + dialog.setText("Choose Export Target Folder"); + String loc = exportLocation.getText(); + dialog.setFilterPath(loc); + String file = dialog.open(); + if (file == null) + return; + exportLocation.setText(file); + validatePage(); + } + }); + } + } + + Label horizRule = new Label(container, SWT.BORDER); + GridDataFactory.fillDefaults().hint(SWT.DEFAULT, 0).grab(true, false).span(3, 1).applyTo(horizRule); + + overwrite = new Button(container, SWT.CHECK); + overwrite.setText("&Overwrite existing files without warning"); + overwrite.setSelection(exportData.isOverwrite()); + GridDataFactory.fillDefaults().grab(true, false).span(3, 1).applyTo(overwrite); + overwrite.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + validatePage(); + } + }); + + try { + initializeData(); + } catch (DatabaseException e) { + e.printStackTrace(); + } + + setControl(container); + validatePage(); + + } + + + + + protected void initializeData() throws DatabaseException { + final Resource selection = ResourceAdaptionUtils.toSingleResource(exportData.getSelection()); + + Simantics.getSessionContext().getSession().syncRequest( + new ReadRequest() { + @Override + public void run(ReadGraph graph) throws DatabaseException { + Layer0 L0 = Layer0.getInstance(graph); + models = getSupportedModels(graph, Simantics.getProject().get()); + } + }); + + Collections.sort(models); + + // Populate combo boxes + int i = 0; + boolean selected = false; + for (NamedResource s : models) { + model.add(s.getName()); + model.setData(String.valueOf(i), s); + if (s.getResource().equals(selection)) { + model.select(i); + selected = true; + } + ++i; + } + if (!selected && i > 0) + model.select(0); + + if (model.getSelectionIndex() >= 0) { + exportData.setModel((NamedResource)model.getData(Integer.toString(model.getSelectionIndex()))); + } + for (String path : exportData.getRecentLocations()) { + exportLocation.add(path); + } + if (exportLocation.getItemCount() > 0) + exportLocation.select(0); + } + + + + protected void validatePage() { + if (exportData.getModel() == null) { + setMessage("Select model to export."); + setErrorMessage(null); + setPageComplete(false); + return; + } + String exportLoc = exportLocation.getText(); + File file; + if (exportToFile) { + + if (exportLoc.isEmpty()) { + setMessage("Select target file."); + setErrorMessage(null); + setPageComplete(false); + return; + } + file = new File(exportLoc); + if (file.exists() && !file.isFile()) { + setErrorMessage("The target must be a file, an existing directory was given."); + setPageComplete(false); + return; + } + File parent = file.getParentFile(); + if (parent == null || !parent.isDirectory()) { + setErrorMessage("The target directory does not exist."); + setPageComplete(false); + return; + } + + } else { + if (exportLoc.isEmpty()) { + setMessage("Select target directory."); + setErrorMessage(null); + setPageComplete(false); + return; + } + file = new File(exportLoc); + if (file.exists() && !file.isDirectory()) { + setErrorMessage("The target must be a directory, an existing file was given."); + setPageComplete(false); + return; + } + + } + + exportData.setExportLocation(file); + exportData.setOverwrite(overwrite.getSelection()); + + setErrorMessage(null); + setMessage("Export selected model."); + setPageComplete(true); + } +} diff --git a/org.simantics.objmap2/.classpath b/org.simantics.objmap2/.classpath new file mode 100644 index 00000000..8a8f1668 --- /dev/null +++ b/org.simantics.objmap2/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/org.simantics.objmap2/.project b/org.simantics.objmap2/.project new file mode 100644 index 00000000..25f87237 --- /dev/null +++ b/org.simantics.objmap2/.project @@ -0,0 +1,28 @@ + + + org.simantics.objmap2 + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/org.simantics.objmap2/.settings/org.eclipse.jdt.core.prefs b/org.simantics.objmap2/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000..7eb740e9 --- /dev/null +++ b/org.simantics.objmap2/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,8 @@ +#Tue Jan 24 15:35:47 EET 2012 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/org.simantics.objmap2/META-INF/MANIFEST.MF b/org.simantics.objmap2/META-INF/MANIFEST.MF new file mode 100644 index 00000000..521cdd41 --- /dev/null +++ b/org.simantics.objmap2/META-INF/MANIFEST.MF @@ -0,0 +1,25 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Objmap2 +Bundle-SymbolicName: org.simantics.objmap2 +Bundle-Version: 1.0.0.qualifier +Bundle-RequiredExecutionEnvironment: JavaSE-1.6 +Require-Bundle: org.simantics.db;bundle-version="1.1.0", + gnu.trove3;bundle-version="3.0.0", + org.eclipse.core.runtime;bundle-version="3.7.0", + org.simantics.layer0;bundle-version="1.0.0", + org.apache.log4j;bundle-version="1.2.15", + org.simantics.db.common;bundle-version="1.1.0", + org.simantics.structural.ontology;bundle-version="1.1.0" +Export-Package: org.simantics.objmap.backward, + org.simantics.objmap.bidirectional, + org.simantics.objmap.exceptions, + org.simantics.objmap.forward, + org.simantics.objmap.graph, + org.simantics.objmap.graph.annotations, + org.simantics.objmap.graph.annotations.factories, + org.simantics.objmap.graph.rules.factory, + org.simantics.objmap.graph.schema, + org.simantics.objmap.structural, + org.simantics.objmap.structural.annotations, + org.simantics.objmap.structural.schema diff --git a/org.simantics.objmap2/build.properties b/org.simantics.objmap2/build.properties new file mode 100644 index 00000000..41eb6ade --- /dev/null +++ b/org.simantics.objmap2/build.properties @@ -0,0 +1,4 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + . diff --git a/org.simantics.objmap2/src/org/simantics/objmap/backward/IBackwardLinkType.java b/org.simantics.objmap2/src/org/simantics/objmap/backward/IBackwardLinkType.java new file mode 100644 index 00000000..9ea95c07 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/backward/IBackwardLinkType.java @@ -0,0 +1,16 @@ +package org.simantics.objmap.backward; + +import org.simantics.db.WriteGraph; +import org.simantics.objmap.exceptions.MappingException; + +/** + * Contains rules for creating and updating domain elements for given + * range elements. + * @author Hannu Niemistö + */ +public interface IBackwardLinkType extends IBackwardMappingRule { + /** + * Creates a domain element based on a known range element. + */ + Domain createDomainElement(WriteGraph graph, Range rangeElement) throws MappingException; +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/backward/IBackwardMapping.java b/org.simantics.objmap2/src/org/simantics/objmap/backward/IBackwardMapping.java new file mode 100644 index 00000000..d54b68e9 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/backward/IBackwardMapping.java @@ -0,0 +1,19 @@ +package org.simantics.objmap.backward; + +import java.util.Set; + +import org.simantics.db.WriteGraph; +import org.simantics.objmap.exceptions.MappingException; + +/** + * A backward mapping is a one-to-one correspondence between domain and range + * elements. It supports adding new range elements and creating corresponding + * domain elements. + * + * @author Hannu Niemistö + */ +public interface IBackwardMapping { + Set getRange(); + Domain inverseGet(Range rangeElement); + Domain inverseMap(WriteGraph graph, Range rangeElement) throws MappingException; +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/backward/IBackwardMappingRule.java b/org.simantics.objmap2/src/org/simantics/objmap/backward/IBackwardMappingRule.java new file mode 100644 index 00000000..067d1acd --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/backward/IBackwardMappingRule.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.backward; + +import org.simantics.db.WriteGraph; +import org.simantics.objmap.exceptions.MappingException; + +public interface IBackwardMappingRule { + /** + * Modifies the domain element so that it corresponds to the range element. + * @param g write transaction + * @param map unidirectional view of the current mapping + * @param domainElement the domain element that is updated + * @param rangeElement the range element that corresponds to the domain element + * @return true if the rule made some modifications + * @throws MappingException + */ + boolean updateDomain(WriteGraph graph, IBackwardMapping mapping, Domain domainElement, Range rangeElement) throws MappingException; + void createDomain(WriteGraph graph, IBackwardMapping mapping, Domain domainElement, Range rangeElement) throws MappingException; +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/backward/IBackwardMappingSchema.java b/org.simantics.objmap2/src/org/simantics/objmap/backward/IBackwardMappingSchema.java new file mode 100644 index 00000000..4f0dd138 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/backward/IBackwardMappingSchema.java @@ -0,0 +1,11 @@ +package org.simantics.objmap.backward; + +import org.simantics.db.ReadGraph; +import org.simantics.objmap.exceptions.MappingException; + +public interface IBackwardMappingSchema { + /** + * @return Link type that should be used for the element. + */ + IBackwardLinkType linkTypeOfRangeElement(ReadGraph graph, Range element) throws MappingException; +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/bidirectional/IBidirectionalLinkType.java b/org.simantics.objmap2/src/org/simantics/objmap/bidirectional/IBidirectionalLinkType.java new file mode 100644 index 00000000..11bbcc93 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/bidirectional/IBidirectionalLinkType.java @@ -0,0 +1,10 @@ +package org.simantics.objmap.bidirectional; + +import org.simantics.objmap.backward.IBackwardLinkType; +import org.simantics.objmap.forward.IForwardLinkType; + + +public interface IBidirectionalLinkType +extends IForwardLinkType, IBackwardLinkType, +IBidirectionalMappingRule { +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/bidirectional/IBidirectionalMapping.java b/org.simantics.objmap2/src/org/simantics/objmap/bidirectional/IBidirectionalMapping.java new file mode 100644 index 00000000..611dab08 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/bidirectional/IBidirectionalMapping.java @@ -0,0 +1,9 @@ +package org.simantics.objmap.bidirectional; + +import org.simantics.objmap.backward.IBackwardMapping; +import org.simantics.objmap.forward.IForwardMapping; + + +public interface IBidirectionalMapping +extends IForwardMapping, IBackwardMapping { +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/bidirectional/IBidirectionalMappingRule.java b/org.simantics.objmap2/src/org/simantics/objmap/bidirectional/IBidirectionalMappingRule.java new file mode 100644 index 00000000..f29c01f1 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/bidirectional/IBidirectionalMappingRule.java @@ -0,0 +1,20 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.bidirectional; + +import org.simantics.objmap.backward.IBackwardMappingRule; +import org.simantics.objmap.forward.IForwardMappingRule; + + +public interface IBidirectionalMappingRule +extends IForwardMappingRule, IBackwardMappingRule { +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/bidirectional/IBidirectionalMappingSchema.java b/org.simantics.objmap2/src/org/simantics/objmap/bidirectional/IBidirectionalMappingSchema.java new file mode 100644 index 00000000..12dd14fe --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/bidirectional/IBidirectionalMappingSchema.java @@ -0,0 +1,13 @@ +package org.simantics.objmap.bidirectional; + +import org.simantics.db.ReadGraph; +import org.simantics.objmap.backward.IBackwardMappingSchema; +import org.simantics.objmap.exceptions.MappingException; +import org.simantics.objmap.forward.IForwardMappingSchema; + + +public interface IBidirectionalMappingSchema +extends IForwardMappingSchema, IBackwardMappingSchema { + IBidirectionalLinkType linkTypeOfDomainElement(ReadGraph graph, Domain element) throws MappingException; + IBidirectionalLinkType linkTypeOfRangeElement(ReadGraph graph, Range element) throws MappingException; +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/exceptions/MappingException.java b/org.simantics.objmap2/src/org/simantics/objmap/exceptions/MappingException.java new file mode 100644 index 00000000..bed3de74 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/exceptions/MappingException.java @@ -0,0 +1,24 @@ +package org.simantics.objmap.exceptions; + +import org.simantics.db.exception.DatabaseException; + +public class MappingException extends DatabaseException { + private static final long serialVersionUID = 5381307568357191426L; + + + public MappingException() { + super(); + } + + public MappingException(String message) { + super(message); + } + + public MappingException(Throwable cause) { + super(cause); + } + + public MappingException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/forward/IForwardLinkType.java b/org.simantics.objmap2/src/org/simantics/objmap/forward/IForwardLinkType.java new file mode 100644 index 00000000..94272661 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/forward/IForwardLinkType.java @@ -0,0 +1,16 @@ +package org.simantics.objmap.forward; + +import org.simantics.db.ReadGraph; +import org.simantics.objmap.exceptions.MappingException; + +/** + * Contains rules for creating and updating range elements for given + * domain elements. + * @author Hannu Niemistö + */ +public interface IForwardLinkType extends IForwardMappingRule { + /** + * Creates a range element based on a known domain element. + */ + Range createRangeElement(ReadGraph graph, Domain domainElement) throws MappingException; +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/forward/IForwardMapping.java b/org.simantics.objmap2/src/org/simantics/objmap/forward/IForwardMapping.java new file mode 100644 index 00000000..23a484d8 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/forward/IForwardMapping.java @@ -0,0 +1,12 @@ +package org.simantics.objmap.forward; + +import java.util.Set; + +import org.simantics.db.ReadGraph; +import org.simantics.objmap.exceptions.MappingException; + +public interface IForwardMapping { + Set getDomain(); + Range get(Domain domainElement); + Range map(ReadGraph graph, Domain domainElement) throws MappingException; +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/forward/IForwardMappingRule.java b/org.simantics.objmap2/src/org/simantics/objmap/forward/IForwardMappingRule.java new file mode 100644 index 00000000..6c89d8d6 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/forward/IForwardMappingRule.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.forward; + +import org.simantics.db.ReadGraph; +import org.simantics.objmap.exceptions.MappingException; + +public interface IForwardMappingRule { + /** + * Modifies the range element so that it corresponds to the domain element. + * @param g read transaction + * @param map unidirectional view of the current mapping + * @param domainElement the domain element that corresponds to the range element + * @param rangeElement the range element that is updated + * @return true if the rule made some modifications + * @throws MappingException + */ + boolean updateRange(ReadGraph graph, IForwardMapping mapping, Domain domainElement, Range rangeElement) throws MappingException; + void createRange(ReadGraph graph, IForwardMapping mapping, Domain domainElement, Range rangeElement) throws MappingException; +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/forward/IForwardMappingSchema.java b/org.simantics.objmap2/src/org/simantics/objmap/forward/IForwardMappingSchema.java new file mode 100644 index 00000000..d0a8afad --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/forward/IForwardMappingSchema.java @@ -0,0 +1,11 @@ +package org.simantics.objmap.forward; + +import org.simantics.db.ReadGraph; +import org.simantics.objmap.exceptions.MappingException; + +public interface IForwardMappingSchema { + /** + * @return Link type that should be used for the element. + */ + IForwardLinkType linkTypeOfDomainElement(ReadGraph graph, Domain element) throws MappingException; +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/IMapping.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/IMapping.java new file mode 100644 index 00000000..fbf876b2 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/IMapping.java @@ -0,0 +1,142 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.graph; + +import java.util.Collection; +import java.util.Set; + +import org.simantics.db.Disposable; +import org.simantics.db.ReadGraph; +import org.simantics.db.WriteGraph; +import org.simantics.objmap.bidirectional.IBidirectionalMapping; +import org.simantics.objmap.exceptions.MappingException; + +/** + * A mapping consists of domain (a set of resources), range (a set of Java objects) and + * a set of links relating them. The mapping is used to propagate modifications of + * domain elements to range and vice versa. + * + * @see Manual + * + * @author Hannu Niemistö + */ +public interface IMapping extends Disposable, IBidirectionalMapping { + + /** + * Returns the domain of the mapping. All set operations are supported. + * Adding a new domain element does not automatically create a link to it. + * Removal of a domain element removes also a link and the target element, + * but does not remove the element from the database. + */ + Set getDomain(); + + /** + * Returns the range of the mapping. All set operations are supported. + * Adding a new range element does not automatically create a link to it. + * Removal of a range element removes also a link and the domain element, + * but does not remove the domain element from the database. + */ + Set getRange(); + + /** + * Updates all domain elements whose counterpart is modified and creates new + * domain elements for previously added range elements. Returns the + * collection of domain elements that were modified or created in the update + * process. + */ + Collection updateDomain(WriteGraph g) throws MappingException; + + /** + * Updates all range elements whose counterpart is modified and creates new + * range elements for previously added domain elements. Returns the + * collection of range elements that were modified or created in the update + * process. + */ + Collection updateRange(ReadGraph g) throws MappingException; + + /** + * Returns the counterpart of a domain element or null if the element does + * not belong to the domain or does not have a link. + */ + Range get(Domain domainElement); + + /** + * Returns the counterpart of a range element or null if the element does + * not belong to the range or does not have a link. + */ + Domain inverseGet(Range rangeElement); + + /** + * A convenience method that adds a domain element to the mapping and + * immediately updates the mapping and returns the corresponding range + * element. + */ + Range map(ReadGraph g, Domain domainElement) throws MappingException; + + /** + * A convenience method that adds a range element to the mapping and + * immediately updates the mapping and returns the corresponding domain + * element. + */ + Domain inverseMap(WriteGraph g, Range rangeElement) + throws MappingException; + + /** + * Tells the mapping that the domain element has been modified. + */ + void domainModified(Domain domainElement); + + /** + * Tells the mapping that the range element has been modified. + */ + void rangeModified(Range rangeElement); + + /** + * Tells if some domain elements have been modified or added. + */ + boolean isDomainModified(); + + /** + * Tells if some range elements have been modified or added. + */ + boolean isRangeModified(); + + Collection getDomainModified(); + Collection getRangeModified(); + + /** + * Returns a collection of domain elements which have been modified and also + * their counterparts in the mapping are modified. These elements are in + * conflict in the sense that the updating domain and range in different + * orders may produce different results. + */ + Collection getConflictingDomainElements(); + + /** + * Returns a collection of range elements which have been modified and also + * their counterparts in the mapping are modified. These elements are in + * conflict in the sense that the updating domain and range in different + * orders may produce different results. + */ + Collection getConflictingRangeElements(); + + /** + * Adds a listener for domain and range modifications. + */ + void addMappingListener(IMappingListener listener); + + /** + * Removes a previously added listener. + */ + void removeMappingListener(IMappingListener listener); + +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/IMappingListener.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/IMappingListener.java new file mode 100644 index 00000000..a48166b3 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/IMappingListener.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.graph; + +/** + * Listens modifications in a mapping. + * @author Hannu Niemistö + */ +public interface IMappingListener { + /** + * Called when some domain element is modified or created + * and the mapping was previously up to date. + */ + void domainModified(); + + /** + * Called when some range element is modified or created + * and the mapping was previously up to date. + */ + void rangeModified(); +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/Mappings.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/Mappings.java new file mode 100644 index 00000000..e60b0187 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/Mappings.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.graph; + +import org.simantics.db.Resource; +import org.simantics.objmap.graph.impl.Mapping; +import org.simantics.objmap.graph.schema.IMappingSchema; +/** + * Static utility methods for mappings. + * @author Hannu Niemistö + */ +public class Mappings { + private Mappings() {} + + /** + * Creates a new mapping based on the given mapping schema. + * The created mapping is not thread-safe and will not + * listen database changes automatically. + */ + public static IMapping createWithoutListening(IMappingSchema schema) { + return new Mapping(schema, false); + } + + /** + * Creates a new mapping based on the given mapping schema. + * The created mapping is not thread-safe. It listens database + * changes automatically. + */ + public static IMapping createWithListening(IMappingSchema schema) { + return new Mapping(schema, true); + } + + +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/Composition.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/Composition.java new file mode 100644 index 00000000..2611b705 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/Composition.java @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.graph.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD,ElementType.METHOD}) +public @interface Composition { +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/CompoundRelatedGetValue.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/CompoundRelatedGetValue.java new file mode 100644 index 00000000..709ae6fa --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/CompoundRelatedGetValue.java @@ -0,0 +1,23 @@ +package org.simantics.objmap.graph.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.simantics.objmap.graph.annotations.meta.IsGetSetRule; +import org.simantics.objmap.graph.rules.adapters.IdentityAdapter; +import org.simantics.objmap.graph.rules.adapters.ValueAdapter; + + + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +@IsGetSetRule +@HasSetter(CompoundRelatedSetValue.class) +public @interface CompoundRelatedGetValue { + String objRelation(); + String objType(); + String valRelation(); +// Class adapter() default IdentityAdapter.class; +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/CompoundRelatedSetValue.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/CompoundRelatedSetValue.java new file mode 100644 index 00000000..93ceeb41 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/CompoundRelatedSetValue.java @@ -0,0 +1,13 @@ +package org.simantics.objmap.graph.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface CompoundRelatedSetValue { + String value(); +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/DynamicGraphType.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/DynamicGraphType.java new file mode 100644 index 00000000..530803ae --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/DynamicGraphType.java @@ -0,0 +1,12 @@ +package org.simantics.objmap.graph.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface DynamicGraphType { + String value(); +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/GetType.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/GetType.java new file mode 100644 index 00000000..f4be045e --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/GetType.java @@ -0,0 +1,15 @@ +package org.simantics.objmap.graph.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + + + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +//@HasGetSetRuleFactory(RelatedGetSetValueRuleFactory.class) +public @interface GetType { + String value(); +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/GraphType.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/GraphType.java new file mode 100644 index 00000000..24fff136 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/GraphType.java @@ -0,0 +1,12 @@ +package org.simantics.objmap.graph.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface GraphType { + String value(); +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/HasCollectionAdder.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/HasCollectionAdder.java new file mode 100644 index 00000000..640aa4db --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/HasCollectionAdder.java @@ -0,0 +1,13 @@ +package org.simantics.objmap.graph.annotations; + +import java.lang.annotation.Annotation; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.ANNOTATION_TYPE) +public @interface HasCollectionAdder { + Class value(); +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/HasCollectionRemover.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/HasCollectionRemover.java new file mode 100644 index 00000000..5e32a243 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/HasCollectionRemover.java @@ -0,0 +1,13 @@ +package org.simantics.objmap.graph.annotations; + +import java.lang.annotation.Annotation; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.ANNOTATION_TYPE) +public @interface HasCollectionRemover { + Class value(); +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/HasSetter.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/HasSetter.java new file mode 100644 index 00000000..e312cd76 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/HasSetter.java @@ -0,0 +1,13 @@ +package org.simantics.objmap.graph.annotations; + +import java.lang.annotation.Annotation; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.ANNOTATION_TYPE) +public @interface HasSetter { + Class value(); +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/OptionalRelatedElements.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/OptionalRelatedElements.java new file mode 100644 index 00000000..103af11e --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/OptionalRelatedElements.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.graph.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.simantics.objmap.graph.annotations.meta.IsFieldRule; + + + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +//@HasFieldRuleFactory(OptionalRelatedElementsRuleFactory.class) +@IsFieldRule +public @interface OptionalRelatedElements { + String value(); + boolean composition() default false; +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedElement.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedElement.java new file mode 100644 index 00000000..554d9a8a --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedElement.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.graph.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.simantics.objmap.graph.annotations.meta.IsFieldRule; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +//HasFieldRuleFactory(RelatedElementRuleFactory.class) +@IsFieldRule +public @interface RelatedElement { + String value(); +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedElements.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedElements.java new file mode 100644 index 00000000..4ef5fb02 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedElements.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.graph.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.simantics.objmap.graph.annotations.meta.IsFieldRule; + + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +//@HasFieldRuleFactory(RelatedElementsRuleFactory.class) +@IsFieldRule +public @interface RelatedElements { + String value(); + boolean composition() default false; +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedElementsAdd.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedElementsAdd.java new file mode 100644 index 00000000..b071c7c8 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedElementsAdd.java @@ -0,0 +1,12 @@ +package org.simantics.objmap.graph.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface RelatedElementsAdd { + String value(); +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedElementsGet.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedElementsGet.java new file mode 100644 index 00000000..135fadc5 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedElementsGet.java @@ -0,0 +1,22 @@ +package org.simantics.objmap.graph.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.simantics.objmap.graph.annotations.meta.IsCollectionRule; + + + + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +//@HasCollectionRuleFactory(RelatedElementsRuleFactory2.class) +@IsCollectionRule +@HasCollectionAdder(RelatedElementsAdd.class) +@HasCollectionRemover(RelatedElementsRem.class) +public @interface RelatedElementsGet { + String value(); + boolean composition() default false; +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedElementsRem.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedElementsRem.java new file mode 100644 index 00000000..fb8d1dbc --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedElementsRem.java @@ -0,0 +1,13 @@ +package org.simantics.objmap.graph.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface RelatedElementsRem { + String value(); +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedGetObj.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedGetObj.java new file mode 100644 index 00000000..2a8f30ce --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedGetObj.java @@ -0,0 +1,19 @@ +package org.simantics.objmap.graph.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.simantics.objmap.graph.annotations.meta.IsGetSetRule; + + + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +//@HasGetSetRuleFactory(RelatedGetSetObjRuleFactory.class) +@IsGetSetRule +@HasSetter(RelatedSetObj.class) +public @interface RelatedGetObj { + String value(); +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedGetValue.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedGetValue.java new file mode 100644 index 00000000..d3d1414c --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedGetValue.java @@ -0,0 +1,22 @@ +package org.simantics.objmap.graph.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.simantics.objmap.graph.annotations.meta.IsGetSetRule; +import org.simantics.objmap.graph.rules.adapters.IdentityAdapter; +import org.simantics.objmap.graph.rules.adapters.ValueAdapter; + + + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +//@HasGetSetRuleFactory(RelatedGetSetValueRuleFactory.class) +@IsGetSetRule +@HasSetter(RelatedSetValue.class) +public @interface RelatedGetValue { + String value(); + Class adapter() default IdentityAdapter.class; +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedOrderedSetElements.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedOrderedSetElements.java new file mode 100644 index 00000000..fe6afef8 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedOrderedSetElements.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.graph.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.simantics.objmap.graph.annotations.meta.IsFieldRule; + + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +//@HasFieldRuleFactory(RelatedOrderedSetElementsRuleFactory.class) +@IsFieldRule +public @interface RelatedOrderedSetElements { + boolean composition() default false; +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedSetObj.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedSetObj.java new file mode 100644 index 00000000..e3212e1b --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedSetObj.java @@ -0,0 +1,13 @@ +package org.simantics.objmap.graph.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface RelatedSetObj { + String value(); +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedSetValue.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedSetValue.java new file mode 100644 index 00000000..201b0cfa --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedSetValue.java @@ -0,0 +1,13 @@ +package org.simantics.objmap.graph.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface RelatedSetValue { + String value(); +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedValue.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedValue.java new file mode 100644 index 00000000..e8148c49 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedValue.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.graph.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.simantics.objmap.graph.annotations.meta.IsFieldRule; +import org.simantics.objmap.graph.rules.adapters.IdentityAdapter; +import org.simantics.objmap.graph.rules.adapters.ValueAdapter; + + + +/** + * Specifies a correspondence between a field and + * functional property. + * @author Hannu Niemistö + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +//@HasFieldRuleFactory(RelatedValueRuleFactory.class) +@IsFieldRule +public @interface RelatedValue { + String value(); + Class adapter() default IdentityAdapter.class; +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/SetType.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/SetType.java new file mode 100644 index 00000000..28ff9c17 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/SetType.java @@ -0,0 +1,15 @@ +package org.simantics.objmap.graph.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + + + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +//@HasGetSetRuleFactory(RelatedGetSetValueRuleFactory.class) +public @interface SetType { + String value(); +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/UpdateMethod.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/UpdateMethod.java new file mode 100644 index 00000000..cc339862 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/UpdateMethod.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.graph.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.simantics.objmap.graph.annotations.meta.IsFieldRule; + + + +/** + * Specifies that the annotated method should be called + * to update range object. + * @author Hannu Niemistö + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +//@HasMethodRuleFactory(UpdateMethodFactory.class) +@IsFieldRule +public @interface UpdateMethod { +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/CompoundRelatedGetSetValueRuleFactory.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/CompoundRelatedGetSetValueRuleFactory.java new file mode 100644 index 00000000..333686f2 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/CompoundRelatedGetSetValueRuleFactory.java @@ -0,0 +1,102 @@ +package org.simantics.objmap.graph.annotations.factories; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; + +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.exception.DatabaseException; +import org.simantics.layer0.Layer0; +import org.simantics.objmap.bidirectional.IBidirectionalMappingRule; +import org.simantics.objmap.graph.annotations.CompoundRelatedGetValue; +import org.simantics.objmap.graph.annotations.CompoundRelatedSetValue; +import org.simantics.objmap.graph.rules.ValueRule; +import org.simantics.objmap.graph.rules.adapters.IdentityAdapter; +import org.simantics.objmap.graph.rules.adapters.ValueAdapter; +import org.simantics.objmap.graph.rules.domain.CompoundValueAccessor; +import org.simantics.objmap.graph.rules.factory.IGetSetRuleFactory; +import org.simantics.objmap.graph.rules.range.AdaptedRangeAccessor; +import org.simantics.objmap.graph.rules.range.CompoundGetSetValueAccessor; +import org.simantics.objmap.graph.rules.range.IRangeAccessor; + +/** + * Rule factory for mapped value using Getter/Setter-methods. + * + * @author Marko Luukkainen + * + */ +public class CompoundRelatedGetSetValueRuleFactory implements IGetSetRuleFactory { + + @Override + public IBidirectionalMappingRule create(ReadGraph g, Annotation annotation, + Method getter, Method setter) + throws DatabaseException { + CompoundRelatedGetValue getterAnn = (CompoundRelatedGetValue)annotation; + +// Class adapterClass = getterAnn.adapter(); + IRangeAccessor rangeAccessor = new CompoundGetSetValueAccessor(getter, setter); +// Resource valueType; +// if (adapterClass == IdentityAdapter.class) { +// valueType = dataTypeOfClass(g, getter.getReturnType()); +// } else { +// try{ +// ValueAdapter adapter = adapterClass.newInstance(); +// rangeAccessor = new AdaptedRangeAccessor(rangeAccessor, adapter); +// valueType = adapter.rangeTypeToDomainType(g, getter.getReturnType()); +// } catch (InstantiationException e) { +// throw new RuntimeException(e); +// } catch (IllegalAccessException e) { +// throw new RuntimeException(e); +// } +// } + return new ValueRule(new CompoundValueAccessor(g.getResource(getterAnn.objRelation()), + g.getResource(getterAnn.objType()), + g.getResource(getterAnn.valRelation())), + rangeAccessor); + } + + @Override + public boolean isSetter(Annotation getterAnnotation, Annotation annotation) { + CompoundRelatedGetValue getterAnn = (CompoundRelatedGetValue)getterAnnotation; + CompoundRelatedSetValue setterAnn = (CompoundRelatedSetValue)annotation; + return getterAnn.objRelation().equals(setterAnn.value()); + } + + public static Resource dataTypeOfClass(ReadGraph g, Class clazz) { + Layer0 b = Layer0.getInstance(g); + if(clazz.equals(Double.class) || clazz.equals(double.class)) + return b.Double; + else if(clazz.equals(String.class)) + return b.String; + else if(clazz.equals(Integer.class) || clazz.equals(int.class)) + return b.Integer; + else if(clazz.equals(Float.class) || clazz.equals(float.class)) + return b.Float; + else if(clazz.equals(Boolean.class) || clazz.equals(boolean.class)) + return b.Boolean; + else if(clazz.equals(Long.class) || clazz.equals(long.class)) + return b.Long; + else if(clazz.equals(Byte.class) || clazz.equals(byte.class)) + return b.Byte; + + else if(clazz.equals(double[].class)) + return b.DoubleArray; + else if(clazz.equals(int[].class)) + return b.IntegerArray; + else if(clazz.equals(byte[].class)) + return b.ByteArray; + else if(clazz.equals(float[].class)) + return b.FloatArray; + else if(clazz.equals(boolean[].class)) + return b.BooleanArray; + else if(clazz.equals(String[].class)) + return b.StringArray; + else if(clazz.equals(long[].class)) + return b.LongArray; + else { + System.out.println("Couldn't find a data type for " + clazz); + return null; + } + } + +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/DataTypeUtils.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/DataTypeUtils.java new file mode 100644 index 00000000..b61ab051 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/DataTypeUtils.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.graph.annotations.factories; + +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.layer0.Layer0; + +public class DataTypeUtils { + + public static Resource dataTypeOfClass(ReadGraph g, Class clazz) { + Layer0 b = Layer0.getInstance(g); + if(clazz.equals(Double.class) || clazz.equals(double.class)) + return b.Double; + else if(clazz.equals(String.class)) + return b.String; + else if(clazz.equals(Integer.class) || clazz.equals(int.class)) + return b.Integer; + else if(clazz.equals(Float.class) || clazz.equals(float.class)) + return b.Float; + else if(clazz.equals(Boolean.class) || clazz.equals(boolean.class)) + return b.Boolean; + else if(clazz.equals(Long.class) || clazz.equals(long.class)) + return b.Long; + else if(clazz.equals(Byte.class) || clazz.equals(byte.class)) + return b.Byte; + + else if(clazz.equals(double[].class)) + return b.DoubleArray; + else if(clazz.equals(int[].class)) + return b.IntegerArray; + else if(clazz.equals(byte[].class)) + return b.ByteArray; + else if(clazz.equals(float[].class)) + return b.FloatArray; + else if(clazz.equals(boolean[].class)) + return b.BooleanArray; + else if(clazz.equals(String[].class)) + return b.StringArray; + else if(clazz.equals(long[].class)) + return b.LongArray; + else { + System.out.println("Couldn't find a data type for " + clazz); + return null; + } + } + +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/OptionalRelatedElementsRuleFactory.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/OptionalRelatedElementsRuleFactory.java new file mode 100644 index 00000000..6900fda6 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/OptionalRelatedElementsRuleFactory.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.graph.annotations.factories; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.util.Collection; +import java.util.Collections; + +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.exception.ResourceNotFoundException; +import org.simantics.db.exception.ServiceException; +import org.simantics.db.exception.ValidationException; +import org.simantics.objmap.bidirectional.IBidirectionalMappingRule; +import org.simantics.objmap.graph.annotations.OptionalRelatedElements; +import org.simantics.objmap.graph.rules.MappedElementsRule; +import org.simantics.objmap.graph.rules.domain.RelatedObjectsAccessor; +import org.simantics.objmap.graph.rules.factory.IFieldRuleFactory; +import org.simantics.objmap.graph.rules.range.FieldAccessorWithDefault; + + +public class OptionalRelatedElementsRuleFactory implements IFieldRuleFactory { + + @Override + public IBidirectionalMappingRule create(ReadGraph g, Annotation _annotation, Field field) throws ResourceNotFoundException, ValidationException, ServiceException { + OptionalRelatedElements annotation = (OptionalRelatedElements)_annotation; + return new MappedElementsRule( + new RelatedObjectsAccessor(g.getResource(annotation.value()), + annotation.composition()), + new FieldAccessorWithDefault>(field, (Collection)Collections.emptyList()) + ); + } + +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/RelatedElementRuleFactory.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/RelatedElementRuleFactory.java new file mode 100644 index 00000000..6aab217c --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/RelatedElementRuleFactory.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.graph.annotations.factories; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; + +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.exception.ResourceNotFoundException; +import org.simantics.db.exception.ServiceException; +import org.simantics.db.exception.ValidationException; +import org.simantics.objmap.bidirectional.IBidirectionalMappingRule; +import org.simantics.objmap.graph.annotations.RelatedElement; +import org.simantics.objmap.graph.rules.MappedElementRule; +import org.simantics.objmap.graph.rules.domain.RelatedObjectAccessor; +import org.simantics.objmap.graph.rules.factory.IFieldRuleFactory; +import org.simantics.objmap.graph.rules.range.FieldAccessor; + + +public class RelatedElementRuleFactory implements IFieldRuleFactory { + + @Override + public IBidirectionalMappingRule create(ReadGraph g, Annotation _annotation, Field field) throws ResourceNotFoundException, ValidationException, ServiceException { + RelatedElement annotation = (RelatedElement)_annotation; + return new MappedElementRule( + new RelatedObjectAccessor(g.getResource(annotation.value())), + new FieldAccessor(field) + ); + } + +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/RelatedElementsRuleFactory.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/RelatedElementsRuleFactory.java new file mode 100644 index 00000000..c086aed0 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/RelatedElementsRuleFactory.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.graph.annotations.factories; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.util.Collection; + +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.exception.ResourceNotFoundException; +import org.simantics.db.exception.ServiceException; +import org.simantics.db.exception.ValidationException; +import org.simantics.objmap.bidirectional.IBidirectionalMappingRule; +import org.simantics.objmap.graph.annotations.RelatedElements; +import org.simantics.objmap.graph.rules.MappedElementsRule; +import org.simantics.objmap.graph.rules.domain.RelatedObjectsAccessor; +import org.simantics.objmap.graph.rules.factory.IFieldRuleFactory; +import org.simantics.objmap.graph.rules.range.FieldAccessor; + + +public class RelatedElementsRuleFactory implements IFieldRuleFactory { + + @Override + public IBidirectionalMappingRule create(ReadGraph g, Annotation _annotation, Field field) throws ResourceNotFoundException, ValidationException, ServiceException { + RelatedElements annotation = (RelatedElements)_annotation; + return new MappedElementsRule( + new RelatedObjectsAccessor(g.getResource(annotation.value()), + annotation.composition()), + new FieldAccessor>(field) + ); + } + +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/RelatedElementsRuleFactory2.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/RelatedElementsRuleFactory2.java new file mode 100644 index 00000000..81bba3f6 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/RelatedElementsRuleFactory2.java @@ -0,0 +1,44 @@ +package org.simantics.objmap.graph.annotations.factories; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; + +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.exception.DatabaseException; +import org.simantics.objmap.bidirectional.IBidirectionalMappingRule; +import org.simantics.objmap.graph.annotations.RelatedElementsAdd; +import org.simantics.objmap.graph.annotations.RelatedElementsGet; +import org.simantics.objmap.graph.annotations.RelatedElementsRem; +import org.simantics.objmap.graph.rules.MappedElementsRule; +import org.simantics.objmap.graph.rules.domain.RelatedObjectsAccessor; +import org.simantics.objmap.graph.rules.factory.ICollectionRuleFactory; +import org.simantics.objmap.graph.rules.range.CollectionAccessor; + + +public class RelatedElementsRuleFactory2 implements ICollectionRuleFactory { + + @Override + public IBidirectionalMappingRule create(ReadGraph g, Annotation annotation, + Method getter, Method adder, Method remover) + throws DatabaseException { + RelatedElementsGet getterAnn = (RelatedElementsGet)annotation; + return new MappedElementsRule(new RelatedObjectsAccessor(g.getResource(getterAnn.value()),getterAnn.composition()), + new CollectionAccessor(getter, adder, remover)); + } + + @Override + public boolean isAdder(Annotation getterAnnotation, Annotation annotation) { + RelatedElementsGet getterAnn = (RelatedElementsGet)getterAnnotation; + RelatedElementsAdd adderAnn = (RelatedElementsAdd)annotation; + return getterAnn.value().equals(adderAnn.value()); + } + + @Override + public boolean isRemover(Annotation getterAnnotation, Annotation annotation) { + RelatedElementsGet getterAnn = (RelatedElementsGet)getterAnnotation; + RelatedElementsRem adderAnn = (RelatedElementsRem)annotation; + return getterAnn.value().equals(adderAnn.value()); + } + +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/RelatedGetSetObjRuleFactory.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/RelatedGetSetObjRuleFactory.java new file mode 100644 index 00000000..f031f4bf --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/RelatedGetSetObjRuleFactory.java @@ -0,0 +1,44 @@ +package org.simantics.objmap.graph.annotations.factories; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; + +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.exception.DatabaseException; +import org.simantics.objmap.bidirectional.IBidirectionalMappingRule; +import org.simantics.objmap.graph.annotations.RelatedGetObj; +import org.simantics.objmap.graph.annotations.RelatedSetObj; +import org.simantics.objmap.graph.rules.MappedElementRule; +import org.simantics.objmap.graph.rules.domain.RelatedObjectAccessor; +import org.simantics.objmap.graph.rules.factory.IGetSetRuleFactory; +import org.simantics.objmap.graph.rules.range.GetSetObjectAccessor; + + +/** + * Rule factory for mapped object using Getter/Setter-methods. + * + * @author Marko Luukkainen + * + */ +public class RelatedGetSetObjRuleFactory implements IGetSetRuleFactory { + + @Override + public IBidirectionalMappingRule create(ReadGraph g, Annotation annotation, + Method getter, Method setter) + throws DatabaseException { + RelatedGetObj getterAnn = (RelatedGetObj)annotation; + return new MappedElementRule(new RelatedObjectAccessor(g.getResource(getterAnn.value())), + new GetSetObjectAccessor(getter, setter)); + } + + @Override + public boolean isSetter(Annotation getterAnnotation, Annotation annotation) { + RelatedGetObj getterAnn = (RelatedGetObj)getterAnnotation; + RelatedSetObj setterAnn = (RelatedSetObj)annotation; + return getterAnn.value().equals(setterAnn.value()); + } + + + +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/RelatedGetSetValueRuleFactory.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/RelatedGetSetValueRuleFactory.java new file mode 100644 index 00000000..5579b07b --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/RelatedGetSetValueRuleFactory.java @@ -0,0 +1,100 @@ +package org.simantics.objmap.graph.annotations.factories; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; + +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.exception.DatabaseException; +import org.simantics.layer0.Layer0; +import org.simantics.objmap.bidirectional.IBidirectionalMappingRule; +import org.simantics.objmap.graph.annotations.RelatedGetValue; +import org.simantics.objmap.graph.annotations.RelatedSetValue; +import org.simantics.objmap.graph.rules.ValueRule; +import org.simantics.objmap.graph.rules.adapters.IdentityAdapter; +import org.simantics.objmap.graph.rules.adapters.ValueAdapter; +import org.simantics.objmap.graph.rules.domain.RelatedValueAccessor; +import org.simantics.objmap.graph.rules.factory.IGetSetRuleFactory; +import org.simantics.objmap.graph.rules.range.AdaptedRangeAccessor; +import org.simantics.objmap.graph.rules.range.GetSetValueAccessor; +import org.simantics.objmap.graph.rules.range.IRangeAccessor; + +/** + * Rule factory for mapped value using Getter/Setter-methods. + * + * @author Marko Luukkainen + * + */ +public class RelatedGetSetValueRuleFactory implements IGetSetRuleFactory { + + @Override + public IBidirectionalMappingRule create(ReadGraph g, Annotation annotation, + Method getter, Method setter) + throws DatabaseException { + RelatedGetValue getterAnn = (RelatedGetValue)annotation; + + Class adapterClass = getterAnn.adapter(); + IRangeAccessor rangeAccessor = new GetSetValueAccessor(getter, setter); + Resource valueType; + if (adapterClass == IdentityAdapter.class) { + valueType = dataTypeOfClass(g, getter.getReturnType()); + } else { + try{ + ValueAdapter adapter = adapterClass.newInstance(); + rangeAccessor = new AdaptedRangeAccessor(rangeAccessor, adapter); + valueType = adapter.rangeTypeToDomainType(g, getter.getReturnType()); + } catch (InstantiationException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + return new ValueRule(new RelatedValueAccessor(g.getResource(getterAnn.value()), valueType), + rangeAccessor); + } + + @Override + public boolean isSetter(Annotation getterAnnotation, Annotation annotation) { + RelatedGetValue getterAnn = (RelatedGetValue)getterAnnotation; + RelatedSetValue setterAnn = (RelatedSetValue)annotation; + return getterAnn.value().equals(setterAnn.value()); + } + + public static Resource dataTypeOfClass(ReadGraph g, Class clazz) { + Layer0 b = Layer0.getInstance(g); + if(clazz.equals(Double.class) || clazz.equals(double.class)) + return b.Double; + else if(clazz.equals(String.class)) + return b.String; + else if(clazz.equals(Integer.class) || clazz.equals(int.class)) + return b.Integer; + else if(clazz.equals(Float.class) || clazz.equals(float.class)) + return b.Float; + else if(clazz.equals(Boolean.class) || clazz.equals(boolean.class)) + return b.Boolean; + else if(clazz.equals(Long.class) || clazz.equals(long.class)) + return b.Long; + else if(clazz.equals(Byte.class) || clazz.equals(byte.class)) + return b.Byte; + + else if(clazz.equals(double[].class)) + return b.DoubleArray; + else if(clazz.equals(int[].class)) + return b.IntegerArray; + else if(clazz.equals(byte[].class)) + return b.ByteArray; + else if(clazz.equals(float[].class)) + return b.FloatArray; + else if(clazz.equals(boolean[].class)) + return b.BooleanArray; + else if(clazz.equals(String[].class)) + return b.StringArray; + else if(clazz.equals(long[].class)) + return b.LongArray; + else { + System.out.println("Couldn't find a data type for " + clazz); + return null; + } + } + +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/RelatedOrderedSetElementsRuleFactory.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/RelatedOrderedSetElementsRuleFactory.java new file mode 100644 index 00000000..d9be2744 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/RelatedOrderedSetElementsRuleFactory.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.graph.annotations.factories; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.util.Collection; + +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.exception.ResourceNotFoundException; +import org.simantics.db.exception.ServiceException; +import org.simantics.db.exception.ValidationException; +import org.simantics.objmap.bidirectional.IBidirectionalMappingRule; +import org.simantics.objmap.graph.annotations.RelatedOrderedSetElements; +import org.simantics.objmap.graph.rules.MappedElementsRule; +import org.simantics.objmap.graph.rules.domain.RelatedOrderedSetElementsAccessor; +import org.simantics.objmap.graph.rules.factory.IFieldRuleFactory; +import org.simantics.objmap.graph.rules.range.FieldAccessor; + + +public class RelatedOrderedSetElementsRuleFactory implements IFieldRuleFactory { + + @Override + public IBidirectionalMappingRule create(ReadGraph g, Annotation _annotation, Field field) throws ResourceNotFoundException, ValidationException, ServiceException { + RelatedOrderedSetElements annotation = (RelatedOrderedSetElements)_annotation; + return new MappedElementsRule( + new RelatedOrderedSetElementsAccessor(annotation.composition()), + new FieldAccessor>(field) + ); + } + +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/RelatedValueRuleFactory.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/RelatedValueRuleFactory.java new file mode 100644 index 00000000..2d906701 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/RelatedValueRuleFactory.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.graph.annotations.factories; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; + +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.exception.ResourceNotFoundException; +import org.simantics.db.exception.ServiceException; +import org.simantics.db.exception.ValidationException; + +import org.simantics.objmap.bidirectional.IBidirectionalMappingRule; +import org.simantics.objmap.graph.annotations.RelatedValue; +import org.simantics.objmap.graph.rules.ValueRule; +import org.simantics.objmap.graph.rules.adapters.IdentityAdapter; +import org.simantics.objmap.graph.rules.adapters.ValueAdapter; +import org.simantics.objmap.graph.rules.domain.RelatedValueAccessor; +import org.simantics.objmap.graph.rules.factory.IFieldRuleFactory; +import org.simantics.objmap.graph.rules.range.AdaptedRangeAccessor; +import org.simantics.objmap.graph.rules.range.FieldAccessor; +import org.simantics.objmap.graph.rules.range.IRangeAccessor; + + +public class RelatedValueRuleFactory implements IFieldRuleFactory { + + @Override + public IBidirectionalMappingRule create(ReadGraph g, Annotation _annotation, Field field) throws ResourceNotFoundException, + ValidationException, ServiceException { + RelatedValue annotation = (RelatedValue) _annotation; + Class adapterClass = annotation.adapter(); + IRangeAccessor rangeAccessor = new FieldAccessor(field); + Resource valueType; + if (adapterClass == IdentityAdapter.class) { + valueType = DataTypeUtils.dataTypeOfClass(g, field.getType()); + } else { + try { + ValueAdapter adapter = adapterClass.newInstance(); + rangeAccessor = new AdaptedRangeAccessor(rangeAccessor, adapter); + valueType = adapter.rangeTypeToDomainType(g, field.getType()); + } catch (InstantiationException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + return new ValueRule(new RelatedValueAccessor(g.getResource(annotation.value()), valueType), rangeAccessor); + } + +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/UpdateMethodFactory.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/UpdateMethodFactory.java new file mode 100644 index 00000000..9fde7b7f --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/UpdateMethodFactory.java @@ -0,0 +1,70 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.graph.annotations.factories; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; + +import org.apache.log4j.Logger; +import org.simantics.db.ReadGraph; +import org.simantics.db.WriteGraph; +import org.simantics.db.exception.DatabaseException; +import org.simantics.objmap.backward.IBackwardMapping; +import org.simantics.objmap.bidirectional.IBidirectionalMappingRule; +import org.simantics.objmap.exceptions.MappingException; +import org.simantics.objmap.forward.IForwardMapping; +import org.simantics.objmap.graph.rules.factory.IMethodRuleFactory; + +public class UpdateMethodFactory implements IMethodRuleFactory { + + static Logger LOGGER = Logger.getLogger("org.simantics.objmap"); + + @Override + public IBidirectionalMappingRule create(ReadGraph g, + Annotation annotation, + final Method method) + throws DatabaseException { + method.setAccessible(true); + return new IBidirectionalMappingRule() { + + @Override + public boolean updateRange(ReadGraph g, IForwardMapping map, + Domain domainElement, Range rangeElement) + throws MappingException { + LOGGER.info(" UpdateMethodFactory.updateRange"); + try { + return (Boolean)method.invoke(rangeElement, g, domainElement); + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return false; + } + + @Override + public boolean updateDomain(WriteGraph g, IBackwardMapping map, + Domain domainElement, Range rangeElement) + throws MappingException { + return false; + } + + public void createDomain(WriteGraph g, IBackwardMapping map, Domain domainElement, Range rangeElement) throws MappingException { + updateDomain(g, map, domainElement, rangeElement); + }; + + public void createRange(ReadGraph g, IForwardMapping map, Domain domainElement, Range rangeElement) throws MappingException { + updateRange(g, map, domainElement, rangeElement); + }; + }; + } + +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/meta/IsClassRule.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/meta/IsClassRule.java new file mode 100644 index 00000000..9f3c62dc --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/meta/IsClassRule.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.graph.annotations.meta; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.ANNOTATION_TYPE) +public @interface IsClassRule { + +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/meta/IsCollectionRule.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/meta/IsCollectionRule.java new file mode 100644 index 00000000..55003a5f --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/meta/IsCollectionRule.java @@ -0,0 +1,12 @@ +package org.simantics.objmap.graph.annotations.meta; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.ANNOTATION_TYPE) +public @interface IsCollectionRule { + +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/meta/IsFieldRule.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/meta/IsFieldRule.java new file mode 100644 index 00000000..2e85c531 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/meta/IsFieldRule.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.graph.annotations.meta; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.ANNOTATION_TYPE) +public @interface IsFieldRule { +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/meta/IsGetSetRule.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/meta/IsGetSetRule.java new file mode 100644 index 00000000..d723b105 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/meta/IsGetSetRule.java @@ -0,0 +1,13 @@ +package org.simantics.objmap.graph.annotations.meta; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.ANNOTATION_TYPE) +public @interface IsGetSetRule { + +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/meta/IsMethodRule.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/meta/IsMethodRule.java new file mode 100644 index 00000000..0e0ab1e4 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/meta/IsMethodRule.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.graph.annotations.meta; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.ANNOTATION_TYPE) +public @interface IsMethodRule { +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/impl/Link.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/impl/Link.java new file mode 100644 index 00000000..95591f51 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/impl/Link.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +/** + * + */ +package org.simantics.objmap.graph.impl; + +import org.simantics.objmap.graph.schema.ILinkType; + + +/** + * An indication that the domain element corresponds to the range element + * in the mapping. The link type describes how source and target objects + * are updated. There are additionally flags for dirtiness of the link. + * @author Hannu Niemistö + */ +public class Link { + public ILinkType type; + public Domain domainElement; + public Range rangeElement; + + public boolean domainModified = false; + public boolean rangeModified = false; + public boolean removed = false; + + public Link(ILinkType type, Domain domainElement, Range rangeElement) { + this.type = type; + this.domainElement = domainElement; + this.rangeElement = rangeElement; + } +} \ No newline at end of file diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/impl/Mapping.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/impl/Mapping.java new file mode 100644 index 00000000..3b75e7e0 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/impl/Mapping.java @@ -0,0 +1,476 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.graph.impl; + + +import gnu.trove.map.hash.THashMap; + +import java.util.AbstractSet; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import org.apache.log4j.Logger; +import org.simantics.db.ReadGraph; +import org.simantics.db.WriteGraph; +import org.simantics.db.exception.DatabaseException; + +import org.simantics.objmap.backward.IBackwardMapping; +import org.simantics.objmap.exceptions.MappingException; +import org.simantics.objmap.forward.IForwardMapping; +import org.simantics.objmap.graph.IMapping; +import org.simantics.objmap.graph.IMappingListener; +import org.simantics.objmap.graph.schema.ILinkType; +import org.simantics.objmap.graph.schema.IMappingSchema; + +/** + * An implementation of IMapping. The class should not be created + * directly but using methods in Mappings. + * @see org.simantics.objmap.graph.Mappings + * @author Hannu Niemistö + */ +public class Mapping implements IMapping { + + static Logger LOGGER = Logger.getLogger("org.simantics.objmap"); + + + IMappingSchema schema; + + THashMap> domain = new THashMap>(); + THashMap> range = new THashMap>(); + ArrayList listeners = new ArrayList(); + + ArrayList> modifiedDomainLinks = new ArrayList>(); + ArrayList> modifiedRangeLinks = new ArrayList>(); + + boolean disposed = false; + + boolean listensDomain; + + public Mapping(IMappingSchema schema, boolean listensDomain) { + this.schema = schema; + this.listensDomain = listensDomain; + } + + private void removeLink(Link link) { + if(link.domainModified) + modifiedDomainLinks.remove(link); + if(link.rangeModified) + modifiedRangeLinks.remove(link); + link.removed = true; + } + + private void createDomain(WriteGraph g, Link link) throws MappingException { + LOGGER.info(" createDomain for " + link.rangeElement); + ILinkType type = schema.linkTypeOfRangeElement(link.rangeElement); + Domain domainElement = type.createDomainElement(g, link.rangeElement); + link.type = type; + link.domainElement = domainElement; + domain.put(domainElement, link); + type.createDomain(g, new RangeToDomain(g), domainElement, link.rangeElement); + + // TODO Should we do this only if the mapping is listening? + domainModified(link); + } + + private void createRange(ReadGraph g, Link link) throws MappingException { + ILinkType type = schema.linkTypeOfDomainElement(g, link.domainElement); + Range rangeElement = type.createRangeElement(g, link.domainElement); + + link.type = type; + link.rangeElement = rangeElement; + range.put(rangeElement, link); + type.createRange(g, new DomainToRange(g), link.domainElement, rangeElement); + } + + Set domainSet = new AbstractSet() { + + public boolean add(Domain e) { + if(domain.containsKey(e)) + return false; + Link link = new Link(null, e, null); + domain.put(e, link); + modifiedDomainLinks.add(link); + return true; + } + + public boolean contains(Object o) { + return domain.contains(o); + } + + public boolean remove(Object o) { + Link link = domain.remove(o); + if(link == null) + return false; + removeLink(link); + if(link.rangeElement != null) + range.remove(link.rangeElement); + return true; + } + + @Override + public Iterator iterator() { + // FIXME does not implement Iterator.remove correctly + return domain.keySet().iterator(); + } + + @Override + public int size() { + return domain.size(); + } + + }; + + Set rangeSet = new AbstractSet() { + + public boolean add(Range e) { + if(range.containsKey(e)) + return false; + Link link = new Link(null, null, e); + range.put(e, link); + modifiedRangeLinks.add(link); + return true; + } + + public boolean contains(Object o) { + return range.contains(o); + } + + public boolean remove(Object o) { + Link link = range.remove(o); + if(link == null) + return false; + removeLink(link); + if(link.domainElement != null) + domain.remove(link.domainElement); + return true; + } + + @Override + public Iterator iterator() { + // FIXME does not implement Iterator.remove correctly + return range.keySet().iterator(); + } + + @Override + public int size() { + return range.size(); + } + + }; + + class DomainToRange implements IForwardMapping { + + ReadGraph g; + + public DomainToRange(ReadGraph g) { + this.g = g; + } + + @Override + public Range get(Domain element) { + Link link = domain.get(element); + if (link != null) + return link.rangeElement; + return null; + + } + + @Override + public Range map(ReadGraph graph, Domain element) + throws MappingException { + Link link = domain.get(element); + if(link == null) { + link = new Link(null, element, null); + link.domainModified = true; + modifiedDomainLinks.add(link); + domain.put(element, link); + createRange(g, link); + } + else if(link.type == null) + createRange(g, link); + return link.rangeElement; + } + + @Override + public Set getDomain() { + return domain.keySet(); + } + + }; + + class RangeToDomain extends DomainToRange implements IBackwardMapping { + + WriteGraph g; + + public RangeToDomain(WriteGraph g) { + super(g); + this.g = g; + } + @Override + public Domain inverseGet(Range element) { + + Link link = range.get(element); + if(link != null) + return link.domainElement; + return null; + } + + @Override + public Domain inverseMap(WriteGraph graph, Range element) + throws MappingException { + Link link = range.get(element); + if(link == null) { + link = new Link(null, null, element); + link.rangeModified = true; + modifiedRangeLinks.add(link); + range.put(element, link); + createDomain(g, link); + } + else if(link.type == null) + createDomain(g, link); + return link.domainElement; + } + + + @Override + public Set getRange() { + return range.keySet(); + } + }; + + @Override + public Set getDomain() { + return domainSet; + } + + @Override + public Set getRange() { + return rangeSet; + } + + + @Override + public synchronized Collection updateDomain(WriteGraph g) throws MappingException { + LOGGER.info("Mapping.updateDomain"); + RangeToDomain map = new RangeToDomain(g); + ArrayList updated = new ArrayList(); + while(!modifiedRangeLinks.isEmpty()) { + LOGGER.info(" modifiedRangeLinks.size() = " + modifiedRangeLinks.size()); + + Link link = modifiedRangeLinks.remove(modifiedRangeLinks.size()-1); + link.rangeModified = false; + /*if(link.domainModified) { + link.domainModified = false; + modifiedDomainLinks.remove(link); + }*/ + + if(link.type == null) { + createDomain(g, link); + } + + if(link.type.updateDomain(g, map, link.domainElement, link.rangeElement)) + updated.add(link.domainElement); + } + if (listensDomain) + updateRange(g); //FIXME: without this listening would stop. + return updated; + } + + @Override + public synchronized Collection updateRange(ReadGraph g) throws MappingException { + LOGGER.info("Mapping.updateRange"); + DomainToRange map = new DomainToRange(g); + ArrayList updated = new ArrayList(); + while(!modifiedDomainLinks.isEmpty()) { + LOGGER.info(" modifiedDomainLinks.size() = " + modifiedDomainLinks.size()); + + Link link = modifiedDomainLinks.remove(modifiedDomainLinks.size()-1); + link.domainModified = false; + /*if(link.rangeModified) { + link.rangeModified = false; + modifiedRangeLinks.remove(link); + }*/ + + if(link.type == null) { + createRange(g, link); + } + + if(listensDomain) { + RangeUpdateRequest request = new RangeUpdateRequest(link, map, this); + try { + g.syncRequest(request, request); + } catch (DatabaseException e) { + throw new MappingException(e); + } + // TODO check if really modified + updated.add(link.rangeElement); + } + else + if(link.type.updateRange(g, map, link.domainElement, link.rangeElement)) + updated.add(link.rangeElement); + } + return updated; + } + + @Override + public Range get(Domain domainElement) { + Link link = domain.get(domainElement); + if(link == null) + return null; + return link.rangeElement; + } + + @Override + public Domain inverseGet(Range rangeElement) { + Link link = range.get(rangeElement); + if(link == null) + return null; + return link.domainElement; + } + + @Override + public Domain inverseMap(WriteGraph g, Range rangeElement) throws MappingException { + getRange().add(rangeElement); + updateDomain(g); + return inverseGet(rangeElement); + } + + @Override + public Range map(ReadGraph g, Domain domainElement) throws MappingException { + getDomain().add(domainElement); + updateRange(g); + return get(domainElement); + } + + void domainModified(Link link) { + if(!link.domainModified) { + synchronized(modifiedDomainLinks) { + LOGGER.info(" domainModified for " + link.rangeElement); + link.domainModified = true; + modifiedDomainLinks.add(link); + if(modifiedDomainLinks.size() == 1) { + for(IMappingListener listener : listeners) + listener.domainModified(); + } + } + } + } + + @Override + public void domainModified(Domain domainElement) { + Link link = domain.get(domainElement); + if(link != null) + domainModified(link); + } + + void rangeModified(Link link) { + if(!link.rangeModified) { + synchronized(modifiedRangeLinks) { + link.rangeModified = true; + modifiedRangeLinks.add(link); + if(modifiedRangeLinks.size() == 1) { + for(IMappingListener listener : listeners) + listener.rangeModified(); + } + } + } + } + + @Override + public void rangeModified(Range rangeElement) { + Link link = range.get(rangeElement); + if(link != null) + rangeModified(link); + } + + @Override + public boolean isDomainModified() { + return !modifiedDomainLinks.isEmpty(); + } + + @Override + public boolean isRangeModified() { + return !modifiedRangeLinks.isEmpty(); + } + + @Override + public Collection getDomainModified() { + List list = new ArrayList(modifiedDomainLinks.size()); + for (Link link : modifiedDomainLinks) + list.add(link.domainElement); + return list; + + } + + @Override + public Collection getRangeModified() { + List list = new ArrayList(modifiedRangeLinks.size()); + for (Link link : modifiedRangeLinks) + list.add(link.rangeElement); + return list; + } + + @Override + public void addMappingListener(IMappingListener listener) { + listeners.add(listener); + } + + @Override + public void removeMappingListener(IMappingListener listener) { + listeners.remove(listener); + } + + @Override + public Collection getConflictingDomainElements() { + ArrayList result = new ArrayList(); + if(modifiedDomainLinks.size() < modifiedRangeLinks.size()) { + for(Link link : modifiedDomainLinks) + if(link.rangeModified) + result.add(link.domainElement); + } + else { + for(Link link : modifiedRangeLinks) + if(link.domainModified) + result.add(link.domainElement); + } + return result; + } + + @Override + public Collection getConflictingRangeElements() { + ArrayList result = new ArrayList(); + if(modifiedDomainLinks.size() < modifiedRangeLinks.size()) { + for(Link link : modifiedDomainLinks) + if(link.rangeModified) + result.add(link.rangeElement); + } + else { + for(Link link : modifiedRangeLinks) + if(link.domainModified) + result.add(link.rangeElement); + } + return result; + } + + @Override + public void dispose() { + disposed = true; + } + + public boolean isDisposed() { + return disposed; + } + +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/impl/RangeUpdateRequest.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/impl/RangeUpdateRequest.java new file mode 100644 index 00000000..599f249b --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/impl/RangeUpdateRequest.java @@ -0,0 +1,77 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.graph.impl; + +import org.simantics.db.ReadGraph; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.procedure.SyncListener; +import org.simantics.db.request.Read; + +import org.simantics.objmap.exceptions.MappingException; +import org.simantics.objmap.forward.IForwardMapping; +import org.simantics.objmap.graph.impl.Link; + + +public class RangeUpdateRequest implements Read, SyncListener { + + Link link; + /* + * Note that this map uses a read request that it has got from caller and + * not the one that is used in updateRange. This is intentional. + */ + IForwardMapping map; // map==null is used to flag that request is performed once + Mapping mapping; // mapping==null is used as a flag the request disposed + + public RangeUpdateRequest(Link link, IForwardMapping map, Mapping mapping) { + this.link = link; + this.map = map; + this.mapping = mapping; + } + + @Override + public Boolean perform(ReadGraph g) throws DatabaseException { + if(map != null) { + link.type.updateRange(g, map, link.domainElement, link.rangeElement); + map = null; + return Boolean.TRUE; + } + else if(mapping != null) { + mapping.domainModified(link); + mapping = null; + return Boolean.FALSE; + } + else + return null; + } + + @Override + public void exception(ReadGraph graph, Throwable throwable) + throws DatabaseException { + if(throwable instanceof DatabaseException) + throw (DatabaseException)throwable; + else + throw new MappingException(throwable); + } + + @Override + public void execute(ReadGraph graph, Boolean result) + throws DatabaseException { + } + + @Override + public boolean isDisposed() { + return mapping == null || link.removed || mapping.isDisposed(); + } + + + +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/MappedElementRule.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/MappedElementRule.java new file mode 100644 index 00000000..85d8b6e9 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/MappedElementRule.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.graph.rules; + +import org.apache.log4j.Logger; +import org.simantics.db.ReadGraph; +import org.simantics.db.WriteGraph; +import org.simantics.objmap.backward.IBackwardMapping; +import org.simantics.objmap.bidirectional.IBidirectionalMappingRule; +import org.simantics.objmap.exceptions.MappingException; +import org.simantics.objmap.forward.IForwardMapping; +import org.simantics.objmap.graph.rules.domain.IDomainAccessor; +import org.simantics.objmap.graph.rules.range.IRangeAccessor; + + + + +/** + * A rule that synchronizes collection of elements between + * domain and range accessors. Elements are mapped from + * between domain and range during the synchronization. + * @author Hannu Niemistö + */ +public class MappedElementRule implements IBidirectionalMappingRule { + + static Logger LOGGER = Logger.getLogger("org.simantics.objmap"); + + IDomainAccessor domainAccessor; + IRangeAccessor rangeAccessor; + + public MappedElementRule(IDomainAccessor domainAccessor, + IRangeAccessor rangeAccessor) { + this.domainAccessor = domainAccessor; + this.rangeAccessor = rangeAccessor; + } + + @Override + public boolean updateDomain(WriteGraph g, IBackwardMapping map, + Domain domainElement, Range rangeElement) + throws MappingException { + LOGGER.info(" MappedElementRule.updateDomain"); + Range value = rangeAccessor.get(rangeElement); + Domain mappedValue = value == null ? null : map.inverseMap(g, value);//map.inverseGet(value); + return domainAccessor.set(g, domainElement, mappedValue); + } + + @Override + public boolean updateRange(ReadGraph g, IForwardMapping map, + Domain domainElement, Range rangeElement) + throws MappingException { + LOGGER.info(" MappedElementRule.updateRange"); + Domain value = domainAccessor.get(g, domainElement); + Range mappedValue = value == null ? null : map.map(g, value);////map.get(value); + return rangeAccessor.set(rangeElement, mappedValue); + } + + public void createDomain(WriteGraph g, IBackwardMapping map, Domain domainElement, Range rangeElement) throws MappingException { + updateDomain(g, map, domainElement, rangeElement); + }; + + public void createRange(ReadGraph g, IForwardMapping map, Domain domainElement, Range rangeElement) throws MappingException { + updateRange(g, map, domainElement, rangeElement); + }; +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/MappedElementsRule.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/MappedElementsRule.java new file mode 100644 index 00000000..6f24fb19 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/MappedElementsRule.java @@ -0,0 +1,82 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.graph.rules; + +import java.util.ArrayList; +import java.util.Collection; + +import org.apache.log4j.Logger; +import org.simantics.db.ReadGraph; +import org.simantics.db.WriteGraph; +import org.simantics.objmap.backward.IBackwardMapping; +import org.simantics.objmap.bidirectional.IBidirectionalMappingRule; +import org.simantics.objmap.exceptions.MappingException; +import org.simantics.objmap.forward.IForwardMapping; +import org.simantics.objmap.graph.rules.domain.IDomainAccessor; +import org.simantics.objmap.graph.rules.range.IRangeAccessor; + + +/** + * A rule that synchronizes collection of elements between + * domain and range accessors. Elements are mapped from + * between domain and range during the synchronization. + * @author Hannu Niemistö + */ +public class MappedElementsRule implements IBidirectionalMappingRule { + + static Logger LOGGER = Logger.getLogger("org.simantics.objmap"); + + IDomainAccessor> domainAccessor; + IRangeAccessor> rangeAccessor; + + public MappedElementsRule(IDomainAccessor> domainAccessor, + IRangeAccessor> rangeAccessor) { + this.domainAccessor = domainAccessor; + this.rangeAccessor = rangeAccessor; + } + + @Override + public boolean updateDomain(WriteGraph g, IBackwardMapping map, + Domain domainElement, Range rangeElement) + throws MappingException { + LOGGER.info(" MappedElementsRule.updateDomain"); + // Snapshot the accessed range value for concurrency safety. + // NOTE: still assumes that the accessed collection is concurrent or + // synchronized for toArray to be atomic. + Collection value = rangeAccessor.get(rangeElement); + Object[] rangeSnapshot = value.toArray(); + ArrayList mappedValue = new ArrayList(rangeSnapshot.length); + for (Object obj : rangeSnapshot) + mappedValue.add(map.inverseMap(g, (Range)obj));//map.inverseGet((Range)obj)); + return domainAccessor.set(g, domainElement, mappedValue); + } + + @Override + public boolean updateRange(ReadGraph g, IForwardMapping map, + Domain domainElement, Range rangeElement) + throws MappingException { + LOGGER.info(" MappedElementsRule.updateRange"); + Collection value = domainAccessor.get(g, domainElement); + ArrayList mappedValue = new ArrayList(value.size()); + for(Domain r : value) + mappedValue.add(map.map(g, r));//map.get(r)); + return rangeAccessor.set(rangeElement, mappedValue); + } + + public void createDomain(WriteGraph g, IBackwardMapping map, Domain domainElement, Range rangeElement) throws MappingException { + updateDomain(g, map, domainElement, rangeElement); + }; + + public void createRange(ReadGraph g, IForwardMapping map, Domain domainElement, Range rangeElement) throws MappingException { + updateRange(g, map, domainElement, rangeElement); + }; +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/ValueRule.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/ValueRule.java new file mode 100644 index 00000000..468a0c25 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/ValueRule.java @@ -0,0 +1,69 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.graph.rules; + +import org.apache.log4j.Logger; +import org.simantics.db.ReadGraph; +import org.simantics.db.WriteGraph; +import org.simantics.objmap.backward.IBackwardMapping; +import org.simantics.objmap.bidirectional.IBidirectionalMappingRule; +import org.simantics.objmap.exceptions.MappingException; +import org.simantics.objmap.forward.IForwardMapping; +import org.simantics.objmap.graph.rules.domain.IDomainAccessor; +import org.simantics.objmap.graph.rules.range.IRangeAccessor; + + +/** + * A rule that synchronizes values between domain and + * range accessors. + * @author Hannu Niemistö + */ +public class ValueRule implements IBidirectionalMappingRule { + + static Logger LOGGER = Logger.getLogger("org.simantics.objmap"); + + IDomainAccessor domainAccessor; + IRangeAccessor rangeAccessor; + + public ValueRule(IDomainAccessor domainAccessor, + IRangeAccessor rangeAccessor) { + this.domainAccessor = domainAccessor; + this.rangeAccessor = rangeAccessor; + } + + @Override + public boolean updateDomain(WriteGraph g, IBackwardMapping map, + Domain domainElement, Range rangeElement) + throws MappingException { + LOGGER.info(" ValueRule.updateDomain"); + Object value = rangeAccessor.get(rangeElement); + return domainAccessor.set(g, domainElement, value); + } + + @Override + public boolean updateRange(ReadGraph g, IForwardMapping map, + Domain domainElement, Range rangeElement) + throws MappingException { + LOGGER.info(" ValueRule.updateRange"); + Object value = domainAccessor.get(g, domainElement); + return rangeAccessor.set(rangeElement, value); + } + + public void createDomain(WriteGraph g, IBackwardMapping map, Domain domainElement, Range rangeElement) throws MappingException { + updateDomain(g, map, domainElement, rangeElement); + }; + public void createRange(ReadGraph g, IForwardMapping map, Domain domainElement, Range rangeElement) throws MappingException { + updateRange(g, map, domainElement, rangeElement); + }; +} + + diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/adapters/IdentityAdapter.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/adapters/IdentityAdapter.java new file mode 100644 index 00000000..7c498ec4 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/adapters/IdentityAdapter.java @@ -0,0 +1,23 @@ +package org.simantics.objmap.graph.rules.adapters; + +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; + +public enum IdentityAdapter implements ValueAdapter { + INSTANCE; + + @Override + public Object domainToRange(Object domainValue) { + return domainValue; + } + + @Override + public Object rangeToDomain(Object rangeValue) { + return rangeValue; + } + + @Override + public Resource rangeTypeToDomainType(ReadGraph graph, Class rangeType) { + return null; + } +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/adapters/ValueAdapter.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/adapters/ValueAdapter.java new file mode 100644 index 00000000..19100595 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/adapters/ValueAdapter.java @@ -0,0 +1,10 @@ +package org.simantics.objmap.graph.rules.adapters; + +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; + +public interface ValueAdapter { + Resource rangeTypeToDomainType(ReadGraph graph, Class rangeType); + Object domainToRange(Object domainValue); + Object rangeToDomain(Object rangeValue); +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/domain/CompoundValueAccessor.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/domain/CompoundValueAccessor.java new file mode 100644 index 00000000..abf15ecf --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/domain/CompoundValueAccessor.java @@ -0,0 +1,151 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.graph.rules.domain; + +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import org.apache.log4j.Logger; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.Statement; +import org.simantics.db.WriteGraph; +import org.simantics.db.exception.DatabaseException; +import org.simantics.layer0.Layer0; +import org.simantics.objmap.exceptions.MappingException; +import org.simantics.objmap.graph.annotations.factories.CompoundRelatedGetSetValueRuleFactory; + +/** + * + * @author Marko Luukkainen + */ +public class CompoundValueAccessor implements IDomainAccessor { + + static Logger LOGGER = Logger.getLogger("org.simantics.objmap"); + + Resource objRelation; + Resource objType; + Resource valRelation; + + public CompoundValueAccessor(Resource objRelation, Resource objType, Resource valRelation) { + this.objRelation = objRelation; + this.objType = objType; + this.valRelation = valRelation; + } + + @Override + public Object get(ReadGraph g, Resource element) throws MappingException { + try { + Layer0 l0 = Layer0.getInstance(g); + LOGGER.info(" CompoundValueAccessor.get"); + Collection coll = g.getStatements(element, objRelation); + Map map = new HashMap(); + for (Statement c : coll) { + String name = g.getRelatedValue(c.getObject(), l0.HasName); + if (!map.containsKey(name) || !c.isAsserted(element)) + map.put(name, g.getRelatedValue(c.getObject(), valRelation)); + } + return map; + } catch (DatabaseException e) { + throw new MappingException(e); + } + } + + @Override + public boolean set(WriteGraph g, Resource element, Object v) + throws MappingException { + try { + Layer0 l0 = Layer0.getInstance(g); + LOGGER.info(" CompoundValueAccessor.set"); + Map values = (Map)v; + + Collection coll = g.getStatements(element, objRelation); + Map stmMap = new HashMap(); + Map valueMap = new HashMap(); + for (Statement c : coll) { + String name = g.getRelatedValue(c.getObject(), l0.HasName); + if (!stmMap.containsKey(name) || !c.isAsserted(element)) { + stmMap.put(name, c); + valueMap.put(name, g.getRelatedValue(c.getObject(), valRelation)); + } + } + boolean changed = false; + for (String key : values.keySet()) { + Object value = values.get(key); + if (value.equals(valueMap.get(key))) + continue; + changed = true; + Statement stm = stmMap.get(key); + if (stm == null || stm.isAsserted(element)) { + Resource obj = g.newResource(); + g.claim(obj, l0.InstanceOf, objType); + g.claimLiteral(obj, l0.HasName, key); + g.claim(element, objRelation, obj); + stm = getStatement(g, element, objRelation, obj); + } + + Statement valueStatement = g.getPossibleStatement(stm.getObject(), valRelation); + Resource valueType = CompoundRelatedGetSetValueRuleFactory.dataTypeOfClass(g, value.getClass()); + if(valueStatement == null) { + + Resource valueResource = g.newResource(); + g.claim(valueResource, Layer0.getInstance(g).InstanceOf, null, valueType); + g.claim(stm.getObject(), valRelation, valueResource); + g.claimValue(valueResource, value); + } else { + + + if (!valueStatement.isAsserted(stm.getObject())) + g.claimValue(valueStatement.getObject(), value); + else { + Resource valueResource = g.newResource(); + g.claim(valueResource, Layer0.getInstance(g).InstanceOf, null, + valueType); + g.claim(stm.getObject(), valRelation, valueResource); + g.claimValue(valueResource, value); + } + } + } + return changed; + + } catch (DatabaseException e) { + throw new MappingException(e); + } + + } + + private Statement getStatement(ReadGraph g, Resource s, Resource p, Resource o) throws DatabaseException{ + for (Statement stm : g.getStatements(s, p)) { + if (stm.getObject().equals(o)) + return stm; + } + return null; + } + + private boolean equals(Object o1, Object o2) { + if (o1 instanceof boolean[]) + Arrays.equals((boolean[])o1,(boolean[])o2); + if (o1 instanceof int[]) + Arrays.equals((int[])o1,(int[])o2); + if (o1 instanceof float[]) + Arrays.equals((float[])o1,(float[])o2); + if (o1 instanceof double[]) + Arrays.equals((double[])o1,(double[])o2); + if (o1 instanceof byte[]) + Arrays.equals((byte[])o1,(byte[])o2); + return o1.equals(o2); + + } + +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/domain/IDomainAccessor.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/domain/IDomainAccessor.java new file mode 100644 index 00000000..cd9b6975 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/domain/IDomainAccessor.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.graph.rules.domain; + +import org.simantics.db.ReadGraph; +import org.simantics.db.WriteGraph; +import org.simantics.objmap.exceptions.MappingException; + + +/** + * Provides access to some property of domain elements. + * @author Hannu Niemistö + */ +public interface IDomainAccessor { + T get(ReadGraph g, Domain element) throws MappingException; + boolean set(WriteGraph g, Domain element, T value) throws MappingException; +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/domain/MappingUtils.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/domain/MappingUtils.java new file mode 100644 index 00000000..1b6724bc --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/domain/MappingUtils.java @@ -0,0 +1,92 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.graph.rules.domain; + +import java.util.Arrays; +import java.util.Collection; + +import org.apache.log4j.Logger; +import org.simantics.db.Resource; +import org.simantics.db.WriteGraph; +import org.simantics.db.exception.DatabaseException; + +/** + * Static utility methods for rule implementations. + * @author Hannu Niemistö + */ +public class MappingUtils { + + static Logger LOGGER = Logger.getLogger("org.simantics.objmap"); + + /** + * Adds and removes statements to/from the database so that objects + * will be exactly the objects connected to subject by predicate. + * Returns true if the method made modifications to the database. + */ + public static boolean synchronizeStatements(WriteGraph g, Resource subject, Resource predicate, Resource[] objects, + boolean deleteExtraObjects) + throws DatabaseException { + Collection currentObjects0 = g.getObjects(subject, predicate); + Resource[] currentObjects = currentObjects0.toArray(new Resource[currentObjects0.size()]); + + Arrays.sort(objects); + Arrays.sort(currentObjects); + + boolean modified = false; + int i=0, j=0; + if(currentObjects.length > 0 && objects.length > 0) + while(true) { + int cmp = currentObjects[i].compareTo(objects[j]); + if(cmp < 0) { + LOGGER.info(" remove statement"); + if(deleteExtraObjects) + g.deny(currentObjects[i]); + else + g.denyStatement(subject, predicate, currentObjects[i]); + modified = true; + ++i; + if(i >= currentObjects.length) + break; + } + else if(cmp > 0) { + LOGGER.info(" add statement"); + g.claim(subject, predicate, objects[j]); + modified = true; + ++j; + if(j >= objects.length) + break; + } + else { + ++i; ++j; + if(i >= currentObjects.length) + break; + if(j >= objects.length) + break; + } + } + while(i < currentObjects.length) { + if(deleteExtraObjects) + g.deny(currentObjects[i]); + else + g.denyStatement(subject, predicate, currentObjects[i]); + modified = true; + ++i; + } + while(j < objects.length) { + g.claim(subject, predicate, objects[j]); + modified = true; + ++j; + } + return modified; + } + +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/domain/RelatedObjectAccessor.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/domain/RelatedObjectAccessor.java new file mode 100644 index 00000000..f1f4ce64 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/domain/RelatedObjectAccessor.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.graph.rules.domain; + +import org.apache.log4j.Logger; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.WriteGraph; +import org.simantics.db.exception.DatabaseException; +import org.simantics.objmap.exceptions.MappingException; + +/** + * Accesses a resource attached to the element by given functional relation. + * @author Hannu Niemistö + */ +public class RelatedObjectAccessor implements IDomainAccessor { + + static Logger LOGGER = Logger.getLogger("org.simantics.objmap"); + + Resource relation; + + public RelatedObjectAccessor(Resource relation) { + this.relation = relation; + } + + @Override + public Resource get(ReadGraph g, Resource element) throws MappingException { + try { + LOGGER.info(" RelatedObjectAccessor.get"); + return g.getPossibleObject(element, relation); + } catch (DatabaseException e) { + throw new MappingException(e); + } + } + + @Override + public boolean set(WriteGraph g, Resource element, Resource value) + throws MappingException { + try { + LOGGER.info(" RelatedObjectAccessor.set"); + Resource resource = g.getPossibleObject(element, relation); + if(resource == null) { + if(value == null) + return false; + g.claim(element, relation, value); + return true; + } + else if(resource.equals(value)) + return false; + else { + g.deny(element, relation); + if(value != null) + g.claim(element, relation, value); + return true; + } + } catch (DatabaseException e) { + throw new MappingException(e); + } + + } + +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/domain/RelatedObjectsAccessor.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/domain/RelatedObjectsAccessor.java new file mode 100644 index 00000000..a5441169 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/domain/RelatedObjectsAccessor.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.graph.rules.domain; + +import java.util.Collection; + +import org.apache.log4j.Logger; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.WriteGraph; +import org.simantics.db.exception.DatabaseException; +import org.simantics.objmap.exceptions.MappingException; + +/** + * Accesses the set of objects attached to the element by the given relation. + * @author Hannu Niemistö + */ +public class RelatedObjectsAccessor implements IDomainAccessor> { + + static Logger LOGGER = Logger.getLogger("org.simantics.objmap"); + + Resource relation; + boolean deleteExtraObjects; + + public RelatedObjectsAccessor(Resource relation, boolean deleteExtraObjects) { + super(); + this.relation = relation; + this.deleteExtraObjects = deleteExtraObjects; + } + + @Override + public Collection get(ReadGraph g, Resource element) throws MappingException { + try { + LOGGER.info(" RelatedObjectsAccessor.get"); + return g.getObjects(element, relation); + } catch (DatabaseException e) { + throw new MappingException(e); + } + } + + @Override + public boolean set(WriteGraph g, Resource element, Collection value) + throws MappingException { + try { + LOGGER.info(" RelatedObjectsAccessor.set"); + return MappingUtils.synchronizeStatements(g, element, relation, + value.toArray(new Resource[value.size()]), deleteExtraObjects); + } catch (DatabaseException e) { + throw new MappingException(e); + } + + } + +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/domain/RelatedOrderedSetElementsAccessor.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/domain/RelatedOrderedSetElementsAccessor.java new file mode 100644 index 00000000..74583795 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/domain/RelatedOrderedSetElementsAccessor.java @@ -0,0 +1,62 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.graph.rules.domain; + +import java.util.Collection; + +import org.apache.log4j.Logger; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.WriteGraph; +import org.simantics.db.common.utils.OrderedSetUtils; +import org.simantics.db.exception.DatabaseException; +import org.simantics.objmap.exceptions.MappingException; + +/** + * Accesses the set of objects attached to the element by the given relation. + * @author Hannu Niemistö + */ +public class RelatedOrderedSetElementsAccessor implements IDomainAccessor> { + + static Logger LOGGER = Logger.getLogger("org.simantics.objmap"); + + boolean deleteExtraObjects; + + public RelatedOrderedSetElementsAccessor(boolean deleteExtraObjects) { + super(); + this.deleteExtraObjects = deleteExtraObjects; + } + + @Override + public Collection get(ReadGraph g, Resource element) throws MappingException { + try { + LOGGER.info(" RelatedOrderedSetElementsAccessor.get"); + return OrderedSetUtils.toList(g, element); + } catch (DatabaseException e) { + throw new MappingException(e); + } + } + + @Override + public boolean set(WriteGraph g, Resource element, Collection value) + throws MappingException { + try { + LOGGER.info(" RelatedOrderedSetElementsAccessor.set"); + return OrderedSetUtils.set(g, element, value); + // FIXME Implement deleteExtraObjects + } catch (DatabaseException e) { + throw new MappingException(e); + } + + } + +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/domain/RelatedValueAccessor.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/domain/RelatedValueAccessor.java new file mode 100644 index 00000000..e4531c43 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/domain/RelatedValueAccessor.java @@ -0,0 +1,114 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.graph.rules.domain; + +import java.util.Arrays; + +import org.apache.log4j.Logger; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.Statement; +import org.simantics.db.WriteGraph; +import org.simantics.db.exception.DatabaseException; +import org.simantics.layer0.Layer0; +import org.simantics.objmap.exceptions.MappingException; + +/** + * Accesses a value attached to the element by given functional relation. + * @author Hannu Niemist� + */ +public class RelatedValueAccessor implements IDomainAccessor { + + static Logger LOGGER = Logger.getLogger("org.simantics.objmap"); + + Resource relation; + Resource valueType; + + public RelatedValueAccessor(Resource relation, Resource valueType) { + this.relation = relation; + this.valueType = valueType; + } + + @Override + public Object get(ReadGraph g, Resource element) throws MappingException { + try { + LOGGER.info(" RelatedValueAccessor.get"); + Resource valueResource = g.getPossibleObject(element, relation); + if(valueResource == null) + return null; + return g.getValue(valueResource); + } catch (DatabaseException e) { + throw new MappingException(e); + } + } + + @Override + public boolean set(WriteGraph g, Resource element, Object value) + throws MappingException { + try { + LOGGER.info(" RelatedValueAccessor.set"); + Statement valueStatement = g.getPossibleStatement(element, relation); + if(valueStatement == null) { + if(value == null) + return false; + Resource valueResource = g.newResource(); + g.claim(valueResource, Layer0.getInstance(g).InstanceOf, null, + valueType); + g.claim(element, relation, valueResource); + g.claimValue(valueResource, value); + return true; + } + else { + if(value == null) { + if (!valueStatement.isAsserted(element)) { + g.deny(valueStatement.getObject()); + return true; + } else { + return false; + } + } + Object currentValue = g.getValue(valueStatement.getObject()); + if(equals(currentValue,value)) + return false; + if (!valueStatement.isAsserted(element)) + g.claimValue(valueStatement.getObject(), value); + else { + Resource valueResource = g.newResource(); + g.claim(valueResource, Layer0.getInstance(g).InstanceOf, null, + valueType); + g.claim(element, relation, valueResource); + g.claimValue(valueResource, value); + } + return true; + } + } catch (DatabaseException e) { + throw new MappingException(e); + } + + } + + private boolean equals(Object o1, Object o2) { + if (o1 instanceof boolean[]) + Arrays.equals((boolean[])o1,(boolean[])o2); + if (o1 instanceof int[]) + Arrays.equals((int[])o1,(int[])o2); + if (o1 instanceof float[]) + Arrays.equals((float[])o1,(float[])o2); + if (o1 instanceof double[]) + Arrays.equals((double[])o1,(double[])o2); + if (o1 instanceof byte[]) + Arrays.equals((byte[])o1,(byte[])o2); + return o1.equals(o2); + + } + +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/factory/IClassRuleFactory.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/factory/IClassRuleFactory.java new file mode 100644 index 00000000..bb307ce8 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/factory/IClassRuleFactory.java @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.graph.rules.factory; + +import java.lang.annotation.Annotation; + +import org.simantics.db.ReadGraph; +import org.simantics.db.exception.DatabaseException; +import org.simantics.objmap.bidirectional.IBidirectionalMappingRule; + +public interface IClassRuleFactory { + IBidirectionalMappingRule create(ReadGraph g, Annotation annotation, Class clazz) throws DatabaseException; +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/factory/ICollectionRuleFactory.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/factory/ICollectionRuleFactory.java new file mode 100644 index 00000000..835639a2 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/factory/ICollectionRuleFactory.java @@ -0,0 +1,14 @@ +package org.simantics.objmap.graph.rules.factory; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; + +import org.simantics.db.ReadGraph; +import org.simantics.db.exception.DatabaseException; +import org.simantics.objmap.bidirectional.IBidirectionalMappingRule; + +public interface ICollectionRuleFactory { + IBidirectionalMappingRule create(ReadGraph g, Annotation annotation, Method getter, Method adder, Method remover) throws DatabaseException; + boolean isAdder(Annotation getterAnnotation, Annotation annotation); + boolean isRemover(Annotation getterAnnotation, Annotation annotation); +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/factory/IFieldRuleFactory.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/factory/IFieldRuleFactory.java new file mode 100644 index 00000000..6da04548 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/factory/IFieldRuleFactory.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.graph.rules.factory; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; + +import org.simantics.db.ReadGraph; +import org.simantics.db.exception.DatabaseException; +import org.simantics.objmap.bidirectional.IBidirectionalMappingRule; + +public interface IFieldRuleFactory { + IBidirectionalMappingRule create(ReadGraph g, Annotation annotation, Field field) throws DatabaseException; +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/factory/IGetSetRuleFactory.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/factory/IGetSetRuleFactory.java new file mode 100644 index 00000000..e3397d62 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/factory/IGetSetRuleFactory.java @@ -0,0 +1,13 @@ +package org.simantics.objmap.graph.rules.factory; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; + +import org.simantics.db.ReadGraph; +import org.simantics.db.exception.DatabaseException; +import org.simantics.objmap.bidirectional.IBidirectionalMappingRule; + +public interface IGetSetRuleFactory { + IBidirectionalMappingRule create(ReadGraph g, Annotation annotation, Method getter, Method setter) throws DatabaseException; + boolean isSetter(Annotation getterAnnotation, Annotation annotation); +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/factory/IMethodRuleFactory.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/factory/IMethodRuleFactory.java new file mode 100644 index 00000000..96336ee7 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/factory/IMethodRuleFactory.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.graph.rules.factory; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; + +import org.simantics.db.ReadGraph; +import org.simantics.db.exception.DatabaseException; +import org.simantics.objmap.bidirectional.IBidirectionalMappingRule; + +public interface IMethodRuleFactory { + IBidirectionalMappingRule create(ReadGraph g, Annotation annotation, Method method) throws DatabaseException; +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/range/AdaptedRangeAccessor.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/range/AdaptedRangeAccessor.java new file mode 100644 index 00000000..a38cb9e1 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/range/AdaptedRangeAccessor.java @@ -0,0 +1,27 @@ +package org.simantics.objmap.graph.rules.range; + +import org.simantics.objmap.exceptions.MappingException; +import org.simantics.objmap.graph.rules.adapters.ValueAdapter; + + + +public class AdaptedRangeAccessor implements IRangeAccessor { + IRangeAccessor baseAccessor; + ValueAdapter adapter; + + public AdaptedRangeAccessor(IRangeAccessor baseAccessror, + ValueAdapter adapter) { + this.baseAccessor = baseAccessror; + this.adapter = adapter; + } + + @Override + public Object get(Range element) throws MappingException { + return adapter.rangeToDomain(baseAccessor.get(element)); + } + + @Override + public boolean set(Range element, Object value) throws MappingException { + return baseAccessor.set(element, adapter.domainToRange(value)); + } +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/range/CollectionAccessor.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/range/CollectionAccessor.java new file mode 100644 index 00000000..c4141f71 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/range/CollectionAccessor.java @@ -0,0 +1,80 @@ +package org.simantics.objmap.graph.rules.range; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collection; + +import org.simantics.objmap.exceptions.MappingException; + + +/** + * Accessor for mapped collections. + * Uses three methods: + * - Getter: returns the collection. + * - Adder: adds one item into the collection. + * - Remover: removes one item from the collection. + * + * @author Marko Luukkainen + * + * @param + */ +public class CollectionAccessor implements IRangeAccessor> { + + private Method getter; + private Method adder; + private Method remover; + + public CollectionAccessor(Method getter, Method adder, Method remover) { + this.getter = getter; + this.adder = adder; + this.remover = remover; + } + + @SuppressWarnings("unchecked") + public java.util.Collection get(Object element) throws MappingException { + try { + return (Collection) getter.invoke(element); + } catch (IllegalArgumentException e) { + throw new MappingException(e); + } catch (IllegalAccessException e) { + throw new MappingException(e); + } catch (InvocationTargetException e) { + throw new MappingException(e); + } + }; + + @Override + public boolean set(Range element, Collection value) + throws MappingException { + java.util.Collection current = get(element); + Collection adding = new ArrayList(); + Collection removing = new ArrayList(); + for (T e : current) { + if (!value.contains(e)) + removing.add(e); + } + for (T e : value) { + if (!current.contains(e)) + adding.add(e); + } + + try { + for (T e : removing) { + remover.invoke(element, e); + } + + for (T e : adding) { + adder.invoke(element, e); + } + } catch (IllegalArgumentException e) { + throw new MappingException(e); + } catch (IllegalAccessException e) { + throw new MappingException(e); + } catch (InvocationTargetException e) { + throw new MappingException(e); + } + return removing.size() > 0 || adding.size() > 0; + + } +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/range/CompoundGetSetValueAccessor.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/range/CompoundGetSetValueAccessor.java new file mode 100644 index 00000000..ce051536 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/range/CompoundGetSetValueAccessor.java @@ -0,0 +1,73 @@ +package org.simantics.objmap.graph.rules.range; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import org.simantics.objmap.exceptions.MappingException; + + +/** + * Accessor for mapped value. Uses two methods: + * - Getter: returns the current value. + * - Setter: sets the current value. The value may be null. (if setter parameter is primitive, null value is not mapped). + * + * @author Marko Luukkainen + * + * @param + */ +public class CompoundGetSetValueAccessor implements IRangeAccessor { + + private Method getter; + private Method setter; + private boolean primitive; + + public CompoundGetSetValueAccessor(Method getter, Method setter) { + this.getter = getter; + this.setter = setter; + this.primitive = setter.getParameterTypes()[0].isPrimitive(); + } + + @SuppressWarnings("unchecked") + public T get(Range element) throws MappingException { + try { + return (T) getter.invoke(element); + } catch (IllegalArgumentException e) { + throw new MappingException(e); + } catch (IllegalAccessException e) { + throw new MappingException(e); + } catch (InvocationTargetException e) { + throw new MappingException(e); + } + }; + + @Override + public boolean set(Range element, T value) + throws MappingException { + if (value == null && primitive) + return false; + if (equal(get(element),value)) + return false; + try { + setter.invoke(element, value); + } catch (IllegalArgumentException e) { + throw new MappingException(e); + } catch (IllegalAccessException e) { + throw new MappingException(e); + } catch (InvocationTargetException e) { + throw new MappingException(e); + } + return true; + + } + + private boolean equal(Object v1, Object v2) { + if (v1 == null) { + if (v2 == null) + return true; + return false; + } else if (v2 == null) { + return false; + } + return v1.equals(v2); + } +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/range/FieldAccessor.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/range/FieldAccessor.java new file mode 100644 index 00000000..91f9b80e --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/range/FieldAccessor.java @@ -0,0 +1,75 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.graph.rules.range; + +import java.lang.reflect.Field; + +import org.apache.log4j.Logger; +import org.simantics.objmap.exceptions.MappingException; + + +/** + * Accesses the given field of the element. + * @author Hannu Niemistö + */ +public class FieldAccessor implements IRangeAccessor { + + static Logger LOGGER = Logger.getLogger("org.simantics.objmap"); + + Field field; + + public FieldAccessor(Field field) { + this.field = field; + } + + @Override + public T get(Range element) throws MappingException { + try { + T result = (T)field.get(element); + + if(LOGGER.isInfoEnabled()) + LOGGER.info(" FieldAccessor.get " + + field.getName() + " -> " + result + ); + + return result; + } catch (IllegalArgumentException e) { + throw new MappingException(e); + } catch (IllegalAccessException e) { + throw new MappingException(e); + } + } + + @Override + public boolean set(Range element, T value) throws MappingException { + try { + Object currentValue = field.get(element); + + if(LOGGER.isInfoEnabled()) + LOGGER.info(" FieldAccessor.set " + + field.getName() + " " + currentValue + + " -> " + value + ); + + if(value == null + ? (currentValue == null || field.getType().isPrimitive()) + : value.equals(currentValue)) + return false; + field.set(element, value); + return true; + } catch (IllegalArgumentException e) { + throw new MappingException(e); + } catch (IllegalAccessException e) { + throw new MappingException(e); + } + } +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/range/FieldAccessorWithDefault.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/range/FieldAccessorWithDefault.java new file mode 100644 index 00000000..528826e4 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/range/FieldAccessorWithDefault.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.graph.rules.range; + +import java.lang.reflect.Field; + +import org.simantics.objmap.exceptions.MappingException; + + +/** + * Accesses the given field of the element. + * @author Hannu Niemist� + */ +public class FieldAccessorWithDefault extends FieldAccessor { + + T defaultValue; + + public FieldAccessorWithDefault(Field field, T defaultValue) { + super(field); + this.defaultValue = defaultValue; + } + + @Override + public T get(Range element) throws MappingException { + T value = super.get(element); + if(value == null) + return defaultValue; + else + return value; + } +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/range/GetSetObjectAccessor.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/range/GetSetObjectAccessor.java new file mode 100644 index 00000000..f5cd6092 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/range/GetSetObjectAccessor.java @@ -0,0 +1,58 @@ +package org.simantics.objmap.graph.rules.range; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import org.simantics.objmap.exceptions.MappingException; + + +/** + * Accessor for mapped objects. Uses two methods: + * - Getter: returns the current object. + * - Setter: sets the current object. The object may be null. + * + * @author Marko Luukkainen + * + * @param + */ +public class GetSetObjectAccessor implements IRangeAccessor { + + private Method getter; + private Method setter; + + + public GetSetObjectAccessor(Method getter, Method setter) { + this.getter = getter; + this.setter = setter; + + } + + @SuppressWarnings("unchecked") + public T get(Range element) throws MappingException { + try { + return (T) getter.invoke(element); + } catch (IllegalArgumentException e) { + throw new MappingException(e); + } catch (IllegalAccessException e) { + throw new MappingException(e); + } catch (InvocationTargetException e) { + throw new MappingException(e); + } + }; + + @Override + public boolean set(Range element, T value) + throws MappingException { + try { + setter.invoke(element, value); + } catch (IllegalArgumentException e) { + throw new MappingException(e); + } catch (IllegalAccessException e) { + throw new MappingException(e); + } catch (InvocationTargetException e) { + throw new MappingException(e); + } + return true; + + } +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/range/GetSetValueAccessor.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/range/GetSetValueAccessor.java new file mode 100644 index 00000000..94fc5d4e --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/range/GetSetValueAccessor.java @@ -0,0 +1,73 @@ +package org.simantics.objmap.graph.rules.range; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import org.simantics.objmap.exceptions.MappingException; + + +/** + * Accessor for mapped value. Uses two methods: + * - Getter: returns the current value. + * - Setter: sets the current value. The value may be null. (if setter parameter is primitive, null value is not mapped). + * + * @author Marko Luukkainen + * + * @param + */ +public class GetSetValueAccessor implements IRangeAccessor { + + private Method getter; + private Method setter; + private boolean primitive; + + public GetSetValueAccessor(Method getter, Method setter) { + this.getter = getter; + this.setter = setter; + this.primitive = setter.getParameterTypes()[0].isPrimitive(); + } + + @SuppressWarnings("unchecked") + public T get(Range element) throws MappingException { + try { + return (T) getter.invoke(element); + } catch (IllegalArgumentException e) { + throw new MappingException(e); + } catch (IllegalAccessException e) { + throw new MappingException(e); + } catch (InvocationTargetException e) { + throw new MappingException(e); + } + }; + + @Override + public boolean set(Range element, T value) + throws MappingException { + if (value == null && primitive) + return false; + if (equal(get(element),value)) + return false; + try { + setter.invoke(element, value); + } catch (IllegalArgumentException e) { + throw new MappingException(e); + } catch (IllegalAccessException e) { + throw new MappingException(e); + } catch (InvocationTargetException e) { + throw new MappingException(e); + } + return true; + + } + + private boolean equal(Object v1, Object v2) { + if (v1 == null) { + if (v2 == null) + return true; + return false; + } else if (v2 == null) { + return false; + } + return v1.equals(v2); + } +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/range/IRangeAccessor.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/range/IRangeAccessor.java new file mode 100644 index 00000000..871ec720 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/range/IRangeAccessor.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.graph.rules.range; + +import org.simantics.objmap.exceptions.MappingException; + + + +/** + * Provides access to some property of range elements. + * @author Hannu Niemistö + */ +public interface IRangeAccessor { + T get(Range element) throws MappingException; + boolean set(Range element, T value) throws MappingException; +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/schema/AdaptedLinkType.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/schema/AdaptedLinkType.java new file mode 100644 index 00000000..c75c5ed6 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/schema/AdaptedLinkType.java @@ -0,0 +1,75 @@ +package org.simantics.objmap.graph.schema; + +//import org.apache.log4j.Logger; +import org.eclipse.core.runtime.IAdaptable; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.WriteGraph; +import org.simantics.db.exception.DatabaseException; + +import org.simantics.objmap.backward.IBackwardMapping; +import org.simantics.objmap.exceptions.MappingException; +import org.simantics.objmap.forward.IForwardMapping; + +/** + * A link type that is associated with adaptable resource (ReadGraph.getAdapter(Resource,Class)). + * The adapted object must implement IAdaptable interface for returning the original Resource. + * + * @author Marko Luukkainen + * + */ +public class AdaptedLinkType implements ILinkType { + + + //static Logger LOGGER = Logger.getLogger("org.simantics.objmap"); + + Resource domainType; + Class rangeType; + + + public AdaptedLinkType(Resource domainType, Class rangeType) { + this.domainType = domainType; + this.rangeType = rangeType; + } + + @Override + public Resource createDomainElement(WriteGraph g, Range rangeElement) + throws MappingException { + try { + IAdaptable adaptable = (IAdaptable)rangeElement; + Resource res = (Resource)adaptable.getAdapter(Resource.class); + if (res == null) + throw new NullPointerException(); + return res; + } catch (Exception e) { + throw new MappingException("Adapted object must implement IAdaptable interface to return the source Resource.", e); + } + + } + + @Override + public Range createRangeElement(ReadGraph g, Resource domainElement) + throws MappingException { + try { + return (Range)g.adapt(domainElement, rangeType); + } catch (DatabaseException e) { + throw new MappingException(e); + } + } + + public void createDomain(WriteGraph graph, IBackwardMapping mapping, Resource domainElement, Range rangeElement) throws MappingException { + + }; + + public void createRange(ReadGraph graph, org.simantics.objmap.forward.IForwardMapping mapping, Resource domainElement, Range rangeElement) throws MappingException { + + }; + + public boolean updateDomain(WriteGraph g, IBackwardMapping map, Resource domainElement, Range rangeElement) throws MappingException { + return false; + } + + public boolean updateRange(ReadGraph g, IForwardMapping map, Resource domainElement, Range rangeElement) throws MappingException { + return false; + } +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/schema/DefaultSchema.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/schema/DefaultSchema.java new file mode 100644 index 00000000..14f4d66c --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/schema/DefaultSchema.java @@ -0,0 +1,96 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.graph.schema; + + + +import gnu.trove.map.hash.THashMap; + +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.common.utils.NameUtils; +import org.simantics.db.exception.DatabaseException; +import org.simantics.objmap.exceptions.MappingException; + + +/** + * + */ +public class DefaultSchema implements IMappingSchema { + + THashMap> domainLinkTypes = + new THashMap>(); + THashMap, ILinkType> rangeLinkTypes = + new THashMap, ILinkType>(); + + public void addLinkType(SimpleLinkType linkType) { + domainLinkTypes.put(linkType.domainType, linkType); + rangeLinkTypes.put(linkType.rangeType, linkType); + } + + public void addLinkType(AdaptedLinkType linkType) { + domainLinkTypes.put(linkType.domainType, linkType); + rangeLinkTypes.put(linkType.rangeType, linkType); + } + + @Override + public ILinkType linkTypeOfDomainElement(ReadGraph g, Resource element) throws MappingException { + try { + + for(Resource type : g.getTypes(element)) { + + ILinkType linkType = domainLinkTypes.get(type); + if(linkType != null) return linkType; + + } + + throw new MappingException("Didn't find a link type for " + + NameUtils.getSafeName(g, element) + "."); + + } catch (DatabaseException e) { + throw new MappingException(e); + } + } + + @Override + public ILinkType linkTypeOfRangeElement(Object element) throws MappingException { + ILinkType type = rangeLinkTypes.get(element.getClass()); + if(type == null) { + for (Class clazz : element.getClass().getInterfaces()) { + type = rangeLinkTypes.get(clazz); + if (type != null) + return type; + + } + throw new MappingException("Didn't find a link type for " + element + "."); + } + return type; + } + + + public ILinkType linkTypeOfDomainType(ReadGraph g, Resource type) { + return domainLinkTypes.get(type); + } + + public ILinkType linkTypeOfRangeType(Class clazz) { + ILinkType type = rangeLinkTypes.get(clazz); + if(type == null) { + for (Class c : clazz.getInterfaces()) { + type = rangeLinkTypes.get(clazz); + if (type != null) + return type; + + } + } + return null; + } +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/schema/DynamicSimpleLinkType.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/schema/DynamicSimpleLinkType.java new file mode 100644 index 00000000..e7da15a5 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/schema/DynamicSimpleLinkType.java @@ -0,0 +1,112 @@ +package org.simantics.objmap.graph.schema; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; + +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.WriteGraph; +import org.simantics.db.common.utils.NameUtils; +import org.simantics.db.exception.DatabaseException; +import org.simantics.layer0.Layer0; +import org.simantics.objmap.bidirectional.IBidirectionalMappingRule; +import org.simantics.objmap.exceptions.MappingException; +import org.simantics.objmap.graph.annotations.GetType; +import org.simantics.objmap.graph.annotations.SetType; + +public class DynamicSimpleLinkType extends SimpleLinkType{ + + protected Method typeGetter; + protected Method typeSetter; + + public DynamicSimpleLinkType(Resource domainType, Class rangeType, ArrayList> rules) { + super(domainType, rangeType, rules); + findTypeGetter(rangeType); + } + + public DynamicSimpleLinkType(Resource domainType, Class rangeType) { + super(domainType, rangeType); + findTypeGetter(rangeType); + } + + private void findTypeGetter(Class clazz) { + for (Method m : clazz.getDeclaredMethods()) { + m.setAccessible(true); + GetType t = m.getAnnotation(GetType.class); + if (t != null) { + typeGetter = m; + } + SetType t2 = m.getAnnotation(SetType.class); + if (t2 != null) { + typeSetter = m; + } + } + if (typeGetter == null || typeSetter == null) { + Class superClazz = clazz.getSuperclass(); + if (superClazz != Object.class) + findTypeGetter(superClazz); + if (typeGetter == null || typeSetter == null) { + throw new RuntimeException("Cannot find dynamic type methods for class " + clazz.getSimpleName()); + } + } + + + } + + @Override + public Resource createDomainElement(WriteGraph g, Range rangeElement) + throws MappingException { + try { + String typeUri = (String)typeGetter.invoke(rangeElement, null); + if(LOGGER.isInfoEnabled()) + LOGGER.info("SimpleLinkType.createDomainElement " + + rangeElement.toString() + ); + Resource actualDomainType = g.getResource(typeUri); + Resource result = g.newResource(); + //g.claim(result, Layer0.getInstance(g).InstanceOf, null, domainType); + g.claim(result, Layer0.getInstance(g).InstanceOf, null, actualDomainType); + return result; + } catch(DatabaseException e) { + throw new MappingException(e); + } catch (IllegalArgumentException e) { + throw new MappingException(e); + } catch (IllegalAccessException e) { + throw new MappingException(e); + } catch (InvocationTargetException e) { + throw new MappingException(e); + } + } + + @Override + public Range createRangeElement(ReadGraph g, Resource domainElement) + throws MappingException { + try { + if(LOGGER.isInfoEnabled()) + try { + LOGGER.info("SimpleLinkType.createRangeElement " + + NameUtils.getSafeName(g, domainElement) + ); + } catch(DatabaseException e) { + throw new MappingException(e); + } + Range r = (Range)rangeType.newInstance(); + Resource type = g.getSingleType(domainElement, domainType); + String uri = g.getURI(type); + typeSetter.invoke(r, uri); + return r; + } catch (InstantiationException e) { + throw new MappingException(e); + } catch (IllegalAccessException e) { + throw new MappingException(e); + } catch (DatabaseException e) { + throw new MappingException(e); + } catch (IllegalArgumentException e) { + throw new MappingException(e); + } catch (InvocationTargetException e) { + throw new MappingException(e); + } + } + +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/schema/ILinkType.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/schema/ILinkType.java new file mode 100644 index 00000000..aec69739 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/schema/ILinkType.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.graph.schema; + +import org.simantics.objmap.backward.IBackwardLinkType; +import org.simantics.objmap.bidirectional.IBidirectionalMappingRule; +import org.simantics.objmap.forward.IForwardLinkType; + +/** + * Contains rules for how a link should be created and maintained. + * @author Hannu Niemistö + */ +public interface ILinkType extends IBidirectionalMappingRule, IBackwardLinkType, IForwardLinkType { + /** + * Creates a domain element based on known range element. + */ + //Resource createDomainElement(WriteGraph g, Object rangeElement) throws MappingException; + + /** + * Creates a range element based on known domain element. + */ + //Object createRangeElement(ReadGraph g, Resource domainElement) throws MappingException; +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/schema/IMappingSchema.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/schema/IMappingSchema.java new file mode 100644 index 00000000..c5cdb0f8 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/schema/IMappingSchema.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.graph.schema; + +import org.simantics.db.ReadGraph; +import org.simantics.objmap.exceptions.MappingException; + +/** + * Specifies the link types of new elements added to a mapping. + * @author Hannu Niemistö + */ +public interface IMappingSchema { + /** + * @return Link type that should be used for the element. + */ + ILinkType linkTypeOfDomainElement(ReadGraph g, Domain element) throws MappingException; + + /** + * @return Link type that should be used for the element. + */ + ILinkType linkTypeOfRangeElement(Range element) throws MappingException; +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/schema/MappingSchemas.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/schema/MappingSchemas.java new file mode 100644 index 00000000..6a7d940f --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/schema/MappingSchemas.java @@ -0,0 +1,238 @@ +package org.simantics.objmap.graph.schema; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collection; + +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.exception.DatabaseException; +import org.simantics.objmap.bidirectional.IBidirectionalMappingRule; +import org.simantics.objmap.graph.annotations.CompoundRelatedGetValue; +import org.simantics.objmap.graph.annotations.DynamicGraphType; +import org.simantics.objmap.graph.annotations.GraphType; +import org.simantics.objmap.graph.annotations.HasCollectionAdder; +import org.simantics.objmap.graph.annotations.HasCollectionRemover; +import org.simantics.objmap.graph.annotations.HasSetter; +import org.simantics.objmap.graph.annotations.OptionalRelatedElements; +import org.simantics.objmap.graph.annotations.RelatedElements; +import org.simantics.objmap.graph.annotations.RelatedElementsGet; +import org.simantics.objmap.graph.annotations.RelatedGetObj; +import org.simantics.objmap.graph.annotations.RelatedGetValue; +import org.simantics.objmap.graph.annotations.RelatedOrderedSetElements; +import org.simantics.objmap.graph.annotations.RelatedValue; +import org.simantics.objmap.graph.annotations.UpdateMethod; +import org.simantics.objmap.graph.annotations.factories.CompoundRelatedGetSetValueRuleFactory; +import org.simantics.objmap.graph.annotations.factories.OptionalRelatedElementsRuleFactory; +import org.simantics.objmap.graph.annotations.factories.RelatedElementsRuleFactory; +import org.simantics.objmap.graph.annotations.factories.RelatedElementsRuleFactory2; +import org.simantics.objmap.graph.annotations.factories.RelatedGetSetObjRuleFactory; +import org.simantics.objmap.graph.annotations.factories.RelatedGetSetValueRuleFactory; +import org.simantics.objmap.graph.annotations.factories.RelatedOrderedSetElementsRuleFactory; +import org.simantics.objmap.graph.annotations.factories.RelatedValueRuleFactory; +import org.simantics.objmap.graph.annotations.factories.UpdateMethodFactory; +import org.simantics.objmap.graph.annotations.meta.IsClassRule; +import org.simantics.objmap.graph.annotations.meta.IsCollectionRule; +import org.simantics.objmap.graph.annotations.meta.IsFieldRule; +import org.simantics.objmap.graph.annotations.meta.IsGetSetRule; +import org.simantics.objmap.graph.annotations.meta.IsMethodRule; +import org.simantics.objmap.graph.rules.factory.IClassRuleFactory; +import org.simantics.objmap.graph.rules.factory.ICollectionRuleFactory; +import org.simantics.objmap.graph.rules.factory.IFieldRuleFactory; +import org.simantics.objmap.graph.rules.factory.IGetSetRuleFactory; +import org.simantics.objmap.graph.rules.factory.IMethodRuleFactory; + + +public class MappingSchemas { + /** + * Creates a new SimpleLinkType based on the annotations in the given class. + * @throws IllegalAccessException + * @throws InstantiationException + * @see GraphType + * @see RelatedValue + */ + public static SimpleLinkType fromAnnotations(ReadGraph g, Class clazz) throws DatabaseException, InstantiationException, IllegalAccessException { + GraphType graphType = clazz.getAnnotation(GraphType.class); + + if (graphType != null) { + ArrayList> rules = new ArrayList>(); + collectRulesFromAnnotations(g, clazz, rules); + + return new SimpleLinkType(g.getResource(graphType.value()), clazz, rules); + } + DynamicGraphType dynamicType = clazz.getAnnotation(DynamicGraphType.class); + if (dynamicType != null) { + ArrayList> rules = new ArrayList>(); + collectRulesFromAnnotations(g, clazz, rules); + + return new DynamicSimpleLinkType(g.getResource(dynamicType.value()), clazz, rules); + } + throw new IllegalArgumentException("Class " + clazz.toString() + " does not contain annotations."); + } + + public static void collectRulesFromAnnotations(ReadGraph g, Class clazz, Collection> rules) throws DatabaseException, InstantiationException, IllegalAccessException { + Class superclass = clazz.getSuperclass(); + if(superclass != null) + collectRulesFromAnnotations(g, superclass, rules); + + for(Annotation annotation : clazz.getAnnotations()) { + + IsClassRule tag = annotation.annotationType().getAnnotation(IsClassRule.class); + if(tag!= null) { + rules.add(createClassRule(g, annotation, clazz).create(g, annotation, clazz)); + } + } + + for(Field f : clazz.getDeclaredFields()) { + f.setAccessible(true); + + for(Annotation annotation : f.getAnnotations()) { + + IsFieldRule tag = annotation.annotationType().getAnnotation(IsFieldRule.class); + if(tag != null) { + rules.add(createFieldRule(g, annotation, f).create(g, annotation, f)); + } + } + } + + for(Method m : clazz.getDeclaredMethods()) { + m.setAccessible(true); + + for(Annotation annotation : m.getAnnotations()) { + IsMethodRule tag = + annotation.annotationType().getAnnotation(IsMethodRule.class); + if(tag != null) { + rules.add(createMethodRule(g, annotation, m).create(g, annotation, m)); + } + } + } + + for (Method m : clazz.getDeclaredMethods()) { + m.setAccessible(true); + for (Annotation annotation : m.getAnnotations()) { + Class annotationType = annotation.annotationType(); + + IsGetSetRule tag = + annotationType.getAnnotation(IsGetSetRule.class); + if (tag != null) { + + HasSetter setterAnnType = annotationType.getAnnotation(HasSetter.class); + + Class setterAnn = setterAnnType.value(); + + Method getter = m; + + IGetSetRuleFactory ruleFactory = createGetSetRuleFactory(g, annotation, getter); + + + Method setter = null; + + for (Method m2 : clazz.getDeclaredMethods()) { + Annotation set = m2.getAnnotation(setterAnn); + if (set != null && ruleFactory.isSetter(annotation, set)) + setter = m2; + } + + rules.add(ruleFactory.create(g, annotation, getter, setter)); + } + + } + } + + for (Method m : clazz.getDeclaredMethods()) { + m.setAccessible(true); + for (Annotation annotation : m.getAnnotations()) { + Class annotationType = annotation.annotationType(); + + IsCollectionRule tag = + annotationType.getAnnotation(IsCollectionRule.class); + if (tag != null) { + + HasCollectionAdder adderAnnType = annotationType.getAnnotation(HasCollectionAdder.class); + HasCollectionRemover removerAnnType = annotationType.getAnnotation(HasCollectionRemover.class); + + Class adderAnn = adderAnnType.value(); + Class removerAnn = removerAnnType.value(); + + Method getter = m; + + ICollectionRuleFactory ruleFactory = createCollectionRuleFactory(g, annotation, getter); + + + Method adder = null; + Method remover = null; + + for (Method m2 : clazz.getDeclaredMethods()) { + Annotation add = m2.getAnnotation(adderAnn); + Annotation rem = m2.getAnnotation(removerAnn); + if (add != null && ruleFactory.isAdder(annotation, add)) + adder = m2; + if (rem != null && ruleFactory.isRemover(annotation, rem)) + remover = m2; + } + + + + rules.add(ruleFactory.create(g, annotation, getter,adder,remover)); + } + + } + } + } + + public static IClassRuleFactory createClassRule(ReadGraph g, Annotation annotation, Class clazz) { + return null; + } + + public static IFieldRuleFactory createFieldRule(ReadGraph g, Annotation annotation, Field field) { + if (annotation.annotationType().equals(RelatedElements.class)) + return new RelatedElementsRuleFactory(); + if (annotation.annotationType().equals(RelatedValue.class)) + return new RelatedValueRuleFactory(); + if (annotation.annotationType().equals(OptionalRelatedElements.class)) + return new OptionalRelatedElementsRuleFactory(); + if (annotation.annotationType().equals(RelatedOrderedSetElements.class)) + return new RelatedOrderedSetElementsRuleFactory(); + return null; + } + + public static IMethodRuleFactory createMethodRule(ReadGraph g, Annotation annotation, Method m) { + if (annotation.annotationType().equals(UpdateMethod.class)) + return new UpdateMethodFactory(); + return null; + } + + public static IGetSetRuleFactory createGetSetRuleFactory(ReadGraph g, Annotation annotation, Method getter) { + if (annotation.annotationType().equals(RelatedGetValue.class)) + return new RelatedGetSetValueRuleFactory(); + if (annotation.annotationType().equals(RelatedGetObj.class)) + return new RelatedGetSetObjRuleFactory(); + if (annotation.annotationType().equals(CompoundRelatedGetValue.class)) + return new CompoundRelatedGetSetValueRuleFactory(); + return null; + } + + public static ICollectionRuleFactory createCollectionRuleFactory(ReadGraph g, Annotation annotation, Method getter) { + if (annotation.annotationType().equals(RelatedElementsGet.class)) + return new RelatedElementsRuleFactory2(); + return null; + } + + /** + * Creates a new SimpleLinkType based on the annotations in the given class. + * @throws IllegalAccessException + * @throws InstantiationException + * @see GraphType + * @see RelatedValue + */ + + public static AdaptedLinkType fromAdaptable(ReadGraph g, String type, Class clazz) throws DatabaseException, InstantiationException, IllegalAccessException { + + + return new AdaptedLinkType(g.getResource(type), clazz); + } + + +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/schema/SimpleLinkType.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/schema/SimpleLinkType.java new file mode 100644 index 00000000..812b22db --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/schema/SimpleLinkType.java @@ -0,0 +1,139 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.graph.schema; + +import java.util.ArrayList; + +import org.apache.log4j.Logger; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.WriteGraph; +import org.simantics.db.common.utils.NameUtils; +import org.simantics.db.exception.DatabaseException; +import org.simantics.layer0.Layer0; +import org.simantics.objmap.backward.IBackwardMapping; +import org.simantics.objmap.bidirectional.IBidirectionalMappingRule; +import org.simantics.objmap.exceptions.MappingException; +import org.simantics.objmap.forward.IForwardMapping; + + +/** + * A link type that is associated with single domain and range type (class). + * SimpleLinkType is composed of simpler rules whose combination determines + * its update policy. + * @author Hannu Niemist� + */ +public class SimpleLinkType implements ILinkType { + + static Logger LOGGER = Logger.getLogger("org.simantics.objmap"); + + public Resource domainType; + public Class rangeType; + ArrayList> rules; + + public SimpleLinkType(Resource domainType, Class rangeType, + ArrayList> rules) { + this.domainType = domainType; + this.rangeType = rangeType; + this.rules = rules; + } + + public SimpleLinkType(Resource domainType, Class rangeType) { + this(domainType, rangeType, new ArrayList>()); + } + + /** + * Adds a new rule to this link type that is enforced + * during updates. + */ + public void addRule(IBidirectionalMappingRule rule) { + rules.add(rule); + } + + @Override + public Resource createDomainElement(WriteGraph g, Range rangeElement) + throws MappingException { + try { + if(LOGGER.isInfoEnabled()) + LOGGER.info("SimpleLinkType.createDomainElement " + + rangeElement.toString() + ); + Resource result = g.newResource(); + g.claim(result, Layer0.getInstance(g).InstanceOf, null, domainType); + return result; + } catch(DatabaseException e) { + throw new MappingException(e); + } + } + @Override + public Range createRangeElement(ReadGraph g, Resource domainElement) + throws MappingException { + try { + if(LOGGER.isInfoEnabled()) + try { + LOGGER.info("SimpleLinkType.createRangeElement " + + NameUtils.getSafeName(g, domainElement) + ); + } catch(DatabaseException e) { + throw new MappingException(e); + } + return (Range)rangeType.newInstance(); + } catch (InstantiationException e) { + throw new MappingException(e); + } catch (IllegalAccessException e) { + throw new MappingException(e); + } + } + + public void createDomain(WriteGraph graph, IBackwardMapping mapping, Resource domainElement, Range rangeElement) throws MappingException { + updateDomain(graph, mapping, domainElement, rangeElement); + }; + + public void createRange(ReadGraph graph, org.simantics.objmap.forward.IForwardMapping mapping, Resource domainElement, Range rangeElement) throws MappingException { + updateRange(graph, mapping, domainElement, rangeElement); + }; + + public boolean updateDomain(WriteGraph g, IBackwardMapping map, Resource domainElement, Range rangeElement) throws MappingException { + if(LOGGER.isInfoEnabled()) + try { + LOGGER.info("SimpleLinkType.updateDomain " + + NameUtils.getSafeName(g, domainElement) + " " + + rangeElement.toString() + ); + } catch(DatabaseException e) { + throw new MappingException(e); + } + + boolean updated = false; + for(IBidirectionalMappingRule rule : rules) + updated |= rule.updateDomain(g, map, domainElement, rangeElement); + return updated; + } + + public boolean updateRange(ReadGraph g, IForwardMapping map, Resource domainElement, Range rangeElement) throws MappingException { + + if(LOGGER.isInfoEnabled()) + try { + LOGGER.info("SimpleLinkType.updateRange " + + NameUtils.getSafeName(g, domainElement) + " " + + rangeElement.toString() + ); + } catch(DatabaseException e) { + throw new MappingException(e); + } + + boolean updated = false; + for(IBidirectionalMappingRule rule : rules) + updated |= rule.updateRange(g, map, domainElement, rangeElement); + return updated; + } +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/schema/SimpleSchema.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/schema/SimpleSchema.java new file mode 100644 index 00000000..87f4cfbb --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/graph/schema/SimpleSchema.java @@ -0,0 +1,94 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.graph.schema; + + +import java.util.Stack; + +import gnu.trove.map.hash.THashMap; + +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.common.utils.NameUtils; +import org.simantics.db.exception.DatabaseException; +import org.simantics.objmap.exceptions.MappingException; + + +/** + * An implementation of IMappingSchema that contains + * only SimpleLinkTypes. The link type of any domain + * element is based solely on its type in database and + * the link type of any range element is based on its class. + * @author Hannu Niemistö + */ +public class SimpleSchema implements IMappingSchema { + + THashMap> domainLinkTypes = + new THashMap>(); + THashMap, ILinkType> rangeLinkTypes = + new THashMap, ILinkType>(); + + public void addLinkType(SimpleLinkType linkType) { + domainLinkTypes.put(linkType.domainType, linkType); + rangeLinkTypes.put(linkType.rangeType, linkType); + } + + public void addLinkType(AdaptedLinkType linkType) { + domainLinkTypes.put(linkType.domainType, linkType); + rangeLinkTypes.put(linkType.rangeType, linkType); + } + + @Override + public ILinkType linkTypeOfDomainElement(ReadGraph g, Resource element) throws MappingException { + try { + + for(Resource type : g.getTypes(element)) { + + ILinkType linkType = domainLinkTypes.get(type); + if(linkType != null) return linkType; + + } + + throw new MappingException("Didn't find a link type for " + NameUtils.getSafeName(g, element) + "."); + + } catch (DatabaseException e) { + throw new MappingException(e); + } + } + + @Override + public ILinkType linkTypeOfRangeElement(Object element) throws MappingException { + ILinkType type = rangeLinkTypes.get(element.getClass()); + if(type == null) { + Stack> clazzes = new Stack>(); + for (Class clazz : element.getClass().getInterfaces()) { + clazzes.add(clazz); + } + clazzes.add(element.getClass().getSuperclass()); + + + while (!clazzes.isEmpty()) { + Class clazz = clazzes.pop(); + + type = rangeLinkTypes.get(clazz); + if (type != null) + return type; + for (Class c : clazz.getInterfaces()) + clazzes.add(c); + + } + throw new MappingException("Didn't find a link type for " + element.getClass() + "."); + } + return type; + } + +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/internal/BidirectionalLink.java b/org.simantics.objmap2/src/org/simantics/objmap/internal/BidirectionalLink.java new file mode 100644 index 00000000..326782d4 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/internal/BidirectionalLink.java @@ -0,0 +1,19 @@ +package org.simantics.objmap.internal; + +import org.simantics.objmap.bidirectional.IBidirectionalLinkType; + +public class BidirectionalLink { + IBidirectionalLinkType linkType; + Domain domainElement; + Range rangeElement; + + boolean domainModified; + boolean rangeModified; + + public BidirectionalLink(IBidirectionalLinkType linkType, + Domain domainElement, Range rangeElement) { + this.linkType = linkType; + this.domainElement = domainElement; + this.rangeElement = rangeElement; + } +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/internal/BidirectionalMapping.java b/org.simantics.objmap2/src/org/simantics/objmap/internal/BidirectionalMapping.java new file mode 100644 index 00000000..b3fdacad --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/internal/BidirectionalMapping.java @@ -0,0 +1,129 @@ +package org.simantics.objmap.internal; + +import gnu.trove.map.hash.THashMap; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Set; + +import org.simantics.db.ReadGraph; +import org.simantics.db.WriteGraph; +import org.simantics.objmap.bidirectional.IBidirectionalLinkType; +import org.simantics.objmap.bidirectional.IBidirectionalMapping; +import org.simantics.objmap.bidirectional.IBidirectionalMappingSchema; +import org.simantics.objmap.exceptions.MappingException; + +public class BidirectionalMapping implements IBidirectionalMapping { + + IBidirectionalMappingSchema schema; + THashMap> forwardMap = + new THashMap>(); + THashMap> backwardMap = + new THashMap>(); + + ArrayList> modifiedDomain = new ArrayList>(); + ArrayList> modifiedRange = new ArrayList>(); + + private void markDomainModified(BidirectionalLink link) { + if(!link.domainModified) { + link.domainModified = true; + modifiedDomain.add(link); + } + } + + private void markRangeModified(BidirectionalLink link) { + if(!link.rangeModified) { + link.rangeModified = true; + modifiedRange.add(link); + } + } + + public BidirectionalMapping(IBidirectionalMappingSchema schema) { + this.schema = schema; + } + + private BidirectionalLink addLink(IBidirectionalLinkType linkType, Domain domainElement, Range rangeElement) { + BidirectionalLink link = + new BidirectionalLink(linkType, domainElement, rangeElement); + forwardMap.put(domainElement, link); + backwardMap.put(rangeElement, link); + return link; + } + + @Override + public Set getDomain() { + return Collections.unmodifiableSet(forwardMap.keySet()); + } + + @Override + public Range get(Domain domainElement) { + BidirectionalLink link = forwardMap.get(domainElement); + if(link == null) + return null; + return link.rangeElement; + } + + @Override + public Range map(ReadGraph graph, Domain domainElement) throws MappingException { + Range result = get(domainElement); + if(result == null) { + IBidirectionalLinkType linkType = + schema.linkTypeOfDomainElement(graph, domainElement); + Range rangeElement = linkType.createRangeElement(graph, domainElement); + addLink(linkType, domainElement, rangeElement); + linkType.createRange(graph, this, domainElement, rangeElement); + } + return result; + } + + public Collection updateRange(ReadGraph graph) throws MappingException { + ArrayList updated = new ArrayList(Math.max(10, modifiedDomain.size())); + for(BidirectionalLink link : modifiedDomain) { + link.domainModified = false; + if(link.linkType.updateRange(graph, this, link.domainElement, link.rangeElement)) + updated.add(link.rangeElement); + } + modifiedDomain.clear(); + return updated; + } + + @Override + public Set getRange() { + return Collections.unmodifiableSet(backwardMap.keySet()); + } + + @Override + public Domain inverseGet(Range rangeElement) { + BidirectionalLink link = backwardMap.get(rangeElement); + if(link == null) + return null; + return link.domainElement; + } + + @Override + public Domain inverseMap(WriteGraph graph, Range rangeElement) + throws MappingException { + Domain result = inverseGet(rangeElement); + if(result == null) { + IBidirectionalLinkType linkType = + schema.linkTypeOfRangeElement(graph, rangeElement); + Domain domainElement = linkType.createDomainElement(graph, rangeElement); + addLink(linkType, domainElement, rangeElement); + linkType.createDomain(graph, this, domainElement, rangeElement); + } + return result; + } + + public Collection updateDomain(WriteGraph graph) throws MappingException { + ArrayList updated = new ArrayList(Math.max(10, modifiedRange.size())); + for(BidirectionalLink link : modifiedRange) { + link.rangeModified = false; + if(link.linkType.updateDomain(graph, this, link.domainElement, link.rangeElement)) + updated.add(link.domainElement); + } + modifiedDomain.clear(); + return updated; + } + +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/internal/MonotoneBackwardMapping.java b/org.simantics.objmap2/src/org/simantics/objmap/internal/MonotoneBackwardMapping.java new file mode 100644 index 00000000..709d3e09 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/internal/MonotoneBackwardMapping.java @@ -0,0 +1,52 @@ +package org.simantics.objmap.internal; + +import gnu.trove.map.hash.THashMap; + +import java.util.Collections; +import java.util.Set; + +import org.simantics.db.WriteGraph; +import org.simantics.objmap.backward.IBackwardLinkType; +import org.simantics.objmap.backward.IBackwardMapping; +import org.simantics.objmap.backward.IBackwardMappingSchema; +import org.simantics.objmap.exceptions.MappingException; + +/** + * An unidirectional (from range to domain) mapping that does not support removals. + * + * @author Hannu Niemistö + */ +public class MonotoneBackwardMapping implements IBackwardMapping { + + IBackwardMappingSchema schema; + THashMap map = new THashMap(); + + public MonotoneBackwardMapping(IBackwardMappingSchema schema) { + this.schema = schema; + } + + @Override + public Set getRange() { + return Collections.unmodifiableSet(map.keySet()); + } + + @Override + public Domain inverseGet(Range rangeElement) { + return map.get(rangeElement); + } + + @Override + public Domain inverseMap(WriteGraph graph, Range rangeElement) throws MappingException { + Domain result = inverseGet(rangeElement); + if(result == null) { + IBackwardLinkType linkType = + schema.linkTypeOfRangeElement(graph, rangeElement); + // Two phase creation makes cyclic references possible + Domain domainElement = linkType.createDomainElement(graph, rangeElement); + map.put(rangeElement, domainElement); + linkType.createDomain(graph, this, domainElement, rangeElement); + } + return result; + } + +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/internal/MonotoneForwardMapping.java b/org.simantics.objmap2/src/org/simantics/objmap/internal/MonotoneForwardMapping.java new file mode 100644 index 00000000..51065ff2 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/internal/MonotoneForwardMapping.java @@ -0,0 +1,47 @@ +package org.simantics.objmap.internal; + +import gnu.trove.map.hash.THashMap; + +import java.util.Collections; +import java.util.Set; + +import org.simantics.db.ReadGraph; +import org.simantics.objmap.exceptions.MappingException; +import org.simantics.objmap.forward.IForwardLinkType; +import org.simantics.objmap.forward.IForwardMapping; +import org.simantics.objmap.forward.IForwardMappingSchema; + +public class MonotoneForwardMapping implements IForwardMapping { + + IForwardMappingSchema schema; + THashMap map = new THashMap(); + + public MonotoneForwardMapping(IForwardMappingSchema schema) { + this.schema = schema; + } + + @Override + public Set getDomain() { + return Collections.unmodifiableSet(map.keySet()); + } + + @Override + public Range get(Domain domainElement) { + return map.get(domainElement); + } + + @Override + public Range map(ReadGraph graph, Domain domainElement) throws MappingException { + Range result = get(domainElement); + if(result == null) { + IForwardLinkType linkType = + schema.linkTypeOfDomainElement(graph, domainElement); + // Two phase creation makes cyclic references possible + Range rangeElement = linkType.createRangeElement(graph, domainElement); + map.put(domainElement, rangeElement); + linkType.createRange(graph, this, domainElement, rangeElement); + } + return result; + } + +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/IStructuralObject.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/IStructuralObject.java new file mode 100644 index 00000000..051f3751 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/structural/IStructuralObject.java @@ -0,0 +1,38 @@ +package org.simantics.objmap.structural; + +import java.util.List; + +import org.simantics.db.Resource; + +/** + * Interface for structurally mapped Java objects. + * + * @author Marko Luukkainen + * + */ +public interface IStructuralObject { + + /** + * Context of an object. + * @return + */ + public List getContext(); + + /** + * Sets object's context. Used by ObjMap, don't touch. + * @param object + */ + public void setContext(List object); + + /** + * Return type resource for Structural instances. For other objects returns null. + * @return + */ + public Resource getType(); + + /** + * Sets object's type. Used by ObjMap, don't touch. + * @param object + */ + public void setType(Resource type); +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/StructuralResource.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/StructuralResource.java new file mode 100644 index 00000000..20e9230b --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/structural/StructuralResource.java @@ -0,0 +1,156 @@ +package org.simantics.objmap.structural; + +import java.util.ArrayList; +import java.util.List; + +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.exception.DatabaseException; +import org.simantics.layer0.Layer0; + +/** + * An object representing structural Resource. + * + * + * @author Marko Luukkainen + * + */ +public class StructuralResource { + + private Resource resource; + private List context = new ArrayList(1); + + private Resource typeResource = null; + + public StructuralResource(Resource resource) { + assert(resource != null); + this.resource = resource; + } + public StructuralResource(ReadGraph g, Resource resource, Resource context) throws DatabaseException { + assert(resource != null); + this.resource = resource; + this.context.add(context); + resolveType(g); + } + + public StructuralResource(ReadGraph g, Resource resource, Resource... context) throws DatabaseException { + assert(resource != null); + this.resource = resource; + for (Resource r : context) + this.context.add(r); + resolveType(g); + } + + public StructuralResource(ReadGraph g, Resource resource, List context) throws DatabaseException { + assert(resource != null); + this.resource = resource; + for (Resource r : context) + this.context.add(r); + resolveType(g); + } + public StructuralResource(ReadGraph g, Resource resource, List context, Resource context2) throws DatabaseException { + assert(resource != null); + this.resource = resource; + for (Resource r : context) + this.context.add(r); + this.context.add(context2); + resolveType(g); + } + + private void resolveType(ReadGraph g) throws DatabaseException { + if (this.context.contains(resource)) { + Layer0 l0 = Layer0.getInstance(g); + typeResource = g.getSingleObject(resource, l0.InstanceOf); + } + } + + + /** + * The Resource in the DB. + * @return + */ + public Resource getResource() { + return resource; + } + + /** + * Context in which this resource is accessed. Each context resource represents a structural model instance. + * @return + */ + public List getContext() { + return context; + } + + /** + * If the resource is structural model instance, this returns the type Resource. Otherwise returns null. + * @return + */ + public Resource getTypeResource() { + return typeResource; + } + + /** + * Returns true, if the resource is structural, + * @return + */ + public boolean isStructural() { + return context.size() > 0; + } + + /** + * Returns true is the Resource is root of Structural Model instance. + * In this case the resource instance is editable. + * + * @return + */ + public boolean isStructuralRoot() { + return (context.size() == 1 && context.get(0).equals(resource)); + } + + /** + * Returns true, the resource is structural model instance. + * @return + */ + public boolean isStructuralInstance() { + return typeResource != null; + } + + @Override + public int hashCode() { + int hashCode = resource.hashCode(); + for (Resource ctx : context) + hashCode += ctx.hashCode(); + return hashCode; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) + return true; + if (obj == null) + return false; + if (obj.getClass() != getClass()) + return false; + StructuralResource other = (StructuralResource)obj; + if (!resource.equals(other.resource)) + return false; + if (context.size() != other.context.size()) + return false; + for (int i = 0; i < context.size(); i++) { + if (!context.get(i).equals(other.context.get(i))) + return false; + } + return true; + } + + @Override + public String toString() { + String s = "Res: " + resource + " Context:"; + for (Resource ctx : context) + s+= " "+ ctx; + if (typeResource != null) + s+= " Type: " + typeResource; + return s; + } + +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/StructuralRelatedElementsAdd.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/StructuralRelatedElementsAdd.java new file mode 100644 index 00000000..4237abcf --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/StructuralRelatedElementsAdd.java @@ -0,0 +1,12 @@ +package org.simantics.objmap.structural.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface StructuralRelatedElementsAdd { + String value(); +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/StructuralRelatedElementsGet.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/StructuralRelatedElementsGet.java new file mode 100644 index 00000000..65f3b25c --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/StructuralRelatedElementsGet.java @@ -0,0 +1,21 @@ +package org.simantics.objmap.structural.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.simantics.objmap.graph.annotations.HasCollectionAdder; +import org.simantics.objmap.graph.annotations.HasCollectionRemover; +import org.simantics.objmap.graph.annotations.meta.IsCollectionRule; + + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +@IsCollectionRule +@HasCollectionAdder(StructuralRelatedElementsAdd.class) +@HasCollectionRemover(StructuralRelatedElementsRem.class) +public @interface StructuralRelatedElementsGet { + String value(); + boolean composition() default false; +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/StructuralRelatedElementsRem.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/StructuralRelatedElementsRem.java new file mode 100644 index 00000000..aaa8d7fd --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/StructuralRelatedElementsRem.java @@ -0,0 +1,13 @@ +package org.simantics.objmap.structural.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface StructuralRelatedElementsRem { + String value(); +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/StructuralRelatedGetObj.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/StructuralRelatedGetObj.java new file mode 100644 index 00000000..f274eb8b --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/StructuralRelatedGetObj.java @@ -0,0 +1,19 @@ +package org.simantics.objmap.structural.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.simantics.objmap.graph.annotations.HasSetter; +import org.simantics.objmap.graph.annotations.meta.IsGetSetRule; + + + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +@IsGetSetRule +@HasSetter(StructuralRelatedSetObj.class) +public @interface StructuralRelatedGetObj { + String value(); +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/StructuralRelatedSetObj.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/StructuralRelatedSetObj.java new file mode 100644 index 00000000..19cf3bfa --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/StructuralRelatedSetObj.java @@ -0,0 +1,13 @@ +package org.simantics.objmap.structural.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface StructuralRelatedSetObj { + String value(); +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/TypeRelatedElementsAdd.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/TypeRelatedElementsAdd.java new file mode 100644 index 00000000..82b675e3 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/TypeRelatedElementsAdd.java @@ -0,0 +1,12 @@ +package org.simantics.objmap.structural.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface TypeRelatedElementsAdd { + String value(); +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/TypeRelatedElementsGet.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/TypeRelatedElementsGet.java new file mode 100644 index 00000000..5ec2f453 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/TypeRelatedElementsGet.java @@ -0,0 +1,21 @@ +package org.simantics.objmap.structural.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.simantics.objmap.graph.annotations.HasCollectionAdder; +import org.simantics.objmap.graph.annotations.HasCollectionRemover; +import org.simantics.objmap.graph.annotations.meta.IsCollectionRule; + + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +@IsCollectionRule +@HasCollectionAdder(TypeRelatedElementsAdd.class) +@HasCollectionRemover(TypeRelatedElementsRem.class) +public @interface TypeRelatedElementsGet { + String value(); + boolean composition() default false; +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/TypeRelatedElementsRem.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/TypeRelatedElementsRem.java new file mode 100644 index 00000000..773b652b --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/TypeRelatedElementsRem.java @@ -0,0 +1,13 @@ +package org.simantics.objmap.structural.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface TypeRelatedElementsRem { + String value(); +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/TypeRelatedGetObj.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/TypeRelatedGetObj.java new file mode 100644 index 00000000..e2d0b9f2 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/TypeRelatedGetObj.java @@ -0,0 +1,20 @@ +package org.simantics.objmap.structural.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.simantics.objmap.graph.annotations.HasSetter; +import org.simantics.objmap.graph.annotations.meta.IsGetSetRule; + + + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +//@HasGetSetRuleFactory(RelatedGetSetObjRuleFactory.class) +@IsGetSetRule +@HasSetter(TypeRelatedSetObj.class) +public @interface TypeRelatedGetObj { + String value(); +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/TypeRelatedGetValue.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/TypeRelatedGetValue.java new file mode 100644 index 00000000..2cb19f51 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/TypeRelatedGetValue.java @@ -0,0 +1,23 @@ +package org.simantics.objmap.structural.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.simantics.objmap.graph.annotations.HasSetter; +import org.simantics.objmap.graph.annotations.meta.IsGetSetRule; +import org.simantics.objmap.graph.rules.adapters.IdentityAdapter; +import org.simantics.objmap.graph.rules.adapters.ValueAdapter; + + + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +//@HasGetSetRuleFactory(RelatedGetSetValueRuleFactory.class) +@IsGetSetRule +@HasSetter(TypeRelatedSetValue.class) +public @interface TypeRelatedGetValue { + String value(); + Class adapter() default IdentityAdapter.class; +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/TypeRelatedSetObj.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/TypeRelatedSetObj.java new file mode 100644 index 00000000..71e9628f --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/TypeRelatedSetObj.java @@ -0,0 +1,13 @@ +package org.simantics.objmap.structural.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface TypeRelatedSetObj { + String value(); +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/TypeRelatedSetValue.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/TypeRelatedSetValue.java new file mode 100644 index 00000000..de8a6043 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/TypeRelatedSetValue.java @@ -0,0 +1,13 @@ +package org.simantics.objmap.structural.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface TypeRelatedSetValue { + String value(); +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/DataTypeUtils.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/DataTypeUtils.java new file mode 100644 index 00000000..36091e4d --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/DataTypeUtils.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.structural.annotations.factories; + +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.layer0.Layer0; + +public class DataTypeUtils { + + public static Resource dataTypeOfClass(ReadGraph g, Class clazz) { + Layer0 b = Layer0.getInstance(g); + if(clazz.equals(Double.class) || clazz.equals(double.class)) + return b.Double; + else if(clazz.equals(String.class)) + return b.String; + else if(clazz.equals(Integer.class) || clazz.equals(int.class)) + return b.Integer; + else if(clazz.equals(Float.class) || clazz.equals(float.class)) + return b.Float; + else if(clazz.equals(Boolean.class) || clazz.equals(boolean.class)) + return b.Boolean; + else if(clazz.equals(Long.class) || clazz.equals(long.class)) + return b.Long; + else if(clazz.equals(Byte.class) || clazz.equals(byte.class)) + return b.Byte; + + else if(clazz.equals(double[].class)) + return b.DoubleArray; + else if(clazz.equals(int[].class)) + return b.IntegerArray; + else if(clazz.equals(byte[].class)) + return b.ByteArray; + else if(clazz.equals(float[].class)) + return b.FloatArray; + else if(clazz.equals(boolean[].class)) + return b.BooleanArray; + else if(clazz.equals(String[].class)) + return b.StringArray; + else if(clazz.equals(long[].class)) + return b.LongArray; + else { + System.out.println("Couldn't find a data type for " + clazz); + return null; + } + } + +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/OptionalRelatedElementsRuleFactory.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/OptionalRelatedElementsRuleFactory.java new file mode 100644 index 00000000..ad603ec3 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/OptionalRelatedElementsRuleFactory.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.structural.annotations.factories; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.util.Collection; +import java.util.Collections; + +import org.simantics.db.ReadGraph; +import org.simantics.db.exception.ResourceNotFoundException; +import org.simantics.db.exception.ServiceException; +import org.simantics.db.exception.ValidationException; +import org.simantics.objmap.bidirectional.IBidirectionalMappingRule; +import org.simantics.objmap.graph.annotations.OptionalRelatedElements; +import org.simantics.objmap.graph.rules.MappedElementsRule; +import org.simantics.objmap.structural.rules.domain.RelatedObjectsAccessor; +import org.simantics.objmap.graph.rules.factory.IFieldRuleFactory; +import org.simantics.objmap.graph.rules.range.FieldAccessorWithDefault; +import org.simantics.objmap.structural.StructuralResource; + + +public class OptionalRelatedElementsRuleFactory implements IFieldRuleFactory { + + @Override + public IBidirectionalMappingRule create(ReadGraph g, Annotation _annotation, Field field) throws ResourceNotFoundException, ValidationException, ServiceException { + OptionalRelatedElements annotation = (OptionalRelatedElements)_annotation; + return new MappedElementsRule( + new RelatedObjectsAccessor(g.getResource(annotation.value()), + annotation.composition(),false), + new FieldAccessorWithDefault>(field, (Collection)Collections.emptyList()) + ); + } + +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/RelatedElementRuleFactory.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/RelatedElementRuleFactory.java new file mode 100644 index 00000000..b6074047 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/RelatedElementRuleFactory.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.structural.annotations.factories; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; + +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.exception.ResourceNotFoundException; +import org.simantics.db.exception.ServiceException; +import org.simantics.db.exception.ValidationException; +import org.simantics.objmap.bidirectional.IBidirectionalMappingRule; +import org.simantics.objmap.graph.annotations.RelatedElement; +import org.simantics.objmap.graph.rules.MappedElementRule; +import org.simantics.objmap.graph.rules.domain.RelatedObjectAccessor; +import org.simantics.objmap.graph.rules.factory.IFieldRuleFactory; +import org.simantics.objmap.graph.rules.range.FieldAccessor; + + +public class RelatedElementRuleFactory implements IFieldRuleFactory { + + @Override + public IBidirectionalMappingRule create(ReadGraph g, Annotation _annotation, Field field) throws ResourceNotFoundException, ValidationException, ServiceException { + RelatedElement annotation = (RelatedElement)_annotation; + return new MappedElementRule( + new RelatedObjectAccessor(g.getResource(annotation.value())), + new FieldAccessor(field) + ); + } + +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/RelatedElementsRuleFactory.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/RelatedElementsRuleFactory.java new file mode 100644 index 00000000..b1c5f823 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/RelatedElementsRuleFactory.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.structural.annotations.factories; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.util.Collection; + +import org.simantics.db.ReadGraph; +import org.simantics.db.exception.ResourceNotFoundException; +import org.simantics.db.exception.ServiceException; +import org.simantics.db.exception.ValidationException; +import org.simantics.objmap.bidirectional.IBidirectionalMappingRule; +import org.simantics.objmap.graph.annotations.RelatedElements; +import org.simantics.objmap.graph.rules.MappedElementsRule; +import org.simantics.objmap.structural.rules.domain.RelatedObjectsAccessor; +import org.simantics.objmap.graph.rules.factory.IFieldRuleFactory; +import org.simantics.objmap.graph.rules.range.FieldAccessor; +import org.simantics.objmap.structural.StructuralResource; + + +public class RelatedElementsRuleFactory implements IFieldRuleFactory { + + @Override + public IBidirectionalMappingRule create(ReadGraph g, Annotation _annotation, Field field) throws ResourceNotFoundException, ValidationException, ServiceException { + RelatedElements annotation = (RelatedElements)_annotation; + return new MappedElementsRule( + new RelatedObjectsAccessor(g.getResource(annotation.value()), + annotation.composition(),false), + new FieldAccessor>(field) + ); + } + +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/RelatedElementsRuleFactory2.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/RelatedElementsRuleFactory2.java new file mode 100644 index 00000000..08feae22 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/RelatedElementsRuleFactory2.java @@ -0,0 +1,44 @@ +package org.simantics.objmap.structural.annotations.factories; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; + +import org.simantics.db.ReadGraph; +import org.simantics.db.exception.DatabaseException; +import org.simantics.objmap.bidirectional.IBidirectionalMappingRule; +import org.simantics.objmap.graph.annotations.RelatedElementsAdd; +import org.simantics.objmap.graph.annotations.RelatedElementsGet; +import org.simantics.objmap.graph.annotations.RelatedElementsRem; +import org.simantics.objmap.graph.rules.MappedElementsRule; +import org.simantics.objmap.graph.rules.factory.ICollectionRuleFactory; +import org.simantics.objmap.graph.rules.range.CollectionAccessor; +import org.simantics.objmap.structural.StructuralResource; +import org.simantics.objmap.structural.rules.domain.RelatedObjectsAccessor; + + +public class RelatedElementsRuleFactory2 implements ICollectionRuleFactory { + + @Override + public IBidirectionalMappingRule create(ReadGraph g, Annotation annotation, + Method getter, Method adder, Method remover) + throws DatabaseException { + RelatedElementsGet getterAnn = (RelatedElementsGet)annotation; + return new MappedElementsRule(new RelatedObjectsAccessor(g.getResource(getterAnn.value()),getterAnn.composition(),false,true,false), + new CollectionAccessor(getter, adder, remover)); + } + + @Override + public boolean isAdder(Annotation getterAnnotation, Annotation annotation) { + RelatedElementsGet getterAnn = (RelatedElementsGet)getterAnnotation; + RelatedElementsAdd adderAnn = (RelatedElementsAdd)annotation; + return getterAnn.value().equals(adderAnn.value()); + } + + @Override + public boolean isRemover(Annotation getterAnnotation, Annotation annotation) { + RelatedElementsGet getterAnn = (RelatedElementsGet)getterAnnotation; + RelatedElementsRem adderAnn = (RelatedElementsRem)annotation; + return getterAnn.value().equals(adderAnn.value()); + } + +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/RelatedGetSetObjRuleFactory.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/RelatedGetSetObjRuleFactory.java new file mode 100644 index 00000000..9c6bc776 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/RelatedGetSetObjRuleFactory.java @@ -0,0 +1,44 @@ +package org.simantics.objmap.structural.annotations.factories; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; + +import org.simantics.db.ReadGraph; +import org.simantics.db.exception.DatabaseException; +import org.simantics.objmap.bidirectional.IBidirectionalMappingRule; +import org.simantics.objmap.graph.annotations.RelatedGetObj; +import org.simantics.objmap.graph.annotations.RelatedSetObj; +import org.simantics.objmap.graph.rules.MappedElementRule; +import org.simantics.objmap.structural.rules.domain.RelatedObjectAccessor; +import org.simantics.objmap.graph.rules.factory.IGetSetRuleFactory; +import org.simantics.objmap.graph.rules.range.GetSetObjectAccessor; +import org.simantics.objmap.structural.StructuralResource; + + +/** + * Rule factory for mapped object using Getter/Setter-methods. + * + * @author Marko Luukkainen + * + */ +public class RelatedGetSetObjRuleFactory implements IGetSetRuleFactory { + + @Override + public IBidirectionalMappingRule create(ReadGraph g, Annotation annotation, + Method getter, Method setter) + throws DatabaseException { + RelatedGetObj getterAnn = (RelatedGetObj)annotation; + return new MappedElementRule(new RelatedObjectAccessor(g.getResource(getterAnn.value()),false,true,false), + new GetSetObjectAccessor(getter, setter)); + } + + @Override + public boolean isSetter(Annotation getterAnnotation, Annotation annotation) { + RelatedGetObj getterAnn = (RelatedGetObj)getterAnnotation; + RelatedSetObj setterAnn = (RelatedSetObj)annotation; + return getterAnn.value().equals(setterAnn.value()); + } + + + +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/RelatedGetSetValueRuleFactory.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/RelatedGetSetValueRuleFactory.java new file mode 100644 index 00000000..5974dd8e --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/RelatedGetSetValueRuleFactory.java @@ -0,0 +1,101 @@ +package org.simantics.objmap.structural.annotations.factories; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; + +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.exception.DatabaseException; +import org.simantics.layer0.Layer0; +import org.simantics.objmap.bidirectional.IBidirectionalMappingRule; +import org.simantics.objmap.graph.annotations.RelatedGetValue; +import org.simantics.objmap.graph.annotations.RelatedSetValue; +import org.simantics.objmap.graph.rules.ValueRule; +import org.simantics.objmap.graph.rules.adapters.IdentityAdapter; +import org.simantics.objmap.graph.rules.adapters.ValueAdapter; +import org.simantics.objmap.structural.StructuralResource; +import org.simantics.objmap.structural.rules.domain.RelatedValueAccessor; +import org.simantics.objmap.graph.rules.factory.IGetSetRuleFactory; +import org.simantics.objmap.graph.rules.range.AdaptedRangeAccessor; +import org.simantics.objmap.graph.rules.range.GetSetValueAccessor; +import org.simantics.objmap.graph.rules.range.IRangeAccessor; + +/** + * Rule factory for mapped value using Getter/Setter-methods. + * + * @author Marko Luukkainen + * + */ +public class RelatedGetSetValueRuleFactory implements IGetSetRuleFactory { + + @Override + public IBidirectionalMappingRule create(ReadGraph g, Annotation annotation, + Method getter, Method setter) + throws DatabaseException { + RelatedGetValue getterAnn = (RelatedGetValue)annotation; + + Class adapterClass = getterAnn.adapter(); + IRangeAccessor rangeAccessor = new GetSetValueAccessor(getter, setter); + Resource valueType; + if (adapterClass == IdentityAdapter.class) { + valueType = dataTypeOfClass(g, getter.getReturnType()); + } else { + try{ + ValueAdapter adapter = adapterClass.newInstance(); + rangeAccessor = new AdaptedRangeAccessor(rangeAccessor, adapter); + valueType = adapter.rangeTypeToDomainType(g, getter.getReturnType()); + } catch (InstantiationException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + return new ValueRule(new RelatedValueAccessor(g.getResource(getterAnn.value()), valueType,false,true,false), + rangeAccessor); + } + + @Override + public boolean isSetter(Annotation getterAnnotation, Annotation annotation) { + RelatedGetValue getterAnn = (RelatedGetValue)getterAnnotation; + RelatedSetValue setterAnn = (RelatedSetValue)annotation; + return getterAnn.value().equals(setterAnn.value()); + } + + public static Resource dataTypeOfClass(ReadGraph g, Class clazz) { + Layer0 b = Layer0.getInstance(g); + if(clazz.equals(Double.class) || clazz.equals(double.class)) + return b.Double; + else if(clazz.equals(String.class)) + return b.String; + else if(clazz.equals(Integer.class) || clazz.equals(int.class)) + return b.Integer; + else if(clazz.equals(Float.class) || clazz.equals(float.class)) + return b.Float; + else if(clazz.equals(Boolean.class) || clazz.equals(boolean.class)) + return b.Boolean; + else if(clazz.equals(Long.class) || clazz.equals(long.class)) + return b.Long; + else if(clazz.equals(Byte.class) || clazz.equals(byte.class)) + return b.Byte; + + else if(clazz.equals(double[].class)) + return b.DoubleArray; + else if(clazz.equals(int[].class)) + return b.IntegerArray; + else if(clazz.equals(byte[].class)) + return b.ByteArray; + else if(clazz.equals(float[].class)) + return b.FloatArray; + else if(clazz.equals(boolean[].class)) + return b.BooleanArray; + else if(clazz.equals(String[].class)) + return b.StringArray; + else if(clazz.equals(long[].class)) + return b.LongArray; + else { + System.out.println("Couldn't find a data type for " + clazz); + return null; + } + } + +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/RelatedOrderedSetElementsRuleFactory.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/RelatedOrderedSetElementsRuleFactory.java new file mode 100644 index 00000000..01838ab9 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/RelatedOrderedSetElementsRuleFactory.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.structural.annotations.factories; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.util.Collection; + +import org.simantics.db.ReadGraph; +import org.simantics.db.exception.ResourceNotFoundException; +import org.simantics.db.exception.ServiceException; +import org.simantics.db.exception.ValidationException; +import org.simantics.objmap.bidirectional.IBidirectionalMappingRule; +import org.simantics.objmap.graph.annotations.RelatedOrderedSetElements; +import org.simantics.objmap.graph.rules.MappedElementsRule; +import org.simantics.objmap.graph.rules.factory.IFieldRuleFactory; +import org.simantics.objmap.graph.rules.range.FieldAccessor; +import org.simantics.objmap.structural.StructuralResource; +import org.simantics.objmap.structural.rules.domain.RelatedOrderedSetElementsAccessor; + + +public class RelatedOrderedSetElementsRuleFactory implements IFieldRuleFactory { + + @Override + public IBidirectionalMappingRule create(ReadGraph g, Annotation _annotation, Field field) throws ResourceNotFoundException, ValidationException, ServiceException { + RelatedOrderedSetElements annotation = (RelatedOrderedSetElements)_annotation; + return new MappedElementsRule( + new RelatedOrderedSetElementsAccessor(annotation.composition(),false), + new FieldAccessor>(field) + ); + } + +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/RelatedValueRuleFactory.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/RelatedValueRuleFactory.java new file mode 100644 index 00000000..5ee9f20c --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/RelatedValueRuleFactory.java @@ -0,0 +1,61 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.structural.annotations.factories; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; + +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.exception.ResourceNotFoundException; +import org.simantics.db.exception.ServiceException; +import org.simantics.db.exception.ValidationException; + +import org.simantics.objmap.bidirectional.IBidirectionalMappingRule; +import org.simantics.objmap.graph.annotations.RelatedValue; +import org.simantics.objmap.graph.rules.ValueRule; +import org.simantics.objmap.graph.rules.adapters.IdentityAdapter; +import org.simantics.objmap.graph.rules.adapters.ValueAdapter; +import org.simantics.objmap.structural.rules.domain.RelatedValueAccessor; +import org.simantics.objmap.graph.rules.factory.IFieldRuleFactory; +import org.simantics.objmap.graph.rules.range.AdaptedRangeAccessor; +import org.simantics.objmap.graph.rules.range.FieldAccessor; +import org.simantics.objmap.graph.rules.range.IRangeAccessor; +import org.simantics.objmap.structural.StructuralResource; + + +public class RelatedValueRuleFactory implements IFieldRuleFactory { + + @Override + public IBidirectionalMappingRule create(ReadGraph g, Annotation _annotation, Field field) throws ResourceNotFoundException, + ValidationException, ServiceException { + RelatedValue annotation = (RelatedValue) _annotation; + Class adapterClass = annotation.adapter(); + IRangeAccessor rangeAccessor = new FieldAccessor(field); + Resource valueType; + if (adapterClass == IdentityAdapter.class) { + valueType = DataTypeUtils.dataTypeOfClass(g, field.getType()); + } else { + try { + ValueAdapter adapter = adapterClass.newInstance(); + rangeAccessor = new AdaptedRangeAccessor(rangeAccessor, adapter); + valueType = adapter.rangeTypeToDomainType(g, field.getType()); + } catch (InstantiationException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + return new ValueRule(new RelatedValueAccessor(g.getResource(annotation.value()), valueType,false,true,false), rangeAccessor); + } + +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/StructuralRelatedElementsRuleFactory2.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/StructuralRelatedElementsRuleFactory2.java new file mode 100644 index 00000000..ad30aee2 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/StructuralRelatedElementsRuleFactory2.java @@ -0,0 +1,44 @@ +package org.simantics.objmap.structural.annotations.factories; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; + +import org.simantics.db.ReadGraph; +import org.simantics.db.exception.DatabaseException; +import org.simantics.objmap.bidirectional.IBidirectionalMappingRule; +import org.simantics.objmap.graph.rules.MappedElementsRule; +import org.simantics.objmap.graph.rules.factory.ICollectionRuleFactory; +import org.simantics.objmap.graph.rules.range.CollectionAccessor; +import org.simantics.objmap.structural.StructuralResource; +import org.simantics.objmap.structural.annotations.StructuralRelatedElementsAdd; +import org.simantics.objmap.structural.annotations.StructuralRelatedElementsGet; +import org.simantics.objmap.structural.annotations.StructuralRelatedElementsRem; +import org.simantics.objmap.structural.rules.domain.StructuralRelatedObjectsAccessor; + + +public class StructuralRelatedElementsRuleFactory2 implements ICollectionRuleFactory { + + @Override + public IBidirectionalMappingRule create(ReadGraph g, Annotation annotation, + Method getter, Method adder, Method remover) + throws DatabaseException { + StructuralRelatedElementsGet getterAnn = (StructuralRelatedElementsGet)annotation; + return new MappedElementsRule(new StructuralRelatedObjectsAccessor(g.getResource(getterAnn.value()),getterAnn.composition()), + new CollectionAccessor(getter, adder, remover)); + } + + @Override + public boolean isAdder(Annotation getterAnnotation, Annotation annotation) { + StructuralRelatedElementsGet getterAnn = (StructuralRelatedElementsGet)getterAnnotation; + StructuralRelatedElementsAdd adderAnn = (StructuralRelatedElementsAdd)annotation; + return getterAnn.value().equals(adderAnn.value()); + } + + @Override + public boolean isRemover(Annotation getterAnnotation, Annotation annotation) { + StructuralRelatedElementsGet getterAnn = (StructuralRelatedElementsGet)getterAnnotation; + StructuralRelatedElementsRem adderAnn = (StructuralRelatedElementsRem)annotation; + return getterAnn.value().equals(adderAnn.value()); + } + +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/StructuralRelatedGetSetObjRuleFactory.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/StructuralRelatedGetSetObjRuleFactory.java new file mode 100644 index 00000000..bb97f7b6 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/StructuralRelatedGetSetObjRuleFactory.java @@ -0,0 +1,44 @@ +package org.simantics.objmap.structural.annotations.factories; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; + +import org.simantics.db.ReadGraph; +import org.simantics.db.exception.DatabaseException; +import org.simantics.objmap.bidirectional.IBidirectionalMappingRule; +import org.simantics.objmap.graph.rules.MappedElementRule; +import org.simantics.objmap.graph.rules.factory.IGetSetRuleFactory; +import org.simantics.objmap.graph.rules.range.GetSetObjectAccessor; +import org.simantics.objmap.structural.StructuralResource; +import org.simantics.objmap.structural.annotations.StructuralRelatedGetObj; +import org.simantics.objmap.structural.annotations.StructuralRelatedSetObj; +import org.simantics.objmap.structural.rules.domain.StructuralRelatedObjectAccessor; + + +/** + * Rule factory for mapped object using Getter/Setter-methods. + * + * @author Marko Luukkainen + * + */ +public class StructuralRelatedGetSetObjRuleFactory implements IGetSetRuleFactory { + + @Override + public IBidirectionalMappingRule create(ReadGraph g, Annotation annotation, + Method getter, Method setter) + throws DatabaseException { + StructuralRelatedGetObj getterAnn = (StructuralRelatedGetObj)annotation; + return new MappedElementRule(new StructuralRelatedObjectAccessor(g.getResource(getterAnn.value()),false,true,false), + new GetSetObjectAccessor(getter, setter)); + } + + @Override + public boolean isSetter(Annotation getterAnnotation, Annotation annotation) { + StructuralRelatedGetObj getterAnn = (StructuralRelatedGetObj)getterAnnotation; + StructuralRelatedSetObj setterAnn = (StructuralRelatedSetObj)annotation; + return getterAnn.value().equals(setterAnn.value()); + } + + + +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/TypeRelatedElementsRuleFactory2.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/TypeRelatedElementsRuleFactory2.java new file mode 100644 index 00000000..565f9dc3 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/TypeRelatedElementsRuleFactory2.java @@ -0,0 +1,44 @@ +package org.simantics.objmap.structural.annotations.factories; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; + +import org.simantics.db.ReadGraph; +import org.simantics.db.exception.DatabaseException; +import org.simantics.objmap.bidirectional.IBidirectionalMappingRule; +import org.simantics.objmap.graph.rules.MappedElementsRule; +import org.simantics.objmap.graph.rules.factory.ICollectionRuleFactory; +import org.simantics.objmap.graph.rules.range.CollectionAccessor; +import org.simantics.objmap.structural.StructuralResource; +import org.simantics.objmap.structural.annotations.TypeRelatedElementsAdd; +import org.simantics.objmap.structural.annotations.TypeRelatedElementsGet; +import org.simantics.objmap.structural.annotations.TypeRelatedElementsRem; +import org.simantics.objmap.structural.rules.domain.RelatedObjectsAccessor; + + +public class TypeRelatedElementsRuleFactory2 implements ICollectionRuleFactory { + + @Override + public IBidirectionalMappingRule create(ReadGraph g, Annotation annotation, + Method getter, Method adder, Method remover) + throws DatabaseException { + TypeRelatedElementsGet getterAnn = (TypeRelatedElementsGet)annotation; + return new MappedElementsRule(new RelatedObjectsAccessor(g.getResource(getterAnn.value()),getterAnn.composition(),true,true,true), + new CollectionAccessor(getter, adder, remover)); + } + + @Override + public boolean isAdder(Annotation getterAnnotation, Annotation annotation) { + TypeRelatedElementsGet getterAnn = (TypeRelatedElementsGet)getterAnnotation; + TypeRelatedElementsAdd adderAnn = (TypeRelatedElementsAdd)annotation; + return getterAnn.value().equals(adderAnn.value()); + } + + @Override + public boolean isRemover(Annotation getterAnnotation, Annotation annotation) { + TypeRelatedElementsGet getterAnn = (TypeRelatedElementsGet)getterAnnotation; + TypeRelatedElementsRem adderAnn = (TypeRelatedElementsRem)annotation; + return getterAnn.value().equals(adderAnn.value()); + } + +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/TypeRelatedGetSetObjRuleFactory.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/TypeRelatedGetSetObjRuleFactory.java new file mode 100644 index 00000000..44dfffd7 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/TypeRelatedGetSetObjRuleFactory.java @@ -0,0 +1,44 @@ +package org.simantics.objmap.structural.annotations.factories; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; + +import org.simantics.db.ReadGraph; +import org.simantics.db.exception.DatabaseException; +import org.simantics.objmap.bidirectional.IBidirectionalMappingRule; +import org.simantics.objmap.graph.rules.MappedElementRule; +import org.simantics.objmap.graph.rules.factory.IGetSetRuleFactory; +import org.simantics.objmap.graph.rules.range.GetSetObjectAccessor; +import org.simantics.objmap.structural.StructuralResource; +import org.simantics.objmap.structural.annotations.TypeRelatedGetObj; +import org.simantics.objmap.structural.annotations.TypeRelatedSetObj; +import org.simantics.objmap.structural.rules.domain.RelatedObjectAccessor; + + +/** + * Rule factory for mapped object using Getter/Setter-methods. + * + * @author Marko Luukkainen + * + */ +public class TypeRelatedGetSetObjRuleFactory implements IGetSetRuleFactory { + + @Override + public IBidirectionalMappingRule create(ReadGraph g, Annotation annotation, + Method getter, Method setter) + throws DatabaseException { + TypeRelatedGetObj getterAnn = (TypeRelatedGetObj)annotation; + return new MappedElementRule(new RelatedObjectAccessor(g.getResource(getterAnn.value()),true,true,true), + new GetSetObjectAccessor(getter, setter)); + } + + @Override + public boolean isSetter(Annotation getterAnnotation, Annotation annotation) { + TypeRelatedGetObj getterAnn = (TypeRelatedGetObj)getterAnnotation; + TypeRelatedSetObj setterAnn = (TypeRelatedSetObj)annotation; + return getterAnn.value().equals(setterAnn.value()); + } + + + +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/TypeRelatedGetSetValueRuleFactory.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/TypeRelatedGetSetValueRuleFactory.java new file mode 100644 index 00000000..05dd6783 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/TypeRelatedGetSetValueRuleFactory.java @@ -0,0 +1,101 @@ +package org.simantics.objmap.structural.annotations.factories; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; + +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.exception.DatabaseException; +import org.simantics.layer0.Layer0; +import org.simantics.objmap.bidirectional.IBidirectionalMappingRule; +import org.simantics.objmap.graph.rules.ValueRule; +import org.simantics.objmap.graph.rules.adapters.IdentityAdapter; +import org.simantics.objmap.graph.rules.adapters.ValueAdapter; +import org.simantics.objmap.graph.rules.factory.IGetSetRuleFactory; +import org.simantics.objmap.graph.rules.range.AdaptedRangeAccessor; +import org.simantics.objmap.graph.rules.range.GetSetValueAccessor; +import org.simantics.objmap.graph.rules.range.IRangeAccessor; +import org.simantics.objmap.structural.StructuralResource; +import org.simantics.objmap.structural.annotations.TypeRelatedGetValue; +import org.simantics.objmap.structural.annotations.TypeRelatedSetValue; +import org.simantics.objmap.structural.rules.domain.RelatedValueAccessor; + +/** + * Rule factory for mapped value using Getter/Setter-methods. + * + * @author Marko Luukkainen + * + */ +public class TypeRelatedGetSetValueRuleFactory implements IGetSetRuleFactory { + + @Override + public IBidirectionalMappingRule create(ReadGraph g, Annotation annotation, + Method getter, Method setter) + throws DatabaseException { + TypeRelatedGetValue getterAnn = (TypeRelatedGetValue)annotation; + + Class adapterClass = getterAnn.adapter(); + IRangeAccessor rangeAccessor = new GetSetValueAccessor(getter, setter); + Resource valueType; + if (adapterClass == IdentityAdapter.class) { + valueType = dataTypeOfClass(g, getter.getReturnType()); + } else { + try{ + ValueAdapter adapter = adapterClass.newInstance(); + rangeAccessor = new AdaptedRangeAccessor(rangeAccessor, adapter); + valueType = adapter.rangeTypeToDomainType(g, getter.getReturnType()); + } catch (InstantiationException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + return new ValueRule(new RelatedValueAccessor(g.getResource(getterAnn.value()), valueType,true,true,true), + rangeAccessor); + } + + @Override + public boolean isSetter(Annotation getterAnnotation, Annotation annotation) { + TypeRelatedGetValue getterAnn = (TypeRelatedGetValue)getterAnnotation; + TypeRelatedSetValue setterAnn = (TypeRelatedSetValue)annotation; + return getterAnn.value().equals(setterAnn.value()); + } + + public static Resource dataTypeOfClass(ReadGraph g, Class clazz) { + Layer0 b = Layer0.getInstance(g); + if(clazz.equals(Double.class) || clazz.equals(double.class)) + return b.Double; + else if(clazz.equals(String.class)) + return b.String; + else if(clazz.equals(Integer.class) || clazz.equals(int.class)) + return b.Integer; + else if(clazz.equals(Float.class) || clazz.equals(float.class)) + return b.Float; + else if(clazz.equals(Boolean.class) || clazz.equals(boolean.class)) + return b.Boolean; + else if(clazz.equals(Long.class) || clazz.equals(long.class)) + return b.Long; + else if(clazz.equals(Byte.class) || clazz.equals(byte.class)) + return b.Byte; + + else if(clazz.equals(double[].class)) + return b.DoubleArray; + else if(clazz.equals(int[].class)) + return b.IntegerArray; + else if(clazz.equals(byte[].class)) + return b.ByteArray; + else if(clazz.equals(float[].class)) + return b.FloatArray; + else if(clazz.equals(boolean[].class)) + return b.BooleanArray; + else if(clazz.equals(String[].class)) + return b.StringArray; + else if(clazz.equals(long[].class)) + return b.LongArray; + else { + System.out.println("Couldn't find a data type for " + clazz); + return null; + } + } + +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/UpdateMethodFactory.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/UpdateMethodFactory.java new file mode 100644 index 00000000..690e0061 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/UpdateMethodFactory.java @@ -0,0 +1,70 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.structural.annotations.factories; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; + +import org.apache.log4j.Logger; +import org.simantics.db.ReadGraph; +import org.simantics.db.WriteGraph; +import org.simantics.db.exception.DatabaseException; +import org.simantics.objmap.backward.IBackwardMapping; +import org.simantics.objmap.bidirectional.IBidirectionalMappingRule; +import org.simantics.objmap.exceptions.MappingException; +import org.simantics.objmap.forward.IForwardMapping; +import org.simantics.objmap.graph.rules.factory.IMethodRuleFactory; + +public class UpdateMethodFactory implements IMethodRuleFactory { + + static Logger LOGGER = Logger.getLogger("org.simantics.objmap"); + + @Override + public IBidirectionalMappingRule create(ReadGraph g, + Annotation annotation, + final Method method) + throws DatabaseException { + method.setAccessible(true); + return new IBidirectionalMappingRule() { + + @Override + public boolean updateRange(ReadGraph g, IForwardMapping map, + Domain domainElement, Range rangeElement) + throws MappingException { + LOGGER.info(" UpdateMethodFactory.updateRange"); + try { + return (Boolean)method.invoke(rangeElement, g, domainElement); + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return false; + } + + @Override + public boolean updateDomain(WriteGraph g, IBackwardMapping map, + Domain domainElement, Range rangeElement) + throws MappingException { + return false; + } + + public void createDomain(WriteGraph g, IBackwardMapping map, Domain domainElement, Range rangeElement) throws MappingException { + updateDomain(g, map, domainElement, rangeElement); + }; + + public void createRange(ReadGraph g, IForwardMapping map, Domain domainElement, Range rangeElement) throws MappingException { + updateRange(g, map, domainElement, rangeElement); + }; + }; + } + +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/rules/domain/RelatedObjectAccessor.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/rules/domain/RelatedObjectAccessor.java new file mode 100644 index 00000000..5cf862fc --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/structural/rules/domain/RelatedObjectAccessor.java @@ -0,0 +1,111 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.structural.rules.domain; + +import org.apache.log4j.Logger; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.WriteGraph; +import org.simantics.db.exception.DatabaseException; +import org.simantics.objmap.exceptions.MappingException; +import org.simantics.objmap.graph.rules.domain.IDomainAccessor; +import org.simantics.objmap.structural.StructuralResource; + + +public class RelatedObjectAccessor implements IDomainAccessor { + + static Logger LOGGER = Logger.getLogger("org.simantics.objmap"); + + Resource relation; + boolean useTypeResource; + + private boolean preventStructuralChanges = true; + private boolean preventStructuralRootChanges = true; + + public RelatedObjectAccessor(Resource relation, boolean useTypeResource) { + this.relation = relation; + this.useTypeResource = useTypeResource; + } + + public RelatedObjectAccessor(Resource relation, boolean useTypeResource, boolean preventStructuralChanges, boolean preventStructuralRootChanges) { + this.relation = relation; + this.useTypeResource = useTypeResource; + this.preventStructuralChanges = preventStructuralChanges; + this.preventStructuralRootChanges = preventStructuralRootChanges; + } + + private boolean preventChange(StructuralResource element) { + return preventStructuralChanges && element.isStructural() && (!element.isStructuralRoot()||preventStructuralRootChanges); + } + + @Override + public StructuralResource get(ReadGraph g, StructuralResource element) throws MappingException { + try { + LOGGER.info(" RelatedObjectAccessor.get"); + Resource res = getServiceResource(g, element); + if (res == null) + return null; + Resource r = g.getPossibleObject(res, relation); + if (r == null) + return null; + if (StructuralUtils.isStructuralInstance(g, r)) { + return new StructuralResource(g, r, element.getContext(),r); + } else { + return new StructuralResource(g, r, element.getContext()); + } + } catch (DatabaseException e) { + throw new MappingException(e); + } + } + + @Override + public boolean set(WriteGraph g, StructuralResource selement, StructuralResource value) + throws MappingException { + try { + LOGGER.info(" RelatedObjectAccessor.set"); + Resource element = getServiceResource(g, selement); + if (element == null) + return false; + Resource resource = g.getPossibleObject(element, relation); + if(resource == null) { + if(value == null) + return false; + if (preventChange(selement)) + return false; + g.claim(element, relation, value.getResource()); + return true; + } + else if(resource.equals(value)) + return false; + else { + if (preventChange(selement)) + return false; + g.deny(element, relation); + if(value != null) + g.claim(element, relation, value.getResource()); + return true; + } + } catch (DatabaseException e) { + throw new MappingException(e); + } + + } + + + + private Resource getServiceResource(ReadGraph g, StructuralResource element) { + if(!useTypeResource) + return element.getResource(); + return element.getTypeResource(); + } + +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/rules/domain/RelatedObjectsAccessor.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/rules/domain/RelatedObjectsAccessor.java new file mode 100644 index 00000000..02895649 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/structural/rules/domain/RelatedObjectsAccessor.java @@ -0,0 +1,113 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.structural.rules.domain; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import org.apache.log4j.Logger; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.WriteGraph; +import org.simantics.db.exception.DatabaseException; +import org.simantics.objmap.exceptions.MappingException; +import org.simantics.objmap.graph.rules.domain.IDomainAccessor; +import org.simantics.objmap.graph.rules.domain.MappingUtils; +import org.simantics.objmap.structural.StructuralResource; + + +public class RelatedObjectsAccessor implements IDomainAccessor> { + + static Logger LOGGER = Logger.getLogger("org.simantics.objmap"); + + Resource relation; + boolean deleteExtraObjects; + boolean useTypeResource; + + private boolean preventStructuralChanges = true; + private boolean preventStructuralRootChanges = true; + + public RelatedObjectsAccessor(Resource relation, boolean deleteExtraObjects, boolean useTypeResource) { + super(); + this.relation = relation; + this.deleteExtraObjects = deleteExtraObjects; + this.useTypeResource = useTypeResource; + } + + public RelatedObjectsAccessor(Resource relation, boolean deleteExtraObjects, boolean useTypeResource, boolean preventStructuralChanges, boolean preventStructuralRootChanges) { + super(); + this.relation = relation; + this.deleteExtraObjects = deleteExtraObjects; + this.useTypeResource = useTypeResource; + this.preventStructuralChanges = preventStructuralChanges; + this.preventStructuralRootChanges = preventStructuralRootChanges; + } + + @Override + public Collection get(ReadGraph g, StructuralResource element) throws MappingException { + try { + LOGGER.info(" RelatedObjectsAccessor.get"); + + + Resource res = getServiceResource(g, element); + if (res == null) + return Collections.EMPTY_LIST; + Collection coll = g.getObjects(res, relation); + List result = new ArrayList(coll.size()); + for (Resource r : coll) { + if (StructuralUtils.isStructuralInstance(g, r)) { + result.add(new StructuralResource(g, r, element.getContext(),r)); + } else { + result.add(new StructuralResource(g, r, element.getContext())); + } + } + return result; + } catch (DatabaseException e) { + throw new MappingException(e); + } + } + + private boolean preventChange(StructuralResource element) { + return preventStructuralChanges && element.isStructural() && (!element.isStructuralRoot()||preventStructuralRootChanges); + } + + @Override + public boolean set(WriteGraph g, StructuralResource element, Collection value) + throws MappingException { + try { + LOGGER.info(" RelatedObjectsAccessor.set"); + Resource res = getServiceResource(g, element); + if (res == null) + return false; + if (preventChange(element)) + return false; + Resource[] arr = new Resource[value.size()]; + int i = 0; + for (StructuralResource sr : value) { + arr[i++] = sr.getResource(); + } + return MappingUtils.synchronizeStatements(g, res, relation, + arr, deleteExtraObjects); + } catch (DatabaseException e) { + throw new MappingException(e); + } + + } + + private Resource getServiceResource(ReadGraph g, StructuralResource element) { + if (!useTypeResource) + return element.getResource(); + return element.getTypeResource(); + } +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/rules/domain/RelatedOrderedSetElementsAccessor.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/rules/domain/RelatedOrderedSetElementsAccessor.java new file mode 100644 index 00000000..654a3258 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/structural/rules/domain/RelatedOrderedSetElementsAccessor.java @@ -0,0 +1,86 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.structural.rules.domain; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import org.apache.log4j.Logger; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.WriteGraph; +import org.simantics.db.common.utils.OrderedSetUtils; +import org.simantics.db.exception.DatabaseException; +import org.simantics.objmap.exceptions.MappingException; +import org.simantics.objmap.graph.rules.domain.IDomainAccessor; +import org.simantics.objmap.structural.StructuralResource; + +public class RelatedOrderedSetElementsAccessor implements IDomainAccessor> { + + static Logger LOGGER = Logger.getLogger("org.simantics.objmap"); + + boolean deleteExtraObjects; + boolean useTypeResource; + + public RelatedOrderedSetElementsAccessor(boolean deleteExtraObjects, boolean useTypeResource) { + super(); + this.deleteExtraObjects = deleteExtraObjects; + this.useTypeResource = useTypeResource; + } + + @Override + public Collection get(ReadGraph g, StructuralResource element) throws MappingException { + try { + LOGGER.info(" RelatedOrderedSetElementsAccessor.get"); + Resource res = getServiceResource(g, element); + if (res == null) + return Collections.EMPTY_LIST; + List list = OrderedSetUtils.toList(g, res); + List result = new ArrayList(list.size()); + for (Resource r : list) { + result.add(new StructuralResource(g,r,element.getContext())); + } + return result; + } catch (DatabaseException e) { + throw new MappingException(e); + } + } + + @Override + public boolean set(WriteGraph g, StructuralResource element, Collection value) + throws MappingException { + try { + LOGGER.info(" RelatedOrderedSetElementsAccessor.set"); + Resource res = getServiceResource(g, element); + if (res == null) + return false; + List list = new ArrayList(value.size()); + for (StructuralResource r : value) { + list.add(r.getResource()); + } + return OrderedSetUtils.set(g, res, list); + // FIXME Implement deleteExtraObjects + } catch (DatabaseException e) { + throw new MappingException(e); + } + + } + + private Resource getServiceResource(ReadGraph g, StructuralResource element) { + if (!useTypeResource) + return element.getResource(); + return element.getTypeResource(); + } + +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/rules/domain/RelatedValueAccessor.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/rules/domain/RelatedValueAccessor.java new file mode 100644 index 00000000..0c152c1b --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/structural/rules/domain/RelatedValueAccessor.java @@ -0,0 +1,150 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.structural.rules.domain; + +import java.util.Arrays; + +import org.apache.log4j.Logger; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.Statement; +import org.simantics.db.WriteGraph; +import org.simantics.db.exception.DatabaseException; +import org.simantics.layer0.Layer0; +import org.simantics.objmap.exceptions.MappingException; +import org.simantics.objmap.graph.rules.domain.IDomainAccessor; +import org.simantics.objmap.structural.StructuralResource; + + +public class RelatedValueAccessor implements IDomainAccessor { + + static Logger LOGGER = Logger.getLogger("org.simantics.objmap"); + + Resource relation; + Resource valueType; + boolean useTypeResource; + + private boolean preventStructuralChanges = true; + private boolean preventStructuralRootChanges = true; + + public RelatedValueAccessor(Resource relation, Resource valueType, boolean useTypeResource) { + this.relation = relation; + this.valueType = valueType; + this.useTypeResource = useTypeResource; + } + + public RelatedValueAccessor(Resource relation, Resource valueType, boolean useTypeResource, boolean preventStructuralChanges, boolean preventStructuralRootChanges) { + this.relation = relation; + this.valueType = valueType; + this.useTypeResource = useTypeResource; + this.preventStructuralChanges = preventStructuralChanges; + this.preventStructuralRootChanges = preventStructuralRootChanges; + } + + private boolean preventChange(StructuralResource element) { + return preventStructuralChanges && element.isStructural() && (!element.isStructuralRoot()||preventStructuralRootChanges); + } + + @Override + public Object get(ReadGraph g, StructuralResource element) throws MappingException { + try { + LOGGER.info(" RelatedValueAccessor.get"); + Resource res = getServiceResource(g, element); + if (res == null) + return null; + Resource valueResource = g.getPossibleObject(res, relation); + if(valueResource == null) + return null; + return g.getValue(valueResource); + } catch (DatabaseException e) { + throw new MappingException(e); + } + } + + @Override + public boolean set(WriteGraph g, StructuralResource relement, Object value) + throws MappingException { + try { + LOGGER.info(" RelatedValueAccessor.set"); + + Resource element = getServiceResource(g, relement); + if (element == null) + return false; + Statement valueStatement = g.getPossibleStatement(element, relation); + if(valueStatement == null) { + if(value == null) + return false; + if (preventChange(relement)) + return false; + Resource valueResource = g.newResource(); + g.claim(valueResource, Layer0.getInstance(g).InstanceOf, null, + valueType); + g.claim(element, relation, valueResource); + g.claimValue(valueResource, value); + return true; + } + else { + if(value == null) { + if (preventChange(relement)) + return false; + if (!valueStatement.isAsserted(element)) { + g.deny(valueStatement.getObject()); + return true; + } else { + return false; + } + + } + Object currentValue = g.getValue(valueStatement.getObject()); + if(equals(currentValue,value)) + return false; + if (preventChange(relement)) + return false; + if (!valueStatement.isAsserted(element)) + g.claimValue(valueStatement.getObject(), value); + else { + Resource valueResource = g.newResource(); + g.claim(valueResource, Layer0.getInstance(g).InstanceOf, null, + valueType); + g.claim(element, relation, valueResource); + g.claimValue(valueResource, value); + } + return true; + } + } catch (DatabaseException e) { + throw new MappingException(e); + } + + } + + private Resource getServiceResource(ReadGraph g, StructuralResource element) { + if (!useTypeResource) + return element.getResource(); + return element.getTypeResource(); + } + + private boolean equals(Object o1, Object o2) { + if (o1 instanceof boolean[]) + Arrays.equals((boolean[])o1,(boolean[])o2); + if (o1 instanceof int[]) + Arrays.equals((int[])o1,(int[])o2); + if (o1 instanceof float[]) + Arrays.equals((float[])o1,(float[])o2); + if (o1 instanceof double[]) + Arrays.equals((double[])o1,(double[])o2); + if (o1 instanceof byte[]) + Arrays.equals((byte[])o1,(byte[])o2); + return o1.equals(o2); + + } + +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/rules/domain/StructuralRelatedObjectAccessor.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/rules/domain/StructuralRelatedObjectAccessor.java new file mode 100644 index 00000000..5148360f --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/structural/rules/domain/StructuralRelatedObjectAccessor.java @@ -0,0 +1,131 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.structural.rules.domain; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.WriteGraph; +import org.simantics.db.exception.DatabaseException; +import org.simantics.objmap.exceptions.MappingException; +import org.simantics.objmap.graph.rules.domain.IDomainAccessor; +import org.simantics.objmap.structural.StructuralResource; + + +public class StructuralRelatedObjectAccessor implements IDomainAccessor { + + static Logger LOGGER = Logger.getLogger("org.simantics.objmap"); + + Resource relation; + boolean useTypeResource; + + private boolean preventStructuralChanges = true; + private boolean preventStructuralRootChanges = true; + + public StructuralRelatedObjectAccessor(Resource relation, boolean useTypeResource) { + this.relation = relation; + this.useTypeResource = useTypeResource; + } + + public StructuralRelatedObjectAccessor(Resource relation, boolean useTypeResource, boolean preventStructuralChanges, boolean preventStructuralRootChanges) { + this.relation = relation; + this.useTypeResource = useTypeResource; + this.preventStructuralChanges = preventStructuralChanges; + this.preventStructuralRootChanges = preventStructuralRootChanges; + } + + private boolean preventChange(StructuralResource element) { + return preventStructuralChanges && element.isStructural() && (!element.isStructuralRoot()||preventStructuralRootChanges); + } + + @Override + public StructuralResource get(ReadGraph g, StructuralResource element) throws MappingException { + try { + + LOGGER.info(" RelatedObjectAccessor.get"); + + if (!element.isStructural()) + return null; + Resource instance = StructuralUtils.getContainingInstance(element); + + Resource publicRelation = StructuralUtils.getPublishedRelation(g, element, relation); + + if (publicRelation == null) + return null; + Resource r = g.getPossibleObject(instance, publicRelation); + if (r == null) + return null; + List context = new ArrayList(); + for (int i = 0; i < element.getContext().size()-1; i++) + context.add(element.getContext().get(i)); + if (StructuralUtils.isStructuralInstance(g, r)) { + return new StructuralResource(g, r, context,r); + } else { + return new StructuralResource(g, r, context); + } + } catch (DatabaseException e) { + throw new MappingException(e); + } + } + + @Override + public boolean set(WriteGraph g, StructuralResource element, StructuralResource value) + throws MappingException { + try { + LOGGER.info(" RelatedObjectAccessor.set"); + Resource instance = StructuralUtils.getContainingInstance(element); + Resource publicRelation = null; + if (instance == null) + return false; + publicRelation = StructuralUtils.getPublishedRelation(g, element, relation); + if (value == null) { + if (publicRelation == null) + return false; + if (preventChange(element)) + return false; + g.deny(instance, publicRelation); + return true; + } else { + if (publicRelation == null) { + if (preventChange(element)) + return false; + publicRelation = StructuralUtils.getOrCreatePublishedRelation(g, element, relation); + g.claim(instance, publicRelation, value.getResource()); + return true; + } else { + Resource r = g.getPossibleObject(instance, publicRelation); + if (r == null) { + if (preventChange(element)) + return false; + g.claim(instance, publicRelation, value.getResource()); + return true; + } else { + if (r.equals(value.getResource())) + return false; + if (preventChange(element)) + return false; + g.deny(instance, publicRelation); + g.claim(instance, publicRelation, value.getResource()); + return true; + } + } + } + } catch (DatabaseException e) { + throw new MappingException(e); + } + + } + +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/rules/domain/StructuralRelatedObjectsAccessor.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/rules/domain/StructuralRelatedObjectsAccessor.java new file mode 100644 index 00000000..5b32a983 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/structural/rules/domain/StructuralRelatedObjectsAccessor.java @@ -0,0 +1,118 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.structural.rules.domain; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import org.apache.log4j.Logger; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.WriteGraph; +import org.simantics.db.exception.DatabaseException; +import org.simantics.layer0.Layer0; +import org.simantics.objmap.exceptions.MappingException; +import org.simantics.objmap.graph.rules.domain.IDomainAccessor; +import org.simantics.objmap.graph.rules.domain.MappingUtils; +import org.simantics.objmap.structural.StructuralResource; +import org.simantics.structural.stubs.StructuralResource2; + + +public class StructuralRelatedObjectsAccessor implements IDomainAccessor> { + + static Logger LOGGER = Logger.getLogger("org.simantics.objmap"); + + Resource relation; + boolean deleteExtraObjects; + + public StructuralRelatedObjectsAccessor(Resource relation, boolean deleteExtraObjects) { + super(); + this.relation = relation; + this.deleteExtraObjects = deleteExtraObjects; + } + + @Override + public Collection get(ReadGraph g, StructuralResource element) throws MappingException { + try { + LOGGER.info(" RelatedObjectsAccessor.get"); + + if (!element.isStructural()) + return Collections.EMPTY_LIST; + + // Structural instance + Resource instance = StructuralUtils.getContainingInstance(element); + + Resource publicRelation = StructuralUtils.getPublishedRelation(g, element, relation); + + if (publicRelation == null) + return Collections.EMPTY_LIST; + + Collection coll = g.getObjects(instance, publicRelation); + List result = new ArrayList(coll.size()); + List context = new ArrayList(); + for (int i = 0; i < element.getContext().size()-1; i++) + context.add(element.getContext().get(i)); + for (Resource r : coll) { + if (StructuralUtils.isStructuralInstance(g, r)) { + result.add(new StructuralResource(g, r, context,r)); + } else { + result.add(new StructuralResource(g, r, context)); + } + } + return result; + } catch (DatabaseException e) { + throw new MappingException(e); + } + } + + @Override + public boolean set(WriteGraph g, StructuralResource element, Collection value) + throws MappingException { + try { + LOGGER.info(" RelatedObjectsAccessor.set"); + + if (!element.isStructural()) + return false; + + Resource instance = StructuralUtils.getContainingInstance(element); + Resource publicRelation = null; + if (value.size() == 0) { + publicRelation = StructuralUtils.getPublishedRelation(g, element, relation); + if (publicRelation == null) + return false; + else { + return MappingUtils.synchronizeStatements(g, instance, publicRelation, new Resource[0], deleteExtraObjects); + } + } else { + publicRelation = StructuralUtils.getOrCreatePublishedRelation(g, element, relation); + if (publicRelation == null) + throw new MappingException("Structural Resource " + element + " cannot contain structural elements, the Resource is not published."); + Resource[] arr = new Resource[value.size()]; + int i = 0; + for (StructuralResource sr : value) { + arr[i++] = sr.getResource(); + } + return MappingUtils.synchronizeStatements(g, instance, publicRelation, arr, deleteExtraObjects); + } + + + + } catch (DatabaseException e) { + throw new MappingException(e); + } + + } + + +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/rules/domain/StructuralUtils.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/rules/domain/StructuralUtils.java new file mode 100644 index 00000000..c4ba7048 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/structural/rules/domain/StructuralUtils.java @@ -0,0 +1,105 @@ +package org.simantics.objmap.structural.rules.domain; + +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.WriteGraph; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.exception.NoSingleResultException; +import org.simantics.layer0.Layer0; +import org.simantics.objmap.structural.StructuralResource; +import org.simantics.structural.stubs.StructuralResource2; + +public class StructuralUtils { + + + public static boolean isStructuralInstance(ReadGraph g, Resource r) throws DatabaseException { + StructuralResource2 sr = StructuralResource2.getInstance(g); + if (g.isInstanceOf(r, sr.Component)) { + Resource type = g.getSingleType(r); + return g.isInstanceOf(type, sr.Component); + } + return false; + + } + + public static Resource getContainingInstance(StructuralResource element) { + if (!element.isStructural()) + return null; + Resource instance = element.getContext().get(element.getContext().size()-1); + return instance; + } + + public static Resource getPublishedRelation(ReadGraph g, StructuralResource element, Resource relation) throws DatabaseException{ + Resource instance = getContainingInstance(element); + if (instance == null) + return null; + + Layer0 l0 = Layer0.getInstance(g); + StructuralResource2 sr = StructuralResource2.getInstance(g); + + Resource type = null; + try { + type = g.getSingleType(instance); + } catch (NoSingleResultException e) { + + } + if (type == null) + return null; + + boolean elementPublished = false; + Resource publicRelation = null; + for (Resource r : g.getObjects(type, l0.DomainOf)) { + if (r.equals(element.getResource())) + elementPublished = true; + if (g.isInstanceOf(r, relation)) { + if (element.getResource().equals(g.getPossibleObject(r, sr.IsBoundBy))) + publicRelation = r; + } + } + if (!elementPublished) + return null; + return publicRelation; + } + + public static Resource getOrCreatePublishedRelation(WriteGraph g, StructuralResource element, Resource relation) throws DatabaseException{ + Resource instance = getContainingInstance(element); + if (instance == null) + return null; + + Layer0 l0 = Layer0.getInstance(g); + StructuralResource2 sr = StructuralResource2.getInstance(g); + + Resource type = g.getSingleType(instance); + + boolean elementPublished = false; + Resource publicRelation = null; + for (Resource r : g.getObjects(type, l0.DomainOf)) { + if (r.equals(element.getResource())) + elementPublished = true; + if (g.isInstanceOf(r, relation)) { + if (element.getResource().equals(g.getPossibleObject(r, sr.IsBoundBy))) + publicRelation = r; + } + } + if (!elementPublished) + return null; + if (publicRelation != null) + return publicRelation; + + publicRelation = g.newResource(); + // TODO: type ConsistsOf publicRelation, publicRelation ConsistsOf publicInverse ? + g.claim(publicRelation, l0.SubrelationOf, l0.IsRelatedTo); + g.claim(publicRelation, l0.InstanceOf, relation); + g.claim(publicRelation, sr.IsBoundBy, element.getResource()); + g.claim(type, l0.DomainOf, publicRelation); + g.claimLiteral(publicRelation, l0.HasName, g.getRelatedValue(element.getResource(), l0.HasName) +"_" + g.getRelatedValue(relation, l0.HasName)); + Resource inverse = g.getPossibleInverse(relation); + if (inverse != null) { + Resource publicInverse = g.newResource(); + g.claim(publicInverse, l0.SubrelationOf, inverse); + g.claim(publicRelation, l0.InverseOf, publicInverse); + } + return publicRelation; + + } +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/schema/AdaptedLinkType.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/schema/AdaptedLinkType.java new file mode 100644 index 00000000..9981a73c --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/structural/schema/AdaptedLinkType.java @@ -0,0 +1,79 @@ +package org.simantics.objmap.structural.schema; + +//import org.apache.log4j.Logger; +import org.eclipse.core.runtime.IAdaptable; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.WriteGraph; +import org.simantics.db.exception.DatabaseException; +import org.simantics.objmap.backward.IBackwardMapping; +import org.simantics.objmap.exceptions.MappingException; +import org.simantics.objmap.forward.IForwardMapping; +import org.simantics.objmap.graph.schema.ILinkType; +import org.simantics.objmap.structural.IStructuralObject; +import org.simantics.objmap.structural.StructuralResource; + +/** + * A link type that is associated with adaptable resource (ReadGraph.getAdapter(Resource,Class)). + * The adapted object must implement IAdaptable interface for returning the original Resource. + * + * @author Marko Luukkainen + * + */ +public class AdaptedLinkType implements ILinkType { + + + //static Logger LOGGER = Logger.getLogger("org.simantics.objmap"); + + Resource domainType; + Class rangeType; + + + public AdaptedLinkType(Resource domainType, Class rangeType) { + this.domainType = domainType; + this.rangeType = rangeType; + } + + @Override + public StructuralResource createDomainElement(WriteGraph g, IStructuralObject rangeElement) + throws MappingException { + try { + IAdaptable adaptable = (IAdaptable)rangeElement; + Resource res = (Resource)adaptable.getAdapter(Resource.class); + if (res == null) + throw new NullPointerException(); + return new StructuralResource(g,res); + } catch (Exception e) { + throw new MappingException("Adapted object must implement IAdaptable interface to return the source Resource.", e); + } + + } + + + @Override + public IStructuralObject createRangeElement(ReadGraph g, StructuralResource domainElement) + throws MappingException { + try { + // FIXME : this will not work, we cannot assume that adapted objects would implement IStructuralObject interface. + return (IStructuralObject)g.adapt(domainElement.getResource(), rangeType); + } catch (DatabaseException e) { + throw new MappingException(e); + } + } + + public void createDomain(WriteGraph graph, IBackwardMapping mapping, StructuralResource domainElement, IStructuralObject rangeElement) throws MappingException { + + }; + + public void createRange(ReadGraph graph, org.simantics.objmap.forward.IForwardMapping mapping, StructuralResource domainElement, IStructuralObject rangeElement) throws MappingException { + + }; + + public boolean updateDomain(WriteGraph g, IBackwardMapping map, StructuralResource domainElement, IStructuralObject rangeElement) throws MappingException { + return false; + } + + public boolean updateRange(ReadGraph g, IForwardMapping map, StructuralResource domainElement, IStructuralObject rangeElement) throws MappingException { + return false; + } +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/schema/DefaultSchema.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/schema/DefaultSchema.java new file mode 100644 index 00000000..d0fa8057 --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/structural/schema/DefaultSchema.java @@ -0,0 +1,123 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.structural.schema; + + + +import java.util.Stack; + +import gnu.trove.map.hash.THashMap; + +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.common.utils.NameUtils; +import org.simantics.db.exception.DatabaseException; +import org.simantics.objmap.exceptions.MappingException; +import org.simantics.objmap.graph.schema.ILinkType; +import org.simantics.objmap.graph.schema.IMappingSchema; +import org.simantics.objmap.structural.IStructuralObject; +import org.simantics.objmap.structural.StructuralResource; + + +/** + * + */ +public class DefaultSchema implements IMappingSchema { + + THashMap> domainLinkTypes = + new THashMap>(); + THashMap, ILinkType> rangeLinkTypes = + new THashMap, ILinkType>(); + + public void addLinkType(SimpleLinkType linkType) { + domainLinkTypes.put(linkType.domainType, linkType); + rangeLinkTypes.put(linkType.rangeType, linkType); + } + + public void addLinkType(AdaptedLinkType linkType) { + domainLinkTypes.put(linkType.domainType, linkType); + rangeLinkTypes.put(linkType.rangeType, linkType); + } + + @Override + public ILinkType linkTypeOfDomainElement(ReadGraph g, StructuralResource element) throws MappingException { + try { + + for(Resource type : g.getTypes(element.getResource())) { + + ILinkType linkType = domainLinkTypes.get(type); + if(linkType != null) return linkType; + + } + + throw new MappingException("Didn't find a link type for " + + NameUtils.getSafeName(g, element.getResource()) + "."); + + } catch (DatabaseException e) { + throw new MappingException(e); + } + } + + @Override + public ILinkType linkTypeOfRangeElement(IStructuralObject element) throws MappingException { + ILinkType type = rangeLinkTypes.get(element.getClass()); + if(type == null) { + Stack> clazzes = new Stack>(); + for (Class clazz : element.getClass().getInterfaces()) { + clazzes.add(clazz); + } + clazzes.add(element.getClass().getSuperclass()); + + while (!clazzes.isEmpty()) { + Class clazz = clazzes.pop(); + + type = rangeLinkTypes.get(clazz); + if (type != null) + return type; + for (Class c : clazz.getInterfaces()) + clazzes.add(c); + + } + throw new MappingException("Didn't find a link type for " + element + "."); + } + return type; + } + + + public ILinkType linkTypeOfDomainType(ReadGraph g, Resource type) { + return domainLinkTypes.get(type); + } + + public ILinkType linkTypeOfRangeType(Class clazz) { + ILinkType type = rangeLinkTypes.get(clazz); + if(type == null) { + Stack> clazzes = new Stack>(); + for (Class c : clazz.getInterfaces()) { + clazzes.add(c); + } + clazzes.add(clazz.getSuperclass()); + + while (!clazzes.isEmpty()) { + Class c = clazzes.pop(); + + type = rangeLinkTypes.get(c); + if (type != null) + return type; + for (Class c2 : c.getInterfaces()) + clazzes.add(c2); + + } + + } + return null; + } +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/schema/MappingSchemas.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/schema/MappingSchemas.java new file mode 100644 index 00000000..c656368f --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/structural/schema/MappingSchemas.java @@ -0,0 +1,247 @@ +package org.simantics.objmap.structural.schema; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collection; + +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.exception.DatabaseException; +import org.simantics.objmap.bidirectional.IBidirectionalMappingRule; +import org.simantics.objmap.graph.annotations.GraphType; +import org.simantics.objmap.graph.annotations.HasCollectionAdder; +import org.simantics.objmap.graph.annotations.HasCollectionRemover; +import org.simantics.objmap.graph.annotations.HasSetter; +import org.simantics.objmap.graph.annotations.OptionalRelatedElements; +import org.simantics.objmap.graph.annotations.RelatedElements; +import org.simantics.objmap.graph.annotations.RelatedElementsGet; +import org.simantics.objmap.graph.annotations.RelatedGetObj; +import org.simantics.objmap.graph.annotations.RelatedGetValue; +import org.simantics.objmap.graph.annotations.RelatedOrderedSetElements; +import org.simantics.objmap.graph.annotations.RelatedValue; +import org.simantics.objmap.graph.annotations.UpdateMethod; +import org.simantics.objmap.structural.annotations.StructuralRelatedElementsGet; +import org.simantics.objmap.structural.annotations.StructuralRelatedGetObj; +import org.simantics.objmap.structural.annotations.TypeRelatedElementsGet; +import org.simantics.objmap.structural.annotations.TypeRelatedGetObj; +import org.simantics.objmap.structural.annotations.TypeRelatedGetValue; +import org.simantics.objmap.structural.annotations.factories.OptionalRelatedElementsRuleFactory; +import org.simantics.objmap.structural.annotations.factories.RelatedElementsRuleFactory; +import org.simantics.objmap.structural.annotations.factories.RelatedElementsRuleFactory2; +import org.simantics.objmap.structural.annotations.factories.RelatedGetSetObjRuleFactory; +import org.simantics.objmap.structural.annotations.factories.RelatedGetSetValueRuleFactory; +import org.simantics.objmap.structural.annotations.factories.RelatedOrderedSetElementsRuleFactory; +import org.simantics.objmap.structural.annotations.factories.RelatedValueRuleFactory; +import org.simantics.objmap.structural.annotations.factories.StructuralRelatedElementsRuleFactory2; +import org.simantics.objmap.structural.annotations.factories.StructuralRelatedGetSetObjRuleFactory; +import org.simantics.objmap.structural.annotations.factories.TypeRelatedElementsRuleFactory2; +import org.simantics.objmap.structural.annotations.factories.TypeRelatedGetSetObjRuleFactory; +import org.simantics.objmap.structural.annotations.factories.TypeRelatedGetSetValueRuleFactory; +import org.simantics.objmap.structural.annotations.factories.UpdateMethodFactory; +import org.simantics.objmap.graph.annotations.meta.IsClassRule; +import org.simantics.objmap.graph.annotations.meta.IsCollectionRule; +import org.simantics.objmap.graph.annotations.meta.IsFieldRule; +import org.simantics.objmap.graph.annotations.meta.IsGetSetRule; +import org.simantics.objmap.graph.annotations.meta.IsMethodRule; +import org.simantics.objmap.graph.rules.factory.IClassRuleFactory; +import org.simantics.objmap.graph.rules.factory.ICollectionRuleFactory; +import org.simantics.objmap.graph.rules.factory.IFieldRuleFactory; +import org.simantics.objmap.graph.rules.factory.IGetSetRuleFactory; +import org.simantics.objmap.graph.rules.factory.IMethodRuleFactory; +import org.simantics.objmap.structural.IStructuralObject; +import org.simantics.objmap.structural.StructuralResource; + + +public class MappingSchemas { + /** + * Creates a new SimpleLinkType based on the annotations in the given class. + * @throws IllegalAccessException + * @throws InstantiationException + * @see GraphType + * @see RelatedValue + */ + public static SimpleLinkType fromAnnotations(ReadGraph g, Class clazz) throws DatabaseException, InstantiationException, IllegalAccessException { + GraphType graphType = clazz.getAnnotation(GraphType.class); + + ArrayList> rules = new ArrayList>(); + collectRulesFromAnnotations(g, clazz, rules); + + return new SimpleLinkType( + g.getResource(graphType.value()), + clazz, rules); + } + + public static void collectRulesFromAnnotations(ReadGraph g, Class clazz, Collection> rules) throws DatabaseException, InstantiationException, IllegalAccessException { + Class superclass = clazz.getSuperclass(); + if(superclass != null) + collectRulesFromAnnotations(g, superclass, rules); + + for(Annotation annotation : clazz.getAnnotations()) { + + IsClassRule tag = annotation.annotationType().getAnnotation(IsClassRule.class); + if(tag!= null) { + rules.add(createClassRule(g, annotation, clazz).create(g, annotation, clazz)); + } + } + + for(Field f : clazz.getDeclaredFields()) { + f.setAccessible(true); + + for(Annotation annotation : f.getAnnotations()) { + + IsFieldRule tag = annotation.annotationType().getAnnotation(IsFieldRule.class); + if(tag != null) { + rules.add(createFieldRule(g, annotation, f).create(g, annotation, f)); + } + } + } + + for(Method m : clazz.getDeclaredMethods()) { + m.setAccessible(true); + + for(Annotation annotation : m.getAnnotations()) { + IsMethodRule tag = + annotation.annotationType().getAnnotation(IsMethodRule.class); + if(tag != null) { + rules.add(createMethodRule(g, annotation, m).create(g, annotation, m)); + } + } + } + + for (Method m : clazz.getDeclaredMethods()) { + m.setAccessible(true); + for (Annotation annotation : m.getAnnotations()) { + Class annotationType = annotation.annotationType(); + + IsGetSetRule tag = + annotationType.getAnnotation(IsGetSetRule.class); + if (tag != null) { + + HasSetter setterAnnType = annotationType.getAnnotation(HasSetter.class); + + Class setterAnn = setterAnnType.value(); + + Method getter = m; + + IGetSetRuleFactory ruleFactory = createGetSetRuleFactory(g, annotation, getter); + + + Method setter = null; + + for (Method m2 : clazz.getDeclaredMethods()) { + Annotation set = m2.getAnnotation(setterAnn); + if (set != null && ruleFactory.isSetter(annotation, set)) + setter = m2; + } + + rules.add(ruleFactory.create(g, annotation, getter, setter)); + } + + } + } + + for (Method m : clazz.getDeclaredMethods()) { + m.setAccessible(true); + for (Annotation annotation : m.getAnnotations()) { + Class annotationType = annotation.annotationType(); + + IsCollectionRule tag = + annotationType.getAnnotation(IsCollectionRule.class); + if (tag != null) { + + HasCollectionAdder adderAnnType = annotationType.getAnnotation(HasCollectionAdder.class); + HasCollectionRemover removerAnnType = annotationType.getAnnotation(HasCollectionRemover.class); + + Class adderAnn = adderAnnType.value(); + Class removerAnn = removerAnnType.value(); + + Method getter = m; + + ICollectionRuleFactory ruleFactory = createCollectionRuleFactory(g, annotation, getter); + + + Method adder = null; + Method remover = null; + + for (Method m2 : clazz.getDeclaredMethods()) { + Annotation add = m2.getAnnotation(adderAnn); + Annotation rem = m2.getAnnotation(removerAnn); + if (add != null && ruleFactory.isAdder(annotation, add)) + adder = m2; + if (rem != null && ruleFactory.isRemover(annotation, rem)) + remover = m2; + } + + + + rules.add(ruleFactory.create(g, annotation, getter,adder,remover)); + } + + } + } + } + + public static IClassRuleFactory createClassRule(ReadGraph g, Annotation annotation, Class clazz) { + return null; + } + + public static IFieldRuleFactory createFieldRule(ReadGraph g, Annotation annotation, Field field) { + if (annotation.annotationType().equals(RelatedElements.class)) + return new RelatedElementsRuleFactory(); + if (annotation.annotationType().equals(RelatedValue.class)) + return new RelatedValueRuleFactory(); + if (annotation.annotationType().equals(OptionalRelatedElements.class)) + return new OptionalRelatedElementsRuleFactory(); + if (annotation.annotationType().equals(RelatedOrderedSetElements.class)) + return new RelatedOrderedSetElementsRuleFactory(); + return null; + } + + public static IMethodRuleFactory createMethodRule(ReadGraph g, Annotation annotation, Method m) { + if (annotation.annotationType().equals(UpdateMethod.class)) + return new UpdateMethodFactory(); + return null; + } + + public static IGetSetRuleFactory createGetSetRuleFactory(ReadGraph g, Annotation annotation, Method getter) { + if (annotation.annotationType().equals(RelatedGetValue.class)) + return new RelatedGetSetValueRuleFactory(); + if (annotation.annotationType().equals(RelatedGetObj.class)) + return new RelatedGetSetObjRuleFactory(); + if (annotation.annotationType().equals(TypeRelatedGetValue.class)) + return new TypeRelatedGetSetValueRuleFactory(); + if (annotation.annotationType().equals(TypeRelatedGetObj.class)) + return new TypeRelatedGetSetObjRuleFactory(); + if (annotation.annotationType().equals(StructuralRelatedGetObj.class)) + return new StructuralRelatedGetSetObjRuleFactory(); + return null; + } + + public static ICollectionRuleFactory createCollectionRuleFactory(ReadGraph g, Annotation annotation, Method getter) { + if (annotation.annotationType().equals(RelatedElementsGet.class)) + return new RelatedElementsRuleFactory2(); + if (annotation.annotationType().equals(TypeRelatedElementsGet.class)) + return new TypeRelatedElementsRuleFactory2(); + if (annotation.annotationType().equals(StructuralRelatedElementsGet.class)) + return new StructuralRelatedElementsRuleFactory2(); + return null; + } + + + /** + * Creates a new SimpleLinkType based on the annotations in the given class. + * @throws IllegalAccessException + * @throws InstantiationException + * @see GraphType + * @see RelatedValue + */ + public static AdaptedLinkType fromAdaptable(ReadGraph g, String type, Class clazz) throws DatabaseException, InstantiationException, IllegalAccessException { + + + return new AdaptedLinkType(g.getResource(type), clazz); + } + + +} diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/schema/SimpleLinkType.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/schema/SimpleLinkType.java new file mode 100644 index 00000000..01c0fe0d --- /dev/null +++ b/org.simantics.objmap2/src/org/simantics/objmap/structural/schema/SimpleLinkType.java @@ -0,0 +1,186 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.objmap.structural.schema; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.apache.log4j.Logger; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.WriteGraph; +import org.simantics.db.common.utils.NameUtils; +import org.simantics.db.exception.DatabaseException; +import org.simantics.layer0.Layer0; +import org.simantics.objmap.backward.IBackwardMapping; +import org.simantics.objmap.bidirectional.IBidirectionalMappingRule; +import org.simantics.objmap.exceptions.MappingException; +import org.simantics.objmap.forward.IForwardMapping; +import org.simantics.objmap.graph.schema.ILinkType; +import org.simantics.objmap.structural.IStructuralObject; +import org.simantics.objmap.structural.StructuralResource; + + + +public class SimpleLinkType implements ILinkType { + + static Logger LOGGER = Logger.getLogger("org.simantics.objmap"); + + public Resource domainType; + public Class rangeType; + ArrayList> rules; + + public SimpleLinkType(Resource domainType, Class rangeType, + ArrayList> rules) { + this.domainType = domainType; + this.rangeType = rangeType; + this.rules = rules; + } + + public SimpleLinkType(Resource domainType, Class rangeType) { + this(domainType, rangeType, new ArrayList>()); + } + + /** + * Adds a new rule to this link type that is enforced + * during updates. + */ + public void addRule(IBidirectionalMappingRule rule) { + rules.add(rule); + } + + @Override + public StructuralResource createDomainElement(WriteGraph g, IStructuralObject rangeElement) + throws MappingException { + try { + if(LOGGER.isInfoEnabled()) + LOGGER.info("SimpleLinkType.createDomainElement " + + rangeElement.toString() + ); + if (rangeElement.getContext().size() == 0) { + // there is no context, this not a structural resource / object. + Resource result = g.newResource(); + g.claim(result, Layer0.getInstance(g).InstanceOf, null, domainType); + return new StructuralResource(g,result); + } else { + if (rangeElement.getContext().size() == 1 && rangeElement.getContext().get(0).equals(rangeElement)) { + // Structural object's context is itself, we are instantiating a new structural model. + Resource type = rangeElement.getType(); + Resource result = g.newResource(); + g.claim(result, Layer0.getInstance(g).InstanceOf, null, type); + return new StructuralResource(g,result,result); + } else { + // Structural object's context is not itself, which means that the object is inside of a structural model. + // At the moment we do not support modifying instantiated structural models. + throw new MappingException("Cannot create a new StucturalObject " + rangeElement + " " + rangeElement.getClass()); + } + } + } catch(DatabaseException e) { + throw new MappingException(e); + } + } + @Override + public IStructuralObject createRangeElement(ReadGraph g, StructuralResource domainElement) + throws MappingException { + try { + if(LOGGER.isInfoEnabled()) + try { + LOGGER.info("SimpleLinkType.createRangeElement " + NameUtils.getSafeName(g, domainElement.getResource())); + } catch(DatabaseException e) { + throw new MappingException(e); + } + IStructuralObject result = (IStructuralObject)rangeType.newInstance(); + if (domainElement.getContext().size() == 1) { + if (domainElement.getContext().get(0).equals(domainElement.getResource())) + result.setContext(Collections.singletonList(result)); + else { + //result.setContext(result); + } + } + return result; + } catch (InstantiationException e) { + throw new MappingException(e); + } catch (IllegalAccessException e) { + throw new MappingException(e); + } + } + + @SuppressWarnings("unchecked") + public void createDomain(WriteGraph graph, IBackwardMapping mapping, StructuralResource domainElement, IStructuralObject rangeElement) throws MappingException { + if (domainElement.isStructuralRoot()) + // FIXME: this is nasty, but when a structural model is instantiated by creating new IStructuralObject, its related objects must be read from the graph first, or otherwise the objects would be deleted from the graph. + // as a side effect, if the new IStructuralObject has any properties set, those properties are set to null (because the graph does not contain those values). + // + updateRange(graph, (IForwardMapping)mapping, domainElement, rangeElement); + updateDomain(graph, mapping, domainElement, rangeElement); + }; + + + @Override + public void createRange(ReadGraph graph, IForwardMapping mapping, StructuralResource domainElement, IStructuralObject rangeElement) throws MappingException { + if (rangeElement.getContext().size() == 0 && domainElement.getContext().size() > 0) { + List ctx = new ArrayList(domainElement.getContext().size()); + try { + List context = new ArrayList(); + for (int i = 0; i map, StructuralResource domainElement, IStructuralObject rangeElement) throws MappingException { + if(LOGGER.isInfoEnabled()) + try { + LOGGER.info("SimpleLinkType.updateDomain " + + NameUtils.getSafeName(g, domainElement.getResource()) + " " + + rangeElement.toString() + ); + } catch(DatabaseException e) { + throw new MappingException(e); + } + + boolean updated = false; + for(IBidirectionalMappingRule rule : rules) + updated |= rule.updateDomain(g, map, domainElement, rangeElement); + return updated; + } + + public boolean updateRange(ReadGraph g, IForwardMapping map, StructuralResource domainElement, IStructuralObject rangeElement) throws MappingException { + + if(LOGGER.isInfoEnabled()) + try { + LOGGER.info("SimpleLinkType.updateRange " + + NameUtils.getSafeName(g, domainElement.getResource()) + " " + + rangeElement.toString() + ); + } catch(DatabaseException e) { + throw new MappingException(e); + } + + boolean updated = false; + for(IBidirectionalMappingRule rule : rules) + updated |= rule.updateRange(g, map, domainElement, rangeElement); + return updated; + } +} diff --git a/org.simantics.opencascade.vtk/.classpath b/org.simantics.opencascade.vtk/.classpath new file mode 100644 index 00000000..8a8f1668 --- /dev/null +++ b/org.simantics.opencascade.vtk/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/org.simantics.opencascade.vtk/.project b/org.simantics.opencascade.vtk/.project new file mode 100644 index 00000000..e0986a71 --- /dev/null +++ b/org.simantics.opencascade.vtk/.project @@ -0,0 +1,28 @@ + + + org.simantics.opencascade.vtk + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/org.simantics.opencascade.vtk/.settings/org.eclipse.jdt.core.prefs b/org.simantics.opencascade.vtk/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000..24422af6 --- /dev/null +++ b/org.simantics.opencascade.vtk/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,8 @@ +#Wed Aug 08 16:10:05 EEST 2012 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/org.simantics.opencascade.vtk/META-INF/MANIFEST.MF b/org.simantics.opencascade.vtk/META-INF/MANIFEST.MF new file mode 100644 index 00000000..f9a953f9 --- /dev/null +++ b/org.simantics.opencascade.vtk/META-INF/MANIFEST.MF @@ -0,0 +1,17 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Vtk +Bundle-SymbolicName: org.simantics.opencascade.vtk +Bundle-Version: 1.0.0.qualifier +Bundle-Activator: org.simantics.opencascade.vtk.Activator +Bundle-Vendor: VTT +Require-Bundle: org.eclipse.ui, + org.eclipse.core.runtime, + org.jcae.opencascade;bundle-version="6.5.2", + org.simantics.opencascade;bundle-version="1.0.0", + vtk;bundle-version="5.8.0", + javax.vecmath;bundle-version="1.5.2", + org.simantics.utils.datastructures;bundle-version="1.1.0" +Bundle-RequiredExecutionEnvironment: JavaSE-1.6 +Bundle-ActivationPolicy: lazy +Export-Package: org.simantics.opencascade.vtk diff --git a/org.simantics.opencascade.vtk/build.properties b/org.simantics.opencascade.vtk/build.properties new file mode 100644 index 00000000..41eb6ade --- /dev/null +++ b/org.simantics.opencascade.vtk/build.properties @@ -0,0 +1,4 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + . diff --git a/org.simantics.opencascade.vtk/src/org/simantics/opencascade/vtk/Activator.java b/org.simantics.opencascade.vtk/src/org/simantics/opencascade/vtk/Activator.java new file mode 100644 index 00000000..7c3e13ae --- /dev/null +++ b/org.simantics.opencascade.vtk/src/org/simantics/opencascade/vtk/Activator.java @@ -0,0 +1,50 @@ +package org.simantics.opencascade.vtk; + +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.BundleContext; + +/** + * The activator class controls the plug-in life cycle + */ +public class Activator extends AbstractUIPlugin { + + // The plug-in ID + public static final String PLUGIN_ID = "org.simantics.opencascade.vtk"; //$NON-NLS-1$ + + // The shared instance + private static Activator plugin; + + /** + * The constructor + */ + public Activator() { + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext) + */ + public void start(BundleContext context) throws Exception { + super.start(context); + plugin = this; + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext) + */ + public void stop(BundleContext context) throws Exception { + plugin = null; + super.stop(context); + } + + /** + * Returns the shared instance + * + * @return the shared instance + */ + public static Activator getDefault() { + return plugin; + } + +} diff --git a/org.simantics.opencascade.vtk/src/org/simantics/opencascade/vtk/EdgePointsFilter.java b/org.simantics.opencascade.vtk/src/org/simantics/opencascade/vtk/EdgePointsFilter.java new file mode 100644 index 00000000..e8505d3d --- /dev/null +++ b/org.simantics.opencascade.vtk/src/org/simantics/opencascade/vtk/EdgePointsFilter.java @@ -0,0 +1,97 @@ +package org.simantics.opencascade.vtk; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import javax.vecmath.Point3d; +import javax.vecmath.Vector3d; + +import org.simantics.utils.datastructures.MapList; + +import vtk.vtkCell; +import vtk.vtkIdList; +import vtk.vtkLine; +import vtk.vtkPoints; +import vtk.vtkPolyData; +import vtk.vtkProgrammableFilter; +import vtk.vtkVertex; + +public class EdgePointsFilter extends vtkProgrammableFilter { + vtkPoints outputPoints; + + + public EdgePointsFilter() { + SetExecuteMethod(this, "compute"); + } + + public void compute() { + vtkPolyData polyDataInput = GetPolyDataInput(); + vtkPolyData polyDataOutput = GetPolyDataOutput(); + vtkPoints inputPoints = polyDataInput.GetPoints(); + + outputPoints = new vtkPoints(); + + MapList edgeIndices = new MapList(); + for (int i = 0; i 0) { + vtkLine line = (vtkLine)cell; + int i1 = line.GetPointId(0); + int i2 = line.GetPointId(1); + if (!edgeIndices.contains(i1, i2)) { + edgeIndices.add(i1, i2); + edgeIndices.add(i2, i1); + } + line.Delete(); + } + } + + Set vertices = new HashSet(); + for (Integer i : edgeIndices.getKeys()) { + List edges = edgeIndices.getValues(i); + if (edges.size() != 2) + vertices.add(i); + else { + double tp[] = inputPoints.GetPoint(i); + double ep1[] = inputPoints.GetPoint(edges.get(0)); + double ep2[] = inputPoints.GetPoint(edges.get(1)); + Point3d t = new Point3d(tp); + Vector3d v1 = new Vector3d(ep1); + Vector3d v2 = new Vector3d(ep2); + v1.sub(t); + v2.sub(t); + double angle = Math.PI - v1.angle(v2); + if (angle > Math.PI/6) + vertices.add(i); + } + } + for (int i : vertices) { + outputPoints.InsertNextPoint(inputPoints.GetPoint(i)); + } + polyDataOutput.Allocate(vertices.size(), vertices.size()); + + vtkVertex vertex = new vtkVertex(); + vtkIdList list = vertex.GetPointIds(); + for (int i = 0; i < vertices.size(); i++) { + list.SetId(0, i); + polyDataOutput.InsertNextCell(vertex.GetCellType(), list); + } + + polyDataOutput.SetPoints(outputPoints); + + + list.Delete(); + vertex.Delete(); + + polyDataOutput.Delete(); + polyDataInput.Delete(); + + } + + @Override + public void Delete() { + outputPoints.Delete(); + super.Delete(); + } +} diff --git a/org.simantics.opencascade.vtk/src/org/simantics/opencascade/vtk/VTKOCCTool.java b/org.simantics.opencascade.vtk/src/org/simantics/opencascade/vtk/VTKOCCTool.java new file mode 100644 index 00000000..187c7853 --- /dev/null +++ b/org.simantics.opencascade.vtk/src/org/simantics/opencascade/vtk/VTKOCCTool.java @@ -0,0 +1,709 @@ +package org.simantics.opencascade.vtk; + +import java.util.List; + +import javax.vecmath.Matrix4d; +import javax.vecmath.Point3d; + +import org.jcae.opencascade.jni.BRepMesh_IncrementalMesh; +import org.jcae.opencascade.jni.BRep_Tool; +import org.jcae.opencascade.jni.GP_Trsf; +import org.jcae.opencascade.jni.Poly_Triangulation; +import org.jcae.opencascade.jni.TopAbs_Orientation; +import org.jcae.opencascade.jni.TopAbs_ShapeEnum; +import org.jcae.opencascade.jni.TopExp_Explorer; +import org.jcae.opencascade.jni.TopLoc_Location; +import org.jcae.opencascade.jni.TopoDS_Face; +import org.jcae.opencascade.jni.TopoDS_Shape; +import org.simantics.opencascade.OCCTTool; + +import vtk.vtkActor; +import vtk.vtkAlgorithmOutput; +import vtk.vtkAppendPolyData; +import vtk.vtkAssembly; +import vtk.vtkCleanPolyData; +import vtk.vtkDataSetMapper; +import vtk.vtkFeatureEdges; +import vtk.vtkGlyph3D; +import vtk.vtkIdList; +import vtk.vtkPoints; +import vtk.vtkPolyData; +import vtk.vtkPolyDataMapper; +import vtk.vtkPolyDataNormals; +import vtk.vtkProp; +import vtk.vtkPropCollection; +import vtk.vtkProperty; +import vtk.vtkSphereSource; +import vtk.vtkTriangle; + +public class VTKOCCTool { + public static vtkAssembly vtkTestAssembly() { + vtkAssembly assemblies = new vtkAssembly(); + vtkPolyData partGrid = createTestPartGrid(); + gridToAssembly(assemblies, partGrid); + return assemblies; + } + + public static vtkAssembly vtkOCCShapeToAssembly(TopoDS_Shape shape) { + double deflection = 0.001; + + if (deflection <= 0.0) { + deflection = 0.0005; + System.out.println("Bad value for deflection. Using: " + deflection); + } + + // FIXME : leaks memory! + //BRepTools.clean(shape); + + double mass = OCCTTool.getMass(shape); + + if (mass < 1.0e-12) { + System.out.println("Non 3D-shape detected"); + System.out.println("The cad import features are currently limited to 3D models."); + } + + double length = OCCTTool.getBoundingBoxDiagonal(shape); + deflection *= length; // use relative units + + BRepMesh_IncrementalMesh mesh = new BRepMesh_IncrementalMesh(shape,deflection); + + int faceNumber = 0; + TopExp_Explorer expFace = new TopExp_Explorer(); + + vtkAssembly assemblies = new vtkAssembly(); + for (expFace.init(shape, TopAbs_ShapeEnum.FACE); expFace.more(); expFace.next()) { + TopoDS_Face face = (TopoDS_Face) expFace.current(); + vtkPolyData partGrid = createPartGrid(face); + face.delete(); + if (partGrid == null) + continue; + faceNumber++; + //gridToAssembly(assemblies, partGrid, stlSurfaceData, stlEdgeData); + gridToAssembly(assemblies, partGrid); + + } + expFace.delete(); + mesh.delete(); + + if (faceNumber == 0) { + System.out + .println("Cad import: error: no surface triangulation was generated."); + return null; + } + + return assemblies; + } + + private static void gridToAssembly(vtkAssembly assemblies, vtkPolyData partGrid, vtkAppendPolyData stlSurfaceData, vtkAppendPolyData stlEdgeData) { + + double featureAngle = 30; + + + vtkDataSetMapper partMapper = new vtkDataSetMapper(); + + boolean computeNormals = true; + boolean cleanPart = true; + boolean mergePoints = false; + + vtkCleanPolyData partCleaner = new vtkCleanPolyData(); + if (cleanPart) + { + partCleaner.SetInput(partGrid); + if(mergePoints) { + partCleaner.PointMergingOn(); + } else { + partCleaner.PointMergingOff(); + } + } + + if (computeNormals) + { + vtkPolyDataNormals partNormals = new vtkPolyDataNormals(); + + if (cleanPart) + { + partNormals.SetInputConnection(partCleaner.GetOutputPort()); + } + else partNormals.SetInput(partGrid); + + partNormals.SetFeatureAngle(featureAngle); // this do not have to be neccesarily called + partMapper.SetInputConnection(partNormals.GetOutputPort()); + partNormals.Delete(); + } + else + { + if (cleanPart) partMapper.SetInputConnection(partCleaner.GetOutputPort()); // metoda 2, ne tak pekne, viz http://www.codeguru.com/cpp/g-m/opengl/article.php/c2681 + else partMapper.SetInput(partGrid); // metoda 1, ne tak pekne stinovani, viz: http://www.codeguru.com/cpp/g-m/opengl/article.php/c2681 + } + partMapper.ScalarVisibilityOn(); + + vtkActor partActor = new vtkActor(); + + partActor.SetPickable(1); + partActor.GetProperty().SetColor(1, 1, 0); + partActor.SetMapper(partMapper); + + // EDGES OF PARTS DETECTION + vtkFeatureEdges partEdges = new vtkFeatureEdges(); + if (cleanPart) partEdges.SetInputConnection(partCleaner.GetOutputPort()); + else partEdges.SetInput(partGrid); + partEdges.SetFeatureAngle(featureAngle); // this do not have to be neccesarily called + partEdges.FeatureEdgesOn(); + partEdges.BoundaryEdgesOn(); + partEdges.NonManifoldEdgesOn(); + partEdges.ManifoldEdgesOn(); + + vtkDataSetMapper partEdgesMapper = new vtkDataSetMapper(); + partEdgesMapper.SetInputConnection(partEdges.GetOutputPort()); + partEdgesMapper.SetResolveCoincidentTopologyToPolygonOffset(); + partEdgesMapper.ScalarVisibilityOff(); + + vtkActor partEdgesActor = new vtkActor(); + partEdgesActor.SetPickable(0); + partEdgesActor.GetProperty().SetColor(1, 0, 1); + partEdgesActor.SetMapper(partEdgesMapper); + + + // Add triangles and edges to STL structures: + //-------------------------------------------- + if (cleanPart) stlSurfaceData.AddInput(partCleaner.GetOutput()); + else stlSurfaceData.AddInput(partGrid); + stlEdgeData.AddInput(partEdges.GetOutput()); + + assemblies.AddPart(partActor); + assemblies.AddPart(partEdgesActor); + + // Clean up: + //---------- + partEdgesActor.Delete(); + partEdgesMapper.Delete(); + partEdges.Delete(); + partActor.Delete(); + partMapper.Delete(); + partGrid.Delete(); + partCleaner.Delete(); + } + +public static void gridToAssembly(vtkAssembly assemblies, vtkPolyData partGrid) { + + double featureAngle = 30; + + + vtkDataSetMapper partMapper = new vtkDataSetMapper(); + + boolean computeNormals = true; + boolean cleanPart = false; + boolean mergePoints = false; + + vtkCleanPolyData partCleaner = new vtkCleanPolyData(); + if (cleanPart) + { + partCleaner.SetInput(partGrid); + if(mergePoints) { + partCleaner.PointMergingOn(); + } else { + partCleaner.PointMergingOff(); + } + } + + if (computeNormals) + { + vtkPolyDataNormals partNormals = new vtkPolyDataNormals(); + + if (cleanPart) + { + vtkAlgorithmOutput out = partCleaner.GetOutputPort(); + partNormals.SetInputConnection(out); + out.Delete(); + } + else partNormals.SetInput(partGrid); + + partNormals.SetFeatureAngle(featureAngle); // this do not have to be neccesarily called + vtkAlgorithmOutput out = partNormals.GetOutputPort(); + partMapper.SetInputConnection(out); + out.Delete(); + partNormals.Delete(); + } + else + { + if (cleanPart) { + vtkAlgorithmOutput out = partCleaner.GetOutputPort(); + partMapper.SetInputConnection(out); // metoda 2, ne tak pekne, viz http://www.codeguru.com/cpp/g-m/opengl/article.php/c2681 + out.Delete(); + } + else partMapper.SetInput(partGrid); // metoda 1, ne tak pekne stinovani, viz: http://www.codeguru.com/cpp/g-m/opengl/article.php/c2681 + } + partMapper.ScalarVisibilityOn(); + + vtkActor partActor = new vtkActor(); + partActor.SetPickable(1); + vtkProperty prop = partActor.GetProperty(); + prop.SetColor(1, 1, 0); + prop.Delete(); + partActor.SetMapper(partMapper); + + assemblies.AddPart(partActor); + + { + // EDGES OF PARTS DETECTION + vtkFeatureEdges partEdges = new vtkFeatureEdges(); + if (cleanPart) { + vtkAlgorithmOutput out = partCleaner.GetOutputPort(); + partEdges.SetInputConnection(out); + out.Delete(); + } + else partEdges.SetInput(partGrid); + // partEdges.SetFeatureAngle(featureAngle); // this do not have to be neccesarily called + partEdges.FeatureEdgesOn(); + partEdges.BoundaryEdgesOn(); + partEdges.NonManifoldEdgesOn(); + partEdges.ManifoldEdgesOn(); + + vtkDataSetMapper partEdgesMapper = new vtkDataSetMapper(); + vtkAlgorithmOutput out = partEdges.GetOutputPort(); + partEdgesMapper.SetInputConnection(out); + out.Delete(); + partEdgesMapper.SetResolveCoincidentTopologyToPolygonOffset(); + partEdgesMapper.ScalarVisibilityOff(); + + vtkActor partEdgesActor = new vtkActor(); + + prop = partEdgesActor.GetProperty(); + prop.SetColor(0, 0, 0); + prop.SetLineWidth(2.0); + prop.Delete(); + partEdgesActor.SetMapper(partEdgesMapper); + partEdgesActor.PickableOn(); + + assemblies.AddPart(partEdgesActor); + + { + + EdgePointsFilter edgePoints = new EdgePointsFilter(); + + + out = partEdges.GetOutputPort(); + edgePoints.SetInputConnection(out); + out.Delete(); + +// vtkDataSetMapper partEdgePointsMapper = new vtkDataSetMapper(); +// out = edgePoints.GetOutputPort(); +// partEdgePointsMapper.SetInputConnection(out); +// out.Delete(); + +// vtkVertexGlyphFilter glyphFilter = new vtkVertexGlyphFilter(); +// out = edgePoints.GetOutputPort(); +// glyphFilter.SetInputConnection(out); +// glyphFilter.Update(); +// out.Delete(); +// +// vtkPolyDataMapper partEdgePointsMapper = new vtkPolyDataMapper(); +// out = glyphFilter.GetOutputPort(); +// partEdgePointsMapper.SetInputConnection(out); +// out.Delete(); + + vtkSphereSource sphereSource = new vtkSphereSource(); + vtkGlyph3D glyph3D = new vtkGlyph3D(); + out = sphereSource.GetOutputPort(); + glyph3D.SetSourceConnection(out); + out.Delete(); + + out = edgePoints.GetOutputPort(); + glyph3D.SetInputConnection(out); + out.Delete(); + + //glyph3D.ScalingOff(); + glyph3D.SetScaleFactor(0.03); + + glyph3D.Update(); + + vtkPolyDataMapper partEdgePointsMapper = new vtkPolyDataMapper(); + out = glyph3D.GetOutputPort(); + partEdgePointsMapper.SetInputConnection(out); + out.Delete(); + + vtkActor edgePointsActor = new vtkActor(); + + prop = edgePointsActor.GetProperty(); + prop.SetColor(0, 0, 1); + //prop.SetPointSize(10.0); + //prop.SetRepresentationToPoints(); + prop.Delete(); + edgePointsActor.SetMapper(partEdgePointsMapper); + + edgePointsActor.PickableOn(); + assemblies.AddPart(edgePointsActor); + + + edgePointsActor.Delete(); + partEdgePointsMapper.Delete(); + // edgePoints.Delete(); + } + // Clean up: + //---------- + partEdgesActor.Delete(); + partEdgesMapper.Delete(); + partEdges.Delete(); + } + + partActor.Delete(); + partMapper.Delete(); + partGrid.Delete(); + partCleaner.Delete(); +} + + + + public static vtkPolyData createPartGrid ( TopoDS_Face face) + { + TopLoc_Location Location = new TopLoc_Location(); + + Poly_Triangulation triangulation = BRep_Tool.triangulation(face, Location); + + if(triangulation == null) { + Location.delete(); + System.out.println("Encountered empty triangulation after face"); + return null; + } + + boolean reverse = face.orientation()==TopAbs_Orientation.REVERSED; + + int[]triangles = triangulation.triangles(); + double[]nodes = triangulation.nodes(); + + int nofTriangles = triangulation.nbTriangles(); + int nofNodes = triangulation.nbNodes(); + + triangulation.delete(); + + if(nofTriangles < 1) { + System.out.println("No triangles for mesh on face"); + Location.delete(); + return null; + } + + if(nofNodes < 1) { + System.out.println("No nodes for mesh on face:"); + Location.delete(); + return null; + } + //System.out.println("v " + nofNodes + " t " +nofTriangles); + vtkPolyData partGrid = new vtkPolyData(); + partGrid.Allocate(nofTriangles, nofTriangles); + + vtkTriangle triangle = new vtkTriangle(); + vtkIdList list = triangle.GetPointIds(); + for(int i = 0; i < nofTriangles; i++) + { + int n0, n1, n2; + if (!reverse) { + n0 = triangles[3 * i]; + n1 = triangles[3 * i + 1]; + n2 = triangles[3 * i + 2]; + } else { + n0 = triangles[3 * i + 2]; + n1 = triangles[3 * i + 1]; + n2 = triangles[3 * i]; + } + + list.SetId(0, n0); + list.SetId(1, n1); + list.SetId(2, n2); + partGrid.InsertNextCell(triangle.GetCellType(), list); + + } + list.Delete(); + triangle.Delete(); + + GP_Trsf transformation = Location.transformation(); + Location.delete(); + + double d_mat[] = new double[16]; + double d_p[] = new double[3]; + transformation.getValues(d_mat); + Matrix4d mat = new Matrix4d(d_mat); + + vtkPoints partPoints = new vtkPoints(); + + for(int i = 0; i < nofNodes; i++) { + // FIXME: GP_Trsf.transform(double[]) leaks memory + + //double xyz[] = new double[]{nodes[3 * i], nodes[3 * i + 1], nodes[3 * i + 2]}; + //transformation.transforms(xyz); + //partPoints.InsertPoint(i, xyz); + Point3d p = new Point3d(nodes[3 * i], nodes[3 * i + 1], nodes[3 * i + 2]); + mat.transform(p); + d_p[0] = p.x; + d_p[1] = p.y; + d_p[2] = p.z; + partPoints.InsertPoint(i, d_p); + } + + transformation.delete(); + + partGrid.SetPoints(partPoints); + partPoints.Delete(); + + return partGrid; + } + + + + public static vtkPolyData createPartGrid ( List meshPoints, List meshTriangles) + { + + + + + + int nofTriangles = meshTriangles.size() / 3; + int nofNodes = meshPoints.size() /3; + + + if(nofTriangles < 1) { + System.out.println("No triangles for mesh on face"); + return null; + } + + if(nofNodes < 1) { + System.out.println("No nodes for mesh on face:"); + return null; + } + //System.out.println("v " + nofNodes + " t " +nofTriangles); + vtkPolyData partGrid = new vtkPolyData(); + partGrid.Allocate(nofTriangles, nofTriangles); + + vtkTriangle triangle = new vtkTriangle(); + vtkIdList list = triangle.GetPointIds(); + for(int i = 0; i < nofTriangles; i++) + { + int n0, n1, n2; + n0 = meshTriangles.get(3 * i); + n1 = meshTriangles.get(3 * i + 1); + n2 = meshTriangles.get(3 * i + 2); + + + list.SetId(0, n0); + list.SetId(1, n1); + list.SetId(2, n2); + partGrid.InsertNextCell(triangle.GetCellType(), list); + + } + list.Delete(); + triangle.Delete(); + + + + double d_p[] = new double[3]; + + + vtkPoints partPoints = new vtkPoints(); + + for(int i = 0; i < nofNodes; i++) { + + d_p[0] = meshPoints.get(3*i); + d_p[1] = meshPoints.get(3*i+1); + d_p[2] = meshPoints.get(3*i+2); + partPoints.InsertPoint(i, d_p); + } + + partGrid.SetPoints(partPoints); + partPoints.Delete(); + + return partGrid; + } + + private static vtkPolyData createTestPartGrid () + { + int size = 64; + + double[] nodes = new double[(size+1)*(size+1)*3]; + int[] triangles = new int[3 * size * size * 2]; + + double es = 1.0; + for (int i = 0; i <= size; i++) { + for (int j = 0; j <= size; j++) { + int index = j * size + i; + index *= 3; + double x = (double)i * es; + double y = (Math.sin((double)i/(double)size) + Math.sin((double)j/(double)size)) * es; + double z = (double)j * es; + nodes[index] = x; + nodes[index+1] = y; + nodes[index+2] = z; + } + } + + for (int i = 0; i < size; i++) { + for (int j = 0; j < size; j++) { + int index = j * size + i; + index *= 3; + index *= 2; + triangles[index ] = (j * (size+1) + i ); + triangles[index+1] = (j * (size+1) + i+1); + triangles[index+2] = ((j+1) * (size+1) + i ); + triangles[index+3] = ((j+1) * (size+1) + i ); + triangles[index+4] = ((j ) * (size+1) + i +1 ); + triangles[index+5] = ((j+1) * (size+1) + i +1 ); + } + } + + int nofTriangles = triangles.length / 3; + int nofNodes = nodes.length / 3; + + if(nofTriangles < 1) { + + return null; + } + + if(nofNodes < 1) { + + return null; + } + //System.out.println("v " + nofNodes + " t " +nofTriangles); + vtkPolyData partGrid = new vtkPolyData(); + partGrid.Allocate(nofTriangles, nofTriangles); + + vtkTriangle triangle = new vtkTriangle(); + vtkIdList list = triangle.GetPointIds(); + for(int i = 0; i < nofTriangles; i++) + { + int n0, n1, n2; + n0 = triangles[3 * i]; n1 = triangles[3 * i + 1]; n2 = triangles[3 * i + 2]; // triangles(i).Get(n0, n1, n2); + +// if(face.orientation() != TopAbs_Orientation.FORWARD) { +// int tmp = n2; n2 = n1; n1 = tmp; +// } + + list.SetId(0, n0); + list.SetId(1, n1); + list.SetId(2, n2); + partGrid.InsertNextCell(triangle.GetCellType(), list); + + } + list.Delete(); + triangle.Delete(); + + vtkPoints partPoints = new vtkPoints(); + for(int i = 0; i < nofNodes; i++) { + double xyz[] = new double[]{nodes[3 * i], nodes[3 * i + 1], nodes[3 * i + 2]}; + partPoints.InsertPoint(i, xyz); + } + + partGrid.SetPoints(partPoints); + + partPoints.Delete(); + + return partGrid; + } + + public static void test() { + TopoDS_Shape shape = null; + //shape = OccTriangulator.makeCylinder(new double[]{0,0,0}, new double[]{0,1,0}, 1, 1); + for (int t = 0; t < 5000; t++) { + //shape = OccTriangulator.makeCylinder(new double[]{0,0,0}, new double[]{0,1,0}, 1, 1); + int test = 2; + if (test == 0) { + vtkAssembly ass = VTKOCCTool.vtkOCCShapeToAssembly(shape); + vtkPropCollection col; + col = ass.GetParts(); + for (int i = 0; i < col.GetNumberOfItems(); i++) + { + vtkProp prop = (vtkProp) col.GetItemAsObject(i); + //System.out.println(prop.Print()); + prop.Delete(); + } + col.Delete(); + ass.Delete(); + } + else if (test == 1) { + //BRepTools.clean(shape); + + + vtkAssembly ass = new vtkAssembly(); + + double vol = OCCTTool.getBoundingBoxDiagonal(shape); + double d = 0.001 * vol; + BRepMesh_IncrementalMesh mesh = new BRepMesh_IncrementalMesh(shape,d); + TopExp_Explorer expFace = new TopExp_Explorer(); + for (expFace.init(shape, TopAbs_ShapeEnum.FACE); expFace.more(); expFace.next()) { + TopoDS_Face face = (TopoDS_Face) expFace.current(); + { +// TopLoc_Location Location = new TopLoc_Location(); +// Poly_Triangulation triangulation = BRep_Tool.triangulation(face, Location); +// if (triangulation != null) { +// +// int[]triangles = triangulation.triangles(); +// double[]nodes = triangulation.nodes(); +// int nofTriangles = triangulation.nbTriangles(); +// int nofNodes = triangulation.nbNodes(); +// +// triangulation.delete(); +// +// GP_Trsf transformation = Location.transformation(); +// double d_mat[] = new double[16]; +// transformation.getValues(d_mat); +// Matrix4d mat = new Matrix4d(d_mat); +// for(int i = 0; i < nofNodes; i++) { +// //double xyz[] = new double[]{nodes[3 * i], nodes[3 * i + 1], nodes[3 * i + 2]}; +// Point3d p = new Point3d(nodes[3 * i], nodes[3 * i + 1], nodes[3 * i + 2]); +// //transformation.transforms(xyz); +// mat.transform(p); +// } +// transformation.delete(); +// } +// +// Location.delete(); + vtkPolyData data = VTKOCCTool.createPartGrid(face); + VTKOCCTool.gridToAssembly(ass, data); + //data.Delete(); + } + face.delete(); + } + expFace.delete(); + mesh.delete(); + + vtkPropCollection col; + col = ass.GetParts(); + for (int i = 0; i < col.GetNumberOfItems(); i++) + { + vtkProp prop = (vtkProp) col.GetItemAsObject(i); + //System.out.println(prop.Print()); + prop.Delete(); + } + col.Delete(); + ass.Delete(); + } else if (test == 2) { + double[] pointStruct = new double[]{0,0,0}, dirStruct = new double[]{0,1,0}; + double radius = 1.0; + double height = 1.0; + + double[] axe = new double[6]; + + System.arraycopy(pointStruct, 0, axe, 0, 3); + System.arraycopy(dirStruct, 0, axe, 3, 3); + org.jcae.opencascade.jni.BRepPrimAPI_MakeCylinder cyl = new org.jcae.opencascade.jni.BRepPrimAPI_MakeCylinder(axe, radius, height, 2 * Math.PI); + org.jcae.opencascade.jni.TopoDS_Shape tds = cyl.shape(); + cyl.delete(); + + double vol = OCCTTool.getBoundingBoxDiagonal(tds); + double d = 0.001 * vol; + BRepMesh_IncrementalMesh mesh = new BRepMesh_IncrementalMesh(tds,d); +// TopExp_Explorer expFace = new TopExp_Explorer(); +// for (expFace.init(tds, TopAbs_ShapeEnum.FACE); expFace.more(); expFace.next()) { +// TopoDS_Face face = (TopoDS_Face) expFace.current(); +// { +// +// } +// face.delete(); +// } + mesh.delete(); + + tds.delete(); + } + //shape.delete(); + System.out.println(t); + } + //shape.delete(); + } +} diff --git a/org.simantics.opencascade.vtk/src/org/simantics/opencascade/vtk/vtkSolidObject.java b/org.simantics.opencascade.vtk/src/org/simantics/opencascade/vtk/vtkSolidObject.java new file mode 100644 index 00000000..221c45b4 --- /dev/null +++ b/org.simantics.opencascade.vtk/src/org/simantics/opencascade/vtk/vtkSolidObject.java @@ -0,0 +1,464 @@ +package org.simantics.opencascade.vtk; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.jcae.opencascade.jni.BRepMesh_IncrementalMesh; +import org.jcae.opencascade.jni.TopAbs_ShapeEnum; +import org.jcae.opencascade.jni.TopExp_Explorer; +import org.jcae.opencascade.jni.TopoDS_Face; +import org.jcae.opencascade.jni.TopoDS_Shape; +import org.simantics.opencascade.OCCTTool; +import org.simantics.utils.threads.AWTThread; +import org.simantics.utils.threads.ThreadUtils; + +import vtk.vtkActor; +import vtk.vtkAlgorithmOutput; +import vtk.vtkCleanPolyData; +import vtk.vtkDataSetMapper; +import vtk.vtkFeatureEdges; +import vtk.vtkGlyph3D; +import vtk.vtkPanel; +import vtk.vtkPolyData; +import vtk.vtkPolyDataMapper; +import vtk.vtkPolyDataNormals; +import vtk.vtkPolyDataSilhouette; +import vtk.vtkProp3D; +import vtk.vtkProperty; +import vtk.vtkRenderer; +import vtk.vtkSphereSource; + +public class vtkSolidObject { + + public static double deflection = 0.001; + + public static double featureAngle = 30; + public static boolean computeNormals = true; + public static boolean cleanPart = false; + public static boolean mergePoints = false; + + private vtkPanel panel; + private TopoDS_Shape shape; + + private List actors = new ArrayList(2); + + private List solid = new ArrayList(1); + private List edges = new ArrayList(1); + private vtkActor silhouette = null; + + public vtkSolidObject(vtkPanel panel,TopoDS_Shape shape) { + this.shape = shape; + this.panel = panel; + } + + public void visualizeSolid(boolean showEdges, boolean showVertices) { + visualizeSolid(true, showEdges, showVertices); + } + + public void visualizeSolid(boolean showFaces, boolean showEdges, boolean showVertices) { + visualizeSolid(showFaces, showEdges, showVertices, false); + } + + public void visualizeSolid(boolean showFaces, boolean showEdges, boolean showVertices, boolean showSilhouette) { + clearActorsAWT(); + vtkPolyData data = createSolidMesh(shape); + if (data == null) + return; + if (showFaces) { + solid.add(createActor(data)); + } + if (showEdges) { + vtkActor edge = createEdgesActor(data); + edges.add(edge); + if (showVertices) { + actors.add(createVerticesActor(edge)); + } + } + if (showSilhouette) { + silhouette = createSilhouette(panel.GetRenderer(), data); + } + actors.addAll(solid); + actors.addAll(edges); + if (silhouette != null) + actors.add(silhouette); + data.Delete(); + showActorsAWT(); + } + + public void visualizeFaces(boolean showEdges, boolean showVertices) { + clearActorsAWT(); + Collection datas = createFaceMeshes(shape); + for (vtkPolyData data : datas) { + solid.add(createActor(data)); + + if (showEdges) { + vtkActor edgesActor = createEdgesActor(data); + edges.add(edgesActor); + if (showVertices) { + actors.add(createVerticesActor(edgesActor)); + } + } + data.Delete(); + } + actors.addAll(solid); + actors.addAll(edges); + + showActorsAWT(); + } + + public List getActors() { + assert (Thread.currentThread() == AWTThread.getThreadAccess().getThread()); + return actors; + } + + public List getSolid() { + assert (Thread.currentThread() == AWTThread.getThreadAccess().getThread()); + return solid; + } + + public List getEdges() { + assert (Thread.currentThread() == AWTThread.getThreadAccess().getThread()); + return edges; + } + + public vtkActor getSilhouette() { + assert (Thread.currentThread() == AWTThread.getThreadAccess().getThread()); + return silhouette; + } + + public void showActorsAWT() { + assert (Thread.currentThread() == AWTThread.getThreadAccess().getThread()); + vtkRenderer ren = panel.GetRenderer(); + for (vtkProp3D act : actors) { + ren.AddActor(act); + } + } + + public void showActors() { + ThreadUtils.asyncExec(AWTThread.getThreadAccess(), new Runnable() { + + @Override + public void run() { + showActorsAWT(); + } + }); + } + + public void clearActorsAWT() { + assert (Thread.currentThread() == AWTThread.getThreadAccess().getThread()); + if (actors.size() == 0) + return; + vtkRenderer ren = panel.GetRenderer(); + for (vtkProp3D act : actors) { + if (act.GetVTKId() != 0) { + ren.RemoveActor(act); + act.Delete(); + } + } + actors.clear(); + solid.clear(); + edges.clear(); + } + + private void clearActorsAWT(List actors) { + assert (Thread.currentThread() == AWTThread.getThreadAccess().getThread()); + + if (actors.size() == 0) + return; + vtkRenderer ren = panel.GetRenderer(); + panel.lock(); + for (vtkProp3D act : actors) { + if (act.GetVTKId() != 0) { + ren.RemoveActor(act); + act.Delete(); + } + } + panel.unlock(); + } + + public void clearActors() { + if (actors.size() == 0) + return; + final List temp = new ArrayList(actors.size()); + temp.addAll(actors); + actors.clear(); + solid.clear(); + edges.clear(); + ThreadUtils.asyncExec(AWTThread.getThreadAccess(), new Runnable() { + + @Override + public void run() { + clearActorsAWT(temp); + } + }); + } + + public void dispose() { + if (shape != null) { + shape.delete(); + shape = null; + } + clearActors(); + } + + public void delete() { + if (shape != null) { + shape.delete(); + shape = null; + } + clearActorsAWT(); + } + + private static double TOLERANCE = 0.01; + + public static vtkPolyData createSolidMesh(TopoDS_Shape shape) { + + double volume = OCCTTool.getBoundingBoxDiagonal(shape); + if (volume < TOLERANCE) + return null; + + BRepMesh_IncrementalMesh mesh = new BRepMesh_IncrementalMesh(shape,deflection*volume); + + TopExp_Explorer expFace = new TopExp_Explorer(); + + List meshPoints = new ArrayList(); + List meshTriangles = new ArrayList(); + for (expFace.init(shape, TopAbs_ShapeEnum.FACE); expFace.more(); expFace.next()) { + TopoDS_Face face = (TopoDS_Face) expFace.current(); + OCCTTool.appendToMesh(face, meshPoints, meshTriangles); + face.delete(); + } + if (meshPoints.size() == 0 || meshTriangles.size() == 0) + return null; + + vtkPolyData data = VTKOCCTool.createPartGrid(meshPoints, meshTriangles); + + expFace.delete(); + mesh.delete(); + + return data; + } + + public static Collection createFaceMeshes(TopoDS_Shape shape) { + + double volume = OCCTTool.getBoundingBoxDiagonal(shape); + Collection faces = new ArrayList(); + + if (volume > TOLERANCE) { + + BRepMesh_IncrementalMesh mesh = new BRepMesh_IncrementalMesh(shape,deflection*volume); + + TopExp_Explorer expFace = new TopExp_Explorer(); + + + for (expFace.init(shape, TopAbs_ShapeEnum.FACE); expFace.more(); expFace.next()) { + TopoDS_Face face = (TopoDS_Face) expFace.current(); + vtkPolyData data = VTKOCCTool.createPartGrid(face); + face.delete(); + faces.add(data); + } + + expFace.delete(); + mesh.delete(); + } + + return faces; + } + + + + public static vtkActor createActor(vtkPolyData partGrid) { + + + vtkDataSetMapper partMapper = new vtkDataSetMapper(); + + vtkCleanPolyData partCleaner = null; + if (cleanPart) + { + partCleaner = new vtkCleanPolyData(); + partCleaner.SetInput(partGrid); + if(mergePoints) { + partCleaner.PointMergingOn(); + } else { + partCleaner.PointMergingOff(); + } + } + + if (computeNormals) + { + vtkPolyDataNormals partNormals = new vtkPolyDataNormals(); + + if (cleanPart) + { + vtkAlgorithmOutput out = partCleaner.GetOutputPort(); + partNormals.SetInputConnection(out); + out.Delete(); + } + else partNormals.SetInput(partGrid); + + partNormals.SetFeatureAngle(featureAngle); // this do not have to be neccesarily called + vtkAlgorithmOutput out = partNormals.GetOutputPort(); + partMapper.SetInputConnection(out); + out.Delete(); + partNormals.Delete(); + } + else + { + if (cleanPart) { + vtkAlgorithmOutput out = partCleaner.GetOutputPort(); + partMapper.SetInputConnection(out); // metoda 2, ne tak pekne, viz http://www.codeguru.com/cpp/g-m/opengl/article.php/c2681 + out.Delete(); + } + else partMapper.SetInput(partGrid); // metoda 1, ne tak pekne stinovani, viz: http://www.codeguru.com/cpp/g-m/opengl/article.php/c2681 + } + partMapper.ScalarVisibilityOn(); + + vtkActor partActor = new vtkActor(); + // partActor.SetPickable(1); + vtkProperty prop = partActor.GetProperty(); + prop.SetColor(1, 1, 0); + prop.Delete(); + partActor.SetMapper(partMapper); + + partMapper.Delete(); + + if (cleanPart) + partCleaner.Delete(); + + return partActor; + } + + public static vtkActor createEdgesActor(vtkPolyData partGrid) { + vtkCleanPolyData partCleaner = null; + + if (cleanPart) + { + partCleaner = new vtkCleanPolyData(); + partCleaner.SetInput(partGrid); + if(mergePoints) { + partCleaner.PointMergingOn(); + } else { + partCleaner.PointMergingOff(); + } + } + + vtkFeatureEdges partEdges = new vtkFeatureEdges(); + if (cleanPart) { + vtkAlgorithmOutput out = partCleaner.GetOutputPort(); + partEdges.SetInputConnection(out); + out.Delete(); + } + else partEdges.SetInput(partGrid); + // partEdges.SetFeatureAngle(featureAngle); // this do not have to be neccesarily called + partEdges.FeatureEdgesOn(); + partEdges.BoundaryEdgesOn(); + partEdges.NonManifoldEdgesOn(); + partEdges.ManifoldEdgesOn(); + + vtkDataSetMapper partEdgesMapper = new vtkDataSetMapper(); + vtkAlgorithmOutput out = partEdges.GetOutputPort(); + partEdgesMapper.SetInputConnection(out); + out.Delete(); + partEdgesMapper.SetResolveCoincidentTopologyToPolygonOffset(); + partEdgesMapper.ScalarVisibilityOff(); + + vtkActor partEdgesActor = new vtkActor(); + + vtkProperty prop = partEdgesActor.GetProperty(); + prop.SetColor(0, 0, 0); + prop.SetLineWidth(2.0); + prop.Delete(); + partEdgesActor.SetMapper(partEdgesMapper); + + partEdgesMapper.Delete(); + partEdges.Delete(); + + if (cleanPart) + partCleaner.Delete(); + + return partEdgesActor; + } + + public static vtkActor createVerticesActor(vtkActor partEdgesActor) { + vtkDataSetMapper partEdgesMapper = (vtkDataSetMapper) partEdgesActor.GetMapper(); + vtkAlgorithmOutput out = partEdgesMapper.GetInputConnection(0, 0); + vtkFeatureEdges partEdges = (vtkFeatureEdges)out.GetProducer(); + + vtkActor edgePointsActor = createVerticesActor(partEdges); + + partEdges.Delete(); + //out.Delete(); + partEdgesMapper.Delete(); + return edgePointsActor; + } + + public static vtkActor createVerticesActor(vtkFeatureEdges partEdges) { + EdgePointsFilter edgePoints = new EdgePointsFilter(); + + + vtkAlgorithmOutput out = partEdges.GetOutputPort(); + edgePoints.SetInputConnection(out); + out.Delete(); + + vtkSphereSource sphereSource = new vtkSphereSource(); + vtkGlyph3D glyph3D = new vtkGlyph3D(); + out = sphereSource.GetOutputPort(); + glyph3D.SetSourceConnection(out); + out.Delete(); + + out = edgePoints.GetOutputPort(); + glyph3D.SetInputConnection(out); + out.Delete(); + + glyph3D.SetScaleFactor(0.03); + + glyph3D.Update(); + + vtkPolyDataMapper partEdgePointsMapper = new vtkPolyDataMapper(); + out = glyph3D.GetOutputPort(); + partEdgePointsMapper.SetInputConnection(out); + out.Delete(); + + vtkActor edgePointsActor = new vtkActor(); + + vtkProperty prop = edgePointsActor.GetProperty(); + prop.SetColor(0, 0, 1); + prop.Delete(); + edgePointsActor.SetMapper(partEdgePointsMapper); + + edgePointsActor.PickableOn(); + + + partEdgePointsMapper.Delete(); + edgePoints.Delete(); + sphereSource.Delete(); + + return edgePointsActor; + } + + public static vtkActor createSilhouette(vtkRenderer ren, vtkPolyData data) { + + + vtkPolyDataSilhouette silhouette = new vtkPolyDataSilhouette(); + + silhouette.SetInput(data); + silhouette.SetCamera(ren.GetActiveCamera()); + silhouette.SetEnableFeatureAngle(0); + vtkPolyDataMapper mapper = new vtkPolyDataMapper(); + + mapper.SetInputConnection(silhouette.GetOutputPort()); + + vtkActor actor = new vtkActor(); + actor.SetMapper(mapper); + + actor.GetProperty().SetColor(0,0,1); + actor.GetProperty().SetLineWidth(6); + + return actor; + + + + } + +} diff --git a/org.simantics.opencascade/.classpath b/org.simantics.opencascade/.classpath new file mode 100644 index 00000000..8a8f1668 --- /dev/null +++ b/org.simantics.opencascade/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/org.simantics.opencascade/.project b/org.simantics.opencascade/.project new file mode 100644 index 00000000..332b01db --- /dev/null +++ b/org.simantics.opencascade/.project @@ -0,0 +1,28 @@ + + + org.simantics.opencascade + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/org.simantics.opencascade/.settings/org.eclipse.jdt.core.prefs b/org.simantics.opencascade/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000..a29390ad --- /dev/null +++ b/org.simantics.opencascade/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,8 @@ +#Mon Dec 12 17:21:52 EET 2011 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/org.simantics.opencascade/META-INF/MANIFEST.MF b/org.simantics.opencascade/META-INF/MANIFEST.MF new file mode 100644 index 00000000..3456c4d4 --- /dev/null +++ b/org.simantics.opencascade/META-INF/MANIFEST.MF @@ -0,0 +1,14 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Opencascade +Bundle-SymbolicName: org.simantics.opencascade +Bundle-Version: 1.0.0.qualifier +Bundle-Activator: org.simantics.opencascade.Activator +Bundle-Vendor: VTT +Require-Bundle: org.eclipse.core.runtime, + javax.vecmath;bundle-version="1.5.2", + org.jcae.opencascade;bundle-version="1.0.0", + org.simantics.utils.datastructures;bundle-version="1.1.0" +Bundle-RequiredExecutionEnvironment: JavaSE-1.6 +Bundle-ActivationPolicy: lazy +Export-Package: org.simantics.opencascade diff --git a/org.simantics.opencascade/build.properties b/org.simantics.opencascade/build.properties new file mode 100644 index 00000000..41eb6ade --- /dev/null +++ b/org.simantics.opencascade/build.properties @@ -0,0 +1,4 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + . diff --git a/org.simantics.opencascade/src/org/simantics/opencascade/Activator.java b/org.simantics.opencascade/src/org/simantics/opencascade/Activator.java new file mode 100644 index 00000000..73b38c87 --- /dev/null +++ b/org.simantics.opencascade/src/org/simantics/opencascade/Activator.java @@ -0,0 +1,30 @@ +package org.simantics.opencascade; + +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; + +public class Activator implements BundleActivator { + + private static BundleContext context; + + static BundleContext getContext() { + return context; + } + + /* + * (non-Javadoc) + * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext) + */ + public void start(BundleContext bundleContext) throws Exception { + Activator.context = bundleContext; + } + + /* + * (non-Javadoc) + * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) + */ + public void stop(BundleContext bundleContext) throws Exception { + Activator.context = null; + } + +} diff --git a/org.simantics.opencascade/src/org/simantics/opencascade/OCCTTool.java b/org.simantics.opencascade/src/org/simantics/opencascade/OCCTTool.java new file mode 100644 index 00000000..eba42a6a --- /dev/null +++ b/org.simantics.opencascade/src/org/simantics/opencascade/OCCTTool.java @@ -0,0 +1,206 @@ +package org.simantics.opencascade; + +import java.util.List; + +import javax.vecmath.Matrix4d; +import javax.vecmath.Point3d; + +import org.jcae.opencascade.jni.BRepBndLib; +import org.jcae.opencascade.jni.BRepGProp; +import org.jcae.opencascade.jni.BRep_Tool; +import org.jcae.opencascade.jni.Bnd_Box; +import org.jcae.opencascade.jni.GP_Trsf; +import org.jcae.opencascade.jni.GProp_GProps; +import org.jcae.opencascade.jni.GProp_VelGProps; +import org.jcae.opencascade.jni.Poly_Triangulation; +import org.jcae.opencascade.jni.TopAbs_Orientation; +import org.jcae.opencascade.jni.TopLoc_Location; +import org.jcae.opencascade.jni.TopoDS_Face; +import org.jcae.opencascade.jni.TopoDS_Shape; + +public class OCCTTool { +public static double getBoundingBoxDiagonal(TopoDS_Shape shape) { + + double []min = new double[3]; + double []max = new double[3]; + double []mmm = new double[3]; + double []bb = new double[6]; + + // Compute bounding box: + //---------------------- + Bnd_Box boundingBox = new Bnd_Box(); + BRepBndLib.add(shape, boundingBox); + boundingBox.get(bb); + boundingBox.delete(); + + min[0] = bb[0]; min[1] = bb[1]; min[2] = bb[2]; + max[0] = bb[3]; max[1] = bb[4]; max[2] = bb[5]; + + //System.out.println("Bounding box: "+"[ "+min[0]+", "+min[1]+", " + min[2] + "] x "+"[ " +max[0] +", " +max[1] +", " +max[2] +"]"); + + // The length of the space diagonal of cuboid + for (int i = 0; i < 3; i++) mmm[i] = max[i] - min[i]; + double length = Math.sqrt(mmm[2]*mmm[2] + mmm[1]*mmm[1] + mmm[0]*mmm[0]); + + double t0 = mmm[0]*mmm[0]; + double t1 = mmm[1]*mmm[1]; + double t2 = mmm[2]*mmm[2]; + + double tol = 1.0e-6 * length; + + if((t0 < tol) || (t1 < tol) || (t2 < tol)) { + System.out.println("Shape seems to be 2D. Unable to proceed. Aborting."); + return 0; + } + return length; + } + + public static double getBoundingBoxVolume(TopoDS_Shape shape) { + + double []min = new double[3]; + double []max = new double[3]; + double []mmm = new double[3]; + double []bb = new double[6]; + + // Compute bounding box: + //---------------------- + Bnd_Box boundingBox = new Bnd_Box(); + BRepBndLib.add(shape, boundingBox); + boundingBox.get(bb); + boundingBox.delete(); + + min[0] = bb[0]; min[1] = bb[1]; min[2] = bb[2]; + max[0] = bb[3]; max[1] = bb[4]; max[2] = bb[5]; + + //System.out.println("Bounding box: "+"[ "+min[0]+", "+min[1]+", " + min[2] + "] x "+"[ " +max[0] +", " +max[1] +", " +max[2] +"]"); + + for (int i = 0; i < 3; i++) mmm[i] = max[i] - min[i]; + double vol = Math.sqrt(mmm[2]*mmm[1]*mmm[0]); + + return vol; + } + + private static GProp_GProps getGProp(TopoDS_Shape shape) { + GProp_GProps GSystem = null; + int type = 0; + if (type == 0) { + GSystem = new GProp_GProps(); + BRepGProp.volumeProperties(shape, GSystem,0.001); + } else if (type == 1) { + GSystem = new GProp_VelGProps(); + BRepGProp.volumeProperties(shape, GSystem,0.001); + } else if (type == 2) { + GSystem = new GProp_VelGProps(); + BRepGProp.volumePropertiesGK(shape, GSystem, 0.001); + } + return GSystem; + } + + public static double getMass( TopoDS_Shape shape) { + + GProp_GProps GSystem = getGProp(shape); + + + double mass = GSystem.mass(); + //System.out.println("Mass " + mass); + GSystem.delete(); + return mass; + } + + public static double[] getInertia(TopoDS_Shape shape) { + GProp_GProps GSystem = getGProp(shape); + + double inertia[] = GSystem.matrixOfInertia(); + GSystem.delete(); + return inertia; + } + + public static double[] getCentreOfMass(TopoDS_Shape shape) { + GProp_GProps GSystem = getGProp(shape); + + double cm[] = GSystem.centreOfMass(); + GSystem.delete(); + return cm; + } + + public static boolean appendToMesh (TopoDS_Face face, List meshPoints, List meshTriangles) + { + TopLoc_Location Location = new TopLoc_Location(); + + Poly_Triangulation triangulation = BRep_Tool.triangulation(face, Location); + + if(triangulation == null) { + Location.delete(); + System.out.println("Encountered empty triangulation after face"); + return false; + } + + boolean reverse = face.orientation()==TopAbs_Orientation.REVERSED; + + int lastPoint = meshPoints.size() / 3; + + int[]triangles = triangulation.triangles(); + double[]nodes = triangulation.nodes(); + + int nofTriangles = triangulation.nbTriangles(); + int nofNodes = triangulation.nbNodes(); + + + triangulation.delete(); + + if(nofTriangles < 1) { + System.out.println("No triangles for mesh on face"); + Location.delete(); + return false; + } + + if(nofNodes < 1) { + System.out.println("No nodes for mesh on face:"); + Location.delete(); + return false; + } + + for(int i = 0; i < nofTriangles; i++) + { + int n0, n1, n2; + if (!reverse) { + n0 = triangles[3 * i]; + n1 = triangles[3 * i + 1]; + n2 = triangles[3 * i + 2]; + } else { + n0 = triangles[3 * i + 2]; + n1 = triangles[3 * i + 1]; + n2 = triangles[3 * i]; + } + + meshTriangles.add(n0 + lastPoint); + meshTriangles.add(n1 + lastPoint); + meshTriangles.add(n2 + lastPoint); + } + + + GP_Trsf transformation = Location.transformation(); + Location.delete(); + + double d_mat[] = new double[16]; + + transformation.getValues(d_mat); + Matrix4d mat = new Matrix4d(d_mat); + + + for(int i = 0; i < nofNodes; i++) { + + Point3d p = new Point3d(nodes[3 * i], nodes[3 * i + 1], nodes[3 * i + 2]); + mat.transform(p); + + meshPoints.add(p.x); + meshPoints.add(p.y); + meshPoints.add(p.z); + + } + + transformation.delete(); + + return true; + } +} diff --git a/org.simantics.opencascade/src/org/simantics/opencascade/OccTriangulator.java b/org.simantics.opencascade/src/org/simantics/opencascade/OccTriangulator.java new file mode 100644 index 00000000..e545a69c --- /dev/null +++ b/org.simantics.opencascade/src/org/simantics/opencascade/OccTriangulator.java @@ -0,0 +1,303 @@ +package org.simantics.opencascade; + +/******************************************************************************* + * Copyright (c) 2007- VTT Technical Research Centre of Finland. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ + +import javax.vecmath.Vector2d; + +import org.jcae.opencascade.jni.BRepBuilderAPI_MakeEdge; +import org.jcae.opencascade.jni.BRepBuilderAPI_MakeFace; +import org.jcae.opencascade.jni.BRepBuilderAPI_MakeWire; +import org.jcae.opencascade.jni.BRepBuilderAPI_Transform; +import org.jcae.opencascade.jni.BRepPrimAPI_MakePrism; +import org.jcae.opencascade.jni.BRepPrimAPI_MakeTorus; +import org.jcae.opencascade.jni.BRep_Builder; +import org.jcae.opencascade.jni.GP_Elips; +import org.jcae.opencascade.jni.GP_Trsf; +import org.jcae.opencascade.jni.TopoDS_Edge; +import org.jcae.opencascade.jni.TopoDS_Face; +import org.jcae.opencascade.jni.TopoDS_Shape; +import org.jcae.opencascade.jni.TopoDS_Wire; + + +public class OccTriangulator { + + + public static final double MIN_VALUE = 0.001; + + public OccTriangulator() { + + } + + + public static TopoDS_Shape getShapeFromFile(String filename) { + assert (filename != null); + String lowerFileName = filename.toLowerCase(); + if (lowerFileName.endsWith(".stp") || lowerFileName.endsWith(".step")) { + TopoDS_Shape shape = importSTEP(filename); + return shape; + } else if (lowerFileName.endsWith(".iges")) { + TopoDS_Shape shape = importIGES(filename); + return shape; + } else if (lowerFileName.endsWith(".brep")) { + TopoDS_Shape shape = importBREP(filename); + return shape; + } else { + throw new UnsupportedOperationException("Unsupported format " + filename); + } + } + + public static TopoDS_Shape importBREP(String filename) { + return importBREP(filename,1.0); // convert to meters. + } + public static TopoDS_Shape importBREP(String filename, double scale) { + org.jcae.opencascade.jni.BRep_Builder aBuilder = new org.jcae.opencascade.jni.BRep_Builder(); + org.jcae.opencascade.jni.TopoDS_Shape myShape = org.jcae.opencascade.jni.BRepTools.read(filename, aBuilder); + aBuilder.delete(); + if (Math.abs(scale-1.0) < 0.001) + return myShape; + TopoDS_Shape scaled = makeScale(myShape, scale); + myShape.delete(); + return scaled; + } + + public static TopoDS_Shape importIGES(String filename) { + org.jcae.opencascade.jni.IGESControl_Reader aReader = new org.jcae.opencascade.jni.IGESControl_Reader(); + aReader.setReadUnitM(); + aReader.readFile(filename.getBytes()); + aReader.clearShapes(); + aReader.transferRoots(); + TopoDS_Shape result = aReader.oneShape(); + aReader.delete(); + return result; + } + + public static TopoDS_Shape importSTEP(String filename) { + org.jcae.opencascade.jni.STEPControl_Reader aReader = new org.jcae.opencascade.jni.STEPControl_Reader(); + aReader.setReadUnitM(); + aReader.readFile(filename.getBytes()); + aReader.clearShapes(); + aReader.transferRoots(); + TopoDS_Shape result = aReader.oneShape(); + aReader.delete(); + return result; + } + + + + public static TopoDS_Shape makeTranslation(TopoDS_Shape aShape, double x, double y, double z) { + GP_Trsf theTransformation = new GP_Trsf(); + theTransformation.setTranslation(new double[] { x, y, z }); + BRepBuilderAPI_Transform bt = new BRepBuilderAPI_Transform(aShape, theTransformation, true); + + TopoDS_Shape shape = bt.shape(); + bt.delete(); + theTransformation.delete(); + return shape; + } + + public static TopoDS_Shape makeTorus(double[] pointStruct, double[] dirStruct, double r1, double r2) { + double[] axe = new double[6]; + System.arraycopy(pointStruct, 0, axe, 0, 3); + System.arraycopy(dirStruct, 0, axe, 3, 3); + BRepPrimAPI_MakeTorus torus = new BRepPrimAPI_MakeTorus(axe, r1, r2); + org.jcae.opencascade.jni.TopoDS_Shape tds = torus.shape(); + torus.delete(); + return tds; + } + + public static TopoDS_Shape makeTorus(double[] pointStruct, double[] dirStruct, double r1, double r2, double angle1, double angle2, double angle) { + double[] axe = new double[6]; + System.arraycopy(pointStruct, 0, axe, 0, 3); + System.arraycopy(dirStruct, 0, axe, 3, 3); + BRepPrimAPI_MakeTorus torus = new BRepPrimAPI_MakeTorus(axe, r1, r2,angle1,angle2,angle); + org.jcae.opencascade.jni.TopoDS_Shape tds = torus.shape(); + torus.delete(); + return tds; + } + + public static TopoDS_Shape makeSphere(double x, double y, double z, double radius) { + double[] c = new double[] { x, y, z }; + org.jcae.opencascade.jni.BRepPrimAPI_MakeSphere sphere = new org.jcae.opencascade.jni.BRepPrimAPI_MakeSphere(c, radius); + org.jcae.opencascade.jni.TopoDS_Shape tds = sphere.shape(); + sphere.delete(); + return tds; + } + + + public static TopoDS_Shape makeRotation(TopoDS_Shape aShape, double[] axisStruct, double angle) { + + GP_Trsf theTransformation = new GP_Trsf(); + theTransformation.setRotation(axisStruct, angle); + BRepBuilderAPI_Transform bt = new BRepBuilderAPI_Transform(aShape, theTransformation, true); + TopoDS_Shape shape = bt.shape(); + bt.delete(); + theTransformation.delete(); + return shape; + } + + public static TopoDS_Shape makeScale(TopoDS_Shape aShape, double s) { + + GP_Trsf theTransformation = new GP_Trsf(); + theTransformation.setValues(s, 0, 0, 0, + 0, s, 0, 0, + 0, 0, s, 0, 1, 1); + BRepBuilderAPI_Transform bt = new BRepBuilderAPI_Transform(aShape, theTransformation, true); + TopoDS_Shape shape = bt.shape(); + bt.delete(); + theTransformation.delete(); + return shape; + } + + + public static TopoDS_Shape makeCylinder(double[] pointStruct, double[] dirStruct, double radius, double height) { + double[] axe = new double[6]; + System.arraycopy(pointStruct, 0, axe, 0, 3); + System.arraycopy(dirStruct, 0, axe, 3, 3); + org.jcae.opencascade.jni.BRepPrimAPI_MakeCylinder cyl = new org.jcae.opencascade.jni.BRepPrimAPI_MakeCylinder(axe, radius, height, 2 * Math.PI); + org.jcae.opencascade.jni.TopoDS_Shape tds = cyl.shape(); + cyl.delete(); + return tds; + } + + public static TopoDS_Shape makeCopy(TopoDS_Shape topoDS_Shape) { + throw new UnsupportedOperationException(); + } + + public static TopoDS_Shape makeCone(double[] pointStruct, double[] dirStruct, double radius1, double radius2, double height) { + double[] axe = new double[6]; + System.arraycopy(pointStruct, 0, axe, 0, 3); + System.arraycopy(dirStruct, 0, axe, 3, 3); + org.jcae.opencascade.jni.BRepPrimAPI_MakeCone cone = new org.jcae.opencascade.jni.BRepPrimAPI_MakeCone(axe, radius1, radius2, height, 2 * Math.PI); + org.jcae.opencascade.jni.TopoDS_Shape tds = cone.shape(); + cone.delete(); + return tds; + } + + public static TopoDS_Shape makeCompound(TopoDS_Shape[] shapes) { + BRep_Builder builder = new BRep_Builder(); + org.jcae.opencascade.jni.TopoDS_Compound comp = new org.jcae.opencascade.jni.TopoDS_Compound(); + builder.makeCompound(comp); + for (int i = 0; i < shapes.length; i++) { + + builder.add(comp, shapes[i]); + } + builder.delete(); + return comp; + } + + + public static TopoDS_Shape makeBox(double x1, double y1, double z1, double x2, double y2, double z2) { + double[] p1 = new double[] { x1, y1, z1 }; + double[] p2 = new double[] { x2, y2, z2 }; + org.jcae.opencascade.jni.BRepPrimAPI_MakeBox box = new org.jcae.opencascade.jni.BRepPrimAPI_MakeBox(p1, p2); + org.jcae.opencascade.jni.TopoDS_Shape tds = box.shape(); + box.delete(); + return tds; + } + + public static TopoDS_Shape makeCut(TopoDS_Shape shape1, TopoDS_Shape shape2) { + org.jcae.opencascade.jni.BRepAlgoAPI_Cut cut = new org.jcae.opencascade.jni.BRepAlgoAPI_Cut(shape1, shape2); + org.jcae.opencascade.jni.TopoDS_Shape s = cut.shape(); + cut.delete(); + return s; + } + + public static TopoDS_Shape makeCommon(TopoDS_Shape shape1, TopoDS_Shape shape2) { + org.jcae.opencascade.jni.BRepAlgoAPI_Common common = new org.jcae.opencascade.jni.BRepAlgoAPI_Common(shape1, shape2); + org.jcae.opencascade.jni.TopoDS_Shape s = common.shape(); + common.delete(); + return s; + } + + public static TopoDS_Shape makeFuse(TopoDS_Shape shape1, TopoDS_Shape shape2) { + org.jcae.opencascade.jni.BRepAlgoAPI_Fuse fuse = new org.jcae.opencascade.jni.BRepAlgoAPI_Fuse(shape1, shape2); + org.jcae.opencascade.jni.TopoDS_Shape s = fuse.shape(); + fuse.delete(); + return s; + } + + + public static TopoDS_Shape makeWedge(double[] pointStruct, double[] dirStruct,double dx, double dy, double dz, double xmin, double zmin, double xmax, double zmax) { + double[] axe = new double[6]; + System.arraycopy(pointStruct, 0, axe, 0, 3); + System.arraycopy(dirStruct, 0, axe, 3, 3); + + org.jcae.opencascade.jni.BRepPrimAPI_MakeWedge wedge = new org.jcae.opencascade.jni.BRepPrimAPI_MakeWedge(axe, dx, dy, dz, xmin, zmin, xmax, zmax); + org.jcae.opencascade.jni.TopoDS_Shape s = wedge.shape(); + wedge.delete(); + return s; + } + + public static TopoDS_Shape makeEllipticCylinder(double h, double r1, double r2) { + GP_Elips ellipse; + if (r1 < r2) { + // FIXME : ellipse should be rotated, but current JNI won't allow it since Ax2 is not separate object + ellipse = new GP_Elips(new double[]{0.0,-h*0.5,0.0,0.0,1.0,0.0},r2,r1); + } else { + ellipse = new GP_Elips(new double[]{0.0,-h*0.5,0.0,0.0,1.0,0.0},r1,r2); + } + BRepBuilderAPI_MakeEdge edge = new BRepBuilderAPI_MakeEdge(ellipse); + TopoDS_Edge ed = (TopoDS_Edge) edge.shape(); + BRepBuilderAPI_MakeWire wire = new BRepBuilderAPI_MakeWire(ed); + TopoDS_Wire w = (TopoDS_Wire) wire.shape(); + BRepBuilderAPI_MakeFace face = new BRepBuilderAPI_MakeFace(w); + TopoDS_Face F = (TopoDS_Face) face.shape(); + BRepPrimAPI_MakePrism prism = new BRepPrimAPI_MakePrism(F, new double[] { 0.0, h, 0.0 }); + TopoDS_Shape shape = prism.shape(); + ellipse.delete(); + edge.delete(); + wire.delete(); + face.delete(); + ed.delete(); + w.delete(); + F.delete(); + prism.delete(); + return shape; + } + + public static TopoDS_Shape makeReqularPrism(double h, double r, int n) { + if (n < 3) + n = 3; + Vector2d vertices[] = new Vector2d[n]; + for (int i = 0; i < n; i++) { + vertices[i] = new Vector2d(Math.sin(Math.PI * 2.0 * i / n)*r,Math.cos(Math.PI * 2.0 * i / n)*r); + } + BRepBuilderAPI_MakeWire wire = new BRepBuilderAPI_MakeWire(); + for (int i = 0; i < n; i++) { + Vector2d v1 = vertices[i]; + Vector2d v2 = vertices[(i+1)%n]; + BRepBuilderAPI_MakeEdge edge = new BRepBuilderAPI_MakeEdge(new double[]{v1.x,-h*0.5,v1.y},new double[]{v2.x,-h*0.5,v2.y}); + wire.add((TopoDS_Edge)edge.shape()); + edge.delete(); + } + TopoDS_Wire w = (TopoDS_Wire)wire.shape(); + + BRepBuilderAPI_MakeFace face = new BRepBuilderAPI_MakeFace(w); + TopoDS_Face F = (TopoDS_Face) face.shape(); + face.delete(); + + BRepPrimAPI_MakePrism prism = new BRepPrimAPI_MakePrism(F, new double[] { 0.0, h, 0.0 }); + TopoDS_Shape shape = prism.shape(); + prism.delete(); + + wire.delete(); + w.delete(); + F.delete(); + return shape; + } + + + public static void exportBREP(TopoDS_Shape shape, String filename) { + org.jcae.opencascade.jni.BRepTools.write(shape, filename); + } + +} diff --git a/org.simantics.opencascade/src/org/simantics/opencascade/ParametricSolidModelProvider.java b/org.simantics.opencascade/src/org/simantics/opencascade/ParametricSolidModelProvider.java new file mode 100644 index 00000000..f066002d --- /dev/null +++ b/org.simantics.opencascade/src/org/simantics/opencascade/ParametricSolidModelProvider.java @@ -0,0 +1,11 @@ +package org.simantics.opencascade; + +import java.util.Map; + +public interface ParametricSolidModelProvider extends SolidModelProvider{ + + public void setProperties(Map props); + + public void updateCalculatedProperties(Map returnProps); + +} diff --git a/org.simantics.opencascade/src/org/simantics/opencascade/SolidModelProvider.java b/org.simantics.opencascade/src/org/simantics/opencascade/SolidModelProvider.java new file mode 100644 index 00000000..bc45ec98 --- /dev/null +++ b/org.simantics.opencascade/src/org/simantics/opencascade/SolidModelProvider.java @@ -0,0 +1,11 @@ +package org.simantics.opencascade; + +import java.util.Collection; + +import org.jcae.opencascade.jni.TopoDS_Shape; + +public interface SolidModelProvider { + + + public Collection getModel() throws Exception; +}