]> gerrit.simantics Code Review - simantics/3d.git/commitdiff
Additional SCL Bindings to G3D and Plant3D classes 11/3111/1
authorMarko Luukkainen <marko.luukkainen@semantum.fi>
Fri, 16 Aug 2019 12:43:24 +0000 (15:43 +0300)
committerMarko Luukkainen <marko.luukkainen@semantum.fi>
Fri, 16 Aug 2019 12:43:24 +0000 (15:43 +0300)
gitlab #28

Change-Id: I1f3b29cd84ac60a16c58736ddae31792393a08ec

23 files changed:
org.simantics.g3d/META-INF/MANIFEST.MF
org.simantics.g3d/scl/g3d/scenegraph/G3DNode.scl [new file with mode: 0644]
org.simantics.g3d/scl/g3d/scenegraph/G3DParentNode.scl [new file with mode: 0644]
org.simantics.g3d/scl/g3d/scenegraph/Node.scl [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/scl/ScriptNodeMap.java [new file with mode: 0644]
org.simantics.plant3d/scl/plant3d/scenegraph/EndComponent.scl
org.simantics.plant3d/scl/plant3d/scenegraph/InlineComponent.scl
org.simantics.plant3d/scl/plant3d/scenegraph/Nozzle.scl
org.simantics.plant3d/scl/plant3d/scenegraph/P3DRootNode.scl [new file with mode: 0644]
org.simantics.plant3d/scl/plant3d/scenegraph/PipeControlPoint.scl [deleted file]
org.simantics.plant3d/scl/plant3d/scenegraph/PipeRun.scl [deleted file]
org.simantics.plant3d/scl/plant3d/scenegraph/PipelineComponent.scl
org.simantics.plant3d/scl/plant3d/scenegraph/Root.scl [deleted file]
org.simantics.plant3d/scl/plant3d/scenegraph/TurnComponent.scl
org.simantics.plant3d/scl/plant3d/utils/Loader.scl [new file with mode: 0644]
org.simantics.plant3d/scl/plant3d/utils/P3DScriptNodeMap.scl [new file with mode: 0644]
org.simantics.plant3d/src/org/simantics/plant3d/editor/P3DContentOutlinePage.java
org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/P3DRootNode.java
org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/PipelineComponent.java
org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/controlpoint/ControlPointFactory.java
org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/controlpoint/PipeControlPoint.java
org.simantics.plant3d/src/org/simantics/plant3d/scl/P3DScriptNodeMap.java [new file with mode: 0644]
org.simantics.plant3d/src/org/simantics/plant3d/scl/SCLUtil.java [new file with mode: 0644]

index bacef662041831a4ef58b4bc16eba5600fb83d0e..c479403d10aa7d89cb39aad2e34dd700f4b39d18 100644 (file)
@@ -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 (file)
index 0000000..64b6809
--- /dev/null
@@ -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 (file)
index 0000000..d9e9214
--- /dev/null
@@ -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 (file)
index 0000000..84d7fc4
--- /dev/null
@@ -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 (file)
index 0000000..359f5c3
--- /dev/null
@@ -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 <E>
+ */
+public abstract class ScriptNodeMap<E extends INode> implements NodeMap<Object,E>, IMappingListener, NodeListener {
+
+    private static final boolean DEBUG = false;
+    
+    protected Session session;
+    protected IMapping<Object,E> mapping;
+    
+    protected ParentNode<E> rootNode;
+    
+    protected Set<E> nodes = new HashSet<E>();
+    
+    private boolean dirty = false;
+    
+    public ScriptNodeMap(Session session, IMapping<Object,E> mapping, ParentNode<E> 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<String> 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<Object> getRenderObjects(INode node) {
+        return Collections.EMPTY_LIST;
+    }
+    
+    @SuppressWarnings("unchecked")
+    @Override
+    public ParentNode<E> getRootNode() {
+        return (ParentNode<E>)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<Pair<E,String>> added = new ArrayList<Pair<E,String>>();
+    private List<Pair<E,String>> removed = new ArrayList<Pair<E,String>>();
+    private MapSet<E, String> updated = new MapSet.Hash<E, String>();
+
+    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<E, String> n : added) {
+                if (n.first.equals(node))
+                    return;
+            }
+            if (changeTracking) {
+                mapping.rangeModified((E)node.getParent());
+            }
+            added.add(new Pair<E, String>(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<E, String> n : removed) {
+                if (n.first.equals(node))
+                    return;
+            }
+            if (changeTracking && !db)
+                mapping.rangeModified((E)node.getParent());
+            removed.add(new Pair<E, String>(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<E, String> n : updated) {
+//              if (n.first.equals(node))
+//                  return;
+//          }
+            if (changeTracking && !db)
+                mapping.rangeModified(node);
+            //updated.add(new Pair<E, String>(node, id));
+            updated.add(node, id);
+            rangeModified = true;
+        }
+        repaint();
+    }
+    
+    private boolean graphUpdates = false;
+    private Set<E> graphModified = new HashSet<E>();
+    
+    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<Pair<E, String>> rem = new ArrayList<Pair<E,String>>();  // Removed objects
+    List<Pair<E, String>> add = new ArrayList<Pair<E,String>>();  // Added objects
+    MapSet<E, String> mod = new MapSet.Hash<E, String>();         // Modified objects
+    Set<E> propagation = new HashSet<E>();                        // Objects with propagated changes 
+    Stack<E> stack = new Stack<E>();                              // Stack for handling propagation
+    Set<E> delete = Collections.synchronizedSet(new HashSet<E>()); // Objects to be completely deleted
+    Set<E> deleteUC = new HashSet<E>();
+    
+   
+    
+    
+    /**
+     * 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<E, String> n : removed) {
+            deleteUC.add(n.first);   
+         }
+         for (Pair<E, String> 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<E, String> n : rem) {
+            stopListening(n.first);
+            removeActor(n.first);
+        }
+        
+        for (Pair<E, String> n : add) {
+            addActor(n.first);
+            listen(n.first);
+        }
+        
+        for (E e : mod.getKeys()) {
+            Set<String> 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<E>)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<String> ids = mod.getValues(e);
+            updateActor(e,ids);
+        }
+        
+        
+        for (Pair<E, String> n : rem) {
+            for (NodeListener l : nodeListeners)
+                l.nodeRemoved(null, n.first, n.second);
+        }
+        for (Pair<E, String> n : add) {
+            for (NodeListener l : nodeListeners)
+                l.nodeAdded(n.first.getParent(), n.first, n.second);
+        }
+//      for (Pair<E, String> 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<INode> parentNode = (ParentNode<INode>)node;
+            for (INode n : parentNode.getNodes())
+                listen(n);
+        }
+    }
+    
+    private void stopListening(INode node) {
+        node.removeListener(this);
+        if (node instanceof ParentNode<?>) {
+            @SuppressWarnings("unchecked")
+            ParentNode<INode> parentNode = (ParentNode<INode>)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 <T extends INode> void nodeAdded(ParentNode<T> 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 <T extends INode> void nodeRemoved(ParentNode<T> 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<NodeListener> nodeListeners = new ArrayList<NodeListener>();
+    @Override
+    public void addListener(NodeListener listener) {
+        nodeListeners.add(listener);
+        
+    }
+    
+    @Override
+    public void removeListener(NodeListener listener) {
+        nodeListeners.remove(listener);
+        
+    }
+    
+    public IMapping<Object,E> getMapping() {
+        return mapping;
+    }
+    
+    
+}
index 5a20dcecca80f52ce26624b2877fe8662fd88c31..d6688e314ad5bee5f1707f79f40c589b24123076 100644 (file)
@@ -1,5 +1,4 @@
 import "./PipelineComponent"
-import "./PipeRun"
 
 importJava "org.simantics.plant3d.scenegraph.EndComponent" where
   data EndComponent
index 1af26ab8a571f6551b330a733e048e3686146c59..b8055009aaf0f920968c285d69db0175292ff594 100644 (file)
@@ -1,5 +1,4 @@
 import "./PipelineComponent"
-import "./PipeRun"
 
 importJava "org.simantics.plant3d.scenegraph.InlineComponent" where
   data InlineComponent
index 702c4b0354a0e58c8ffd71b9f769bae1298170a6..b5b780c6b2dad5b305cf4110bf9e5bf826ec87bc 100644 (file)
@@ -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 (file)
index 0000000..29648fe
--- /dev/null
@@ -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 (file)
index 139597f..0000000
+++ /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 (file)
index 2e56a0d..0000000
+++ /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
index 94dc9a47fb16c6e873bfa049eb85bb2296aca083..f8eab1766c9620fcc7ad975bfa7c0d9d87046360 100644 (file)
@@ -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 (file)
index e69de29..0000000
index f6ed6cfec0d217abd63b86c9d22d654e38c06b23..c5be3778a078037e3d8d5cb4bd1b91f50338f2bc 100644 (file)
@@ -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 (file)
index 0000000..a039f7e
--- /dev/null
@@ -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 (file)
index 0000000..9f3569f
--- /dev/null
@@ -0,0 +1,2 @@
+importJava "org.simantics.plant3d.scl.P3DScriptNodeMap" where
+   data P3DScriptNodeMap
\ No newline at end of file
index 0c5ab5df39e0cdf842a953694072a13af4864cb2..5a9e8b01e32cf899a1e452cc7c4420737c30728f 100644 (file)
@@ -30,7 +30,7 @@ import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint;
 
 public class P3DContentOutlinePage extends VTKContentOutlinePage<Resource, Object>{
        
-       private static final boolean DEBUG = false;
+       private static final boolean DEBUG = true;
        protected Menu contextMenu;
        
        private LocalResourceManager manager = new LocalResourceManager(JFaceResources.getResources());
index 5a968604f29ba6c8659e61198813b291ea85c0ea..1e9492a45297252e5cf63bdcb23e15f86989b7be 100644 (file)
@@ -28,7 +28,8 @@ public class P3DRootNode extends ParentNode<INode> 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<INode> 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);
        }
        
index e200af6b2c852419ffbae9f3334ce2744cbf256b..631894b485d0f86bcf10024f0823b228dcddf19d 100644 (file)
@@ -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());
index 71602dcc0ff163220a36b741a78ec9c4d082111d..99b1448cb8e498decc9c8eef3f7655bd0fdea324 100644 (file)
@@ -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;
                                }
index ac76be8b25f373f1e133cb1c2860b52433343548..2d8c00b22f5c20f7e09da25b99da30db78b1662d 100644 (file)
@@ -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 (file)
index 0000000..b9826ff
--- /dev/null
@@ -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<INode>{
+    
+    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<String> 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<String> ids2 = new HashSet<String>();
+            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<IP3DNode> p = (ParentNode<IP3DNode>)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 (file)
index 0000000..9007432
--- /dev/null
@@ -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<P3DScriptNodeMap>() {
+            @Override
+            public P3DScriptNodeMap perform(ReadGraph graph) throws DatabaseException {
+                PipingRules.setEnabled(false);
+                IMappingSchema<Resource, Object> 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<P3DRootNode>() {
+            @Override
+            public P3DRootNode perform(ReadGraph graph) throws DatabaseException {
+                PipingRules.setEnabled(false);
+                IMappingSchema<Resource, Object> 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;
+                
+            }
+        });
+    }
+
+}