From: Marko Luukkainen Date: Tue, 13 Aug 2019 14:04:19 +0000 (+0000) Subject: Merge changes Ia3e00f11,I7f3a3a75 X-Git-Tag: v1.43.0~227 X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=commitdiff_plain;h=b8221b6f5e0b6ced872c0b760d796a4c205476af;hp=923dc84d6d22c7b80039dd4e07bec088ab78ea33;p=simantics%2F3d.git Merge changes Ia3e00f11,I7f3a3a75 * changes: Clear removed objects from mapping cache Mark undo pints when committing changes to the graph --- 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 index e4d82492..be196042 100644 --- 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 @@ -1,80 +1,80 @@ -/******************************************************************************* - * Copyright (c) 2012, 2013 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.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); - } - } - -} +/******************************************************************************* + * Copyright (c) 2012, 2013 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.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("Add Boolean Op"); + } 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 index 3a16a21d..55748e78 100644 --- 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 @@ -1,46 +1,46 @@ -/******************************************************************************* - * Copyright (c) 2012, 2013 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.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); - } - } - -} +/******************************************************************************* + * Copyright (c) 2012, 2013 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.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("Add primitive"); + } 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 index ace2262c..cebe1b45 100644 --- 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 @@ -1,60 +1,60 @@ -/******************************************************************************* - * Copyright (c) 2012, 2013 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.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(); - - } - -} +/******************************************************************************* + * Copyright (c) 2012, 2013 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.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("Split"); + + } + +} 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 index df74d2a1..8fcb9368 100644 --- 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 @@ -1,53 +1,53 @@ -/******************************************************************************* - * Copyright (c) 2012, 2013 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.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(); - } -} +/******************************************************************************* + * Copyright (c) 2012, 2013 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.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("Remove"); + node = null; + } + + protected void doRemove(IG3DNode node) { + node.remove(); + } +} diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/awt/RotateAction.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/awt/RotateAction.java index f7ffc553..4f62533b 100644 --- a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/awt/RotateAction.java +++ b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/awt/RotateAction.java @@ -135,7 +135,7 @@ public class RotateAction extends vtkAwtAction{ public void deattach() { node = null; - nodeMap.commit(); + nodeMap.commit("Rotate"); deattachUI(); super.deattach(); panel.repaint(); diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/awt/TranslateAction.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/awt/TranslateAction.java index d7d81331..1b07afa8 100644 --- a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/awt/TranslateAction.java +++ b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/awt/TranslateAction.java @@ -93,7 +93,7 @@ public class TranslateAction extends vtkAwtAction{ public void deattach() { node = null; - nodeMap.commit(); + nodeMap.commit("Translate"); deattachUI(); super.deattach(); panel.repaint(); 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 index 646fbe41..6194ec82 100644 --- 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 @@ -13,6 +13,7 @@ package org.simantics.g3d.vtk.common; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -26,11 +27,14 @@ 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.db.service.UndoRedoSupport; import org.simantics.g3d.ontology.G3D; 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.exceptions.MappingException; import org.simantics.objmap.graph.IMapping; import org.simantics.objmap.graph.IMappingListener; import org.simantics.utils.datastructures.Callback; @@ -41,7 +45,7 @@ import org.simantics.utils.ui.ExceptionUtils; import vtk.vtkProp; -public abstract class AbstractVTKNodeMap implements VTKNodeMap, IMappingListener, RenderListener, NodeListener{ +public abstract class AbstractVTKNodeMap implements VTKNodeMap, IMappingListener, RenderListener, NodeListener, UndoRedoSupport.ChangeListener{ private static final boolean DEBUG = false; @@ -54,6 +58,9 @@ public abstract class AbstractVTKNodeMap implements VTKNodeMap< protected ParentNode rootNode; + protected UndoRedoSupport undoRedoSupport; + protected int undoOpCount = 0; + protected boolean runUndo = false; public AbstractVTKNodeMap(Session session, IMapping mapping, VtkView view, ParentNode rootNode) { this.session = session; this.mapping = mapping; @@ -62,9 +69,18 @@ public abstract class AbstractVTKNodeMap implements VTKNodeMap< view.addListener(this); mapping.addMappingListener(this); rootNode.addListener(this); + + undoRedoSupport = session.getService(UndoRedoSupport.class); + undoRedoSupport.subscribe(this); + try { + undoOpCount = undoRedoSupport.getUndoContext(session).getAll().size(); + } catch(DatabaseException e) { + e.printStackTrace(); + } } + protected abstract void addActor(E node); protected abstract void removeActor(E node); protected abstract void updateActor(E node,Set ids); @@ -121,6 +137,25 @@ public abstract class AbstractVTKNodeMap implements VTKNodeMap< private boolean rangeModified = false; + @Override + public void onChanged() { + try { + int count = undoRedoSupport.getUndoContext(session).getAll().size(); + if (count < undoOpCount) { + runUndo = true; + } else { + runUndo = false; + } + undoOpCount = count; + if (DEBUG) System.out.println("Undo " + runUndo); + } catch (DatabaseException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + + } + @SuppressWarnings("unchecked") @Override public void updateRenderObjectsFor(INode node) { @@ -152,7 +187,7 @@ public abstract class AbstractVTKNodeMap implements VTKNodeMap< @SuppressWarnings("unchecked") private void receiveAdd(E node, String id, boolean db) { - if (DEBUG) System.out.println("receiveAdd " + node + " " + id + " " + db); + if (DEBUG) System.out.println("receiveAdd " + debugString(node) + " " + id + " " + db); synchronized (syncMutex) { for (Pair n : added) { if (n.first.equals(node)) @@ -169,7 +204,7 @@ public abstract class AbstractVTKNodeMap implements VTKNodeMap< @SuppressWarnings("unchecked") private void receiveRemove(E node, String id, boolean db) { - if (DEBUG) System.out.println("receiveRemove " + node + " " + id + " " + db); + if (DEBUG) System.out.println("receiveRemove " + debugString(node) + " " + id + " " + db); synchronized (syncMutex) { for (Pair n : removed) { if (n.first.equals(node)) @@ -185,7 +220,7 @@ public abstract class AbstractVTKNodeMap implements VTKNodeMap< @SuppressWarnings("unchecked") private void receiveUpdate(E node, String id, boolean db) { - if (DEBUG) System.out.println("receiveUpdate " + node + " " + id + " " + db); + if (DEBUG) System.out.println("receiveUpdate " + debugString(node) + " " + id + " " + db); synchronized (syncMutex) { // for (Pair n : updated) { // if (n.first.equals(node)) @@ -204,10 +239,12 @@ public abstract class AbstractVTKNodeMap implements VTKNodeMap< private Set graphModified = new HashSet(); private boolean requestCommit = false; + private String commitMessage = null; @Override - public void commit() { + public void commit(String message) { requestCommit = true; + commitMessage = message; } protected void doCommit() { @@ -215,7 +252,13 @@ public abstract class AbstractVTKNodeMap implements VTKNodeMap< @Override public void perform(WriteGraph graph) throws DatabaseException { - commit(graph); + if (DEBUG) System.out.println("Commit " + commitMessage); + if (commitMessage != null) { + Layer0Utils.addCommentMetadata(graph, commitMessage); + graph.markUndoPoint(); + commitMessage = null; + } + commit(graph); } }, new Callback() { @@ -234,9 +277,13 @@ public abstract class AbstractVTKNodeMap implements VTKNodeMap< graphUpdates = true; mapping.updateDomain(graph); graphUpdates = false; + clearDeletes(); + if (DEBUG) System.out.println("Commit done"); } } + + @Override public void domainModified() { if (graphUpdates) @@ -253,21 +300,45 @@ public abstract class AbstractVTKNodeMap implements VTKNodeMap< } + 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; + } + } + + private boolean useFullSyncWithUndo = false; + 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 (DEBUG) System.out.println("Graph update start"); + if (runUndo && useFullSyncWithUndo) { + reset(graph); + } else { + 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()) - commit(); + //if (mapping.isRangeModified() && !runUndo) // FIXME : redo? + if (mapping.isRangeModified()) + commit((String)null); + if (DEBUG) System.out.println("Graph update done"); } @Override @@ -287,18 +358,62 @@ public abstract class AbstractVTKNodeMap implements VTKNodeMap< } } - List> rem = new ArrayList>(); - List> add = new ArrayList>(); - MapSet mod = new MapSet.Hash(); - Set propagation = new HashSet(); - Stack stack = new Stack(); - + // 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(); @Override public synchronized void preRender() { updateCycle(); } + + /** + * 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(); @@ -306,6 +421,7 @@ public abstract class AbstractVTKNodeMap implements VTKNodeMap< mod.clear(); propagation.clear(); + synchronized (syncMutex) { rem.addAll(removed); add.addAll(added); @@ -314,7 +430,7 @@ public abstract class AbstractVTKNodeMap implements VTKNodeMap< mod.add(e, s); } } - + syncDeletes(); removed.clear(); added.clear(); updated.clear(); @@ -323,7 +439,6 @@ public abstract class AbstractVTKNodeMap implements VTKNodeMap< for (Pair n : rem) { stopListening(n.first); removeActor(n.first); - } for (Pair n : add) { @@ -400,8 +515,9 @@ public abstract class AbstractVTKNodeMap implements VTKNodeMap< for (String s : mod.getValues(e)) l.propertyChanged(e, s); } + synchronized (syncMutex) { - if (added.isEmpty() && removed.isEmpty() && updated.getKeys().size() == 0) + if (added.isEmpty() && removed.isEmpty() && updated.getKeys().size() == 0) rangeModified = false; } } @@ -459,6 +575,9 @@ public abstract class AbstractVTKNodeMap implements VTKNodeMap< @Override public void delete() { + if (undoRedoSupport != null) + undoRedoSupport.cancel(this); + changeTracking = false; view.removeListener(this); mapping.removeMappingListener(this); diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/swt/RotateAction.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/swt/RotateAction.java index 1b2d7914..c45316e8 100644 --- a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/swt/RotateAction.java +++ b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/swt/RotateAction.java @@ -141,7 +141,7 @@ public class RotateAction extends vtkSwtAction{ public void deattach() { node = null; - nodeMap.commit(); + nodeMap.commit("Rotate"); deattachUI(); super.deattach(); panel.refresh(); diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/swt/TranslateAction.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/swt/TranslateAction.java index b6b5ca7f..83c434bb 100644 --- a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/swt/TranslateAction.java +++ b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/swt/TranslateAction.java @@ -99,7 +99,7 @@ public class TranslateAction extends vtkSwtAction{ public void deattach() { node = null; - nodeMap.commit(); + nodeMap.commit("Translate"); deattachUI(); super.deattach(); panel.refresh(); diff --git a/org.simantics.g3d/src/org/simantics/g3d/property/AnnotatedPropertyTabContributorFactory.java b/org.simantics.g3d/src/org/simantics/g3d/property/AnnotatedPropertyTabContributorFactory.java index c3d7376f..a3fca78b 100644 --- a/org.simantics.g3d/src/org/simantics/g3d/property/AnnotatedPropertyTabContributorFactory.java +++ b/org.simantics.g3d/src/org/simantics/g3d/property/AnnotatedPropertyTabContributorFactory.java @@ -799,7 +799,7 @@ public class AnnotatedPropertyTabContributorFactory implements PropertyTabContri if (DEBUG)System.err.println("CELL SET VALUE: " + element + " " + value); manipulator.setValue((String)value,index); viewer.refresh(item); - nodeMap.commit(); + nodeMap.commit("Set " + item.id + " value to " + value); } diff --git a/org.simantics.g3d/src/org/simantics/g3d/scenegraph/NodeMap.java b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/NodeMap.java index 6324d90e..36ee73a3 100644 --- a/org.simantics.g3d/src/org/simantics/g3d/scenegraph/NodeMap.java +++ b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/NodeMap.java @@ -31,7 +31,7 @@ public interface NodeMap { /** * Commit changes to the database. */ - public void commit(); + public void commit(String message); /** diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/actions/AddComponentAction.java b/org.simantics.plant3d/src/org/simantics/plant3d/actions/AddComponentAction.java index a4398a54..18087b68 100644 --- a/org.simantics.plant3d/src/org/simantics/plant3d/actions/AddComponentAction.java +++ b/org.simantics.plant3d/src/org/simantics/plant3d/actions/AddComponentAction.java @@ -117,7 +117,7 @@ public class AddComponentAction extends vtkSwtAction { public void deattach() { // deactivate(); component = null; - nodeMap.commit(); + nodeMap.commit("Add component"); deattachUI(); super.deattach(); panel.refresh(); diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/actions/AddEquipmentAction.java b/org.simantics.plant3d/src/org/simantics/plant3d/actions/AddEquipmentAction.java index 6c66909a..ae7603ca 100644 --- a/org.simantics.plant3d/src/org/simantics/plant3d/actions/AddEquipmentAction.java +++ b/org.simantics.plant3d/src/org/simantics/plant3d/actions/AddEquipmentAction.java @@ -25,7 +25,7 @@ public class AddEquipmentAction extends Action { String n = root.getUniqueName(item.getName()); equipment.setName(n); root.addChild(equipment); - root.getNodeMap().commit(); + root.getNodeMap().commit("Add equipment " + n); } catch (Exception e) { ExceptionUtils.logAndShowError("Cannot create equipment",e); } diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/actions/AddNozzleAction.java b/org.simantics.plant3d/src/org/simantics/plant3d/actions/AddNozzleAction.java index e6b8ecd6..34069d95 100644 --- a/org.simantics.plant3d/src/org/simantics/plant3d/actions/AddNozzleAction.java +++ b/org.simantics.plant3d/src/org/simantics/plant3d/actions/AddNozzleAction.java @@ -41,7 +41,7 @@ public class AddNozzleAction extends Action { equipment.addChild(nozzle); //root.addChild(nozzle); root.addChild(pipeRun); - root.getNodeMap().commit(); + root.getNodeMap().commit("Add nozzle " + n); } catch (Exception e) { ExceptionUtils.logAndShowError("Cannot create equipment",e); } diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/actions/RoutePipeAction.java b/org.simantics.plant3d/src/org/simantics/plant3d/actions/RoutePipeAction.java index da7beb45..17455a32 100644 --- a/org.simantics.plant3d/src/org/simantics/plant3d/actions/RoutePipeAction.java +++ b/org.simantics.plant3d/src/org/simantics/plant3d/actions/RoutePipeAction.java @@ -111,7 +111,7 @@ public class RoutePipeAction extends vtkSwtAction { public void deattach() { deactivate(); startComponent = null; - nodeMap.commit(); + nodeMap.commit("Route pipe"); deattachUI(); super.deattach(); panel.refresh(); diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/actions/TranslateInlineAction.java b/org.simantics.plant3d/src/org/simantics/plant3d/actions/TranslateInlineAction.java index 23096f7e..7ea42d59 100644 --- a/org.simantics.plant3d/src/org/simantics/plant3d/actions/TranslateInlineAction.java +++ b/org.simantics.plant3d/src/org/simantics/plant3d/actions/TranslateInlineAction.java @@ -46,9 +46,9 @@ public class TranslateInlineAction extends TranslateAction{ setEnabled(false); return; } - if (prev.getControlPoint().isInline() && !prev.getControlPoint().isFixed()) + if (prev.getControlPoint().isInline() && !prev.getControlPoint().isFixed() && prev.getPrevious() != null) prev = prev.getPrevious(); - if (next.getControlPoint().isInline() && !next.getControlPoint().isFixed()) { + if (next.getControlPoint().isInline() && !next.getControlPoint().isFixed() && next.getNext() != null) { next = next.getNext(); } Point3d ns = new Point3d(); @@ -61,8 +61,14 @@ public class TranslateInlineAction extends TranslateAction{ dir.normalize(); // We may have offsets in the path leg, hence we have to project the coordinates. Vector3d wp = node.getWorldPosition(); - s = MathTools.closestPointOnStraight(pe, wp, dir); - e = MathTools.closestPointOnStraight(ns, wp, dir); + if (prev.getControlPoint().isVariableLength()) + s = MathTools.closestPointOnStraight(ps, wp, dir); + else + s = MathTools.closestPointOnStraight(pe, wp, dir); + if (next.getControlPoint().isVariableLength()) + e = MathTools.closestPointOnStraight(ne, wp, dir); + else + e = MathTools.closestPointOnStraight(ns, wp, dir); // Remove component's own space from end points to get actual movement range double l = comp.getControlPoint().getInlineLength(); Vector3d ld = new Vector3d(dir); diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/editor/P3DNodeMap.java b/org.simantics.plant3d/src/org/simantics/plant3d/editor/P3DNodeMap.java index ea379520..46f3bf64 100644 --- a/org.simantics.plant3d/src/org/simantics/plant3d/editor/P3DNodeMap.java +++ b/org.simantics.plant3d/src/org/simantics/plant3d/editor/P3DNodeMap.java @@ -199,10 +199,10 @@ public class P3DNodeMap extends AbstractVTKNodeMap { } @Override - public void commit() { + public void commit(String commitMessage) { validate(); // System.out.println("Graph commit"); - super.commit(); + super.commit(commitMessage); } @Override 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 26a32397..36c6dde1 100644 --- a/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/PipelineComponent.java +++ b/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/PipelineComponent.java @@ -88,7 +88,10 @@ public abstract class PipelineComponent extends GeometryNode { public void setNext(PipelineComponent comp) { if (next == comp) return; + if (comp == null) + this.next._removeRef(this); this.next = comp; + this.syncnext = false; syncNext(); firePropertyChanged(Plant3D.URIs.HasNext); if (comp != null) @@ -106,8 +109,11 @@ public abstract class PipelineComponent extends GeometryNode { public void setPrevious(PipelineComponent comp) { if (previous == comp) return; + if (comp == null) + this.previous._removeRef(this); this.previous = comp; - + this.syncprev = false; + syncPrevious(); firePropertyChanged(Plant3D.URIs.HasPrevious); if (comp != null) comp.sync(); @@ -124,7 +130,10 @@ public abstract class PipelineComponent extends GeometryNode { public void setBranch0(PipelineComponent comp) { if (branch0 == comp) return; + if (comp == null) + this.branch0._removeRef(this); this.branch0 = comp; + this.syncbr0 = false; syncBranch0(); firePropertyChanged(Plant3D.URIs.HasBranch0); if (comp != null) @@ -132,8 +141,29 @@ public abstract class PipelineComponent extends GeometryNode { // System.out.println(this + " next " + comp); } + @GetPropertyValue(name="Previous",tabId="Debug",value=Plant3D.URIs.HasPrevious) + public String getPreviousDebug() { + if (previous == null) + return null; + return previous.getName(); + } + + @GetPropertyValue(name="Next",tabId="Debug",value=Plant3D.URIs.HasNext) + public String getNextDebug() { + if (next == null) + return null; + return next.getName(); + } + + @GetPropertyValue(name="Branch0",tabId="Debug",value=Plant3D.URIs.HasBranch0) + public String getBR0Debug() { + if (branch0 == null) + return null; + return branch0.getName(); + } + private PipeControlPoint getBranchPoint() { PipeControlPoint branchPoint; if (getControlPoint().getSubPoint().size() > 0) { @@ -182,28 +212,56 @@ public abstract class PipelineComponent extends GeometryNode { return true; } + // When link to a component is removed, also link to the other direction must be removed at the same time, or + // Control point structure is left into illegal state. + private void _removeRef(PipelineComponent comp) { + if (next == comp) { + next = null; + syncnext = false; + syncNext(); + } else if (previous == comp) { + previous = null; + syncprev = false; + syncPrevious(); + } else if (branch0 == comp) { + branch0 = null; + syncbr0 = false; + syncBranch0(); + } + } + + boolean syncnext = false; + private void syncNext() { + if (syncnext) + return; + syncnext = _syncNext(); + } - private boolean syncNext() { - - if (getControlPoint() != null) { + private boolean _syncNext() { + PipeControlPoint pcp = getControlPoint(); + if (pcp != null) { + if (next != null ) { - if (next.getControlPoint() != null && next.getPipeRun() != null) { + if (next.getControlPoint() != null) { // TODO, relying that the other direction is connected. boolean nxt = next.getPrevious() == this; boolean br0 = next.getBranch0() == this; if (nxt){ - return _connectNext(getControlPoint(), next.getControlPoint()); + return _connectNext(pcp, next.getControlPoint()); } else if (br0) { - return _connectNext(getControlPoint(), next.getBranchPoint()); + return _connectNext(pcp, next.getBranchPoint()); + } else { + return false; } } else { return false; } - } else if (getControlPoint().getPrevious() != null) { - getControlPoint().setNext(null); + } else if (pcp.getNext() != null) { + pcp.setNext(null); + return true; } } else { return false; @@ -211,26 +269,36 @@ public abstract class PipelineComponent extends GeometryNode { return true; } - private boolean syncPrevious() { - - if (getControlPoint() != null) { + boolean syncprev = false; + private void syncPrevious() { + if (syncprev) + return; + syncprev = _syncPrevious(); + } + + private boolean _syncPrevious() { + PipeControlPoint pcp = getControlPoint(); + if (pcp != null) { if (previous != null ) { - if (previous.getControlPoint() != null && previous.getPipeRun() != null) { + if (previous.getControlPoint() != null) { // TODO, relying that the other direction is connected. boolean prev = previous.getNext() == this; boolean br0 = previous.getBranch0() == this; if (prev){ - return _connectPrev(getControlPoint(), previous.getControlPoint()); + return _connectPrev(pcp, previous.getControlPoint()); } else if (br0) { - return _connectPrev(getControlPoint(), previous.getBranchPoint()); + return _connectPrev(pcp, previous.getBranchPoint()); + } else { + return false; } } else { return false; } - } else if (getControlPoint().getPrevious() != null) { - getControlPoint().setPrevious(null); + } else if (pcp.getPrevious() != null) { + pcp.setPrevious(null); + return true; } } else { return false; @@ -238,14 +306,21 @@ public abstract class PipelineComponent extends GeometryNode { return true; } - private boolean syncBranch0() { + boolean syncbr0 = false; + private void syncBranch0() { + if (syncbr0) + return; + syncbr0 = _syncBranch0(); + } + + private boolean _syncBranch0() { if (getControlPoint() != null) { if (getControlPoint().isDualInline()) { branch0 = null; return false; } if (branch0 != null) { - if (branch0.getControlPoint() != null && branch0.getPipeRun() != null) { + if (branch0.getControlPoint() != null) { PipeControlPoint branchPoint = getBranchPoint(); PipeControlPoint pcp = branch0.getControlPoint(); // TODO, relying that the other direction is connected. @@ -255,7 +330,10 @@ public abstract class PipelineComponent extends GeometryNode { _connectNext(branchPoint, pcp); } else if (prev){ _connectPrev(branchPoint, pcp); + } else { + return false; } + } else { return false; } @@ -263,6 +341,7 @@ public abstract class PipelineComponent extends GeometryNode { } else if (getControlPoint().getSubPoint().size() > 0) { // TODO : this may cause problems? (Removes branch point, before branch has been set?) getControlPoint().getSubPoint().get(0).remove(); getControlPoint().children.clear(); + return true; } } else { return false; 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 22c58ddb..fc78f1b9 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 @@ -22,6 +22,8 @@ import vtk.vtkRenderer; public class PipeControlPoint extends G3DNode implements IP3DNode { + + private static boolean DEBUG = false; public enum Type{INLINE,TURN,END}; public enum Direction{NEXT,PREVIOUS}; @@ -186,8 +188,9 @@ public class PipeControlPoint extends G3DNode implements IP3DNode { public void setNext(PipeControlPoint next) { if (isEnd() && previous != null && next != null) throw new RuntimeException("End control points are allowed to have only one connection"); -// if (next != null && getPipeRun() == null) -// throw new RuntimeException("Cannot connect control point befor piperun has been set"); + if (this.next == next) + return; + if (DEBUG) System.out.println(this + " next " + next); this.next = next; if (component != null) { if (parent == null || sub) @@ -202,8 +205,9 @@ public class PipeControlPoint extends G3DNode implements IP3DNode { public void setPrevious(PipeControlPoint previous) { if (isEnd() && next != null && previous != null) throw new RuntimeException("End control points are allowed to have only one connection"); -// if (previous != null && getPipeRun() == null) -// throw new RuntimeException("Cannot connect control point befor piperun has been set"); + if (this.previous == previous) + return; + if (DEBUG) System.out.println(this + " previous " + previous); this.previous = previous; if (component != null) { if (parent == null || sub) @@ -225,14 +229,8 @@ public class PipeControlPoint extends G3DNode implements IP3DNode { public PipeControlPoint getParentPoint() { return parent; } - - - - - - private double length; private Double turnAngle; private Vector3d turnAxis; @@ -300,7 +298,9 @@ public class PipeControlPoint extends G3DNode implements IP3DNode { } public void setTurnAxis(Vector3d turnAxis) { - this.turnAxis = turnAxis; + if (this.turnAxis != null && MathTools.equals(turnAxis, this.turnAxis)) + return; + this.turnAxis = turnAxis; firePropertyChanged("turnAxis"); } @@ -483,6 +483,8 @@ public class PipeControlPoint extends G3DNode implements IP3DNode { dir.sub(pcp.getWorldPosition(),previous.getWorldPosition()); if (dir.lengthSquared() > MathTools.NEAR_ZERO) dir.normalize(); + else + return null; Quat4d q = getControlPointOrientationQuat(dir, pcp.getRotationAngle() != null ? pcp.getRotationAngle() : 0.0); AxisAngle4d aa = new AxisAngle4d(MathTools.Y_AXIS,pcp.getTurnAngle() == null ? 0.0 : pcp.getTurnAngle()); Quat4d q2 = MathTools.getQuat(aa); @@ -499,6 +501,8 @@ public class PipeControlPoint extends G3DNode implements IP3DNode { dir.sub(next.getWorldPosition(),pcp.getWorldPosition()); if (dir.lengthSquared() > MathTools.NEAR_ZERO) dir.normalize(); + else + return null; Quat4d q = getControlPointOrientationQuat(dir, pcp.getRotationAngle() != null ? pcp.getRotationAngle() : 0.0); AxisAngle4d aa = new AxisAngle4d(MathTools.Y_AXIS,pcp.getTurnAngle() == null ? 0.0 : pcp.getTurnAngle()); Quat4d q2 = MathTools.getQuat(aa); @@ -1149,18 +1153,34 @@ public class PipeControlPoint extends G3DNode implements IP3DNode { if (component == null) return; PipelineComponent next = component.getNext(); - PipelineComponent prev = component.getNext(); + PipelineComponent prev = component.getPrevious(); + PipelineComponent br0 = component.getBranch0(); + component.setNext(null); + component.setPrevious(null); + component.setBranch0(null); if (next != null) { if (next.getNext() == component) next.setNext(null); else if (next.getPrevious() == component) next.setPrevious(null); + else if (next.getBranch0() == component) + next.setBranch0(null); } if (prev != null) { if (prev.getNext() == component) prev.setNext(null); else if (prev.getPrevious() == component) prev.setPrevious(null); + else if (prev.getBranch0() == component) + prev.setBranch0(null); + } + if (br0 != null) { + if (br0.getNext() == component) + prev.setNext(null); + else if (br0.getPrevious() == component) + prev.setPrevious(null); + else if (br0.getBranch0() == component) + br0.setBranch0(null); } PipelineComponent comp = component; component = null; diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/controlpoint/PipingRules.java b/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/controlpoint/PipingRules.java index be66cf14..67c5f35b 100644 --- a/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/controlpoint/PipingRules.java +++ b/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/controlpoint/PipingRules.java @@ -1612,7 +1612,7 @@ public class PipingRules { turnAngle = 0.0; tcp.setTurnAngle(0.0); tcp.setLength(0.0); - tcp.setTurnAxis(MathTools.Y_AXIS); + tcp.setTurnAxis(new Vector3d(MathTools.Y_AXIS)); } updateControlPointOrientation(tcp); if (DEBUG) @@ -1731,7 +1731,7 @@ public class PipingRules { } List runPcps = getControlPoints(pipeRun); if (runPcps.size() != count) { - System.out.println("Run is not connected"); + System.out.println("Run " + pipeRun.getName() + " contains unconnected control points"); } for (PipeControlPoint pcp : pcps) { if (!pcp.isDirected() && pcp.getNext() == null && pcp.getPrevious() == null)