From 8da9a6a979f4513be2e0ab5533acc5e4763cf00e Mon Sep 17 00:00:00 2001 From: Marko Luukkainen Date: Fri, 16 Aug 2019 15:43:24 +0300 Subject: [PATCH] Additional SCL Bindings to G3D and Plant3D classes gitlab #28 Change-Id: I1f3b29cd84ac60a16c58736ddae31792393a08ec --- org.simantics.g3d/META-INF/MANIFEST.MF | 1 + .../scl/g3d/scenegraph/G3DNode.scl | 17 + .../scl/g3d/scenegraph/G3DParentNode.scl | 17 + org.simantics.g3d/scl/g3d/scenegraph/Node.scl | 24 + .../org/simantics/g3d/scl/ScriptNodeMap.java | 542 ++++++++++++++++++ .../scl/plant3d/scenegraph/EndComponent.scl | 1 - .../plant3d/scenegraph/InlineComponent.scl | 1 - .../scl/plant3d/scenegraph/Nozzle.scl | 1 - .../scl/plant3d/scenegraph/P3DRootNode.scl | 11 + .../plant3d/scenegraph/PipeControlPoint.scl | 2 - .../scl/plant3d/scenegraph/PipeRun.scl | 4 - .../plant3d/scenegraph/PipelineComponent.scl | 53 +- .../scl/plant3d/scenegraph/Root.scl | 0 .../scl/plant3d/scenegraph/TurnComponent.scl | 1 - .../scl/plant3d/utils/Loader.scl | 13 + .../scl/plant3d/utils/P3DScriptNodeMap.scl | 2 + .../plant3d/editor/P3DContentOutlinePage.java | 2 +- .../plant3d/scenegraph/P3DRootNode.java | 6 +- .../plant3d/scenegraph/PipelineComponent.java | 4 +- .../controlpoint/ControlPointFactory.java | 14 +- .../controlpoint/PipeControlPoint.java | 20 +- .../plant3d/scl/P3DScriptNodeMap.java | 179 ++++++ .../org/simantics/plant3d/scl/SCLUtil.java | 73 +++ 23 files changed, 950 insertions(+), 38 deletions(-) create mode 100644 org.simantics.g3d/scl/g3d/scenegraph/G3DNode.scl create mode 100644 org.simantics.g3d/scl/g3d/scenegraph/G3DParentNode.scl create mode 100644 org.simantics.g3d/scl/g3d/scenegraph/Node.scl create mode 100644 org.simantics.g3d/src/org/simantics/g3d/scl/ScriptNodeMap.java create mode 100644 org.simantics.plant3d/scl/plant3d/scenegraph/P3DRootNode.scl delete mode 100644 org.simantics.plant3d/scl/plant3d/scenegraph/PipeControlPoint.scl delete mode 100644 org.simantics.plant3d/scl/plant3d/scenegraph/PipeRun.scl delete mode 100644 org.simantics.plant3d/scl/plant3d/scenegraph/Root.scl create mode 100644 org.simantics.plant3d/scl/plant3d/utils/Loader.scl create mode 100644 org.simantics.plant3d/scl/plant3d/utils/P3DScriptNodeMap.scl create mode 100644 org.simantics.plant3d/src/org/simantics/plant3d/scl/P3DScriptNodeMap.java create mode 100644 org.simantics.plant3d/src/org/simantics/plant3d/scl/SCLUtil.java diff --git a/org.simantics.g3d/META-INF/MANIFEST.MF b/org.simantics.g3d/META-INF/MANIFEST.MF index bacef662..c479403d 100644 --- a/org.simantics.g3d/META-INF/MANIFEST.MF +++ b/org.simantics.g3d/META-INF/MANIFEST.MF @@ -30,6 +30,7 @@ Export-Package: org.simantics.g3d, org.simantics.g3d.scenegraph, org.simantics.g3d.scenegraph.base, org.simantics.g3d.scenegraph.structural, + org.simantics.g3d.scl, org.simantics.g3d.shape, org.simantics.g3d.toolbar, org.simantics.g3d.tools, diff --git a/org.simantics.g3d/scl/g3d/scenegraph/G3DNode.scl b/org.simantics.g3d/scl/g3d/scenegraph/G3DNode.scl new file mode 100644 index 00000000..64b68090 --- /dev/null +++ b/org.simantics.g3d/scl/g3d/scenegraph/G3DNode.scl @@ -0,0 +1,17 @@ +import "g3d/math/Vector3d" +import "g3d/math/Quat4d" + +importJava "org.simantics.g3d.scenegraph.G3DNode" where + data G3DNode + + getOrientation :: G3DNode -> Quat4d + getPosition :: G3DNode -> Vector3d + + setOrientation :: G3DNode -> Quat4d -> () + setPosition :: G3DNode -> Vector3d -> () + + getWorldOrientation :: G3DNode -> Quat4d + getWorldPosition :: G3DNode -> Vector3d + + setWorldOrientation :: G3DNode -> Quat4d -> () + setWorldPosition :: G3DNode -> Vector3d -> () \ No newline at end of file diff --git a/org.simantics.g3d/scl/g3d/scenegraph/G3DParentNode.scl b/org.simantics.g3d/scl/g3d/scenegraph/G3DParentNode.scl new file mode 100644 index 00000000..d9e9214f --- /dev/null +++ b/org.simantics.g3d/scl/g3d/scenegraph/G3DParentNode.scl @@ -0,0 +1,17 @@ +import "g3d/math/Vector3d" +import "g3d/math/Quat4d" + +importJava "org.simantics.g3d.scenegraph.G3DparentNode" where + data G3DParentNode + + getOrientation :: G3DParentNode -> Quat4d + getPosition :: G3DParentNode -> Vector3d + + setOrientation :: G3DParentNode -> Quat4d -> () + setPosition :: G3DParentNode -> Vector3d -> () + + getWorldOrientation :: G3DParentNode -> Quat4d + getWorldPosition :: G3DParentNode -> Vector3d + + setWorldOrientation :: G3DParentNode -> Quat4d -> () + setWorldPosition :: G3DParentNode -> Vector3d -> () \ No newline at end of file diff --git a/org.simantics.g3d/scl/g3d/scenegraph/Node.scl b/org.simantics.g3d/scl/g3d/scenegraph/Node.scl new file mode 100644 index 00000000..84d7fc4e --- /dev/null +++ b/org.simantics.g3d/scl/g3d/scenegraph/Node.scl @@ -0,0 +1,24 @@ + + +importJava "org.simantics.g3d.scenegraph.base.INode" where + data INode + +importJava "org.simantics.g3d.scenegraph.base.ParentNode" where + data ParentNode + + addNode :: ParentNode -> String -> INode -> () + removeNode :: ParentNode -> String -> INode -> Boolean + deattachNode :: ParentNode -> String -> INode -> Boolean + + removeNodes :: ParentNode -> String ->() + getNodes :: ParentNode -> String -> [INode] + @JavaName getNodes + getAllNodes :: ParentNode -> [INode] + remove :: ParentNode -> () + +importJava "org.simantics.g3d.scenegraph.base.Node" where + data Node + + getParent :: Node -> Maybe ParentNode + getRootNode :: Node -> Maybe ParentNode + deattach :: Node -> () diff --git a/org.simantics.g3d/src/org/simantics/g3d/scl/ScriptNodeMap.java b/org.simantics.g3d/src/org/simantics/g3d/scl/ScriptNodeMap.java new file mode 100644 index 00000000..359f5c3e --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/g3d/scl/ScriptNodeMap.java @@ -0,0 +1,542 @@ +package org.simantics.g3d.scl; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.Stack; + +import org.simantics.db.ReadGraph; +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.db.layer0.util.Layer0Utils; +import org.simantics.g3d.ontology.G3D; +import org.simantics.g3d.scenegraph.NodeMap; +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.exceptions.MappingException; +import org.simantics.objmap.graph.IMapping; +import org.simantics.objmap.graph.IMappingListener; +import org.simantics.utils.datastructures.MapSet; +import org.simantics.utils.datastructures.Pair; + +/** + * NodeMap implementation used with SCL scripts. + * + * In practice, there are no visible objects to synchronize. + * + * TODO: + * This implementation is Copy-paste of AbstractVTKNodeMap with VTK references removed. + * There may be more sensible way to do this. + * + * + * @author luukkainen + * + * @param + */ +public abstract class ScriptNodeMap implements NodeMap, IMappingListener, NodeListener { + + private static final boolean DEBUG = false; + + protected Session session; + protected IMapping mapping; + + protected ParentNode rootNode; + + protected Set nodes = new HashSet(); + + private boolean dirty = false; + + public ScriptNodeMap(Session session, IMapping mapping, ParentNode rootNode) { + this.session = session; + this.mapping = mapping; + this.rootNode = rootNode; + 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() { + dirty = true; + } + + public void populate() { + for (E node : rootNode.getNodes()) { + receiveAdd(node, node.getParentRel(),true); + } + repaint(); + } + + @Override + public E getNode(Object o) { + return null; + } + + @SuppressWarnings("unchecked") + @Override + public Collection getRenderObjects(INode node) { + return Collections.EMPTY_LIST; + } + + @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 MapSet updated = new MapSet.Hash(); + + private boolean rangeModified = false; + + + + @SuppressWarnings("unchecked") + @Override + public void updateRenderObjectsFor(E node) { + nodes.add((E)node); + + } + + @SuppressWarnings("unchecked") + private void receiveAdd(E node, String id, boolean db) { + if (DEBUG) System.out.println("receiveAdd " + debugString(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; + } + repaint(); + } + + @SuppressWarnings("unchecked") + private void receiveRemove(E node, String id, boolean db) { + if (DEBUG) System.out.println("receiveRemove " + debugString(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; + } + repaint(); + } + + @SuppressWarnings("unchecked") + private void receiveUpdate(E node, String id, boolean db) { + if (DEBUG) System.out.println("receiveUpdate " + debugString(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; + } + repaint(); + } + + private boolean graphUpdates = false; + private Set graphModified = new HashSet(); + + private boolean requestCommit = false; + private String commitMessage = null; + + @Override + public void commit(String message) { + requestCommit = true; + commitMessage = message; + } + + protected void doCommit() throws DatabaseException { + session.syncRequest(new WriteRequest() { + + @Override + public void perform(WriteGraph graph) throws DatabaseException { + if (DEBUG) System.out.println("Commit " + commitMessage); + if (commitMessage != null) { + Layer0Utils.addCommentMetadata(graph, commitMessage); + graph.markUndoPoint(); + commitMessage = null; + } + commit(graph); + } + + }); + } + + protected void commit(WriteGraph graph) throws DatabaseException { + synchronized(syncMutex) { + if (DEBUG) System.out.println("Commit"); + graphUpdates = true; + mapping.updateDomain(graph); + graphUpdates = false; + clearDeletes(); + if (DEBUG) System.out.println("Commit done"); + } + } + + + + @Override + public void domainModified() { + if (graphUpdates) + return; + if (DEBUG)System.out.println("domainModified"); + // FIXME : this is called by IMapping id DB thread + session.asyncRequest(new ReadRequest() { + + @SuppressWarnings("unchecked") + @Override + public void run(ReadGraph graph) throws DatabaseException { + update(graph); + } + }); + + } + + protected void reset(ReadGraph graph) throws MappingException { + if (DEBUG) System.out.println("Reset"); + synchronized (syncMutex) { + graphUpdates = true; + mapping.getRangeModified().clear(); + for (Object o : mapping.getDomain()) + mapping.domainModified(o); + mapping.updateRange(graph); + graphModified.clear(); + graphUpdates = false; + } + } + + + protected void update(ReadGraph graph) throws DatabaseException { + if (DEBUG) System.out.println("Graph update start"); + 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(); + syncDeletes(); + clearDeletes(); + graphUpdates = false; + } + + + //if (mapping.isRangeModified() && !runUndo) // FIXME : redo? + if (mapping.isRangeModified()) + commit((String)null); + if (DEBUG) System.out.println("Graph update done"); + } + + @Override + public void rangeModified() { + //System.out.println("rangeModified"); + + } + + public void update() throws DatabaseException{ + while (dirty) { + dirty = false; + // preRender + updateCycle(); + // postRender + if (requestCommit && !rangeModified) { // FIXME : not thread safe. + requestCommit = false; + doCommit(); + } + } + } + + + + // Reusable containers for data synchronisation + List> rem = new ArrayList>(); // Removed objects + List> add = new ArrayList>(); // Added objects + MapSet mod = new MapSet.Hash(); // Modified objects + Set propagation = new HashSet(); // Objects with propagated changes + Stack stack = new Stack(); // Stack for handling propagation + Set delete = Collections.synchronizedSet(new HashSet()); // Objects to be completely deleted + Set deleteUC = new HashSet(); + + + + + /** + * When objects are removed (either from Java or Graph), after remove processing the Java objects remain in mapping cache. + * This causes problems with Undo and Redo, whcih the end up re-using the removed objects from mapping cache. + * + * This code here synchronizes removed and added objects to collect deletable objects. (a deletable object is one which is removed but not added). + * + */ + protected void syncDeletes() { + deleteUC.clear(); + for (Pair n : removed) { + deleteUC.add(n.first); + } + for (Pair n : added) { + deleteUC.remove(n.first); + } + if (DEBUG && deleteUC.size() > 0) { + System.out.println("Delete sync"); + for (E n : delete) { + System.out.println(debugString(n)); + } + } + delete.addAll(deleteUC); + deleteUC.clear(); + } + + /** + * Clears deletable objects from mapping cache. + */ + protected void clearDeletes() { + if (DEBUG && delete.size() > 0) System.out.println("Delete"); + for (E n : delete) { + if (DEBUG) System.out.println(debugString(n)); + mapping.getRange().remove(n); + } + delete.clear(); + } + + protected String debugString(E n) { + return n + "@" + Integer.toHexString(n.hashCode()); + } + + @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); + } + } + syncDeletes(); + 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; + mapping.removeMappingListener(this); + + for (E node : nodes) { + node.removeListener(this); + removeActor(node); + node.cleanup(); + } + nodes.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.plant3d/scl/plant3d/scenegraph/EndComponent.scl b/org.simantics.plant3d/scl/plant3d/scenegraph/EndComponent.scl index 5a20dcec..d6688e31 100644 --- a/org.simantics.plant3d/scl/plant3d/scenegraph/EndComponent.scl +++ b/org.simantics.plant3d/scl/plant3d/scenegraph/EndComponent.scl @@ -1,5 +1,4 @@ import "./PipelineComponent" -import "./PipeRun" importJava "org.simantics.plant3d.scenegraph.EndComponent" where data EndComponent diff --git a/org.simantics.plant3d/scl/plant3d/scenegraph/InlineComponent.scl b/org.simantics.plant3d/scl/plant3d/scenegraph/InlineComponent.scl index 1af26ab8..b8055009 100644 --- a/org.simantics.plant3d/scl/plant3d/scenegraph/InlineComponent.scl +++ b/org.simantics.plant3d/scl/plant3d/scenegraph/InlineComponent.scl @@ -1,5 +1,4 @@ import "./PipelineComponent" -import "./PipeRun" importJava "org.simantics.plant3d.scenegraph.InlineComponent" where data InlineComponent diff --git a/org.simantics.plant3d/scl/plant3d/scenegraph/Nozzle.scl b/org.simantics.plant3d/scl/plant3d/scenegraph/Nozzle.scl index 702c4b03..b5b780c6 100644 --- a/org.simantics.plant3d/scl/plant3d/scenegraph/Nozzle.scl +++ b/org.simantics.plant3d/scl/plant3d/scenegraph/Nozzle.scl @@ -1,5 +1,4 @@ import "./PipelineComponent" -import "./PipeRun" importJava "org.simantics.plant3d.scenegraph.Nozzle" where data Nozzle diff --git a/org.simantics.plant3d/scl/plant3d/scenegraph/P3DRootNode.scl b/org.simantics.plant3d/scl/plant3d/scenegraph/P3DRootNode.scl new file mode 100644 index 00000000..29648fe0 --- /dev/null +++ b/org.simantics.plant3d/scl/plant3d/scenegraph/P3DRootNode.scl @@ -0,0 +1,11 @@ +import "g3d/math/Vector3d" +import "g3d/math/Quat4d" +import "g3d/scenegraph/Node" + +importJava "org.simantics.plant3d.scenegraph.P3DRootNode" where + data P3DRootNode + + addChild :: P3DRootNode -> INode -> () + getChild :: P3DRootNode -> [INode] + remChild :: P3DRootNode -> INode -> () + diff --git a/org.simantics.plant3d/scl/plant3d/scenegraph/PipeControlPoint.scl b/org.simantics.plant3d/scl/plant3d/scenegraph/PipeControlPoint.scl deleted file mode 100644 index 139597f9..00000000 --- a/org.simantics.plant3d/scl/plant3d/scenegraph/PipeControlPoint.scl +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/org.simantics.plant3d/scl/plant3d/scenegraph/PipeRun.scl b/org.simantics.plant3d/scl/plant3d/scenegraph/PipeRun.scl deleted file mode 100644 index 2e56a0d6..00000000 --- a/org.simantics.plant3d/scl/plant3d/scenegraph/PipeRun.scl +++ /dev/null @@ -1,4 +0,0 @@ -import "g3d/math/Tuple3d" - -importJava "org.simantics.plant3d.scenegraph.PipeRun" where - data PipeRun \ No newline at end of file diff --git a/org.simantics.plant3d/scl/plant3d/scenegraph/PipelineComponent.scl b/org.simantics.plant3d/scl/plant3d/scenegraph/PipelineComponent.scl index 94dc9a47..f8eab176 100644 --- a/org.simantics.plant3d/scl/plant3d/scenegraph/PipelineComponent.scl +++ b/org.simantics.plant3d/scl/plant3d/scenegraph/PipelineComponent.scl @@ -1,6 +1,6 @@ import "g3d/math/Tuple3d" - -import "./PipeRun" +import "g3d/math/Quat4d" +import "g3d/math/Vector3d" importJava "org.simantics.plant3d.scenegraph.PipelineComponent" where data PipelineComponent @@ -31,14 +31,40 @@ importJava "org.simantics.plant3d.scenegraph.PipelineComponent" where getFlowLength :: PipelineComponent -> Maybe Double getEnds :: PipelineComponent -> Tuple3d -> Tuple3d -> () -importJava "org.simantics.plant3d.scenegraph.PipeControlPoint$Type" where + getOrientation :: PipelineComponent -> Quat4d + getPosition :: PipelineComponent -> Vector3d + + setOrientation :: PipelineComponent -> Quat4d -> () + setPosition :: PipelineComponent -> Vector3d -> () + + getWorldOrientation :: PipelineComponent -> Quat4d + getWorldPosition :: PipelineComponent -> Vector3d + + setWorldOrientation :: PipelineComponent -> Quat4d -> () + setWorldPosition :: PipelineComponent -> Vector3d -> () + +importJava "org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint$PointType" where data PointType -importJava "org.simantics.plant3d.scenegraph.PipeControlPoint.Direction" where + INLINE :: PointType + TURN :: PointType + END :: PointType + +importJava "org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint$Direction" where data Direction -importJava "org.simantics.plant3d.scenegraph.PipeControlPoint.PositionType" where + @JavaName NEXT + DNEXT :: Direction + @JavaName PREVIOUS + DPREVIOUS :: Direction + +importJava "org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint$PositionType" where data PositionType + + NEXT :: PositionType + PREVIOUS :: PositionType + SPLIT :: PositionType + PORT :: PositionType importJava "org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint" where data PipeControlPoint @@ -51,4 +77,19 @@ importJava "org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint" wher isFixed :: PipeControlPoint -> Boolean getSubPoint :: PipeControlPoint -> [PipeControlPoint] - getParentPoint :: PipeControlPoint -> Maybe PipeControlPoint \ No newline at end of file + getParentPoint :: PipeControlPoint -> Maybe PipeControlPoint + +importJava "org.simantics.plant3d.scenegraph.PipeRun" where + data PipeRun + + getTurnRadius :: PipeRun -> Double + setTurnRadius :: PipeRun -> Double -> () + + getPipeDiameter :: PipeRun -> Double + setPipeDiameter :: PipeRun -> Double -> () + + addChild :: PipeRun -> PipelineComponent -> () + getChild :: PipeRun -> [PipelineComponent] + remChild :: PipeRun -> PipelineComponent -> () + + getSortedChild :: PipeRun -> [PipelineComponent] \ No newline at end of file diff --git a/org.simantics.plant3d/scl/plant3d/scenegraph/Root.scl b/org.simantics.plant3d/scl/plant3d/scenegraph/Root.scl deleted file mode 100644 index e69de29b..00000000 diff --git a/org.simantics.plant3d/scl/plant3d/scenegraph/TurnComponent.scl b/org.simantics.plant3d/scl/plant3d/scenegraph/TurnComponent.scl index f6ed6cfe..c5be3778 100644 --- a/org.simantics.plant3d/scl/plant3d/scenegraph/TurnComponent.scl +++ b/org.simantics.plant3d/scl/plant3d/scenegraph/TurnComponent.scl @@ -1,5 +1,4 @@ import "./PipelineComponent" -import "./PipeRun" import "g3d/math/Vector3d" diff --git a/org.simantics.plant3d/scl/plant3d/utils/Loader.scl b/org.simantics.plant3d/scl/plant3d/utils/Loader.scl new file mode 100644 index 00000000..a039f7e7 --- /dev/null +++ b/org.simantics.plant3d/scl/plant3d/utils/Loader.scl @@ -0,0 +1,13 @@ +import "Simantics/DB" +import "plant3d/scenegraph/P3DRootNode" +import "./P3DScriptNodeMap" +import "JavaBuiltin" + +importJava "org.simantics.plant3d.scl.SCLUtil" where + + loadReadOnly :: Resource -> P3DRootNode + load :: Resource -> P3DScriptNodeMap + +safeCoerce :: a -> Maybe b +safeCoerce a = do + (Just $ unsafeCoerce a) `catch` (\(_ :: Exception) -> Nothing) \ No newline at end of file diff --git a/org.simantics.plant3d/scl/plant3d/utils/P3DScriptNodeMap.scl b/org.simantics.plant3d/scl/plant3d/utils/P3DScriptNodeMap.scl new file mode 100644 index 00000000..9f3569fe --- /dev/null +++ b/org.simantics.plant3d/scl/plant3d/utils/P3DScriptNodeMap.scl @@ -0,0 +1,2 @@ +importJava "org.simantics.plant3d.scl.P3DScriptNodeMap" where + data P3DScriptNodeMap \ No newline at end of file diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/editor/P3DContentOutlinePage.java b/org.simantics.plant3d/src/org/simantics/plant3d/editor/P3DContentOutlinePage.java index 0c5ab5df..5a9e8b01 100644 --- a/org.simantics.plant3d/src/org/simantics/plant3d/editor/P3DContentOutlinePage.java +++ b/org.simantics.plant3d/src/org/simantics/plant3d/editor/P3DContentOutlinePage.java @@ -30,7 +30,7 @@ import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint; public class P3DContentOutlinePage extends VTKContentOutlinePage{ - private static final boolean DEBUG = false; + private static final boolean DEBUG = true; protected Menu contextMenu; private LocalResourceManager manager = new LocalResourceManager(JFaceResources.getResources()); diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/P3DRootNode.java b/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/P3DRootNode.java index 5a968604..1e9492a4 100644 --- a/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/P3DRootNode.java +++ b/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/P3DRootNode.java @@ -28,7 +28,8 @@ public class P3DRootNode extends ParentNode implements IG3DNode, NodeMapP @RelatedElementsAdd(Plant3D.URIs.childen) - public void addChild(IP3DVisualNode node) { + public void addChild(INode node) { + //public void addChild(IP3DVisualNode node) { addNode(Plant3D.URIs.childen,node); } @@ -38,7 +39,8 @@ public class P3DRootNode extends ParentNode implements IG3DNode, NodeMapP } @RelatedElementsRem(Plant3D.URIs.childen) - public void remChild(IP3DNode node) { + public void remChild(INode node) { + //public void remChild(IP3DNode node) { removeNode(Plant3D.URIs.childen, node); } diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/PipelineComponent.java b/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/PipelineComponent.java index e200af6b..631894b4 100644 --- a/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/PipelineComponent.java +++ b/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/PipelineComponent.java @@ -14,7 +14,7 @@ import org.simantics.objmap.graph.annotations.RelatedGetObj; import org.simantics.objmap.graph.annotations.RelatedSetObj; import org.simantics.plant3d.ontology.Plant3D; import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint; -import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint.Type; +import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint.PointType; import org.simantics.plant3d.scenegraph.controlpoint.PipingRules; /** @@ -177,7 +177,7 @@ public abstract class PipelineComponent extends GeometryNode { return null; branchPoint = new PipeControlPoint(this,branch0.getPipeRun()); branchPoint.setFixed(false); - branchPoint.setType(Type.END); + branchPoint.setType(PointType.END); branchPoint.parent = getControlPoint(); getControlPoint().children.add(branchPoint); branchPoint.setWorldOrientation(getControlPoint().getWorldOrientation()); diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/controlpoint/ControlPointFactory.java b/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/controlpoint/ControlPointFactory.java index 71602dcc..99b1448c 100644 --- a/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/controlpoint/ControlPointFactory.java +++ b/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/controlpoint/ControlPointFactory.java @@ -11,7 +11,7 @@ import org.simantics.db.exception.DatabaseException; import org.simantics.db.request.Read; import org.simantics.plant3d.ontology.Plant3D; import org.simantics.plant3d.scenegraph.PipelineComponent; -import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint.Type; +import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint.PointType; import org.simantics.plant3d.utils.Item; import org.simantics.plant3d.utils.P3DUtil; @@ -74,7 +74,7 @@ public class ControlPointFactory { private static class Instruction { - Type type; + PointType type; boolean fixed; boolean isOffset; boolean isSizeChange; @@ -95,15 +95,15 @@ public class ControlPointFactory { i.isSizeChange = false; i.isRotate = false; i.isReverse = false; - i.type = Type.INLINE; + i.type = PointType.INLINE; if (graph.isInheritedFrom(res, p3d.Nozzle)) { i.fixed = true; i.isOffset = false; i.isSizeChange = false; - i.type = Type.END; + i.type = PointType.END; } else if (graph.isInheritedFrom(res, p3d.InlineComponent)){ - i.type = Type.INLINE; + i.type = PointType.INLINE; if (graph.hasStatement(res,p3d.VariableLengthInlineComponent)) { i.fixed = false; } else if (graph.hasStatement(res,p3d.FixedLengthInlineComponent)) { @@ -126,7 +126,7 @@ public class ControlPointFactory { } } else if (graph.isInheritedFrom(res, p3d.TurnComponent)) { - i.type = Type.TURN; + i.type = PointType.TURN; if (graph.hasStatement(res,p3d.VariableAngleTurnComponent)) { i.fixed = false; } else if (graph.hasStatement(res,p3d.FixedAngleTurnComponent)) { @@ -134,7 +134,7 @@ public class ControlPointFactory { } } else if (graph.isInheritedFrom(res, p3d.EndComponent)) { i.fixed = false; - i.type = Type.END; + i.type = PointType.END; } else { return null; } diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/controlpoint/PipeControlPoint.java b/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/controlpoint/PipeControlPoint.java index ac76be8b..2d8c00b2 100644 --- a/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/controlpoint/PipeControlPoint.java +++ b/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/controlpoint/PipeControlPoint.java @@ -26,13 +26,13 @@ public class PipeControlPoint extends G3DNode implements IP3DNode { private static boolean DEBUG = false; - public enum Type{INLINE,TURN,END}; + public enum PointType{INLINE,TURN,END}; public enum Direction{NEXT,PREVIOUS}; public enum PositionType {SPLIT,NEXT,PREVIOUS,PORT} private PipelineComponent component; - private Type type; + private PointType type; private boolean fixed = true; private boolean rotate = false; private boolean reverse = false; @@ -69,11 +69,11 @@ public class PipeControlPoint extends G3DNode implements IP3DNode { return component; } - public Type getType() { + public PointType getType() { return type; } - public void setType(Type type) { + public void setType(PointType type) { this.type = type; } @@ -119,19 +119,19 @@ public class PipeControlPoint extends G3DNode implements IP3DNode { } public boolean isPathLegEnd() { - return type != Type.INLINE; + return type != PointType.INLINE; } public boolean isEnd() { - return type == Type.END; + return type == PointType.END; } public boolean isTurn() { - return type == Type.TURN; + return type == PointType.TURN; } public boolean isInline() { - return type == Type.INLINE; + return type == PointType.INLINE; } public boolean isDirected() { @@ -796,9 +796,9 @@ public class PipeControlPoint extends G3DNode implements IP3DNode { } public double getInlineLength() { - if (type == Type.TURN) + if (type == PointType.TURN) return length; - else if (type == Type.INLINE) + else if (type == PointType.INLINE) return length * 0.5; return 0; } diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/scl/P3DScriptNodeMap.java b/org.simantics.plant3d/src/org/simantics/plant3d/scl/P3DScriptNodeMap.java new file mode 100644 index 00000000..b9826ff0 --- /dev/null +++ b/org.simantics.plant3d/src/org/simantics/plant3d/scl/P3DScriptNodeMap.java @@ -0,0 +1,179 @@ +package org.simantics.plant3d.scl; + +import java.util.HashSet; +import java.util.Set; + +import org.simantics.db.ReadGraph; +import org.simantics.db.Session; +import org.simantics.db.exception.DatabaseException; +import org.simantics.g3d.ontology.G3D; +import org.simantics.g3d.scenegraph.base.INode; +import org.simantics.g3d.scenegraph.base.ParentNode; +import org.simantics.g3d.scl.ScriptNodeMap; +import org.simantics.g3d.vtk.common.VtkView; +import org.simantics.objmap.graph.IMapping; +import org.simantics.plant3d.ontology.Plant3D; +import org.simantics.plant3d.scenegraph.IP3DNode; +import org.simantics.plant3d.scenegraph.IP3DVisualNode; +import org.simantics.plant3d.scenegraph.P3DParentNode; +import org.simantics.plant3d.scenegraph.P3DRootNode; +import org.simantics.plant3d.scenegraph.ParameterizedNode; +import org.simantics.plant3d.scenegraph.PipeRun; +import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint; +import org.simantics.plant3d.scenegraph.controlpoint.PipingRules; + +import vtk.vtkProp3D; + +public class P3DScriptNodeMap extends ScriptNodeMap{ + + private static final boolean DEBUG = false; + + public P3DScriptNodeMap(Session session, IMapping mapping, P3DRootNode rootNode) { + super(session,mapping,rootNode); + //rootNode.setNodeMap(this); + } + + @Override + protected void updateActor(INode n, Set ids) { + if (DEBUG) System.out.println("P3DNodeMap update " + n); + if (!(n instanceof IP3DVisualNode)) { + if (n instanceof PipeControlPoint) { + n = ((PipeControlPoint)n).getPipelineComponent(); + if (n == null) + return; + } else { + return; + } + } + + IP3DVisualNode node = (IP3DVisualNode)n; + + if (DEBUG) { + System.out.print("P3DNodeMap update " + node); + for (String s : ids) + System.out.print(" " + s); + System.out.println(); + } + + if (ids.contains(Plant3D.URIs.hasGeometry)) { + //node.visualize(view); + //updateRenderObjectsFor(node); + updateTransform(node); + } + if (n instanceof ParameterizedNode) { + ParameterizedNode geom = (ParameterizedNode)n; + for (String id : geom.getParameterMap().keySet()) { + if (ids.contains(id)) { +// node.visualize(view); +// updateRenderObjectsFor(node); + updateTransform(node); + break; + } + } + } else if (n instanceof PipeRun) { + // FIXME: may require rule based update! + PipeRun run = (PipeRun)n; + Set ids2 = new HashSet(); + ids2.add(Plant3D.URIs.hasGeometry); + for (PipeControlPoint pcp : run.getControlPoints()) { + updateActor(pcp, ids2); + } + } + + if (ids.contains(G3D.URIs.hasPosition) || + ids.contains(G3D.URIs.hasOrientation) || + ids.contains(G3D.URIs.hasWorldPosition) || + ids.contains(G3D.URIs.hasWorldOrientation)) { + updateTransform(node); + } + } + + private void updateTransform(IP3DNode node) { + if (DEBUG) System.out.println("P3DNodeMap update Transform " + node); + + + if (node instanceof ParentNode) { + ParentNode p = (ParentNode)node; + for (IP3DNode n : p.getNodes()) + updateTransform(n); + } + } + + @Override + protected void removeActor(INode n) { + if (DEBUG) System.out.println("P3DNodeMap.removeActor " + n); + if (!(n instanceof IP3DVisualNode)) + return; + IP3DVisualNode node = (IP3DVisualNode)n; +// remActor(node); + + if (node instanceof P3DParentNode) { + for (IP3DNode n2 : ((P3DParentNode)node).getNodes()) + if (n2 instanceof IP3DVisualNode) + removeActor((IP3DVisualNode)n2); + } + } + + @Override + protected void addActor(INode n) { + if (DEBUG) System.out.println("P3DNodeMap.addActor " + n); + if (!(n instanceof IP3DVisualNode)) + return; + IP3DVisualNode node = (IP3DVisualNode)n; + +// if (hasActor(node)) +// return; + + if (node instanceof P3DParentNode) { + for (IP3DNode n2 : ((P3DParentNode)node).getNodes()) + if (n2 instanceof IP3DVisualNode) + addActor((IP3DVisualNode)n2); + } + + updateTransform(node); + } + + @Override + protected void update(ReadGraph graph) throws DatabaseException { + validate(); +// System.out.println("Graph updates"); + super.update(graph); + validate(); + } + + @Override + public void commit(String commitMessage) { + validate(); +// System.out.println("Graph commit"); + super.commit(commitMessage); + + } + @Override + protected void doCommit() throws DatabaseException{ +// System.out.println("Do commit"); + validate(); + super.doCommit(); + } + + private void validate() { + for (INode node : rootNode.getNodes()) { + if (node instanceof PipeRun) + PipingRules.validate((PipeRun)node); + } + } + + @Override + public void update() throws DatabaseException { + try { + boolean b = true; + while (b) { + updateCycle(); + b = PipingRules.update(); + } + } catch (Exception e) { + e.printStackTrace(); + } + super.update(); + } + +} diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/scl/SCLUtil.java b/org.simantics.plant3d/src/org/simantics/plant3d/scl/SCLUtil.java new file mode 100644 index 00000000..9007432b --- /dev/null +++ b/org.simantics.plant3d/src/org/simantics/plant3d/scl/SCLUtil.java @@ -0,0 +1,73 @@ +package org.simantics.plant3d.scl; + + +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.objmap.graph.IMapping; +import org.simantics.objmap.graph.Mappings; +import org.simantics.objmap.graph.schema.IMappingSchema; +import org.simantics.plant3d.scenegraph.P3DRootNode; +import org.simantics.plant3d.scenegraph.SchemaBuilder; +import org.simantics.plant3d.scenegraph.controlpoint.ControlPointFactory; +import org.simantics.plant3d.scenegraph.controlpoint.PipingRules; +import org.simantics.plant3d.utils.ComponentUtils; +import org.simantics.plant3d.utils.P3DUtil; + +public class SCLUtil { + + public static P3DScriptNodeMap load(final Resource root) throws DatabaseException { + try { + ControlPointFactory.preloadCache(); + ComponentUtils.preloadCache(); + } catch (Exception e) { + throw new DatabaseException(e); + } + return Simantics.getSession().syncRequest(new Read() { + @Override + public P3DScriptNodeMap perform(ReadGraph graph) throws DatabaseException { + PipingRules.setEnabled(false); + IMappingSchema schema = SchemaBuilder.getSchema(graph); + IMapping mapping = Mappings.createWithListening(schema); + P3DRootNode rootNode = (P3DRootNode)mapping.map(graph, root); + try { + P3DUtil.finalizeDBLoad(rootNode); + } catch (Exception e) { + throw new DatabaseException(e); + } + P3DScriptNodeMap nodeMap = new P3DScriptNodeMap(Simantics.getSession(), mapping, rootNode); + return nodeMap; + + } + }); + + } + + public static P3DRootNode loadReadOnly(final Resource root) throws DatabaseException { + try { + ControlPointFactory.preloadCache(); + ComponentUtils.preloadCache(); + } catch (Exception e) { + throw new DatabaseException(e); + } + return Simantics.getSession().syncRequest(new Read() { + @Override + public P3DRootNode perform(ReadGraph graph) throws DatabaseException { + PipingRules.setEnabled(false); + IMappingSchema schema = SchemaBuilder.getSchema(graph); + IMapping mapping = Mappings.createWithoutListening(schema); + P3DRootNode rootNode = (P3DRootNode)mapping.map(graph, root); + try { + P3DUtil.finalizeDBLoad(rootNode); + } catch (Exception e) { + throw new DatabaseException(e); + } + return rootNode; + + } + }); + } + +} -- 2.45.2