]> gerrit.simantics Code Review - simantics/3d.git/commitdiff
latest release (0.41), third attempt
authorluukkainen <luukkainen@ac1ea38d-2e2b-0410-8846-a27921b304fc>
Mon, 29 Sep 2008 11:10:38 +0000 (11:10 +0000)
committerluukkainen <luukkainen@ac1ea38d-2e2b-0410-8846-a27921b304fc>
Mon, 29 Sep 2008 11:10:38 +0000 (11:10 +0000)
git-svn-id: https://www.simantics.org/svn/simantics/3d/trunk@6851 ac1ea38d-2e2b-0410-8846-a27921b304fc

106 files changed:
org.simantics.proconf.processeditor/.classpath [new file with mode: 0644]
org.simantics.proconf.processeditor/.project [new file with mode: 0644]
org.simantics.proconf.processeditor/META-INF/MANIFEST.MF [new file with mode: 0644]
org.simantics.proconf.processeditor/build.properties [new file with mode: 0644]
org.simantics.proconf.processeditor/data/dcp.mtl [new file with mode: 0644]
org.simantics.proconf.processeditor/data/dcp.obj [new file with mode: 0644]
org.simantics.proconf.processeditor/icons/Component.png [new file with mode: 0644]
org.simantics.proconf.processeditor/icons/Component.svg [new file with mode: 0644]
org.simantics.proconf.processeditor/icons/Elbow.png [new file with mode: 0644]
org.simantics.proconf.processeditor/icons/Elbow.svg [new file with mode: 0644]
org.simantics.proconf.processeditor/icons/Nozzle.png [new file with mode: 0644]
org.simantics.proconf.processeditor/icons/Nozzle.svg [new file with mode: 0644]
org.simantics.proconf.processeditor/icons/Straight.png [new file with mode: 0644]
org.simantics.proconf.processeditor/icons/Straight.svg [new file with mode: 0644]
org.simantics.proconf.processeditor/icons/bubble.png [new file with mode: 0644]
org.simantics.proconf.processeditor/icons/bubble.svg [new file with mode: 0644]
org.simantics.proconf.processeditor/icons/crosshair.png [new file with mode: 0644]
org.simantics.proconf.processeditor/icons/crosshair.svg [new file with mode: 0644]
org.simantics.proconf.processeditor/icons/factory.png [new file with mode: 0644]
org.simantics.proconf.processeditor/icons/factory.svg [new file with mode: 0644]
org.simantics.proconf.processeditor/icons/middle.png [new file with mode: 0644]
org.simantics.proconf.processeditor/icons/middle.svg [new file with mode: 0644]
org.simantics.proconf.processeditor/icons/plus.png [new file with mode: 0644]
org.simantics.proconf.processeditor/icons/plus.svg [new file with mode: 0644]
org.simantics.proconf.processeditor/icons/tank.png [new file with mode: 0644]
org.simantics.proconf.processeditor/icons/tank.svg [new file with mode: 0644]
org.simantics.proconf.processeditor/icons/translate_d.png [new file with mode: 0644]
org.simantics.proconf.processeditor/icons/translate_d.svg [new file with mode: 0644]
org.simantics.proconf.processeditor/icons/x-axis.png [new file with mode: 0644]
org.simantics.proconf.processeditor/icons/x-axis.svg [new file with mode: 0644]
org.simantics.proconf.processeditor/icons/x-plane.png [new file with mode: 0644]
org.simantics.proconf.processeditor/icons/x-plane.svg [new file with mode: 0644]
org.simantics.proconf.processeditor/icons/y-axis.png [new file with mode: 0644]
org.simantics.proconf.processeditor/icons/y-axis.svg [new file with mode: 0644]
org.simantics.proconf.processeditor/icons/y-plane.png [new file with mode: 0644]
org.simantics.proconf.processeditor/icons/y-plane.svg [new file with mode: 0644]
org.simantics.proconf.processeditor/icons/z-axis.png [new file with mode: 0644]
org.simantics.proconf.processeditor/icons/z-axis.svg [new file with mode: 0644]
org.simantics.proconf.processeditor/icons/z-plane.png [new file with mode: 0644]
org.simantics.proconf.processeditor/icons/z-plane.svg [new file with mode: 0644]
org.simantics.proconf.processeditor/plugin.xml [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/Activator.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/ProcessResource.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/InsertComponentAction.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/InsertEquipmentAction.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/InsertNozzleAction.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/PositionType.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/ReversePipelineAction.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/RoutePipeAction.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/SelectSplitPointAction.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/SplitPointListener.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/TranslateElbowAction.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/TranslateInlineComponentAction.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/TranslateStraightAction.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/adapters/InlineComponentConstraintAdapter.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/adapters/NozzleConstraintAdapter.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/adapters/TurnComponentConstraintAdapter.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/animations/PipeAnimationController.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/animations/PipeFlowAnimation.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/animations/ResourcePipeAnimationController.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/ControlPointTools.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/PathUtils.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/PipeComponentProvider.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/PipingRules.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/PipingTools.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/PipingTools2.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/ConfigureAnimationDialog.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/ConfigureMonitorDialog.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/ConfigurePipelineAnimationDialog.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/EquipmentDialog.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/LibraryComponentDialog.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/NozzleDialog.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/PipelineComponentDialog.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/PipelineDialog.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/gizmo/PositionSelectionGizmo.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/EquipmentEditorAdapter.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/NewComponentHandler.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/NewEquipmentHandler.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/NewPlantHandler.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/PipelineComponentEditorAdapter.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/Plant3DEditorAdapter.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/Plant3DProjectAdapter.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/Plant3DProjectType.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/BillboardMonitor.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/Monitor.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/MonitorTextProvider.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/ObjectPropertyProvider.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/PathContainer.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/ResourcePathPropertyProvider.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/TextMonitor.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/perspectives/Plant3DModellingPerspective.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/perspectives/ViewpointGenerator.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/scenegraph/NonVisibleNode.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/scenegraph/PipeComponentNode.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/scenegraph/PipeRunNode.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/scenegraph/PipelineComponentNode.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/tools/ControlPointContribution.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/tools/NozzleContribution.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/tools/PlantEditContribution.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/tools/PlantVisualizationContribution.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/EquipmentEditorPart.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/PipelineComponentEditorPart.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/PlantStructureOutlinePage.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/PlantStructureView.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/ProcessEditor.java [new file with mode: 0644]
org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/ProcessEditorPart.java [new file with mode: 0644]

diff --git a/org.simantics.proconf.processeditor/.classpath b/org.simantics.proconf.processeditor/.classpath
new file mode 100644 (file)
index 0000000..0215967
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<classpath>\r
+       <classpathentry kind="src" path="src"/>\r
+       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>\r
+       <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>\r
+       <classpathentry kind="output" path="bin"/>\r
+</classpath>\r
diff --git a/org.simantics.proconf.processeditor/.project b/org.simantics.proconf.processeditor/.project
new file mode 100644 (file)
index 0000000..4f2fb46
--- /dev/null
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<projectDescription>\r
+       <name>org.simantics.proconf.processeditor</name>\r
+       <comment></comment>\r
+       <projects>\r
+       </projects>\r
+       <buildSpec>\r
+               <buildCommand>\r
+                       <name>org.eclipse.jdt.core.javabuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+               <buildCommand>\r
+                       <name>org.eclipse.pde.ManifestBuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+               <buildCommand>\r
+                       <name>org.eclipse.pde.SchemaBuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+       </buildSpec>\r
+       <natures>\r
+               <nature>org.eclipse.pde.PluginNature</nature>\r
+               <nature>org.eclipse.jdt.core.javanature</nature>\r
+       </natures>\r
+</projectDescription>\r
diff --git a/org.simantics.proconf.processeditor/META-INF/MANIFEST.MF b/org.simantics.proconf.processeditor/META-INF/MANIFEST.MF
new file mode 100644 (file)
index 0000000..2c2e6e9
--- /dev/null
@@ -0,0 +1,26 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Processeditor Plug-in
+Bundle-SymbolicName: fi.vtt.simantics.processeditor;singleton:=true
+Bundle-Version: 1.0.0
+Bundle-Activator: fi.vtt.simantics.processeditor.Activator
+Bundle-Vendor: VTT
+Require-Bundle: org.eclipse.ui,
+ org.eclipse.core.runtime,
+ com.jme.eclipse,
+ org.simantics.g2d.stubs,
+ org.simantics.proconf.ui,
+ org.simantics.proconf.g3d,
+ org.simantics.proconf.image,
+ org.simantics.layer0.stubs,
+ org.simantics.layer0.utils,
+ org.simantics.utils,
+ org.simantics.utils.datastructures,
+ javax.vecmath,
+ org.simantics.proconf.ode,
+ org.simantics.proconf.browsing,
+ org.simantics.utils.ui,
+ org.simantics.utils.ui.workbench,
+ org.simantics.proconf.g3d.shapeeditor,
+ org.eclipse.ui.views
+Eclipse-LazyStart: true
diff --git a/org.simantics.proconf.processeditor/build.properties b/org.simantics.proconf.processeditor/build.properties
new file mode 100644 (file)
index 0000000..6f20375
--- /dev/null
@@ -0,0 +1,5 @@
+source.. = src/\r
+output.. = bin/\r
+bin.includes = META-INF/,\\r
+               .,\\r
+               plugin.xml\r
diff --git a/org.simantics.proconf.processeditor/data/dcp.mtl b/org.simantics.proconf.processeditor/data/dcp.mtl
new file mode 100644 (file)
index 0000000..e30d811
--- /dev/null
@@ -0,0 +1,2 @@
+# Blender3D MTL File: dcp.blend\r
+# Material Count: 0\r
diff --git a/org.simantics.proconf.processeditor/data/dcp.obj b/org.simantics.proconf.processeditor/data/dcp.obj
new file mode 100644 (file)
index 0000000..8b19e69
--- /dev/null
@@ -0,0 +1,476 @@
+# Blender v242 OBJ File: dcp.blend\r
+# www.blender3d.org\r
+mtllib dcp.mtl\r
+o Sphere_Sphere\r
+v 0.092388 -0.000000 -0.038268\r
+v -0.092388 0.014645 -0.035355\r
+v -0.070711 0.027060 -0.065328\r
+v -0.038268 0.035355 -0.085355\r
+v 0.000000 0.038268 -0.092388\r
+v 0.038268 0.035355 -0.085355\r
+v 0.070711 0.027060 -0.065328\r
+v 0.092388 0.014645 -0.035355\r
+v 0.092388 0.027060 -0.027060\r
+v 0.070711 0.050000 -0.050000\r
+v 0.038268 0.065328 -0.065328\r
+v 0.000000 0.070711 -0.070711\r
+v -0.038268 0.065328 -0.065328\r
+v -0.070711 0.050000 -0.050000\r
+v -0.092388 0.027060 -0.027060\r
+v -0.092388 0.035355 -0.014645\r
+v -0.070711 0.065328 -0.027060\r
+v -0.038268 0.085355 -0.035355\r
+v 0.000000 0.092388 -0.038268\r
+v 0.038268 0.085355 -0.035355\r
+v 0.070711 0.065328 -0.027060\r
+v 0.092388 0.035355 -0.014645\r
+v 0.092388 0.038268 0.000000\r
+v 0.070711 0.070711 0.000000\r
+v 0.038268 0.092388 0.000000\r
+v 0.000000 0.100000 0.000000\r
+v -0.038268 0.092388 -0.000000\r
+v -0.070711 0.070711 -0.000000\r
+v -0.092388 0.038268 -0.000000\r
+v -0.092388 0.035355 0.014645\r
+v -0.070711 0.065328 0.027060\r
+v -0.038268 0.085355 0.035355\r
+v 0.000000 0.092388 0.038268\r
+v 0.038268 0.085355 0.035355\r
+v 0.070711 0.065328 0.027060\r
+v 0.092388 0.035355 0.014645\r
+v 0.092388 0.027060 0.027060\r
+v 0.070711 0.050000 0.050000\r
+v 0.038268 0.065328 0.065328\r
+v 0.000000 0.070711 0.070711\r
+v -0.038268 0.065328 0.065328\r
+v -0.070711 0.050000 0.050000\r
+v -0.092388 0.027060 0.027060\r
+v -0.092388 0.014645 0.035355\r
+v -0.070711 0.027060 0.065328\r
+v -0.038268 0.035355 0.085355\r
+v -0.000000 0.038268 0.092388\r
+v 0.038268 0.035355 0.085355\r
+v 0.070711 0.027060 0.065328\r
+v 0.092388 0.014645 0.035355\r
+v 0.092388 -0.000000 0.038268\r
+v 0.070711 -0.000000 0.070711\r
+v 0.038268 -0.000000 0.092388\r
+v -0.000000 0.000000 0.100000\r
+v -0.038268 -0.000000 0.092388\r
+v -0.070711 -0.000000 0.070711\r
+v -0.092388 0.000000 0.038268\r
+v -0.092388 -0.014645 0.035355\r
+v -0.070711 -0.027060 0.065328\r
+v -0.038268 -0.035355 0.085355\r
+v -0.000000 -0.038268 0.092388\r
+v 0.038268 -0.035355 0.085355\r
+v 0.070711 -0.027060 0.065328\r
+v 0.092388 -0.014645 0.035355\r
+v 0.092388 -0.027060 0.027060\r
+v 0.070711 -0.050000 0.050000\r
+v 0.038268 -0.065328 0.065328\r
+v -0.000000 -0.070711 0.070711\r
+v -0.038268 -0.065328 0.065328\r
+v -0.070711 -0.050000 0.050000\r
+v -0.092388 -0.027060 0.027060\r
+v -0.100000 -0.000000 0.000000\r
+v -0.092388 -0.035355 0.014645\r
+v -0.070711 -0.065328 0.027060\r
+v -0.038268 -0.085355 0.035355\r
+v -0.000000 -0.092388 0.038268\r
+v 0.038268 -0.085355 0.035355\r
+v 0.070711 -0.065328 0.027060\r
+v 0.092388 -0.035355 0.014645\r
+v 0.092388 -0.038268 0.000000\r
+v 0.070711 -0.070711 0.000000\r
+v 0.038268 -0.092388 0.000000\r
+v 0.000000 -0.100000 0.000000\r
+v -0.038268 -0.092388 -0.000000\r
+v -0.070711 -0.070711 -0.000000\r
+v -0.092388 -0.038268 -0.000000\r
+v -0.092388 -0.035355 -0.014645\r
+v -0.070711 -0.065328 -0.027060\r
+v -0.038268 -0.085355 -0.035355\r
+v 0.000000 -0.092388 -0.038268\r
+v 0.038268 -0.085355 -0.035355\r
+v 0.070711 -0.065328 -0.027060\r
+v 0.092388 -0.035355 -0.014645\r
+v 0.092388 -0.027060 -0.027060\r
+v 0.070711 -0.050000 -0.050000\r
+v 0.038268 -0.065328 -0.065328\r
+v 0.000000 -0.070711 -0.070711\r
+v -0.038268 -0.065328 -0.065328\r
+v -0.070711 -0.050000 -0.050000\r
+v -0.092388 -0.027060 -0.027060\r
+v -0.092388 -0.014645 -0.035355\r
+v -0.070711 -0.027060 -0.065328\r
+v -0.038268 -0.035355 -0.085355\r
+v 0.000000 -0.038268 -0.092388\r
+v 0.038268 -0.035355 -0.085355\r
+v 0.070711 -0.027060 -0.065328\r
+v 0.092388 -0.014645 -0.035355\r
+v 0.070711 0.000000 -0.070711\r
+v 0.038268 0.000000 -0.092388\r
+v 0.000000 0.000000 -0.100000\r
+v -0.038268 0.000000 -0.092388\r
+v -0.070711 0.000000 -0.070711\r
+v -0.092388 0.000000 -0.038268\r
+v 0.232388 -0.014645 -0.035355\r
+v 0.232388 -0.027060 -0.027060\r
+v 0.232388 -0.035355 -0.014645\r
+v 0.232388 -0.038268 0.000000\r
+v 0.232388 -0.035355 0.014645\r
+v 0.232388 -0.027060 0.027060\r
+v 0.232388 -0.014645 0.035355\r
+v 0.232388 -0.000000 0.038268\r
+v 0.232388 0.014645 0.035355\r
+v 0.232388 0.027060 0.027060\r
+v 0.232388 0.035355 0.014645\r
+v 0.232388 0.038268 0.000000\r
+v 0.232388 0.035355 -0.014645\r
+v 0.232388 0.027060 -0.027060\r
+v 0.232388 0.014645 -0.035355\r
+v 0.232388 -0.000000 -0.038268\r
+v 0.231045 -0.000000 -0.153073\r
+v 0.231045 0.058579 -0.141421\r
+v 0.511493 -0.000000 0.000000\r
+v 0.231045 0.108239 -0.108239\r
+v 0.231045 0.141421 -0.058579\r
+v 0.231045 0.153073 0.000000\r
+v 0.231045 0.141421 0.058579\r
+v 0.231045 0.108239 0.108239\r
+v 0.231045 0.058579 0.141421\r
+v 0.231045 -0.000000 0.153073\r
+v 0.231045 -0.058579 0.141421\r
+v 0.231045 -0.108239 0.108239\r
+v 0.231045 -0.141421 0.058579\r
+v 0.231045 -0.153073 0.000000\r
+v 0.231045 -0.141421 -0.058579\r
+v 0.231045 -0.108239 -0.108239\r
+v 0.231045 -0.058579 -0.141421\r
+vn -0.999929 -0.002325 0.011699\r
+vn -0.999929 -0.006629 0.009917\r
+vn -0.999929 -0.009918 0.006627\r
+vn -0.999929 -0.011699 0.002327\r
+vn -0.999929 -0.011699 -0.002327\r
+vn -0.999929 -0.009918 -0.006627\r
+vn -0.999929 -0.006627 -0.009918\r
+vn -0.999929 -0.002327 -0.011699\r
+vn -0.999929 0.002327 -0.011699\r
+vn -0.999929 0.006627 -0.009918\r
+vn -0.999929 0.009918 -0.006627\r
+vn -0.999929 0.011699 -0.002327\r
+vn -0.999929 0.011699 0.002327\r
+vn -0.999929 0.009918 0.006627\r
+vn -0.999929 0.006627 0.009918\r
+vn -0.999929 0.002327 0.011699\r
+vn -1.000000 0.000000 0.000000\r
+vn -0.924070 0.146245 -0.353099\r
+vn -0.924070 0.000000 -0.382183\r
+vn -0.707602 0.270394 -0.652791\r
+vn -0.707602 0.000000 -0.706565\r
+vn -0.383129 0.353465 -0.853359\r
+vn -0.383129 0.000000 -0.923673\r
+vn 0.000000 0.382672 -0.923856\r
+vn 0.000000 0.000000 -1.000000\r
+vn 0.383129 0.353465 -0.853359\r
+vn 0.383129 0.000000 -0.923673\r
+vn 0.707602 0.270394 -0.652791\r
+vn 0.707602 0.000000 -0.706565\r
+vn 0.474532 0.336833 -0.813227\r
+vn 0.474532 0.000000 -0.880215\r
+vn 0.707602 0.499619 -0.499619\r
+vn 0.474532 0.622395 -0.622395\r
+vn 0.383129 0.653127 -0.653127\r
+vn 0.000000 0.707083 -0.707083\r
+vn -0.383129 0.653127 -0.653127\r
+vn -0.707602 0.499619 -0.499619\r
+vn -0.924070 0.270241 -0.270241\r
+vn -0.924070 0.353099 -0.146245\r
+vn -0.707602 0.652791 -0.270394\r
+vn -0.383129 0.853359 -0.353465\r
+vn 0.000000 0.923856 -0.382672\r
+vn 0.383129 0.853359 -0.353465\r
+vn 0.707602 0.652791 -0.270394\r
+vn 0.474532 0.813227 -0.336833\r
+vn 0.707602 0.706565 0.000000\r
+vn 0.474532 0.880215 0.000000\r
+vn 0.383129 0.923673 0.000000\r
+vn 0.000000 1.000000 0.000000\r
+vn -0.383129 0.923673 0.000000\r
+vn -0.707602 0.706565 0.000000\r
+vn -0.924070 0.382183 0.000000\r
+vn -0.924070 0.353099 0.146245\r
+vn -0.707602 0.652791 0.270394\r
+vn -0.383129 0.853359 0.353465\r
+vn 0.000000 0.923856 0.382672\r
+vn 0.383129 0.853359 0.353465\r
+vn 0.707602 0.652791 0.270394\r
+vn 0.474532 0.813227 0.336833\r
+vn 0.707602 0.499619 0.499619\r
+vn 0.474532 0.622395 0.622395\r
+vn 0.383129 0.653127 0.653127\r
+vn 0.000000 0.707083 0.707083\r
+vn -0.383129 0.653127 0.653127\r
+vn -0.707602 0.499619 0.499619\r
+vn -0.924070 0.270241 0.270241\r
+vn -0.924070 0.146245 0.353099\r
+vn -0.707602 0.270394 0.652791\r
+vn -0.383129 0.353465 0.853359\r
+vn 0.000000 0.382672 0.923856\r
+vn 0.383129 0.353465 0.853359\r
+vn 0.707602 0.270394 0.652791\r
+vn 0.474532 0.336833 0.813227\r
+vn 0.707602 0.000000 0.706565\r
+vn 0.474532 0.000000 0.880215\r
+vn 0.383129 0.000000 0.923673\r
+vn 0.000000 0.000000 1.000000\r
+vn -0.383129 0.000000 0.923673\r
+vn -0.707602 0.000000 0.706565\r
+vn -0.924070 0.000000 0.382183\r
+vn -0.924070 -0.146245 0.353099\r
+vn -0.707602 -0.270394 0.652791\r
+vn -0.383129 -0.353465 0.853359\r
+vn 0.000000 -0.382672 0.923856\r
+vn 0.383129 -0.353465 0.853359\r
+vn 0.707602 -0.270394 0.652791\r
+vn 0.474532 -0.336833 0.813227\r
+vn 0.707602 -0.499619 0.499619\r
+vn 0.474532 -0.622395 0.622395\r
+vn 0.383129 -0.653127 0.653127\r
+vn 0.000000 -0.707083 0.707083\r
+vn -0.383129 -0.653127 0.653127\r
+vn -0.707602 -0.499619 0.499619\r
+vn -0.924070 -0.270241 0.270241\r
+vn -0.924070 -0.353099 0.146245\r
+vn -0.707602 -0.652791 0.270394\r
+vn -0.383129 -0.853359 0.353465\r
+vn 0.000000 -0.923856 0.382672\r
+vn 0.383129 -0.853359 0.353465\r
+vn 0.707602 -0.652791 0.270394\r
+vn 0.474532 -0.813227 0.336833\r
+vn 0.707602 -0.706565 0.000000\r
+vn 0.474532 -0.880215 0.000000\r
+vn 0.383129 -0.923673 0.000000\r
+vn 0.000000 -1.000000 0.000000\r
+vn -0.383129 -0.923673 0.000000\r
+vn -0.707602 -0.706565 0.000000\r
+vn -0.924070 -0.382183 0.000000\r
+vn -0.924070 -0.353099 -0.146245\r
+vn -0.707602 -0.652791 -0.270394\r
+vn -0.383129 -0.853359 -0.353465\r
+vn 0.000000 -0.923856 -0.382672\r
+vn 0.383129 -0.853359 -0.353465\r
+vn 0.707602 -0.652791 -0.270394\r
+vn 0.474532 -0.813227 -0.336833\r
+vn 0.707602 -0.499619 -0.499619\r
+vn 0.474532 -0.622395 -0.622395\r
+vn 0.383129 -0.653127 -0.653127\r
+vn 0.000000 -0.707083 -0.707083\r
+vn -0.383129 -0.653127 -0.653127\r
+vn -0.707602 -0.499619 -0.499619\r
+vn -0.924070 -0.270241 -0.270241\r
+vn -0.924070 -0.146245 -0.353099\r
+vn -0.707602 -0.270394 -0.652791\r
+vn -0.383129 -0.353465 -0.853359\r
+vn 0.000000 -0.382672 -0.923856\r
+vn 0.383129 -0.353465 -0.853359\r
+vn 0.707602 -0.270394 -0.652791\r
+vn 0.474532 -0.336833 -0.813227\r
+vn -0.718070 0.000000 -0.695944\r
+vn -0.718070 -0.266305 -0.642964\r
+vn -0.718070 -0.492080 -0.492080\r
+vn -0.718070 -0.642964 -0.266305\r
+vn -0.718070 -0.695944 0.000000\r
+vn -0.718070 -0.642964 0.266305\r
+vn -0.718070 -0.492080 0.492080\r
+vn -0.718070 -0.266305 0.642964\r
+vn -0.718070 0.000000 0.695944\r
+vn -0.718070 0.266305 0.642964\r
+vn -0.718070 0.492080 0.492080\r
+vn -0.718070 0.642964 0.266305\r
+vn -0.718070 0.695944 0.000000\r
+vn -0.718070 0.642964 -0.266305\r
+vn -0.718070 0.492080 -0.492080\r
+vn -0.718070 0.266305 -0.642964\r
+vn -0.526292 0.000000 -0.850276\r
+vn -0.526292 0.325388 -0.785546\r
+vn 1.000000 0.000000 0.000000\r
+vn -0.526292 0.601245 -0.601245\r
+vn -0.526292 0.785546 -0.325388\r
+vn -0.526292 0.850276 0.000000\r
+vn -0.526292 0.785546 0.325388\r
+vn -0.526292 0.601245 0.601245\r
+vn -0.526292 0.325388 0.785546\r
+vn -0.526292 0.000000 0.850276\r
+vn -0.526292 -0.325388 0.785546\r
+vn -0.526292 -0.601245 0.601245\r
+vn -0.526292 -0.785546 0.325388\r
+vn -0.526292 -0.850276 0.000000\r
+vn -0.526292 -0.785546 -0.325388\r
+vn -0.526292 -0.601245 -0.601245\r
+vn -0.526292 -0.325388 -0.785546\r
+usemtl (null)\r
+usemtl (null)\r
+s off\r
+f 129//1 128//1 131//1 130//1\r
+f 128//2 127//2 133//2 131//2\r
+f 127//3 126//3 134//3 133//3\r
+f 126//4 125//4 135//4 134//4\r
+f 125//5 124//5 136//5 135//5\r
+f 124//6 123//6 137//6 136//6\r
+f 123//7 122//7 138//7 137//7\r
+f 122//8 121//8 139//8 138//8\r
+f 121//9 120//9 140//9 139//9\r
+f 120//10 119//10 141//10 140//10\r
+f 119//11 118//11 142//11 141//11\r
+f 118//12 117//12 143//12 142//12\r
+f 117//13 116//13 144//13 143//13\r
+f 116//14 115//14 145//14 144//14\r
+f 115//15 114//15 146//15 145//15\r
+f 114//16 129//16 130//16 146//16\r
+s 1\r
+f 72//17 2//18 113//19\r
+f 113//19 2//18 3//20 112//21\r
+f 112//21 3//20 4//22 111//23\r
+f 111//23 4//22 5//24 110//25\r
+f 110//25 5//24 6//26 109//27\r
+f 109//27 6//26 7//28 108//29\r
+f 8//30 1//31 108//29 7//28\r
+f 7//28 10//32 9//33 8//30\r
+f 6//26 11//34 10//32 7//28\r
+f 5//24 12//35 11//34 6//26\r
+f 4//22 13//36 12//35 5//24\r
+f 3//20 14//37 13//36 4//22\r
+f 2//18 15//38 14//37 3//20\r
+f 72//17 15//38 2//18\r
+f 72//17 16//39 15//38\r
+f 15//38 16//39 17//40 14//37\r
+f 14//37 17//40 18//41 13//36\r
+f 13//36 18//41 19//42 12//35\r
+f 12//35 19//42 20//43 11//34\r
+f 11//34 20//43 21//44 10//32\r
+f 10//32 21//44 22//45 9//33\r
+f 21//44 24//46 23//47 22//45\r
+f 20//43 25//48 24//46 21//44\r
+f 19//42 26//49 25//48 20//43\r
+f 18//41 27//50 26//49 19//42\r
+f 17//40 28//51 27//50 18//41\r
+f 16//39 29//52 28//51 17//40\r
+f 72//17 29//52 16//39\r
+f 72//17 30//53 29//52\r
+f 29//52 30//53 31//54 28//51\r
+f 28//51 31//54 32//55 27//50\r
+f 27//50 32//55 33//56 26//49\r
+f 26//49 33//56 34//57 25//48\r
+f 25//48 34//57 35//58 24//46\r
+f 24//46 35//58 36//59 23//47\r
+f 35//58 38//60 37//61 36//59\r
+f 34//57 39//62 38//60 35//58\r
+f 33//56 40//63 39//62 34//57\r
+f 32//55 41//64 40//63 33//56\r
+f 31//54 42//65 41//64 32//55\r
+f 30//53 43//66 42//65 31//54\r
+f 72//17 43//66 30//53\r
+f 72//17 44//67 43//66\r
+f 43//66 44//67 45//68 42//65\r
+f 42//65 45//68 46//69 41//64\r
+f 41//64 46//69 47//70 40//63\r
+f 40//63 47//70 48//71 39//62\r
+f 39//62 48//71 49//72 38//60\r
+f 38//60 49//72 50//73 37//61\r
+f 49//72 52//74 51//75 50//73\r
+f 48//71 53//76 52//74 49//72\r
+f 47//70 54//77 53//76 48//71\r
+f 46//69 55//78 54//77 47//70\r
+f 45//68 56//79 55//78 46//69\r
+f 44//67 57//80 56//79 45//68\r
+f 72//17 57//80 44//67\r
+f 72//17 58//81 57//80\r
+f 57//80 58//81 59//82 56//79\r
+f 56//79 59//82 60//83 55//78\r
+f 55//78 60//83 61//84 54//77\r
+f 54//77 61//84 62//85 53//76\r
+f 53//76 62//85 63//86 52//74\r
+f 52//74 63//86 64//87 51//75\r
+f 63//86 66//88 65//89 64//87\r
+f 62//85 67//90 66//88 63//86\r
+f 61//84 68//91 67//90 62//85\r
+f 60//83 69//92 68//91 61//84\r
+f 59//82 70//93 69//92 60//83\r
+f 58//81 71//94 70//93 59//82\r
+f 72//17 71//94 58//81\r
+f 72//17 73//95 71//94\r
+f 71//94 73//95 74//96 70//93\r
+f 70//93 74//96 75//97 69//92\r
+f 69//92 75//97 76//98 68//91\r
+f 68//91 76//98 77//99 67//90\r
+f 67//90 77//99 78//100 66//88\r
+f 66//88 78//100 79//101 65//89\r
+f 78//100 81//102 80//103 79//101\r
+f 77//99 82//104 81//102 78//100\r
+f 76//98 83//105 82//104 77//99\r
+f 75//97 84//106 83//105 76//98\r
+f 74//96 85//107 84//106 75//97\r
+f 73//95 86//108 85//107 74//96\r
+f 72//17 86//108 73//95\r
+f 72//17 87//109 86//108\r
+f 86//108 87//109 88//110 85//107\r
+f 85//107 88//110 89//111 84//106\r
+f 84//106 89//111 90//112 83//105\r
+f 83//105 90//112 91//113 82//104\r
+f 82//104 91//113 92//114 81//102\r
+f 81//102 92//114 93//115 80//103\r
+f 92//114 95//116 94//117 93//115\r
+f 91//113 96//118 95//116 92//114\r
+f 90//112 97//119 96//118 91//113\r
+f 89//111 98//120 97//119 90//112\r
+f 88//110 99//121 98//120 89//111\r
+f 87//109 100//122 99//121 88//110\r
+f 72//17 100//122 87//109\r
+f 72//17 101//123 100//122\r
+f 100//122 101//123 102//124 99//121\r
+f 99//121 102//124 103//125 98//120\r
+f 98//120 103//125 104//126 97//119\r
+f 97//119 104//126 105//127 96//118\r
+f 96//118 105//127 106//128 95//116\r
+f 95//116 106//128 107//129 94//117\r
+f 1//31 107//129 106//128 108//29\r
+f 105//127 109//27 108//29 106//128\r
+f 104//126 110//25 109//27 105//127\r
+f 103//125 111//23 110//25 104//126\r
+f 102//124 112//21 111//23 103//125\r
+f 101//123 113//19 112//21 102//124\r
+f 72//17 113//19 101//123\r
+f 107//129 1//31 129//130 114//131\r
+f 94//117 107//129 114//131 115//132\r
+f 93//115 94//117 115//132 116//133\r
+f 80//103 93//115 116//133 117//134\r
+f 79//101 80//103 117//134 118//135\r
+f 65//89 79//101 118//135 119//136\r
+f 64//87 65//89 119//136 120//137\r
+f 51//75 64//87 120//137 121//138\r
+f 50//73 51//75 121//138 122//139\r
+f 37//61 50//73 122//139 123//140\r
+f 36//59 37//61 123//140 124//141\r
+f 23//47 36//59 124//141 125//142\r
+f 22//45 23//47 125//142 126//143\r
+f 9//33 22//45 126//143 127//144\r
+f 8//30 9//33 127//144 128//145\r
+f 1//31 8//30 128//145 129//130\r
+f 130//146 131//147 132//148\r
+f 131//147 133//149 132//148\r
+f 133//149 134//150 132//148\r
+f 134//150 135//151 132//148\r
+f 135//151 136//152 132//148\r
+f 136//152 137//153 132//148\r
+f 137//153 138//154 132//148\r
+f 138//154 139//155 132//148\r
+f 139//155 140//156 132//148\r
+f 140//156 141//157 132//148\r
+f 141//157 142//158 132//148\r
+f 142//158 143//159 132//148\r
+f 143//159 144//160 132//148\r
+f 144//160 145//161 132//148\r
+f 145//161 146//162 132//148\r
+f 146//162 130//146 132//148\r
diff --git a/org.simantics.proconf.processeditor/icons/Component.png b/org.simantics.proconf.processeditor/icons/Component.png
new file mode 100644 (file)
index 0000000..0d43ef5
Binary files /dev/null and b/org.simantics.proconf.processeditor/icons/Component.png differ
diff --git a/org.simantics.proconf.processeditor/icons/Component.svg b/org.simantics.proconf.processeditor/icons/Component.svg
new file mode 100644 (file)
index 0000000..eaf3034
--- /dev/null
@@ -0,0 +1,128 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="100"
+   height="100"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.44+devel"
+   version="1.0"
+   sodipodi:docname="Component.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   sodipodi:docbase="C:\Documents and Settings\Make\Desktop"
+   inkscape:export-filename="C:\Documents and Settings\Make\Desktop\Component.png"
+   inkscape:export-xdpi="14.4"
+   inkscape:export-ydpi="14.4"
+   sodipodi:modified="true">
+  <defs
+     id="defs4">
+    <linearGradient
+       id="linearGradient3133">
+      <stop
+         style="stop-color:#4c4c4c;stop-opacity:1;"
+         offset="0"
+         id="stop3135" />
+      <stop
+         id="stop3141"
+         offset="0.5"
+         style="stop-color:#cbcbcb;stop-opacity:1;" />
+      <stop
+         style="stop-color:#4c4c4c;stop-opacity:1;"
+         offset="1"
+         id="stop3137" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3133"
+       id="linearGradient5083"
+       x1="45.114037"
+       y1="48.248638"
+       x2="45.114037"
+       y2="82.201416"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3133"
+       id="linearGradient3152"
+       x1="21.809525"
+       y1="10.776942"
+       x2="74.932327"
+       y2="10.776942"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3133"
+       id="linearGradient4129"
+       x1="34.842106"
+       y1="25.93985"
+       x2="62.776943"
+       y2="25.93985"
+       gradientUnits="userSpaceOnUse" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     gridtolerance="10000"
+     guidetolerance="10"
+     objecttolerance="10"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="7.98"
+     inkscape:cx="50"
+     inkscape:cy="65.037594"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     width="100px"
+     height="100px"
+     inkscape:window-width="1680"
+     inkscape:window-height="994"
+     inkscape:window-x="1276"
+     inkscape:window-y="-4" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1">
+    <rect
+       style="fill:url(#linearGradient5083);fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:4;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="rect2160"
+       width="77.318306"
+       height="29.949863"
+       x="11.403508"
+       y="50.250629" />
+    <rect
+       style="fill:url(#linearGradient4129);fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:4;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="rect2171"
+       width="23.934837"
+       height="17.167919"
+       x="36.842106"
+       y="32.957397" />
+    <rect
+       style="fill:url(#linearGradient3152);fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:4;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="rect2173"
+       width="49.122807"
+       height="13.283208"
+       x="23.809525"
+       y="19.674185" />
+  </g>
+</svg>
diff --git a/org.simantics.proconf.processeditor/icons/Elbow.png b/org.simantics.proconf.processeditor/icons/Elbow.png
new file mode 100644 (file)
index 0000000..bbaa16e
Binary files /dev/null and b/org.simantics.proconf.processeditor/icons/Elbow.png differ
diff --git a/org.simantics.proconf.processeditor/icons/Elbow.svg b/org.simantics.proconf.processeditor/icons/Elbow.svg
new file mode 100644 (file)
index 0000000..611748a
--- /dev/null
@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="100"
+   height="100"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.44+devel"
+   version="1.0"
+   sodipodi:docbase="C:\Documents and Settings\Make\Desktop"
+   sodipodi:docname="Elbow.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   inkscape:export-filename="C:\Documents and Settings\Make\Desktop\Elbow.png"
+   inkscape:export-xdpi="14.4"
+   inkscape:export-ydpi="14.4"
+   sodipodi:modified="true">
+  <defs
+     id="defs4">
+    <linearGradient
+       id="linearGradient8030">
+      <stop
+         id="stop8032"
+         offset="0"
+         style="stop-color:#6c6c6c;stop-opacity:1;" />
+      <stop
+         style="stop-color:#4c4c4c;stop-opacity:1;"
+         offset="0.25"
+         id="stop8038" />
+      <stop
+         style="stop-color:#c8c8c8;stop-opacity:1;"
+         offset="0.5"
+         id="stop8034" />
+      <stop
+         id="stop8040"
+         offset="0.75"
+         style="stop-color:#4c4c4c;stop-opacity:1;" />
+      <stop
+         id="stop8036"
+         offset="1"
+         style="stop-color:#6c6c6c;stop-opacity:1;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3133">
+      <stop
+         style="stop-color:#6c6c6c;stop-opacity:1;"
+         offset="0"
+         id="stop3135" />
+      <stop
+         id="stop3141"
+         offset="0.5"
+         style="stop-color:#ffffff;stop-opacity:1;" />
+      <stop
+         style="stop-color:#6c6c6c;stop-opacity:1;"
+         offset="1"
+         id="stop3137" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3133"
+       id="linearGradient5083"
+       x1="45.114037"
+       y1="34.211781"
+       x2="45.236843"
+       y2="63.532585"
+       gradientUnits="userSpaceOnUse" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient8030"
+       id="radialGradient6090"
+       cx="96.962318"
+       cy="96.001694"
+       fx="96.962318"
+       fy="96.001694"
+       r="50.5"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(2.2964837,5.7024121e-8,-5.8341962e-8,2.3753605,-132.4242,-138.9854)" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     gridtolerance="10000"
+     guidetolerance="10"
+     objecttolerance="10"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="6.0477091"
+     inkscape:cx="115.16906"
+     inkscape:cy="57.595569"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     width="100px"
+     height="100px"
+     inkscape:window-width="1680"
+     inkscape:window-height="994"
+     inkscape:window-x="1280"
+     inkscape:window-y="22" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1">
+    <path
+       style="fill:url(#radialGradient6090);fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:4;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-start:none"
+       d="M 89.854773,9.8471149 C 46.494023,9.8471149 11.30269,45.155211 11.30269,88.65983 L 50.578732,88.65983 C 50.577409,88.527292 50.578732,88.398616 50.578732,88.265766 C 50.578732,66.73098 67.998442,49.253473 89.462013,49.253473 C 89.594423,49.253473 89.722674,49.252145 89.854773,49.253473 L 89.854773,9.8471149 z "
+       id="path5107" />
+  </g>
+</svg>
diff --git a/org.simantics.proconf.processeditor/icons/Nozzle.png b/org.simantics.proconf.processeditor/icons/Nozzle.png
new file mode 100644 (file)
index 0000000..48cf03e
Binary files /dev/null and b/org.simantics.proconf.processeditor/icons/Nozzle.png differ
diff --git a/org.simantics.proconf.processeditor/icons/Nozzle.svg b/org.simantics.proconf.processeditor/icons/Nozzle.svg
new file mode 100644 (file)
index 0000000..0dd815c
--- /dev/null
@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="100"
+   height="100"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.44"
+   version="1.0"
+   sodipodi:docname="Nozzle.svg"
+   sodipodi:docbase="D:\dev\icons"
+   inkscape:export-filename="C:\Documents and Settings\Make\Desktop\Straight.png"
+   inkscape:export-xdpi="14.4"
+   inkscape:export-ydpi="14.4">
+  <defs
+     id="defs4">
+    <linearGradient
+       id="linearGradient3133">
+      <stop
+         style="stop-color:#4c4c4c;stop-opacity:1;"
+         offset="0"
+         id="stop3135" />
+      <stop
+         id="stop3141"
+         offset="0.5"
+         style="stop-color:#cbcbcb;stop-opacity:1;" />
+      <stop
+         style="stop-color:#4c4c4c;stop-opacity:1;"
+         offset="1"
+         id="stop3137" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3133"
+       id="linearGradient5083"
+       x1="45.114037"
+       y1="32.711548"
+       x2="45.114037"
+       y2="66.681152"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3133"
+       id="linearGradient2772"
+       x1="81.077698"
+       y1="12.912281"
+       x2="81.077698"
+       y2="84.456146"
+       gradientUnits="userSpaceOnUse" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     gridtolerance="10000"
+     guidetolerance="10"
+     objecttolerance="10"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="7.98"
+     inkscape:cx="50"
+     inkscape:cy="50"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     width="100px"
+     height="100px"
+     inkscape:window-width="1280"
+     inkscape:window-height="968"
+     inkscape:window-x="-4"
+     inkscape:window-y="-4" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1">
+    <rect
+       style="fill:url(#linearGradient5083);fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:4;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="rect2160"
+       width="77.318306"
+       height="29.949863"
+       x="11.403508"
+       y="34.711781" />
+    <rect
+       style="fill:url(#linearGradient2772);fill-opacity:1.0;stroke:black;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="rect1875"
+       width="15.789474"
+       height="67.543861"
+       x="73.182961"
+       y="14.912281" />
+  </g>
+</svg>
diff --git a/org.simantics.proconf.processeditor/icons/Straight.png b/org.simantics.proconf.processeditor/icons/Straight.png
new file mode 100644 (file)
index 0000000..459919e
Binary files /dev/null and b/org.simantics.proconf.processeditor/icons/Straight.png differ
diff --git a/org.simantics.proconf.processeditor/icons/Straight.svg b/org.simantics.proconf.processeditor/icons/Straight.svg
new file mode 100644 (file)
index 0000000..117e6ec
--- /dev/null
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="100"
+   height="100"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.44+devel"
+   version="1.0"
+   sodipodi:docname="Straight.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   sodipodi:docbase="C:\Documents and Settings\Make\Desktop"
+   inkscape:export-filename="C:\Documents and Settings\Make\Desktop\Straight.png"
+   inkscape:export-xdpi="14.4"
+   inkscape:export-ydpi="14.4"
+   sodipodi:modified="true">
+  <defs
+     id="defs4">
+    <linearGradient
+       id="linearGradient3133">
+      <stop
+         style="stop-color:#4c4c4c;stop-opacity:1;"
+         offset="0"
+         id="stop3135" />
+      <stop
+         id="stop3141"
+         offset="0.5"
+         style="stop-color:#cbcbcb;stop-opacity:1;" />
+      <stop
+         style="stop-color:#4c4c4c;stop-opacity:1;"
+         offset="1"
+         id="stop3137" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3133"
+       id="linearGradient5083"
+       x1="45.114037"
+       y1="32.711548"
+       x2="45.114037"
+       y2="66.681152"
+       gradientUnits="userSpaceOnUse" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     gridtolerance="10000"
+     guidetolerance="10"
+     objecttolerance="10"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="7.98"
+     inkscape:cx="50"
+     inkscape:cy="44.987469"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     width="100px"
+     height="100px"
+     inkscape:window-width="1680"
+     inkscape:window-height="994"
+     inkscape:window-x="1276"
+     inkscape:window-y="-4" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1">
+    <rect
+       style="fill:url(#linearGradient5083);fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:4;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="rect2160"
+       width="77.318306"
+       height="29.949863"
+       x="11.403508"
+       y="34.711781" />
+  </g>
+</svg>
diff --git a/org.simantics.proconf.processeditor/icons/bubble.png b/org.simantics.proconf.processeditor/icons/bubble.png
new file mode 100644 (file)
index 0000000..410e268
Binary files /dev/null and b/org.simantics.proconf.processeditor/icons/bubble.png differ
diff --git a/org.simantics.proconf.processeditor/icons/bubble.svg b/org.simantics.proconf.processeditor/icons/bubble.svg
new file mode 100644 (file)
index 0000000..f52235f
--- /dev/null
@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="32"
+   height="32"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.44"
+   version="1.0"
+   inkscape:export-filename="C:\Documents and Settings\tuoxmao\Desktop\bubble.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90"
+   sodipodi:docbase="C:\Documents and Settings\tuoxmao\Desktop"
+   sodipodi:docname="bubble.svg">
+  <defs
+     id="defs4">
+    <linearGradient
+       id="linearGradient3835">
+      <stop
+         style="stop-color:black;stop-opacity:1;"
+         offset="0"
+         id="stop3837" />
+      <stop
+         style="stop-color:black;stop-opacity:0;"
+         offset="1"
+         id="stop3839" />
+    </linearGradient>
+    <marker
+       inkscape:stockid="Arrow1Lstart"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="Arrow1Lstart"
+       style="overflow:visible">
+      <path
+         id="path3828"
+         d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none"
+         transform="scale(0.8) translate(12.5,0)" />
+    </marker>
+    <linearGradient
+       id="linearGradient2762">
+      <stop
+         style="stop-color:white;stop-opacity:0;"
+         offset="0"
+         id="stop2764" />
+      <stop
+         id="stop5615"
+         offset="0.25"
+         style="stop-color:white;stop-opacity:0.20392157;" />
+      <stop
+         id="stop5613"
+         offset="0.5"
+         style="stop-color:white;stop-opacity:1;" />
+      <stop
+         style="stop-color:white;stop-opacity:1;"
+         offset="1"
+         id="stop2766" />
+    </linearGradient>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2762"
+       id="radialGradient2768"
+       cx="9.7167473"
+       cy="9.0794983"
+       fx="9.7167473"
+       fy="9.0794983"
+       r="16"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.470992,1.073004,-1.001683,1.373218,6.378253,-11.49047)" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     gridtolerance="10000"
+     guidetolerance="10"
+     objecttolerance="10"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="10"
+     inkscape:cx="16"
+     inkscape:cy="16"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     width="32px"
+     height="32px"
+     inkscape:window-width="1280"
+     inkscape:window-height="968"
+     inkscape:window-x="-4"
+     inkscape:window-y="-4" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1">
+    <path
+       sodipodi:type="arc"
+       style="fill:url(#radialGradient2768);fill-opacity:1;stroke:white;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;marker-start:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:10;stroke-opacity:1"
+       id="path1874"
+       sodipodi:cx="16"
+       sodipodi:cy="16"
+       sodipodi:rx="16"
+       sodipodi:ry="16"
+       d="M 32 16 A 16 16 0 1 1  0,16 A 16 16 0 1 1  32 16 z"
+       transform="matrix(0.935294,0,0,0.935294,1.035294,1.035294)" />
+  </g>
+</svg>
diff --git a/org.simantics.proconf.processeditor/icons/crosshair.png b/org.simantics.proconf.processeditor/icons/crosshair.png
new file mode 100644 (file)
index 0000000..379424e
Binary files /dev/null and b/org.simantics.proconf.processeditor/icons/crosshair.png differ
diff --git a/org.simantics.proconf.processeditor/icons/crosshair.svg b/org.simantics.proconf.processeditor/icons/crosshair.svg
new file mode 100644 (file)
index 0000000..8c73e69
--- /dev/null
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="32"
+   height="32"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.44"
+   version="1.0"
+   inkscape:export-filename="C:\Documents and Settings\tuoxmao\Desktop\crosshair.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90"
+   sodipodi:docbase="C:\Documents and Settings\tuoxmao\Desktop"
+   sodipodi:docname="crosshair.svg">
+  <defs
+     id="defs4" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     gridtolerance="10000"
+     guidetolerance="10"
+     objecttolerance="10"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="10"
+     inkscape:cx="16"
+     inkscape:cy="16"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     width="32px"
+     height="32px"
+     inkscape:window-width="1280"
+     inkscape:window-height="968"
+     inkscape:window-x="-4"
+     inkscape:window-y="-4" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1">
+    <path
+       sodipodi:type="arc"
+       style="fill:none;fill-opacity:1;stroke:white;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:10;stroke-opacity:0.4973262"
+       id="path1872"
+       sodipodi:cx="16"
+       sodipodi:cy="16"
+       sodipodi:rx="12"
+       sodipodi:ry="12"
+       d="M 28 16 A 12 12 0 1 1  4,16 A 12 12 0 1 1  28 16 z" />
+    <path
+       style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:white;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.4973262;stroke-miterlimit:4;stroke-dasharray:none"
+       d="M 16,7.1054274e-015 L 16,32"
+       id="path2760" />
+    <path
+       style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:white;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.4973262;stroke-miterlimit:4;stroke-dasharray:none"
+       d="M 0,16 L 32,16"
+       id="path2762" />
+  </g>
+</svg>
diff --git a/org.simantics.proconf.processeditor/icons/factory.png b/org.simantics.proconf.processeditor/icons/factory.png
new file mode 100644 (file)
index 0000000..aad23e3
Binary files /dev/null and b/org.simantics.proconf.processeditor/icons/factory.png differ
diff --git a/org.simantics.proconf.processeditor/icons/factory.svg b/org.simantics.proconf.processeditor/icons/factory.svg
new file mode 100644 (file)
index 0000000..e05205c
--- /dev/null
@@ -0,0 +1,308 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="100"
+   height="100"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.44"
+   inkscape:export-filename="D:\dev\icons\factory.png"
+   inkscape:export-xdpi="14.4"
+   inkscape:export-ydpi="14.4"
+   sodipodi:docbase="D:\dev\icons"
+   sodipodi:docname="factory.svg"
+   version="1.0">
+  <defs
+     id="defs4">
+    <linearGradient
+       id="linearGradient10747">
+      <stop
+         style="stop-color:blue;stop-opacity:1;"
+         offset="0"
+         id="stop10749" />
+      <stop
+         style="stop-color:aqua;stop-opacity:1;"
+         offset="1"
+         id="stop10751" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient10747"
+       id="linearGradient10753"
+       x1="20.142487"
+       y1="1011.8181"
+       x2="20.142487"
+       y2="1019.4606"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient10747"
+       id="linearGradient11642"
+       gradientUnits="userSpaceOnUse"
+       x1="20.142487"
+       y1="1011.8181"
+       x2="20.142487"
+       y2="1019.4606"
+       gradientTransform="translate(11.59326,6.479275e-2)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient10747"
+       id="linearGradient11646"
+       gradientUnits="userSpaceOnUse"
+       x1="20.142487"
+       y1="1011.8181"
+       x2="20.142487"
+       y2="1019.4606"
+       gradientTransform="translate(23.6399,6.479232e-2)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient10747"
+       id="linearGradient12543"
+       gradientUnits="userSpaceOnUse"
+       x1="20.142487"
+       y1="1011.8181"
+       x2="20.142487"
+       y2="1019.4606" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient10747"
+       id="linearGradient12545"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(11.59326,6.479275e-2)"
+       x1="20.142487"
+       y1="1011.8181"
+       x2="20.142487"
+       y2="1019.4606" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient10747"
+       id="linearGradient12547"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(23.6399,6.479232e-2)"
+       x1="20.142487"
+       y1="1011.8181"
+       x2="20.142487"
+       y2="1019.4606" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient10747"
+       id="linearGradient1943"
+       gradientUnits="userSpaceOnUse"
+       x1="20.142487"
+       y1="1011.8181"
+       x2="20.142487"
+       y2="1019.4606" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient10747"
+       id="linearGradient1945"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(11.59326,6.479275e-2)"
+       x1="20.142487"
+       y1="1011.8181"
+       x2="20.142487"
+       y2="1019.4606" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient10747"
+       id="linearGradient1947"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(23.6399,6.479232e-2)"
+       x1="20.142487"
+       y1="1011.8181"
+       x2="20.142487"
+       y2="1019.4606" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     gridtolerance="10000"
+     guidetolerance="10"
+     objecttolerance="10"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="7.72"
+     inkscape:cx="50"
+     inkscape:cy="53.887018"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     inkscape:window-width="1280"
+     inkscape:window-height="968"
+     inkscape:window-x="-4"
+     inkscape:window-y="-4"
+     width="100px"
+     height="100px" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1">
+    <g
+       id="g1923"
+       transform="translate(0,-952.3316)">
+      <rect
+         y="952.36218"
+         x="0"
+         height="100"
+         width="100"
+         id="rect1874"
+         style="fill:#00fd00;fill-opacity:0;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+      <g
+         id="g1905">
+        <rect
+           style="fill:#d30000;fill-opacity:1;stroke:black;stroke-width:0.99912792;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+           id="rect2768"
+           width="9.0682287"
+           height="69.819527"
+           x="9.9736586"
+           y="974.77106" />
+        <g
+           id="g12537"
+           transform="matrix(1.681297,0,0,1,1.435511,0.129534)">
+          <rect
+             ry="0"
+             y="1005.8278"
+             x="10.411273"
+             height="38.664726"
+             width="42.032604"
+             id="rect2766"
+             style="fill:#d30000;fill-opacity:1;stroke:black;stroke-width:0.93630695;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+          <rect
+             y="1011.8181"
+             x="15.803109"
+             height="7.642487"
+             width="8.6787567"
+             id="rect9860"
+             style="fill:url(#linearGradient1943);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.06417111" />
+          <rect
+             y="1011.8829"
+             x="27.396372"
+             height="7.642487"
+             width="8.6787567"
+             id="rect11640"
+             style="fill:url(#linearGradient1945);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.06417111" />
+          <rect
+             y="1011.883"
+             x="39.443005"
+             height="7.642487"
+             width="8.6787567"
+             id="rect11644"
+             style="fill:url(#linearGradient1947);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.06417111" />
+        </g>
+        <g
+           id="g1894">
+          <path
+             transform="translate(-36.39896,5.829015)"
+             d="M 74.222796 966.48132 A 7.2538862 5.8290157 0 1 1  59.715024,966.48132 A 7.2538862 5.8290157 0 1 1  74.222796 966.48132 z"
+             sodipodi:ry="5.8290157"
+             sodipodi:rx="7.2538862"
+             sodipodi:cy="966.48132"
+             sodipodi:cx="66.96891"
+             id="path2770"
+             style="fill:black;fill-opacity:0.28877007;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+             sodipodi:type="arc" />
+          <path
+             transform="translate(-57.12436,-10.23316)"
+             d="M 85.621764 974.12384 A 7.5129533 8.4196892 0 1 1  70.595857,974.12384 A 7.5129533 8.4196892 0 1 1  85.621764 974.12384 z"
+             sodipodi:ry="8.4196892"
+             sodipodi:rx="7.5129533"
+             sodipodi:cy="974.12384"
+             sodipodi:cx="78.10881"
+             id="path2772"
+             style="fill:black;fill-opacity:0.44117647;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+             sodipodi:type="arc" />
+          <path
+             transform="translate(-46.76166,-0.259068)"
+             d="M 98.834197 969.13678 A 8.6139898 7.9663215 0 1 1  81.606217,969.13678 A 8.6139898 7.9663215 0 1 1  98.834197 969.13678 z"
+             sodipodi:ry="7.9663215"
+             sodipodi:rx="8.6139898"
+             sodipodi:cy="969.13678"
+             sodipodi:cx="90.220207"
+             id="path2774"
+             style="fill:black;fill-opacity:0.33422463;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.06417111"
+             sodipodi:type="arc" />
+          <path
+             transform="matrix(0.932331,0,0,0.869919,-40.39746,117.1935)"
+             d="M 98.834197 969.13678 A 8.6139898 7.9663215 0 1 1  81.606217,969.13678 A 8.6139898 7.9663215 0 1 1  98.834197 969.13678 z"
+             sodipodi:ry="7.9663215"
+             sodipodi:rx="8.6139898"
+             sodipodi:cy="969.13678"
+             sodipodi:cx="90.220207"
+             id="path9856"
+             style="fill:black;fill-opacity:0.33422463;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.06417111"
+             sodipodi:type="arc" />
+          <path
+             transform="translate(-32.44819,-6.411903)"
+             d="M 98.834197 969.13678 A 8.6139898 7.9663215 0 1 1  81.606217,969.13678 A 8.6139898 7.9663215 0 1 1  98.834197 969.13678 z"
+             sodipodi:ry="7.9663215"
+             sodipodi:rx="8.6139898"
+             sodipodi:cy="969.13678"
+             sodipodi:cx="90.220207"
+             id="path9858"
+             style="fill:black;fill-opacity:0.33422463;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.06417111"
+             sodipodi:type="arc" />
+          <path
+             transform="translate(-47.21503,8.484471)"
+             d="M 98.834197 969.13678 A 8.6139898 7.9663215 0 1 1  81.606217,969.13678 A 8.6139898 7.9663215 0 1 1  98.834197 969.13678 z"
+             sodipodi:ry="7.9663215"
+             sodipodi:rx="8.6139898"
+             sodipodi:cy="969.13678"
+             sodipodi:cx="90.220207"
+             id="path12533"
+             style="fill:black;fill-opacity:0.33422463;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.06417111"
+             sodipodi:type="arc" />
+          <path
+             transform="matrix(0.691729,0,0,0.699187,-30.08931,285.3113)"
+             d="M 98.834197 969.13678 A 8.6139898 7.9663215 0 1 1  81.606217,969.13678 A 8.6139898 7.9663215 0 1 1  98.834197 969.13678 z"
+             sodipodi:ry="7.9663215"
+             sodipodi:rx="8.6139898"
+             sodipodi:cy="969.13678"
+             sodipodi:cx="90.220207"
+             id="path12535"
+             style="fill:black;fill-opacity:0.33422463;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.06417111"
+             sodipodi:type="arc" />
+          <path
+             transform="translate(-32.57772,4.59846)"
+             d="M 98.834197 969.13678 A 8.6139898 7.9663215 0 1 1  81.606217,969.13678 A 8.6139898 7.9663215 0 1 1  98.834197 969.13678 z"
+             sodipodi:ry="7.9663215"
+             sodipodi:rx="8.6139898"
+             sodipodi:cy="969.13678"
+             sodipodi:cx="90.220207"
+             id="path12549"
+             style="fill:black;fill-opacity:0.33422463;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.06417111"
+             sodipodi:type="arc" />
+          <path
+             transform="translate(-19.75388,-0.453354)"
+             d="M 98.834197 969.13678 A 8.6139898 7.9663215 0 1 1  81.606217,969.13678 A 8.6139898 7.9663215 0 1 1  98.834197 969.13678 z"
+             sodipodi:ry="7.9663215"
+             sodipodi:rx="8.6139898"
+             sodipodi:cy="969.13678"
+             sodipodi:cx="90.220207"
+             id="path12551"
+             style="fill:black;fill-opacity:0.33422463;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.06417111"
+             sodipodi:type="arc" />
+        </g>
+      </g>
+    </g>
+  </g>
+</svg>
diff --git a/org.simantics.proconf.processeditor/icons/middle.png b/org.simantics.proconf.processeditor/icons/middle.png
new file mode 100644 (file)
index 0000000..4e3d03e
Binary files /dev/null and b/org.simantics.proconf.processeditor/icons/middle.png differ
diff --git a/org.simantics.proconf.processeditor/icons/middle.svg b/org.simantics.proconf.processeditor/icons/middle.svg
new file mode 100644 (file)
index 0000000..670c3b4
--- /dev/null
@@ -0,0 +1,190 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="64px"
+   height="64px"
+   id="svg2157"
+   sodipodi:version="0.32"
+   inkscape:version="0.45+0.46pre2+devel"
+   sodipodi:docbase="C:\Documents and Settings\Make\Desktop"
+   sodipodi:docname="middle.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   inkscape:export-filename="D:\dev\icons\New Folder\middle.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90">
+  <defs
+     id="defs2159">
+    <inkscape:perspective
+       sodipodi:type="inkscape:persp3d"
+       inkscape:vp_x="-50 : 600 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_z="700 : 600 : 1"
+       inkscape:persp3d-origin="300 : 400 : 1"
+       id="perspective31" />
+    <linearGradient
+       id="linearGradient3149">
+      <stop
+         id="stop3151"
+         offset="0"
+         style="stop-color:#c0c03f;stop-opacity:1;" />
+      <stop
+         id="stop3153"
+         offset="1"
+         style="stop-color:#c0a63f;stop-opacity:1;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient7046">
+      <stop
+         style="stop-color:#ffff00;stop-opacity:1;"
+         offset="0"
+         id="stop7048" />
+      <stop
+         style="stop-color:#ffcd00;stop-opacity:1;"
+         offset="1"
+         id="stop7050" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient5088">
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="0"
+         id="stop5090" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:0;"
+         offset="1"
+         id="stop5092" />
+    </linearGradient>
+    <filter
+       inkscape:collect="always"
+       id="filter11994">
+      <feGaussianBlur
+         inkscape:collect="always"
+         stdDeviation="1.375"
+         id="feGaussianBlur11996" />
+    </filter>
+    <filter
+       inkscape:collect="always"
+       id="filter12983">
+      <feGaussianBlur
+         inkscape:collect="always"
+         stdDeviation="0.915"
+         id="feGaussianBlur12985" />
+    </filter>
+    <filter
+       inkscape:collect="always"
+       x="-0.14285714"
+       width="1.2857143"
+       y="-0.10344828"
+       height="1.2068966"
+       id="filter5187">
+      <feGaussianBlur
+         inkscape:collect="always"
+         stdDeviation="1.25"
+         id="feGaussianBlur5189" />
+    </filter>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient5088"
+       id="linearGradient5094"
+       x1="20.198912"
+       y1="-9.0645924"
+       x2="35.243752"
+       y2="39.135406"
+       gradientUnits="userSpaceOnUse" />
+    <filter
+       inkscape:collect="always"
+       id="filter6073">
+      <feGaussianBlur
+         inkscape:collect="always"
+         stdDeviation="0.62861738"
+         id="feGaussianBlur6075" />
+    </filter>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient7046"
+       id="linearGradient7052"
+       x1="32"
+       y1="59.5"
+       x2="32"
+       y2="4.5"
+       gradientUnits="userSpaceOnUse" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="1"
+     inkscape:cx="32"
+     inkscape:cy="28.07"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     inkscape:document-units="px"
+     inkscape:grid-bbox="true"
+     inkscape:window-width="739"
+     inkscape:window-height="573"
+     inkscape:window-x="367"
+     inkscape:window-y="140" />
+  <metadata
+     id="metadata2162">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer">
+    <path
+       sodipodi:type="arc"
+       style="fill:#000000;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter12983);fill-opacity:1"
+       id="path2169"
+       sodipodi:cx="32"
+       sodipodi:cy="32"
+       sodipodi:rx="30"
+       sodipodi:ry="30"
+       d="M 62 32 A 30 30 0 1 1  2,32 A 30 30 0 1 1  62 32 z" />
+    <path
+       sodipodi:type="arc"
+       style="fill:url(#linearGradient7052);fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;fill-opacity:1.0;filter:url(#filter11994)"
+       id="path2167"
+       sodipodi:cx="32"
+       sodipodi:cy="32"
+       sodipodi:rx="27"
+       sodipodi:ry="27"
+       d="M 59 32 A 27 27 0 1 1  5,32 A 27 27 0 1 1  59 32 z" />
+    <path
+       style="fill:#000000;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;fill-opacity:1;filter:url(#filter5187)"
+       d="M 32,32 L 47,17 L 53,23 L 44,32 L 53,41 L 47,47 L 32,32 z "
+       id="path2168"
+       sodipodi:nodetypes="ccccccc" />
+    <use
+       x="0"
+       y="0"
+       xlink:href="#path2168"
+       id="use5195"
+       transform="matrix(-1,0,0,-1,64,64)"
+       width="64"
+       height="64" />
+    <path
+       style="fill:url(#linearGradient5094);fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;fill-opacity:1.0;filter:url(#filter6073)"
+       d="M 32 2 C 15.44 2 2 15.44 2 32 C 2 32.158352 1.9975512 32.310977 2 32.46875 C 8.1463048 32.486214 16.553215 32.403245 20.3125 31.8125 C 27.274155 30.718527 40.93099 29.497975 55.34375 13.15625 C 49.842663 6.3498757 41.426528 2 32 2 z "
+       id="path2170" />
+  </g>
+</svg>
diff --git a/org.simantics.proconf.processeditor/icons/plus.png b/org.simantics.proconf.processeditor/icons/plus.png
new file mode 100644 (file)
index 0000000..1d6b816
Binary files /dev/null and b/org.simantics.proconf.processeditor/icons/plus.png differ
diff --git a/org.simantics.proconf.processeditor/icons/plus.svg b/org.simantics.proconf.processeditor/icons/plus.svg
new file mode 100644 (file)
index 0000000..7338a01
--- /dev/null
@@ -0,0 +1,184 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="64px"
+   height="64px"
+   id="svg2157"
+   sodipodi:version="0.32"
+   inkscape:version="0.45+0.46pre2+devel"
+   sodipodi:docbase="C:\Documents and Settings\Make\Desktop"
+   sodipodi:docname="plus.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   inkscape:export-filename="D:\dev\icons\New Folder\plus.png"
+   inkscape:export-xdpi="45"
+   inkscape:export-ydpi="45">
+  <defs
+     id="defs2159">
+    <inkscape:perspective
+       sodipodi:type="inkscape:persp3d"
+       inkscape:vp_x="-50 : 600 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_z="700 : 600 : 1"
+       inkscape:persp3d-origin="300 : 400 : 1"
+       id="perspective31" />
+    <inkscape:perspective
+       sodipodi:type="inkscape:persp3d"
+       inkscape:vp_x="-50 : 600 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_z="700 : 600 : 1"
+       inkscape:persp3d-origin="300 : 400 : 1"
+       id="perspective30" />
+    <linearGradient
+       id="linearGradient3149">
+      <stop
+         id="stop3151"
+         offset="0"
+         style="stop-color:#c0c03f;stop-opacity:1;" />
+      <stop
+         id="stop3153"
+         offset="1"
+         style="stop-color:#c0a63f;stop-opacity:1;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient7046">
+      <stop
+         style="stop-color:#ffff00;stop-opacity:1;"
+         offset="0"
+         id="stop7048" />
+      <stop
+         style="stop-color:#ffcd00;stop-opacity:1;"
+         offset="1"
+         id="stop7050" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient5088">
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="0"
+         id="stop5090" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:0;"
+         offset="1"
+         id="stop5092" />
+    </linearGradient>
+    <filter
+       inkscape:collect="always"
+       id="filter11994">
+      <feGaussianBlur
+         inkscape:collect="always"
+         stdDeviation="1.375"
+         id="feGaussianBlur11996" />
+    </filter>
+    <filter
+       inkscape:collect="always"
+       id="filter12983">
+      <feGaussianBlur
+         inkscape:collect="always"
+         stdDeviation="0.915"
+         id="feGaussianBlur12985" />
+    </filter>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient5088"
+       id="linearGradient5094"
+       x1="20.198912"
+       y1="-9.0645924"
+       x2="35.243752"
+       y2="39.135406"
+       gradientUnits="userSpaceOnUse" />
+    <filter
+       inkscape:collect="always"
+       id="filter6073">
+      <feGaussianBlur
+         inkscape:collect="always"
+         stdDeviation="0.62861738"
+         id="feGaussianBlur6075" />
+    </filter>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient7046"
+       id="linearGradient7052"
+       x1="32"
+       y1="59.5"
+       x2="32"
+       y2="4.5"
+       gradientUnits="userSpaceOnUse" />
+    <filter
+       inkscape:collect="always"
+       id="filter3153">
+      <feGaussianBlur
+         inkscape:collect="always"
+         stdDeviation="1.0725"
+         id="feGaussianBlur3155" />
+    </filter>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="5"
+     inkscape:cx="32"
+     inkscape:cy="32"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     inkscape:document-units="px"
+     inkscape:grid-bbox="true"
+     inkscape:window-width="857"
+     inkscape:window-height="644"
+     inkscape:window-x="594"
+     inkscape:window-y="111" />
+  <metadata
+     id="metadata2162">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer">
+    <path
+       sodipodi:type="arc"
+       style="fill:#000000;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter12983);fill-opacity:1"
+       id="path2169"
+       sodipodi:cx="32"
+       sodipodi:cy="32"
+       sodipodi:rx="30"
+       sodipodi:ry="30"
+       d="M 62 32 A 30 30 0 1 1  2,32 A 30 30 0 1 1  62 32 z" />
+    <path
+       sodipodi:type="arc"
+       style="fill:url(#linearGradient7052);fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;fill-opacity:1.0;filter:url(#filter11994)"
+       id="path2167"
+       sodipodi:cx="32"
+       sodipodi:cy="32"
+       sodipodi:rx="27"
+       sodipodi:ry="27"
+       d="M 59 32 A 27 27 0 1 1  5,32 A 27 27 0 1 1  59 32 z" />
+    <path
+       style="fill:#000000;fill-rule:evenodd;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;fill-opacity:1;filter:url(#filter3153);stroke-miterlimit:4;stroke-dasharray:none"
+       d="M 15,34 L 15,30 L 30,30 L 30,15 L 34,15 L 34,30 L 49,30 L 49,34 L 34,34 L 34,49 L 30,49 L 30,34 L 15,34 z "
+       id="path2178" />
+    <path
+       style="fill:url(#linearGradient5094);fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;fill-opacity:1.0;filter:url(#filter6073)"
+       d="M 32 2 C 15.44 2 2 15.44 2 32 C 2 32.158352 1.9975512 32.310977 2 32.46875 C 8.1463048 32.486214 16.553215 32.403245 20.3125 31.8125 C 27.274155 30.718527 40.93099 29.497975 55.34375 13.15625 C 49.842663 6.3498757 41.426528 2 32 2 z "
+       id="path2170" />
+  </g>
+</svg>
diff --git a/org.simantics.proconf.processeditor/icons/tank.png b/org.simantics.proconf.processeditor/icons/tank.png
new file mode 100644 (file)
index 0000000..44015a3
Binary files /dev/null and b/org.simantics.proconf.processeditor/icons/tank.png differ
diff --git a/org.simantics.proconf.processeditor/icons/tank.svg b/org.simantics.proconf.processeditor/icons/tank.svg
new file mode 100644 (file)
index 0000000..8e8784f
--- /dev/null
@@ -0,0 +1,184 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="16"
+   height="16"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.45+0.46pre2+devel"
+   version="1.0"
+   sodipodi:docname="tank.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   inkscape:export-filename="D:\dev\icons\tank.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90">
+  <defs
+     id="defs4">
+    <inkscape:perspective
+       sodipodi:type="inkscape:persp3d"
+       inkscape:vp_x="-50 : 600 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_z="700 : 600 : 1"
+       inkscape:persp3d-origin="300 : 400 : 1"
+       id="perspective24" />
+    <linearGradient
+       id="linearGradient3186">
+      <stop
+         style="stop-color:#ff0000;stop-opacity:1;"
+         offset="0"
+         id="stop3188" />
+      <stop
+         id="stop3194"
+         offset="0.5"
+         style="stop-color:#ffffff;stop-opacity:1;" />
+      <stop
+         style="stop-color:#ff0000;stop-opacity:1;"
+         offset="1"
+         id="stop3190" />
+    </linearGradient>
+    <inkscape:perspective
+       sodipodi:type="inkscape:persp3d"
+       inkscape:vp_x="-50 : 600 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_z="700 : 600 : 1"
+       inkscape:persp3d-origin="300 : 400 : 1"
+       id="perspective10" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3186"
+       id="linearGradient3192"
+       x1="5.3350925"
+       y1="6.0993748"
+       x2="7.3876858"
+       y2="12.259375"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-10e-2,-1.8)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3186"
+       id="linearGradient3196"
+       x1="11.69074"
+       y1="4.8200002"
+       x2="13.4933"
+       y2="9.000001"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-10e-2,-1.8)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3186"
+       id="linearGradient3198"
+       x1="8.4300299"
+       y1="7.3143148"
+       x2="8.8612204"
+       y2="10.414315"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-10e-2,-1.8)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3186"
+       id="linearGradient3200"
+       x1="2.3299999"
+       y1="6.6100001"
+       x2="4.7900004"
+       y2="6.5100002"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-10e-2,-1.8)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3186"
+       id="linearGradient3257"
+       x1="8"
+       y1="4"
+       x2="8"
+       y2="10"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3186"
+       id="linearGradient3286"
+       x1="8"
+       y1="3.96875"
+       x2="8"
+       y2="9.96875"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(0,-0.96875)" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     gridtolerance="10000"
+     guidetolerance="10"
+     objecttolerance="10"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="50"
+     inkscape:cx="7.9134759"
+     inkscape:cy="8.287091"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     inkscape:window-width="1280"
+     inkscape:window-height="968"
+     inkscape:window-x="0"
+     inkscape:window-y="22"
+     showguides="true"
+     inkscape:guide-bbox="true">
+    <sodipodi:guide
+       orientation="0,1"
+       position="1.66,13.02"
+       id="guide3236" />
+    <sodipodi:guide
+       orientation="0,1"
+       position="1.26,5"
+       id="guide3238" />
+    <inkscape:grid
+       type="xygrid"
+       id="grid3259"
+       visible="true"
+       enabled="true" />
+  </sodipodi:namedview>
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1">
+    <rect
+       style="fill:#ff0000;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="rect3261"
+       width="2"
+       height="4"
+       x="4"
+       y="10.03125" />
+    <rect
+       style="fill:#ff0000;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="rect3263"
+       width="2"
+       height="4"
+       x="10"
+       y="10.03125" />
+    <path
+       style="fill:url(#linearGradient3286);fill-opacity:1;stroke:#000000;stroke-width:0.50000000000000000;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="M 3,2 C 1.896,2 1,3.8177299 1,6.03125 C 1,8.2447701 1.896,10.03125 3,10.03125 L 13,10.03125 C 14.104,10.03125 15,8.2447701 15,6.03125 C 15,3.8177299 14.104,2 13,2 L 3,2 z"
+       id="path3269" />
+  </g>
+</svg>
diff --git a/org.simantics.proconf.processeditor/icons/translate_d.png b/org.simantics.proconf.processeditor/icons/translate_d.png
new file mode 100644 (file)
index 0000000..f4b3b60
Binary files /dev/null and b/org.simantics.proconf.processeditor/icons/translate_d.png differ
diff --git a/org.simantics.proconf.processeditor/icons/translate_d.svg b/org.simantics.proconf.processeditor/icons/translate_d.svg
new file mode 100644 (file)
index 0000000..1666929
--- /dev/null
@@ -0,0 +1,118 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="100"
+   height="100"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.44"
+   version="1.0"
+   inkscape:export-filename="D:\dev\icons\translate_d.png"
+   inkscape:export-xdpi="14"
+   inkscape:export-ydpi="14"
+   sodipodi:docname="translate_d.svg"
+   sodipodi:docbase="D:\dev\icons">
+  <defs
+     id="defs4">
+    <linearGradient
+       id="linearGradient2184">
+      <stop
+         style="stop-color:#2aae3a;stop-opacity:1;"
+         offset="0"
+         id="stop2186" />
+      <stop
+         style="stop-color:#2aae3a;stop-opacity:0;"
+         offset="1"
+         id="stop2188" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3146">
+      <stop
+         style="stop-color:#0000ff;stop-opacity:1;"
+         offset="0"
+         id="stop3148" />
+      <stop
+         id="stop3156"
+         offset="0.5"
+         style="stop-color:#006eff;stop-opacity:1;" />
+      <stop
+         style="stop-color:#00ffff;stop-opacity:1;"
+         offset="0.75"
+         id="stop3158" />
+      <stop
+         style="stop-color:#0079ff;stop-opacity:1;"
+         offset="1"
+         id="stop3150" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2184"
+       id="linearGradient2190"
+       x1="8.00577"
+       y1="50.15"
+       x2="92.29423"
+       y2="50.15"
+       gradientUnits="userSpaceOnUse" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2184"
+       id="radialGradient4579"
+       cx="50"
+       cy="50"
+       fx="50"
+       fy="50"
+       r="52"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.809436,0,0,0.809436,9.463433,9.592966)" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     gridtolerance="10000"
+     guidetolerance="10"
+     objecttolerance="10"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="7.72"
+     inkscape:cx="50"
+     inkscape:cy="55.181347"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     width="100px"
+     height="100px"
+     inkscape:window-width="1280"
+     inkscape:window-height="968"
+     inkscape:window-x="-4"
+     inkscape:window-y="-4" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1">
+    <path
+       style="fill:url(#radialGradient4579);fill-opacity:1;fill-rule:evenodd;stroke:#009c00;stroke-width:4;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="M 25.652153,41.970406 L 25.652153,33.876046 L 9.4634316,50.064767 L 25.652153,66.253488 L 25.652153,58.159127 L 74.218314,58.159127 L 74.218314,66.253488 L 90.407036,50.064767 L 74.218314,33.876046 L 74.218314,41.970406 L 25.652153,41.970406 z "
+       id="path1879"
+       sodipodi:nodetypes="ccccccccccc" />
+  </g>
+</svg>
diff --git a/org.simantics.proconf.processeditor/icons/x-axis.png b/org.simantics.proconf.processeditor/icons/x-axis.png
new file mode 100644 (file)
index 0000000..8eb8a0d
Binary files /dev/null and b/org.simantics.proconf.processeditor/icons/x-axis.png differ
diff --git a/org.simantics.proconf.processeditor/icons/x-axis.svg b/org.simantics.proconf.processeditor/icons/x-axis.svg
new file mode 100644 (file)
index 0000000..e5c2293
--- /dev/null
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="744.09448819"
+   height="1052.3622047"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.44"
+   sodipodi:docbase="D:\dev\icons"
+   sodipodi:docname="x-axis.svg"
+   inkscape:export-filename="D:\dev\icons\x-axis.png"
+   inkscape:export-xdpi="14.4"
+   inkscape:export-ydpi="14.4">
+  <defs
+     id="defs4" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     gridtolerance="10000"
+     guidetolerance="10"
+     objecttolerance="10"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="7.7183778"
+     inkscape:cx="50"
+     inkscape:cy="49.989491"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showguides="true"
+     inkscape:guide-bbox="true"
+     inkscape:window-width="1280"
+     inkscape:window-height="968"
+     inkscape:window-x="-4"
+     inkscape:window-y="-4" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1">
+    <rect
+       style="fill:#00fd00;fill-opacity:0;stroke:none;stroke-width:16;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="rect1958"
+       width="100"
+       height="100"
+       x="0"
+       y="952.36218" />
+    <text
+       xml:space="preserve"
+       style="font-size:79.64511871px;font-style:normal;font-weight:normal;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+       x="22.170273"
+       y="1016.5383"
+       id="text2846"><tspan
+         sodipodi:role="line"
+         id="tspan2848"
+         x="22.170273"
+         y="1016.5383">X</tspan></text>
+    <path
+       style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="M 89.651844,1031.0133 L 4.4186832,1031.0133 M 77.083149,1048.3832 L 94.286422,1031.1799 L 77.551265,1014.4447"
+       id="path2850"
+       sodipodi:nodetypes="cc" />
+  </g>
+</svg>
diff --git a/org.simantics.proconf.processeditor/icons/x-plane.png b/org.simantics.proconf.processeditor/icons/x-plane.png
new file mode 100644 (file)
index 0000000..6b57f1e
Binary files /dev/null and b/org.simantics.proconf.processeditor/icons/x-plane.png differ
diff --git a/org.simantics.proconf.processeditor/icons/x-plane.svg b/org.simantics.proconf.processeditor/icons/x-plane.svg
new file mode 100644 (file)
index 0000000..316d3ce
--- /dev/null
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="744.09448819"
+   height="1052.3622047"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.44"
+   sodipodi:docbase="D:\dev\icons"
+   sodipodi:docname="x-plane.svg"
+   inkscape:export-filename="D:\dev\icons\x-plane.png"
+   inkscape:export-xdpi="14.4"
+   inkscape:export-ydpi="14.4">
+  <defs
+     id="defs4" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     gridtolerance="10000"
+     guidetolerance="10"
+     objecttolerance="10"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="7.7183778"
+     inkscape:cx="50"
+     inkscape:cy="63.68827"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showguides="true"
+     inkscape:guide-bbox="true"
+     inkscape:window-width="1280"
+     inkscape:window-height="968"
+     inkscape:window-x="-4"
+     inkscape:window-y="-4" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1">
+    <rect
+       style="fill:#00fd00;fill-opacity:0;stroke:none;stroke-width:16;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="rect1958"
+       width="100"
+       height="100"
+       x="0"
+       y="952.36218" />
+    <text
+       xml:space="preserve"
+       style="font-size:90.08292227;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr;text-anchor:start;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+       x="28.756321"
+       y="1082.9758"
+       id="text2846"
+       sodipodi:linespacing="125%"
+       transform="scale(1.065357,0.938653)"><tspan
+         sodipodi:role="line"
+         id="tspan4650"
+         x="28.756321"
+         y="1082.9758">X</tspan></text>
+    <path
+       style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="M 89.651844,1031.0133 L 16.726969,1031.0133 M 77.083149,1048.3832 L 94.286422,1031.1799 L 77.551265,1031.0285"
+       id="path2850"
+       sodipodi:nodetypes="ccccc" />
+    <path
+       style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="M 20.588217,963.08889 L 20.588217,1034.8478 M 20.596956,975.65763 L 20.754816,958.45431 L 4.0196163,975.18943"
+       id="path4646"
+       sodipodi:nodetypes="ccccc" />
+  </g>
+</svg>
diff --git a/org.simantics.proconf.processeditor/icons/y-axis.png b/org.simantics.proconf.processeditor/icons/y-axis.png
new file mode 100644 (file)
index 0000000..ca60724
Binary files /dev/null and b/org.simantics.proconf.processeditor/icons/y-axis.png differ
diff --git a/org.simantics.proconf.processeditor/icons/y-axis.svg b/org.simantics.proconf.processeditor/icons/y-axis.svg
new file mode 100644 (file)
index 0000000..65eddcf
--- /dev/null
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="744.09448819"
+   height="1052.3622047"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.44"
+   sodipodi:docbase="D:\dev\icons"
+   sodipodi:docname="y-axis.svg"
+   inkscape:export-filename="D:\dev\icons\y-axis.png"
+   inkscape:export-xdpi="14.4"
+   inkscape:export-ydpi="14.4">
+  <defs
+     id="defs4" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     gridtolerance="10000"
+     guidetolerance="10"
+     objecttolerance="10"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="7.7183778"
+     inkscape:cx="50"
+     inkscape:cy="49.989491"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showguides="true"
+     inkscape:guide-bbox="true"
+     inkscape:window-width="1280"
+     inkscape:window-height="968"
+     inkscape:window-x="-4"
+     inkscape:window-y="-4" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1">
+    <rect
+       style="fill:#00fd00;fill-opacity:0;stroke:none;stroke-width:16;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="rect1958"
+       width="100"
+       height="100"
+       x="0"
+       y="952.36218" />
+    <text
+       xml:space="preserve"
+       style="font-size:79.64511871;font-style:normal;font-weight:normal;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;font-stretch:normal;font-variant:normal;text-anchor:start;text-align:start;writing-mode:lr;line-height:125%"
+       x="22.170273"
+       y="1016.5383"
+       id="text2846"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4642"
+         x="22.170273"
+         y="1016.5383">Y</tspan></text>
+    <path
+       style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="M 89.651844,1031.0133 L 4.4186832,1031.0133 M 77.083149,1048.3832 L 94.286422,1031.1799 L 77.551265,1014.4447"
+       id="path2850"
+       sodipodi:nodetypes="cc" />
+  </g>
+</svg>
diff --git a/org.simantics.proconf.processeditor/icons/y-plane.png b/org.simantics.proconf.processeditor/icons/y-plane.png
new file mode 100644 (file)
index 0000000..59c3a2b
Binary files /dev/null and b/org.simantics.proconf.processeditor/icons/y-plane.png differ
diff --git a/org.simantics.proconf.processeditor/icons/y-plane.svg b/org.simantics.proconf.processeditor/icons/y-plane.svg
new file mode 100644 (file)
index 0000000..69d3814
--- /dev/null
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="744.09448819"
+   height="1052.3622047"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.44"
+   sodipodi:docbase="D:\dev\icons"
+   sodipodi:docname="y-plane.svg"
+   inkscape:export-filename="D:\dev\icons\y-plane.png"
+   inkscape:export-xdpi="14.4"
+   inkscape:export-ydpi="14.4">
+  <defs
+     id="defs4" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     gridtolerance="10000"
+     guidetolerance="10"
+     objecttolerance="10"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="7.7183778"
+     inkscape:cx="50"
+     inkscape:cy="63.68827"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showguides="true"
+     inkscape:guide-bbox="true"
+     inkscape:window-width="1280"
+     inkscape:window-height="968"
+     inkscape:window-x="-4"
+     inkscape:window-y="-4" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1">
+    <rect
+       style="fill:#00fd00;fill-opacity:0;stroke:none;stroke-width:16;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="rect1958"
+       width="100"
+       height="100"
+       x="0"
+       y="952.36218" />
+    <text
+       xml:space="preserve"
+       style="font-size:90.08292227;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr;text-anchor:start;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+       x="28.756321"
+       y="1082.9758"
+       id="text2846"
+       sodipodi:linespacing="125%"
+       transform="scale(1.065357,0.938653)"><tspan
+         sodipodi:role="line"
+         id="tspan4648"
+         x="28.756321"
+         y="1082.9758">Y</tspan></text>
+    <path
+       style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="M 89.651844,1031.0133 L 16.726969,1031.0133 M 77.083149,1048.3832 L 94.286422,1031.1799 L 77.551265,1031.0285"
+       id="path2850"
+       sodipodi:nodetypes="ccccc" />
+    <path
+       style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="M 20.588217,963.08889 L 20.588217,1034.8478 M 20.596956,975.65763 L 20.754816,958.45431 L 4.0196163,975.18943"
+       id="path4646"
+       sodipodi:nodetypes="ccccc" />
+  </g>
+</svg>
diff --git a/org.simantics.proconf.processeditor/icons/z-axis.png b/org.simantics.proconf.processeditor/icons/z-axis.png
new file mode 100644 (file)
index 0000000..11a5741
Binary files /dev/null and b/org.simantics.proconf.processeditor/icons/z-axis.png differ
diff --git a/org.simantics.proconf.processeditor/icons/z-axis.svg b/org.simantics.proconf.processeditor/icons/z-axis.svg
new file mode 100644 (file)
index 0000000..02e200d
--- /dev/null
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="744.09448819"
+   height="1052.3622047"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.44"
+   sodipodi:docbase="D:\dev\icons"
+   sodipodi:docname="z-axis.svg"
+   inkscape:export-filename="D:\dev\icons\z-axis.png"
+   inkscape:export-xdpi="14.4"
+   inkscape:export-ydpi="14.4">
+  <defs
+     id="defs4" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     gridtolerance="10000"
+     guidetolerance="10"
+     objecttolerance="10"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="7.7183778"
+     inkscape:cx="50"
+     inkscape:cy="49.989491"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showguides="true"
+     inkscape:guide-bbox="true"
+     inkscape:window-width="1280"
+     inkscape:window-height="968"
+     inkscape:window-x="-4"
+     inkscape:window-y="-4" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1">
+    <rect
+       style="fill:#00fd00;fill-opacity:0;stroke:none;stroke-width:16;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="rect1958"
+       width="100"
+       height="100"
+       x="0"
+       y="952.36218" />
+    <text
+       xml:space="preserve"
+       style="font-size:79.64511871px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+       x="20.097298"
+       y="1016.5383"
+       id="text2846"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4644"
+         x="20.097298"
+         y="1016.5383">Z</tspan></text>
+    <path
+       style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="M 89.651844,1031.0133 L 4.4186832,1031.0133 M 77.083149,1048.3832 L 94.286422,1031.1799 L 77.551265,1014.4447"
+       id="path2850"
+       sodipodi:nodetypes="cc" />
+  </g>
+</svg>
diff --git a/org.simantics.proconf.processeditor/icons/z-plane.png b/org.simantics.proconf.processeditor/icons/z-plane.png
new file mode 100644 (file)
index 0000000..d6e9f70
Binary files /dev/null and b/org.simantics.proconf.processeditor/icons/z-plane.png differ
diff --git a/org.simantics.proconf.processeditor/icons/z-plane.svg b/org.simantics.proconf.processeditor/icons/z-plane.svg
new file mode 100644 (file)
index 0000000..d1a654c
--- /dev/null
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="744.09448819"
+   height="1052.3622047"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.44"
+   sodipodi:docbase="D:\dev\icons"
+   sodipodi:docname="z-plane.svg"
+   inkscape:export-filename="D:\dev\icons\z-plane.png"
+   inkscape:export-xdpi="14.4"
+   inkscape:export-ydpi="14.4">
+  <defs
+     id="defs4" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     gridtolerance="10000"
+     guidetolerance="10"
+     objecttolerance="10"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="7.7183778"
+     inkscape:cx="50"
+     inkscape:cy="63.68827"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showguides="true"
+     inkscape:guide-bbox="true"
+     inkscape:window-width="1280"
+     inkscape:window-height="968"
+     inkscape:window-x="-4"
+     inkscape:window-y="-4" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1">
+    <rect
+       style="fill:#00fd00;fill-opacity:0;stroke:none;stroke-width:16;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="rect1958"
+       width="100"
+       height="100"
+       x="0"
+       y="952.36218" />
+    <text
+       xml:space="preserve"
+       style="font-size:90.08292389px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+       x="28.756321"
+       y="1082.9758"
+       id="text2846"
+       sodipodi:linespacing="125%"
+       transform="scale(1.065357,0.938653)"><tspan
+         sodipodi:role="line"
+         id="tspan4644"
+         x="28.756321"
+         y="1082.9758">Z</tspan></text>
+    <path
+       style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="M 89.651844,1031.0133 L 16.726969,1031.0133 M 77.083149,1048.3832 L 94.286422,1031.1799 L 77.551265,1031.0285"
+       id="path2850"
+       sodipodi:nodetypes="ccccc" />
+    <path
+       style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="M 20.588217,963.08889 L 20.588217,1034.8478 M 20.596956,975.65763 L 20.754816,958.45431 L 4.0196163,975.18943"
+       id="path4646"
+       sodipodi:nodetypes="ccccc" />
+  </g>
+</svg>
diff --git a/org.simantics.proconf.processeditor/plugin.xml b/org.simantics.proconf.processeditor/plugin.xml
new file mode 100644 (file)
index 0000000..3350141
--- /dev/null
@@ -0,0 +1,266 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<?eclipse version="3.2"?>\r
+<plugin>\r
+   <extension\r
+         point="org.simantics.db.resourceAdapter">\r
+      <resource_adapter\r
+            adapter_class="fi.vtt.simantics.processeditor.handlers.Plant3DProjectAdapter"\r
+            operation="http://www.vtt.fi/Simantics/Layer0/1.0/Relations#HasProjectTypeAdapter"\r
+            type_uri="http://www.vtt.fi/Simantics/Plant3D/1.0/Types#Plant3DProjectType">\r
+      </resource_adapter>\r
+      <resource_adapter\r
+            adapter_class="fi.vtt.simantics.processeditor.adapters.NozzleConstraintAdapter"\r
+            operation="http://www.vtt.fi/Simantics/G3D/1.0/Relations#HasConstraints"\r
+            type_uri="http://www.vtt.fi/Simantics/Plant3D/1.0/Types#Nozzle">\r
+      </resource_adapter>\r
+      <resource_adapter\r
+            adapter_class="fi.vtt.simantics.processeditor.adapters.InlineComponentConstraintAdapter"\r
+            operation="http://www.vtt.fi/Simantics/G3D/1.0/Relations#HasConstraints"\r
+            type_uri="http://www.vtt.fi/Simantics/Plant3D/1.0/Types#InlineComponent">\r
+      </resource_adapter>\r
+      <resource_adapter\r
+            adapter_class="fi.vtt.simantics.processeditor.adapters.TurnComponentConstraintAdapter"\r
+            operation="http://www.vtt.fi/Simantics/G3D/1.0/Relations#HasConstraints"\r
+            type_uri="http://www.vtt.fi/Simantics/Plant3D/1.0/Types#TurnComponent">\r
+      </resource_adapter>\r
+   </extension>\r
+   <extension\r
+         point="org.eclipse.ui.editors">\r
+      <editor\r
+            class="fi.vtt.simantics.processeditor.views.ProcessEditorPart"\r
+            icon="icons/factory.png"\r
+            id="org.simantics.proconf.processeditor.planteditor"\r
+            name="Plant Editor">\r
+      </editor>\r
+      <editor\r
+            class="fi.vtt.simantics.processeditor.views.PipelineComponentEditorPart"\r
+            icon="icons/Component.png"\r
+            id="org.simantics.proconf.processeditor.componenteditor"\r
+            name="Component Editor">\r
+      </editor>\r
+      <editor\r
+            class="fi.vtt.simantics.processeditor.views.EquipmentEditorPart"\r
+            icon="icons/tank.png"\r
+            id="org.simantics.proconf.processeditor.equipmenteditor"\r
+            name="Equipment Editor">\r
+      </editor>\r
+   </extension>\r
+   <extension\r
+         point="org.eclipse.ui.views">\r
+      <view\r
+            class="fi.vtt.simantics.processeditor.views.PlantStructureView"\r
+            icon="icons/factory.png"\r
+            id="org.simantics.proconf.processeditor.plantstructure"\r
+            name="Plant Structure">\r
+      </view>\r
+   </extension>\r
+   <extension\r
+         point="org.eclipse.ui.commands">\r
+      <command\r
+            categoryId="org.simantics.proconf.processeditor.commands"\r
+            description="New Pipeline Component"\r
+            id="org.simantics.proconf.processeditor.commands.newComponent"\r
+            name="New Pipeline Component">\r
+      </command>\r
+      <command\r
+            categoryId="org.simantics.proconf.processeditor.commands"\r
+            description="New Equipment"\r
+            id="org.simantics.proconf.processeditor.commands.newEquipment"\r
+            name="New Equipment">\r
+      </command>\r
+      <command\r
+            categoryId="org.simantics.proconf.processeditor.commands"\r
+            description="New Plant"\r
+            id="org.simantics.proconf.processeditor.commands.newPlant"\r
+            name="New Plant">\r
+      </command>\r
+      <category\r
+            id="org.simantics.proconf.processeditor.commands"\r
+            name="Plant3D Commands">\r
+      </category>\r
+   </extension>\r
+   <extension\r
+         point="org.eclipse.ui.handlers">\r
+      <handler\r
+            class="fi.vtt.simantics.processeditor.handlers.NewPlantHandler"\r
+            commandId="org.simantics.proconf.processeditor.commands.newPlant">\r
+      </handler>\r
+      <handler\r
+            class="fi.vtt.simantics.processeditor.handlers.NewEquipmentHandler"\r
+            commandId="org.simantics.proconf.processeditor.commands.newEquipment">\r
+      </handler>\r
+      <handler\r
+            class="fi.vtt.simantics.processeditor.handlers.NewComponentHandler"\r
+            commandId="org.simantics.proconf.processeditor.commands.newComponent">\r
+      </handler>\r
+   </extension>\r
+   <extension\r
+         point="org.eclipse.ui.menus">\r
+      <menuContribution\r
+            locationURI="popup:#OEPopup?after=additions">\r
+         <command\r
+               commandId="org.simantics.proconf.processeditor.commands.newPlant"\r
+               icon="icons/factory.png"\r
+               id="org.simantics.proconf.processeditor.popups.newPlant"\r
+               label="New Plant"\r
+               style="push">\r
+            <visibleWhen>\r
+               <and>\r
+                  <with\r
+                        variable="activeContexts">\r
+                     <iterate\r
+                           ifEmpty="false"\r
+                           operator="or">\r
+                        <equals\r
+                              value="org.simantics.proconf.processeditor.plantmodelling">\r
+                        </equals>\r
+                     </iterate>\r
+                  </with>\r
+                  <with\r
+                        variable="selection">\r
+                     <and>\r
+                        <test\r
+                              args="http://www.vtt.fi/Simantics/Layer0/1.0/Types#Library"\r
+                              property="org.simantics.graph.resourceType">\r
+                        </test>\r
+                     </and>\r
+                  </with>\r
+               </and>\r
+            </visibleWhen>\r
+         </command>\r
+         <command\r
+               commandId="org.simantics.proconf.processeditor.commands.newEquipment"\r
+               icon="icons/tank.png"\r
+               id="org.simantics.proconf.processeditor.popups.newEquipment"\r
+               label="New Equipment"\r
+               style="push">\r
+            <visibleWhen>\r
+               <and>\r
+                  <with\r
+                        variable="activeContexts">\r
+                     <iterate\r
+                           ifEmpty="false"\r
+                           operator="or">\r
+                        <equals\r
+                              value="org.simantics.proconf.processeditor.plantmodelling">\r
+                        </equals>\r
+                     </iterate>\r
+                  </with>\r
+                  <with\r
+                        variable="selection">\r
+                     <and>\r
+                        <test\r
+                              args="http://www.vtt.fi/Simantics/Layer0/1.0/Types#Library"\r
+                              property="org.simantics.graph.resourceType">\r
+                        </test>\r
+                     </and>\r
+                  </with>\r
+               </and>\r
+            </visibleWhen>\r
+         </command>\r
+         <command\r
+               commandId="org.simantics.proconf.processeditor.commands.newComponent"\r
+               icon="icons/Component.png"\r
+               id="org.simantics.proconf.processeditor.popups.newComponent"\r
+               label="New  Component"\r
+               style="push">\r
+            <visibleWhen>\r
+               <and>\r
+                  <with\r
+                        variable="activeContexts">\r
+                     <iterate\r
+                           ifEmpty="false"\r
+                           operator="or">\r
+                        <equals\r
+                              value="org.simantics.proconf.processeditor.plantmodelling">\r
+                        </equals>\r
+                     </iterate>\r
+                  </with>\r
+                  <with\r
+                        variable="selection">\r
+                     <and>\r
+                        <test\r
+                              args="http://www.vtt.fi/Simantics/Layer0/1.0/Types#Library"\r
+                              property="org.simantics.graph.resourceType">\r
+                        </test>\r
+                     </and>\r
+                  </with>\r
+               </and>\r
+            </visibleWhen>\r
+         </command>\r
+      </menuContribution>\r
+   </extension>\r
+   <extension\r
+         point="org.simantics.proconf.ui.resourceEditorAdapter">\r
+      <adapterClass\r
+            class="fi.vtt.simantics.processeditor.handlers.Plant3DEditorAdapter"\r
+            id="org.simantics.proconf.processeditor.ResourceEditorDescription1">\r
+      </adapterClass>\r
+      <adapterClass\r
+            class="fi.vtt.simantics.processeditor.handlers.PipelineComponentEditorAdapter"\r
+            id="org.simantics.proconf.processeditor.ResourceEditorDescription2">\r
+      </adapterClass>\r
+      <adapterClass\r
+            class="fi.vtt.simantics.processeditor.handlers.EquipmentEditorAdapter"\r
+            id="org.simantics.proconf.processeditor.ResourceEditorDescription3">\r
+      </adapterClass>\r
+   </extension>\r
+   <extension\r
+         point="org.eclipse.ui.perspectives">\r
+      <perspective\r
+            class="fi.vtt.simantics.processeditor.perspectives.Plant3DModellingPerspective"\r
+            icon="icons/factory.png"\r
+            id="org.simantics.proconf.processeditor.plantmodelling"\r
+            name="3D Plant Modelling">\r
+      </perspective>\r
+   </extension>\r
+   <extension\r
+         point="org.eclipse.ui.perspectiveExtensions">\r
+      <perspectiveExtension\r
+            targetID="org.simantics.proconf.processeditor.plantmodelling">\r
+         <view\r
+               id="org.simantics.proconf.processeditor.plantstructure"\r
+               ratio="0.3"\r
+               relationship="left"\r
+               relative="org.eclipse.ui.editorss"\r
+               visible="true">\r
+         </view>\r
+         <view\r
+               id="org.simantics.proconf.browsing.views.property"\r
+               ratio="0.7"\r
+               relationship="bottom"\r
+               relative="org.simantics.proconf.processeditor.plantstructure"\r
+               visible="true">\r
+         </view>\r
+         <view\r
+               id="org.eclipse.pde.runtime.LogView"\r
+               relationship="fast"\r
+               relative="fi.vtt.proconf.ui.views.property"\r
+               visible="false">\r
+         </view>\r
+      </perspectiveExtension>\r
+   </extension>\r
+   <extension\r
+         point="org.simantics.proconf.g3d.geometry">\r
+      <Geometry\r
+            class="fi.vtt.simantics.processeditor.common.PipeComponentProvider"\r
+            id="org.simantics.proconf.processeditor.Geometry1">\r
+      </Geometry>\r
+   </extension>\r
+   <extension\r
+         point="org.simantics.proconf.ui.perspectiveContextBinding">\r
+      <binding\r
+            contextIds="org.simantics.proconf.processeditor.plantmodelling"\r
+            perspectiveId="org.simantics.proconf.processeditor.plantmodelling">\r
+      </binding>\r
+   </extension>\r
+   <extension\r
+         point="org.eclipse.ui.contexts">\r
+      <context\r
+            id="org.simantics.proconf.processeditor.plantmodelling"\r
+            name="Plant Modelling"\r
+            parentId="org.eclipse.ui.contexts.window">\r
+      </context>\r
+   </extension>\r
+\r
+</plugin>\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/Activator.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/Activator.java
new file mode 100644 (file)
index 0000000..9f2ad49
--- /dev/null
@@ -0,0 +1,97 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007 VTT Technical Research Centre of Finland and others.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package fi.vtt.simantics.processeditor;\r
+\r
+import org.eclipse.ui.plugin.AbstractUIPlugin;\r
+import org.osgi.framework.BundleContext;\r
+import org.simantics.db.Graph;\r
+import org.simantics.db.GraphRequestAdapter;\r
+import org.simantics.db.GraphRequestStatus;\r
+import org.simantics.db.management.ISessionContext;\r
+import org.simantics.db.management.ISessionContextChangedListener;\r
+import org.simantics.db.management.SessionContextChangedEvent;\r
+import org.simantics.proconf.ui.ProConfUI;\r
+\r
+\r
+\r
+\r
+/**\r
+ * The activator class controls the plug-in life cycle\r
+ */\r
+public class Activator extends AbstractUIPlugin {\r
+\r
+       // The plug-in ID\r
+       public static final String PLUGIN_ID = "fi.vtt.simantics.processeditor";\r
+\r
+       // The shared instance\r
+       private static Activator plugin;\r
+       \r
+       /**\r
+        * The constructor\r
+        */\r
+       public Activator() {\r
+       }\r
+\r
+       /*\r
+        * (non-Javadoc)\r
+        * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)\r
+        */\r
+       public void start(BundleContext context) throws Exception {\r
+               super.start(context);\r
+               plugin = this;\r
+               ProConfUI.getSessionContextProvider().addContextChangedListener(new ISessionContextChangedListener() {\r
+                       @Override\r
+                       public void sessionContextChanged(SessionContextChangedEvent event) {\r
+                               ISessionContext ctx = event.getNewValue();\r
+                               if (ctx != null) {\r
+                                       ctx.getSession().asyncRead(new GraphRequestAdapter() {\r
+                                               public GraphRequestStatus perform(Graph g) throws Exception {\r
+                                                       ProcessResource.initialize(g);\r
+                                                       return GraphRequestStatus.transactionComplete();\r
+                                               };\r
+                                       });\r
+                               } else {\r
+                                       ProcessResource.deinitialize();\r
+                               }\r
+                       }\r
+               });\r
+               try {\r
+                       ProConfUI.getSession().asyncRead(new GraphRequestAdapter() {\r
+                               @Override\r
+                               public GraphRequestStatus perform(Graph g) throws Exception {\r
+                                       ProcessResource.initialize(g);\r
+                                       return GraphRequestStatus.transactionComplete();\r
+                               }\r
+                       });\r
+               } catch (Exception e) {\r
+                       \r
+               }\r
+       }\r
+\r
+       /*\r
+        * (non-Javadoc)\r
+        * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)\r
+        */\r
+       public void stop(BundleContext context) throws Exception {\r
+               plugin = null;\r
+               super.stop(context);\r
+       }\r
+\r
+       /**\r
+        * Returns the shared instance\r
+        *\r
+        * @return the shared instance\r
+        */\r
+       public static Activator getDefault() {\r
+               return plugin;\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/ProcessResource.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/ProcessResource.java
new file mode 100644 (file)
index 0000000..a7df93c
--- /dev/null
@@ -0,0 +1,43 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007 VTT Technical Research Centre of Finland and others.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package fi.vtt.simantics.processeditor;\r
+\r
+import org.simantics.db.Builtins;\r
+import org.simantics.db.Graph;\r
+import org.simantics.proconf.g3d.stubs.G3DResource;\r
+\r
+import fi.vtt.simantics.processeditor.common.ControlPointTools;\r
+import fi.vtt.simantics.processeditor.stubs.Plant3DResource;\r
+\r
+public class ProcessResource {\r
+       public static Builtins builtins;\r
+       public static G3DResource g3dResource;\r
+       public static Plant3DResource plant3Dresource;\r
+       \r
+       \r
+       public static void initialize(Graph g) {\r
+               ProcessResource.builtins = Builtins.getInstance(g);\r
+               ProcessResource.g3dResource = G3DResource.getInstance(g);\r
+               ProcessResource.plant3Dresource = Plant3DResource.getInstance(g);\r
+               ControlPointTools.initialize();\r
+       }\r
+       \r
+       public static void deinitialize() {\r
+               builtins = null;\r
+               g3dResource = null;\r
+               plant3Dresource = null;\r
+               ControlPointTools.deinitialize();\r
+       }\r
+       \r
+       public static boolean isInitialized() {\r
+               return builtins != null;\r
+       }\r
+}\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/InsertComponentAction.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/InsertComponentAction.java
new file mode 100644 (file)
index 0000000..50f8fed
--- /dev/null
@@ -0,0 +1,403 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007 VTT Technical Research Centre of Finland and others.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package fi.vtt.simantics.processeditor.actions;\r
+\r
+import java.awt.event.KeyEvent;\r
+import java.awt.event.MouseEvent;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import javax.vecmath.Point3d;\r
+\r
+import org.eclipse.swt.widgets.Display;\r
+import org.simantics.db.Graph;\r
+import org.simantics.db.GraphRequestAdapter;\r
+import org.simantics.db.GraphRequestStatus;\r
+import org.simantics.db.GraphRequestWithResult;\r
+import org.simantics.db.Resource;\r
+import org.simantics.layer0.utils.EntityFactory;\r
+import org.simantics.layer0.utils.IEntity;\r
+import org.simantics.proconf.g3d.actions.InteractiveAction;\r
+import org.simantics.proconf.g3d.base.G3DAPI;\r
+import org.simantics.proconf.g3d.base.G3DTools;\r
+import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase;\r
+import org.simantics.proconf.g3d.common.StructuredResourceSelection;\r
+import org.simantics.proconf.g3d.dnd.DropListener;\r
+import org.simantics.proconf.g3d.scenegraph.IGraphicsNode;\r
+import org.simantics.utils.datastructures.Pair;\r
+\r
+import fi.vtt.simantics.processeditor.Activator;\r
+import fi.vtt.simantics.processeditor.ProcessResource;\r
+import fi.vtt.simantics.processeditor.common.ControlPointTools;\r
+import fi.vtt.simantics.processeditor.common.PipingTools2;\r
+import fi.vtt.simantics.processeditor.common.PipingTools2.Direction;\r
+import fi.vtt.simantics.processeditor.dialogs.PipelineComponentDialog;\r
+import fi.vtt.simantics.processeditor.gizmo.PositionSelectionGizmo;\r
+import fi.vtt.simantics.processeditor.stubs.PipeControlPoint;\r
+import fi.vtt.simantics.processeditor.stubs.PipelineComponent;\r
+\r
+\r
+\r
+/**\r
+ * Action that inserts new components into pipe run.\r
+ * - VariableLengthInlineComponents cannot be inserted with this action\r
+ * - Assumes that SizeChangeComponent is dual connected\r
+ * \r
+ * \r
+ * @author Marko Luukkainen <Marko.Luukkainen@vtt.fi>\r
+ *\r
+ */\r
+public class InsertComponentAction extends InteractiveAction implements DropListener, SplitPointListener {\r
+\r
+    Resource typeResource;                               // type of inserted component\r
+    Resource targetResource;                             // component where we are inserting new one\r
+    Resource selectedPosition;                           // selected control point for insertion\r
+    PositionType selectedType;                           // selected position type\r
+    List<Pair<Resource, PositionType>> insertPositions;\r
+    List<Pair<Point3d, PositionType>> insertPoints;\r
+    PositionSelectionGizmo gizmo = null;\r
+        \r
+    boolean activated = false;\r
+    \r
+    private SelectSplitPointAction splitPointAction;\r
+    \r
+    public InsertComponentAction(ThreeDimensionalEditorBase parent) {\r
+        super(parent);\r
+        splitPointAction = new SelectSplitPointAction(parent,this);\r
+    }\r
+    \r
+    @Override\r
+    public void init() {\r
+        this.setText("Insert Component");\r
+        this.setToolTipText("Inserts a Component into Pipeline");\r
+        this.setImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/Component.png"));\r
+    }\r
+    \r
+    @Override\r
+    public boolean usable(Graph graph, List<Resource> resources) {\r
+        if (!(resources.size() == 1)) {\r
+               return false;\r
+        }\r
+        IEntity target = EntityFactory.create(graph,resources.get(0));\r
+        \r
+        if (!target.isInstanceOf(ProcessResource.plant3Dresource.PipelineComponent)) {\r
+               return false;\r
+        }\r
+        PipelineComponent ic = new PipelineComponent(target);\r
+        PipeControlPoint pcp = ic.getControlPoint();\r
+        // one possibility: adding new component to unconnected position\r
+        // TODO : how about inserting new components between existing ones.\r
+        // TODO : can there be fixed length components that can be split (for example fixed length pipe)\r
+        if (pcp.getNext() == null && pcp.getPrevious() == null)\r
+               return true;\r
+        if (ic.isInstanceOf(ProcessResource.plant3Dresource.InlineComponent) && (pcp.getNext() == null || pcp.getPrevious() == null))\r
+                       return true;\r
+        for (PipeControlPoint p : pcp.getSubPoint())\r
+               // SubPoint's other connection is always null\r
+               // Exception: size change components offset point (that is subpoint)\r
+               //            does have one or both ends connected, but it won't matter\r
+               //            here because previous test fould return true, if insertion\r
+               //            is possible:\r
+               // TODO : here we assume that Size Change Component is dual connected\r
+               if (p.getNext() == null && p.getPrevious() == null) \r
+                       return true;\r
+        \r
+        if (target.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent)) {\r
+               // last option to insert component is split variable length component.\r
+               // If user chooses to split the component, inserted component must be\r
+               // inline component, but not size change component\r
+               return true;\r
+               } \r
+        return false;\r
+    }\r
+    \r
+    @Override\r
+    public void activate() {\r
+       insertPositions = null;\r
+       if (targetResource == null) {\r
+               List<IGraphicsNode> mos = parent.getSelectionAdapter().getSelectedObjects();\r
+               if (mos.size() != 1) {\r
+                               end();\r
+                               return;\r
+                       }\r
+               IGraphicsNode startNode = mos.get(0);\r
+               targetResource = startNode.getResource();\r
+       }\r
+       if (selectedPosition == null) {\r
+               updateInsertPositions();\r
+        }\r
+        if (typeResource == null) {\r
+                       \r
+                       List<Resource> filter = new ArrayList<Resource>();\r
+                       filter.add(ProcessResource.plant3Dresource.VariableLengthInlineComponent);\r
+                       \r
+                       boolean containsEnd = false;\r
+                       for (Pair<Point3d, PositionType> p : insertPoints) {\r
+                               if (p.second == PositionType.NEXT || p.second == PositionType.PREVIOUS) {\r
+                                       containsEnd = true;\r
+                                       break;\r
+                               }\r
+                                       \r
+                       }\r
+                       if(!containsEnd)\r
+                               filter.add(ProcessResource.plant3Dresource.EndComponent);\r
+                       \r
+                       PipelineComponentDialog dialog = new PipelineComponentDialog(Display.getCurrent().getActiveShell(),null, filter , parent.getSession());\r
+                       if (dialog.open() == PipelineComponentDialog.CANCEL) {\r
+                               end();\r
+                               return;\r
+                       }\r
+                       typeResource = dialog.getComboValue();\r
+                       updateInsertPositions();\r
+        }\r
+        \r
+        activated = true;\r
+    }\r
+    \r
+    private void updateInsertPositions() {\r
+       parent.getSession().syncRead(new GraphRequestAdapter() {\r
+                       \r
+                       @Override\r
+                       public GraphRequestStatus perform(Graph g) throws Exception {\r
+                               insertPositions = getInsertPositions(g,targetResource,typeResource);\r
+                               insertPoints = new ArrayList<Pair<Point3d,PositionType>>();\r
+                               for (Pair<Resource, PositionType> p : insertPositions) {\r
+                                       IEntity entity = EntityFactory.create(g,p.first);\r
+                                       Point3d pos = ControlPointTools.getRealPosition(entity, p.second);\r
+                                       insertPoints.add(new Pair<Point3d, PositionType>(pos,p.second));\r
+                               }\r
+                               return GraphRequestStatus.transactionComplete();\r
+                       }\r
+               });\r
+    }\r
+    \r
+    /**\r
+     * Finds possible locations of inserted component\r
+     * \r
+     * TODO (s): currently allows only inline, non size change components to split variable length component\r
+     *           assumes that size change component is DualConnected component\r
+     * \r
+     * @param g\r
+     * @param target \r
+     * @param acceptSplit\r
+     * @return\r
+     */\r
+    private List<Pair<Resource, PositionType>> getInsertPositions(Graph g, Resource target, Resource typeResource) {\r
+       \r
+       boolean acceptSplit = true;\r
+       boolean checkSubPoints = !g.isInstanceOf(target, ProcessResource.plant3Dresource.DualInlineControlPoint);\r
+       if (typeResource != null)\r
+               acceptSplit = g.isInstanceOf(typeResource, ProcessResource.plant3Dresource.InlineComponent) &&\r
+                                        !g.isInstanceOf(typeResource, ProcessResource.plant3Dresource.SizeChangeComponent);\r
+\r
+       \r
+       List<Pair<Resource, PositionType>> insertPositions = new ArrayList<Pair<Resource,PositionType>>();\r
+               PipelineComponent ic = new PipelineComponent(g,target);\r
+           PipeControlPoint pcp = ic.getControlPoint();\r
+           if (pcp.getNext() == null) {\r
+               insertPositions.add(new Pair<Resource, PositionType>(pcp.getResource(),PositionType.NEXT));\r
+           }\r
+           if (pcp.getPrevious() == null) {\r
+               insertPositions.add(new Pair<Resource, PositionType>(pcp.getResource(),PositionType.PREVIOUS));\r
+           }\r
+           if (checkSubPoints) {\r
+               for (PipeControlPoint p : pcp.getSubPoint()) {\r
+                       if (p.getNext() == null && p.getPrevious() == null) {\r
+                               insertPositions.add(new Pair<Resource, PositionType>(p.getResource(),PositionType.PORT));\r
+                       }\r
+               }\r
+           }\r
+           if (acceptSplit && ic.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent)) {\r
+               insertPositions.add(new Pair<Resource, PositionType>(pcp.getResource(),PositionType.SPLIT));\r
+           }\r
+           return insertPositions;\r
+    }\r
+    \r
+    @Override\r
+    public void update() {\r
+       if (splitPointAction.active()) {\r
+               splitPointAction.update();\r
+               return;\r
+        }\r
+        if (!activated) {\r
+            return;\r
+        }\r
+        if (insertPositions == null)\r
+               return;\r
+        if (insertPositions.size() == 0) {\r
+               end();\r
+               return;\r
+        }\r
+        if (insertPositions.size() == 1) {\r
+               activated = false;\r
+               insertComponent(insertPositions.get(0));\r
+               return;\r
+        }\r
+        \r
+        if (gizmo == null) {\r
+               gizmo = new PositionSelectionGizmo(parent,insertPoints);\r
+               parent.setGizmo(gizmo);\r
+               parent.getRenderingComponent().getNoShadowRoot().attachChild(gizmo.getNode());\r
+        }\r
+        gizmo.update();\r
+        if (gizmo.getSelected() >= 0 && input.mouseClicked() && input.clickButton() == MouseEvent.BUTTON1) {\r
+               activated = false;\r
+               insertComponent(insertPositions.get(gizmo.getSelected()));\r
+        }\r
+        if (input.keyPressed(KeyEvent.VK_ESCAPE)) {\r
+               end();\r
+        }\r
+    }\r
+    \r
+    private void insertComponent(Pair<Resource, PositionType> position) {\r
+       selectedPosition = position.first;\r
+       selectedType = position.second;\r
+       switch (selectedType) {\r
+       case NEXT:\r
+       case PREVIOUS:\r
+       case PORT:\r
+               parent.getSession().asyncWrite(new GraphRequestAdapter() {\r
+                       @Override\r
+                       public GraphRequestStatus perform(Graph g) throws Exception {\r
+                               IEntity pcp = EntityFactory.create(g,selectedPosition);\r
+                               Point3d point = ControlPointTools.getRealPosition(pcp, selectedType);\r
+                               IEntity component = instantiateComponent(g,point);\r
+                               PipingTools2.insertComponent(component, EntityFactory.create(g, targetResource), pcp , Direction.NEXT);                                 \r
+                               endThreaded();\r
+                               return GraphRequestStatus.transactionComplete();\r
+                       }\r
+                       \r
+                       \r
+               });\r
+               break;\r
+       case SPLIT:\r
+               parent.getSession().asyncRead(new GraphRequestAdapter() {\r
+                       @Override\r
+                       public GraphRequestStatus perform(Graph g) throws Exception {\r
+                               PipeControlPoint pcp = new PipeControlPoint(g,selectedPosition);\r
+                               Point3d p1 = new Point3d();\r
+                               Point3d p2 = new Point3d();\r
+                               ControlPointTools.getInlineControlPointEnds(pcp, p1, p2);\r
+                               splitPointAction.setSplit(p1, p2);\r
+                       splitPointAction.activate();\r
+                               return GraphRequestStatus.transactionComplete();\r
+                       }\r
+               });             \r
+               break;\r
+       }\r
+    }\r
+    \r
+    private void endThreaded() {\r
+       parent.getRenderingComposite().getDisplay().asyncExec(new Runnable() {\r
+                       @Override\r
+                       public void run() {\r
+                               end();\r
+                       }\r
+               });\r
+    }\r
+    \r
+    @Override\r
+    public void setSplitPoint(final Point3d point) {\r
+       splitPointAction.deactivate();\r
+       if (point == null) {\r
+               end();\r
+               return;\r
+       }\r
+       parent.getSession().asyncWrite(new GraphRequestAdapter() {\r
+                       @Override\r
+                       public GraphRequestStatus perform(Graph g) throws Exception {\r
+                               IEntity component = instantiateComponent(g,point);\r
+                               PipingTools2.splitVariableLengthComponent(component, EntityFactory.create(g,targetResource));\r
+                               \r
+                               return GraphRequestStatus.transactionComplete();\r
+                       }\r
+                       \r
+                       @Override\r
+                       public void requestCompleted(GraphRequestStatus status) {\r
+                               parent.getRenderingComposite().getDisplay().asyncExec(new Runnable(){\r
+                                       @Override\r
+                                       public void run() {\r
+                                               end();\r
+                                               \r
+                                       }\r
+                               });\r
+                       }\r
+               });\r
+    }\r
+    \r
+    /**\r
+     * instantiates selected component\r
+     * @param worldPosition position of the new component\r
+     */\r
+    private PipelineComponent instantiateComponent(Graph g,Point3d worldPosition) {\r
+       PipelineComponent target = new PipelineComponent(g,targetResource);\r
+       IEntity piperun = target.getParent();\r
+       PipelineComponent instance = PipingTools2.instantiatePipelineComponent(g,piperun.getResource(), typeResource);\r
+       G3DTools.resetTransformation(instance);\r
+       //G3DAPI.addNodeWorld(piperun, instance);\r
+       G3DAPI.setWorldPosition(instance, worldPosition);\r
+       return instance;\r
+    }\r
+    \r
+    @Override\r
+    public void deactivate() {\r
+        typeResource = null;\r
+        targetResource = null;\r
+        selectedPosition = null;\r
+        selectedType = null;\r
+        insertPoints = null;\r
+        insertPositions = null;\r
+        if (gizmo != null) {\r
+               parent.setGizmo(null);\r
+               gizmo = null;\r
+        }\r
+    }\r
+\r
+    public boolean acceptDrop(StructuredResourceSelection s, Resource[] ids) {\r
+               if(s.size() != 1)\r
+                       return false;\r
+               if (ids == null)\r
+                       return false;\r
+               if (ids.length != 1)\r
+                       return false;\r
+               \r
+               final Resource type = ids[0];\r
+               final Resource target = s.getSelectionList().get(0);\r
+               GraphRequestWithResult<Boolean> query = new GraphRequestWithResult<Boolean>() {\r
+                       @Override\r
+                       public Boolean performWithResult(Graph g) throws Exception {\r
+                               IEntity entity = EntityFactory.create(g, type);\r
+                               // dropped type must be pipeline component\r
+                               if (!entity.isInstanceOf(ProcessResource.plant3Dresource.PipelineComponent))\r
+                                       return false;\r
+                               // but not variable length inline component\r
+                               if (entity.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent))\r
+                                       return false;\r
+                               if (entity.getRelatedObjects(ProcessResource.plant3Dresource.HasGraphics).size() != 1)\r
+                                       return false;\r
+                       \r
+                               List<Pair<Resource, PositionType>> insertPositions = getInsertPositions(g,target,type);\r
+                               return insertPositions.size() > 0;      \r
+                       }\r
+               };\r
+               \r
+               parent.getSession().syncRead(query);\r
+               \r
+               return query.getResult();\r
+       }    \r
+    \r
+    public void doDrop(StructuredResourceSelection s, Resource[] ids) {\r
+               typeResource = ids[0];\r
+               targetResource = s.getSelectionList().get(0);\r
+               parent.setCurrentAction(this);\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/InsertEquipmentAction.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/InsertEquipmentAction.java
new file mode 100644 (file)
index 0000000..26556b8
--- /dev/null
@@ -0,0 +1,115 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007 VTT Technical Research Centre of Finland and others.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package fi.vtt.simantics.processeditor.actions;\r
+\r
+import java.util.List;\r
+\r
+import org.simantics.db.Graph;\r
+import org.simantics.db.GraphRequestAdapter;\r
+import org.simantics.db.GraphRequestStatus;\r
+import org.simantics.db.GraphRequestWithResult;\r
+import org.simantics.db.Resource;\r
+import org.simantics.layer0.utils.EntityFactory;\r
+import org.simantics.layer0.utils.IEntity;\r
+import org.simantics.proconf.g3d.actions.ContextAction;\r
+import org.simantics.proconf.g3d.base.G3DAPI;\r
+import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase;\r
+import org.simantics.proconf.g3d.common.StructuredResourceSelection;\r
+import org.simantics.proconf.g3d.dnd.DropListener;\r
+import org.simantics.proconf.g3d.stubs.G3DNode;\r
+\r
+\r
+\r
+import fi.vtt.simantics.processeditor.ProcessResource;\r
+import fi.vtt.simantics.processeditor.common.PipingTools2;\r
+import fi.vtt.simantics.processeditor.dialogs.EquipmentDialog;\r
+import fi.vtt.simantics.processeditor.stubs.Equipment;\r
+\r
+public class InsertEquipmentAction extends ContextAction implements DropListener{\r
+\r
+       \r
+    public InsertEquipmentAction(ThreeDimensionalEditorBase parent) {\r
+        super(parent);\r
+        this.setText("Insert Equipment");\r
+    }\r
+    \r
+    @Override\r
+    public void run() {\r
+       EquipmentDialog dialog = new EquipmentDialog(parent.getRenderingComposite().getShell(),"Insert Equipment",parent.getSession());\r
+       if (dialog.open() == EquipmentDialog.CANCEL)\r
+               return;\r
+       final Resource typeResource = dialog.getComboValue();\r
+       parent.getSession().asyncWrite(new GraphRequestAdapter() {\r
+               @Override\r
+               public GraphRequestStatus perform(Graph g) throws Exception {\r
+                       createEquipment(g,typeResource);\r
+                   return GraphRequestStatus.transactionComplete();\r
+               }\r
+       });\r
+    }\r
+    \r
+  \r
+\r
+    \r
+    private void createEquipment(Graph graph,Resource typeResource) {\r
+       \r
+       //G3DNode instanceNode = new G3DNode(graph, instance);\r
+       Equipment instanceNode = PipingTools2.instantiateEquipment(graph, typeResource);\r
+       G3DNode plant = parent.getScenegraphAdapter().getRootNode().getG3DNode(graph); \r
+       \r
+       G3DAPI.addNodeWorld(plant, instanceNode);\r
+\r
+        //parent.getSelectionAdapter().updateSelection(new StructuredResourceSelection(instance)));\r
+    }\r
+    \r
+    public boolean usable(Graph graph,List<Resource> resources) {\r
+        return (resources.size() == 0);\r
+    }\r
+    \r
+\r
+    \r
+    public boolean acceptDrop(StructuredResourceSelection s, Resource[] ids) {\r
+               if(!s.isEmpty())\r
+                       return false;\r
+               if (ids == null)\r
+                       return false;\r
+               if (ids.length != 1)\r
+                       return false;\r
+               final Resource r = ids[0];\r
+               GraphRequestWithResult<Boolean> query = new GraphRequestWithResult<Boolean>() {\r
+                       @Override\r
+                       public Boolean performWithResult(Graph g) throws Exception {\r
+                               IEntity t = EntityFactory.create(g, r);\r
+                               if(!t.isInheritedFrom(ProcessResource.plant3Dresource.Equipment))\r
+                                       return false;\r
+                               if (t.getRelatedObjects(ProcessResource.plant3Dresource.HasGraphics).size() == 1)\r
+                                       return true;\r
+                               return false;\r
+                       }\r
+               };\r
+\r
+               parent.getSession().syncRead(query);\r
+               return query.getResult();\r
+       }\r
+    \r
+    public void doDrop(StructuredResourceSelection s, Resource[] ids) {\r
+               final Resource typeResource = ids[0];\r
+               parent.getSession().asyncWrite(new GraphRequestAdapter() {\r
+                       @Override\r
+                       public GraphRequestStatus perform(Graph g) throws Exception {\r
+                               createEquipment(g,typeResource);\r
+                               return GraphRequestStatus.transactionComplete();\r
+                       }\r
+               });\r
+               \r
+               \r
+       }\r
+}\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/InsertNozzleAction.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/InsertNozzleAction.java
new file mode 100644 (file)
index 0000000..91733ab
--- /dev/null
@@ -0,0 +1,139 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007 VTT Technical Research Centre of Finland and others.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package fi.vtt.simantics.processeditor.actions;\r
+\r
+import java.util.List;\r
+\r
+import org.simantics.db.Graph;\r
+import org.simantics.db.GraphRequestAdapter;\r
+import org.simantics.db.GraphRequestStatus;\r
+import org.simantics.db.GraphRequestWithResult;\r
+import org.simantics.db.Resource;\r
+import org.simantics.layer0.utils.EntityFactory;\r
+import org.simantics.layer0.utils.IEntity;\r
+import org.simantics.layer0.utils.instantiation.Instance;\r
+import org.simantics.layer0.utils.instantiation.InstanceFactory;\r
+import org.simantics.proconf.g3d.actions.WriteAction;\r
+import org.simantics.proconf.g3d.base.G3DAPI;\r
+import org.simantics.proconf.g3d.base.G3DTools;\r
+import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase;\r
+import org.simantics.proconf.g3d.common.StructuredResourceSelection;\r
+import org.simantics.proconf.g3d.dnd.DropListener;\r
+\r
+import fi.vtt.simantics.processeditor.Activator;\r
+import fi.vtt.simantics.processeditor.ProcessResource;\r
+import fi.vtt.simantics.processeditor.common.PipingTools2;\r
+import fi.vtt.simantics.processeditor.dialogs.NozzleDialog;\r
+import fi.vtt.simantics.processeditor.stubs.Equipment;\r
+import fi.vtt.simantics.processeditor.stubs.Nozzle;\r
+\r
+\r
+\r
+public class InsertNozzleAction extends WriteAction implements DropListener {\r
+\r
+    Resource equipmentResource = null;\r
+    Resource nozzleType = null;\r
+    \r
+    public InsertNozzleAction(ThreeDimensionalEditorBase parent) {\r
+        super(parent,false);\r
+    }\r
+\r
+    @Override\r
+    public boolean canActivate() {\r
+       NozzleDialog dialog = new NozzleDialog(parent.getRenderingComposite().getShell(),"Select a nozzle", parent.getSession());\r
+       if (dialog.open() == NozzleDialog.CANCEL) {\r
+             equipmentResource = null;\r
+             return false;\r
+        }\r
+       Resource type = dialog.getComboValue();\r
+       if (type == null) {\r
+               equipmentResource = null;\r
+               return false;\r
+       }\r
+       nozzleType = type;      \r
+        return true;\r
+    }\r
+    \r
+    @Override\r
+    public GraphRequestStatus doChanges(Graph graph) throws Exception {\r
+       createNozzle(graph);\r
+       return GraphRequestStatus.transactionComplete();\r
+    }\r
+    \r
+    private void createNozzle(Graph graph) {\r
+       assert(nozzleType != null);\r
+       assert(equipmentResource != null);\r
+\r
+       Nozzle n = PipingTools2.instantiateNozzle(graph, nozzleType);\r
+       \r
+       Equipment equipment = new Equipment(graph, equipmentResource);\r
+       \r
+       G3DAPI.addNodeLocal(equipment,ProcessResource.plant3Dresource.HasNozzle, n);\r
+        //parent.getSelectionAdapter().updateSelection(new StructuredResourceSelection(n.getResource()));        \r
+        equipment = null;\r
+    }\r
+    \r
+    public boolean usable(Graph graph, List<Resource> resources) {\r
+        if (resources.size() != 1) {\r
+            return false;\r
+        }\r
+        Resource r = resources.iterator().next();\r
+        IEntity t = EntityFactory.create(graph,r);\r
+        if (t.isInstanceOf(ProcessResource.plant3Dresource.Equipment)) {\r
+            equipmentResource = r;\r
+            return true;\r
+        }\r
+        return false;\r
+    }\r
+    \r
+    @Override\r
+    public void init() {\r
+        setText("Insert Nozzle");\r
+        this.setImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/Nozzle.png"));\r
+    }\r
+    \r
+    public boolean acceptDrop(StructuredResourceSelection s, Resource[] ids) {\r
+               if(s.size() != 1)\r
+                       return false;\r
+               if (ids == null)\r
+                       return false;\r
+               if (ids.length != 1)\r
+                       return false;\r
+               final Resource r = ids[0];\r
+               final Resource selectedResource = s.iterator().next();\r
+               GraphRequestWithResult<Boolean> query = new GraphRequestWithResult<Boolean>() {\r
+                       @Override\r
+                       public Boolean performWithResult(Graph g) throws Exception {\r
+                               IEntity t = EntityFactory.create(g,r);\r
+                               if (!t.isInheritedFrom(ProcessResource.plant3Dresource.Nozzle))\r
+                                       return false;\r
+                               t = EntityFactory.create(g,selectedResource);\r
+                               if (t.isInstanceOf(ProcessResource.plant3Dresource.Equipment)) {\r
+                                       return true;\r
+                               }\r
+                               return false;\r
+                       }\r
+               };\r
+               parent.getSession().syncRead(query);\r
+               return query.getResult();\r
+       }\r
+    \r
+    public void doDrop(StructuredResourceSelection s, Resource[] ids) {\r
+       equipmentResource = s.iterator().next();\r
+       parent.getSession().asyncWrite(new GraphRequestAdapter() {\r
+               @Override\r
+               public GraphRequestStatus perform(Graph g) throws Exception {\r
+                       createNozzle(g);\r
+                       return GraphRequestStatus.transactionComplete();\r
+               }\r
+       });\r
+    }\r
+}\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/PositionType.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/PositionType.java
new file mode 100644 (file)
index 0000000..0ab3a5b
--- /dev/null
@@ -0,0 +1,15 @@
+package fi.vtt.simantics.processeditor.actions;\r
+\r
+\r
+/**\r
+ * Position types for inserting new components and routing new pipe\r
+ * \r
+ * @author Marko Luukkainen <Marko.Luukkainen@vtt.fi>\r
+ *\r
+ */\r
+public enum PositionType {\r
+       SPLIT,\r
+       NEXT,\r
+       PREVIOUS,\r
+       PORT\r
+}\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/ReversePipelineAction.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/ReversePipelineAction.java
new file mode 100644 (file)
index 0000000..a75d7e0
--- /dev/null
@@ -0,0 +1,57 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007 VTT Technical Research Centre of Finland and others.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package fi.vtt.simantics.processeditor.actions;\r
+\r
+import java.util.List;\r
+\r
+import org.simantics.db.Graph;\r
+import org.simantics.db.GraphRequestStatus;\r
+import org.simantics.db.Resource;\r
+import org.simantics.layer0.utils.EntityFactory;\r
+import org.simantics.layer0.utils.IEntity;\r
+import org.simantics.proconf.g3d.actions.WriteAction;\r
+import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase;\r
+\r
+\r
+import fi.vtt.simantics.processeditor.ProcessResource;\r
+import fi.vtt.simantics.processeditor.common.PipingTools2;\r
+import fi.vtt.simantics.processeditor.stubs.PipelineComponent;\r
+\r
+public class ReversePipelineAction extends WriteAction {\r
+       \r
+       public ReversePipelineAction(ThreeDimensionalEditorBase parent) {\r
+               super(parent,false);\r
+       }\r
+\r
+       @Override\r
+       public boolean usable(Graph graph, List<Resource> resources) {\r
+               if (resources.size() != 1)\r
+                       return false;\r
+               IEntity t = EntityFactory.create(graph, resources.get(0));\r
+               return (t.isInstanceOf(ProcessResource.plant3Dresource.PipelineComponent));\r
+       }\r
+       \r
+       @Override\r
+       public GraphRequestStatus doChanges(Graph graph) throws Exception {\r
+               Resource r = parent.getSelectionAdapter().getSelectedResources().get(0);\r
+               PipelineComponent comp = new PipelineComponent(graph, r);\r
+               PipingTools2.reversePipeRun(PipingTools2.getPipeRun(comp));\r
+\r
+               return GraphRequestStatus.transactionComplete();\r
+       }\r
+\r
+       \r
+       @Override\r
+       public void init() {\r
+               this.setText("Reverse pipeline");\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/RoutePipeAction.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/RoutePipeAction.java
new file mode 100644 (file)
index 0000000..00d7ac3
--- /dev/null
@@ -0,0 +1,1342 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007 VTT Technical Research Centre of Finland and others.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package fi.vtt.simantics.processeditor.actions;\r
+\r
+import java.awt.event.KeyEvent;\r
+import java.awt.event.MouseEvent;\r
+import java.math.BigDecimal;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import javax.vecmath.Point3d;\r
+import javax.vecmath.Vector3d;\r
+\r
+import org.eclipse.jface.action.Action;\r
+import org.eclipse.jface.action.IToolBarManager;\r
+import org.eclipse.jface.resource.ImageDescriptor;\r
+import org.simantics.db.Graph;\r
+import org.simantics.db.GraphRequestAdapter;\r
+import org.simantics.db.GraphRequestStatus;\r
+import org.simantics.db.GraphRequestWithResult;\r
+import org.simantics.db.Resource;\r
+import org.simantics.layer0.utils.EntityFactory;\r
+import org.simantics.layer0.utils.IEntity;\r
+import org.simantics.proconf.g3d.actions.InteractiveAction;\r
+import org.simantics.proconf.g3d.base.ConstraintDetector;\r
+import org.simantics.proconf.g3d.base.G3DAPI;\r
+import org.simantics.proconf.g3d.base.G3DTools;\r
+import org.simantics.proconf.g3d.base.MathTools;\r
+import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase;\r
+import org.simantics.proconf.g3d.common.StructuredResourceSelection;\r
+import org.simantics.proconf.g3d.dnd.DropListener;\r
+import org.simantics.proconf.g3d.scenegraph.IGraphicsNode;\r
+import org.simantics.utils.datastructures.Pair;\r
+\r
+import com.jme.renderer.ColorRGBA;\r
+import com.jme.scene.Geometry;\r
+import com.jme.scene.Line;\r
+import com.jme.scene.state.MaterialState;\r
+\r
+import fi.vtt.simantics.processeditor.Activator;\r
+import fi.vtt.simantics.processeditor.ProcessResource;\r
+import fi.vtt.simantics.processeditor.common.ControlPointTools;\r
+import fi.vtt.simantics.processeditor.common.PipeComponentProvider;\r
+import fi.vtt.simantics.processeditor.common.PipingTools2;\r
+import fi.vtt.simantics.processeditor.common.PipingTools2.Direction;\r
+import fi.vtt.simantics.processeditor.dialogs.PipelineDialog;\r
+import fi.vtt.simantics.processeditor.gizmo.PositionSelectionGizmo;\r
+import fi.vtt.simantics.processeditor.stubs.BranchEndControlPoint;\r
+import fi.vtt.simantics.processeditor.stubs.PipeControlPoint;\r
+import fi.vtt.simantics.processeditor.stubs.PipeRun;\r
+import fi.vtt.simantics.processeditor.stubs.PipelineComponent;\r
+import fi.vtt.simantics.processeditor.stubs.VariableLengthInlineComponent;\r
+import fi.vtt.simantics.processeditor.views.ProcessEditor;\r
+\r
+/**\r
+ * Action for Routing Pipes\r
+ * \r
+ * FIXME : does several thing that should be done by PipingTools.\r
+ * TODO : instead of using lines to show route of pipe, generate pipe and change it real-time\r
+ * \r
+ * @author MLMARKO\r
+ *\r
+ */\r
+public class RoutePipeAction extends InteractiveAction implements DropListener, SplitPointListener {\r
+       \r
+       \r
+       private static final ImageDescriptor X_AXIS_ICON = Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/x-axis.png");\r
+       private static final ImageDescriptor Y_AXIS_ICON = Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/y-axis.png");\r
+       private static final ImageDescriptor Z_AXIS_ICON = Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/z-axis.png");\r
+       private static final ImageDescriptor X_PLANE_ICON = Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/x-plane.png");\r
+       private static final ImageDescriptor Y_PLANE_ICON = Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/y-plane.png");\r
+       private static final ImageDescriptor Z_PLANE_ICON = Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/z-plane.png");\r
+    \r
+       private static final ImageDescriptor CAMERA_ICON = Activator.imageDescriptorFromPlugin("org.simantics.proconf.g3d", "icons/eye.png");\r
+    \r
+       \r
+       private Action xAxisAction;\r
+       private Action yAxisAction;\r
+       private Action zAxisAction;\r
+       private Action xPlaneAction;\r
+       private Action yPlaneAction;\r
+       private Action zPlaneAction;\r
+       \r
+       private Action cameraAction;\r
+       \r
+    ConstraintDetector detector = null;\r
+    \r
+    public RoutePipeAction(ThreeDimensionalEditorBase parent) {\r
+        super(parent);\r
+        detector = new ConstraintDetector(parent);\r
+        xAxisAction = new Action("X",Action.AS_RADIO_BUTTON) {\r
+               public void run() {\r
+                       if (lock == LockType.X)\r
+                               setLockType(LockType.NONE,false);\r
+                       else\r
+                               setLockType(LockType.X,false);\r
+               }\r
+        };\r
+        xAxisAction.setImageDescriptor(X_AXIS_ICON);\r
+        xAxisAction.setToolTipText("Lock X-Axis");\r
+        yAxisAction = new Action("Y",Action.AS_RADIO_BUTTON) {\r
+               public void run() {\r
+                       if (lock == LockType.Y)\r
+                               setLockType(LockType.NONE,false);\r
+                       else\r
+                               setLockType(LockType.Y,false);\r
+               }\r
+        };\r
+        yAxisAction.setImageDescriptor(Y_AXIS_ICON);\r
+        yAxisAction.setToolTipText("Lock Y-Axis");\r
+        zAxisAction = new Action("Z",Action.AS_RADIO_BUTTON) {\r
+               public void run() {\r
+                       if (lock == LockType.Z)\r
+                               setLockType(LockType.NONE,false);\r
+                       else\r
+                               setLockType(LockType.Z,false);\r
+               }\r
+        };\r
+        zAxisAction.setImageDescriptor(Z_AXIS_ICON);\r
+        zAxisAction.setToolTipText("Lock Z-Axis");\r
+        xPlaneAction = new Action("X",Action.AS_RADIO_BUTTON) {\r
+               public void run() {\r
+                       if (lock == LockType.YZ)\r
+                               setLockType(LockType.NONE,false);\r
+                       else\r
+                               setLockType(LockType.YZ,false);\r
+               }\r
+        };\r
+        xPlaneAction.setImageDescriptor(X_PLANE_ICON);\r
+        xPlaneAction.setToolTipText("Lock X-Plane");\r
+        yPlaneAction = new Action("Y",Action.AS_RADIO_BUTTON) {\r
+               public void run() {\r
+                       if (lock == LockType.XZ)\r
+                               setLockType(LockType.NONE,false);\r
+                       else\r
+                               setLockType(LockType.XZ,false);\r
+               }\r
+        };\r
+        yPlaneAction.setImageDescriptor(Y_PLANE_ICON);\r
+        yPlaneAction.setToolTipText("Lock Y-Plane");\r
+        zPlaneAction = new Action("Z",Action.AS_RADIO_BUTTON) {\r
+               public void run() {\r
+                       if (lock == LockType.XY)\r
+                               setLockType(LockType.NONE,false);\r
+                       else\r
+                               setLockType(LockType.XY,false);\r
+               }\r
+        };\r
+        zPlaneAction.setImageDescriptor(Z_PLANE_ICON);\r
+        zPlaneAction.setToolTipText("Lock Z-Plane");\r
+        cameraAction = new Action("C", Action.AS_CHECK_BOX) {\r
+               public void run() {\r
+                       useCamera = this.isChecked();\r
+               }\r
+        };\r
+        cameraAction.setImageDescriptor(CAMERA_ICON);\r
+        cameraAction.setToolTipText("Use camera");\r
+        splitPointAction = new SelectSplitPointAction(parent,this);\r
+        \r
+    }\r
+    \r
+    public void fillToolBar(IToolBarManager manager) {\r
+        \r
+        manager.add(cameraAction);\r
+        cameraAction.setChecked(useCamera);\r
+       manager.add(xAxisAction);\r
+        manager.add(yAxisAction);\r
+        manager.add(zAxisAction);\r
+        manager.add(xPlaneAction);\r
+        manager.add(yPlaneAction);\r
+        manager.add(zPlaneAction);  \r
+        \r
+    }\r
+\r
+    enum LockType {NONE,X,Y,Z,XY,YZ,XZ,CUSTOM};\r
+    LockType lock = LockType.NONE;\r
+    \r
+    private void setLockType(LockType type, boolean force) {\r
+       if (force || lock != LockType.CUSTOM) {\r
+               lock = type;\r
+       }\r
+       xAxisAction.setChecked(false);\r
+       yAxisAction.setChecked(false);\r
+       zAxisAction.setChecked(false);\r
+       xPlaneAction.setChecked(false);\r
+       yPlaneAction.setChecked(false);\r
+       zPlaneAction.setChecked(false);\r
+       xAxisAction.setEnabled(true);\r
+       yAxisAction.setEnabled(true);\r
+       zAxisAction.setEnabled(true);\r
+       xPlaneAction.setEnabled(true);\r
+       yPlaneAction.setEnabled(true);\r
+       zPlaneAction.setEnabled(true);\r
+       switch (lock) {\r
+       case X:\r
+               xAxisAction.setChecked(true);\r
+               break;\r
+       case Y:\r
+               yAxisAction.setChecked(true);\r
+               break;\r
+       case Z:\r
+               zAxisAction.setChecked(true);\r
+               break;  \r
+       case XY:\r
+               zPlaneAction.setChecked(true);\r
+               break;  \r
+       case XZ:\r
+               yPlaneAction.setChecked(true);\r
+               break;  \r
+       case YZ:\r
+               xPlaneAction.setChecked(true);\r
+               break;  \r
+       case CUSTOM:\r
+               xAxisAction.setEnabled(false);\r
+               yAxisAction.setEnabled(false);\r
+               zAxisAction.setEnabled(false);\r
+               xPlaneAction.setEnabled(false);\r
+               yPlaneAction.setEnabled(false);\r
+               zPlaneAction.setEnabled(false);\r
+               break;\r
+       }\r
+    }\r
+    \r
+    private double BRANCH_SNAP_DISTANCE = 0.05;\r
+    private double NOZZLE_SNAP_DISTANCE = 0.05;\r
+    \r
+    private double istep = 10.0;\r
+    private int decimals = 2;\r
+    \r
+    private double pipeDiameter = 0.2;\r
+    private double elbowRadius = 0.5;\r
+    private double eps = 0.001;\r
+    \r
+    private ArrayList<Point3d> controlPoints = new ArrayList<Point3d>();\r
+\r
+    private Point3d currentPoint = new Point3d();\r
+    private Point3d lastPoint = new Point3d();\r
+    \r
+    private Vector3d customLockDir = null;\r
+    \r
+    private Line selectionLine;\r
+    private List<Line> pipeShapes = new ArrayList<Line>();\r
+    private MaterialState ms;\r
+    \r
+    \r
+    private Resource selectedPort = null;\r
+    private PositionType selectedType = null;\r
+    private Resource beginComponentResource = null;\r
+    \r
+    private Resource endComponentResource = null;\r
+    private Resource endComponentPort = null;\r
+    private PositionType endPortType = null;\r
+    \r
+    private Resource highlightedResource = null;\r
+    \r
+    private boolean useCamera = false;\r
+    \r
+    private List<Pair<Resource, PositionType>> positions = null;\r
+    \r
+    private SelectSplitPointAction splitPointAction;\r
+    private PositionSelectionGizmo gizmo = null;\r
+    \r
+    \r
+    \r
+    private enum ToolState{NOT_ACTIVE, INITIALIZING, SELECTING_POSITION, SELECTING_SPLIT, ROUTING};\r
+    private ToolState state = ToolState.NOT_ACTIVE;\r
+    \r
+    @Override\r
+    public void activate() {\r
+       state = ToolState.INITIALIZING;\r
+        controlPoints.clear();\r
+        if (beginComponentResource == null) {\r
+               List<IGraphicsNode> mos = parent.getSelectionAdapter().getSelectedObjects();\r
+            if (mos.size() != 1) {\r
+               end();\r
+                return;\r
+            }\r
+            beginComponentResource = mos.get(0).getResource();\r
+        }\r
+        parent.getSession().asyncRead(new GraphRequestAdapter() {\r
+               @Override\r
+               public GraphRequestStatus perform(Graph g) throws Exception {\r
+                       positions = checkStartNode(g,beginComponentResource);\r
+                       if (positions.size() == 0) {\r
+                               positions = null;\r
+                               end();\r
+                       } else {\r
+                               state = ToolState.SELECTING_POSITION;\r
+                       }\r
+                       return GraphRequestStatus.transactionComplete();\r
+               }\r
+        });\r
+        \r
+        if (ms == null) {\r
+               ms = parent.getRenderingComponent().getDisplaySystem().getRenderer().createMaterialState();\r
+            ms.setEmissive(new ColorRGBA(1.f,1.f,1.f,1.f));\r
+        }\r
+\r
+    }\r
+    \r
+    \r
+\r
+    @Override\r
+    public void deactivate() {\r
+        for (Line l : pipeShapes)\r
+               l.removeFromParent();\r
+         pipeShapes.clear();\r
+         if (selectionLine != null)\r
+               selectionLine.removeFromParent();\r
+         selectionLine = null;\r
+         customLockDir = null;\r
+         \r
+         setLockType(LockType.NONE,true);\r
+         beginComponentResource = null;\r
+         endComponentResource = null;\r
+         detector.clearConstraintHighlights(); \r
+         state = ToolState.NOT_ACTIVE;\r
+         selectedPort = null;\r
+         selectedType = null;\r
+        \r
+    }\r
+    \r
+    private List<Pair<Resource, PositionType>> checkStartNode(Graph g, Resource resource) {\r
+        List<Pair<Resource, PositionType>> positions = new ArrayList<Pair<Resource,PositionType>>();\r
+       \r
+       IEntity beginComponent = EntityFactory.create(g, resource);\r
+        \r
+        if (beginComponent.isInstanceOf(ProcessResource.plant3Dresource.Nozzle)) {\r
+               if (PipingTools2.isFreeNozzle(beginComponent)) {\r
+\r
+                               positions.add(new Pair<Resource, PositionType>(beginComponent.getSingleRelatedObject(ProcessResource.plant3Dresource.HasControlPoint).getResource(),PositionType.NEXT));\r
+               } \r
+        } else if (beginComponent.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent)) {\r
+               // variable length inline component is exception from other pipeline components,\r
+               // since a new pipe can branch it\r
+               VariableLengthInlineComponent vlic = new VariableLengthInlineComponent(beginComponent);\r
+            PipeControlPoint pcp = vlic.getControlPoint();\r
+            if (pcp.getNext() == null) {\r
+\r
+               positions.add(new Pair<Resource, PositionType>(pcp.getResource(),PositionType.NEXT));    \r
+            } else if (pcp.getPrevious() == null) {\r
+\r
+                positions.add(new Pair<Resource, PositionType>(pcp.getResource(),PositionType.PREVIOUS));\r
+            }\r
+            positions.add(new Pair<Resource, PositionType>(pcp.getResource(),PositionType.SPLIT));\r
+        } else if (beginComponent.isInstanceOf(ProcessResource.plant3Dresource.EndComponent)) {\r
+               PipelineComponent component = new PipelineComponent(beginComponent);            \r
+               PipeControlPoint pcp = component.getControlPoint();\r
+               if (pcp.getNext() == null && pcp.getPrevious() == null) { \r
+                       throw new RuntimeException("End component " + beginComponent.getResource() + " is not connected to anything.");\r
+                       //positions.add(new Pair<Resource, PositionType>(pcp.getResource(),PositionType.NEXT));\r
+               }\r
+               for (PipeControlPoint p : pcp.getSubPoint()) {\r
+                       if (p.getNext() == null && p.getPrevious() == null) {\r
+                               positions.add(new Pair<Resource, PositionType>(p.getResource(),PositionType.NEXT));\r
+                       }\r
+               }\r
+        } else if (beginComponent.isInstanceOf(ProcessResource.plant3Dresource.PipelineComponent)) {\r
+               \r
+               PipelineComponent component = new PipelineComponent(beginComponent);\r
+               \r
+               PipeControlPoint pcp = component.getControlPoint();\r
+               if (pcp.getNext() == null) {\r
+                       positions.add(new Pair<Resource, PositionType>(pcp.getResource(),PositionType.NEXT));\r
+               } else if (pcp.getPrevious() == null) {\r
+                       positions.add(new Pair<Resource, PositionType>(pcp.getResource(),PositionType.PREVIOUS));\r
+               }\r
+               if (!beginComponent.isInstanceOf(ProcessResource.plant3Dresource.SizeChangeComponent)||\r
+                       !beginComponent.isInstanceOf(ProcessResource.plant3Dresource.OffsetComponent)) {\r
+                       for (PipeControlPoint p : pcp.getSubPoint()) {\r
+                               if (p.getNext() == null && p.getPrevious() == null) {\r
+                                       positions.add(new Pair<Resource, PositionType>(p.getResource(),PositionType.NEXT));\r
+                               }\r
+                       }\r
+               }       \r
+        } else {\r
+            return positions;\r
+        }\r
+        return positions;\r
+    }\r
+\r
+    @Override\r
+    public void update() {\r
+       \r
+       switch (state) {\r
+       case NOT_ACTIVE:\r
+               return; // TODO : throw Exception?\r
+       case INITIALIZING:\r
+               return;\r
+       case SELECTING_POSITION:\r
+               updateSelectPosition();\r
+               break;\r
+       case SELECTING_SPLIT:\r
+               updateSelectSplit();\r
+               break;\r
+       case ROUTING:\r
+               updateRouting();\r
+               break;\r
+       }\r
+       return;\r
+    }\r
+\r
+    private void updateSelectPosition() {\r
+       \r
+       if (positions == null) {\r
+               throw new RuntimeException("positions must be loaded before select position can be activated");\r
+        }\r
+        if (selectedPort != null) {\r
+               throw new RuntimeException("position is already selected");\r
+        }\r
+        if (positions.size() == 1) {\r
+                       selectedPort = positions.get(0).first;\r
+                       selectedType = positions.get(0).second;\r
+                       state = ToolState.INITIALIZING;\r
+                       \r
+                       \r
+                       \r
+                       if (requiresNewPipeRun()){\r
+                               if(!getNewPipeRunSpecs()) {\r
+                                       end();\r
+                                       return;\r
+                               }\r
+                       }\r
+                       if (selectedType == PositionType.SPLIT) {\r
+                               startSplitting();\r
+                       } else {\r
+                               startRouting();\r
+                       }\r
+\r
+               } else if (gizmo == null) {\r
+                       state = ToolState.INITIALIZING; // asyncRead!\r
+                       parent.getSession().asyncRead(new GraphRequestAdapter() {\r
+                               @Override\r
+                               public GraphRequestStatus perform(Graph g) throws Exception {\r
+                                       List<Pair<Point3d, PositionType>> pos = new ArrayList<Pair<Point3d,PositionType>>();\r
+                                       for (Pair<Resource, PositionType> p : positions) {\r
+                                               IEntity entity = EntityFactory.create(g,p.first);\r
+                                               Point3d position = ControlPointTools.getRealPosition(entity, p.second);\r
+                                               pos.add(new Pair<Point3d, PositionType>(position,p.second));\r
+                                       }\r
+                                       gizmo = new PositionSelectionGizmo(parent, pos);\r
+                                       parent.setGizmo(gizmo);\r
+                                       parent.getRenderingComponent().getNoShadowRoot().attachChild(gizmo.getNode());\r
+                                       state = ToolState.SELECTING_POSITION;\r
+                                       return GraphRequestStatus.transactionComplete();\r
+                               }\r
+                       });\r
+                       \r
+               } else {\r
+                       gizmo.update();\r
+                       \r
+                       if (input.keyPressed(KeyEvent.VK_ESCAPE)) {\r
+                       state = ToolState.INITIALIZING;\r
+                       parent.setGizmo(null);\r
+                       gizmo = null;\r
+                       end();\r
+                       return;\r
+               }\r
+\r
+               if (gizmo.getSelected() >= 0 && input.mouseClicked() && input.clickButton() == MouseEvent.BUTTON1) {\r
+                       state = ToolState.INITIALIZING; // asyncRead!\r
+                       parent.setGizmo(null);\r
+                       selectedPort = positions.get(gizmo.getSelected()).first;\r
+                       selectedType = positions.get(gizmo.getSelected()).second;\r
+                       gizmo = null;\r
+                       \r
+                       if (selectedType == PositionType.SPLIT) {\r
+                               startSplitting();       \r
+                       return;\r
+                       } else {\r
+                               startRouting();\r
+                       }\r
+               } \r
+               \r
+               if (useCamera) {\r
+                       parent.getDefaultAction().update();\r
+                       return;\r
+               }\r
+               }\r
+        \r
+    }\r
+    \r
+    private boolean requiresNewPipeRun() {\r
+       GraphRequestWithResult<Boolean> createsNewPipeline = new GraphRequestWithResult<Boolean>() {\r
+                       @Override\r
+                       public Boolean performWithResult(Graph g) throws Exception {\r
+                               if(g.isInstanceOf(selectedPort, ProcessResource.plant3Dresource.NozzleControlPoint))\r
+                                       return true;\r
+                               if (selectedType == PositionType.SPLIT)\r
+                                       return true;\r
+                               return false;\r
+                               \r
+                       }\r
+               };\r
+               parent.getSession().syncRead(createsNewPipeline);\r
+               return createsNewPipeline.getResult();\r
+    }\r
+    \r
+    private boolean getNewPipeRunSpecs() {\r
+       PipelineDialog dialog;\r
+               dialog = new PipelineDialog(parent.getRenderingComposite().getShell(),pipeDiameter,elbowRadius);\r
+               if (dialog.open() == PipelineDialog.CANCEL) {\r
+                       end();\r
+                       return false;\r
+               }\r
+               pipeDiameter = dialog.getPipeDiameter();\r
+               elbowRadius = dialog.getTurnRadius();\r
+               return true;\r
+    }\r
+    \r
+    private void startRouting() {\r
+       state = ToolState.INITIALIZING;\r
+       parent.getSession().asyncRead(new GraphRequestAdapter() {\r
+                       @Override\r
+                       public GraphRequestStatus perform(Graph g) throws Exception {\r
+                               PipeControlPoint pcp = new PipeControlPoint(g,selectedPort);\r
+                               lastPoint = ControlPointTools.getRealPosition(pcp, selectedType);//G3DTools.getPoint(pcp.getWorldPosition());\r
+                               if (pcp.isInstanceOf(ProcessResource.plant3Dresource.DirectedControlPoint)) {\r
+                                       lock = LockType.CUSTOM;\r
+                                       customLockDir = ControlPointTools.getDirectedControlPointDirection(pcp);\r
+                               } else if (pcp.isInstanceOf(ProcessResource.plant3Dresource.FixedLengthControlPoint)||\r
+                                                  pcp.isInstanceOf(ProcessResource.plant3Dresource.TurnControlPoint)) {\r
+                                       lock = LockType.CUSTOM;\r
+                                       if (selectedType == PositionType.NEXT)\r
+                                               customLockDir = ControlPointTools.getPathLegDirection(pcp, Direction.NEXT);\r
+                                       else\r
+                                               customLockDir = ControlPointTools.getPathLegDirection(pcp, Direction.PREVIOUS);\r
+                               } else {\r
+                                       lock = LockType.NONE;\r
+                               }\r
+                               IEntity pipeRun = ControlPointTools.getPipeRun(pcp);\r
+                               if (pipeRun != null) {\r
+                                       pipeDiameter = pipeRun.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasPipeDiameter);\r
+                                       elbowRadius = pipeRun.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasTurnRadius);\r
+                               }\r
+                               return GraphRequestStatus.transactionComplete();\r
+                       }\r
+                       \r
+                       @Override\r
+                       public void requestCompleted(GraphRequestStatus status) {\r
+                               createLine();\r
+                               state = ToolState.ROUTING;\r
+                       }\r
+               });\r
+    }\r
+    \r
+    private void startSplitting() {\r
+       parent.getSession().asyncRead(new GraphRequestAdapter() {\r
+                       @Override\r
+                       public GraphRequestStatus perform(Graph g) throws Exception {\r
+                               PipeControlPoint pcp = new PipeControlPoint(g,selectedPort);\r
+                               Point3d p1 = new Point3d();\r
+                               Point3d p2 = new Point3d();\r
+                               ControlPointTools.getInlineControlPointEnds(pcp, p1, p2);\r
+                               splitPointAction.setSplit(p1, p2);\r
+                       splitPointAction.activate();\r
+                       state = ToolState.SELECTING_SPLIT;\r
+                               return GraphRequestStatus.transactionComplete();\r
+                       }\r
+               }); \r
+    }\r
+    \r
+   \r
+    private void updateSelectSplit() {\r
+       if (splitPointAction.active()) {\r
+               splitPointAction.update();\r
+               return;\r
+       } else {\r
+               throw new RuntimeException("SplitPointAction should be active");\r
+       }\r
+    }\r
+    \r
+    @Override\r
+    public void setSplitPoint(Point3d point) {\r
+       splitPointAction.deactivate();\r
+       if (point == null) {\r
+               end();\r
+               return;\r
+       } else {\r
+               \r
+                       \r
+               lastPoint = point;\r
+               createLine();\r
+               state = ToolState.ROUTING;\r
+       }\r
+    }\r
+    \r
+    private void updateRouting() {\r
+       if(input.keyPressed(KeyEvent.VK_ESCAPE)) {\r
+            controlPoints.clear();\r
+            end();\r
+            return;\r
+        }\r
+       if (input.keyPressed(KeyEvent.VK_C)) {\r
+               useCamera = !useCamera;\r
+               cameraAction.setChecked(useCamera);\r
+        }\r
+        if (useCamera) {\r
+               parent.getDefaultAction().update();\r
+               return;\r
+        }\r
+        \r
+        parent.getSession().syncRead(new GraphRequestAdapter() {\r
+                @Override\r
+               public GraphRequestStatus perform(Graph g) throws Exception {\r
+        \r
+        Vector3d o = new Vector3d();\r
+        Vector3d d = new Vector3d();\r
+        parent.createPickRay(o, d);\r
+        if (!updateCurrentPoint(o, d))\r
+            return GraphRequestStatus.transactionComplete();\r
+        //Point3d startPoint = new Point3d();\r
+        double mu[] = new double[2];\r
+        \r
+        IEntity endTo = null;\r
+        PositionType endType = null;\r
+        IEntity endPort = null;\r
+        \r
+        if (parent.getSelectionAdapter().getHighlightSelection().size() > 0) {\r
+               highlightedResource = parent.getSelectionAdapter().getHighlightSelection().getSelectionList().get(0);\r
+        } else {\r
+               highlightedResource = null;\r
+        }\r
+\r
+          if (highlightedResource != null) {\r
+                 IEntity highlightNode = EntityFactory.create(g,highlightedResource);\r
+                    \r
+                 if (lock == LockType.NONE) {\r
+                         if (highlightNode.isInstanceOf(ProcessResource.plant3Dresource.Nozzle) && endingToNozzle(highlightNode,o,d)) {\r
+                                 endTo = highlightNode;\r
+                         } else if (highlightNode.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent)) {\r
+                                 endTo = highlightNode;\r
+                                 endType = endingToStraight(new VariableLengthInlineComponent(highlightNode),mu,o,d);     \r
+                         } else if (highlightNode.isInstanceOf(ProcessResource.plant3Dresource.PipelineComponent) && (endPort = endingToComponent(highlightNode,o,d)) != null) {\r
+                                 endTo = highlightNode;\r
+                         } else {\r
+                                 updateRoute(o,d); \r
+                         }\r
+                 } else {  \r
+                         if (highlightNode.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent)  && (endType = endingLockToStraight(new VariableLengthInlineComponent(highlightNode),mu)) != null) {\r
+                                 endTo = highlightNode;\r
+                         } else if (highlightNode.isInstanceOf(ProcessResource.plant3Dresource.Nozzle) && endingLockToNozzle(highlightNode)) {\r
+                                 endTo = highlightNode;\r
+                         } else if (highlightNode.isInstanceOf(ProcessResource.plant3Dresource.PipelineComponent) && (endPort = endingLockToComponent(highlightNode)) != null) {\r
+                                 endTo = highlightNode;\r
+                         } else {\r
+                                 updateRoute(o,d);\r
+                         }\r
+                 }\r
+                               \r
+              \r
+        } else {\r
+            updateRoute(o,d);\r
+        }\r
+        \r
+        parent.setViewChanged(true);\r
+        if (input.mouseClicked()) {\r
+            if (input.clickButton() == MouseEvent.BUTTON1) {\r
+                if (controlPoints.size() > 0) {\r
+                    addPoint();\r
+                    setLockType(LockType.NONE,true);\r
+                    if (endTo != null) {\r
+                        endComponentResource = endTo.getResource();\r
+                        if (endPort != null)\r
+                               endComponentPort = endPort.getResource();\r
+                        endPortType = endType;\r
+                        \r
+                        endPiping();\r
+                    }\r
+                } else {\r
+                       throw new RuntimeException("kjf");\r
+//                     // user was selecting position of branch\r
+//                    lastPoint.set(startPoint);\r
+//                    controlPoints.add(new Point3d(startPoint));\r
+//                    if (selectionLine != null)\r
+//                     selectionLine.removeFromParent();\r
+//                    selectionLine = null;\r
+                }\r
+            } else if (input.clickButton() == MouseEvent.BUTTON2){\r
+                detector.updateConstraintReference();\r
+            } else if (input.clickButton() == MouseEvent.BUTTON3){      \r
+                endPiping();\r
+            }\r
+        }\r
+        \r
+        return GraphRequestStatus.transactionComplete();\r
+               } \r
+         });\r
+       \r
+    }\r
+    \r
+    private void createLine() {\r
+       controlPoints.add(new Point3d(lastPoint));\r
+       Line line = new Line();\r
+       line.setRenderState(ms);\r
+      \r
+       PipeComponentProvider.createStraightEdges(line, currentPoint, currentPoint, pipeDiameter*0.5);\r
+       pipeShapes.add(line);\r
+       parent.getRenderingComponent().getNoShadowRoot().attachChild(line);    \r
+       line.setCullMode(Geometry.CULL_NEVER);\r
+    }\r
+    \r
+    \r
+    /**\r
+     * Adds current point to pipeline\r
+     *\r
+     */\r
+    private void addPoint() {\r
+       \r
+       controlPoints.add(new Point3d(currentPoint));\r
+        Line line = new Line();\r
+        line.setRenderState(ms);\r
+        PipeComponentProvider.createStraightEdges(line, controlPoints.get(controlPoints.size() - 1), currentPoint, pipeDiameter*0.5);\r
+       pipeShapes.add(line);\r
+       parent.getRenderingComponent().getNoShadowRoot().attachChild(line);   \r
+       line.setCullMode(Geometry.CULL_NEVER);\r
+        lastPoint.set(currentPoint);\r
+    }\r
+    \r
+    /**\r
+     * Updates tool graphics for current point \r
+     */\r
+    private void updateCurrentPoint() {\r
+       PipeComponentProvider.createStraightEdges(pipeShapes.get(pipeShapes.size() - 1), controlPoints.get(controlPoints.size() - 1), currentPoint, pipeDiameter*0.5);\r
+    }\r
+    \r
+    /**\r
+     * Removes last point from pipeline\r
+     */\r
+    public void removePoint() {\r
+       if (controlPoints.size() < 2)\r
+               return;\r
+       controlPoints.remove(controlPoints.size() - 1);\r
+\r
+        pipeShapes.get(pipeShapes.size() - 1).removeFromParent();\r
+        pipeShapes.remove(pipeShapes.size() - 1);\r
+        PipeComponentProvider.createStraightEdges(pipeShapes.get(pipeShapes.size() - 1), controlPoints.get(controlPoints.size() - 1), currentPoint, pipeDiameter*0.5);\r
+       \r
+        lastPoint.set(controlPoints.get(controlPoints.size()-1));\r
+        if (controlPoints.size() < 2 && customLockDir != null) {\r
+               setLockType(LockType.CUSTOM, true);\r
+        }\r
+    }\r
+    \r
+   \r
+    \r
+    private boolean endingToNozzle(IEntity nozzle,Vector3d o, Vector3d d) { \r
+        IEntity pcp = nozzle.getSingleRelatedObject(ProcessResource.plant3Dresource.HasControlPoint);\r
+        if (pcp != null && (pcp.getAtMostOneRelatedObject(ProcessResource.plant3Dresource.HasNext) != null ||\r
+                                   pcp.getAtMostOneRelatedObject(ProcessResource.plant3Dresource.HasPrevious) != null))\r
+               return false; // nozzle is already connected to pipe\r
+        currentPoint = G3DTools.getPoint(nozzle.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition));\r
+        Point3d previousPipePoint = controlPoints.get(controlPoints.size() - 1);\r
+        Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint));\r
+        if (p != null) {\r
+            if (p.distance(currentPoint) > NOZZLE_SNAP_DISTANCE) {\r
+                return false;\r
+            }\r
+        } \r
+        \r
+        updateCurrentPoint();\r
+        \r
+        setInfoText("Connect to nozzle " + currentPoint);\r
+        return true;\r
+    \r
+    }\r
+    \r
+    private PositionType endingToStraight(VariableLengthInlineComponent s, double mu[], Vector3d o, Vector3d d) {\r
+        String info = "";\r
+        Point3d sStart = new Point3d();\r
+        Point3d sEnd = new Point3d();\r
+        //detector.clearConstraintHighlights();\r
+        \r
+        Point3d previousPipePoint = controlPoints.get(controlPoints.size() - 1);\r
+        //String st = "";\r
+        if (lock == LockType.NONE) {\r
+            Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint));\r
+            if (p != null) {\r
+                currentPoint = p;\r
+                // snapping is detected, check if snapped point can create branch with straight\r
+                PositionType t = endingLockToStraight(s, mu);\r
+                if (t != null)\r
+                    return t;\r
+                // if not, we'll have to remove highlight that was added when snapped point was detected\r
+                detector.clearConstraintHighlights();\r
+            } \r
+                \r
+            PipingTools2.getInlineComponentEnds(s, sStart, sEnd);\r
+            Vector3d sDir = new Vector3d(sEnd);\r
+            sDir.sub(sStart);\r
+            MathTools.intersectStraightStraight(sStart, sDir, o, d, currentPoint, new Point3d(), mu);\r
+            \r
+\r
+        } else {\r
+            throw new RuntimeException("Lock shouldn't be on");\r
+\r
+        }\r
+        \r
+        updateCurrentPoint();\r
+        \r
+        // branch point must lie between straight's ends. If connection point is exactly\r
+        // on straight end user may want to connect pipes to each other\r
+        // TODO : take account sizes of inline components)\r
+        // TODO : actually make connection if its detected\r
+        boolean connectPrev = false;\r
+        boolean connectNext = false;\r
+        \r
+        if (mu[0] < 0.0) {\r
+            currentPoint.set(sStart);\r
+            connectPrev = true;\r
+        }\r
+        else if (mu[0] > 1.0) {\r
+            currentPoint.set(sEnd);\r
+            connectNext = true;\r
+        }\r
+        boolean connect = false;\r
+        if (connectPrev) {\r
+            PipeControlPoint pcp = s.getControlPoint();\r
+            if (pcp.getPrevious() == null)\r
+                connect = true;\r
+        } else if (connectNext) {\r
+               PipeControlPoint pcp = s.getControlPoint();\r
+            if (pcp.getNext() == null)\r
+                connect = true;\r
+        }\r
+        \r
+        updateCurrentPoint();\r
+        \r
+        if (connect)\r
+            info += "Connect pipes :";\r
+        else\r
+            info += "Make Branch :";\r
+        \r
+        setInfoText(info + currentPoint + " " + Math.max(0.0, Math.min(mu[0], 1.0)));\r
+        if (connect) {\r
+               if (connectNext) {\r
+                       return PositionType.NEXT;\r
+               } else {\r
+                       return PositionType.PREVIOUS;\r
+               }\r
+                       \r
+        }\r
+        return PositionType.SPLIT;\r
+               \r
+    }\r
+    \r
+    private IEntity endingToComponent(IEntity component, Vector3d o, Vector3d d) {\r
+       // TODO : scan all empty pcps of the component and select closest one.\r
+       return null;\r
+    }\r
+    \r
+    private PositionType endingLockToStraight(VariableLengthInlineComponent s, double mu[]) {\r
+        \r
+        Point3d sStart = new Point3d();//G3DTools.getPoint(s.getHasControlPoint().getPreviousPoint().getLocalPosition());\r
+        Point3d sEnd = new Point3d(); //G3DTools.getPoint(s.getHasControlPoint().getNextPoint().getLocalPosition());\r
+        PipingTools2.getInlineComponentEnds(s, sStart, sEnd);\r
+        Vector3d sDir = new Vector3d(sEnd);\r
+        sDir.sub(sStart);\r
+        Vector3d dir = new Vector3d(currentPoint);\r
+        Point3d prev = controlPoints.get(controlPoints.size() - 1);\r
+        dir.sub(prev);\r
+        // intersection point in pipe where branch would be inserted to\r
+        Vector3d branchPoint = new Vector3d();\r
+        // intersection point in straight pipe that is currently routed\r
+        Vector3d routePoint = new Vector3d();\r
+        MathTools.intersectStraightStraight(sStart, sDir, new Vector3d(prev), dir, branchPoint, routePoint, mu);\r
+        routePoint.sub(branchPoint);\r
+        // startPoint of branch must be between pipe ends\r
+        // TODO : take account sizes of elbows (or other components)\r
+        // branch point must be between pipe ends and intersection points must be quite close to each othert\r
+        if (mu[0] > 0.0 && mu[0] < 1.0 && routePoint.lengthSquared() < BRANCH_SNAP_DISTANCE) {\r
+            currentPoint.set(branchPoint);\r
+            \r
+            updateCurrentPoint();\r
+            \r
+            setInfoText("Make branch (l) :" + currentPoint + " " + Math.max(0.0, Math.min(mu[0], 1.0)) + " " + routePoint.lengthSquared());\r
+            return PositionType.SPLIT;\r
+        }\r
+        return null;\r
+    }\r
+    \r
+    private boolean endingLockToNozzle(IEntity nozzle) {\r
+        Vector3d dir = new Vector3d(currentPoint);\r
+         Point3d prev = controlPoints.get(controlPoints.size() - 1);\r
+         dir.sub(prev);\r
+         Point3d nozzleLoc = G3DTools.getPoint(nozzle.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition));\r
+         double u[] = new double[1];\r
+         Vector3d closest = MathTools.closestPointOnStraight(new Point3d(nozzleLoc), new Point3d(prev), new Vector3d(dir), u);\r
+         double dist = nozzleLoc.distanceSquared(new Point3d(closest));\r
+         if (dist < BRANCH_SNAP_DISTANCE) {\r
+                // FIXME : directions should be checked (insert an elbow)\r
+                currentPoint.set(nozzleLoc);\r
+                updateCurrentPoint();\r
+                setInfoText("Connect to nozzle (l) :" + currentPoint);\r
+                return true;\r
+         } \r
+         //System.out.println(u[0]);\r
+       return false;\r
+    }\r
+    \r
+    private IEntity endingLockToComponent(IEntity component) {\r
+       // we'll must scan all free pcp's and their direction to accept the connection.\r
+       return null;\r
+    }\r
+    \r
+    private void updateRoute(Vector3d o, Vector3d d) {\r
+        detector.clearConstraintHighlights();\r
+        Point3d previousPipePoint = controlPoints.get(controlPoints.size() - 1);\r
+        String s = "";\r
+        if (lock == LockType.NONE) {\r
+            Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint));\r
+            if (p != null)\r
+                currentPoint = p;\r
+            s += detector.getSnapString();\r
+\r
+        } else {\r
+            Vector3d dir = new Vector3d(currentPoint);\r
+            dir.sub(previousPipePoint);\r
+            Point3d p = detector.getPointSnap(new Vector3d(previousPipePoint), dir);\r
+            if (p != null)\r
+                currentPoint = p;\r
+            s += detector.getSnapString();\r
+\r
+        }\r
+        \r
+        updateCurrentPoint();\r
+        s += currentPoint.toString();\r
+        setInfoText(s);\r
+    }\r
+    \r
+    private boolean updateCurrentPoint(Vector3d o, Vector3d d) {\r
+       if (lock != LockType.CUSTOM) {\r
+               if (input.keyPressed(KeyEvent.VK_X)) {\r
+                               if (lock == LockType.X)\r
+                                       setLockType(LockType.YZ,false);\r
+                               else\r
+                                       setLockType(LockType.X,false);\r
+                       }\r
+                       if (input.keyPressed(KeyEvent.VK_Y)) {\r
+                               if (lock == LockType.Y)\r
+                                       setLockType(LockType.XZ,false);\r
+                               else\r
+                                       setLockType(LockType.Y,false);\r
+                       }\r
+                       if (input.keyPressed(KeyEvent.VK_Z)) {\r
+                               if (lock == LockType.Z)\r
+                                       setLockType(LockType.XY,false);\r
+                               else\r
+                                       setLockType(LockType.Z,false);\r
+                       }\r
+                       if (input.keyPressed(KeyEvent.VK_N)) {\r
+                               setLockType(LockType.NONE,false);\r
+                       }\r
+                       if (input.keyPressed(KeyEvent.VK_BACK_SPACE)) {\r
+                               removePoint();\r
+                       }\r
+       }\r
+        Vector3d point = new Vector3d(lastPoint);\r
+        boolean step = ((input.moveModifiers() & MouseEvent.CTRL_DOWN_MASK) > 0);\r
+        switch(lock) {\r
+        case X:\r
+            MathTools.intersectStraightStraight(point, new Vector3d(1.0,0.0,0.0), o,d, currentPoint, new Vector3d());\r
+            if (step) {\r
+                currentPoint.x = Math.round(istep * currentPoint.x) / istep;\r
+                BigDecimal bx = new BigDecimal(currentPoint.x);\r
+                bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);\r
+                currentPoint.x = bx.doubleValue();\r
+            }\r
+            break;\r
+        case Y:\r
+            MathTools.intersectStraightStraight(point, new Vector3d(0.0,1.0,0.0), o,d, currentPoint, new Vector3d());\r
+            if (step) {\r
+                currentPoint.y = Math.round(istep * currentPoint.y) / istep;\r
+                BigDecimal bx = new BigDecimal(currentPoint.y);\r
+                bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);\r
+                currentPoint.y = bx.doubleValue();\r
+            }\r
+            break;\r
+        case Z:\r
+            MathTools.intersectStraightStraight(point, new Vector3d(0.0,0.0,1.0), o,d, currentPoint, new Vector3d());\r
+            if (step) {\r
+                currentPoint.z = Math.round(istep * currentPoint.z) / istep;\r
+                BigDecimal bx = new BigDecimal(currentPoint.z);\r
+                bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);\r
+                currentPoint.z = bx.doubleValue();\r
+            }break;\r
+        case XY:\r
+            MathTools.intersectStraightPlane(o, d, point, new Vector3d(0.0,0.0,1.0), currentPoint);\r
+            break;\r
+        case XZ:\r
+            MathTools.intersectStraightPlane(o, d, point, new Vector3d(0.0,1.0,0.0), currentPoint);\r
+            break;\r
+        case YZ:\r
+            MathTools.intersectStraightPlane(o, d, point, new Vector3d(1.0,0.0,0.0), currentPoint);\r
+            break;\r
+        case NONE:\r
+            Vector3d normal = parent.getCamera().getUnNormalizedHeading();\r
+            normal.normalize();\r
+            \r
+            MathTools.intersectStraightPlane(o, d, point, normal, currentPoint);\r
+            break;\r
+        case CUSTOM:\r
+               MathTools.intersectStraightStraight(point, new Vector3d(customLockDir), o,d, currentPoint, new Vector3d());\r
+            double dist = MathTools.distanceFromPlane(new Vector3d(currentPoint), customLockDir, lastPoint);\r
+               if (dist < 0.0)\r
+                       currentPoint.set(lastPoint);\r
+            break;\r
+        default:\r
+            return false;\r
+        }\r
+        return true;\r
+    }\r
+    \r
+   \r
+    private ArrayList<Point3d> filterPoints() {\r
+        ArrayList<Point3d> filteredControlPoints = new ArrayList<Point3d>();\r
+        \r
+        //  this loop filters control points that are not needed\r
+        for (int i = 0; i < controlPoints.size() - 2; i++) {\r
+            Point3d start = controlPoints.get(i);\r
+            if (i == 0)\r
+                filteredControlPoints.add(start);\r
+            \r
+            Point3d middle = controlPoints.get(i+1);\r
+            Point3d end = controlPoints.get(i+2);\r
+            \r
+            Vector3d dir1 = new Vector3d(middle);\r
+            dir1.sub(start);\r
+            Vector3d dir2 = new Vector3d(end);\r
+            dir2.sub(middle);\r
+            double angle = dir1.angle(dir2);\r
+            if (angle > eps && angle < (Math.PI - eps))\r
+                filteredControlPoints.add(middle);\r
+            // if angle is near PI pipe turns back to where it started\r
+            // if angle is near zero, pipe is straight and there's no need for control point\r
+            \r
+            if (i == controlPoints.size() - 3)\r
+                filteredControlPoints.add(end);\r
+            \r
+        } \r
+        return filteredControlPoints;\r
+    }\r
+    \r
+    private PipeControlPoint connectPipeStart(Graph graph, PipeRun pipeRun, boolean reversed) {\r
+       PipeControlPoint pcp = new PipeControlPoint(graph,selectedPort);\r
+        IEntity beginComponent = EntityFactory.create(graph,beginComponentResource);\r
+        if (beginComponent.isInstanceOf(ProcessResource.plant3Dresource.Nozzle)) {\r
+               PipingTools2.linkNozzleAndPipeRun(beginComponent, pipeRun);\r
+               // TODO : set diameters same\r
+               //reversed = false;\r
+               \r
+        } else if (beginComponent.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent)) {\r
+               switch (selectedType) {\r
+               case NEXT:\r
+                       {\r
+                               PipeControlPoint tcp = createTurn(graph, pipeRun, 0);\r
+                               connectControlPoints(pcp, tcp, reversed);\r
+                               return tcp;\r
+                       }\r
+               case PREVIOUS:\r
+                       {\r
+                               PipeControlPoint tcp = createTurn(graph, pipeRun, 0);\r
+                               connectControlPoints(pcp, tcp, reversed);\r
+                               return tcp;\r
+                       }\r
+               case SPLIT:\r
+                       //reversed = false;\r
+                       // 1. create (non visible) splitting component.\r
+                       PipelineComponent newComponent = PipingTools2.instantiatePipelineComponent(graph, PipingTools2.getPipeRun(beginComponent).getResource(), ProcessResource.plant3Dresource.BranchSplitComponent);                 \r
+                       PipeControlPoint mainCP = newComponent.getControlPoint();\r
+                       // 2. create control point for the branch\r
+                       BranchEndControlPoint becp = BranchEndControlPoint.createDefault(graph);\r
+                       mainCP.addSubPoint(becp);\r
+                       pipeRun.addControlPoints(becp);\r
+                       pcp = becp.toPipeControlPoint();\r
+                       ControlPointTools.setWorldPosition(mainCP, controlPoints.get(0));\r
+                       \r
+                       PipingTools2.splitVariableLengthComponent(newComponent, beginComponent);\r
+               }\r
+        } else if (beginComponent.isInstanceOf(ProcessResource.plant3Dresource.PipelineComponent)) {\r
+               //if (selectedType == PositionType.PREVIOUS)\r
+                       //reversed = true;\r
+               //else\r
+                       //reversed = false;\r
+        } else {\r
+               throw new RuntimeException("unknown starting component");\r
+        }\r
+        \r
+        return pcp;\r
+    }\r
+    \r
+    private PipeControlPoint connectPipeEnd(Graph graph, PipeRun pipeline, boolean reversed) {\r
+        PipeControlPoint pcp = null;\r
+        IEntity endComponent = null;\r
+        if (endComponentResource != null)\r
+               endComponent = EntityFactory.create(graph, endComponentResource);\r
+        if (endComponent == null) {\r
+               return null;\r
+        } else if (endComponent.isInstanceOf(ProcessResource.plant3Dresource.Nozzle)){\r
+               pcp = new PipeControlPoint(endComponent.getSingleRelatedObject(ProcessResource.plant3Dresource.HasControlPoint));\r
+               PipingTools2.linkNozzleAndPipeRun(endComponent, pipeline);\r
+        } else if (endComponent.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent)) {\r
+           assert(endPortType != null);\r
+           if (endPortType == PositionType.SPLIT) {\r
+                  //System.out.println(lastPoint + " " + currentPoint + " " + positions.get(positions.size() - 1));\r
+                  Point3d pos = lastPoint;\r
+                  // 1. create (non visible) splitting component.\r
+                  PipelineComponent newComponent = PipingTools2.instantiatePipelineComponent(graph, PipingTools2.getPipeRun(endComponent).getResource(), ProcessResource.plant3Dresource.BranchSplitComponent);\r
+                         \r
+                          PipeControlPoint mainCP = newComponent.getControlPoint();\r
+                          // 2. create control point for the branch\r
+                          BranchEndControlPoint becp = BranchEndControlPoint.createDefault(graph);\r
+                          mainCP.addSubPoint(becp);\r
+                          pipeline.addControlPoints(becp);\r
+                          pcp = becp.toPipeControlPoint();\r
+                          ControlPointTools.setWorldPosition(mainCP, pos);\r
+                          \r
+                          PipingTools2.splitVariableLengthComponent(newComponent, endComponent);\r
+           } else {\r
+                  \r
+           }      \r
+        } else if (endComponent.isInstanceOf(ProcessResource.plant3Dresource.FixedLengthInlineComponent)) {\r
+               // attach to selected port, reverse the piperun if needed\r
+               pcp = new PipeControlPoint(graph,endComponentPort);\r
+               if (!reversed && pcp.getPrevious() != null || reversed && pcp.getNext() != null) {\r
+                       PipingTools2.reversePipeRun(ControlPointTools.getPipeRun(pcp));\r
+               }\r
+        }\r
+        return pcp;\r
+    }\r
+    \r
+    private PipeControlPoint createTurn(Graph coreTC,PipeRun pipeRun, int i) {\r
+       PipelineComponent elbow = PipingTools2.instantiatePipelineComponent(coreTC,pipeRun.getResource(), ProcessResource.plant3Dresource.Elbow);\r
+        G3DAPI.setWorldPosition(elbow, controlPoints.get(i));\r
+        return elbow.getControlPoint();\r
+    }\r
+    \r
+    private PipeControlPoint createInline(Graph graph, PipeRun pipeRun, int i) {\r
+       Point3d p1 = controlPoints.get(i-1);\r
+       Point3d p2 = controlPoints.get(i);\r
+       Vector3d v = new Vector3d(p2);\r
+       v.sub(p1);\r
+       double length = v.length();\r
+       v.scale(0.5);\r
+       v.add(p1);\r
+       PipelineComponent straight = PipingTools2.instantiatePipelineComponent(graph,pipeRun.getResource(), ProcessResource.plant3Dresource.Straight);\r
+       G3DAPI.setWorldPosition(straight, v);\r
+       straight.setRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength, length);\r
+        return straight.getControlPoint();\r
+       \r
+    }\r
+    \r
+    private void connectControlPoints(PipeControlPoint previous, PipeControlPoint pcp, boolean reversed) {\r
+        if (previous != null) {\r
+               PipeControlPoint sccp;\r
+               PipeControlPoint ocp;\r
+               if (previous.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)) {\r
+                       sccp = previous;\r
+                       ocp = sccp.getSubPoint().iterator().next();\r
+               } else if (previous.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)) {\r
+                       ocp = previous;\r
+                       sccp = ocp.getSubPointOf();\r
+               } else {\r
+                       if (!reversed) {\r
+                                       previous.setNext(pcp);\r
+                                       pcp.setPrevious(previous);\r
+                               } else {\r
+                                       previous.setPrevious(pcp);\r
+                                       pcp.setNext(previous);\r
+                               }\r
+                       return;\r
+               }\r
+               if (!reversed) {\r
+                               sccp.setNext(pcp);\r
+                               ocp.setNext(pcp);\r
+                               pcp.setPrevious(ocp);\r
+                       } else {\r
+                               sccp.setPrevious(pcp);\r
+                               ocp.setPrevious(pcp);\r
+                               pcp.setNext(sccp);\r
+                       }\r
+               \r
+        }\r
+    }\r
+    \r
+    private void endPiping() {\r
+        state = ToolState.NOT_ACTIVE;\r
+         \r
+        if (controlPoints.size() > 2)   // if there's only two control points, filtering does nothing\r
+            controlPoints = filterPoints();\r
+        \r
+        if (controlPoints.size() > 1) {\r
+            parent.getSession().asyncWrite(new GraphRequestAdapter() {\r
+               @Override\r
+               public GraphRequestStatus perform(Graph graph) throws Exception {\r
+                       PipeRun pipeline = null;\r
+                    boolean reversed;\r
+                    PipelineComponent beginComponent = new PipelineComponent(graph,beginComponentResource);\r
+                    if (beginComponent.isInstanceOf(ProcessResource.plant3Dresource.Nozzle) ||\r
+                               selectedType == PositionType.SPLIT) {\r
+\r
+                       \r
+//                      \r
+                        pipeline = PipeRun.createDefault(graph);\r
+                        ((ProcessEditor) parent).getPlant(graph).addChild(pipeline);\r
+                        pipeline.setPipeDiameter(pipeDiameter);\r
+                        pipeline.setTurnRadius(elbowRadius);\r
+                        reversed = false;\r
+                    } else if (beginComponent.isInstanceOf(ProcessResource.plant3Dresource.SizeChangeComponent)||\r
+                               beginComponent.isInstanceOf(ProcessResource.plant3Dresource.OffsetComponent)){\r
+                       PipeControlPoint pcp = new PipeControlPoint(graph,selectedPort);\r
+                       if (selectedType == PositionType.NEXT) {\r
+                               // get the piperun from offsetpoint\r
+                               reversed = false;\r
+                               pipeline = pcp.getSubPoint().iterator().next().getControlPointOfPipeRun();\r
+                       } else if (selectedType == PositionType.PREVIOUS) {\r
+                               reversed = true;\r
+                               pipeline = pcp.getControlPointOfPipeRun();\r
+                       } else {\r
+                               throw new RuntimeException("Wrong PsoitionType " + selectedType + " for a SizeChangeComponent");\r
+                       }\r
+                       \r
+                    } else if (beginComponent.isInstanceOf(ProcessResource.plant3Dresource.PipelineComponent)) {\r
+                       \r
+                        pipeline = new PipeRun(beginComponent.getParent());\r
+                        if (selectedType == PositionType.PREVIOUS) {\r
+                               reversed = true;\r
+                        } else {\r
+                               reversed = false;\r
+                        }\r
+                    } else {\r
+                        throw new RuntimeException("Cannot start routing pipe : object not supported!");\r
+                    }\r
+\r
+                    PipeControlPoint previous = null;\r
+                    for (int i = 0; i < controlPoints.size(); i++) {\r
+                        PipeControlPoint pcp = null;\r
+                        if (i == 0) {\r
+                            pcp = connectPipeStart(graph, pipeline,reversed);\r
+\r
+                        } else {\r
+                               pcp = createInline(graph, pipeline, i);\r
+                               connectControlPoints(previous, pcp, reversed);\r
+                               previous = pcp;\r
+                               if (i == controlPoints.size() - 1) {\r
+                                        pcp = connectPipeEnd(graph, pipeline, reversed);\r
+                               } else {\r
+                               \r
+                                pcp = createTurn(graph,pipeline,i);\r
+                            }\r
+                        }\r
+                           \r
+                        if (pcp != null) {\r
+                               connectControlPoints(previous, pcp, reversed);\r
+                               //pipeline.addSgetHasControlPointSet().add(pcp);\r
+                               previous = pcp;\r
+                        }\r
+                    }\r
+                       return GraphRequestStatus.transactionComplete();\r
+               }\r
+               \r
+               @Override\r
+               public void requestCompleted(GraphRequestStatus status) {\r
+                       endThreaded();\r
+               }\r
+            });\r
+\r
+                \r
+            \r
+        } else {\r
+            endThreaded();     \r
+        }\r
+    }\r
+    \r
+    private void endThreaded() {\r
+       parent.getRenderingComposite().getDisplay().asyncExec(new Runnable() {\r
+                       @Override\r
+                       public void run() {\r
+                               end();\r
+                       }\r
+               });\r
+    }\r
+\r
+    @Override\r
+    public void init() {\r
+        this.setText("Route pipe");\r
+        this.setToolTipText("Starts routing a new pipeline");\r
+        this.setImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/Straight.png"));\r
+    }\r
+\r
+    @Override\r
+    public boolean usable(Graph g, List<Resource> resources) {\r
+        if (resources.size() != 1) {\r
+               return false;\r
+        }\r
+        return checkStartNode(g,resources.get(0)).size() > 0;\r
+    }\r
+    \r
+   \r
+    \r
+  public boolean acceptDrop(StructuredResourceSelection s, Resource[] ids) {\r
+       if (s.size() != 1)\r
+               return false;\r
+       if (ids == null)\r
+               return false;\r
+       if (ids.length != 1)\r
+               return false;\r
+       final Resource dropped = ids[0];\r
+       final Resource target = s.iterator().next();\r
+       GraphRequestWithResult<Boolean> query = new GraphRequestWithResult<Boolean>() {\r
+               @Override\r
+               public Boolean performWithResult(Graph g) throws Exception {\r
+                       if(!g.isInstanceOf(dropped, ProcessResource.plant3Dresource.VariableLengthInlineComponent))\r
+                               return false;\r
+                       // TODO : check that type is not abstract\r
+                       List<Resource> list = new ArrayList<Resource>();\r
+                       list.add(target);\r
+                       return usable(g, list);\r
+               }\r
+       };\r
+       parent.getSession().syncRead(query);\r
+       return query.getResult();\r
+  }\r
+  \r
+   public void doDrop(StructuredResourceSelection s, Resource[] ids) {\r
+          beginComponentResource = s.iterator().next(); \r
+          parent.setCurrentAction(this);\r
+   }\r
+   \r
+   public void setInfoText(String text) {\r
+          \r
+   }\r
+\r
+}
\ No newline at end of file
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/SelectSplitPointAction.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/SelectSplitPointAction.java
new file mode 100644 (file)
index 0000000..1b004e9
--- /dev/null
@@ -0,0 +1,135 @@
+package fi.vtt.simantics.processeditor.actions;\r
+\r
+import java.awt.event.MouseEvent;\r
+import java.util.List;\r
+\r
+import javax.vecmath.Point3d;\r
+import javax.vecmath.Vector3d;\r
+\r
+import org.simantics.db.Graph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.proconf.g3d.actions.InteractiveAction;\r
+import org.simantics.proconf.g3d.base.MathTools;\r
+import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase;\r
+import org.simantics.proconf.g3d.base.VecmathJmeTools;\r
+\r
+import com.jme.math.Vector3f;\r
+import com.jme.renderer.ColorRGBA;\r
+import com.jme.scene.Line;\r
+import com.jme.scene.state.MaterialState;\r
+import com.jme.util.geom.BufferUtils;\r
+\r
+public class SelectSplitPointAction extends InteractiveAction {\r
+       \r
+       Point3d start;\r
+       Point3d end;\r
+       Vector3d dir;\r
+       \r
+    Line line;\r
+    \r
+    boolean activated;\r
+    \r
+    SplitPointListener listener;\r
+    \r
+    public SelectSplitPointAction(ThreeDimensionalEditorBase parent, SplitPointListener listener) {\r
+               super(parent);\r
+               this.listener = listener;\r
+       }\r
+    \r
+    \r
+    public void setSplit(Point3d start, Point3d end) {\r
+       this.start = start;\r
+       this.end = end;\r
+       dir = new Vector3d(end);\r
+               dir.sub(start);\r
+    }\r
+       \r
+       \r
+       @Override\r
+       public void activate() {\r
+               if (start == null) throw new RuntimeException("Starting split action without information about range");\r
+               \r
+//             start = new Point3d();\r
+//             end = new Point3d();\r
+//             PipingTools.getStraightPipeEnds(PipingTools.getPipeline(straight),\r
+//                             straight, startStart, startEnd);\r
+    \r
+        line = new Line();\r
+        MaterialState ms = parent.getRenderingComponent().getDisplaySystem().getRenderer().createMaterialState();\r
+        ms.setEmissive(new ColorRGBA(1.f,1.f,1.f,1.f));\r
+        line.setRenderState(ms);\r
+        parent.getRenderingComponent().getNoShadowRoot().attachChild(line);\r
+        activated = true;\r
+               \r
+       }\r
+       \r
+       @Override\r
+       public boolean usable(Graph graph, List<Resource> resources) {\r
+//             if (resources.size() != 1)\r
+//                     return false;\r
+//             IEntity entity = EntityFactory.create(graph, resources.get(0));\r
+//             if (entity.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent)) {\r
+//                     return true;\r
+//             }\r
+               // This is not a standalone action\r
+               return false;\r
+       }\r
+       \r
+       @Override\r
+       public void deactivate() {\r
+               line.removeFromParent();\r
+               activated = false;\r
+               start = null;\r
+               end = null;\r
+               dir = null;\r
+               \r
+       }\r
+       \r
+       public boolean active() {\r
+               return activated;\r
+       }\r
+       \r
+       @Override\r
+       public void update() {\r
+               if (!activated) {\r
+                       return;\r
+               }\r
+               if (input.mouseClicked() && input.clickButton() == MouseEvent.BUTTON3) {\r
+                       listener.setSplitPoint(null);\r
+                       activated = false;\r
+                       return;\r
+               }\r
+               Vector3d o = new Vector3d();\r
+               Vector3d d = new Vector3d();\r
+               parent.createPickRay(o, d);\r
+\r
+               Vector3d normal = parent.getCamera().getUnNormalizedHeading();\r
+               normal.normalize();\r
+               normal.negate();\r
+               // reference point for selection line\r
+               Vector3d point = new Vector3d(start);\r
+               Vector3d currentPoint = new Vector3d();\r
+               MathTools.intersectStraightPlane(o, d, point, normal, currentPoint);\r
+               Point3d startPoint = new Point3d();\r
+               double mu[] = new double[2];\r
+               MathTools.intersectStraightStraight(start, dir, o, d, startPoint,\r
+                               new Point3d(), mu);\r
+               // startPoint of branch must be between pipe ends\r
+               // TODO : take account sizes of elbows (or other components)\r
+               if (mu[0] < 0.0)\r
+                       startPoint.set(start);\r
+               else if (mu[0] > 1.0)\r
+                       startPoint.set(end);\r
+\r
+               Vector3f verts[] = new Vector3f[2];\r
+               verts[0] = VecmathJmeTools.get(startPoint);\r
+               verts[1] = VecmathJmeTools.get(currentPoint);\r
+               line.reconstruct(BufferUtils.createFloatBuffer(verts), null, null, null);\r
+\r
+               parent.setViewChanged(true);\r
+               if (input.mouseClicked() && input.clickButton() == MouseEvent.BUTTON1) {\r
+                       listener.setSplitPoint(new Point3d(startPoint));\r
+               }\r
+               \r
+       }\r
+}\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/SplitPointListener.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/SplitPointListener.java
new file mode 100644 (file)
index 0000000..d766ad3
--- /dev/null
@@ -0,0 +1,19 @@
+package fi.vtt.simantics.processeditor.actions;\r
+\r
+import javax.vecmath.Point3d;\r
+\r
+/**\r
+ * SplitPointListener is used by SplitPointAction to pass the selected split point.\r
+ * Implementing class must set itself as active action into editor (SplitPointAction won't close automatically). \r
+ * \r
+ * @author Marko Luukkainen <Marko.Luukkainen@vtt.fi>\r
+ *\r
+ */\r
+public interface SplitPointListener {\r
+\r
+       /**\r
+        * Sets selected split point, or null if user cancelled the action.\r
+        * @param point\r
+        */\r
+       public void setSplitPoint(Point3d point);\r
+}\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/TranslateElbowAction.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/TranslateElbowAction.java
new file mode 100644 (file)
index 0000000..b500e0c
--- /dev/null
@@ -0,0 +1,232 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007 VTT Technical Research Centre of Finland and others.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package fi.vtt.simantics.processeditor.actions;\r
+\r
+import java.util.List;\r
+\r
+import javax.vecmath.AxisAngle4f;\r
+import javax.vecmath.Point3d;\r
+import javax.vecmath.Vector3d;\r
+\r
+import org.simantics.db.Graph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.layer0.utils.EntityFactory;\r
+import org.simantics.layer0.utils.IEntity;\r
+import org.simantics.proconf.g3d.actions.ConstrainedTransformAction;\r
+import org.simantics.proconf.g3d.actions.TranslateActionConstraints;\r
+import org.simantics.proconf.g3d.base.G3DAPI;\r
+import org.simantics.proconf.g3d.base.G3DTools;\r
+import org.simantics.proconf.g3d.base.MathTools;\r
+import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase;\r
+import org.simantics.proconf.g3d.gizmo.TransformInlineGizmo;\r
+import org.simantics.proconf.g3d.scenegraph.IGraphicsNode;\r
+import org.simantics.proconf.g3d.stubs.G3DNode;\r
+\r
+import fi.vtt.simantics.processeditor.Activator;\r
+import fi.vtt.simantics.processeditor.ProcessResource;\r
+import fi.vtt.simantics.processeditor.common.ControlPointTools;\r
+import fi.vtt.simantics.processeditor.stubs.DirectedControlPoint;\r
+import fi.vtt.simantics.processeditor.stubs.PipeControlPoint;\r
+import fi.vtt.simantics.processeditor.stubs.VariableAngleTurnComponent;\r
+\r
+public class TranslateElbowAction extends ConstrainedTransformAction {\r
+\r
+    TransformInlineGizmo gizmo;\r
+    List<IGraphicsNode> mos;\r
+    Vector3d dir;\r
+    Vector3d orgPos;\r
+    double istep = 10.0;\r
+    int decimals = 2;\r
+    \r
+    private Resource pcpResource;\r
+    \r
+    public TranslateElbowAction(ThreeDimensionalEditorBase parent) {\r
+        super(parent);\r
+        gizmo = new TransformInlineGizmo(component.getDisplaySystem().getRenderer());\r
+    \r
+        \r
+    }\r
+    \r
+    public void init() {\r
+        this.setText("Translate directed");\r
+        this.setToolTipText("Translate the elbow in connections direction");\r
+        this.setImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/translate_d.png"));\r
+    }\r
+    \r
+    \r
+    \r
+    @Override\r
+    public boolean usable(Graph graph, List<Resource> resources) {\r
+       // TODO : it should be possible to move multiple components on the same straight\r
+       // TODO : checking against elbow and dcp; these are not correct!\r
+        if (resources.size() != 1)\r
+            return false;\r
+        IEntity r = EntityFactory.create(graph,resources.get(0));\r
+        if (r.isInstanceOf(ProcessResource.plant3Dresource.VariableAngleTurnComponent)) {\r
+               VariableAngleTurnComponent e = new VariableAngleTurnComponent(r);\r
+               PipeControlPoint pcp = e.getControlPoint();\r
+               PipeControlPoint prev = ControlPointTools.findPreviousEnd(pcp);\r
+               PipeControlPoint next = ControlPointTools.findNextEnd(pcp);\r
+               DirectedControlPoint dcp = null;\r
+               int directedCount = 0;\r
+               if (prev != null && prev.isInstanceOf(ProcessResource.plant3Dresource.DirectedControlPoint)) {\r
+                       directedCount++;\r
+                       dcp = new DirectedControlPoint(prev);\r
+               }\r
+               if (next != null && next.isInstanceOf(ProcessResource.plant3Dresource.DirectedControlPoint)) {\r
+                       directedCount++;\r
+                       dcp = new DirectedControlPoint(next);\r
+               }\r
+               if (directedCount == 1) {\r
+                       orgPos = G3DTools.getVector(dcp.getWorldPosition());\r
+                       dir = ControlPointTools.getDirectedControlPointDirection(dcp);\r
+                       pcpResource = pcp.getResource();\r
+                       return true;\r
+               }\r
+               } \r
+               return false;\r
+\r
+    }\r
+    \r
+    @Override\r
+    public void deactivate() {\r
+        parent.setGizmo(null);\r
+        super.deactivate();\r
+    }\r
+\r
+    @Override\r
+    public void activate() {\r
+        parent.setGizmo(gizmo);\r
+\r
+        String text = "";\r
+        mos = parent.getSelectionAdapter().getSelectedObjects();\r
+//        for (IGraphicsNode mo : mos) {\r
+//            text += GraphicsNodeTools.getWorldTranslation(mo.getGraphicsNode());//mo.getWorldPosition() + " ";\r
+//        }\r
+\r
+        mos.iterator().next().getGroup().attachChild(gizmo.getNode());\r
+        setInfoText(text);    \r
+           \r
+        Vector3d front = new Vector3d(1.0,0.0,0.0);\r
+        Vector3d current = new Vector3d(dir);\r
+        float angle = (float)current.angle(front);\r
+        AxisAngle4f aa;\r
+        if (angle < 0.01 || (Math.PI - angle) < 0.01) {\r
+            aa = new AxisAngle4f();\r
+        } else {\r
+            current.normalize();\r
+            Vector3d right = new Vector3d();\r
+            right.cross(front, current);\r
+\r
+            right.normalize();\r
+            if (right.lengthSquared() < 0.01) {\r
+                aa = new AxisAngle4f();\r
+            } else {\r
+                aa = new AxisAngle4f((float) right.x, (float) right.y, (float) right.z, angle);\r
+            }\r
+        }\r
+        gizmo.setRotation(aa);\r
+        \r
+        updateGizmo();\r
+        TranslateActionConstraints.addConstraints(new Resource[]{pcpResource}, detector);\r
+        parent.setViewChanged(true);\r
+    }\r
+    \r
+    \r
+    \r
+    Vector3d getTranslate() {\r
+        Vector3d translate = new Vector3d();\r
+        Vector3d o = new Vector3d();\r
+        Vector3d d = new Vector3d();\r
+        parent.createPickRay(o, d);\r
+        //Vector3d p = gizmo.getPosition();\r
+        if (gizmo.isSelected()) {\r
+            double s[] = new double[1];\r
+           \r
+            Vector3d i1 = new Vector3d();\r
+            Vector3d i2 = new Vector3d();\r
+            s = new double[2];\r
+            MathTools.intersectStraightStraight(orgPos, dir,o, d, i2, i1,s);\r
+            translate.set(dir);\r
+            if (s[0] < 0.0)\r
+                s[0] = 0.0;\r
+            \r
+            translate.scale(s[0]);\r
+            translate.add(orgPos);\r
+            \r
+            if (useConstraints) {\r
+                Vector3d t = new Vector3d(translate);\r
+//              FIXME : snapped point may be outside of proper range\r
+                Point3d snap = detector.getPointSnap2(t, dir);\r
+                if (snap != null) {\r
+                    translate = new Vector3d(snap);\r
+                }\r
+            }\r
+        \r
+            return translate;\r
+        }\r
+        return null;\r
+    }\r
+    \r
+    Vector3d prevTranslate = new Vector3d();\r
+    \r
+    @Override\r
+    public void doChanges(Graph g) throws Exception {\r
+        if (input.mousePressed()) {\r
+            //prevTranslate = getTranslate();\r
+            \r
+        }\r
+        if (input.mouseClicked()) {\r
+            end();\r
+            return;\r
+        }\r
+        if (!input.mouseDragged()) {\r
+            parent.getDefaultAction().update();\r
+            return;\r
+        }   \r
+        parent.setViewChanged(true);\r
+        \r
+        \r
+        List<IGraphicsNode> mos = parent.getSelectionAdapter().getSelectedObjects();\r
+        Vector3d translate = getTranslate();\r
+       \r
+        if (translate == null) {\r
+            //cameraRotateAction.update();\r
+            parent.getDefaultAction().update();\r
+            updateGizmo();\r
+            return;\r
+        }\r
+\r
+        String text = "";\r
+               for (IGraphicsNode mo : mos) {\r
+                       G3DNode node = mo.getG3DNode(g);\r
+                       G3DAPI.setWorldPosition(node, translate);\r
+                       //G3DTools.setTuple3(node.getW, translation)\r
+                       //G3DTools.setLocalTranslation(node,translate);\r
+                       // mo.setLocalTranslation(translate);\r
+                       text += G3DTools.getVector(node.getWorldPosition()) + " " + translate;// mo.getWorldPosition() + " " +\r
+                                                                       \r
+               }\r
+               setInfoText(text);\r
+\r
+        updateGizmo();\r
+\r
+    }\r
+    \r
+    protected void updateGizmo() {\r
+       gizmo.update(camera.getCameraPos(),component);\r
+    }\r
+    \r
+    public void setInfoText(String text) {\r
+       \r
+    }\r
+\r
+}
\ No newline at end of file
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/TranslateInlineComponentAction.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/TranslateInlineComponentAction.java
new file mode 100644 (file)
index 0000000..ebb6649
--- /dev/null
@@ -0,0 +1,234 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007 VTT Technical Research Centre of Finland and others.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package fi.vtt.simantics.processeditor.actions;\r
+\r
+import java.util.List;\r
+\r
+import javax.vecmath.Point3d;\r
+import javax.vecmath.Vector3d;\r
+\r
+import org.eclipse.jface.action.Action;\r
+import org.eclipse.jface.action.IToolBarManager;\r
+import org.simantics.db.Graph;\r
+import org.simantics.db.GraphRequestAdapter;\r
+import org.simantics.db.GraphRequestStatus;\r
+import org.simantics.db.Resource;\r
+import org.simantics.layer0.utils.EntityFactory;\r
+import org.simantics.layer0.utils.IEntity;\r
+import org.simantics.proconf.g3d.actions.ConstrainedTransformAction;\r
+import org.simantics.proconf.g3d.base.G3DAPI;\r
+import org.simantics.proconf.g3d.base.G3DTools;\r
+import org.simantics.proconf.g3d.base.MathTools;\r
+import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase;\r
+import org.simantics.proconf.g3d.gizmo.TransformInlineGizmo;\r
+import org.simantics.proconf.g3d.scenegraph.IGraphicsNode;\r
+import org.simantics.proconf.g3d.stubs.G3DNode;\r
+\r
+import fi.vtt.simantics.processeditor.Activator;\r
+import fi.vtt.simantics.processeditor.ProcessResource;\r
+import fi.vtt.simantics.processeditor.common.PipingTools2;\r
+import fi.vtt.simantics.processeditor.stubs.InlineComponent;\r
+import fi.vtt.simantics.processeditor.stubs.PipeControlPoint;\r
+\r
+\r
+public class TranslateInlineComponentAction extends ConstrainedTransformAction {\r
+       \r
+    TransformInlineGizmo gizmo;\r
+    List<IGraphicsNode> mos;\r
+    Point3d start;\r
+    Point3d end;\r
+    Vector3d dir;\r
+    double istep = 10.0;\r
+    int decimals = 2;\r
+    \r
+    public TranslateInlineComponentAction(ThreeDimensionalEditorBase parent) {\r
+        super(parent);\r
+        gizmo = new TransformInlineGizmo(component.getDisplaySystem().getRenderer());\r
+\r
+    }\r
+    \r
+    public void init() {\r
+        this.setText("Translate");\r
+        this.setToolTipText("Translate the object");\r
+        this.setImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/translate_d.png"));\r
+    }\r
+    \r
+   \r
+    \r
+    @Override\r
+    public boolean usable(Graph graph, List<Resource> resources) {\r
+       // TODO : it should be possible to move multiple components on the same straight\r
+        if (resources.size() != 1)\r
+            return false;\r
+        IEntity r = EntityFactory.create(graph,resources.get(0));\r
+        PipeControlPoint pcp = null;\r
+        if (r.isInstanceOf(ProcessResource.plant3Dresource.FixedLengthInlineComponent)) {\r
+               InlineComponent component = new InlineComponent(r);\r
+               pcp = component.getControlPoint();\r
+               } else {\r
+                       return false;\r
+               }\r
+        if (pcp.getNext() == null || pcp.getPrevious() == null)\r
+               return false;\r
+        return true;\r
+    }\r
+    \r
+    @Override\r
+    public void deactivate() {\r
+        parent.setGizmo(null);\r
+        super.deactivate();\r
+    }\r
+\r
+    @Override\r
+    public void activate() {\r
+        parent.setGizmo(gizmo);\r
+\r
+        String text = "";\r
+        mos = parent.getSelectionAdapter().getSelectedObjects();\r
+//        for (IGraphicsNode mo : mos) {\r
+//            text += GraphicsNodeTools.getWorldTranslation(mo.getGraphicsNode());//mo.getWorldPosition() + " ";\r
+//        }\r
+\r
+        mos.iterator().next().getGroup().attachChild(gizmo.getNode());\r
+        setInfoText(text);    \r
+           \r
+        \r
+        start = new Point3d();\r
+        end = new Point3d();\r
+        dir = new Vector3d();\r
+        parent.getSession().syncRead(new GraphRequestAdapter() {\r
+               @Override\r
+               public GraphRequestStatus perform(Graph g) throws Exception {\r
+                       \r
+                       InlineComponent ic = new InlineComponent(mos.iterator().next().getG3DNode(g));\r
+                       PipingTools2.getInlineMovement(ic, start, end);\r
+                       \r
+                       //PipingTools2.getInlineComponentEnds(ic, start, end);\r
+                dir.set(end);\r
+                dir.sub(start);\r
+\r
+                       return GraphRequestStatus.transactionComplete();\r
+               }\r
+        });\r
+        \r
+        updateGizmo();\r
+        parent.setViewChanged(true);\r
+    }\r
+    \r
+    \r
+    \r
+    Vector3d getTranslate() {\r
+        Vector3d translate = new Vector3d();\r
+        Vector3d o = new Vector3d();\r
+        Vector3d d = new Vector3d();\r
+        parent.createPickRay(o, d);\r
+        //Vector3d p = gizmo.getPosition();\r
+        if (gizmo.isSelected()) {\r
+            double s[] = new double[1];\r
+           \r
+            Vector3d i1 = new Vector3d();\r
+            Vector3d i2 = new Vector3d();\r
+            s = new double[2];\r
+            MathTools.intersectStraightStraight( start, dir,o, d, i2, i1,s);\r
+            translate.set(dir);\r
+            if (s[0] < 0.0)\r
+                s[0] = 0.0;\r
+            else if (s[0] > 1.0)\r
+                s[0] = 1.0;\r
+            translate.scale(s[0]);\r
+            translate.add(start);\r
+            \r
+            if (useConstraints) {\r
+                Vector3d t = new Vector3d(translate);\r
+//              FIXME : snapped point may be outside of proper range\r
+                Point3d snap = detector.getPointSnap2(t, dir);\r
+                if (snap != null) {\r
+                    translate = new Vector3d(snap);\r
+                }\r
+            }\r
+        \r
+            return translate;\r
+        }\r
+        return null;\r
+    }\r
+    \r
+    Vector3d prevTranslate = new Vector3d();\r
+    \r
+    @Override\r
+    public void doChanges(Graph graph) throws Exception {\r
+        if (input.mousePressed()) {\r
+            //prevTranslate = getTranslate();\r
+            \r
+        }\r
+        if (input.mouseClicked()) {\r
+            end();\r
+            return;\r
+        }\r
+        if (!input.mouseDragged()) {\r
+            parent.getDefaultAction().update();\r
+            return;\r
+        }   \r
+        parent.setViewChanged(true);\r
+        \r
+        \r
+        List<IGraphicsNode> mos = parent.getSelectionAdapter().getSelectedObjects();\r
+        Vector3d translate = getTranslate();\r
+       \r
+        if (translate == null) {\r
+            //cameraRotateAction.update();\r
+            parent.getDefaultAction().update();\r
+            updateGizmo();\r
+            return;\r
+        }\r
+        //translate.sub(prevTranslate);\r
+       \r
+//        if ((input.dragModifiers() & MouseEvent.CTRL_MASK) > 0) {\r
+//            String text = "";\r
+//            for (IGraphicsNode mo : mos) {\r
+//                \r
+//                Point3d p = mo.getWorldPosition();\r
+//                p.add(translate);\r
+//                p.x = Math.round(istep * p.x) / istep;\r
+//                BigDecimal bx = new BigDecimal(p.x);\r
+//                bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);\r
+//                p.x = bx.doubleValue();\r
+//\r
+//                \r
+//                 text += p + " ";\r
+//                mo.setWorldTranslation(p);\r
+//                \r
+//            }\r
+//            this.parent.setInfoText(text);\r
+//            \r
+//        } else {\r
+            String text = "";\r
+            for (IGraphicsNode mo : mos) {\r
+               G3DNode node = mo.getG3DNode(graph);\r
+                G3DAPI.setWorldPosition(node, translate);\r
+               //G3DTools.setLocalTranslation(node, translate);\r
+                //mo.setLocalTranslation(translate);\r
+                text += G3DTools.getVector(node.getWorldPosition()) +" " + translate;//mo.getWorldPosition() + " " + translate;\r
+            }\r
+            setInfoText(text);\r
+//        }\r
+        updateGizmo();\r
+\r
+    }\r
+    \r
+    protected void updateGizmo() {\r
+       gizmo.update(camera.getCameraPos(),component);\r
+    }\r
+    \r
+    public void setInfoText(String text) {\r
+       \r
+    }\r
+\r
+}
\ No newline at end of file
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/TranslateStraightAction.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/TranslateStraightAction.java
new file mode 100644 (file)
index 0000000..84d3a64
--- /dev/null
@@ -0,0 +1,404 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007 VTT Technical Research Centre of Finland and others.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package fi.vtt.simantics.processeditor.actions;\r
+\r
+import java.util.List;\r
+\r
+import javax.vecmath.AxisAngle4f;\r
+import javax.vecmath.Point3d;\r
+import javax.vecmath.Vector3d;\r
+\r
+import org.eclipse.jface.action.IToolBarManager;\r
+import org.simantics.db.Graph;\r
+import org.simantics.db.GraphRequestAdapter;\r
+import org.simantics.db.GraphRequestStatus;\r
+import org.simantics.db.Resource;\r
+import org.simantics.layer0.utils.EntityFactory;\r
+import org.simantics.layer0.utils.IEntity;\r
+import org.simantics.proconf.g3d.actions.ConstrainedTransformAction;\r
+import org.simantics.proconf.g3d.actions.TranslateActionConstraints;\r
+import org.simantics.proconf.g3d.base.G3DTools;\r
+import org.simantics.proconf.g3d.base.MathTools;\r
+import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase;\r
+import org.simantics.proconf.g3d.gizmo.AbstractGizmo;\r
+import org.simantics.proconf.g3d.gizmo.TransformGizmo;\r
+import org.simantics.proconf.g3d.gizmo.TransformInlineGizmo;\r
+\r
+import fi.vtt.simantics.processeditor.common.ControlPointTools;\r
+import fi.vtt.simantics.processeditor.common.PipingTools2;\r
+import fi.vtt.simantics.processeditor.stubs.FixedLengthInlineComponent;\r
+import fi.vtt.simantics.processeditor.stubs.PipeControlPoint;\r
+
+import fi.vtt.simantics.processeditor.Activator;\r
+import fi.vtt.simantics.processeditor.ProcessResource;\r
+\r
+\r
+/**\r
+ * Action that allows translating VariableLengthInlineComontolPoints.\r
+ * \r
+ * TODO : Action won't show two gizmos when both ends can be moved\r
+ * TODO : With loose ends, gizmo is in the middle of component, when it should be positioned on the end of the component\r
+ * \r
+ * \r
+ * @author Marko Luukkainen <Marko.Luukkainen@vtt.fi>\r
+ *\r
+ */\r
+public class TranslateStraightAction extends ConstrainedTransformAction {\r
+       \r
+       private static final int CONNECTED = 0;\r
+    private static final int LOOSE = 1;\r
+    \r
+    private AbstractGizmo gizmo; \r
+    private TransformGizmo transformGizmo;\r
+    private TransformInlineGizmo transformInlineGizmo;\r
+    \r
+    \r
+    //private Straight straight;\r
+    //private PipeControlPoint pcp;\r
+    \r
+    private Resource pcpResource;\r
+    \r
+    private int type;\r
+\r
+    Vector3d prevTranslate = new Vector3d();\r
+    \r
+    Point3d start;\r
+    Point3d end;\r
+    Vector3d dir;\r
+    double istep = 10.0;\r
+    int decimals = 2;\r
+    public TranslateStraightAction(ThreeDimensionalEditorBase parent) {\r
+       super(parent);\r
+        transformGizmo = new TransformGizmo(component.getDisplaySystem().getRenderer());\r
+        transformInlineGizmo = new TransformInlineGizmo(component.getDisplaySystem().getRenderer());\r
+    }\r
+    \r
+    public void init() {\r
+        this.setText("Translate");\r
+        this.setToolTipText("Translate one end of a straight");\r
+        this.setImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/translate_d.png"));\r
+    }\r
+    \r
+    @Override\r
+    public boolean usable(Graph graph, List<Resource> resources) {\r
+        if (resources.size() != 1)\r
+            return false;\r
+       \r
+        IEntity r = EntityFactory.create(graph,resources.get(0));\r
+        if (!r.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent)) {\r
+                       return false;\r
+               }\r
+        FixedLengthInlineComponent flic = new FixedLengthInlineComponent(r);\r
+        PipeControlPoint scp = flic.getControlPoint();\r
+        PipeControlPoint start = scp.getPrevious();\r
+        PipeControlPoint end = scp.getNext(); \r
+        \r
+        if (start == null) {\r
+               pcpResource = scp.getResource();\r
+               type = LOOSE;\r
+               return true;\r
+        }\r
+        if (end == null) {\r
+               pcpResource = scp.getResource();\r
+               type = LOOSE;\r
+               return true;\r
+        }\r
+        if (start.isInstanceOf(ProcessResource.plant3Dresource.BranchEndControlPoint)) {\r
+               pcpResource = graph.getObjects(start.getResource(), ProcessResource.plant3Dresource.SubPointOf).iterator().next();\r
+               type = CONNECTED;\r
+               return true;\r
+        }\r
+        if (end.isInstanceOf(ProcessResource.plant3Dresource.BranchEndControlPoint)) {\r
+               pcpResource = graph.getObjects(end.getResource(), ProcessResource.plant3Dresource.SubPointOf).iterator().next();\r
+               type = CONNECTED;\r
+               return true;\r
+        }\r
+       \r
+\r
+        return false;\r
+        \r
+    }\r
+    \r
+    @Override\r
+    public void deactivate() {\r
+       super.deactivate();\r
+        parent.setGizmo(null);\r
+\r
+    }\r
+\r
+    @Override\r
+    public void activate() {\r
+       parent.getSession().syncRead(new GraphRequestAdapter() {\r
+               @Override\r
+               public GraphRequestStatus perform(Graph g) throws Exception {\r
+                       PipeControlPoint pcp = new PipeControlPoint(g,pcpResource);\r
+                       if (type == CONNECTED) {\r
+                   gizmo = transformInlineGizmo;\r
+                   \r
+                   start = new Point3d();\r
+                   end = new Point3d();\r
+                   dir = new Vector3d();\r
+                   //ControlPointTools.getInlineControlPointEnds(pcp, start, end, dir);\r
+                   ControlPointTools.getInlineMovement(pcp, start, end);\r
+                       \r
+                       //PipingTools2.getInlineComponentEnds(ic, start, end);\r
+                    dir.set(end);\r
+                    dir.sub(start);\r
+                    \r
+                   //System.out.println(start + " " + end + " " + dir);\r
+                   Vector3d front = new Vector3d(1.0,0.0,0.0);\r
+                   Vector3d current = new Vector3d(dir);\r
+                   float angle = (float)current.angle(front);\r
+                   AxisAngle4f aa;\r
+                   if (angle < 0.01 || (Math.PI - angle) < 0.01) {\r
+                       aa = new AxisAngle4f();\r
+                   } else {\r
+                       current.normalize();\r
+                       Vector3d right = new Vector3d();\r
+                       right.cross(front, current);\r
+\r
+                       right.normalize();\r
+                       if (right.lengthSquared() < 0.01) {\r
+                           aa = new AxisAngle4f();\r
+                       } else {\r
+                           aa = new AxisAngle4f((float) right.x, (float) right.y, (float) right.z, angle);\r
+                       }\r
+                   }\r
+                   transformInlineGizmo.setRotation(aa);\r
+                   \r
+               } else {\r
+                   gizmo = transformGizmo;\r
+               }\r
+               parent.setGizmo(gizmo);\r
+\r
+               component.getNoShadowRoot().attachChild(gizmo.getNode());\r
+\r
+               updateGizmo(pcp);\r
+               TranslateActionConstraints.addConstraints(new Resource[]{pcpResource}, detector);\r
+               parent.setViewChanged(true);\r
+               \r
+                       return GraphRequestStatus.transactionComplete();\r
+               }\r
+       });\r
+        \r
+    }\r
+    \r
+    \r
+    // FIXME : copy-paste from TranslateInlineAction.getTranslate()\r
+    Vector3d getTranslate() {\r
+        Vector3d translate = new Vector3d();\r
+        Vector3d o = new Vector3d();\r
+        Vector3d d = new Vector3d();\r
+        parent.createPickRay(o, d);\r
+        // Vector3d p = gizmo.getPosition();\r
+        if (((TransformInlineGizmo) gizmo).isSelected()) {\r
+            double s[] = new double[1];\r
+\r
+            Vector3d i1 = new Vector3d();\r
+            Vector3d i2 = new Vector3d();\r
+            s = new double[2];\r
+            MathTools.intersectStraightStraight(start, dir, o, d, i2, i1, s);\r
+            translate.set(dir);\r
+            if (s[0] < 0.0)\r
+                s[0] = 0.0;\r
+            else if (s[0] > 1.0)\r
+                s[0] = 1.0;\r
+            translate.scale(s[0]);\r
+            translate.add(start);\r
+            \r
+            if (useConstraints) {\r
+                Vector3d t = new Vector3d(translate);\r
+                // FIXME : snapped point may be outside of proper range\r
+                Point3d snap = detector.getPointSnap2(t, dir);\r
+                if (snap != null) {\r
+                    translate = new Vector3d(snap);\r
+                }\r
+            }\r
+\r
+            return translate;\r
+        }\r
+        return null;\r
+    }\r
+    // FIXME : copy-paste from TranslateAction.getTranslate(Vector3d v)\r
+    Vector3d getTranslate(PipeControlPoint pcp, Vector3d offset) {\r
+        Vector3d translate = new Vector3d();\r
+        Vector3d o = new Vector3d();\r
+        Vector3d d = new Vector3d();\r
+        parent.createPickRay(o, d);\r
+        Vector3d p = ((TransformGizmo)gizmo).getPosition();\r
+        Vector3d dir = null;\r
+        switch (((TransformGizmo)gizmo).getSelected()) {\r
+        case TransformGizmo.XYZ :\r
+            Vector3d normal = camera.getUnNormalizedHeading();\r
+            normal.normalize();\r
+            double s[] = new double[1];\r
+            Vector3d r = new Vector3d();\r
+            if (MathTools.intersectStraightPlane(o, d, p, normal, r)) {\r
+                r.sub(p);\r
+                translate.x = r.x;\r
+                translate.y = r.y;\r
+                translate.z = r.z;\r
+            }\r
+            break;\r
+        case TransformGizmo.X :\r
+            dir = new Vector3d(1.0,0.0,0.0);\r
+            Vector3d i1 = new Vector3d();\r
+            Vector3d i2 = new Vector3d();\r
+            s = new double[2];\r
+            MathTools.intersectStraightStraight( p, dir,o, d, i2, i1,s);\r
+            translate.x = s[0];\r
+            \r
+            break;\r
+        case TransformGizmo.Y :\r
+            dir = new Vector3d(0.0,1.0,0.0);\r
+            i1 = new Vector3d();\r
+            i2 = new Vector3d();\r
+            s = new double[2];\r
+            MathTools.intersectStraightStraight( p, dir,o, d, i2, i1,s);\r
+            translate.y = s[0];\r
+            break;\r
+        case TransformGizmo.Z :\r
+            dir = new Vector3d(0.0,0.0,1.0);\r
+            i1 = new Vector3d();\r
+            i2 = new Vector3d();\r
+            s = new double[2];\r
+            MathTools.intersectStraightStraight( p, dir,o, d, i2, i1,s);\r
+            translate.z = s[0];\r
+            break;\r
+        case TransformGizmo.XY :\r
+            normal = new Vector3d(0.0,0.0,1.0);\r
+            s = new double[1];\r
+            r = new Vector3d();\r
+            if (MathTools.intersectStraightPlane(o, d, p, normal, r)) {\r
+                r.sub(p);\r
+                translate.x = r.x;\r
+                translate.y = r.y;\r
+            }\r
+            break;\r
+        case TransformGizmo.XZ :\r
+            normal = new Vector3d(0.0,1.0,0.0);\r
+            s = new double[1];\r
+            r = new Vector3d();\r
+            if (MathTools.intersectStraightPlane(o, d, p, normal, r)) {\r
+                r.sub(p);\r
+                translate.x = r.x;\r
+                translate.z = r.z;\r
+            }\r
+            break;\r
+        case TransformGizmo.YZ :\r
+            normal = new Vector3d(1.0,0.0,0.0);\r
+            s = new double[1];\r
+            r = new Vector3d();\r
+            if (MathTools.intersectStraightPlane(o, d, p, normal, r)) {\r
+                r.sub(p);\r
+                translate.y = r.y;\r
+                translate.z = r.z;\r
+            }\r
+            break;\r
+        default :\r
+            \r
+            return null;\r
+        }\r
+        //System.out.println(translate + " " + offset);\r
+        translate.sub(offset);\r
+        \r
+        if (useConstraints) {\r
+            switch (((TransformGizmo)gizmo).getSelected()) {\r
+            case TransformGizmo.X:\r
+            case TransformGizmo.Y:\r
+            case TransformGizmo.Z:\r
+                Vector3d t = new Vector3d(translate);\r
+                // TODO : to the test against all translated objects and snap to closest one\r
+                Point3d pos = G3DTools.getPoint(pcp.getLocalPosition());\r
+                t.add(pos);\r
+                Point3d snap = detector.getPointSnap2(t, dir);\r
+                if (snap != null) {\r
+                   // System.out.print("t: " + translate);\r
+                    translate = new Vector3d(snap);\r
+                    translate.sub(pos);\r
+                   // System.out.println(" " + translate);\r
+                }\r
+                break;\r
+                \r
+            }\r
+        }\r
+        //System.out.println(translate);\r
+        return translate;\r
+    }\r
+    \r
+    \r
+    \r
+    @Override\r
+    public void doChanges(Graph graph) throws Exception {\r
+       PipeControlPoint pcp = new PipeControlPoint(graph, pcpResource); \r
+        if (input.mousePressed()) {\r
+            if (type == LOOSE)\r
+                prevTranslate = getTranslate(pcp,new Vector3d());\r
+            \r
+        }\r
+        if (input.mouseClicked()) {\r
+            //System.out.println("end");\r
+            end();\r
+            return;\r
+        }\r
+        if (!input.mouseDragged()) {\r
+            parent.getDefaultAction().update();\r
+            return;\r
+        } \r
+        detector.clearConstraintHighlights();\r
+        parent.setViewChanged(true);\r
+        \r
+        \r
+        Vector3d translate;\r
+        if (type == CONNECTED)\r
+            translate = getTranslate();\r
+        else\r
+            translate = getTranslate(pcp,prevTranslate);\r
+       \r
+        if (translate == null) {\r
+            //cameraRotateAction.update();\r
+            parent.getDefaultAction().update();\r
+            updateGizmo(pcp);\r
+            return;\r
+        }\r
+\r
+        String text = "";\r
+        \r
+        if (type == CONNECTED) {\r
+                G3DTools.setTuple3(pcp.getWorldPosition(), translate);\r
+                // mo.setLocalTranslation(translate);\r
+                //text += GraphicsNodeTools.getWorldTranslation(mo.getGraphicsNode()) + " " + translate;// mo.getWorldPosition()\r
+                if (useConstraints)\r
+                    text+=detector.getSnapString();\r
+\r
+        } else {\r
+                G3DTools.addTuple3(pcp.getWorldPosition(), translate);\r
+               // mo.modifyWorldTranslation(translate);\r
+                //text += GraphicsNodeTools.getWorldTranslation(mo.getGraphicsNode()) + " ";//mo.getWorldPosition() + " ";\r
+            if (useConstraints)\r
+                text+=detector.getSnapString();\r
+            \r
+        }\r
+        \r
+        setInfoText(text);\r
+        updateGizmo(pcp);\r
+\r
+    }\r
+    \r
+    protected void updateGizmo(PipeControlPoint pcp) {\r
+               gizmo.update(G3DTools.getVector(pcp.getWorldPosition()), camera.getCameraPos(), component);\r
+    }\r
+    \r
+    public void setInfoText(String text) {\r
+       \r
+    }\r
+\r
+}
\ No newline at end of file
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/adapters/InlineComponentConstraintAdapter.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/adapters/InlineComponentConstraintAdapter.java
new file mode 100644 (file)
index 0000000..e21bda7
--- /dev/null
@@ -0,0 +1,36 @@
+package fi.vtt.simantics.processeditor.adapters;\r
+\r
+import javax.vecmath.Point3d;\r
+import javax.vecmath.Vector3d;\r
+\r
+import org.simantics.db.Graph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.adaption.AdaptionException;\r
+import org.simantics.db.adaption.ResourceAdapter;\r
+import org.simantics.layer0.utils.EntityFactory;\r
+import org.simantics.layer0.utils.IEntity;\r
+import org.simantics.proconf.g3d.base.Constraint;\r
+\r
+import fi.vtt.simantics.processeditor.ProcessResource;\r
+import fi.vtt.simantics.processeditor.common.PipingTools2;\r
+\r
+public class InlineComponentConstraintAdapter implements ResourceAdapter {\r
+       @SuppressWarnings("unchecked")\r
+       @Override\r
+       public <T> T adapt(Graph graph, Resource resource, Resource mia) throws AdaptionException {\r
+               Constraint c = new Constraint();\r
+               assert(graph.isInstanceOf(resource, ProcessResource.plant3Dresource.InlineComponent));\r
+               IEntity ent = EntityFactory.create(graph,resource);\r
+               Point3d center = new Point3d();\r
+               Point3d p1 = new Point3d();\r
+               Point3d p2 = new Point3d();\r
+               Vector3d dir = new Vector3d();\r
+               PipingTools2.getInlineComponentEnds(ent, center, p1, p2, dir);\r
+               c.points.add(center);\r
+               c.points.add(p1);\r
+               c.points.add(p2);\r
+               c.dirs.add(dir);\r
+               return (T) c;\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/adapters/NozzleConstraintAdapter.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/adapters/NozzleConstraintAdapter.java
new file mode 100644 (file)
index 0000000..33b8075
--- /dev/null
@@ -0,0 +1,32 @@
+package fi.vtt.simantics.processeditor.adapters;\r
+\r
+import javax.vecmath.Point3d;\r
+import javax.vecmath.Vector3d;\r
+\r
+import org.simantics.db.Graph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.adaption.AdaptionException;\r
+import org.simantics.db.adaption.ResourceAdapter;\r
+import org.simantics.layer0.utils.EntityFactory;\r
+import org.simantics.layer0.utils.IEntity;\r
+import org.simantics.proconf.g3d.base.Constraint;\r
+import org.simantics.proconf.g3d.base.G3DTools;\r
+\r
+import fi.vtt.simantics.processeditor.ProcessResource;\r
+import fi.vtt.simantics.processeditor.common.PipingTools2;\r
+\r
+public class NozzleConstraintAdapter implements ResourceAdapter {\r
+       @SuppressWarnings("unchecked")\r
+       @Override\r
+       public <T> T adapt(Graph graph, Resource resource, Resource mia) throws AdaptionException {\r
+               Constraint c = new Constraint();\r
+               assert(graph.isInstanceOf(resource, ProcessResource.plant3Dresource.Nozzle));\r
+               IEntity ent = EntityFactory.create(graph,resource);\r
+               Vector3d dir = PipingTools2.getNozzleDirection(ent);\r
+               Point3d center = G3DTools.getPoint(ent.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition));\r
+               c.points.add(center);\r
+               c.dirs.add(dir);\r
+               return (T) c;\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/adapters/TurnComponentConstraintAdapter.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/adapters/TurnComponentConstraintAdapter.java
new file mode 100644 (file)
index 0000000..4df00b5
--- /dev/null
@@ -0,0 +1,42 @@
+package fi.vtt.simantics.processeditor.adapters;\r
+\r
+import javax.vecmath.Point3d;\r
+import javax.vecmath.Vector3d;\r
+\r
+import org.simantics.db.Graph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.adaption.AdaptionException;\r
+import org.simantics.db.adaption.ResourceAdapter;\r
+import org.simantics.layer0.utils.EntityFactory;\r
+import org.simantics.layer0.utils.IEntity;\r
+import org.simantics.proconf.g3d.base.Constraint;\r
+import org.simantics.proconf.g3d.base.G3DTools;\r
+\r
+import fi.vtt.simantics.processeditor.ProcessResource;\r
+import fi.vtt.simantics.processeditor.actions.PositionType;\r
+import fi.vtt.simantics.processeditor.common.ControlPointTools;\r
+import fi.vtt.simantics.processeditor.common.PipingTools2.Direction;\r
+\r
+public class TurnComponentConstraintAdapter implements ResourceAdapter {\r
+       @SuppressWarnings("unchecked")\r
+       @Override\r
+       public <T> T adapt(Graph graph, Resource resource, Resource mia) throws AdaptionException {\r
+               Constraint c = new Constraint();\r
+               assert(graph.isInstanceOf(resource, ProcessResource.plant3Dresource.TurnComponent));\r
+               IEntity ent = EntityFactory.create(graph,resource);\r
+               IEntity pcp = ent.getSingleRelatedObject(ProcessResource.plant3Dresource.HasControlPoint);\r
+               \r
+               Point3d center = G3DTools.getPoint(pcp.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition));\r
+               Point3d p1 = ControlPointTools.getRealPosition(pcp, PositionType.NEXT);\r
+               Point3d p2 = ControlPointTools.getRealPosition(pcp, PositionType.PREVIOUS);\r
+               Vector3d dir1 = ControlPointTools.getPathLegDirection(pcp, Direction.NEXT);\r
+               Vector3d dir2 = ControlPointTools.getPathLegDirection(pcp, Direction.PREVIOUS);\r
+               c.points.add(center);\r
+               c.points.add(p1);\r
+               c.points.add(p2);\r
+               c.dirs.add(dir1);\r
+               c.dirs.add(dir2);\r
+               return (T) c;\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/animations/PipeAnimationController.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/animations/PipeAnimationController.java
new file mode 100644 (file)
index 0000000..0524171
--- /dev/null
@@ -0,0 +1,141 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007 VTT Technical Research Centre of Finland and others.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package fi.vtt.simantics.processeditor.animations;\r
+\r
+import java.net.URL;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import org.eclipse.core.runtime.FileLocator;\r
+import org.eclipse.core.runtime.Path;\r
+import org.simantics.db.Graph;\r
+import org.simantics.layer0.utils.IEntity;\r
+import org.simantics.proconf.g3d.animation.Animatable;\r
+import org.simantics.proconf.g3d.animation.AnimationController;\r
+import org.simantics.proconf.g3d.base.JmeRenderingComponent;\r
+\r
+import com.jme.bounding.BoundingBox;\r
+import com.jme.image.Texture;\r
+import com.jme.intersection.PickResults;\r
+import com.jme.math.Ray;\r
+import com.jme.renderer.Renderer;\r
+import com.jme.scene.Node;\r
+import com.jme.scene.state.AlphaState;\r
+import com.jme.scene.state.TextureState;\r
+import com.jme.scene.state.ZBufferState;\r
+import com.jme.util.TextureManager;\r
+import com.jmex.effects.particles.ParticleGeometry;\r
+\r
+import fi.vtt.simantics.processeditor.Activator;\r
+import fi.vtt.simantics.processeditor.ProcessResource;\r
+import fi.vtt.simantics.processeditor.stubs.PipeRun;\r
+import fi.vtt.simantics.processeditor.stubs.VariableLengthInlineComponent;\r
+\r
+\r
+public class PipeAnimationController implements AnimationController {\r
+       private List<ParticleGeometry> pipeAnimations = new ArrayList<ParticleGeometry>();\r
+       \r
+       List<PipeFlowAnimation> animatables = new ArrayList<PipeFlowAnimation>();\r
+       \r
+       private double d = Math.random();\r
+    private double delta = 0.01;\r
+    \r
+    AlphaState as1;\r
+       TextureState ts;\r
+       Node particleNode = new Node() {\r
+               private static final long serialVersionUID = 7477121374264124684L;\r
+\r
+               // Without this picking code tries to pick particles which doesn't work (Causes class cast exception)\r
+               public void findPick(Ray toTest, PickResults results) {\r
+                       return;\r
+               }\r
+       };\r
+    \r
+    public PipeAnimationController(JmeRenderingComponent component, PipeRun pipeline) {\r
+       as1 = component.getDisplaySystem().getRenderer().createAlphaState();\r
+        as1.setBlendEnabled(true);\r
+        as1.setSrcFunction(AlphaState.SB_SRC_ALPHA);\r
+        as1.setDstFunction(AlphaState.DB_ONE);\r
+        //as1.setDstFunction(AlphaState.DB_ONE_MINUS_SRC_ALPHA);\r
+        as1.setTestEnabled(true);\r
+        as1.setTestFunction(AlphaState.TF_GREATER);\r
+        as1.setEnabled(true);\r
+\r
+        TextureState ts = component.getDisplaySystem().getRenderer().createTextureState();\r
+        //URL url = FileLocator.find(com.jme.eclipse.Activator.getDefault().getBundle(),new Path("data/textures/flaresmall.jpg"),null);\r
+        URL url = FileLocator.find(Activator.getDefault().getBundle(),new Path("icons/bubble.png"),null);\r
+        \r
+        ts.setTexture(\r
+            TextureManager.loadTexture(url,\r
+            Texture.MM_LINEAR_LINEAR,\r
+            Texture.FM_LINEAR));\r
+        ts.setEnabled(true);\r
+        \r
+        ZBufferState zs = component.getDisplaySystem().getRenderer().createZBufferState();\r
+        zs.setFunction(ZBufferState.CF_LEQUAL);\r
+        zs.setWritable(false);\r
+        //zs.setFunction(ZBufferState.CF_ALWAYS);\r
+        particleNode.setRenderState(as1);\r
+        particleNode.setRenderState(ts);\r
+        particleNode.setRenderState(zs);\r
+        particleNode.setRenderQueueMode(Renderer.QUEUE_TRANSPARENT);\r
+        component.getShadowRoot().attachChild(particleNode);\r
+       createAnimations(pipeline);\r
+    }\r
+       \r
+    public void addAnimatable(Animatable animatable) {\r
+               animatables.add((PipeFlowAnimation)animatable);\r
+               \r
+       }\r
+       \r
+       public void setAnimatable(Animatable animatable) {\r
+               animatables.clear();\r
+               animatables.add((PipeFlowAnimation)animatable);\r
+               \r
+       }\r
+       \r
+       \r
+       public void updateAnimation(Graph g, double frameTime) {\r
+               d += delta;\r
+        if (d > 1.0) {\r
+            d = 1.0;\r
+            delta = -delta;\r
+        } else if (d < 0.0) {\r
+            delta = -delta;\r
+            d = 0.0;\r
+        }\r
+        for (Animatable a : animatables)\r
+            a.animate(d,frameTime);    \r
+       }\r
+       \r
+       public void dispose() {\r
+               for (ParticleGeometry p : pipeAnimations)\r
+                       p.removeFromParent();\r
+               pipeAnimations.clear();\r
+               \r
+       }\r
+       \r
+       private void createAnimations(PipeRun pipeline) {\r
+               List<IEntity> straights = new ArrayList<IEntity>();\r
+               for (IEntity t : pipeline.getChild()) {\r
+                       if (t.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent))\r
+                               straights.add(t);\r
+               }\r
+               \r
+               for (IEntity r : straights) {\r
+               animatables.add(new PipeFlowAnimation(pipeAnimations, particleNode, new VariableLengthInlineComponent(r),false));\r
+        }\r
+        particleNode.setModelBound(new BoundingBox());\r
+        particleNode.updateModelBound();\r
+        particleNode.updateRenderState();\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/animations/PipeFlowAnimation.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/animations/PipeFlowAnimation.java
new file mode 100644 (file)
index 0000000..d86358d
--- /dev/null
@@ -0,0 +1,144 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007 VTT Technical Research Centre of Finland and others.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package fi.vtt.simantics.processeditor.animations;\r
+\r
+import java.util.List;\r
+\r
+import javax.vecmath.Point3d;\r
+import javax.vecmath.Vector3d;\r
+\r
+import org.simantics.db.Graph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.proconf.g3d.animation.Animatable;\r
+import org.simantics.proconf.g3d.base.G3DTools;\r
+import org.simantics.proconf.g3d.base.VecmathJmeTools;\r
+\r
+import com.jme.renderer.ColorRGBA;\r
+import com.jme.scene.Node;\r
+import com.jmex.effects.particles.ParticleFactory;\r
+import com.jmex.effects.particles.ParticleGeometry;\r
+\r
+\r
+import fi.vtt.simantics.processeditor.common.ControlPointTools;\r
+import fi.vtt.simantics.processeditor.common.PipingTools2;\r
+import fi.vtt.simantics.processeditor.stubs.PipeControlPoint;\r
+import fi.vtt.simantics.processeditor.stubs.VariableLengthInlineComponent;\r
+\r
+\r
+public class PipeFlowAnimation implements Animatable{ \r
+       \r
+       ParticleGeometry particle;\r
+       float length;\r
+       int numParticles;\r
+       \r
+       public PipeFlowAnimation(List<ParticleGeometry> pipeAnimations, Node particleNode, VariableLengthInlineComponent s, boolean reversed) {\r
+       PipeControlPoint pcp = s.getControlPoint();\r
+       \r
+       Point3d p1 = new Point3d();\r
+       Point3d p2 = new Point3d();\r
+       \r
+       ControlPointTools.getInlineControlPointEnds(pcp, p2, p1);\r
+\r
+       if (reversed) {\r
+               Point3d t = p1;\r
+               p1 = p2;\r
+               p2 = t;\r
+       }\r
+       \r
+       \r
+       Vector3d dir = new Vector3d(p2);\r
+       dir.sub(p1);\r
+       length = (float)dir.length();\r
+       //if (length < 0.1f)\r
+       //      return;\r
+               //continue;\r
+       // with longer pipes particles will travel too far so the length of the pipe must be scaled\r
+       length *= 0.83f;\r
+       float vel = 0.1f;\r
+       //float size = (float)s.getPipeRadiusValue() + 0.1f;\r
+       //size *= 2.f;\r
+       float size = (float)s.getPipeDiameter()[0];\r
+       //size *= 1.2f;\r
+       float life = length/vel;\r
+       \r
+       //int releaseRate = 40;\r
+       //int numParticles = (int)(releaseRate * life / 100.f);//(int)(releaseRate * life / 500.f);\r
+       \r
+       numParticles = (int)(length * 2.0);\r
+       int releaseRate = (int)((numParticles * 500.0) / life);\r
+       \r
+       if (numParticles < 2)\r
+               numParticles = 2;\r
+       \r
+       particle = ParticleFactory.buildParticles("Animation of " + s.getResource().getResourceId(),numParticles, ParticleGeometry.PT_QUAD);//new ParticleMesh("Animation of " + r.getId(),40);\r
+       particle.setEmissionDirection(VecmathJmeTools.get(dir).normalize());\r
+       particle.setLocalTranslation(VecmathJmeTools.get(p1));\r
+       particle.setEmitType(ParticleGeometry.ET_POINT);\r
+       particle.setInitialVelocity(vel);\r
+       particle.setMinimumAngle(0.f);\r
+       particle.setMaximumAngle(0.f);\r
+       particle.setReleaseRate(releaseRate);\r
+       particle.getParticleController().setReleaseVariance(0.f);\r
+       particle.getParticleController().setControlFlow(true);\r
+       particle.setStartColor(new ColorRGBA(1.f,1.f,0.f,1.f));\r
+       particle.setEndColor(new ColorRGBA(1.f,1.f,0.f,1.f));\r
+       particle.setStartSize(size);\r
+       particle.setEndSize(size);\r
+       setFlow(vel);\r
+       particle.getParticleController().setSpeed(vel);\r
+       particle.warmUp(60);\r
+       pipeAnimations.add(particle);\r
+       particleNode.attachChild(particle);\r
+       }\r
+       \r
+       ParticleGeometry getParticleGeometry() {\r
+               return particle;\r
+       }\r
+       \r
+       private void setFlow(float vel) {\r
+               float life;\r
+               if (vel > 0.f)\r
+                       life = length/vel;\r
+               else\r
+                       life = 0.f;\r
+               particle.setInitialVelocity(vel);\r
+       particle.setMaximumLifeTime(life);\r
+       particle.setMinimumLifeTime(life);\r
+       particle.getParticleController().setSpeed(vel);\r
+\r
+       }\r
+       \r
+       private void setReleaserate(float vel) {\r
+               float life;\r
+               if (vel > 0.f)\r
+                       life = length/vel;\r
+               else\r
+                       life = 0.f;\r
+               particle.setInitialVelocity(vel);\r
+       particle.setMaximumLifeTime(life);\r
+       particle.setMinimumLifeTime(life);\r
+       particle.setReleaseRate((int)((numParticles * 500.0) / life));\r
+       }\r
+       \r
+       public void animate(double delta,double frameRate) {\r
+               //setFlow(0.1f*(float)delta);\r
+               setReleaserate(0.05f*(float)delta);\r
+       }\r
+       \r
+       public boolean setAnimation(Graph graph, Resource animation) {\r
+               return false;\r
+       }\r
+       \r
+       public boolean setRandomAnimation(Graph graph) {\r
+               return false;\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/animations/ResourcePipeAnimationController.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/animations/ResourcePipeAnimationController.java
new file mode 100644 (file)
index 0000000..4350500
--- /dev/null
@@ -0,0 +1,72 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007 VTT Technical Research Centre of Finland and others.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package fi.vtt.simantics.processeditor.animations;\r
+\r
+import org.simantics.db.Graph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.proconf.g3d.base.JmeRenderingComponent;\r
+\r
+import com.jme.renderer.ColorRGBA;\r
+\r
+import fi.vtt.simantics.processeditor.stubs.PipeRun;\r
+\r
+// TODO : this class won't work with valueSets\r
+public class ResourcePipeAnimationController extends PipeAnimationController {\r
+       Resource color;\r
+       Resource velocity;\r
+       \r
+       ColorRGBA minColor = new ColorRGBA(0.f,0.f,1.f,1.f);\r
+       ColorRGBA maxColor = new ColorRGBA(1.f,0.f,0.f,1.f);\r
+       ColorRGBA currentColor = new ColorRGBA(1.f,1.f,1.f,1.f);\r
+       \r
+       double colorMin;\r
+       double colorMax;\r
+       double iColorRange;\r
+       \r
+       double velMin;\r
+       double velMax;\r
+       double iVelRange;\r
+       public ResourcePipeAnimationController(JmeRenderingComponent component, PipeRun pipeline, Resource color,double colorMin, double colorMax, Resource velocity, double velMin, double velMax) {\r
+               super(component, pipeline);\r
+               this.color = color;\r
+               this.velocity = velocity;\r
+               \r
+               this.colorMin = colorMin;\r
+               this.colorMax = colorMax;\r
+               this.iColorRange = 1.0/(colorMax-colorMin);\r
+               this.velMin = velMin;\r
+               this.velMax = velMax;\r
+               this.iVelRange = 1.0/(velMax-velMin);\r
+       }\r
+       \r
+       private double getVelocity(Graph graph) {\r
+               return graph.getScalarDouble(velocity);\r
+               //velocity.getDoubleScalarValue();\r
+       }\r
+       \r
+       private double getColor(Graph graph) {\r
+               return graph.getScalarDouble(color);\r
+       }\r
+       public void updateAnimation(Graph g,double frameTime) {\r
+               double d = (getVelocity(g)-velMin)*iVelRange;\r
+               float f = (float)((getColor(g)-colorMin)*iColorRange);\r
+        currentColor.interpolate(minColor, maxColor, f);\r
+               for (PipeFlowAnimation a : animatables) {\r
+            a.animate(d,frameTime);    \r
+            //a.getParticleGeometry().setDefaultColor(currentColor);\r
+            a.getParticleGeometry().setStartColor(currentColor);\r
+            a.getParticleGeometry().setEndColor(currentColor);\r
+        }\r
+       }\r
+       \r
+       \r
+\r
+}\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/ControlPointTools.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/ControlPointTools.java
new file mode 100644 (file)
index 0000000..077ea70
--- /dev/null
@@ -0,0 +1,1198 @@
+package fi.vtt.simantics.processeditor.common;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.HashMap;\r
+import java.util.Stack;\r
+\r
+import javax.vecmath.AxisAngle4d;\r
+import javax.vecmath.Matrix3d;\r
+import javax.vecmath.Point3d;\r
+import javax.vecmath.Quat4d;\r
+import javax.vecmath.Tuple3d;\r
+import javax.vecmath.Vector3d;\r
+\r
+import org.simantics.db.Graph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.layer0.utils.EntityFactory;\r
+import org.simantics.layer0.utils.IEntity;\r
+import org.simantics.proconf.g3d.base.G3DTools;\r
+import org.simantics.proconf.g3d.base.MathTools;\r
+import org.simantics.proconf.g3d.base.TransformationTools;\r
+import org.simantics.utils.ErrorLogger;\r
+import org.simantics.utils.datastructures.Pair;\r
+\r
+import fi.vtt.simantics.processeditor.ProcessResource;\r
+import fi.vtt.simantics.processeditor.actions.PositionType;\r
+import fi.vtt.simantics.processeditor.common.PipingTools2.Direction;\r
+import fi.vtt.simantics.processeditor.stubs.PipeControlPoint;\r
+import fi.vtt.simantics.processeditor.stubs.PipeRun;\r
+\r
+public class ControlPointTools {\r
+       \r
+       private static boolean DEBUG = false;\r
+       \r
+       private static TransformationTools tt;\r
+       \r
+       public static void initialize() {\r
+               tt = new TransformationTools(ProcessResource.plant3Dresource.HasSubPoint,ProcessResource.plant3Dresource.SubPointOf) {\r
+                       @Override\r
+                       public IEntity getParent(IEntity node) {\r
+                               IEntity parent =  super.getParent(node);\r
+                               if (parent == null) {\r
+                                       parent = node.getAtMostOneRelatedObject(ProcessResource.plant3Dresource.ControlPointOf);\r
+                                       if (parent != null)\r
+                                               parent = parent.getAtMostOneRelatedObject(ProcessResource.g3dResource.HasParent);\r
+                                       else\r
+                                               parent = node.getAtMostOneRelatedObject(ProcessResource.g3dResource.HasParent);\r
+                                               \r
+                               }\r
+                               return parent;\r
+                       }\r
+               };\r
+       }\r
+       \r
+       public static void deinitialize() {\r
+               tt = null;\r
+       }\r
+       \r
+       /**\r
+        * Adds new control point between given control points.\r
+        * New pcp must be already part of the same piperun as previous CP and nextCP\r
+        * \r
+        * SizeChangeControlPoints cannot be inserted with this method, since it does link two different piperuns to each other\r
+        * \r
+        * @param newCP\r
+        * @param previousCP\r
+        * @param nextCP\r
+        */\r
+       public static void insertControlPoint(IEntity newCP, IEntity previousCP, IEntity nextCP) {\r
+               // inserting an offsetpoint is error, \r
+               assert(!newCP.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint));\r
+               // size change control point cannot be inserted this way, because it ends PipeRun\r
+               assert(!newCP.isInstanceOf(ProcessResource.plant3Dresource.SizeChangeControlPoint));\r
+               \r
+               IEntity piperun = previousCP.getSingleRelatedObject(ProcessResource.plant3Dresource.ControlPointOfPipeRun);\r
+               // and just to make sure that control point structure is not corrupted\r
+               assert(piperun.equals(nextCP.getSingleRelatedObject(ProcessResource.plant3Dresource.ControlPointOfPipeRun)));\r
+               assert(piperun.equals(newCP.getSingleRelatedObject(ProcessResource.plant3Dresource.ControlPointOfPipeRun)));\r
+               \r
+               // insert new BranchControlPoint between straight's control points\r
+       IEntity previousNext = previousCP.getAtMostOneRelatedObject(ProcessResource.plant3Dresource.HasNext);\r
+       IEntity previousPrevious = previousCP.getAtMostOneRelatedObject(ProcessResource.plant3Dresource.HasPrevious);\r
+       \r
+       IEntity offsetCP = null;\r
+       \r
+       if (newCP.isInstanceOf(ProcessResource.plant3Dresource.OffsettingPoint)) {\r
+               offsetCP = newCP.getSingleRelatedObject(ProcessResource.plant3Dresource.HasSubPoint);\r
+       }\r
+       \r
+               if (previousNext != null && previousNext.equals(nextCP)) {\r
+                       assert(!previousCP.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint));\r
+                       assert(!nextCP.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint));\r
+                       \r
+                       setStatement(previousCP, ProcessResource.plant3Dresource.HasNext, newCP);\r
+            setStatement(newCP, ProcessResource.plant3Dresource.HasPrevious, previousCP);\r
+            \r
+            if (previousCP.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)) {                \r
+               IEntity sccp = previousCP.getSingleRelatedObject(ProcessResource.plant3Dresource.SubPointOf);\r
+               setStatement(sccp, ProcessResource.plant3Dresource.HasNext, newCP);\r
+            }\r
+            \r
+            setStatement(newCP, ProcessResource.plant3Dresource.HasNext, nextCP);\r
+            \r
+            if (offsetCP == null) {\r
+               setStatement(nextCP, ProcessResource.plant3Dresource.HasPrevious, newCP);\r
+            } else {\r
+               setStatement(nextCP, ProcessResource.plant3Dresource.HasPrevious, offsetCP);\r
+               setStatement(offsetCP, ProcessResource.plant3Dresource.HasNext, nextCP);\r
+               setStatement(offsetCP, ProcessResource.plant3Dresource.HasPrevious, previousCP);\r
+            }\r
+            \r
+            if (nextCP.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)) {\r
+               IEntity ocp = nextCP.getSingleRelatedObject(ProcessResource.plant3Dresource.HasSubPoint);\r
+               setStatement(ocp, ProcessResource.plant3Dresource.HasPrevious, newCP);\r
+            }\r
+            \r
+         } else if (previousPrevious != null && previousPrevious.equals(nextCP)) {\r
+                // control point were given in reverse order \r
+                assert(!nextCP.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint));\r
+                        assert(!previousCP.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint));\r
+                        \r
+                        setStatement(newCP, ProcessResource.plant3Dresource.HasNext, previousCP);\r
+                        if (offsetCP == null) {\r
+               setStatement(previousCP, ProcessResource.plant3Dresource.HasPrevious, newCP);\r
+             } else {\r
+               setStatement(previousCP, ProcessResource.plant3Dresource.HasPrevious, offsetCP);\r
+               setStatement(offsetCP, ProcessResource.plant3Dresource.HasNext, previousCP);\r
+               setStatement(offsetCP, ProcessResource.plant3Dresource.HasPrevious, nextCP);\r
+             }\r
+                        \r
+                if (previousCP.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)) {\r
+                        IEntity ocp = previousCP.getSingleRelatedObject(ProcessResource.plant3Dresource.HasSubPoint);\r
+                        setStatement(ocp, ProcessResource.plant3Dresource.HasPrevious, newCP);\r
+             }\r
+                \r
+                setStatement(newCP, ProcessResource.plant3Dresource.HasPrevious, nextCP);\r
+                setStatement(nextCP, ProcessResource.plant3Dresource.HasNext, newCP);\r
+             if (nextCP.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)) {\r
+                IEntity sccp = nextCP.getSingleRelatedObject(ProcessResource.plant3Dresource.SubPointOf);\r
+                setStatement(sccp, ProcessResource.plant3Dresource.HasNext, newCP);\r
+             }\r
+        } else {\r
+            ErrorLogger.defaultLogError(\r
+                    "Route pipe : could not find connection between straight pipe's control points", null);\r
+        }\r
+\r
+       }\r
+       \r
+       /**\r
+        * Adds new control point attaching it to given control point.\r
+        * If the new control point is SizeChangeControlPoint, it must have its offset point set.\r
+        * \r
+        * @param newCP\r
+        * @param pcp\r
+        * @param direction\r
+        */\r
+       public static void insertControlPoint(IEntity newCP, IEntity pcp, Direction direction) {\r
+               assert(!newCP.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint));\r
+               if (direction == Direction.NEXT) {\r
+                       // if direction is next, user must have given OffsetPoint\r
+                       assert(!pcp.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint));\r
+                       // basic next/prev links\r
+                       pcp.removeRelatedStatements(ProcessResource.plant3Dresource.HasNext);\r
+                       pcp.addStatement(ProcessResource.plant3Dresource.HasNext, newCP);\r
+                       newCP.removeRelatedStatements(ProcessResource.plant3Dresource.HasPrevious);\r
+                       newCP.addStatement(ProcessResource.plant3Dresource.HasPrevious, pcp);\r
+                       // and last take care of sizechange / offset points\r
+                       if (pcp.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)) {\r
+                               IEntity sccp = pcp.getSingleRelatedObject(ProcessResource.plant3Dresource.SubPointOf);\r
+                               sccp.removeRelatedStatements(ProcessResource.plant3Dresource.HasNext);\r
+                               sccp.addStatement(ProcessResource.plant3Dresource.HasNext, newCP);\r
+                       }\r
+                       if (newCP.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)) {\r
+                               IEntity ocp = newCP.getSingleRelatedObject(ProcessResource.plant3Dresource.HasSubPoint);\r
+                               ocp.removeRelatedStatements(ProcessResource.plant3Dresource.HasPrevious);\r
+                               ocp.addStatement(ProcessResource.plant3Dresource.HasPrevious, pcp);\r
+                       }\r
+               } else {\r
+                       // if direction is previous, user must have given sizechange\r
+                       assert(!pcp.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint));\r
+                       // previous direction is more complicated, since if newCP is SizeChangeControlPoint,\r
+                       // we must link pcp to newCP's OffsetPoint\r
+                       IEntity nocp = null;\r
+                       if (newCP.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)) {\r
+                               nocp = newCP.getSingleRelatedObject(ProcessResource.plant3Dresource.HasSubPoint);\r
+                               nocp.removeRelatedStatements(ProcessResource.plant3Dresource.HasNext);\r
+                               nocp.addStatement(ProcessResource.plant3Dresource.HasNext, pcp);\r
+                       }\r
+                       pcp.removeRelatedStatements(ProcessResource.plant3Dresource.HasPrevious);\r
+                       if (nocp == null)\r
+                               pcp.addStatement(ProcessResource.plant3Dresource.HasPrevious, newCP);\r
+                       else\r
+                               pcp.addStatement(ProcessResource.plant3Dresource.HasPrevious, nocp);\r
+                       \r
+                       newCP.removeRelatedStatements(ProcessResource.plant3Dresource.HasNext);\r
+                       newCP.addStatement(ProcessResource.plant3Dresource.HasNext, pcp);\r
+                       if (pcp.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)) {\r
+                               IEntity ocp = pcp.getSingleRelatedObject(ProcessResource.plant3Dresource.HasSubPoint);\r
+                               ocp.removeRelatedStatements(ProcessResource.plant3Dresource.HasPrevious);\r
+                               if (nocp == null)\r
+                                       ocp.addStatement(ProcessResource.plant3Dresource.HasPrevious, newCP);\r
+                               else\r
+                                       ocp.addStatement(ProcessResource.plant3Dresource.HasPrevious, nocp);\r
+                       }\r
+                       \r
+               }\r
+       }\r
+       \r
+       /**\r
+        * Returns path legs direction\r
+        * @param pcp\r
+        * @param direction\r
+        * @return\r
+        */\r
+       public static Vector3d getPathLegDirection(IEntity pcp,Direction direction) {\r
+               IEntity previous = pcp.getAtMostOneRelatedObject(ProcessResource.plant3Dresource.HasPrevious);\r
+               IEntity next = pcp.getAtMostOneRelatedObject(ProcessResource.plant3Dresource.HasNext);\r
+               if (direction == Direction.NEXT) {\r
+                       if (next != null) {\r
+                               if (pcp.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint))\r
+                                       pcp = pcp.getSingleRelatedObject(ProcessResource.plant3Dresource.HasSubPoint);\r
+                               Point3d p1 = G3DTools.getPoint(pcp.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition));\r
+                               Point3d p2 = G3DTools.getPoint(next.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition));\r
+                               Vector3d v = new Vector3d();\r
+                               v.sub(p2, p1);\r
+                               return v;\r
+                       } else {\r
+                               if (pcp.isInstanceOf(ProcessResource.plant3Dresource.VariableAngleTurnControlPoint))\r
+                                       throw new RuntimeException("Cannot calculate path leg direction for unconnected variable angle control point " + pcp.getResource());\r
+                               if (previous == null) {\r
+                                       if (!pcp.isInstanceOf(ProcessResource.plant3Dresource.DirectedControlPoint))\r
+                                               throw new RuntimeException("Cannot calculate path leg direction for unconnected control point " + pcp.getResource());\r
+                                       else\r
+                                               return getDirectedControlPointDirection(pcp);\r
+                               } else {\r
+                                       if (pcp.isInstanceOf(ProcessResource.plant3Dresource.InlineControlPoint)) {\r
+                                               Point3d p1 = G3DTools.getPoint(previous.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition));\r
+                                               Point3d p2 = G3DTools.getPoint(pcp.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition));\r
+                                               Vector3d v = new Vector3d();\r
+                                               v.sub(p2, p1);\r
+                                               return v;\r
+                                       }\r
+                                       throw new RuntimeException("Missing implementation");\r
+                               }\r
+                       }\r
+               } else {\r
+                       if (previous != null) {\r
+                               if (pcp.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint))\r
+                                       pcp = pcp.getSingleRelatedObject(ProcessResource.plant3Dresource.SubPointOf);\r
+                               Point3d p1 = G3DTools.getPoint(pcp.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition));\r
+                               Point3d p2 = G3DTools.getPoint(previous.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition));\r
+                               Vector3d v = new Vector3d();\r
+                               v.sub(p2, p1);\r
+                               return v;\r
+                       } else {\r
+                               if (pcp.isInstanceOf(ProcessResource.plant3Dresource.VariableAngleTurnControlPoint))\r
+                                       throw new RuntimeException("Cannot calculate path leg direction for unconnected variable angle control point " + pcp.getResource());\r
+                               if (next == null) {\r
+                                       if (!pcp.isInstanceOf(ProcessResource.plant3Dresource.DirectedControlPoint))\r
+                                               throw new RuntimeException("Cannot calculate path leg direction for unconnected control point " + pcp.getResource());\r
+                                       else {\r
+                                               Vector3d v = getDirectedControlPointDirection(pcp);\r
+                                               v.negate();\r
+                                               return v;\r
+                                       }\r
+                               } else {\r
+                                       if (pcp.isInstanceOf(ProcessResource.plant3Dresource.InlineControlPoint)) {\r
+                                               Point3d p1 = G3DTools.getPoint(next.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition));\r
+                                               Point3d p2 = G3DTools.getPoint(pcp.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition));\r
+                                               Vector3d v = new Vector3d();\r
+                                               v.sub(p2, p1);\r
+                                               return v;\r
+                                       }\r
+                                       throw new RuntimeException("Missing implementation");\r
+                               }\r
+                       }\r
+               }\r
+               \r
+       }\r
+       \r
+       /**\r
+        * Return positions (world) of an InlineComponents ends\r
+        * @param pcp\r
+        * @param p1\r
+        * @param p2\r
+        */\r
+       public static void getInlineControlPointEnds(IEntity pcp, Point3d p1, Point3d p2) {\r
+               assert (pcp.isInstanceOf(ProcessResource.plant3Dresource.InlineControlPoint));\r
+               \r
+               Point3d pos = G3DTools.getPoint(pcp.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition));\r
+               Vector3d dir = ControlPointTools.getPathLegDirection(pcp, Direction.NEXT);\r
+               dir.normalize();\r
+               double length = pcp.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength);\r
+               dir.scale(length * 0.5);\r
+               p1.set(pos);\r
+               p2.set(pos);\r
+               p1.add(dir);\r
+               p2.sub(dir);\r
+       }\r
+       \r
+       /**\r
+        * Return positions (world) of an InlineComponents ends\r
+        * @param pcp\r
+        * @param p1\r
+        * @param p2\r
+        */\r
+       public static void getInlineControlPointEnds(IEntity pcp, Point3d p1, Point3d p2, Vector3d dir) {\r
+               assert (pcp.isInstanceOf(ProcessResource.plant3Dresource.InlineControlPoint));\r
+               \r
+               Point3d pos = G3DTools.getPoint(pcp.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition));\r
+               dir.set(ControlPointTools.getPathLegDirection(pcp, Direction.NEXT));\r
+               double length = pcp.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength);\r
+               Vector3d d = new Vector3d(dir);\r
+               d.scale(length * 0.5);\r
+               p1.set(pos);\r
+               p2.set(pos);\r
+               p1.add(d);\r
+               p2.sub(d);\r
+       }\r
+       \r
+       /**\r
+        * Return positions (world) of an InlineComponents ends\r
+        * @param pcp\r
+        * @param p1\r
+        * @param p2\r
+        */\r
+       public static void getInlineControlPointEnds(IEntity pcp, Point3d center, Point3d p1, Point3d p2, Vector3d dir) {\r
+               assert (pcp.isInstanceOf(ProcessResource.plant3Dresource.InlineControlPoint));\r
+               \r
+               Point3d pos = G3DTools.getPoint(pcp.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition));\r
+               center.set(pos);\r
+               dir.set(ControlPointTools.getPathLegDirection(pcp, Direction.NEXT));\r
+               double length = pcp.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength);\r
+               Vector3d d = new Vector3d(dir);\r
+               d.scale(length * 0.5);\r
+               p1.set(pos);\r
+               p2.set(pos);\r
+               p1.add(d);\r
+               p2.sub(d);\r
+       }\r
+       \r
+       public static double getInlineLength(IEntity pcp) {\r
+       double l2 = 0.0;\r
+       if (pcp.isInstanceOf(ProcessResource.plant3Dresource.TurnControlPoint)) {\r
+               l2 += pcp.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength);\r
+       } else if (pcp.isInstanceOf(ProcessResource.plant3Dresource.InlineControlPoint)) {\r
+               l2 += pcp.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength) * 0.5;\r
+       }\r
+       return l2;\r
+    }\r
+       \r
+       /**\r
+        * Returns position (world) of a single port\r
+        * @param pcp\r
+        * @param type\r
+        * @return\r
+        */\r
+       public static Point3d getRealPosition(IEntity pcp, PositionType type) {\r
+               PipeControlPoint p= new PipeControlPoint(pcp);\r
+               Point3d pos = G3DTools.getPoint(p.getWorldPosition());\r
+               switch (type) {\r
+               case NEXT: {\r
+                       Vector3d dir = ControlPointTools.getPathLegDirection(pcp,Direction.NEXT);\r
+                       double length = getInlineLength(pcp);\r
+                       dir.normalize();\r
+                       dir.scale(length);\r
+                       pos.add(dir);\r
+                       break;\r
+               }\r
+               case PREVIOUS: {\r
+                       Vector3d dir = ControlPointTools.getPathLegDirection(pcp,Direction.PREVIOUS);\r
+                       double length = getInlineLength(pcp);\r
+                       dir.normalize();\r
+                       dir.scale(length);\r
+                       pos.add(dir);\r
+                       break;\r
+               }\r
+               case PORT:\r
+                       // IEntity portDir = pcp.getSingleRelatedObject(ProcessResource.plant3Dresource.HasDirection);\r
+                       // TODO : how we calculated needed space for a port; does it has an offset from control point's position or not?\r
+                       break;\r
+               case SPLIT:\r
+                       // do nothing\r
+                       break;\r
+                       \r
+               }\r
+               return pos;\r
+       }\r
+       \r
+       public static void getInlineMovement(PipeControlPoint pcp, Point3d start, Point3d end) {\r
+               // FIXME : check type of neighbor components and allow movement on top of variable length components,\r
+               //         ffind proper range for movement (pcp's position is not)\r
+               PipeControlPoint prev = pcp.getPrevious().getPrevious();\r
+               PipeControlPoint next = pcp.getNext().getNext();\r
+               start.set(G3DTools.getPoint(prev.getWorldPosition()));\r
+               end.set(G3DTools.getPoint(next.getWorldPosition()));\r
+       }\r
+       \r
+       public static AxisAngle4d getControlPointLocalRotation(IEntity pcp, double angle) {\r
+               Quat4d q1 = getControlPointLocalOrientationQuat(pcp, angle);\r
+        AxisAngle4d aa= new AxisAngle4d();\r
+               aa.set(q1);\r
+               return aa;\r
+       }\r
+       \r
+       public static AxisAngle4d getControlPointWorldRotation(IEntity pcp, double angle) {\r
+               Quat4d q1 = getControlPointWorldOrientationQuat(pcp, angle);\r
+        AxisAngle4d aa= new AxisAngle4d();\r
+               aa.set(q1);\r
+               return aa;\r
+       }\r
+       \r
+\r
+    public static Quat4d getControlPointLocalOrientationQuat(IEntity pcp, double angle) {\r
+       return getControlPointLocalOrientationQuat(pcp, angle, false);\r
+    }\r
+    \r
+    public static Quat4d getControlPointWorldOrientationQuat(IEntity pcp, double angle) {\r
+       return getControlPointWorldOrientationQuat(pcp, angle, false);\r
+    }\r
+    \r
+    public static Quat4d getControlPointLocalOrientationQuat(IEntity cp, double angle, boolean offset) {\r
+       PipeControlPoint pcp = new PipeControlPoint(cp);\r
+       PipeControlPoint next;\r
+       // if pcp is size change control point with offset, next control point is not in line with previous and pcp control point (it's offsetted)\r
+       // else it's more numerically stable to use next control point\r
+       if (offset)\r
+               next = pcp;\r
+       else\r
+               next = pcp.getNext();\r
+       \r
+       PipeControlPoint prev = pcp.getPrevious();\r
+        assert (next != null || prev != null);\r
+        if (prev == null)\r
+               prev = pcp;\r
+        else if (next == null)\r
+               next = pcp;\r
+        // TODO : check correct type\r
+        if (pcp.isInstanceOf(ProcessResource.plant3Dresource.PathLegEndControlPoint) && pcp.getPrevious() == null) {\r
+               PipeControlPoint temp = next;\r
+               next = prev;\r
+               prev = temp;\r
+        }\r
+        Vector3d current = new Vector3d(G3DTools.getPoint(next.getLocalPosition()));\r
+        current.sub(G3DTools.getPoint(prev.getLocalPosition()));\r
+        current.normalize();\r
+        return getControlPointOrientationQuat(current, angle);\r
+    }\r
+    \r
+    public static Quat4d getControlPointWorldOrientationQuat(IEntity cp, double angle, boolean offset) {\r
+       PipeControlPoint pcp = new PipeControlPoint(cp);\r
+       PipeControlPoint next;\r
+       // if pcp is size change control point with offset, next control point is not in line with previous and pcp control point (it's offsetted)\r
+       // else it's more numerically stable to use next control point\r
+       if (offset)\r
+               next = pcp;\r
+       else\r
+               next = pcp.getNext();\r
+       \r
+       PipeControlPoint prev = pcp.getPrevious();\r
+        assert (next != null || prev != null);\r
+        if (prev == null)\r
+               prev = pcp;\r
+        else if (next == null)\r
+               next = pcp;\r
+        // TODO : check correct type\r
+        if (pcp.isInstanceOf(ProcessResource.plant3Dresource.PathLegEndControlPoint) && pcp.getPrevious() == null) {\r
+               PipeControlPoint temp = next;\r
+               next = prev;\r
+               prev = temp;\r
+        }\r
+        Vector3d current = new Vector3d(G3DTools.getPoint(next.getWorldPosition()));\r
+        current.sub(G3DTools.getPoint(prev.getWorldPosition()));\r
+        current.normalize();\r
+        return getControlPointOrientationQuat(current, angle);\r
+    }\r
+    \r
+    public static Quat4d getControlPointOrientationQuat(Vector3d dir, double angle) {\r
+\r
+        \r
+        final Vector3d front = new Vector3d(1.0,0.0,0.0);\r
+        \r
+        Quat4d q1 = new Quat4d();\r
+\r
+               Vector3d up = new Vector3d(0.0, 1.0, 0.0);\r
+               double a = up.angle(dir);\r
+               if (a < 0.1 || (Math.PI - a) < 0.1) {\r
+                       up.set(1.0, 0.0, 0.0);\r
+               }\r
+\r
+               Vector3d right = new Vector3d();\r
+\r
+               right.cross(dir, up);\r
+               up.cross(right, dir);\r
+               right.normalize();\r
+               up.normalize();\r
+\r
+               Matrix3d m = new Matrix3d();\r
+               m.m00 = dir.x;\r
+               m.m10 = dir.y;\r
+               m.m20 = dir.z;\r
+               m.m01 = up.x;\r
+               m.m11 = up.y;\r
+               m.m21 = up.z;\r
+               m.m02 = right.x;\r
+               m.m12 = right.y;\r
+               m.m22 = right.z;\r
+\r
+               //q1.set(m); MathTools contains more stable conversion\r
+               MathTools.getQuat(m, q1);\r
+\r
+               if (DEBUG) System.out.println("PipingTools.getPipeComponentOrientationQuat() " + dir+ " " + up + " " + right);\r
+\r
+               Quat4d q2 = new Quat4d();\r
+               q2.set(new AxisAngle4d(front, angle));\r
+               q1.mul(q2);\r
+               return q1;\r
+    }\r
+    \r
+    public static PipeControlPoint findPreviousEnd(PipeControlPoint tcp) {\r
+       // TODO : optimize (we do not need the list here)\r
+       ArrayList<PipeControlPoint> t = new ArrayList<PipeControlPoint>();\r
+        return findPreviousEnd(tcp, t);\r
+    }\r
+    \r
+    public static PipeControlPoint findNextEnd(PipeControlPoint tcp) {\r
+        // TODO : optimize (we do not need the list here)\r
+       ArrayList<PipeControlPoint> t = new ArrayList<PipeControlPoint>();\r
+        return findNextEnd(tcp, t);\r
+    }\r
+    \r
+    /**\r
+     * Returns pipe leg's end using "nextControlPoint" relation and collects control point in the given list. \r
+     * @param tcp\r
+     * @param nextList\r
+     * @return\r
+     */\r
+    public static PipeControlPoint findNextEnd(PipeControlPoint tcp, ArrayList<PipeControlPoint> nextList) {\r
+       if (DEBUG) System.out.print("PipingTools.findNextEnd " + tcp.getResource());\r
+        while (true) {\r
+            PipeControlPoint pcp = null;\r
+            PipeControlPoint p = null;\r
+            if (nextList.size() == 0)\r
+                p = tcp;\r
+                \r
+            else\r
+                p = nextList.get(nextList.size() - 1);\r
+\r
+            pcp = p.getNext();\r
+            if (pcp == null) {\r
+               pcp = p;\r
+               if (nextList.size() > 0)\r
+                       nextList.remove(nextList.size() - 1);\r
+               if (DEBUG) System.out.println(" " + pcp.getResource() + " not full");\r
+               return pcp;\r
+               //break;\r
+            }\r
+            if (pcp.isInstanceOf(ProcessResource.plant3Dresource.PathLegEndControlPoint)) {\r
+               if (DEBUG) System.out.println(" " + pcp.getResource());\r
+                return pcp;\r
+            } else {\r
+                nextList.add(pcp);\r
+                if (DEBUG) System.out.print(" " + pcp.getResource());\r
+            }\r
+        }\r
+    }\r
+    \r
+   \r
+    \r
+    /**\r
+     * Returns pipe leg's end using "previousControlPoint" relation and collects control point in the given list.\r
+     * @param tcp\r
+     * @param prevList\r
+     * @return\r
+     */\r
+    public static PipeControlPoint findPreviousEnd(PipeControlPoint tcp, ArrayList<PipeControlPoint> prevList) {\r
+       if (DEBUG) System.out.print("PipingTools.findPreviousEnd " + tcp.getResource());\r
+        while (true) {\r
+            PipeControlPoint pcp = null;\r
+            PipeControlPoint p = null;\r
+            if (prevList.size() == 0)\r
+                p = tcp;\r
+                \r
+            else\r
+                p = prevList.get(prevList.size() - 1);\r
+\r
+            pcp = p.getPrevious();\r
+            if (pcp == null) {\r
+               pcp = p;\r
+               if (prevList.size() > 0)\r
+                       prevList.remove(prevList.size() - 1);\r
+               if (DEBUG) System.out.println(" " + pcp.getResource() + " not full");\r
+               return pcp;\r
+            }\r
+            if (pcp.isInstanceOf(ProcessResource.plant3Dresource.PathLegEndControlPoint)) {\r
+               if (DEBUG) System.out.println(" " + pcp.getResource());\r
+                return pcp;\r
+            } else {\r
+               prevList.add(pcp);\r
+                if (DEBUG) System.out.print(" " + pcp.getResource());\r
+            }\r
+        }\r
+    }\r
+    \r
+    public static PipeRun getPipeRun(PipeControlPoint pcp) {\r
+       return pcp.getControlPointOfPipeRun();\r
+    }\r
+    \r
+    @Deprecated\r
+    public static Vector3d getSizeChangeOffsetVector(PipeControlPoint sccp) {\r
+       Quat4d q = getControlPointWorldOrientationQuat(sccp, sccp.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasRotationAngle),true);\r
+       return getSizeChangeOffsetVector(sccp,q);\r
+    }\r
+    \r
+    public static Vector3d getSizeChangeOffsetVector(PipeControlPoint sccp, Vector3d dir) {\r
+       Quat4d q = getControlPointOrientationQuat(dir, sccp.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasRotationAngle));\r
+       return getSizeChangeOffsetVector(sccp,q);\r
+    }\r
+    \r
+    public static Vector3d getSizeChangeOffsetVector(PipeControlPoint sccp, Quat4d q) {\r
+       Vector3d v = new Vector3d(0.0,0.0,sccp.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasOffset));\r
+       Vector3d offset = new Vector3d();\r
+       MathTools.rotate(q, v, offset);\r
+       return offset;\r
+    }\r
+    \r
+    public static Vector3d getDirectedControlPointDirection(IEntity dcp) {\r
+       assert(dcp.isInstanceOf(ProcessResource.plant3Dresource.DirectedControlPoint));\r
+       AxisAngle4d worldR = G3DTools.getOrientation(dcp.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldOrientation));\r
+       Quat4d q = new Quat4d();\r
+               q.set(worldR);\r
+               Vector3d dir = new Vector3d();\r
+               MathTools.rotate(q, new Vector3d(1.0, 0.0, 0.0), dir);\r
+               dir.normalize();\r
+               return dir;\r
+    }\r
+    \r
+    public static Vector3d getNozzleDirection(IEntity rotation) {\r
+       AxisAngle4d worldR = G3DTools.getOrientation(rotation);\r
+        Quat4d q = new Quat4d();\r
+               q.set(worldR);\r
+               Vector3d dir = new Vector3d();\r
+               MathTools.rotate(q, new Vector3d(1.0, 0.0, 0.0), dir);\r
+               return dir;\r
+    }\r
+    \r
+    public static Vector3d getNozzleDirection(PipeControlPoint dcp) {\r
+       return getNozzleDirection(dcp.getWorldOrientation());\r
+    }\r
+\r
+    public static void removeControlPoint(PipeControlPoint removed) {\r
+       if (DEBUG) System.out.println("PipingTools.removeControlPoint() controlpoint " + removed.getResource());//FIXME : offset + size change control points !\r
+       \r
+       // this code is not valid anymore.\r
+       \r
+       // different removing cases:\r
+       //\r
+       // 1. Point is SizeChangeControlPoint  (this is currently ok)\r
+       //    * remove offset point and component \r
+       //    * do NOT link components together\r
+       //\r
+       // 2. Point is VariableLength\r
+       //    * check if its a branch (TODO : ontology support?)\r
+       //      * if so, also branch point in the other piperun may have to be removed\r
+       //        (we cannot move other components next to branch)\r
+       //      * if not, components next to removed one are moved next to each other\r
+       // 3. Other\r
+       //    * check if there is VariableLength on both sides,\r
+       //              * if so, those must be unified to a single Variable Length component.\r
+       //      * if not, components must be moved next to each other\r
+       //\r
+       // a) If removed Control Point is next to Nozzle and after the point is removed nozzle is not connected to anything\r
+       //    * nozzle's link to piperun's specs must be removed\r
+       //    \r
+       \r
+       \r
+       if (removed.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)||\r
+               removed.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)) {\r
+               // sccp & ocp connect two pipeRuns to each other; when thoes are remove, pipeRuns are not connected to each other anymore.\r
+               removeDualPoint(removed);\r
+               return;\r
+       } else {\r
+               PipeControlPoint prev = removed.getPrevious();\r
+            PipeControlPoint next = removed.getNext();\r
+               PipeRun pipeRun = getPipeRun(removed);\r
+               if (pipeRun == null)\r
+                       return;\r
+               if (next == null && prev == null) {\r
+                               if (removed.isInstanceOf(ProcessResource.plant3Dresource.NozzleControlPoint)) {\r
+                                       // Nozzle's control point does not need to be removed, only unlinked\r
+                                       // TODO : what about component ports?\r
+                                       PipingTools2.unlinkNozzleAndPiperun(removed.getSingleRelatedObject(ProcessResource.plant3Dresource.ControlPointOf), ControlPointTools.getPipeRun(removed));\r
+                                       return;\r
+                               }\r
+                       } else {\r
+\r
+                               if (next != null && prev != null) {\r
+                                       boolean link = true;\r
+                                       if (next.isInstanceOf(ProcessResource.plant3Dresource.BranchEndControlPoint)){\r
+                                               link = false;\r
+                                               next.removeRelatedStatements(ProcessResource.plant3Dresource.HasPrevious);\r
+                                               removed.removeRelatedStatements(ProcessResource.plant3Dresource.HasNext);\r
+                                               removeControlPoint(next);\r
+                                       }\r
+                                       if (prev.isInstanceOf(ProcessResource.plant3Dresource.BranchEndControlPoint)) {\r
+                                               link = false;\r
+                                               prev.removeRelatedStatements(ProcessResource.plant3Dresource.HasNext);\r
+                                               removed.removeRelatedStatements(ProcessResource.plant3Dresource.HasPrevious);\r
+                                               removeControlPoint(prev);\r
+                                       }\r
+                                       if (link && prev.isInstanceOf(ProcessResource.plant3Dresource.DirectedControlPoint)&&\r
+                                                               next.isInstanceOf(ProcessResource.plant3Dresource.DirectedControlPoint)) {\r
+                                               link = false;\r
+                                       }\r
+                                       if (next.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)) {\r
+                                               PipeControlPoint sccp = next;\r
+                                               PipeControlPoint ocp = sccp.getSubPoint().iterator().next();\r
+                                               if (ocp == null) {\r
+                                                       ErrorLogger.defaultLogError("Removing PipeControlPoint " + removed.getResource()+ " structure damaged, no offset control point",null);\r
+                                                       return;\r
+                                               }\r
+                                               if (link) {\r
+                                                       sccp.setPrevious(prev);\r
+                                                       ocp.setPrevious(prev);\r
+                                               } else {\r
+                                                       sccp.removeRelatedStatements(ProcessResource.plant3Dresource.HasPrevious);\r
+                                                       ocp.removeRelatedStatements(ProcessResource.plant3Dresource.HasPrevious);\r
+                                                       \r
+                                               }\r
+                                               removed.removeRelatedStatements(ProcessResource.plant3Dresource.HasNext);\r
+                                       } else if (next.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)) {\r
+                                               ErrorLogger.defaultLogError("Removing PipeControlPoint " + removed.getResource()+ " structure damaged, next control point is offset control point",null);\r
+                                               return;\r
+                                       } else if (next.getPrevious().getResource().equals(removed.getResource())) {\r
+                                               if (link) {\r
+                                                       next.setPrevious(prev);\r
+                                               } else {\r
+                                                       next.removeRelatedStatements(ProcessResource.plant3Dresource.HasPrevious);\r
+                                               }\r
+                                               removed.removeRelatedStatements(ProcessResource.plant3Dresource.HasNext);\r
+                                       } else {\r
+                                               ErrorLogger.defaultLogError("Removing PipeControlPoint "+ removed.getResource()+ " structure damaged", null);\r
+                                               return;\r
+                                       }\r
+                                       if (prev.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)) {\r
+                                               ErrorLogger.defaultLogError("Removing PipeControlPoint " + removed.getResource() + " structure damaged, previous control point is size change control point", null);\r
+                                               return;\r
+                                       } else if (prev.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)) {\r
+                                               PipeControlPoint ocp = prev;\r
+                                               PipeControlPoint sccp = ocp.getSubPointOf();\r
+                                               if (sccp == null) {\r
+                                                       ErrorLogger.defaultLogError("Removing PipeControlPoint " + removed.getResource() + " structure damaged, no size change control point",null);\r
+                                                       return;\r
+                                               }\r
+                                               if (link) {\r
+                                                       ocp.setNext(next);\r
+                                                       sccp.setNext(next);\r
+                                               } else {\r
+                                                       ocp.removeRelatedStatements(ProcessResource.plant3Dresource.HasNext);\r
+                                                       sccp.removeRelatedStatements(ProcessResource.plant3Dresource.HasNext);\r
+                                               }\r
+                                               removed.removeRelatedStatements(ProcessResource.plant3Dresource.HasPrevious);\r
+                                       } else if (prev.getNext().getResource().equals(removed.getResource())) {\r
+                                               if (link)\r
+                                                       prev.setNext(next);\r
+                                               else\r
+                                                       prev.removeRelatedStatements(ProcessResource.plant3Dresource.HasNext);\r
+                                               removed.removeRelatedStatements(ProcessResource.plant3Dresource.HasPrevious);\r
+                                       } else {\r
+                                               ErrorLogger.defaultLogError("Removing PipeControlPoint " + removed.getResource() + " structure damaged", null);\r
+                                               return;\r
+                                       }\r
+                                       if (link) {\r
+                                               if (next.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthControlPoint) &&\r
+                                                       prev.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthControlPoint)) {\r
+                                                       // we have to join them into single variable length component.\r
+                                                       removeControlPoint(prev);\r
+                                               }\r
+                                       }\r
+\r
+                                       \r
+                               } else if (next != null) {\r
+                                       if (next.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)) {\r
+                                               PipeControlPoint sccp = next;\r
+                                               PipeControlPoint ocp = sccp.getSubPoint().iterator().next();\r
+                                               if (ocp == null) {\r
+                                                       ErrorLogger.defaultLogError("Removing PipeControlPoint "+ removed.getResource()+ " structure damaged, no offset control point",null);\r
+                                                       return;\r
+                                               }\r
+                                               next.removeRelatedStatements(ProcessResource.plant3Dresource.HasPrevious);\r
+                                               ocp.removeRelatedStatements(ProcessResource.plant3Dresource.HasPrevious);\r
+                                       } else if (next.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)) {\r
+                                               ErrorLogger.defaultLogError("Removing PipeControlPoint " + removed.getResource() + " structure damaged, next control point is offset control point", null);\r
+                                               return;\r
+                                       } else if (next.getPrevious().getResource().equals(removed.getResource())) {\r
+                                               next.removeRelatedStatements(ProcessResource.plant3Dresource.HasPrevious);\r
+                                       } else {\r
+                                               ErrorLogger.defaultLogError("Removing PipeControlPoint " + removed.getResource() + " structure damaged", null);\r
+                                               return;\r
+                                       }\r
+                                       removed.removeRelatedStatements(ProcessResource.plant3Dresource.HasNext);\r
+                               } else { //(prev != null)\r
+                                       if (prev.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)) {\r
+                                               ErrorLogger.defaultLogError("Removing PipeControlPoint " + removed.getResource() + " structure damaged, previous control point is size change control point", null);\r
+                                               return;\r
+                                       } else if (prev.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)) {\r
+                                               PipeControlPoint ocp = prev;\r
+                                               PipeControlPoint sccp = ocp.getSubPointOf();\r
+                                               if (sccp == null) {\r
+                                                       ErrorLogger.defaultLogError("Removing PipeControlPoint " + removed.getResource() + " structure damaged, no size change control point", null);\r
+                                                       return;\r
+                                               }\r
+                                               prev.removeRelatedStatements(ProcessResource.plant3Dresource.HasNext);\r
+                                               sccp.removeRelatedStatements(ProcessResource.plant3Dresource.HasNext);\r
+                                       } else if (prev.getNext().getResource().equals(removed.getResource())) {\r
+                                               prev.removeRelatedStatements(ProcessResource.plant3Dresource.HasNext);\r
+                                       } else {\r
+                                               ErrorLogger.defaultLogError("Removing PipeControlPoint "+ removed.getResource() + " structure damaged", null);\r
+                                               return;\r
+                                       }\r
+                                       removed.removeRelatedStatements(ProcessResource.plant3Dresource.HasPrevious);\r
+                               }\r
+\r
+                       }\r
+                       if (removed.getSubPoint().size() > 0 ) {\r
+                               removeSubPoints(removed);\r
+                       } else if (removed.getSubPointOf() != null) {\r
+                               removeParentPoint(removed);\r
+                       }\r
+                               \r
+                       removeComponents(removed);\r
+                       \r
+                       pipeRun.removeStatement(ProcessResource.plant3Dresource.HasControlPoints, removed);\r
+                       if (pipeRun.getChild().size() == 0) {\r
+                               PipingTools2.removePipeRun(pipeRun);\r
+                       } \r
+                       else if (pipeRun.getControlPoints().size() == 1) {\r
+               removeControlPoint(pipeRun.getControlPoints().iterator().next());\r
+            }\r
+               }\r
+        \r
+    }\r
+    \r
+    private static void removeDualPoint(PipeControlPoint removed) {\r
+       PipeControlPoint prev = removed.getPrevious();\r
+        PipeControlPoint next = removed.getNext();\r
+       if (prev != null) {\r
+               prev.removeRelatedStatements(ProcessResource.plant3Dresource.HasNext);\r
+               }\r
+               if (next != null)\r
+                       next.removeRelatedStatements(ProcessResource.plant3Dresource.HasPrevious);\r
+               PipeControlPoint ocp;\r
+               PipeControlPoint sccp;\r
+               // get sccp / ocp pair\r
+               if (removed.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)) {\r
+                       sccp = removed;\r
+               ocp = sccp.getSubPoint().iterator().next();\r
+               \r
+               } else {\r
+                       ocp = removed;\r
+               sccp = ocp.getSubPointOf();\r
+               }\r
+               PipeRun p1 = getPipeRun(ocp);\r
+               PipeRun p2 = getPipeRun(sccp);\r
+               \r
+               //  removes all components connected to control point\r
+        \r
+        removeComponents(ocp);\r
+        \r
+        removeComponents(sccp); \r
+        \r
+        // remove control points from pipeRuns\r
+        p1.removeStatement(ProcessResource.plant3Dresource.HasControlPoints, ocp);\r
+        p2.removeStatement(ProcessResource.plant3Dresource.HasControlPoints, sccp);\r
+\r
+        // remove links to other control points\r
+        ocp.removeRelatedStatements(ProcessResource.plant3Dresource.HasNext);\r
+        sccp.removeRelatedStatements(ProcessResource.plant3Dresource.HasNext);            \r
+        ocp.removeRelatedStatements(ProcessResource.plant3Dresource.HasPrevious);\r
+        sccp.removeRelatedStatements(ProcessResource.plant3Dresource.HasPrevious);            \r
+        \r
+        // if pipeRuns contains no other components(control points), they can be removed too.\r
+        if (p1.getControlPoints().size() == 0) {\r
+               PipingTools2.removePipeRun(p1);\r
+        } else if (p1.getControlPoints().size() == 1) {\r
+               removeControlPoint(p1.getControlPoints().iterator().next());\r
+        }\r
+        if (p2.getControlPoints().size() == 0) {\r
+               PipingTools2.removePipeRun(p2);\r
+        } else if (p2.getControlPoints().size() == 1) {\r
+               removeControlPoint(p2.getControlPoints().iterator().next());\r
+        }\r
+    }\r
+    \r
+    /**\r
+     * Removes sub points of a point\r
+     * @param removed\r
+     * @throws TransactionException\r
+     */\r
+    private static void removeSubPoints(PipeControlPoint removed) {\r
+       // if control point is branch control point, all branch of points must be removed too\r
+               Collection<PipeControlPoint> points = removed.getSubPoint();\r
+               \r
+               for (PipeControlPoint p : points) {\r
+                       removed.removeStatement(ProcessResource.plant3Dresource.HasSubPoint, p);\r
+                       removeControlPoint(p);\r
+               }\r
+    }\r
+    \r
+    /**\r
+     * Removed point is a subpoint of something, \r
+     * @param removed\r
+     */\r
+    private static void removeParentPoint(PipeControlPoint removed)  {\r
+       throw new RuntimeException("Subpoints cannot be removed");\r
+       \r
+       // if control point is branch it has to be removed from branch control point\r
+//             BranchEndControlPoint ecp = BranchEndControlPointFactory.create(removed);\r
+//             BranchControlPoint bcp = null;\r
+//             if (ecp.getBranchOfPointSet().size() == 1) {\r
+//                     bcp = ecp.getBranchOfPointSet().iterator().next();\r
+//             }\r
+//             if (bcp != null) {\r
+//                     bcp.getBranchPointSet().remove(ecp);\r
+//                     if (bcp.getBranchPointSet().size() == 0) {\r
+//                             // branch control point is not used and can be removed\r
+//                             removeControlPoint(bcp);\r
+//                     }\r
+//             }\r
+    }\r
\r
+    \r
+    private static void removeComponents(PipeControlPoint pcp) {\r
+       IEntity component = pcp.getControlPointOf();\r
+       if (component != null) {\r
+               PipeRun p1 = getPipeRun(pcp);\r
+               p1.removeStatement(ProcessResource.g3dResource.HasChild, component);\r
+               component.removeRelatedStatements(ProcessResource.plant3Dresource.HasControlPoint);\r
+       }\r
+    }\r
+    \r
+    private static void setStatement(IEntity subject, Resource relation, IEntity object) {\r
+       subject.removeRelatedStatements(relation);\r
+       subject.addStatement(relation, object);\r
+    }\r
+    \r
+    \r
+    public static void setWorldPosition(IEntity pcp, Tuple3d position) {\r
+       IEntity wp = pcp.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition);\r
+       G3DTools.setTuple3(wp, position);\r
+       tt.propagateWorldTransformChange(tt.getParent(pcp), pcp);\r
+       \r
+    }\r
+    \r
+    public static void setLocalPosition(IEntity pcp, Tuple3d position) {\r
+       G3DTools.setTuple3(pcp.getSingleRelatedObject(ProcessResource.g3dResource.HasLocalPosition), position);\r
+       tt.propagateLocalTransformChange(tt.getParent(pcp), pcp);\r
+    }\r
+    \r
+    public static void setWorldOrientation(IEntity node, AxisAngle4d orientation) {\r
+               G3DTools.setOrientation(node.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldOrientation), orientation);\r
+               tt.propagateWorldTransformChange(tt.getParent(node), node);\r
+               \r
+       }\r
+       \r
+       public static void setLocalOrientation(IEntity node, AxisAngle4d orientation) {\r
+               G3DTools.setOrientation(node.getSingleRelatedObject(ProcessResource.g3dResource.HasLocalOrientation), orientation);\r
+               tt.propagateLocalTransformChange(tt.getParent(node), node);\r
+       }\r
+    \r
+    private static boolean updatePosition(IEntity pcp) {\r
+       return tt.transformationUpdate(pcp);\r
+       \r
+       \r
+       // TODO : orientation is also needed, current code handles only position\r
+       // TODO : reuse the code in G3DTools!\r
+       /*\r
+       IEntity worldPosition = pcp.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition);\r
+       IEntity localPosition = pcp.getSingleRelatedObject(ProcessResource.g3dResource.HasLocalPosition);\r
+       \r
+       \r
+       Tuple3d worldP = G3DTools.getPoint(worldPosition);\r
+        Tuple3d localP = G3DTools.getPoint(localPosition);\r
+\r
+        if (localP == null || worldP == null)\r
+            return false;\r
+        if (!isValid(worldP) && !isValid(localP))\r
+               return false;\r
+\r
+        Tuple3d cachedWorldP = (Tuple3d) getProperty(worldPosition.getResource());\r
+        Tuple3d cachedLocalP = (Tuple3d) getProperty(localPosition.getResource());\r
+\r
+        if (DEBUG) System.out.println("PipeControlPoint changed " + worldP + " " + cachedWorldP + " " + localP + " " + cachedLocalP);\r
+        boolean changed = false;\r
+\r
+        IEntity parent = pcp.getSingleRelatedObject(ProcessResource.plant3Dresource.ControlPointOf);\r
+        \r
+        if (parent == null) {\r
+               if (DEBUG) System.out.println("PipeControlPoint changed, no parent node");\r
+            return false;\r
+        }\r
+\r
+        if (cachedLocalP == null) {\r
+            storeProperty(localPosition.getResource(), localP);\r
+            Tuple3d p = G3DTools.getWorldFromLocal(parent, new Point3d(localP)); \r
+            storeProperty(worldPosition.getResource(), p);\r
+            G3DTools.setTuple3(worldPosition, p);\r
+            if (DEBUG) System.out.println("PipeControlPoint changed local " + worldP + " " + p);\r
+            changed = true;\r
+        } else {\r
+            if (TransformationTools.changed(cachedLocalP, localP)) {\r
+                storeProperty(localPosition.getResource(), localP);\r
+                Tuple3d p = G3DTools.getWorldFromLocal(parent, new Point3d(localP));\r
+                storeProperty(worldPosition.getResource(), p);\r
+                G3DTools.setTuple3(worldPosition, p);\r
+                if (DEBUG) System.out.println("PipeControlPoint changed local " + worldP + " " + localP);\r
+                changed = true;\r
+            }\r
+            if (cachedWorldP == null) {\r
+                storeProperty(worldPosition.getResource(), worldP);\r
+                Tuple3d p = G3DTools.getLocalFromWorld(parent, new Point3d(worldP));\r
+                G3DTools.setTuple3(localPosition, p);\r
+                storeProperty(localPosition.getResource(), p);\r
+                if (DEBUG) System.out.println("PipeControlPoint changed world " + worldP + " " + p);\r
+                changed = true;\r
+            } else {\r
+                if (TransformationTools.changed(cachedWorldP, worldP)) {\r
+                    storeProperty(worldPosition.getResource(), worldP);\r
+                    Tuple3d p = G3DTools.getLocalFromWorld(parent, new Point3d(worldP));\r
+                    G3DTools.setTuple3(localPosition, p);\r
+                    storeProperty(localPosition.getResource(), p);\r
+                    if (DEBUG) System.out.println("PipeControlPoint changed world " + worldP + " " + p);\r
+                    changed = true;\r
+                }\r
+            }\r
+        }\r
+        return changed;\r
+        //*/\r
+    }\r
+    \r
+    static boolean isControlPointChanged(PipeControlPoint node) {\r
+       long id = node.getResource().getResourceId();\r
+       boolean changed = updatePosition(node);\r
+        //if (!changed) {\r
+               if (node.isInstanceOf(ProcessResource.plant3Dresource.PathLegEndControlPoint)) {\r
+                       if (node.isInstanceOf(ProcessResource.plant3Dresource.TurnControlPoint)) {\r
+                               Pair<Long,Long> connected = (Pair<Long,Long>)getProperty(node.getResource().getResourceId());\r
+                    PipeControlPoint next = node.getNext();\r
+                    PipeControlPoint prev = node.getPrevious();\r
+                    if ((next != null && prev != null) && (\r
+                        connected == null || \r
+                       (connected.first == null && prev != null) ||\r
+                       (connected.second == null && next != null) ||\r
+                        !connected.first.equals(prev.getResource().getResourceId()) ||\r
+                        !connected.second.equals(next.getResource().getResourceId()))) {\r
+                       storeProperty(id, new Pair<Long,Long>(prev.getResource().getResourceId(),next.getResource().getResourceId()));\r
+                        changed = true;  \r
+                    }\r
+                    if (node.isInstanceOf(ProcessResource.plant3Dresource.VariableAngleTurnControlPoint)) {\r
+                       double r = node.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasTurnRadius);\r
+                       Double d = (Double)getProperty(id + ":turnradius");\r
+                       if (d == null || TransformationTools.changed(r, d)) {\r
+                               storeProperty(id + ":turnradius", r);\r
+                               changed = true;\r
+                       }\r
+                    }\r
+                       }\r
+                       else if (node.isInstanceOf(ProcessResource.plant3Dresource.DirectedControlPoint)) {\r
+                               Vector3d dir = ControlPointTools.getDirectedControlPointDirection(node);\r
+                               Vector3d old = (Vector3d)getProperty(id + ":direction");\r
+                               if (old == null || TransformationTools.changed(dir, old)) {\r
+                                       storeProperty(id + ":direction", dir);\r
+                                       changed = true;\r
+                               }\r
+                       }\r
+               } else { // InlineControlPoint\r
+                       if (node.isInstanceOf(ProcessResource.plant3Dresource.FixedLengthControlPoint)) {\r
+                               double length = node.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength);\r
+                               Double d = (Double)getProperty(id + ":length");\r
+                               if (d == null)\r
+                                       changed = true;\r
+                               else\r
+                                       changed = changed || TransformationTools.changed(length, d);\r
+                               \r
+                               if (changed) {\r
+                                       storeProperty(id + ":length", length);\r
+                                       return true;\r
+                               }\r
+                       } else \r
+                       if (node.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)) {\r
+                               \r
+                               double angle = node.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasRotationAngle);\r
+                               Double d = (Double)getProperty(id + ":rotationangle");\r
+                               if (d == null)\r
+                                       changed = true;\r
+                               else\r
+                                       changed = changed || TransformationTools.changed(angle, d);\r
+                               if (changed) {\r
+                                       storeProperty(id + ":rotationangle", angle);\r
+                                       return true;\r
+                               }\r
+                               Collection<PipeControlPoint> subpoints = node.getSubPoint();\r
+                               if (subpoints.size() != 1)\r
+                                       throw new RuntimeException("Current implementation assumes that size change components are dual conmnected");\r
+                               PipeControlPoint ocp = subpoints.iterator().next();\r
+                               if (node.isInstanceOf(ProcessResource.plant3Dresource.OffsettingPoint)) {\r
+                                       double offset = ocp.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasOffset);\r
+                                       d = (Double)getProperty(id +":offset");\r
+                                       if (d == null)\r
+                                               changed = true;\r
+                                       else\r
+                                               changed = TransformationTools.changed(offset, d);\r
+                                       if (changed) {\r
+                                               storeProperty(id+":offset", offset);\r
+                                               return true;\r
+                                       }\r
+                               }\r
+//                     } else if (node instanceof OffsetControlPoint) {\r
+//                             OffsetControlPoint ocp = (OffsetControlPoint)node;\r
+//                             //ocp.\r
+//                     } else if (node instanceof BranchControlPoint) {\r
+//                             BranchControlPoint bcp = (BranchControlPoint)node;\r
+//                             int size = bcp.getBranchPointSet().size();\r
+//                             Integer i = (Integer)getProperty(bcp.getResource().getId());\r
+//                             if (i == null)\r
+//                                     changed =true;\r
+//                             else\r
+//                                     changed = changed || i != size;\r
+//                             if (changed) {\r
+//                                     storeProperty(bcp.getResource().getId(), size);\r
+//                                     return true;\r
+//                             }\r
+                       }\r
+               }\r
+        //}\r
+        \r
+        return changed;\r
+    }\r
+    \r
+    private static boolean isValid(Tuple3d v) {\r
+        if (Double.isInfinite(v.x) || \r
+                 Double.isNaN(v.x) ||\r
+            Double.isInfinite(v.y) || \r
+                 Double.isNaN(v.y) ||\r
+            Double.isInfinite(v.z) || \r
+                 Double.isNaN(v.z))\r
+            return false;\r
+        return true;\r
+    }\r
+    \r
+    private static HashMap<Object, Object> properties = new HashMap<Object, Object>();\r
+    \r
+    public static Object getProperty(Object key) {\r
+        return properties.get(key);\r
+    }\r
+    \r
+    public static void storeProperty(Object key, Object value) {\r
+        properties.put(key, value);\r
+    }\r
+    \r
+    /**\r
+     * Loads positions of controlpoint to rule cache\r
+     * \r
+     * TODO : this caches only transformation information : other info must be cached too\r
+     * \r
+     * @param root resource of the modeled plant\r
+     */\r
+    public static void reloadCache(Graph graph, Resource root) {\r
+        \r
+        Stack<IEntity> stack = new Stack<IEntity>();\r
+        stack.add(EntityFactory.create(graph,root));\r
+        while (!stack.isEmpty()) {\r
+               IEntity current = stack.pop();\r
+               IEntity pcp = current.getAtMostOneRelatedObject(ProcessResource.plant3Dresource.HasControlPoint);\r
+               if (pcp == null) {\r
+                       stack.addAll(current.getRelatedObjects(ProcessResource.g3dResource.HasChild));\r
+               } else {\r
+                       if (DEBUG) System.out.println("Cached pcp " + pcp.getResource());\r
+                       IEntity localPos = pcp.getSingleRelatedObject(ProcessResource.g3dResource.HasLocalPosition);\r
+                       IEntity worldPos = pcp.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition);\r
+                       \r
+                tt.storeProperty(localPos.getResource(),G3DTools.getPoint(localPos));\r
+                tt.storeProperty(worldPos.getResource(),G3DTools.getPoint(worldPos));\r
+                \r
+                IEntity localOr = pcp.getAtMostOneRelatedObject(ProcessResource.g3dResource.HasLocalOrientation);\r
+                       IEntity worldOr = pcp.getAtMostOneRelatedObject(ProcessResource.g3dResource.HasWorldOrientation);\r
+                       \r
+                       if (worldOr != null) {\r
+                               tt.storeProperty(localOr.getResource(),G3DTools.getOrientation(localOr));\r
+                    tt.storeProperty(worldOr.getResource(),G3DTools.getOrientation(worldOr));\r
+                       }\r
+                       \r
+                stack.addAll(pcp.getRelatedObjects(ProcessResource.plant3Dresource.HasSubPoint));\r
+               }\r
+        }\r
+\r
+    }\r
+}\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/PathUtils.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/PathUtils.java
new file mode 100644 (file)
index 0000000..9ddaf04
--- /dev/null
@@ -0,0 +1,145 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007 VTT Technical Research Centre of Finland and others.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package fi.vtt.simantics.processeditor.common;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+\r
+import org.simantics.db.Graph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.layer0.utils.EntityFactory;\r
+import org.simantics.layer0.utils.IEntity;\r
+import org.simantics.layer0.utils.viewpoints.TraversalPath;\r
+import org.simantics.proconf.browsing.GraphExplorer;\r
+import org.simantics.utils.datastructures.Pair;\r
+\r
+\r
+\r
+\r
+\r
+public class PathUtils {\r
+\r
+       public static void createPath(java.util.List<Resource> samplePath, TraversalPath path, Resource sampleInstance, Resource sampleSource, GraphExplorer oe) {\r
+//             while (tNode != null) {\r
+//                     long[] path = tNode.getPath();\r
+//                     for (int i = 0; i < path.length; i++) {\r
+//                             samplePath.add(i, path[i]);\r
+//                     }\r
+//                     samplePath.add(path.length,tNode.getCoreId());\r
+//                     tNode = oe.getTreeParent(tNode);\r
+//             }\r
+               while (path != null) {\r
+                       Resource predicate = path.getPredicate();\r
+                       Resource obj = path.getResource();\r
+                       if (predicate != null) {\r
+                               samplePath.add(0,predicate);\r
+                               path = path.getTail();\r
+                       } else {\r
+                               // there is no relation and so this has to be root\r
+                               path = null; \r
+                       }\r
+                       samplePath.add(1,obj);\r
+                       \r
+               }\r
+               \r
+               if (!sampleInstance.equals(samplePath.get(0)) || !sampleSource.equals(samplePath.get(samplePath.size()-1))) {\r
+                       String s = "";\r
+                       for (int i = 0; i < samplePath.size(); i++) {\r
+                               s += samplePath.get(i) + " ";\r
+                       }\r
+                       throw new RuntimeException("Path from " + sampleInstance + " to "\r
+                                       + sampleSource + " is broken: " + s);\r
+               }\r
+\r
+//             String s = "";\r
+//             for (int i = 0; i < samplePath.size(); i++) {\r
+//                     s += samplePath.get(i) + " ";\r
+//             }\r
+//             System.out.println("Path from " + sampleInstance + " to " + sampleSource + " is: " + s);\r
+               samplePath.remove(0);\r
+       }\r
+       \r
+       \r
+       \r
+       /**\r
+        * Finds similar path in cloned resource\r
+        * TODO : this isn't correct way to do this;\r
+        * Rigth way would be finding mapping between two clones\r
+        * and then find the similar resource \r
+        * (Viewpoint used to create clone is required)\r
+        * \r
+        * @param path\r
+        * @param begin\r
+        * @return\r
+        */\r
+       public static IEntity findSimilar(java.util.List<Resource> path,  IEntity begin) {\r
+               if (path.size() == 0)\r
+                       return begin;\r
+               if (path.size() == 1)\r
+                       return null;\r
+               Graph g = begin.getGraph();\r
+               java.util.List<Resource> tPath = new ArrayList<Resource>();\r
+               tPath.addAll(path);\r
+               \r
+               Resource p = tPath.get(0); // predicate (relation)\r
+               Resource o = tPath.get(1); // object \r
+               tPath.remove(0);\r
+               tPath.remove(0);\r
+               \r
+               IEntity predicate = EntityFactory.create(g, p);\r
+\r
+               \r
+               Collection<IEntity> possibleObjects = begin.getRelatedObjects(predicate);\r
+               if (possibleObjects.size() == 0)\r
+                       return null;\r
+               if (possibleObjects.size() == 1) \r
+                       return findSimilar(tPath, possibleObjects.iterator().next());\r
+               else {\r
+                       IEntity object = EntityFactory.create(g, o);\r
+                       Collection<IEntity> objectTypes = object.getTypes();\r
+                       java.util.List<Pair<IEntity,IEntity>> list = new ArrayList<Pair<IEntity,IEntity>>();\r
+                       for (IEntity possible : possibleObjects) {\r
+                               boolean matchTypes = true;\r
+                               for (IEntity type : objectTypes) {\r
+                                       if(!possible.isInstanceOf(type)) {\r
+                                               matchTypes = false;\r
+                                               break;\r
+                                       }\r
+                                               \r
+                               }\r
+                               if (matchTypes) {\r
+                                       IEntity r = findSimilar(tPath,possible);\r
+                                       if (r != null)\r
+                                               list.add(new Pair<IEntity,IEntity>(possible,r));\r
+                                               //return r;\r
+                               }\r
+                       }\r
+                       if (list.size() == 0)\r
+                               return null;\r
+                       if (list.size() == 1)\r
+                               return list.get(0).second;\r
+                       else {\r
+                               // uses names of objects to detect similarities\r
+                               String name = object.getName();\r
+                               if (name != null) {\r
+                                       for (Pair<IEntity,IEntity> possible : list) {\r
+                                               String otherName = possible.first.getName();\r
+                                               //System.out.println(name + " : " + otherName);\r
+                                               if (otherName != null && name.compareTo(otherName) == 0)\r
+                                                       return possible.second;\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+               \r
+               return null;\r
+       }\r
+}\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/PipeComponentProvider.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/PipeComponentProvider.java
new file mode 100644 (file)
index 0000000..a59e0f8
--- /dev/null
@@ -0,0 +1,531 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007 VTT Technical Research Centre of Finland and others.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package fi.vtt.simantics.processeditor.common;\r
+\r
+import java.nio.FloatBuffer;\r
+import java.nio.IntBuffer;\r
+\r
+import javax.vecmath.AxisAngle4d;\r
+import javax.vecmath.Point3d;\r
+import javax.vecmath.Quat4d;\r
+import javax.vecmath.Vector3d;\r
+\r
+import org.simantics.layer0.utils.IEntity;\r
+import org.simantics.proconf.g3d.base.G3DTools;\r
+import org.simantics.proconf.g3d.base.GeometryProvider;\r
+import org.simantics.proconf.g3d.base.MathTools;\r
+import org.simantics.utils.ErrorLogger;\r
+\r
+import com.jme.scene.Geometry;\r
+import com.jme.scene.Line;\r
+import com.jme.scene.TriMesh;\r
+import com.jme.util.geom.BufferUtils;\r
+\r
+import fi.vtt.simantics.processeditor.ProcessResource;\r
+import fi.vtt.simantics.processeditor.stubs.PipeControlPoint;\r
+import fi.vtt.simantics.processeditor.stubs.PipelineComponent;\r
+import fi.vtt.simantics.processeditor.stubs.TurnControlPoint;\r
+\r
+\r
+/**\r
+ * Geometry provider for pipe components.\r
+ * TODO : split into three providers (one for each type) to faster access (ShapeNodes can cache geometry provider)\r
+ * \r
+ * @author Marko Luukkainen\r
+ *\r
+ */\r
+public class PipeComponentProvider implements GeometryProvider {\r
+       \r
+       \r
+       //private static double ELBOW_RING_ANGLE = 12.0/ Math.PI;\r
+       //private static int RING_SEGMENTS = 8;\r
+       \r
+       private static double ELBOW_RING_ANGLE = 24.0/ Math.PI;\r
+       private static int RING_SEGMENTS = 16;\r
+       \r
+       public boolean canHandle(IEntity instance) {\r
+               if (instance.isInstanceOf(ProcessResource.plant3Dresource.Elbow))\r
+                       return true;\r
+               if (instance.isInstanceOf(ProcessResource.plant3Dresource.Straight))\r
+                       return true;\r
+               if (instance.isInstanceOf(ProcessResource.plant3Dresource.Reducer))\r
+                       return true;    \r
+               return false;\r
+       }\r
+\r
+       \r
+       public Geometry[] getGeometryFromResource(IEntity instance, boolean transform) {\r
+               if (instance.isInstanceOf(ProcessResource.plant3Dresource.Elbow)) {\r
+                       Geometry[] g = new Geometry[]{new TriMesh(),new Line()};\r
+                       if( getElbowGeometry(instance,g)) {\r
+                               return g;\r
+                       }\r
+                       return null;\r
+               }\r
+                       \r
+               if (instance.isInstanceOf(ProcessResource.plant3Dresource.Straight)) {\r
+                       Geometry[] g = new Geometry[]{new TriMesh(),new Line()};\r
+                       if( getStraightGeometry(instance,g)) {\r
+                               return g;\r
+                       }\r
+                       return null;\r
+               }\r
+               if (instance.isInstanceOf(ProcessResource.plant3Dresource.Reducer)) {\r
+                       Geometry[] g = new Geometry[]{new TriMesh(),new Line()};\r
+                       if (getReducerGeometry(instance,g)) {\r
+                               return g;\r
+                       }\r
+                       return null;\r
+               }\r
+               return null;\r
+       }\r
+       \r
+       public boolean reconstructGeometry(IEntity instance, boolean transform, Geometry[] geometry) {\r
+               if (instance.isInstanceOf(ProcessResource.plant3Dresource.Elbow))\r
+                       return getElbowGeometry(instance,geometry);\r
+               if (instance.isInstanceOf(ProcessResource.plant3Dresource.Straight))\r
+                       return getStraightGeometry(instance,geometry);\r
+               if (instance.isInstanceOf(ProcessResource.plant3Dresource.Reducer))\r
+                       return getReducerGeometry(instance,geometry);\r
+               \r
+               return false;\r
+       }\r
+\r
+       public boolean getElbowGeometry(IEntity instance, Geometry[] geometry) {\r
+               PipelineComponent elbow = new PipelineComponent(instance);\r
+               PipeControlPoint pcp = elbow.getControlPoint();\r
+               if (pcp == null) {\r
+                       ErrorLogger.defaultLogError("Elbow " + instance + " has no control point", null);\r
+                       return false;\r
+               }\r
+        TurnControlPoint tcp = new TurnControlPoint(pcp);\r
+        // double turnAngleValue = tcp.getTurnAngleValue();\r
+         \r
+        double pipeRadius = elbow.getPipeDiameter()[0]*0.5;\r
+        double elbowRadius = elbow.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasTurnRadius);\r
+        double R = tcp.getLength()[0]; //getComponentOffset();\r
+        double turnAngle = tcp.getTurnAngle()[0];\r
+\r
+        PipeControlPoint startControlPoint = tcp.getPrevious();\r
+        PipeControlPoint endControlPoint = tcp.getNext();\r
+        if (startControlPoint == null || endControlPoint == null)\r
+            return false;\r
+        \r
+        //Point3d start = getLocalPoint(pipeline,startControlPoint);\r
+        //Point3d middle = getLocalPoint(pipeline,tcp);\r
+        //Point3d end = getLocalPoint(pipeline,endControlPoint);     \r
+        \r
+        Point3d start = G3DTools.getPoint(startControlPoint.getWorldPosition());\r
+        Point3d middle = G3DTools.getPoint(tcp.getWorldPosition());\r
+        Point3d end = G3DTools.getPoint(endControlPoint.getWorldPosition());\r
+        \r
+        Vector3d dir1 = new Vector3d(middle);\r
+        dir1.sub(start);\r
+        Vector3d dir2 = new Vector3d(end);\r
+        dir2.sub(middle);\r
+        \r
+        Vector3d n = new Vector3d(dir1);\r
+        n.normalize();\r
+        Vector3d offset = new Vector3d(n);\r
+\r
+        offset.scale(R);\r
+        Vector3d startPipe = new Vector3d(middle);\r
+        startPipe.sub(offset);\r
+        // normal of the plane\r
+        Vector3d normal = new Vector3d();\r
+        normal.cross(dir1, dir2);\r
+        Vector3d elbowCenter = new Vector3d();\r
+        elbowCenter.cross(normal, dir1);\r
+        elbowCenter.normalize();\r
+        elbowCenter.scale(elbowRadius);\r
+        elbowCenter.add(startPipe);\r
+\r
+        elbowCenter.sub(middle);\r
+            \r
+        // creates sweep shape by rotating a circle\r
+        // several values must be checked if they are infinite (OCC crashes if they are)\r
+        if (turnAngle > 0.001 && normal.lengthSquared() > 0.0 && !(Double.isInfinite(turnAngle)) && isValid(n) && isValid(startPipe)) {\r
+//            System.out.println(startPipe + " " + middle + " " + n + " " +  elbowCenter + " " + normal + " " + turnAngle);\r
+//            gp_Circ circ = new gp_Circ(new double[] { startPipe.x - middle.x, startPipe.y - middle.y,\r
+//                    startPipe.z - middle.z, n.x, n.y, n.z }, pipeRadius);\r
+//            TopoDS_Edge ed = (TopoDS_Edge) new BRepBuilderAPI_MakeEdge(circ).shape();\r
+//            TopoDS_Wire w = (TopoDS_Wire) new BRepBuilderAPI_MakeWire(ed).shape();\r
+//            TopoDS_Face F = (TopoDS_Face) new BRepBuilderAPI_MakeFace(w).shape();\r
+//            TopoDS_Shape S4 = new BRepPrimAPI_MakeRevol(F, new double[] { elbowCenter.x, elbowCenter.y, elbowCenter.z,\r
+//                    normal.x, normal.y, normal.z }, turnAngle).shape();\r
+//\r
+//            try {\r
+//                return OccTriangulator.getGeometry(S4, true);\r
+//\r
+//            } catch (Exception e) {\r
+//                e.printStackTrace();\r
+//                return null;\r
+//            }\r
+               elbow(pipeRadius,elbowRadius,n,normal,turnAngle,elbowCenter,geometry);\r
+               return true;\r
+        }\r
+        return false;\r
+\r
+       }\r
+       \r
+       public void elbow(double radius, double turnRadius, Vector3d sn, Vector3d rn, double angle, Vector3d p, Geometry[] geometry) {\r
+               Vector3d t = new Vector3d();\r
+               t.cross(sn,rn);\r
+               t.normalize();\r
+               t.scale(turnRadius);\r
+               Vector3d vs[][] = calcCirc(RING_SEGMENTS, 0.0, 0.0, 0.0, sn.x, sn.y, sn.z, radius);\r
+               int rings = (int)Math.ceil(angle * ELBOW_RING_ANGLE * Math.sqrt(turnRadius));\r
+               if (rings < 2)\r
+                       rings = 2;\r
+               FloatBuffer v = BufferUtils.createFloatBuffer(vs[0].length * rings * 3);\r
+               FloatBuffer n = BufferUtils.createFloatBuffer(vs[0].length * rings * 3);\r
+               Quat4d q = new Quat4d();\r
+               AxisAngle4d aa = new AxisAngle4d();\r
+               Vector3d pos = new Vector3d();\r
+               Vector3d t2 = new Vector3d();\r
+               \r
+               aa.x = rn.x;\r
+               aa.y = rn.y;\r
+               aa.z = rn.z;\r
+               for (int i = 0; i < rings; i++) {\r
+                       double a = (double)i/(double)(rings-1) * angle;\r
+                       aa.angle = a;\r
+                       q.set(aa);\r
+                       MathTools.rotate(q, t, pos);\r
+                       for (int j = 0; j < vs[0].length; j++) {\r
+                               MathTools.rotate(q, vs[0][j], t2);\r
+                               t2.add(pos);\r
+                               t2.add(p);\r
+                               v.put((float)t2.x);\r
+                               v.put((float)t2.y);\r
+                               v.put((float)t2.z);\r
+                               MathTools.rotate(q, vs[1][j], t2);\r
+                               n.put((float)t2.x);\r
+                               n.put((float)t2.y);\r
+                               n.put((float)t2.z);\r
+                       }\r
+               }\r
+               int indexCount  = indexCount(RING_SEGMENTS, rings);\r
+               int edgeIndexCount = edgeIndexCount(RING_SEGMENTS, rings);\r
+               IntBuffer i = BufferUtils.createIntBuffer(indexCount);\r
+               IntBuffer ei = BufferUtils.createIntBuffer(edgeIndexCount);\r
+               createIndices(i, RING_SEGMENTS, rings);\r
+               createEdgeIndices(ei, RING_SEGMENTS, rings);\r
+               TriMesh m = (TriMesh)geometry[0];//new TriMesh();\r
+               Line l = (Line)geometry[1];//new Line();\r
+       m.reconstruct(v, n, null, null,i);\r
+               l.reconstruct(v, null, null, null,ei);\r
+       //return new Geometry[]{m,l};\r
+       }\r
+\r
+       public boolean  getStraightGeometry(IEntity instance, Geometry[] geometry) {\r
+               //Straight straight = new Straight(instance);\r
+               PipelineComponent straight = new PipelineComponent(instance);\r
+               double pipeRadius = straight.getPipeDiameter()[0] * 0.5;\r
+               //PipeRun pipeline = (PipeRun)PipingTools2.getPipeRun(straight.toPipelineComponent());//parent.getGraphicsNode();\r
+        //double pipeRadius = pipeline.getPipeDiameter()[0] * 0.5;\r
+        \r
+        \r
+//        PipeControlPoint startControlPoint = (PipeControlPoint)StubFactory.getStubForResource(this.getClass().getClassLoader(),straight.getHasPreviousControlPoint().getResource());\r
+//        PipeControlPoint endControlPoint = (PipeControlPoint)StubFactory.getStubForResource(this.getClass().getClassLoader(),straight.getHasNextControlPoint().getResource());\r
+        \r
+        // start and end position of the pipe\r
+        // positions may be linked to other components, like nozzles\r
+        // and then their coordinates are in component's local coordinates\r
+        // which must be transformed into pipeline's local coordinates\r
+        \r
+        Point3d startPipe = new Point3d();//getLocalPoint(pipeline,startControlPoint);\r
+\r
+        \r
+        Point3d endPipe = new Point3d(); //getLocalPoint(pipeline, endControlPoint);\r
+\r
+        \r
+        \r
+        \r
+        PipingTools2.getInlineComponentEnds(straight, startPipe, endPipe);\r
+        boolean b = createStraightGeometry(startPipe, endPipe, pipeRadius, geometry);\r
+        if (!b)\r
+               ErrorLogger.getDefault().logWarning("Straight pipe " + instance + " is too short", null);\r
+        return b;\r
+       }\r
+       \r
+       public static boolean createStraightGeometry(Point3d startPipe, Point3d endPipe, double pipeRadius, Geometry geometry[]) {\r
+               Vector3d dir = new Vector3d(endPipe);\r
+        dir.sub(startPipe);\r
+        \r
+        double h = dir.length();\r
+//      several values must be checked if they are infinite (OCC crashes if they are)\r
+        if (h > 0.001 && h < 10000.0 && pipeRadius > 0.01) {\r
+\r
+            dir.normalize();\r
+\r
+            Vector3d[][] v1 = calcCirc(RING_SEGMENTS, startPipe.x, startPipe.y, startPipe.z, dir.x, dir.y, dir.z, pipeRadius);\r
+               Vector3d[][] v2 = calcCirc(RING_SEGMENTS, endPipe.x, endPipe.y, endPipe.z, dir.x, dir.y, dir.z, pipeRadius);\r
+               TriMesh m = (TriMesh)geometry[0];//new TriMesh();\r
+               Line l = null;\r
+               if (geometry.length>1)\r
+                       l = (Line)geometry[1];//new Line();\r
+               FloatBuffer v = BufferUtils.createFloatBuffer(v1[0].length * 2 * 3);\r
+               FloatBuffer n = BufferUtils.createFloatBuffer(v1[0].length * 2 * 3 );\r
+               for (int i = 0; i < v1[0].length; i++) {\r
+                       v.put((float)v1[0][i].x);\r
+                       v.put((float)v1[0][i].y);\r
+                       v.put((float)v1[0][i].z);\r
+                       n.put((float)v1[1][i].x);\r
+                       n.put((float)v1[1][i].y);\r
+                       n.put((float)v1[1][i].z);\r
+             }\r
+               for (int i = 0; i < v2[0].length; i++) {\r
+                       v.put((float)v2[0][i].x);\r
+                       v.put((float)v2[0][i].y);\r
+                       v.put((float)v2[0][i].z);\r
+                       n.put((float)v2[1][i].x);\r
+                       n.put((float)v2[1][i].y);\r
+                       n.put((float)v2[1][i].z);\r
+             }\r
+               \r
+               IntBuffer i = BufferUtils.createIntBuffer(indexCount(RING_SEGMENTS, 2));\r
+               createIndices(i, RING_SEGMENTS, 2);\r
+               m.reconstruct(v, n, null, null,i);\r
+               if (l != null) {\r
+                       IntBuffer ei = BufferUtils.createIntBuffer(edgeIndexCount(RING_SEGMENTS, 2));\r
+               createEdgeIndices(ei, RING_SEGMENTS, 2);\r
+               l.reconstruct(v, null, null, null,ei);\r
+               }\r
+               return true;\r
+        } \r
+        return false;\r
+       }\r
+       \r
+       public static void createStraightEdges(Line l, Point3d startPipe, Point3d endPipe, double pipeRadius) {\r
+               Vector3d dir = new Vector3d(endPipe);\r
+               dir.sub(startPipe);\r
+               dir.normalize();\r
+                Vector3d[][] v1 = calcCirc(8, startPipe.x, startPipe.y, startPipe.z, dir.x, dir.y, dir.z, pipeRadius);\r
+       Vector3d[][] v2 = calcCirc(8, endPipe.x, endPipe.y, endPipe.z, dir.x, dir.y, dir.z, pipeRadius);\r
+       FloatBuffer v = BufferUtils.createFloatBuffer(v1[0].length * 2 * 3);\r
+       FloatBuffer n = BufferUtils.createFloatBuffer(v1[0].length * 2 * 3 );\r
+       for (int i = 0; i < v1[0].length; i++) {\r
+               v.put((float)v1[0][i].x);\r
+               v.put((float)v1[0][i].y);\r
+               v.put((float)v1[0][i].z);\r
+               n.put((float)v1[1][i].x);\r
+               n.put((float)v1[1][i].y);\r
+               n.put((float)v1[1][i].z);\r
+         }\r
+       for (int i = 0; i < v2[0].length; i++) {\r
+               v.put((float)v2[0][i].x);\r
+               v.put((float)v2[0][i].y);\r
+               v.put((float)v2[0][i].z);\r
+               n.put((float)v2[1][i].x);\r
+               n.put((float)v2[1][i].y);\r
+               n.put((float)v2[1][i].z);\r
+         }\r
+       \r
+\r
+       IntBuffer ei = BufferUtils.createIntBuffer(edgeIndexCount(8, 2));\r
+       createEdgeIndices(ei, 8, 2);\r
+       l.reconstruct(v, null, null, null,ei);\r
+       }\r
+\r
+       public boolean getReducerGeometry(IEntity instance,Geometry[] geometry) {\r
+        //Reducer reducer = new Reducer(instance);\r
+               PipelineComponent reducer = new PipelineComponent(instance);\r
+        PipeControlPoint pcp = reducer.getControlPoint();\r
+        PipeControlPoint pcp2 = pcp.getSubPoint().iterator().next();\r
+        //PipeControlPoint pcp = reducer.getHasControlPoint();\r
+        //PipeControlPoint prev = pcp.getPreviousPoint();\r
+        //assert (prev != null);\r
+        //Point3d prevPoint = GraphicsNodeTools.getPoint(prev.getLocalPosition());\r
+        //Point3d point = GraphicsNodeTools.getPoint(pcp.getLocalPosition());\r
+        //Vector3d dir = new Vector3d(point);\r
+        //dir.sub(prevPoint);\r
+        //dir.normalize();\r
+        double h = reducer.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength);\r
+        double r1 = pcp.getPipeDiameter()[0] * 0.5;//reducer.getBottomRadius();\r
+        double r2 = pcp2.getPipeDiameter()[0] * 0.5;//reducer.getTopRadiusValue();\r
+            \r
+        if (h > 0.001 && r1 > 0.001 && r2 > 0.001 ) {\r
+//            TopoDS_Shape S4 = getShape(h,r1,r2, instance.isInstanceOf(GlobalIdMap.get(PSK3DModelingOntologyMapping.ECCENTRIC_REDUCER)));\r
+//             \r
+//             \r
+//            try {\r
+//                return OccTriangulator.getGeometry(S4, true);\r
+//\r
+//            } catch (Exception e) {\r
+//                e.printStackTrace();\r
+//                return null;\r
+//            }\r
+               Vector3d[][] v1 = calcCirc(RING_SEGMENTS, -h * 0.5, 0.0, 0.0, 1.0, 0.0, 0.0, r1);\r
+               Vector3d[][] v2 = calcCirc(RING_SEGMENTS,  h * 0.5, 0.0, instance.isInstanceOf(ProcessResource.plant3Dresource.EccentricReducer) ? (r1 - r2) : 0.0, 1.0, 0.0, 0.0, r2);\r
+               TriMesh m = (TriMesh)geometry[0];//new TriMesh();\r
+               Line l = (Line)geometry[1];//new Line();\r
+               FloatBuffer v = BufferUtils.createFloatBuffer(v1[0].length * 2 * 3);\r
+               FloatBuffer n = BufferUtils.createFloatBuffer(v1[0].length * 2 * 3 );\r
+               for (int i = 0; i < v1[0].length; i++) {\r
+                       v.put((float)v1[0][i].x);\r
+                       v.put((float)v1[0][i].y);\r
+                       v.put((float)v1[0][i].z);\r
+                       n.put((float)v1[1][i].x);\r
+                       n.put((float)v1[1][i].y);\r
+                       n.put((float)v1[1][i].z);\r
+            }\r
+               for (int i = 0; i < v2[0].length; i++) {\r
+                       v.put((float)v2[0][i].x);\r
+                       v.put((float)v2[0][i].y);\r
+                       v.put((float)v2[0][i].z);\r
+                       n.put((float)v2[1][i].x);\r
+                       n.put((float)v2[1][i].y);\r
+                       n.put((float)v2[1][i].z);\r
+            }\r
+               \r
+               IntBuffer i = BufferUtils.createIntBuffer(indexCount(RING_SEGMENTS, 2));\r
+               IntBuffer ei = BufferUtils.createIntBuffer(edgeIndexCount(RING_SEGMENTS, 2));\r
+               createIndices(i, RING_SEGMENTS, 2);\r
+               createEdgeIndices(ei, RING_SEGMENTS, 2);\r
+               m.reconstruct(v, n, null, null,i);\r
+               l.reconstruct(v, null, null, null,ei);\r
+               //return new Geometry[]{m,l};\r
+               return true;\r
+               \r
+        }\r
+        return false;\r
+\r
+       }\r
+       \r
+//     protected TopoDS_Shape getShape(double h, double r1, double r2, boolean eccentric) {\r
+//             TopoDS_Shape S4 = null;\r
+//\r
+//             gp_Circ circ1 = new gp_Circ(new double[] { -h * 0.5, 0.0,  0.0, 1.0, 0.0, 0.0 }, r1);\r
+//             TopoDS_Edge ed1 = (TopoDS_Edge) new BRepBuilderAPI_MakeEdge(circ1)\r
+//                             .shape();\r
+//             TopoDS_Wire w1 = (TopoDS_Wire) new BRepBuilderAPI_MakeWire(ed1).shape();\r
+//             gp_Circ circ2 = new gp_Circ(new double[] { h * 0.5, 0.0, eccentric ? r1 - r2 : 0.0, 1.0, 0.0, 0.0 }, r2);\r
+//             TopoDS_Edge ed2 = (TopoDS_Edge) new BRepBuilderAPI_MakeEdge(circ2)\r
+//                             .shape();\r
+//             TopoDS_Wire w2 = (TopoDS_Wire) new BRepBuilderAPI_MakeWire(ed2).shape();\r
+////           BRepOffsetAPI_ThruSections generatorb = new BRepOffsetAPI_ThruSections(\r
+////                           true, false);\r
+//             BRepOffsetAPI_ThruSections generatorb = new BRepOffsetAPI_ThruSections(true, true);\r
+//             generatorb.addWire(w1);\r
+//             generatorb.addWire(w2);\r
+//             generatorb.build();\r
+//             S4 = generatorb.shape();\r
+//        return S4;\r
+//     }\r
+       \r
+       private boolean isValid(Vector3d v) {\r
+        if (Double.isInfinite(v.x) || \r
+                 Double.isNaN(v.x) ||\r
+                 Double.isInfinite(v.y) || \r
+                 Double.isNaN(v.y) ||\r
+                 Double.isInfinite(v.z) || \r
+                 Double.isNaN(v.z))\r
+            return false;\r
+        return true;\r
+    }\r
+       \r
+       private static Vector3d[][] calcCirc(int segmentCount,double x, double y, double z, double dx, double dy, double dz, double r) {\r
+               Vector3d res[][] = new Vector3d[2][segmentCount + 1];\r
+               Vector3d t = new Vector3d();\r
+               if (Math.abs(dy) + Math.abs(dz) < 0.001) {\r
+                       t.y = 1.0;\r
+               } else {\r
+                       t.x = 1.0;\r
+               }\r
+               Vector3d d = new Vector3d(dx,dy,dz);\r
+               Vector3d a = new Vector3d();\r
+               a.cross(t, d);\r
+               a.normalize();\r
+               a.scale(r);\r
+               Quat4d q = new Quat4d();\r
+               AxisAngle4d aa = new AxisAngle4d();\r
+               aa.x = dx;\r
+               aa.y = dy;\r
+               aa.z = dz;\r
+               for (int i = 0; i <= segmentCount; i++) {\r
+                       aa.angle = (double)i / (double) segmentCount * Math.PI * 2.0;\r
+                       q.set(aa);\r
+                       res[0][i] = new Vector3d();\r
+                       res[1][i] = new Vector3d();\r
+                       MathTools.rotate(q, a, res[0][i]);\r
+                       res[1][i].normalize(res[0][i]);\r
+                       //res[1][i].negate();\r
+                       res[0][i].x += x;\r
+                       res[0][i].y += y;\r
+                       res[0][i].z += z;       \r
+               }\r
+               return res;\r
+               \r
+       }\r
+       \r
+       private static int indexCount(int segmentCount, int ringCount) {\r
+               return 6 * segmentCount * (ringCount - 1);\r
+       }\r
+       \r
+       private static void createIndices(IntBuffer buf, int segmentCount, int ringCount) {\r
+               int s = segmentCount + 1;\r
+               for (int ring = 0; ring < ringCount - 1; ring++) {\r
+                       for (int segment = 0; segment < segmentCount; segment++) {\r
+                               int index = ring * s + segment;\r
+                               buf.put(index);\r
+                               buf.put(index + 1);\r
+                               buf.put(index + s);\r
+                               buf.put(index + s + 1);\r
+                               buf.put(index + s);\r
+                               buf.put(index + 1);\r
+                       }\r
+               }\r
+       }\r
+       \r
+       private static int edgeIndexCount(int segmentCount, int ringCount) {\r
+               if (ringCount > 1) {\r
+                       return segmentCount * 4 + ringCount * 4 * (segmentCount / 4);\r
+               } else {\r
+                       return ringCount * segmentCount * 2;\r
+               }\r
+       }\r
+       \r
+       private static void createEdgeIndices(IntBuffer buf, int segmentCount, int ringCount) {\r
+               int s = segmentCount + 1;\r
+               if (ringCount > 1) {\r
+                       int ring = 0;\r
+                       for (int segment = 0; segment < segmentCount; segment++) {\r
+                               int index = ring * s + segment;\r
+                               buf.put(index);\r
+                               buf.put(index + 1);\r
+                       }\r
+                       ring = ringCount - 1;\r
+                       for (int segment = 0; segment < segmentCount; segment++) {\r
+                               int index = ring * s + segment;\r
+                               buf.put(index);\r
+                               buf.put(index + 1);\r
+                       }\r
+                       int space = segmentCount / 4;\r
+                       for (ring = 0; ring < ringCount - 1; ring++) {\r
+                               for (int segment = 0; segment < segmentCount; segment+=space) {\r
+                                       int index = ring * s + segment;\r
+                                       buf.put(index);\r
+                                       buf.put(index + s);\r
+                               }\r
+                       }\r
+               } else {\r
+                       int ring = 0;\r
+                       for (int segment = 0; segment < segmentCount; segment++) {\r
+                               int index = ring * s + segment;\r
+                               buf.put(index);\r
+                               buf.put(index + 1);\r
+                       }\r
+               }\r
+               buf.limit(buf.position());\r
+               \r
+       }\r
+}\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/PipingRules.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/PipingRules.java
new file mode 100644 (file)
index 0000000..d7e1619
--- /dev/null
@@ -0,0 +1,1134 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007 VTT Technical Research Centre of Finland and others.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package fi.vtt.simantics.processeditor.common;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+\r
+import javax.vecmath.AxisAngle4d;\r
+import javax.vecmath.Point3d;\r
+import javax.vecmath.Vector3d;\r
+\r
+import org.simantics.db.Graph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.proconf.g3d.base.G3DTools;\r
+import org.simantics.proconf.g3d.base.MathTools;\r
+import org.simantics.utils.ErrorLogger;\r
+\r
+import fi.vtt.simantics.processeditor.ProcessResource;\r
+import fi.vtt.simantics.processeditor.stubs.PipeControlPoint;\r
+import fi.vtt.simantics.processeditor.stubs.PipeRun;\r
+import fi.vtt.simantics.processeditor.stubs.PipelineComponent;\r
+\r
+/**\r
+ * Rules that update pipeline.\r
+ * TODO : optimize, remove stubs\r
+ * \r
+ * FIXME : transformations\r
+ * \r
+ * TODO : FixedAngleTurnComponents are handled like VariableAngleTurnComponents\r
+ * \r
+ * \r
+ * @author Marko Luukkainen <Marko.Luukkainen@vtt.fi>\r
+ *\r
+ */\r
+public class PipingRules {\r
+       \r
+       private static final boolean DEBUG = false;\r
+       private static final boolean DUMMY = false;\r
+       \r
+       private static final double MIN_TURN_ANGLE = 0.01;\r
+       \r
+       private static final int REMOVE_NONE = 0;\r
+       private static final int REMOVE_START = 1;\r
+       private static final int REMOVE_END = 2;\r
+       private static final int REMOVE_BOTH = 3;\r
+       \r
+       private enum PathLegUpdateType {NONE,PREV,NEXT,PREV_S,NEXT_S};\r
+       \r
+       /**\r
+     * Rule\r
+     * \r
+     * @param resources\r
+     * @param pp\r
+     * @throws TransactionException\r
+     */\r
+    public static void pipeControlPointPositionUpdate(Graph g, Resource pp) {\r
+       \r
+       PipeControlPoint pcp = new PipeControlPoint(g,pp);\r
+        if (DEBUG) System.out.println("PipeControlPoint changed " + pp);\r
+        \r
+        boolean changed = ControlPointTools.isControlPointChanged(pcp);\r
+\r
+        \r
+        if (changed) {\r
+               if (pcp.isInstanceOf(ProcessResource.plant3Dresource.PathLegEndControlPoint)) {\r
+                       updatePathLegEndControlPoint(pcp);\r
+               } else {\r
+                       updateInlineControlPoint(pcp);\r
+               }\r
+        } \r
+        \r
+    }\r
+    \r
+  \r
+    \r
+    public static class ExpandIterInfo {\r
+       // these two are turn control points\r
+       private PipeControlPoint start; \r
+       private PipeControlPoint end;\r
+       private int type;\r
+       \r
+       public ExpandIterInfo() {\r
+               \r
+       }\r
+       \r
+       public ExpandIterInfo(PipeControlPoint tcp, int type) {\r
+               if (type == REMOVE_START)\r
+                       start = tcp;\r
+               else \r
+                       end = tcp;\r
+               this.type = type;\r
+       }\r
+       \r
+       public ExpandIterInfo(PipeControlPoint start, PipeControlPoint end) {\r
+               this.start = start;\r
+               this.end = end;\r
+               this.type = REMOVE_BOTH;\r
+       }\r
+       \r
+               public PipeControlPoint getEnd() {\r
+                       return end;\r
+               }\r
+               public void setEnd(PipeControlPoint end) {\r
+                       this.end = end;\r
+               }\r
+               public PipeControlPoint getStart() {\r
+                       return start;\r
+               }\r
+               public void setStart(PipeControlPoint start) {\r
+                       this.start = start;\r
+               }\r
+               public int getType() {\r
+                       return type;\r
+               }\r
+               public void setType(int type) {\r
+                       this.type = type;\r
+               }\r
+       \r
+       \r
+    }\r
+    \r
+    private static void updatePathLegEndControlPoint(PipeControlPoint pcp) {\r
+       if (DEBUG) System.out.println("PipingTools.updateRunEndControlPoint() " + pcp.getResource());\r
+       if (pcp.getNext() != null) {\r
+               updatePathLegNext(pcp,pcp,PathLegUpdateType.NEXT_S);\r
+       }\r
+       if (pcp.getPrevious() != null) {\r
+               updatePathLegPrev(pcp,pcp,PathLegUpdateType.PREV_S);\r
+       }\r
+       \r
+    }\r
+    \r
+    private static void updateInlineControlPoint(PipeControlPoint pcp)  {\r
+       if (DEBUG) System.out.println("PipingTools.updateInlineControlPoint() " + pcp.getResource());\r
+       PipeControlPoint start = ControlPointTools.findPreviousEnd(pcp);\r
+        updatePathLegNext(start,pcp,PathLegUpdateType.NONE);\r
+    }\r
+    \r
+    private static PipeControlPoint insertElbow(PipeControlPoint pcp1 , PipeControlPoint pcp2, Point3d pos)  {\r
+       if (DEBUG) System.out.println("PipingRules.insertElbow() " + pcp1.getResource() + " " + pcp2.getResource()+ " " + pos);\r
+       PipelineComponent elbow = PipingTools2.instantiatePipelineComponent(pcp1.getGraph(), ControlPointTools.getPipeRun(pcp1).getResource(), ProcessResource.plant3Dresource.Elbow);\r
+       PipeControlPoint pcp = elbow.getControlPoint();\r
\r
+               ControlPointTools.insertControlPoint(pcp, pcp1,pcp2);\r
+               \r
+               ControlPointTools.setWorldPosition(pcp, pos);\r
+\r
+        return pcp;\r
+    }\r
+    \r
+    private static void updatePathLegNext(PipeControlPoint start, PipeControlPoint updated, PathLegUpdateType lengthChange){\r
+       ArrayList<PipeControlPoint> list = new ArrayList<PipeControlPoint>();\r
+       PipeControlPoint end = ControlPointTools.findNextEnd(start,list);\r
+       // this is for inline cp that is also path leg end\r
+       if (start.equals(updated))\r
+               lengthChange = PathLegUpdateType.NEXT;\r
+       else if (end.equals(updated))\r
+               lengthChange = PathLegUpdateType.PREV;                  \r
+       updatePathLegNext(start, list, end, updated, lengthChange);\r
+    }\r
+    \r
+    private static void updatePathLegNext(PipeControlPoint start, ArrayList<PipeControlPoint> list, PipeControlPoint end, PipeControlPoint updated, PathLegUpdateType lengthChange) {\r
+        updatePathLeg(start,list,end,false,0,new ArrayList<ExpandIterInfo>(),updated, lengthChange);\r
+    }\r
+    \r
+    private static class UpdateStruct2 {\r
+       public PipeControlPoint start;\r
+               public Point3d startPoint;\r
+               public ArrayList<PipeControlPoint> list;\r
+               public PipeControlPoint end;\r
+               public Point3d endPoint;\r
+               public Vector3d dir;\r
+               public Vector3d offset;\r
+               public boolean hasOffsets;\r
+               public int iter;\r
+               public boolean reversed;\r
+               public ArrayList<ExpandIterInfo> toRemove;\r
+               public PipeControlPoint updated;\r
+               public UpdateStruct2(PipeControlPoint start, Point3d startPoint, ArrayList<PipeControlPoint> list, PipeControlPoint end, Point3d endPoint, Vector3d dir, Vector3d offset, boolean hasOffsets, int iter, boolean reversed, ArrayList<ExpandIterInfo> toRemove, PipeControlPoint updated) {\r
+                       super();\r
+                       this.start = start;\r
+                       this.startPoint = startPoint;\r
+                       this.list = list;\r
+                       this.end = end;\r
+                       this.endPoint = endPoint;\r
+                       this.dir = dir;\r
+                       this.offset = offset;\r
+                       this.hasOffsets = hasOffsets;\r
+                       this.iter = iter;\r
+                       this.reversed = reversed;\r
+                       this.toRemove = toRemove;\r
+                       this.updated = updated;\r
+               }\r
+               \r
+               public String toString() {\r
+                       return start.getResource() + " " + end.getResource() + " " + dir + " " + hasOffsets + " " + offset + " " + iter + " " + toRemove.size();\r
+               }\r
+               \r
+    }\r
+    \r
+    private static boolean calculateOffset(Point3d startPoint, Point3d endPoint, ArrayList<PipeControlPoint> list, Vector3d dir, Vector3d offset) {\r
+       boolean hasOffsets = false;\r
+       dir.set(startPoint);\r
+       dir.sub(endPoint);\r
+       dir.normalize();\r
+       offset.set(0.0,0.0,0.0);\r
+        for (PipeControlPoint icp : list) {\r
+               if (icp.isInstanceOf(ProcessResource.plant3Dresource.OffsettingPoint)) {\r
+                       hasOffsets = true;\r
+                       offset.add(ControlPointTools.getSizeChangeOffsetVector(icp,dir));\r
+               }\r
+               else if (icp.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)) \r
+                       ErrorLogger.defaultLogError("Updating pipe run, found offset controlpoint " + icp.getResource(), new Exception("ASSERT!"));\r
+        }\r
+        return hasOffsets;\r
+    }\r
+    \r
+    /**\r
+     * @param start starting point of the pipe run\r
+     * @param list list of inline control points in the pipe run\r
+     * @param end ending point of the pipe run\r
+     * @param reversed boolean flag indicating wether start or end control point was modified (if true then end point was modified)\r
+     * @throws TransactionException\r
+     */\r
+    private static void updatePathLeg(PipeControlPoint start, ArrayList<PipeControlPoint> list, PipeControlPoint end, boolean reversed, int iter, ArrayList<ExpandIterInfo> toRemove, PipeControlPoint updated, PathLegUpdateType lengthChange) {\r
+        // FIXME: direction is calculated wrong way!\r
+       boolean hasOffsets = false;\r
+        Vector3d offset = new Vector3d();\r
+        Point3d startPoint = G3DTools.getPoint(start.getWorldPosition());\r
+       Point3d endPoint = G3DTools.getPoint(end.getWorldPosition());\r
+       Vector3d dir = new Vector3d ();\r
+       hasOffsets = calculateOffset(startPoint, endPoint, list, dir, offset);\r
+        updatePathLeg(new UpdateStruct2(start, startPoint, list, end, endPoint, dir, offset, hasOffsets, iter, reversed, toRemove, updated), lengthChange);\r
+        \r
+    }\r
+    \r
+    private static void updatePathLeg(UpdateStruct2 u, PathLegUpdateType lengthChange){\r
+       int directed = 0;\r
+        if (u.start.isInstanceOf(ProcessResource.plant3Dresource.DirectedControlPoint))\r
+               directed ++;\r
+        if (u.end.isInstanceOf(ProcessResource.plant3Dresource.DirectedControlPoint))\r
+               directed++;\r
+        switch (directed) {\r
+        case 0:\r
+               updateFreePathLeg(u,lengthChange);\r
+               break;\r
+        case 1:\r
+               updateDirectedPathLeg(u,lengthChange);\r
+               break;\r
+        case 2:\r
+               updateDualDirectedPathLeg(u,lengthChange);\r
+               break;\r
+        }\r
+       \r
+       }\r
+    \r
+    private static void updateFreePathLeg(UpdateStruct2 u, PathLegUpdateType lengthChange) {\r
+       if (DEBUG) System.out.println("PipingRules.updateFreePipeRun " + u + " " + lengthChange);\r
+       checkExpandPathLeg(u, lengthChange);\r
+       }\r
+    \r
+    private static void updateInlineControlPoints(UpdateStruct2 u, boolean checkSizes) {\r
+       if (DEBUG) System.out.println("PipingTools.updateInlineControlPoints() " + u);\r
+       \r
+       if (!u.hasOffsets) {\r
+               // FIXME : cache positions\r
+               if (!checkSizes) {\r
+                       for (PipeControlPoint icp : u.list) {\r
+                               updateInlineControlPoint(icp, u.startPoint, u.endPoint,u.dir);\r
+                       }\r
+                       return;\r
+               }\r
+               \r
+               ArrayList<PipeControlPoint> pathLegPoints = new ArrayList<PipeControlPoint>();\r
+               pathLegPoints.add(u.start);\r
+                       for (PipeControlPoint icp : u.list) {\r
+                               //updateInlineControlPoint(icp, u.startPoint, u.endPoint,u.dir);\r
+                               updateBranchControlPointBranches(icp);\r
+                               pathLegPoints.add(icp);\r
+                       }\r
+                       pathLegPoints.add(u.end);\r
+                       \r
+                       // TODO : values can be cached in the loop\r
+                       for (int i = 1; i < pathLegPoints.size(); i++) {\r
+                               PipeControlPoint icp = pathLegPoints.get(i);\r
+\r
+                               PipeControlPoint prev;\r
+                               Point3d prevPos;\r
+                               prev = pathLegPoints.get(i-1);\r
+                               prevPos = G3DTools.getPoint(prev.getWorldPosition());\r
+                               Point3d currentPos = G3DTools.getPoint(icp.getWorldPosition());\r
+                               \r
+                               if (icp.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthControlPoint)) {     \r
+                                       if (i != pathLegPoints.size() - 1) {\r
+                                               PipeControlPoint next;\r
+                                               Point3d nextPos;\r
+                                               next = pathLegPoints.get(i + 1);\r
+                                               nextPos = G3DTools.getPoint(next.getWorldPosition());\r
+                                               Vector3d dir = new Vector3d(nextPos);\r
+                                               dir.sub(prevPos);\r
+                                               double l = dir.lengthSquared();          // distance between control points (square)\r
+                                               double l2prev = ControlPointTools.getInlineLength(prev);          // distance taken by components\r
+                                               double l2next = ControlPointTools.getInlineLength(next); \r
+                                               double l2 = l2prev + l2next;\r
+                                               double l2s = MathTools.square(l2);\r
+                                               if (l2s < l) {                         // check if there is enough space for variable length component.\r
+                                                       // components fit\r
+                                                       dir.normalize();\r
+                                                       double length = Math.sqrt(l) - l2; // true length of the variable length component \r
+                                                       dir.scale(length*0.5 + l2prev);      // calculate center position of the component\r
+                                                       dir.add(prevPos);\r
+                                                       ControlPointTools.setWorldPosition(icp,dir);\r
+                                                       icp.setRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength, length);\r
+                                               } else {\r
+                                                       //components leave no space to the component and it must be removed\r
+                                                       ControlPointTools.removeControlPoint(icp);\r
+                                               }\r
+\r
+                                       } else {\r
+                                               // this is variable length component at the end of the piperun.\r
+                                               // the problem is that we want to keep unconnected end of the component in the same\r
+                                               // place, but center of the component must be moved.\r
+                                               double currentLength = icp.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength);\r
+                                               Vector3d dir = new Vector3d();\r
+                                               dir.sub(currentPos,prevPos);\r
+                                               dir.normalize();\r
+                                               Point3d endPos = new Point3d(dir);\r
+                                               endPos.scale(currentLength * 0.5);\r
+                                               endPos.add(currentPos);             //this is the free end of the component\r
+                                               \r
+                                               double offset = ControlPointTools.getInlineLength(prev);\r
+                                               Point3d beginPos = new Point3d(dir);\r
+                                               beginPos.scale(offset);\r
+                                               beginPos.add(prevPos);              //this is the connected end of the component\r
+                                               \r
+                                               double l = beginPos.distance(endPos);\r
+                                               \r
+                                               dir.scale(l*0.5);\r
+                                               beginPos.add(dir);                  //center position\r
+                                               \r
+                                               if (DEBUG) System.out.println("PipingRules.updateInlineControlPoints() setting variable length to " + l);\r
+                                               icp.setRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength, l);\r
+                                               \r
+                                               ControlPointTools.setWorldPosition(icp, beginPos);\r
+                                       }\r
+                                       i++;\r
+                                       \r
+                               } else if (!prev.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthControlPoint)){\r
+                                       // If this and previous control point are not variable length pcps, we'll have to check if there is no empty space between them.\r
+                                       // I there is, we'll have to create new variable length component between them.\r
+                                       Vector3d dir = new Vector3d(currentPos);\r
+                                       dir.sub(prevPos);\r
+                                       double l = dir.lengthSquared();\r
+                                       double l2prev = ControlPointTools.getInlineLength(prev);\r
+                                       double l2next = ControlPointTools.getInlineLength(icp);\r
+                                       double l2 = l2prev + l2next;\r
+                                       double l2s = l2 * l2;\r
+                                       if (l > l2s) {\r
+                                               PipelineComponent component = PipingTools2.instantiatePipelineComponent(prev.getGraph(), ControlPointTools.getPipeRun(prev).getResource(), ProcessResource.plant3Dresource.Straight);\r
+                                               PipeControlPoint scp = component.getControlPoint();\r
+                                               ControlPointTools.insertControlPoint(scp, prev, icp);\r
+                                               \r
+                                               dir.normalize();\r
+                                               double length = Math.sqrt(l) - l2; // true length of the variable length component \r
+                                               dir.scale(length*0.5 + l2prev);      // calculate center position of the component\r
+                                               dir.add(prevPos);\r
+                                               ControlPointTools.setWorldPosition(scp, dir);\r
+                                               scp.setRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength, length);\r
+                                       }\r
+                               }\r
+                       }\r
+               } else {\r
+                       u.endPoint.sub(u.offset);\r
+                       // FIXME : straights\r
+                       for (PipeControlPoint icp : u.list) {\r
+                               updateInlineControlPoint(icp, u.startPoint, u.endPoint,u.dir);\r
+                               updateBranchControlPointBranches(icp);\r
+                               if (icp.isInstanceOf(ProcessResource.plant3Dresource.OffsettingPoint)) {\r
+                                       // TODO : offset vector is already calculated and should be\r
+                                       // cached\r
+                                       u.offset = ControlPointTools.getSizeChangeOffsetVector(icp, u.dir);\r
+                                       updateOffsetPoint( icp, u.offset);\r
+                                       u.startPoint.add(u.offset);\r
+                                       u.endPoint.add(u.offset);\r
+                               }\r
+                       }\r
+               }\r
+    }\r
+    \r
+    \r
+    \r
+    private static void ppNoOffset(UpdateStruct2 u) {\r
+       if (DEBUG)System.out.println("PipingRules.ppNoOffset() " + u);\r
+       Vector3d offset = new Vector3d();\r
+               if (u.hasOffsets) {\r
+               u.dir.normalize();\r
+               for (PipeControlPoint icp : u.list) {\r
+                       if (icp.isInstanceOf(ProcessResource.plant3Dresource.OffsettingPoint)) {\r
+                               offset.add(ControlPointTools.getSizeChangeOffsetVector(icp,u.dir));\r
+                       }\r
+                       else if (icp.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)) \r
+                               ErrorLogger.defaultLogError("Updating pipe run, found offset controlpoint " + icp.getResource(), new Exception("ASSERT!"));\r
+               }\r
+               }\r
+               u.offset = offset;\r
+               checkExpandPathLeg(u,PathLegUpdateType.NONE);\r
+    }\r
+    \r
+    private static void ppNoDir(PipeControlPoint start, Point3d startPoint,ArrayList<PipeControlPoint> list, PipeControlPoint end,Point3d endPoint, boolean hasOffsets,int iter,boolean reversed, ArrayList<ExpandIterInfo> toRemove, PipeControlPoint updated)  {\r
+       if (DEBUG)System.out.println("PipingRules.ppNoDir() " + start.getResource() + " " + end.getResource() + " " + iter + " " + toRemove.size());\r
+       // FIXME : extra loop (dir should be calculated here)\r
+       Vector3d dir = new Vector3d();\r
+       Vector3d offset = new Vector3d();\r
+       hasOffsets = calculateOffset(startPoint, endPoint, list, dir, offset);\r
+       ppNoOffset(new UpdateStruct2(start, startPoint, list, end, endPoint, dir, null, hasOffsets, iter, reversed, toRemove,updated));\r
+    }\r
+    \r
+    private static void checkExpandPathLeg(UpdateStruct2 u, PathLegUpdateType lengthChange)  {\r
+       if (DEBUG)System.out.println("PipingRules.checkExpandPathLeg() " + u + " " + lengthChange);\r
+       if (lengthChange != PathLegUpdateType.NONE) {\r
+               // FIXME : turns cannot be checked before inline cps are updated, since their position affects calculation of turns \r
+               processPathLeg(u,false,false);\r
+               int type = checkTurns(u,lengthChange);\r
+               if (type == REMOVE_NONE) {\r
+                               processPathLeg(u,false,true);\r
+                       } else {\r
+                               expandPathLeg(u, type);\r
+                       }\r
+       } else {\r
+               processPathLeg(u,false,true);\r
+       }\r
+    }\r
+    \r
+    private static void updateDirectedPathLeg(UpdateStruct2 u, PathLegUpdateType lengthChange) {\r
+               if (DEBUG)System.out.println("PipingRules.updateDirectedPipeRun() " + u + " " + lengthChange);\r
+               PipeControlPoint dcp;\r
+               PipeControlPoint other;\r
+               boolean canMoveOther = false;\r
+               boolean dcpStart = false;\r
+               Point3d position;\r
+               if (u.start.isInstanceOf(ProcessResource.plant3Dresource.DirectedControlPoint)) {\r
+                       dcp = u.start;\r
+                       other = u.end;\r
+                       position = u.startPoint;\r
+                       dcpStart = true;\r
+                       if (!u.reversed)\r
+                               canMoveOther = true;\r
+               } else {\r
+                       dcp = u.end;\r
+                       other = u.start;\r
+                       position = u.endPoint;\r
+                       if (u.reversed)\r
+                               canMoveOther = true;\r
+               }\r
+\r
+               Vector3d directedDirection = ControlPointTools.getDirectedControlPointDirection(dcp);\r
+               Point3d directedEndPoint = new Point3d(u.endPoint);\r
+               if (u.hasOffsets)\r
+                       directedEndPoint.add(u.offset);\r
+\r
+               double mu[] = new double[2];\r
+\r
+               Vector3d closest;\r
+               Vector3d t = new Vector3d();\r
+      \r
+               if (dcpStart) {\r
+                       closest = MathTools.closestPointOnStraight(directedEndPoint, u.startPoint, directedDirection, mu);\r
+                       t.sub(closest, directedEndPoint);\r
+               } else {\r
+                       closest = MathTools.closestPointOnStraight(u.startPoint, directedEndPoint, directedDirection, mu);\r
+                       t.sub(closest, u.startPoint);\r
+               }\r
+\r
+      \r
+      double distance = t.lengthSquared();\r
+      boolean aligned = (distance < 0.001);\r
+      if (aligned) {\r
+         checkExpandPathLeg(u,lengthChange);\r
+      } else {\r
+         if (u.iter > 0) {\r
+                  backIter(u);\r
+         } else {\r
+                       PipeControlPoint nextToMoved;\r
+                       \r
+                               if (u.list.size() > 0)\r
+                                       if (dcpStart)\r
+                                               nextToMoved = u.list.get(0);\r
+                                       else\r
+                                               nextToMoved = u.list.get(u.list.size() - 1);\r
+                               else if (dcpStart)\r
+                                       nextToMoved = u.end;\r
+                               else\r
+                                       nextToMoved = u.start;\r
+                               if (other.isInstanceOf(ProcessResource.plant3Dresource.VariableAngleTurnControlPoint)) {\r
+                                       \r
+                                       // TODO calculate needed space from next run end.\r
+                                       if (mu[0] < 1.0) {\r
+                                               if (dcpStart) {\r
+                                                       closest.set(u.startPoint);      \r
+                                               } else {\r
+                                                       closest.set(u.endPoint);\r
+                                               }\r
+                                               closest.add(directedDirection);\r
+                                       }\r
+\r
+                                       if (canMoveOther) {\r
+                                               if (DEBUG)System.out.println("PipingRules.updateDirectedPipeRun() moved end " + other.getResource() + " to " + closest);\r
+                                               ControlPointTools.setWorldPosition(other, closest);\r
+                                               if (dcpStart) {\r
+                                                       ppNoOffset(new UpdateStruct2(u.start, u.startPoint, u.list, u.end, new Point3d(closest), directedDirection,null, u.hasOffsets, u.iter, u.reversed, u.toRemove,u.updated));\r
+                                                       if (u.end.getNext() != null)\r
+                                                               updatePathLegNext(u.end,u.updated,PathLegUpdateType.NEXT);\r
+                                               } else {\r
+                                                       ppNoOffset(new UpdateStruct2(u.start, new Point3d(closest), u.list, u.end, u.endPoint, directedDirection,null, u.hasOffsets, u.iter, u.reversed, u.toRemove,u.updated));        \r
+                                                       if (u.start.getPrevious() != null)\r
+                                                               updatePathLegPrev(u.start,u.updated,PathLegUpdateType.PREV);\r
+                                               }\r
+                                       } else {\r
+                                               // TODO : calculate needed space from next run end.\r
+                                               insertElbowUpdate(u, dcp, nextToMoved, dcpStart, position, directedDirection);\r
+                                       }\r
+                               } else if (other.isInstanceOf(ProcessResource.plant3Dresource.UndirectedControlPoint) &&\r
+                                                  other.getSubPointOf() != null) {\r
+                                       // FIXME : this code was for updating branches\r
+                                       Vector3d bintersect = new Vector3d();\r
+                                       PipeControlPoint bcp = other.getSubPointOf();\r
+                                       if (bcp != null && canMoveOther) {\r
+                                               Point3d bstart = new Point3d();\r
+                                               Point3d bend = new Point3d();\r
+                                               Vector3d bdir = new Vector3d();\r
+                                               ControlPointTools.getInlineControlPointEnds(bcp, bstart, bend, bdir);\r
+                                               Vector3d nintersect = new Vector3d();\r
+                                               \r
+                                               MathTools.intersectStraightStraight(position, directedDirection, bstart,\r
+                                                       bdir, nintersect, bintersect, mu);\r
+                                               Vector3d dist = new Vector3d(nintersect);\r
+                                               dist.sub(bintersect);\r
+                                               canMoveOther = mu[1] > 0.0 && mu[1] < 1.0 && dist.lengthSquared() < 0.01;\r
+                                       } else {\r
+                                               // TODO : endControlPoints are undirected: calculcate correct position for it\r
+                                               throw new UnsupportedOperationException("not implemented");\r
+                                       }\r
+                                       if (canMoveOther) { \r
+                                               if (DEBUG) System.out.println("PipingRules.updateDirectedPipeRun() moved end " + other.getResource() + " to " + bintersect);\r
+                                               // is required branch position is in possible range\r
+                                               ControlPointTools.setWorldPosition(bcp, bintersect);\r
+                                               if (dcpStart) {\r
+                                                       checkExpandPathLeg(new UpdateStruct2(u.start, u.startPoint, u.list, u.end, new Point3d(bintersect),directedDirection, u.offset, u.hasOffsets, u.iter, u.reversed, u.toRemove,u.updated),lengthChange);\r
+                                               } else {\r
+                                                       checkExpandPathLeg(new UpdateStruct2(u.start, new Point3d(bintersect), u.list, u.end, u.endPoint,directedDirection, u.offset, u.hasOffsets, u.iter, u.reversed, u.toRemove,u.updated),lengthChange);    \r
+                                               }\r
+                                       } else {\r
+                                               // branch cannot be moved into right position, new turn\r
+                                               // / elbow must be inserted\r
+                                               insertElbowUpdate(u , dcp, nextToMoved, dcpStart, position, directedDirection);\r
+                                       }\r
+\r
+                               } else { // assume that control point cannot be moved, but can be rotated\r
+                                       insertElbowUpdate(u, dcp, nextToMoved, dcpStart, position, directedDirection);\r
+                               }\r
+         }\r
+      }\r
+       }\r
+    \r
+    \r
+    \r
+    private static void updateDualDirectedPathLeg(UpdateStruct2 u, PathLegUpdateType lengthChange) {\r
+               if (DEBUG) System.out.println("PipingRules.updateDualDirectedPipeRun() " + u + " " + lengthChange);\r
+\r
+               PipeControlPoint dcp1 = u.start;\r
+               PipeControlPoint dcp2 = u.end;\r
+               Point3d position1 = u.startPoint;\r
+               Point3d position2 = u.endPoint;\r
+               Point3d position1offset = new Point3d(position1);\r
+               position1offset.sub(u.offset);\r
+               Point3d position2offset = new Point3d(position2);\r
+               position2offset.add(u.offset);\r
+               Vector3d dir1 = ControlPointTools.getDirectedControlPointDirection(dcp1);\r
+               Vector3d dir2 = ControlPointTools.getDirectedControlPointDirection(dcp2);\r
+               Vector3d p1 = MathTools.closestPointOnStraight(position1offset, position2, dir2);\r
+               Vector3d p2 = MathTools.closestPointOnStraight(position2offset, position1, dir1);\r
+               double d1 = position1.distance(new Point3d(p1));\r
+               double d2 = position2.distance(new Point3d(p2));\r
+\r
+               boolean aligned = (d1 < 0.01 && d2 < 0.01);\r
+               if (aligned) {\r
+                       processPathLeg(u);\r
+               } else {\r
+                       if (u.iter > 0) {\r
+                               backIter(u);\r
+                       } else {\r
+                               PipeControlPoint dcp;\r
+                               PipeControlPoint next;\r
+                               if (!u.reversed) {\r
+                                       dcp = dcp1;\r
+                                       if (u.list.size() > 0)\r
+                                               next = u.list.get(0);\r
+                                       else\r
+                                               next = dcp2;\r
+                               } else {\r
+                                       dcp = dcp2;\r
+                                       if (u.list.size() > 0)\r
+                                               next = u.list.get(u.list.size() - 1);\r
+                                       else\r
+                                               next = dcp1;\r
+                               }\r
+\r
+                               PipeRun pipeline = ControlPointTools.getPipeRun(dcp1);\r
+                               PipelineComponent elbow1 = PipingTools2.instantiatePipelineComponent(u.start.getGraph(), pipeline.getResource(), ProcessResource.plant3Dresource.Elbow);\r
+                               PipelineComponent elbow2 = PipingTools2.instantiatePipelineComponent(u.start.getGraph(), pipeline.getResource(), ProcessResource.plant3Dresource.Elbow);\r
+                               \r
+                               PipeControlPoint tcp1 = elbow1.getControlPoint();\r
+                               PipeControlPoint tcp2 = elbow2.getControlPoint();\r
+                               \r
+                               // Straight s1 = getStraight(dcp, next);\r
+                               ControlPointTools.insertControlPoint(tcp1, dcp, next);\r
+                               // s1 = getStraight(tcp1, next);\r
+                               ControlPointTools.insertControlPoint(tcp2, tcp1, next);\r
+                               p1 = G3DTools.getVector(dcp.getLocalPosition());\r
+                               if (!u.reversed)\r
+                                       p1.add(dir1);\r
+                               else\r
+                                       p1.add(dir2);\r
+                               \r
+                               if (!u.reversed)\r
+                                       p2 = MathTools.closestPointOnStraight(new Point3d(p1), position2, dir2);\r
+                               else\r
+                                       p2 = MathTools.closestPointOnStraight(new Point3d(p1), position1, dir1);\r
+                               \r
+                               ControlPointTools.setWorldPosition(tcp1, p1);\r
+                               ControlPointTools.setWorldPosition(tcp2, p2);\r
+                               \r
+                               if (DEBUG) System.out.println("PipingRules.updateDualDirectedPipeRun() created two turns " + tcp1.getResource() + " " + tcp2.getResource());\r
+\r
+                               if (!u.reversed) {\r
+                                       Vector3d dd = new Vector3d(p2);\r
+                                       dd.sub(p1);\r
+                                       dir2.negate();\r
+                                       processPathLeg(new UpdateStruct2(u.start, u.startPoint,new ArrayList<PipeControlPoint>(), tcp1, new Point3d(p1),dir1, new Vector3d(), false, 0, false,new ArrayList<ExpandIterInfo>(), u.updated));\r
+                                       processPathLeg(new UpdateStruct2(tcp1,new Point3d(p1), new ArrayList<PipeControlPoint>(),tcp2, new Point3d(p2), dd,new Vector3d(), false, 0, false,new ArrayList<ExpandIterInfo>(), u.updated));\r
+                                       // offset is recalculated\r
+                                       processPathLegNoOffset(new UpdateStruct2(tcp2, new Point3d(p2), u.list,u.end, u.endPoint, dir2, null, u.hasOffsets,u.iter, u.reversed, u.toRemove, u.updated));\r
+                               } else {\r
+                                       Vector3d dd = new Vector3d(p1);\r
+                                       dd.sub(p2);\r
+                                       dir2.negate();\r
+                                       processPathLeg(new UpdateStruct2(tcp1,new Point3d(p1), new ArrayList<PipeControlPoint>(),u.end, u.endPoint, dir2, new Vector3d(), false, 0,false, new ArrayList<ExpandIterInfo>(), u.updated));\r
+                                       processPathLeg(new UpdateStruct2(tcp2,new Point3d(p2), new ArrayList<PipeControlPoint>(),tcp1, new Point3d(p1), dd,new Vector3d(), false, 0, false,new ArrayList<ExpandIterInfo>(), u.updated));\r
+                                       // offset is recalculated\r
+                                       processPathLegNoOffset(new UpdateStruct2(u.start, u.startPoint,u.list, tcp2, new Point3d(p2),dir1, null, u.hasOffsets, u.iter, u.reversed,u.toRemove, u.updated));\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+    \r
+    private static void insertElbowUpdate(UpdateStruct2 u, PipeControlPoint dcp, PipeControlPoint next, boolean dcpStart, Point3d position, Vector3d directedDirection) {\r
+        \r
+       Vector3d closest = new Vector3d(position);\r
+               closest.add(directedDirection);\r
+               PipeControlPoint tcp = insertElbow(dcp, next, new Point3d(closest));\r
+\r
+               if (DEBUG) System.out.println("PipingRules.updateDirectedPipeRun() inserted " + tcp.getResource());\r
+               \r
+               if (dcpStart) {\r
+                       // update pipe run from new turn to other end\r
+                       ppNoDir(tcp, new Point3d(closest), u.list, u.end, u.endPoint, u.hasOffsets, u.iter, u.reversed, u.toRemove, u.updated);\r
+                       // update pipe run from directed to new turn\r
+                       processPathLeg(new UpdateStruct2(u.start, u.startPoint, new ArrayList<PipeControlPoint>(), tcp, new Point3d(closest), directedDirection, new Vector3d(), false, 0, false, new ArrayList<ExpandIterInfo>(),u.updated));                  \r
+               } else {\r
+                       // update pipe run from other end to new turn\r
+                       ppNoDir(u.start, u.startPoint, u.list, tcp, new Point3d(closest),  u.hasOffsets, u.iter, u.reversed, u.toRemove,u.updated);\r
+                       // update pipe run from new turn to directed\r
+                       processPathLeg(new UpdateStruct2(tcp, new Point3d(closest), new ArrayList<PipeControlPoint>(), u.end, u.endPoint, directedDirection, new Vector3d(), false, 0, false, new ArrayList<ExpandIterInfo>(),u.updated));\r
+               }\r
+    }\r
+    \r
+    /**\r
+     * Checks if turns can be removed (turn angle near zero)\r
+     */\r
+    private static int checkTurns(UpdateStruct2 u, PathLegUpdateType lengthChange) {\r
+               if (DEBUG)\r
+                       System.out.println("PipingRules.checkTurns() " + u.start.getResource()\r
+                                       + " " + u.end.getResource());\r
+               boolean startRemoved = false;\r
+               boolean endRemoved = false;\r
+               if (u.start.isInstanceOf(ProcessResource.plant3Dresource.VariableAngleTurnControlPoint)) {\r
+                       // this won't work properly if inline control points are not updated\r
+                       PipeControlPoint startPrev = u.start.getPrevious();\r
+                       if (startPrev != null) {\r
+                               double a;\r
+                               if (!u.hasOffsets) {\r
+                                       a = updateTurnControlPointTurn( u.start, startPrev, u.end);\r
+                               } else {\r
+                                       Point3d ep = new Point3d(u.endPoint);\r
+                                       ep.add(u.offset);\r
+                                       a = updateTurnControlPointTurn( u.start,u.startPoint, G3DTools.getPoint(startPrev.getLocalPosition()), ep);\r
+\r
+                               }\r
+                               if (a < MIN_TURN_ANGLE)\r
+                                       startRemoved = true;\r
+                               else if (lengthChange == PathLegUpdateType.PREV || lengthChange == PathLegUpdateType.PREV_S){\r
+                                       PathLegUpdateType type;\r
+                                       if (lengthChange == PathLegUpdateType.PREV_S)\r
+                                               type = PathLegUpdateType.PREV;\r
+                                       else\r
+                                               type = PathLegUpdateType.NONE;\r
+                                       updatePathLegPrev(u.start, u.start, type);\r
+                               }\r
+                       }\r
+               }\r
+               if (u.end.isInstanceOf(ProcessResource.plant3Dresource.VariableAngleTurnControlPoint)) {\r
+\r
+                       PipeControlPoint endNext = u.end.getNext();\r
+                       if (endNext != null) {\r
+                               double a;\r
+                               if (!u.hasOffsets) {\r
+                                       a = updateTurnControlPointTurn(u.end,u.start, endNext);\r
+                               } else {\r
+                                       Point3d sp = new Point3d(u.startPoint);\r
+                                       sp.sub(u.offset);\r
+                                       a = updateTurnControlPointTurn(u.end, u.endPoint, sp, G3DTools.getPoint(endNext.getLocalPosition()));\r
+                               }\r
+                               if (a < MIN_TURN_ANGLE)\r
+                                       endRemoved = true;\r
+                               else if (lengthChange == PathLegUpdateType.NEXT || lengthChange == PathLegUpdateType.NEXT_S){\r
+                                       PathLegUpdateType type;\r
+                                       if (lengthChange == PathLegUpdateType.NEXT_S)\r
+                                               type = PathLegUpdateType.NEXT;\r
+                                       else\r
+                                               type = PathLegUpdateType.NONE;\r
+                                       updatePathLegNext(u.end, u.end,type);\r
+                               }\r
+                       }\r
+               }\r
+               if (DEBUG)\r
+                       System.out.println("PipingRules.checkTurns() res " + startRemoved + " " + endRemoved);\r
+               if (!startRemoved && !endRemoved)\r
+                       return REMOVE_NONE;\r
+               if (startRemoved && endRemoved)\r
+                       return REMOVE_BOTH;\r
+               if (startRemoved)\r
+                       return REMOVE_START;\r
+               return REMOVE_END;\r
+       }\r
+    \r
+    /**\r
+        * Expands piperun search over turns that are going to be removed\r
+        * \r
+        */\r
+    private static void expandPathLeg(UpdateStruct2 u, int type) {\r
+       if (DEBUG) System.out.println("PipingRules.expandPipeline " + u.start.getResource() + " " + u.end.getResource());\r
+       ArrayList<PipeControlPoint> newList = new ArrayList<PipeControlPoint> ();\r
+       switch (type) {\r
+       case REMOVE_NONE :\r
+               throw new RuntimeException("Error in piping rules");\r
+       case REMOVE_START :\r
+               u.toRemove.add(new ExpandIterInfo(u.start,REMOVE_START));\r
+               u.start = ControlPointTools.findPreviousEnd(u.start);\r
+               u.startPoint = G3DTools.getPoint(u.start.getLocalPosition());\r
+               ControlPointTools.findNextEnd(u.start,newList);\r
+               newList.addAll(u.list);\r
+               u.list = newList;\r
+               break;\r
+       case REMOVE_END :\r
+               u.toRemove.add(new ExpandIterInfo(u.end,REMOVE_END));\r
+               u.end = ControlPointTools.findNextEnd(u.end,newList);\r
+               u.endPoint = G3DTools.getPoint(u.end.getLocalPosition());\r
+               u.list.addAll(newList);\r
+               break;\r
+       case REMOVE_BOTH :\r
+               u.toRemove.add(new ExpandIterInfo(u.start,u.end));\r
+               u.start = ControlPointTools.findPreviousEnd(u.start);\r
+               u.startPoint = G3DTools.getPoint(u.start.getLocalPosition());\r
+               ControlPointTools.findNextEnd(u.start,newList);\r
+               newList.addAll(u.list);\r
+               u.list = newList;\r
+               newList = new ArrayList<PipeControlPoint> ();\r
+               u.end = ControlPointTools.findNextEnd(u.end,newList);\r
+               u.endPoint = G3DTools.getPoint(u.end.getLocalPosition());\r
+               u.list.addAll(newList);\r
+               break;\r
+       default:\r
+               throw new RuntimeException("Error in piping rules");\r
+                       \r
+       }\r
+       u.offset = new Vector3d();\r
+       if (u.hasOffsets) {\r
+               u.dir.normalize();\r
+               for (PipeControlPoint icp : u.list) {\r
+                       if (icp.isInstanceOf(ProcessResource.plant3Dresource.OffsettingPoint)) {\r
+                               u.offset.add(ControlPointTools.getSizeChangeOffsetVector(icp,u.dir));\r
+                       }\r
+                       else if (icp.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)) \r
+                               ErrorLogger.defaultLogError("Updating pipe run, found offset controlpoint " + icp.getResource(), new Exception("ASSERT!"));\r
+               }\r
+               }\r
+       if (DEBUG) System.out.println("PipingRules.expandPipeline expanded " + u.start.getResource() + " " + u.end.getResource());\r
+       u.iter++;\r
+       updatePathLeg(u,PathLegUpdateType.NONE);\r
+    }\r
+    \r
+    /**\r
+        * reverts one iteration of turn removing back)\r
+     */\r
+    private static void backIter(UpdateStruct2 u) {\r
+               \r
+               if (DEBUG) System.out.println("PipingRules.backIter" + u.start.getResource() + " " + u.end.getResource());      \r
+               if (u.iter == 0)\r
+                       throw new RuntimeException("Error in piping rules");\r
+               ExpandIterInfo info = u.toRemove.get(u.toRemove.size()-1);\r
+               u.toRemove.remove(u.toRemove.size()-1);\r
+               if (info.getType() == REMOVE_START || info.getType() == REMOVE_BOTH) {\r
+                       while (u.list.size() > 0) {\r
+                               PipeControlPoint icp = u.list.get(0);\r
+                               if (icp.getPrevious().getResource().equals(info.getStart().getResource()))  \r
+                                       break;\r
+                               u.list.remove(icp);\r
+                       }\r
+                       u.start = info.getStart();      \r
+               } \r
+               if (info.getType() == REMOVE_END || info.getType() == REMOVE_BOTH) {\r
+                       while (u.list.size() > 0) {\r
+                               PipeControlPoint icp = u.list.get(u.list.size() - 1);\r
+                               if (icp.getNext().getResource().equals(info.getEnd().getResource())) \r
+                                       break;\r
+                               u.list.remove(icp);\r
+                       }\r
+                       u.end = info.getEnd();\r
+               }\r
+               u.offset = new Vector3d();\r
+               if (u.hasOffsets) {\r
+               u.dir.normalize();\r
+               for (PipeControlPoint icp : u.list) {\r
+                       if (icp.isInstanceOf(ProcessResource.plant3Dresource.OffsettingPoint)) {\r
+                               u.offset.add(ControlPointTools.getSizeChangeOffsetVector(icp,u.dir));\r
+                       }\r
+                       else if (icp.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)) \r
+                               ErrorLogger.defaultLogError("Updating pipe run, found offset controlpoint " + icp.getResource(), new Exception("ASSERT!"));\r
+               }\r
+               }\r
+               processPathLeg(u);\r
+       \r
+    }\r
+    \r
+    /**\r
+     * Processes pipe run (removes necessary turns and updates run ends)\r
+     */\r
+   // private static void processPathLeg(PipeControlPoint start, Point3d startPoint,ArrayList<InlineControlPoint> list, PipeControlPoint end,Point3d endPoint, Vector3d dir,Vector3d offset, boolean hasOffsets,int iter, boolean reversed, ArrayList<ExpandIterInfo> toRemove) throws TransactionException {\r
+         \r
+    private static void processPathLeg(UpdateStruct2 u) {\r
+       if (DEBUG) System.out.println("PipingRules.processPathLeg " + u.start.getResource() + " " + u.end.getResource());\r
+       processPathLeg(u, true, true);\r
+    }\r
+    \r
+    \r
+    private static void processPathLeg(UpdateStruct2 u, boolean updateEnds, boolean updateInline) {\r
+       if (DEBUG) System.out.println("PipingRules.processPathLeg " + u.start.getResource() + " " + u.end.getResource());\r
+       if (u.toRemove.size() > 0) {\r
+               for (ExpandIterInfo info : u.toRemove) {\r
+                       if (info.getStart() != null) {\r
+                               ControlPointTools.removeControlPoint(info.getStart());\r
+                       }\r
+                       if (info.getEnd() != null) {\r
+                               ControlPointTools.removeControlPoint(info.getEnd());\r
+                       }\r
+               }\r
+               // ControlPointTools.removeControlPoint may remove mo0re than one CP;\r
+               // we must populate inline CP list again.\r
+               u.list.clear();\r
+               ControlPointTools.findNextEnd(u.start, u.list);\r
+               }\r
+       // FIXME : inline CPs are update twice because their positions must be updated before and after ends.      \r
+       updateInlineControlPoints(u,false);\r
+               if (updateEnds) {\r
+                       if (u.start.isInstanceOf(ProcessResource.plant3Dresource.TurnControlPoint)) {\r
+                               updateTurnControlPointTurn(u.start, u.start.getPrevious(), u.start.getNext());\r
+                               updatePathLegPrev(u.start, u.start, PathLegUpdateType.NONE);\r
+                       } else if (u.start.isInstanceOf(ProcessResource.plant3Dresource.EndComponentControlPoint)) {\r
+                               updateEndComponentControlPoint(u.start, u.startPoint, u.endPoint);\r
+                       }\r
+                       if (u.end.isInstanceOf(ProcessResource.plant3Dresource.TurnControlPoint)) {\r
+                               updateTurnControlPointTurn( u.end, u.end.getPrevious(), u.end.getNext());\r
+                               updatePathLegNext(u.end, u.end, PathLegUpdateType.NONE);\r
+                       } else if (u.end.isInstanceOf(ProcessResource.plant3Dresource.EndComponentControlPoint)) {\r
+                               updateEndComponentControlPoint(u.end, u.startPoint, u.endPoint);\r
+                       }\r
+                       \r
+               } else {\r
+                       if (u.start.isInstanceOf(ProcessResource.plant3Dresource.EndComponentControlPoint)) {\r
+                               updateEndComponentControlPoint(u.start, u.startPoint, u.endPoint);\r
+                       }\r
+                       if (u.end.isInstanceOf(ProcessResource.plant3Dresource.EndComponentControlPoint)) {\r
+                               updateEndComponentControlPoint( u.end, u.startPoint, u.endPoint);\r
+                       }\r
+               }\r
+               if(updateInline)\r
+                       updateInlineControlPoints(u,true);\r
+       \r
+    }\r
+    \r
+    /**\r
+        * Processes pipe run and recalculates offset\r
+     */\r
+    //private static void processPathLeg(PipeControlPoint start, Point3d startPoint,ArrayList<InlineControlPoint> list, PipeControlPoint end,Point3d endPoint, Vector3d dir, boolean hasOffsets,int iter, boolean reversed, ArrayList<ExpandIterInfo> toRemove) throws TransactionException {\r
+    private static void processPathLegNoOffset(UpdateStruct2 u) {\r
+       if (DEBUG) System.out.println("PipingRules.processPathLeg " + u.start.getResource() + " " + u.end.getResource());\r
+       Vector3d offset = new Vector3d();\r
+       if (u.hasOffsets) {\r
+               u.dir.normalize();\r
+           for (PipeControlPoint icp : u.list) {\r
+               if (icp.isInstanceOf(ProcessResource.plant3Dresource.OffsetComponent)) {\r
+                       offset.add(ControlPointTools.getSizeChangeOffsetVector(icp,u.dir));\r
+               } else if (icp.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)) {\r
+                       ErrorLogger.defaultLogError("Updating pipe run, found offset controlpoint " + icp.getResource(), new Exception("ASSERT!"));\r
+               }\r
+           }\r
+       }       \r
+       processPathLeg(u);\r
+    }\r
+    \r
+    private static void updateOffsetPoint(PipeControlPoint sccp, Vector3d offset) {\r
+               Point3d world = G3DTools.getPoint(sccp.getWorldPosition());\r
+               world.add(offset);\r
+               PipeControlPoint ocp = sccp.getSubPoint().iterator().next();\r
+               ControlPointTools.setWorldPosition(ocp, world);\r
+    }\r
+    \r
+    private static void updatePathLegPrev(PipeControlPoint start, PipeControlPoint updated, PathLegUpdateType lengthChange) {\r
+       ArrayList<PipeControlPoint> list = new ArrayList<PipeControlPoint>();\r
+       PipeControlPoint end = ControlPointTools.findPreviousEnd(start,list);\r
+       updatePathLegPrev(start, list, end,updated,lengthChange);\r
+    }\r
+    \r
+    private static void updatePathLegPrev(PipeControlPoint start, ArrayList<PipeControlPoint> list, PipeControlPoint end, PipeControlPoint updated, PathLegUpdateType lengthChange) {\r
+       // reverses the list\r
+       ArrayList<PipeControlPoint> nextList = new ArrayList<PipeControlPoint>();\r
+       for (PipeControlPoint icp : list) {\r
+               if (icp.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)) {\r
+                       nextList.add(0, icp.getSubPointOf());\r
+               } else {\r
+                       nextList.add(0,icp);\r
+               }\r
+               \r
+       }\r
+       updatePathLeg(end, nextList, start, true,0,new ArrayList<ExpandIterInfo>(),updated,lengthChange);\r
+        \r
+    }\r
+\r
+    \r
+    /**\r
+     * Updates InlineControlPoints position when straight pipe's end(s) have\r
+     * been changed)\r
+     * \r
+     * @param pipeline\r
+     * @param icp\r
+     * @param nextPoint\r
+     * @param prevPoint\r
+     */\r
+    private static void updateInlineControlPoint( PipeControlPoint icp, Point3d nextPoint, Point3d prevPoint, Vector3d dir) {\r
+       if (DEBUG) System.out.println("PipingRules.updateInlineControlPoint() " + icp.getResource());\r
+        \r
+       Point3d inlinePoint = G3DTools.getPoint(icp.getLocalPosition());\r
+        if (DEBUG) System.out.print("InlineControlPoint update "+icp.getResource() + " " + inlinePoint + " " + prevPoint + " " + nextPoint);\r
+        Vector3d newInlinePoint = null;\r
+        boolean branchUpdate = false;\r
+        PipeControlPoint becp = null;\r
+        for (PipeControlPoint pcp : icp.getSubPoint())\r
+               if (pcp.isInstanceOf(ProcessResource.plant3Dresource.UndirectedControlPoint)) {\r
+                       branchUpdate = true;\r
+                       becp = pcp;\r
+                       break;\r
+               }\r
+                       \r
+       if (DUMMY || !branchUpdate) {\r
+               newInlinePoint = MathTools.closestPointOnEdge(new Vector3d(inlinePoint), new Vector3d(nextPoint), new Vector3d(prevPoint));\r
+       } else {\r
+               \r
+               // FIXME : can only handle one branch\r
+               PipeControlPoint p = null;\r
+               if (becp.getNext() != null) {\r
+                       p = ControlPointTools.findNextEnd(becp);\r
+               } else if (becp.getPrevious() != null) {\r
+                       p = ControlPointTools.findPreviousEnd(becp);\r
+               } \r
+               if (p == null) {\r
+                       newInlinePoint = MathTools.closestPointOnEdge(new Vector3d(inlinePoint), new Vector3d(nextPoint), new Vector3d(prevPoint));\r
+               } else {\r
+                       Point3d branchLegEnd = G3DTools.getPoint(p.getLocalPosition());\r
+                       Vector3d dir2 = new Vector3d(inlinePoint);\r
+                       dir2.sub(branchLegEnd);\r
+                       Vector3d dir1 = new Vector3d(nextPoint);\r
+                       dir1.sub(prevPoint);\r
+                       newInlinePoint = new Vector3d();\r
+                       double mu[] = new double[2];\r
+                       MathTools.intersectStraightStraight(new Vector3d(prevPoint), dir1, new Vector3d(branchLegEnd), dir2, newInlinePoint, new Vector3d(),mu);\r
+                       if (DEBUG) System.out.println(mu[0]);\r
+                       // FIXME : reserve space \r
+                       if (mu[0] < 0.0) {\r
+                               newInlinePoint = new Vector3d(prevPoint);\r
+                       } else if (mu[0] > 1.0) {\r
+                               newInlinePoint = new Vector3d(nextPoint);\r
+                       }\r
+               }\r
+       }\r
+       if (DEBUG) System.out.println(" " + newInlinePoint);\r
+        \r
+       ControlPointTools.setWorldPosition(icp, newInlinePoint);\r
+       updateControlPointOrientation(icp);\r
+    }\r
+    \r
+    /**\r
+     * Updates InlineControlPoints position when straight pipe's end(s) have\r
+     * been changed)\r
+     * \r
+     * @param pipeline\r
+     * @param icp\r
+     * @param nextPoint\r
+     * @param prevPoint\r
+     */\r
+    private static void updateEndComponentControlPoint( PipeControlPoint ecp, Point3d start, Point3d end) {\r
+       if (DEBUG) System.out.println("PipingRules.updateEndComponentControlPoint() " + ecp.getResource());\r
+//        PipeControlPoint next = ecp.getNext();\r
+//        PipeControlPoint prev = ecp.getPrevious();\r
+//        if (next != null) {\r
+//             end = G3DTools.getPoint(next.getLocalPosition());\r
+//             start = G3DTools.getPoint(ecp.getLocalPosition());\r
+//        } else if (prev != null) {\r
+//             end = G3DTools.getPoint(ecp.getLocalPosition());\r
+//             start = G3DTools.getPoint(prev.getLocalPosition());\r
+//        } else {\r
+//             // TODO : warning?\r
+//             return;\r
+//        }\r
+       //Vector3d dir = new Vector3d (end);\r
+        //dir.sub(start);\r
+        //dir.normalize();\r
+       //G3DTools.setTuple(ecp.getDirection(), dir);\r
+       \r
+       updateControlPointOrientation(ecp);\r
+       \r
+       for (PipeControlPoint pcp : ecp.getSubPoint()) {\r
+               // TODO update position\r
+               updatePathLegEndControlPoint(pcp);\r
+       }\r
+    }\r
+    \r
+    private static void updateControlPointOrientation(PipeControlPoint pcp) {\r
+       // FIXME : hack to bypass variable length components orientation\r
+       if (pcp.getAtMostOneRelatedObject(ProcessResource.g3dResource.HasWorldOrientation) == null)\r
+               return;\r
+       Double angleO = pcp.getAtMostOneRelatedScalarDouble(ProcessResource.plant3Dresource.HasRotationAngle);\r
+       double angle = 0.0;\r
+       if (angleO != null)\r
+               angle = angleO;\r
+       \r
+       AxisAngle4d aa = ControlPointTools.getControlPointWorldRotation(pcp, angle);\r
+       ControlPointTools.setWorldOrientation(pcp,aa);\r
+       \r
+    }\r
+\r
+    /**\r
+     * Updates all branches when branch's position has been changed\r
+     * @param bcp\r
+     */\r
+    private static void updateBranchControlPointBranches(PipeControlPoint bcp) {\r
+       if (DEBUG) System.out.println("PipingRules.updateBranchControlPointBranches() " + bcp.getResource());\r
+        Collection<PipeControlPoint> branches = bcp.getSubPoint();\r
+        if (branches.size() == 0) {\r
+            if (DEBUG) System.out.println("No Branches found");\r
+            return;\r
+        }\r
+        for (PipeControlPoint pcp : branches) {\r
+               updatePathLegEndControlPoint(pcp);\r
+        }\r
+    }\r
+    \r
+    /**\r
+     * Recalculates turn control point's internal data (turn angle and offset)\r
+     * @param tcp\r
+     * @param prev\r
+     * @param next\r
+     */\r
+    private static double updateTurnControlPointTurn( PipeControlPoint tcp, PipeControlPoint prev, PipeControlPoint next) {\r
+       if (DEBUG) System.out.println("PipingTools.updateTurnControlPointTurn()" + tcp.getResource());\r
+        if (next == null || prev == null)\r
+            return Math.PI; // FIXME : argh\r
+        Point3d middlePoint = G3DTools.getPoint(tcp.getWorldPosition());\r
+        Point3d nextPoint = G3DTools.getPoint(next.getWorldPosition());    \r
+        Point3d prevPoint = G3DTools.getPoint(prev.getWorldPosition());     \r
+        return updateTurnControlPointTurn(tcp, middlePoint, prevPoint, nextPoint);\r
+    }\r
+    \r
+    /**\r
+     * Recalculates turn control point's internal data (turn angle and offset)\r
+     * @param tcp\r
+     * @param middlePoint\r
+     * @param nextPoint\r
+     * @param prevPoint\r
+     */\r
+    private static double updateTurnControlPointTurn( PipeControlPoint tcp, Point3d middlePoint, Point3d prevPoint, Point3d nextPoint) {\r
+       \r
+       Vector3d dir1 = new Vector3d(middlePoint);\r
+        dir1.sub(prevPoint);\r
+        Vector3d dir2 = new Vector3d(nextPoint);\r
+        dir2.sub(middlePoint);\r
+        if (DEBUG) System.out.println("PipingTools.updateTurnControlPointTurn " + tcp.getResource() + " " + prevPoint + " " + middlePoint + " " + nextPoint);\r
+        return updateTurnControlPointTurn(tcp, dir1, dir2);\r
+    }\r
+    \r
+    private static double updateTurnControlPointTurn(PipeControlPoint tcp, Vector3d dir1, Vector3d dir2) {\r
+        double turnAngle = dir1.angle(dir2);\r
+         double angle = Math.PI - turnAngle;\r
+         \r
+         double elbowRadius = tcp.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasTurnRadius);\r
+         double R = elbowRadius / Math.tan(angle * 0.5);\r
+         Vector3d turnAxis = new Vector3d();\r
+         turnAxis.cross(dir1, dir2);\r
+         turnAxis.normalize();\r
+         tcp.setRelatedScalarDouble(ProcessResource.plant3Dresource.HasTurnAngle,turnAngle);\r
+         tcp.setRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength, R);//setComponentOffsetValue(R);\r
+         G3DTools.setTuple3(tcp.getSingleRelatedObject(ProcessResource.plant3Dresource.HasTurnAxis), turnAxis);\r
+         if (DEBUG) System.out.println("PipingTools.updateTurnControlPointTurn " + dir1 + " " + dir2 + " " + turnAngle + " " + turnAxis);\r
+         return turnAngle;\r
+    }\r
+    \r
+}\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/PipingTools.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/PipingTools.java
new file mode 100644 (file)
index 0000000..7ae038d
--- /dev/null
@@ -0,0 +1,225 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007 VTT Technical Research Centre of Finland and others.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package fi.vtt.simantics.processeditor.common;\r
+\r
+\r
+public class PipingTools {\r
+//     private static final boolean DEBUG = true;\r
+//     \r
+//\r
+//    \r
+//    /**\r
+//     * Splits straigth by inserting new controlpoint between straight ends.\r
+//     * @param straight\r
+//     * @param newPcp\r
+//     * @throws TransactionException\r
+//     */\r
+////    public static void insertControlPoint(Straight straight, PipeControlPoint newPcp) throws TransactionException {\r
+////        if (straight == null || newPcp == null) {\r
+////            ErrorLogger.defaultLogError("Routing pipe, cannot make branch: straight or control point is null", null);\r
+////            return;\r
+////        }\r
+////        PipeControlPoint scp = straight.getHasControlPoint();\r
+////        PipeControlPoint straightStart = (PipeControlPoint)StubFactory.getStubForResource(straight.getClass().getClassLoader(),scp.getPreviousPoint().getResource());\r
+////        PipeControlPoint straightEnd = (PipeControlPoint)StubFactory.getStubForResource(straight.getClass().getClassLoader(),scp.getNext().getResource());\r
+////        if (DEBUG) System.out.println("PipingTools inserting control point between " + straightStart.getResource() + " " + straightEnd.getResource() + " straight " + straight.getResource());\r
+////        \r
+////        // remove the straight pipe  \r
+////        PipeControlPoint temp = PipeControlPointFactory.instantiate(newPcp.getGraph());\r
+////        //straight.setHasNextControlPoint(temp);\r
+////        //straight.setHasPreviousControlPoint(temp);  \r
+////        straight.setHasControlPoint(temp);\r
+////        \r
+////        PipeRun pipeRun = getPipeRun(straight);\r
+////        if (pipeRun != null) {\r
+////            pipeRun.getHasSubnodesSet().remove(straight.getResource());\r
+////        }\r
+////        insertControlPoint(pipeRun, newPcp, straightStart, straightEnd);\r
+////        \r
+////    }\r
+//    \r
+//\r
+//\r
+//    \r
+//    \r
+//   \r
+//    \r
+//    \r
+//    public static void getStraightPipeEnds(Straight straight, Point3d end1, Point3d end2) {\r
+//        getStraightPipeEnds(getPipeRun(straight), straight, end1, end2);\r
+//    }\r
+//    \r
+//    public static void getStraightPipeEnds(PipeRun pipeRun,Straight straight, Point3d end1, Point3d end2) {\r
+//     if (DEBUG) System.out.println("PipingTools.getStraightPipeEnds() " + straight.getResource());\r
+//     PipeControlPoint scp = straight.getHasControlPoint();\r
+//        PipeControlPoint startControlPoint = (PipeControlPoint)StubFactory.getStubForResource(straight.getClass().getClassLoader(),scp.getPrevious().getResource());\r
+//        PipeControlPoint endControlPoint = (PipeControlPoint)StubFactory.getStubForResource(straight.getClass().getClassLoader(),scp.getNext().getResource());\r
+//        if (startControlPoint == null || endControlPoint == null) {\r
+//            ErrorLogger.defaultLogError("Pipe ends null", new NullPointerException());\r
+//        }\r
+//        // start and end position of the pipe\r
+//        // positions may be linked to other components, like nozzles\r
+//        // and then their coordinates are in component's local coordinates\r
+//        // which must be transformed into pipeRun's local coordinates\r
+//        \r
+//        //Point3d startPipe = getLocalPoint(pipeRun,startControlPoint);\r
+//\r
+//        \r
+//        //Point3d endPipe = getLocalPoint(pipeRun, endControlPoint);\r
+//        Point3d startPipe = G3DTools.getPoint(startControlPoint.getLocalPosition());\r
+//        Point3d endPipe = G3DTools.getPoint(endControlPoint.getLocalPosition());\r
+//        if (startPipe == null || endPipe == null) {\r
+//            end1.x = Double.NaN;\r
+//            end1.y = Double.NaN;\r
+//            end1.z = Double.NaN;\r
+//            end2.x = Double.NaN;\r
+//            end2.y = Double.NaN;\r
+//            end2.z = Double.NaN;\r
+//            if (DEBUG) System.out.println("no positions");\r
+//            return;\r
+//        }\r
+//        \r
+//        Vector3d dir = new Vector3d(endPipe);\r
+//        dir.sub(startPipe);\r
+//        \r
+//\r
+//        if (startControlPoint instanceof TurnControlPoint) {\r
+//            TurnControlPoint t = (TurnControlPoint)startControlPoint;\r
+//            double R = t.getComponentOffsetValue();\r
+//            Vector3d n = new Vector3d(dir);\r
+//            n.normalize();\r
+//            n.scale(R);\r
+//            startPipe.add(n);\r
+//        } else if (startControlPoint instanceof InlineControlPoint && !(startControlPoint instanceof BranchControlPoint)) {\r
+//            InlineControlPoint t = (InlineControlPoint)startControlPoint;\r
+//            double R = t.getNextComponentOffsetValue();\r
+//            Vector3d n = new Vector3d(dir);\r
+//            n.normalize();\r
+//            n.scale(R);\r
+//            startPipe.add(n);\r
+//        }\r
+//\r
+//        if (endControlPoint instanceof TurnControlPoint) {\r
+//            TurnControlPoint t = (TurnControlPoint)endControlPoint;\r
+//            double R = t.getComponentOffsetValue();\r
+//            Vector3d n = new Vector3d(dir);\r
+//            n.normalize();\r
+//            n.scale(R);\r
+//            endPipe.sub(n);\r
+//        } else if (endControlPoint instanceof InlineControlPoint && !(endControlPoint instanceof BranchControlPoint)) {\r
+//            InlineControlPoint t = (InlineControlPoint)endControlPoint;\r
+//            double R = t.getPreviousComponentOffsetValue();\r
+//            Vector3d n = new Vector3d(dir);\r
+//            n.normalize();\r
+//            n.scale(R);\r
+//            endPipe.sub(n);\r
+//        }\r
+//        \r
+//        end1.x = startPipe.x;\r
+//        end1.y = startPipe.y;\r
+//        end1.z = startPipe.z;\r
+//        \r
+//        end2.x = endPipe.x;\r
+//        end2.y = endPipe.y;\r
+//        end2.z = endPipe.z;\r
+//        \r
+//    }\r
+//    \r
+//    /**\r
+//     * Finds direction and ends where inline component, reducer or branch can be moved.\r
+//     * @param icp\r
+//     * @param s\r
+//     * @param e\r
+//     * @param d\r
+//     */\r
+//    public static void getInlineEnds(InlineControlPoint icp, Vector3d s, Vector3d e, Vector3d d) {\r
+//        \r
+//        PipeControlPoint next = (PipeControlPoint)StubFactory.getStubForResource(icp.getClass().getClassLoader(), icp.getNext().getResource());\r
+//        PipeControlPoint prev = (PipeControlPoint)StubFactory.getStubForResource(icp.getClass().getClassLoader(), icp.getPrevious().getResource());\r
+//        Vector3d start = G3DTools.getVector(prev.getLocalPosition());\r
+//        Vector3d end = G3DTools.getVector(next.getLocalPosition());\r
+//        if (icp.getResource().isInstanceOf(GlobalIdMap.get(PSK3DModelingOntologyMapping.SIZE_CHANGE_CONTROL_POINT))) {\r
+//            SizeChangeControlPoint sccp = SizeChangeControlPointFactory.create(icp.getResource());\r
+//            Vector3d tDir = new Vector3d(G3DTools.getVector(sccp.getLocalPosition()));\r
+//            Vector3d offset = getSizeChangeOffsetVector(sccp, tDir);\r
+//            end.sub(offset);\r
+//        }\r
+//        Vector3d dir = new Vector3d(end);\r
+//        dir.sub(start);\r
+//        Vector3d n = new Vector3d(dir);\r
+//        n.normalize();\r
+//        \r
+//        double offset = icp.getNextComponentOffsetValue();\r
+//        if (next instanceof InlineControlPoint) {\r
+//            InlineControlPoint ip = (InlineControlPoint) next;\r
+//            offset += ip.getPreviousComponentOffsetValue();      \r
+//        }\r
+//        else if (next instanceof TurnControlPoint) {\r
+//            TurnControlPoint tcp = (TurnControlPoint)next;\r
+//            offset += tcp.getComponentOffsetValue();\r
+//        }\r
+//        Vector3d t = new Vector3d(n);\r
+//        t.scale(offset);\r
+//        end.sub(t);\r
+//        \r
+//        offset = icp.getPreviousComponentOffsetValue();\r
+//        if (prev instanceof InlineControlPoint) {\r
+//            InlineControlPoint ip = (InlineControlPoint) prev;\r
+//            offset += ip.getPreviousComponentOffsetValue();\r
+//        }\r
+//        else if (prev instanceof TurnControlPoint) {\r
+//            TurnControlPoint tcp = (TurnControlPoint)prev;\r
+//            offset += tcp.getComponentOffsetValue();\r
+//        }\r
+//        t = new Vector3d(n);\r
+//        t.scale(offset);\r
+//        start.add(t);\r
+//        \r
+//        dir= new Vector3d(end);\r
+//        dir.sub(start);\r
+//        \r
+//        s.x = start.x;\r
+//        s.y = start.y;\r
+//        s.z = start.z;\r
+//        \r
+//        e.x = end.x;\r
+//        e.y = end.y;\r
+//        e.z = end.z;\r
+//        \r
+//        d.x = dir.x;\r
+//        d.y = dir.y;\r
+//        d.z = dir.z;\r
+//        \r
+//        System.out.println("PipingTools.getInlineEnds() " + s + " " + e + " " + d);\r
+//    }\r
+//    \r
+//    \r
+//    public static void setSame(fi.vtt.simantics.layer0.stubs.Double d1, fi.vtt.simantics.layer0.stubs.Double d2) {\r
+//     d1.getResource().createRelation(d2.getResource(), GlobalIdMap.get(PSK3DModelingOntologyMapping.IS_SAME_VALUE));\r
+//    }\r
+//    \r
+//    public static void setHalf(fi.vtt.simantics.layer0.stubs.Double d1, fi.vtt.simantics.layer0.stubs.Double d2) {\r
+//     d1.getResource().createRelation(d2.getResource(), GlobalIdMap.get(PSK3DModelingOntologyMapping.IS_HALF_OF_THE_VALUE));\r
+//    }\r
+//    \r
+//    \r
+//    \r
+\r
+//    \r
+//\r
+//    \r
+//    \r
+//    \r
+//    \r
+//    \r
+//    \r
+\r
+}
\ No newline at end of file
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/PipingTools2.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/PipingTools2.java
new file mode 100644 (file)
index 0000000..4baf308
--- /dev/null
@@ -0,0 +1,668 @@
+package fi.vtt.simantics.processeditor.common;\r
+\r
+import java.util.Collection;\r
+\r
+import javax.vecmath.Point3d;\r
+import javax.vecmath.Vector3d;\r
+\r
+import org.simantics.db.Graph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.layer0.utils.EntityFactory;\r
+import org.simantics.layer0.utils.IEntity;\r
+import org.simantics.layer0.utils.Statement;\r
+import org.simantics.layer0.utils.instantiation.Instance;\r
+import org.simantics.layer0.utils.instantiation.InstanceFactory;\r
+import org.simantics.proconf.g3d.base.G3DTools;\r
+import org.simantics.proconf.g3d.stubs.G3DNode;\r
+\r
+import fi.vtt.simantics.processeditor.ProcessResource;\r
+import fi.vtt.simantics.processeditor.actions.PositionType;\r
+import fi.vtt.simantics.processeditor.stubs.Equipment;\r
+import fi.vtt.simantics.processeditor.stubs.InlineComponent;\r
+import fi.vtt.simantics.processeditor.stubs.Nozzle;\r
+import fi.vtt.simantics.processeditor.stubs.PipeControlPoint;\r
+import fi.vtt.simantics.processeditor.stubs.PipeRun;\r
+import fi.vtt.simantics.processeditor.stubs.PipelineComponent;\r
+\r
+public class PipingTools2 {\r
+       private static final boolean DEBUG = false;\r
+       public enum Direction{NEXT,PREVIOUS};\r
+       \r
+\r
+       \r
+       /**\r
+        * Reverses a piperun by swapping all previous/next connections\r
+        * @param pipeRun\r
+        */\r
+       public static void reversePipeRun(IEntity pipeRun) {\r
+//             //FIXME : reducers / size-change / offset-control points\r
+//     RelationTypeSet<PipeControlPoint> cps = pipeRun.getHasControlPointSet();\r
+//     if (cps.size() == 0)\r
+//             return;\r
+//     List<PipeControlPoint> list = new ArrayList<PipeControlPoint>();\r
+//     PipeControlPoint pcp = cps.iterator().next();\r
+//     list.add(pcp);\r
+//     PipeControlPoint temp = pcp.getPrevious();\r
+//     while (temp != null) {\r
+//             list.add(0,temp);\r
+//             temp = temp.getPrevious();\r
+//     }\r
+//     temp = pcp.getNext();\r
+//     while (temp != null) {\r
+//             list.add(temp);\r
+//             temp = temp.getNext();\r
+//     }\r
+//     // now list contains control points in sorted order.\r
+//     // switch order\r
+//     for (int i = 0; i < list.size() - 1; i++) {\r
+//             PipeControlPoint pcp1 = list.get(i);\r
+//             PipeControlPoint pcp2 = list.get(i+1);\r
+//             pcp1.setPrevious(pcp2);\r
+//             pcp2.setNext(pcp1);\r
+//\r
+//     }\r
+//     // fix ends\r
+//     list.get(0).setNext(null);\r
+//     list.get(list.size() - 1).setPrevious(null);\r
+\r
+       }\r
+\r
+       public static IEntity getPipeRun(IEntity component) {\r
+               assert(component.isInstanceOf(ProcessResource.plant3Dresource.PipelineComponent));\r
+               return component.getSingleRelatedObject(ProcessResource.g3dResource.HasParent);\r
+       }\r
+       \r
+        /**\r
+     * Returns Nozzle of a directed control point\r
+     * @param dcp\r
+     * @return\r
+     */\r
+    public static Nozzle getNozzle(PipeControlPoint dcp) {\r
+       assert (dcp.isInstanceOf(ProcessResource.plant3Dresource.DirectedControlPoint));\r
+       IEntity e = dcp.getControlPointOf();\r
+       if (e == null)\r
+               return null;\r
+       assert (e.isInstanceOf(ProcessResource.plant3Dresource.Nozzle));\r
+       return new Nozzle(e);\r
+    }\r
+       \r
+       /**\r
+        * Instantiates new pipeline component and all necessary control points for it.\r
+        * @param graph\r
+        * @param typeResource\r
+        * @return\r
+        */\r
+       public static PipelineComponent instantiatePipelineComponent(Graph graph, Resource pipeRunResource, Resource typeResource) {\r
+               IEntity pipeRun = EntityFactory.create(graph,pipeRunResource);\r
+               Instance ins = InstanceFactory.getInstanceOfType(graph, typeResource);\r
+       Resource instance = ins.instantiate(graph);\r
+       PipelineComponent component = new PipelineComponent(graph,instance);\r
+       G3DTools.resetTransformation(component);\r
+       // copy control point\r
+       Collection<Resource> pcps = graph.getObjects(typeResource, ProcessResource.plant3Dresource.HasControlPoint);\r
+       assert(pcps.size() == 1);\r
+       Collection<Resource> types = graph.getObjects(pcps.iterator().next(), ProcessResource.builtins.InstanceOf);\r
+       PipeControlPoint componentPCP = new PipeControlPoint(graph,InstanceFactory.instantiate(graph, types));\r
+       component.addStatement(ProcessResource.plant3Dresource.HasControlPoint, componentPCP);\r
+       pipeRun.addStatement(ProcessResource.g3dResource.HasChild, component);\r
+       pipeRun.addStatement(ProcessResource.plant3Dresource.HasControlPoints, componentPCP);\r
+       component.setPipeDiameter(pipeRun.getSingleRelatedObject(ProcessResource.plant3Dresource.HasPipeDiameter));\r
+       if (component.isInstanceOf(ProcessResource.plant3Dresource.VariableAngleTurnComponent)) {\r
+               setStatement(component, ProcessResource.plant3Dresource.HasTurnRadius, pipeRun.getSingleRelatedObject(ProcessResource.plant3Dresource.HasTurnRadius));\r
+               setStatement(componentPCP, ProcessResource.plant3Dresource.HasTurnRadius, pipeRun.getSingleRelatedObject(ProcessResource.plant3Dresource.HasTurnRadius));\r
+               setStatement(component, ProcessResource.plant3Dresource.HasTurnAngle, componentPCP.getSingleRelatedObject(ProcessResource.plant3Dresource.HasTurnAngle));\r
+               setStatement(component, ProcessResource.plant3Dresource.HasTurnAxis, componentPCP.getSingleRelatedObject(ProcessResource.plant3Dresource.HasTurnAxis));                 \r
+       }\r
+       if (component.getAtMostOneRelatedObject(ProcessResource.plant3Dresource.HasLength) != null) {\r
+               setStatement(componentPCP, ProcessResource.plant3Dresource.HasLength, component.getSingleRelatedObject(ProcessResource.plant3Dresource.HasLength));\r
+       }\r
+       componentPCP.setLocalOrientation(component.getLocalOrientation());\r
+       componentPCP.setWorldOrientation(component.getWorldOrientation());\r
+       \r
+       componentPCP.setLocalPosition(component.getLocalPosition());\r
+       componentPCP.setWorldPosition(component.getWorldPosition());\r
+       \r
+       setStatement(componentPCP, ProcessResource.plant3Dresource.HasPipeDiameter, pipeRun.getSingleRelatedObject(ProcessResource.plant3Dresource.HasPipeDiameter));\r
+       setStatement(component, ProcessResource.plant3Dresource.HasPipeDiameter, pipeRun.getSingleRelatedObject(ProcessResource.plant3Dresource.HasPipeDiameter));\r
+       \r
+       // TODO : instantiate subpoints\r
+       \r
+       \r
+       return component;\r
+       }\r
+       \r
+       public static Nozzle instantiateNozzle(Graph graph, Resource typeResource) {\r
+               Instance ins = InstanceFactory.getInstanceOfType(graph, typeResource);\r
+       Resource instance = ins.instantiate(graph);\r
+       Nozzle n = new Nozzle(graph,instance);\r
+       G3DTools.resetTransformation(n);\r
+       \r
+       // copy control point\r
+       Collection<Resource> pcps = graph.getObjects(typeResource, ProcessResource.plant3Dresource.HasControlPoint);\r
+       assert(pcps.size() == 1);\r
+       Collection<Resource> types = graph.getObjects(pcps.iterator().next(), ProcessResource.builtins.InstanceOf);\r
+       PipeControlPoint nozzlePCP = new PipeControlPoint(graph,InstanceFactory.instantiate(graph, types));\r
+       n.addStatement(ProcessResource.plant3Dresource.HasControlPoint, nozzlePCP);\r
+       nozzlePCP.setLocalOrientation(n.getLocalOrientation());\r
+       nozzlePCP.setWorldOrientation(n.getWorldOrientation());\r
+       nozzlePCP.setLocalPosition(n.getLocalPosition());\r
+       nozzlePCP.setWorldPosition(n.getWorldPosition());\r
+       setStatement(nozzlePCP, ProcessResource.plant3Dresource.HasPipeDiameter, n.getSingleRelatedObject(ProcessResource.plant3Dresource.HasPipeDiameter));\r
+       nozzlePCP.setPipeDiameter(0.2);\r
+       return n;\r
+       }\r
+       \r
+       public static Equipment instantiateEquipment(Graph graph, Resource typeResource) {\r
+               Instance ins = InstanceFactory.getInstanceOfType(graph, typeResource);\r
+       Resource instance = ins.instantiate(graph);\r
+       Equipment equipment = new Equipment(graph, instance);\r
+       G3DTools.resetTransformation(equipment);\r
+       \r
+       IEntity type = EntityFactory.create(graph, typeResource);\r
+       IEntity geometricModel = type.getSingleRelatedObject(ProcessResource.plant3Dresource.HasGraphics);\r
+       \r
+       Collection<IEntity> sizingProperties = geometricModel.getRelatedObjects(ProcessResource.g3dResource.HasSizingParameter);\r
+       Collection<Statement> equipmentProperties = equipment.getRelatedStatements(ProcessResource.builtins.HasProperty);\r
+               \r
+       for (IEntity e : sizingProperties) {\r
+               String name = e.getName();\r
+               String pName = "Has " + name;\r
+               boolean found = false;\r
+               for (Statement s : equipmentProperties) {\r
+                       IEntity predicate = s.getPredicate();\r
+                       String predicateName = predicate.getName();\r
+                       if (predicateName.equals(pName)) {\r
+                               found = true;\r
+                               break;\r
+                       }\r
+               }\r
+               if(!found) {\r
+                       IEntity rel = getOrCreateRel(graph,name);\r
+                       equipment.setRelatedScalarDouble(rel, 1.0);\r
+               }\r
+       }\r
+       \r
+       // TODO : create nozzles if needed\r
+       \r
+       return equipment;\r
+       }\r
+       \r
+       private static IEntity getOrCreateRel(Graph graph, String name) {\r
+               IEntity rel = null;\r
+               try {\r
+                       Resource relr = graph.getResourceByURI("http://www.vtt.fi/Simantics/Plant3D/1.0/Relations#Has" + name);\r
+                       rel = EntityFactory.create(graph,relr);\r
+               } catch (Exception e) {\r
+                       Resource relLib = null;\r
+                       try {\r
+                               relLib = graph.getResourceByURI("http://www.vtt.fi/Simantics/Plant3D/1.0#Relations");\r
+                       } catch (Exception e2) {\r
+                               \r
+                       }\r
+                       Resource relr = graph.newResource();\r
+                       rel = EntityFactory.create(graph, relr);\r
+                       rel.addStatement(ProcessResource.builtins.SubrelationOf, ProcessResource.g3dResource.HasNonTransformation);\r
+                       rel.setName("Has " + name);\r
+                       Resource irelr = graph.newResource();\r
+                       graph.addStatement(relr,ProcessResource.builtins.InverseOf,irelr);\r
+                       graph.addStatement(relLib, ProcessResource.builtins.ConsistsOf, relr);\r
+               }\r
+               return rel;\r
+       }\r
+       \r
+       public static IEntity getLibraryComponentType(IEntity component) {\r
+               assert(component.isInstanceOf(ProcessResource.plant3Dresource.LibraryComponent));\r
+               // IEntity.getTypes() returns all types, but we want the closest type.\r
+               Collection<IEntity> types = component.getRelatedObjects(ProcessResource.builtins.InstanceOf);//component.getTypes();\r
+               IEntity type = null;\r
+               for (IEntity t : types) {\r
+                       if (t.isInheritedFrom(ProcessResource.plant3Dresource.LibraryComponent)) {\r
+                               if (type == null)\r
+                                       type = t;\r
+                               else\r
+                                       throw new RuntimeException("Cannot find proper type for library component " + component.getResource() );\r
+                       }\r
+               }\r
+               return type;\r
+       }\r
+       \r
+       /**\r
+        * Splits existing VariableLengthComponent with another component.\r
+        * Result is two VariableLengthComponents and inserted component between them.\r
+        * \r
+        * Note : world position of newComponent must be set before this method may be called.\r
+        * \r
+        * @param newComponent\r
+        * @param splittingComponent\r
+        */\r
+       public static void splitVariableLengthComponent(IEntity newComponent, IEntity splittingComponent) {\r
+               assert(splittingComponent.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent));\r
+               assert(newComponent.isInstanceOf(ProcessResource.plant3Dresource.PipelineComponent));\r
+               assert(!newComponent.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent));\r
+               IEntity newCP = newComponent.getSingleRelatedObject(ProcessResource.plant3Dresource.HasControlPoint);\r
+               IEntity splittingCP = splittingComponent.getSingleRelatedObject(ProcessResource.plant3Dresource.HasControlPoint);\r
+               IEntity nextCP = splittingCP.getAtMostOneRelatedObject(ProcessResource.plant3Dresource.HasNext);\r
+               IEntity prevCP = splittingCP.getAtMostOneRelatedObject(ProcessResource.plant3Dresource.HasPrevious);\r
+               \r
+               /* there are many different cases to insert new component when\r
+                  it splits existing VariableLengthinlineComponent.\r
+           \r
+              1. VariableLengthComponet is connected from both sides:\r
+                 - insert new component between VariableLength component and component connected to it\r
+                 - insert new VariableLengthComponent between inserted component and component selected in previous step\r
+               \r
+                  2. VariableLengthComponent is connected from one side\r
+                    - Use previous case or:\r
+                    - Insert new component to empty end\r
+                    - Insert new VariableLength component to inserted components empty end\r
+                    \r
+                  3. VariableLength is not connected to any component.\r
+                    - Should not be possible, at least in current implementation.\r
+                    - Could be done using second case\r
+\r
+               */\r
+               \r
+               if (nextCP == null && prevCP == null) {\r
+                       // this should not be possible\r
+                       throw new RuntimeException("VariableLengthComponent " + splittingComponent.getResource() + " is not connected to anything.");\r
+               }\r
+               \r
+               Point3d next = ControlPointTools.getRealPosition(splittingCP, PositionType.NEXT);\r
+               Point3d prev = ControlPointTools.getRealPosition(splittingCP, PositionType.PREVIOUS);\r
+               Point3d comp = G3DTools.getPoint(newComponent.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition));\r
+               double length = newComponent.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength);\r
+               Vector3d dir = new Vector3d(next);\r
+               dir.sub(prev);\r
+               dir.normalize();\r
+               dir.scale(length * 0.5);\r
+               Point3d vn = new Point3d(comp);\r
+               Point3d vp = new Point3d(comp);\r
+               vn.add(dir);\r
+               vp.sub(dir);\r
+               double ln = vn.distance(next);\r
+               double lp = vp.distance(prev);\r
+               vp.interpolate(prev, 0.5);\r
+               vn.interpolate(next, 0.5);\r
+               \r
+               IEntity type = getLibraryComponentType(splittingComponent);\r
+               \r
+               IEntity newVariableLengthComponent = instantiatePipelineComponent(splittingComponent.getGraph(), getPipeRun(splittingComponent).getResource(), type.getResource());\r
+               IEntity newVariableLengthCP = newVariableLengthComponent.getSingleRelatedObject(ProcessResource.plant3Dresource.HasControlPoint);\r
+               if (nextCP == null) {\r
+                       ControlPointTools.insertControlPoint(newCP, splittingCP,Direction.NEXT);\r
+                       ControlPointTools.insertControlPoint(newVariableLengthCP, newCP,Direction.NEXT);\r
+                       ControlPointTools.setWorldPosition(splittingCP, vp);\r
+                       splittingCP.setRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength, lp);\r
+                       ControlPointTools.setWorldPosition(newVariableLengthCP, vn);    \r
+                       newVariableLengthComponent.setRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength, ln);\r
+               } else if (prevCP == null) {\r
+                       ControlPointTools.insertControlPoint(newCP, splittingCP,Direction.PREVIOUS);\r
+                       ControlPointTools.insertControlPoint(newVariableLengthCP, newCP,Direction.PREVIOUS);\r
+                       ControlPointTools.setWorldPosition(splittingCP, vn);\r
+                       splittingCP.setRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength, ln);\r
+                       ControlPointTools.setWorldPosition(newVariableLengthCP, vp);\r
+                       newVariableLengthComponent.setRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength, lp);\r
+               } else {\r
+                       ControlPointTools.insertControlPoint(newCP,splittingCP,nextCP);\r
+                       ControlPointTools.insertControlPoint(newVariableLengthCP, newCP,nextCP);\r
+                       ControlPointTools.setWorldPosition(splittingCP, vp);\r
+                       splittingCP.setRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength, lp);\r
+                       ControlPointTools.setWorldPosition(newVariableLengthCP, vn);\r
+                       newVariableLengthComponent.setRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength, ln);\r
+               }\r
+\r
+       }\r
+       \r
+       /**\r
+        * Attaches newComponent into connectedComponent's connectedControlPoint\r
+        * @param newComponent\r
+        * @param connectedComponent\r
+        * @param connectedControlPoint\r
+        */\r
+       public static void insertComponent(IEntity newComponent, IEntity connectedComponent, IEntity connectedControlPoint, Direction direction) {\r
+           assert (newComponent.isInstanceOf(ProcessResource.plant3Dresource.PipelineComponent));\r
+           assert (connectedComponent.isInstanceOf(ProcessResource.plant3Dresource.PipelineComponent));\r
+           // TODO : piperun check is more complicated, since newComponent and connectedComponent may be SizeChangeComponents \r
+           //assert (getPipeRun(connectedComponent).equals(getPipeRun(newComponent)));\r
+           \r
+           // new control point and its subpoint\r
+           IEntity newControlPoint = newComponent.getSingleRelatedObject(ProcessResource.plant3Dresource.HasControlPoint);\r
+           ControlPointTools.insertControlPoint(newControlPoint, connectedControlPoint, direction);\r
+//         IEntity newSubPoint = null;\r
+//         if (newControlPoint.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint))\r
+//             newSubPoint = newControlPoint.getSingleRelatedObject(ProcessResource.plant3Dresource.HasSubPoint);\r
+//         \r
+//         // connected components parent or subpoint \r
+//         IEntity connectedSubPoint = null;\r
+//         IEntity connectedParentPoint = null;\r
+//         if (connectedControlPoint.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint))\r
+//             connectedSubPoint = connectedControlPoint.getSingleRelatedObject(ProcessResource.plant3Dresource.HasSubPoint);\r
+//         else if (connectedControlPoint.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint))\r
+//             connectedParentPoint = connectedControlPoint.getSingleRelatedObject(ProcessResource.plant3Dresource.SubPointOf);\r
+//         \r
+//         if (direction == Direction.NEXT) {\r
+//             assert (connectedSubPoint == null); // if direction is next, connection done to subpoint\r
+//             setStatement(connectedControlPoint, ProcessResource.plant3Dresource.HasNext, newControlPoint);\r
+//             if (connectedParentPoint != null)\r
+//                     setStatement(connectedParentPoint, ProcessResource.plant3Dresource.HasNext, newControlPoint);\r
+//             setStatement(newControlPoint, ProcessResource.plant3Dresource.HasPrevious, connectedControlPoint);\r
+//             if (newSubPoint != null)\r
+//                     setStatement(newSubPoint, ProcessResource.plant3Dresource.HasPrevious, connectedControlPoint);\r
+//             \r
+//         } else {\r
+//             assert (connectedParentPoint == null); // if direction is prev, connection done to parentpoint\r
+//             if (newSubPoint != null) {\r
+//                     \r
+//             }\r
+//         }\r
+               \r
+               /*\r
+           private void insertEndComponent() {\r
+               activated = false;\r
+               Graph coreTC = parent.getGraph();\r
+               \r
+               if (replace == null)\r
+                       checkForEndInsertion();\r
+               if (replace == null) {\r
+                       ErrorLogger.defaultLogError("Cannot insert end component",null);\r
+                       end();\r
+                       return;\r
+               }\r
+               G3DNode p = straight.getHasParent();\r
+               if (p == null) {\r
+                   ErrorLogger.defaultLogError("Straight pipe has no parent", new Exception("ASSERT!"));\r
+\r
+               } else {\r
+                   Pipeline pipeline = PipelineFactory.create(p);\r
+                   coreTC.startTransaction(this);\r
+                   try {\r
+                       Vector3d startPoint = GraphicsNodeTools.getVector(replace.getLocalPosition());\r
+                       EndComponentControlPoint ecp = EndComponentControlPointFactory.instantiate(coreTC);\r
+                       coreTC.commitChanges(CommitMessage.CHANGE_MESSAGE);\r
+                       pipeline.getHasControlPointSet().remove(replace);\r
+                       // create dummy node\r
+                       //PipeControlPoint pcp = PipeControlPointFactory.instantiate(coreTC);\r
+                       replace.setNextPoint(null);\r
+                       replace.setPreviousPoint(null);\r
+                       pipeline.getHasControlPointSet().add(ecp);\r
+                       if (next) {\r
+                               straight.getHasControlPoint().getPreviousPoint().setNextPoint(ecp);\r
+                               straight.getHasControlPoint().setNextPoint(ecp);\r
+                               ecp.setPreviousPoint(straight.getHasControlPoint().getPreviousPoint());\r
+                               //ecp.setNextPoint(null);\r
+                       } else {\r
+                               straight.getHasControlPoint().getNextPoint().setPreviousPoint(ecp);\r
+                               straight.getHasControlPoint().setPreviousPoint(ecp);\r
+                               ecp.setNextPoint(straight.getHasControlPoint().getNextPoint());\r
+                               //ecp.setPreviousPoint(null);\r
+                       }\r
+                       G3DTools.setTranslation(ecp.getLocalPosition(), startPoint);\r
+                       // FIXME : component should specify how much space it needs\r
+                       createAndLink(coreTC, pipeline, ecp);\r
+                       coreTC.commitChanges(CommitMessage.CHANGE_MESSAGE);\r
+                       coreTC.commitTransaction(CommitMessage.TRANSACTION_MESSAGE);\r
+                   } catch (TransactionException e) {\r
+                       ErrorLogger.defaultLogError("Cannot insert component", e);\r
+                       coreTC.cancelTransaction();\r
+                   }\r
+               }\r
+               \r
+               end();\r
+           }\r
+           \r
+           private void insertComponent(Point3d startPoint) {\r
+               activated = false;\r
+               Graph coreTC = parent.getGraph();\r
+               G3DNode p = straight.getHasParent();\r
+               if (p == null) {\r
+                   ErrorLogger.defaultLogError("Straight pipe has no parent", new Exception("ASSERT!"));\r
+\r
+               } else {\r
+                   Pipeline pipeline = PipelineFactory.create(p);\r
+                   coreTC.startTransaction(this);\r
+                   try {\r
+                       InlineComponentControlPoint icp = InlineComponentControlPointFactory.instantiate(coreTC);\r
+                       coreTC.commitChanges(CommitMessage.CHANGE_MESSAGE);\r
+                       PipeControlPoint scp = straight.getHasControlPoint();\r
+                       // it shouldn't matter whitch control point to use, next or previous.\r
+                       PipingTools.insertControlPoint(pipeline, icp, scp, scp.getNextPoint());\r
+                       //PipingTools.insertControlPoint(straight, icp);\r
+                       pipeline.getHasControlPointSet().add(icp);\r
+                       G3DTools.setTranslation(icp.getLocalPosition(), startPoint);\r
+                       // FIXME : component should specify how much space it needs\r
+                       icp.setNextComponentOffsetValue(pipeline.getPipeRadiusValue());\r
+                       icp.setPreviousComponentOffsetValue(pipeline.getPipeRadiusValue());\r
+                       PipingTools.setSame(pipeline.getPipeRadius(), icp.getNextComponentOffset());\r
+                       PipingTools.setSame(pipeline.getPipeRadius(), icp.getPreviousComponentOffset());\r
+                       createAndLink(coreTC, pipeline, icp);\r
+                       coreTC.commitChanges(CommitMessage.CHANGE_MESSAGE);\r
+                       coreTC.commitTransaction(CommitMessage.TRANSACTION_MESSAGE);\r
+                   } catch (TransactionException e) {\r
+                       ErrorLogger.defaultLogError("Cannot insert component", e);\r
+                       coreTC.cancelTransaction();\r
+                   }\r
+               }\r
+\r
+               line.removeFromParent();\r
+               \r
+               end();\r
+               \r
+           }\r
+          \r
+           \r
+           private void createAndLink(Graph coreTC, Pipeline pipeline, PipeControlPoint icp) throws TransactionException {\r
+               PipelineComponent component = PipelineComponentFactory.create(OntologyUtils.instantiate(typeResource));\r
+               coreTC.commitChanges(CommitMessage.CHANGE_MESSAGE);\r
+               component.setHasControlPoint(icp);\r
+               component.setLocalPosition(icp.getLocalPosition());\r
+               pipeline.getHasSubnodesSet().add(component);\r
+               component.setPipeRadius(pipeline.getPipeRadius());\r
+               component.setHasGraphics(GraphicsModelFactory.create(modelResource));\r
+               \r
+           }\r
+            */\r
+               \r
+               /*\r
+                       old insert reducer code\r
+                       \r
+                                       Pipeline pipeline = PipingTools.getPipeline(straight);\r
+                       // pcp is Turn Control Point and we'll have to change it's type to Size Change Control Point\r
+                       // First we'll remove its unnecessary properties and elbow connected to it,\r
+                       RelationTypeSet<Entity> pipeComponents = pcp.getControlPointOfSet();\r
+                       Resource elbowResource = null;\r
+                       for (Entity e : pipeComponents) {\r
+                               if (e.getResource().isInstanceOf(GlobalIdMap.get(PSK3DModelingOntologyMapping.ELBOW))) {\r
+                                       elbowResource = e.getResource();\r
+                               }\r
+                       }\r
+                       if (elbowResource != null) {\r
+                               pipeComponents.remove(elbowResource);\r
+                               pipeline.getHasSubnodesSet().remove(elbowResource);\r
+                       }\r
+                       RelationSet rs = pcp.getResource().getRelatedResourcesWithRelationIds(GlobalIdMap.get(PSK3DModelingOntologyMapping.HAS_TURN_ANGLE));\r
+                       RelationReference rr = rs.getRelations()[0];\r
+                       pcp.getResource().removeRelationById(rr.getObjectId(),rr.getRelationId());\r
+                       rs = pcp.getResource().getRelatedResourcesWithRelationIds(GlobalIdMap.get(PSK3DModelingOntologyMapping.HAS_COMPONENT_OFFSET));\r
+                       rr = rs.getRelations()[0];\r
+                       pcp.getResource().removeRelationById(rr.getObjectId(),rr.getRelationId());\r
+                       rs = pcp.getResource().getRelatedResourcesWithRelationIds(GlobalIdMap.get(Builtins.InstanceOf));\r
+                       rr = rs.getRelations()[0];\r
+                       //pcp.getResource().removeRelationById(type[0], GlobalIdMap.get(Builtins.InstanceOf));\r
+                       pcp.getResource().removeRelationById(rr.getObjectId(),rr.getRelationId());\r
+                       Resource sccpType = graph.getResource(PSK3DModelingOntologyMapping.SIZE_CHANGE_CONTROL_POINT);\r
+                       pcp.createRelation(sccpType, graph.getResource(Builtins.InstanceOf));\r
+                       \r
+                       graph.commitChanges(CommitMessage.CHANGE_MESSAGE);\r
+                       \r
+                       Reducer reducer = null;\r
+                       Pipeline newPipeline = PipelineFactory.instantiate(graph);\r
+                       OffsetControlPoint offsetControlPoint = OffsetControlPointFactory.instantiate(graph);\r
+                       if (i == 0) {\r
+                               reducer = ConcentricReducerFactory.instantiate(graph);\r
+                       } else {\r
+                               reducer = EccentricReducerFactory.instantiate(graph);\r
+                       }       \r
+                       graph.commitChanges(CommitMessage.CHANGE_MESSAGE);\r
+                       SizeChangeControlPoint sccp = SizeChangeControlPointFactory.create(pcp.getResource());\r
+                       \r
+                       \r
+                       // FIXME : lenght, pipe radius and turn angle from specs + let the user choose spec for new pipeline\r
+                       double reducerLength = 0.3;\r
+                       reducer.setLengthValue(reducerLength);\r
+                       double newPipeRadius = pipelineDialog.getPipeRadius();\r
+                       double newPipeTurnRadius = pipelineDialog.getTurnRadius();\r
+\r
+                       reducer.setLocalPosition(sccp.getLocalPosition());\r
+                       reducer.setWorldPosition(sccp.getWorldPosition());\r
+                       \r
+                       reducer.setBottomRadiusValue(pipeline.getPipeRadiusValue());\r
+                       \r
+                       reducer.setPipeRadius(pipeline.getPipeRadius());\r
+                       reducer.setTopRadiusValue(newPipeRadius);\r
+                       newPipeline.setPipeRadiusValue(newPipeRadius);\r
+                       newPipeline.setTurnRadiusValue(newPipeTurnRadius);\r
+                       \r
+                       // reducer is adjuste by pipelines' radiis\r
+                       PipingTools.setSame(pipeline.getPipeRadius(), reducer.getBottomRadius());\r
+                       PipingTools.setSame(newPipeline.getPipeRadius(), reducer.getTopRadius());\r
+                       \r
+                       //newPipeline.getHasControlPointSet().add(pcp);\r
+                       sccp.setHasOffsetPoint(offsetControlPoint);\r
+                       offsetControlPoint.setOffsetPointOf(sccp);\r
+                       \r
+                       reducer.setHasControlPoint(sccp);\r
+                       graph.commitChanges(CommitMessage.CHANGE_MESSAGE);\r
+                       \r
+                       sccp.setNextComponentOffsetValue(reducerLength*0.5);\r
+                       sccp.setPreviousComponentOffsetValue(reducerLength*0.5);\r
+                       \r
+                       // offsets are calculated from reducers length\r
+                       PipingTools.setHalf(reducer.getLength(), sccp.getNextComponentOffset());\r
+                       PipingTools.setHalf(reducer.getLength(), sccp.getPreviousComponentOffset());\r
+                       \r
+                       // linking sccp and ocp offsets\r
+                       offsetControlPoint.setNextComponentOffset(sccp.getNextComponentOffset());\r
+                       offsetControlPoint.setPreviousComponentOffset(sccp.getPreviousComponentOffset());\r
+                       \r
+                       \r
+                       offsetControlPoint.setPreviousPoint(sccp.getPreviousPoint());\r
+                       offsetControlPoint.setNextPoint(sccp.getNextPoint());\r
+                       if (i == 1) {\r
+                               // FIXME : link offset value\r
+                               sccp.setOffsetValue(reducer.getBottomRadiusValue() - reducer.getTopRadiusValue());              \r
+                               sccp.setAngle(((EccentricReducer)reducer).getAngle());\r
+                               Vector3d v = PipingTools.getSizeChangeOffsetVector(sccp);\r
+                               Point3d local = GraphicsNodeTools.getTranslation(sccp.getLocalPosition());\r
+                               local.add(v);\r
+                               //Point3d World = GraphicsNodeTools.getTranslation(sccp.getLocalPosition());\r
+                               GraphicsNodeTools.setTranslation(offsetControlPoint.getLocalPosition(), local);\r
+                       } else {\r
+                               // FIXME : is it possible that pipelines are in different coordinate systems \r
+                               offsetControlPoint.setLocalPosition(sccp.getLocalPosition());\r
+                               offsetControlPoint.setWorldPosition(sccp.getWorldPosition());\r
+                       }\r
+                       ((TestProcessEditor)parent).getPlant().getHasSubnodesSet().add(newPipeline);\r
+                       pipeline.getHasSubnodesSet().add(reducer);\r
+                       newPipeline.getHasControlPointSet().add(offsetControlPoint);\r
+                       graph.commitChanges(CommitMessage.CHANGE_MESSAGE);\r
+                       \r
+                       graph.commitTransaction(CommitMessage.TRANSACTION_MESSAGE);\r
+                       \r
+                       */\r
+               \r
+               \r
+                \r
+       }\r
+       \r
+       /**\r
+        * Returns direction of a nozzle\r
+        * @param nozzle\r
+        * @return\r
+        */\r
+       public static Vector3d getNozzleDirection(IEntity nozzle) {\r
+               return ControlPointTools.getNozzleDirection(nozzle.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldOrientation));\r
+       }\r
+       \r
+       /**\r
+        * Returns true if a nozzle is not connected to a pipe\r
+        * @param nozzle\r
+        * @return\r
+        */\r
+       public static boolean isFreeNozzle(IEntity nozzle) {\r
+               assert (nozzle.isInstanceOf(ProcessResource.plant3Dresource.Nozzle));\r
+               IEntity pcp = nozzle.getSingleRelatedObject(ProcessResource.plant3Dresource.HasControlPoint);\r
+               IEntity next = pcp.getAtMostOneRelatedObject(ProcessResource.plant3Dresource.HasNext);\r
+               IEntity previous = pcp.getAtMostOneRelatedObject(ProcessResource.plant3Dresource.HasPrevious);\r
+               if (next == null && previous == null) {\r
+                       assert (pcp.getAtMostOneRelatedObject(ProcessResource.plant3Dresource.ControlPointOfPipeRun) == null);\r
+                       return true;\r
+               }\r
+               assert (pcp.getAtMostOneRelatedObject(ProcessResource.plant3Dresource.ControlPointOfPipeRun) != null);\r
+               return false;\r
+       }\r
+       \r
+       public static void getInlineComponentEnds(IEntity inlineComponent, Point3d p1, Point3d p2) {\r
+               assert(inlineComponent.isInstanceOf(ProcessResource.plant3Dresource.InlineComponent));\r
+               ControlPointTools.getInlineControlPointEnds(inlineComponent.getSingleRelatedObject(ProcessResource.plant3Dresource.HasControlPoint), p1, p2);\r
+       }\r
+       \r
+       public static void getInlineComponentEnds(IEntity inlineComponent, Point3d p1, Point3d p2, Vector3d dir) {\r
+               assert(inlineComponent.isInstanceOf(ProcessResource.plant3Dresource.InlineComponent));\r
+               ControlPointTools.getInlineControlPointEnds(inlineComponent.getSingleRelatedObject(ProcessResource.plant3Dresource.HasControlPoint), p1, p2,dir);\r
+       }\r
+       \r
+       public static void getInlineComponentEnds(IEntity inlineComponent, Point3d center, Point3d p1, Point3d p2, Vector3d dir) {\r
+               assert(inlineComponent.isInstanceOf(ProcessResource.plant3Dresource.InlineComponent));\r
+               ControlPointTools.getInlineControlPointEnds(inlineComponent.getSingleRelatedObject(ProcessResource.plant3Dresource.HasControlPoint), center, p1, p2,dir);\r
+       }\r
+       \r
+       public static void removePipeRun(PipeRun pipeRun) {\r
+       if (DEBUG) System.out.println("PipingTools.removePipeRun() " + pipeRun.getResource());\r
+       G3DNode parent = pipeRun.getParent();\r
+       if (parent != null)\r
+               parent.getChild().remove(pipeRun);\r
+\r
+    }\r
+       /**\r
+        * Liks piperun's specs to nozzle's specs\r
+        * @param nozzle\r
+        * @param piperun\r
+        */\r
+       public static void linkNozzleAndPipeRun(IEntity nozzle, IEntity piperun) {\r
+               assert(nozzle.isInstanceOf(ProcessResource.plant3Dresource.Nozzle));\r
+               assert(piperun.isInstanceOf(ProcessResource.plant3Dresource.PipeRun));\r
+               IEntity diam = piperun.getSingleRelatedObject(ProcessResource.plant3Dresource.HasPipeDiameter); \r
+       \r
+       piperun.addStatement(ProcessResource.plant3Dresource.HasControlPoints, nozzle.getSingleRelatedObject(ProcessResource.plant3Dresource.HasControlPoint));\r
+       setStatement(nozzle, ProcessResource.plant3Dresource.HasPipeDiameter, diam);\r
+       }\r
+       \r
+       /**\r
+        * Unlinks piperun's specs from nozzle's specs.\r
+        * @param nozzle\r
+        * @param piperun\r
+        */\r
+       public static void unlinkNozzleAndPiperun(IEntity nozzle, IEntity piperun) {\r
+               assert(nozzle.isInstanceOf(ProcessResource.plant3Dresource.Nozzle));\r
+               assert(piperun.isInstanceOf(ProcessResource.plant3Dresource.PipeRun));\r
+               \r
+               piperun.removeStatement(ProcessResource.plant3Dresource.HasControlPoints, nozzle.getSingleRelatedObject(ProcessResource.plant3Dresource.HasControlPoint));      \r
+               // get current diameter\r
+               double diam = nozzle.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasPipeDiameter);\r
+               // remove link to shared diameter resource\r
+               nozzle.removeRelatedStatements(ProcessResource.plant3Dresource.HasPipeDiameter);\r
+               // create new reource for diameter\r
+               nozzle.setRelatedScalarDouble(ProcessResource.plant3Dresource.HasPipeDiameter, diam);\r
+       }\r
+       \r
+       private static void setStatement(IEntity subject, Resource relation, IEntity object) {\r
+       subject.removeRelatedStatements(relation);\r
+       subject.addStatement(relation, object);\r
+    }\r
+       \r
+       public static void getInlineMovement(InlineComponent ic, Point3d start, Point3d end) {\r
+               PipeControlPoint pcp = ic.getControlPoint();\r
+               ControlPointTools.getInlineMovement(pcp, start, end);\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/ConfigureAnimationDialog.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/ConfigureAnimationDialog.java
new file mode 100644 (file)
index 0000000..de5e5aa
--- /dev/null
@@ -0,0 +1,478 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007 VTT Technical Research Centre of Finland and others.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package fi.vtt.simantics.processeditor.dialogs;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.HashMap;\r
+import java.util.HashSet;\r
+import java.util.Map;\r
+import java.util.Set;\r
+import java.util.TreeMap;\r
+import java.util.Map.Entry;\r
+\r
+import org.eclipse.jface.dialogs.Dialog;\r
+import org.eclipse.jface.dialogs.IDialogConstants;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.events.SelectionAdapter;\r
+import org.eclipse.swt.events.SelectionEvent;\r
+import org.eclipse.swt.events.SelectionListener;\r
+import org.eclipse.swt.layout.FillLayout;\r
+import org.eclipse.swt.layout.GridData;\r
+import org.eclipse.swt.layout.GridLayout;\r
+import org.eclipse.swt.widgets.Button;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.swt.widgets.Control;\r
+import org.eclipse.swt.widgets.Label;\r
+import org.eclipse.swt.widgets.List;\r
+import org.eclipse.swt.widgets.Shell;\r
+import org.eclipse.swt.widgets.Text;\r
+import org.simantics.db.Graph;\r
+import org.simantics.db.GraphRequestAdapter;\r
+import org.simantics.db.GraphRequestStatus;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.Session;\r
+import org.simantics.g2d.stubs.anim.Animation;\r
+import org.simantics.layer0.utils.EntityFactory;\r
+import org.simantics.layer0.utils.IEntity;\r
+import org.simantics.layer0.utils.viewpoints.TraversalPath;\r
+import org.simantics.proconf.browsing.GraphExplorer;\r
+import org.simantics.proconf.g3d.animation.Animatable;\r
+import org.simantics.proconf.g3d.animation.AnimationSystem;\r
+import org.simantics.proconf.g3d.animation.ResourceAnimationController;\r
+import org.simantics.proconf.g3d.animation.ScaledResourceAnimationController;\r
+import org.simantics.proconf.g3d.base.ScenegraphAdapter;\r
+import org.simantics.proconf.g3d.scenegraph.IGraphicsNode;\r
+import org.simantics.proconf.g3d.stubs.G3DModel;\r
+import org.simantics.proconf.g3d.tools.OEPathSelectionListener;\r
+import org.simantics.utils.ErrorLogger;\r
+\r
+import fi.vtt.simantics.processeditor.ProcessResource;\r
+import fi.vtt.simantics.processeditor.common.PathUtils;\r
+\r
+public class ConfigureAnimationDialog extends Dialog {\r
+       Session session;\r
+       List typeList;\r
+       List animationList;\r
+       java.util.List<Resource> nodes;\r
+       Set<Resource> models;\r
+       \r
+       private Composite oeLabelComposite;\r
+       //private Control viewpointControl;\r
+       private Composite oeComposite;\r
+       private GraphExplorer oe;\r
+       private Map<Resource,Resource> instanceModelMap = new HashMap<Resource, Resource>();\r
+       private ScenegraphAdapter adapter;\r
+       \r
+       private Button applyAnimationButton;\r
+       \r
+       Resource selectedType;\r
+       Resource sampleInstance;\r
+       Resource sampleSource;\r
+       java.util.List<Resource> samplePath;\r
+       AnimationSystem animationSystem;\r
+       \r
+       Button scaleButton;\r
+       Text minText;\r
+       Text maxText;\r
+       \r
+       public ConfigureAnimationDialog(Shell parentShell, Session session, java.util.List<Resource> nodes, ScenegraphAdapter adapter, AnimationSystem animationSystem) {\r
+               super(parentShell);\r
+               this.session = session;\r
+               this.nodes = nodes;\r
+               models = new HashSet<Resource>();\r
+               session.syncRead(new GraphRequestAdapter() {\r
+                       @Override\r
+                       public GraphRequestStatus perform(Graph g) throws Exception {\r
+                               for (Resource n : ConfigureAnimationDialog.this.nodes) {\r
+                                       IEntity t = EntityFactory.create(g,n);\r
+                                       Collection<IEntity> r = t.getRelatedObjects(ProcessResource.plant3Dresource.HasGraphics);\r
+                                       if (r.size() == 1) {\r
+                                               IEntity model = r.iterator().next();\r
+                                               if (model.isInstanceOf(ProcessResource.g3dResource.G3DModel)) {\r
+                                                       models.add(model.getResource());\r
+                                                       instanceModelMap.put(n, model.getResource());\r
+                                               } else {\r
+                                                       throw new RuntimeException("Expected G3DModel, got something else " + model);\r
+                                               }\r
+                                       } else {\r
+                                               ErrorLogger.getDefault().logWarning("Got node without a model", null);\r
+                                       }\r
+                               }\r
+                               return GraphRequestStatus.transactionComplete();\r
+                       }\r
+               });\r
+               \r
+               this.adapter = adapter;\r
+               this.animationSystem = animationSystem;\r
+               int shellStyle = getShellStyle();\r
+               setShellStyle(shellStyle | SWT.MAX | SWT.RESIZE);\r
+       }\r
+       \r
+       @Override\r
+    protected void configureShell(Shell newShell) {  \r
+        super.configureShell(newShell);\r
+        newShell.setText("Configure animations");\r
+        \r
+    }\r
+       \r
+       protected Control createDialogArea(Composite parent) {\r
+        Composite composite = (Composite) super.createDialogArea(parent);\r
+        GridLayout layout = new GridLayout(4,true);\r
+               layout.marginHeight = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN);\r
+               layout.marginWidth = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN);\r
+               layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);\r
+               layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);\r
+               composite.setLayout(layout);\r
+               \r
+               Label label = new Label(composite, SWT.WRAP);\r
+        label.setText("Types");\r
+//        GridData data = new GridData(GridData.GRAB_HORIZONTAL\r
+//                | GridData.GRAB_VERTICAL | GridData.HORIZONTAL_ALIGN_FILL\r
+//                | GridData.VERTICAL_ALIGN_BEGINNING);\r
+        GridData data = new GridData(GridData.CENTER,GridData.FILL,true,false,1,1);\r
+        data.widthHint = convertHorizontalDLUsToPixels(IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH);\r
+        label.setLayoutData(data);\r
+        label.setFont(parent.getFont());\r
+        \r
+        label = new Label(composite, SWT.WRAP);\r
+        label.setText("Models");\r
+        label.setLayoutData(data);\r
+        label.setFont(parent.getFont());\r
+        \r
+        label = new Label(composite, SWT.WRAP);\r
+        label.setText("Animations");\r
+        label.setLayoutData(data);\r
+        label.setFont(parent.getFont());\r
+        \r
+        oeLabelComposite = new Composite(composite,SWT.NONE);\r
+        data = new GridData(GridData.CENTER,GridData.FILL,true,false,1,1);\r
+        data.widthHint = convertHorizontalDLUsToPixels(IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH);\r
+        \r
+        oeLabelComposite.setLayoutData(data);\r
+        oeLabelComposite.setLayout(new FillLayout(SWT.HORIZONTAL));\r
+        //label = new Label(composite, SWT.WRAP);\r
+        label = new Label(oeLabelComposite, SWT.WRAP);\r
+        label.setText("Animation source");\r
+//        label.setLayoutData(data);\r
+        label.setFont(parent.getFont());\r
+        \r
+        typeList = new List(composite, SWT.BORDER | SWT.SINGLE | SWT.READ_ONLY | SWT.V_SCROLL);\r
+        typeList.setLayoutData(new GridData(GridData.GRAB_VERTICAL | GridData.VERTICAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL));\r
+//        modelList = new List(composite, SWT.BORDER | SWT.SINGLE | SWT.READ_ONLY | SWT.V_SCROLL);\r
+//        modelList.setLayoutData(new GridData(GridData.GRAB_VERTICAL | GridData.VERTICAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL));\r
+        animationList = new List(composite, SWT.BORDER | SWT.SINGLE | SWT.READ_ONLY | SWT.V_SCROLL);\r
+        animationList.setLayoutData(new GridData(GridData.GRAB_VERTICAL | GridData.VERTICAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL));\r
+        oeComposite = new Composite(composite,SWT.BORDER);\r
+        oeComposite.setLayoutData(new GridData(GridData.GRAB_VERTICAL | GridData.VERTICAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL));\r
+        layout = new GridLayout();\r
+        layout.marginWidth = 0;\r
+        layout.marginHeight = 0;\r
+        oeComposite.setLayout(layout);\r
+        \r
+        session.asyncRead(new GraphRequestAdapter() {\r
+               TreeMap<String, Resource> sorter;\r
+               @Override\r
+               public GraphRequestStatus perform(Graph g) throws Exception {\r
+                       Collection<Resource> types = getTypes(g,nodes);\r
+                       \r
+                        sorter = new TreeMap<String, Resource>();\r
+                       for (Resource type : types) {\r
+                               IEntity t = EntityFactory.create(g,type);\r
+                               if (t.getRelatedObjects(ProcessResource.plant3Dresource.HasGraphics).size() > 0) {\r
+                                       String key = t.getName();\r
+                               if (key.equals("")) key = "ERROR (" + type.getResourceId() + ")";\r
+                               sorter.put(key, type);\r
+                               }\r
+                       }\r
+                       \r
+                       \r
+                       \r
+                       return GraphRequestStatus.transactionComplete();\r
+               }\r
+               \r
+               @Override\r
+               public void requestCompleted(GraphRequestStatus status) {\r
+                       getShell().getDisplay().asyncExec(new Runnable(){\r
+                               @Override\r
+                               public void run() {\r
+                                       for (Entry<String, Resource> e : sorter.entrySet()) {\r
+                           typeList.add(e.getKey());\r
+                           typeList.setData(e.getKey(), e.getValue());\r
+                       }\r
+                               }\r
+                       });\r
+               }\r
+        });\r
+       \r
+        typeList.addSelectionListener(new SelectionListener() {\r
+            public void widgetSelected(SelectionEvent e) {\r
+               session.asyncRead(new GraphRequestAdapter(){\r
+                       @Override\r
+                       public GraphRequestStatus perform(Graph g) throws Exception {\r
+                               String key = typeList.getItem(typeList.getSelectionIndex());\r
+                        selectType(EntityFactory.create(g,(Resource) typeList.getData(key)));\r
+                               return GraphRequestStatus.transactionComplete();\r
+                       }\r
+               });\r
+                \r
+            }\r
+            public void widgetDefaultSelected(SelectionEvent e) {\r
+            }\r
+        });\r
+        \r
+//        modelList.addSelectionListener(new SelectionListener() {\r
+//            public void widgetSelected(SelectionEvent e) {\r
+//             if (modelList.getSelectionIndex() < 0 || modelList.getSelectionIndex() >= modelList.getItemCount())\r
+//                     return;\r
+//                String key = modelList.getItem(modelList.getSelectionIndex());\r
+//                selectModel((GraphicsModel) modelList.getData(key));\r
+//            }\r
+//            public void widgetDefaultSelected(SelectionEvent e) {\r
+//            }\r
+//        });\r
+        \r
+        Composite buttonComposite = new Composite(composite,SWT.NONE);\r
+        buttonComposite.setLayoutData(new GridData(GridData.END,GridData.FILL,true,false,4,1));\r
+        buttonComposite.setLayout(new FillLayout(SWT.HORIZONTAL));\r
+        scaleButton = new Button(buttonComposite,SWT.CHECK);\r
+        scaleButton.setText("Scaling");\r
+        scaleButton.addSelectionListener(new SelectionAdapter() {\r
+               @Override\r
+               public void widgetSelected(SelectionEvent e) {\r
+                       if (scaleButton.getSelection()) {\r
+                               minText.setEnabled(true);\r
+                               maxText.setEnabled(true);\r
+                       } else {\r
+                               minText.setEnabled(false);\r
+                               maxText.setEnabled(false);\r
+                       }\r
+               }\r
+        });\r
+        minText = new Text(buttonComposite,SWT.SINGLE|SWT.BORDER);\r
+        minText.setText("0.0");\r
+        \r
+        maxText = new Text(buttonComposite,SWT.SINGLE|SWT.BORDER);\r
+        maxText.setText("1.0");\r
+        \r
+        minText.setEnabled(false);\r
+               maxText.setEnabled(false);\r
+        \r
+        applyAnimationButton = new Button(buttonComposite,SWT.PUSH);\r
+        applyAnimationButton.setText("Apply animation");\r
+        applyAnimationButton.addSelectionListener(new SelectionAdapter() {\r
+               @Override\r
+               public void widgetSelected(SelectionEvent e) {\r
+                       session.asyncRead(new GraphRequestAdapter() {\r
+                               @Override\r
+                               public GraphRequestStatus perform(Graph g) throws Exception {\r
+                                       applyAnimation(g);\r
+                                       return GraphRequestStatus.transactionComplete();\r
+                               }\r
+                       });\r
+                       \r
+               }\r
+        });\r
+        return composite;\r
+       }\r
+       \r
+       /**\r
+        * Updates type selection:\r
+        * Finds all GraphicsModels that are connected to instances of selected type with HasGraphics-relation\r
+        * and lists them in modelList.\r
+        *\r
+        * @param resource\r
+        */\r
+       private void selectType(IEntity resource) {\r
+               Graph g = resource.getGraph();\r
+               selectedType = resource.getResource();\r
+               //modelList.removeAll();\r
+               animationList.removeAll();\r
+               \r
+               Collection<IEntity> model = resource.getRelatedObjects(ProcessResource.plant3Dresource.HasGraphics);\r
+               if (model.size() != 1)\r
+                       throw new RuntimeException("Type " + resource + " does not have a model");\r
+        \r
+        if (oe != null) {\r
+               oe.dispose();   \r
+        }\r
+        sampleInstance = null;\r
+        sampleSource = null;\r
+        for (Resource n : nodes) {\r
+               IEntity t = EntityFactory.create(g,n);\r
+               if (t.isInstanceOf(resource.getResource())) {\r
+                       sampleInstance = n;\r
+                       break;\r
+               }\r
+        }\r
+        if (sampleInstance != null) {\r
+//             oe = new OntologyExplorer("Animation Source",this.getShell(), new OntologyEditorInput(sampleInstance.getId()));\r
+//             if(viewpointControl != null && !viewpointControl.isDisposed()) {\r
+//                     viewpointControl.dispose();\r
+//             }\r
+//             viewpointControl = oe.getControl(oeLabelComposite, 1, OntologyExplorer.ViewpointSelector, SWT.NONE);\r
+//             Control c = oe.getControl(oeComposite, 1, OntologyExplorer.OntologyTree, SWT.SINGLE);\r
+//             c.setLayoutData(new GridData(GridData.FILL_BOTH));\r
+//             oe.init(null, ViewpointUtils.getModelledHandler(oe.getGraph(), Builtins.DefaultViewpointId), null, ViewLabelProviderDecorationSettings.DEFAULT, new MenuAboutToShowAction(), new NullAdditionAction(), false);\r
+//             //oeComposite.layout(true, true);\r
+//             oe.setSelectionScheme(new SourceSelectionScheme(oe));\r
+//             //oeLabelComposite.layout(true, true);\r
+//             oeComposite.getParent().getParent().layout(true,true);\r
+        \r
+               oe = new GraphExplorer(oeComposite,SWT.SINGLE);\r
+               oe.getTree().setLayoutData(new GridData(GridData.FILL_BOTH));\r
+               oe.getViewer().addPostSelectionChangedListener(new OEPathSelectionListener(){\r
+                       @Override\r
+                       protected void pathSelectionUpdated(java.util.List<TraversalPath> paths) {\r
+                               if (paths.size() == 0) {\r
+                       //selectSource(null);\r
+                   } else {\r
+                       final TraversalPath path = paths.iterator().next();\r
+                       session.asyncRead(new GraphRequestAdapter() {\r
+                               @Override\r
+                               public GraphRequestStatus perform(Graph g) throws Exception {\r
+                                       selectSource(g,path);\r
+                                       return GraphRequestStatus.transactionComplete();\r
+                               }\r
+                       });\r
+                       \r
+                   }   \r
+                       }\r
+               });\r
+        }\r
+               \r
+//        modelList.redraw();\r
+//        animationList.redraw();\r
+        selectModel(new G3DModel(model.iterator().next()));\r
+       }\r
+       \r
+       /**\r
+        * Selects model and shows model's animations in animationList\r
+        * @param model\r
+        */\r
+       private void selectModel(G3DModel model) {\r
+               animationList.removeAll();\r
+               \r
+               TreeMap<String, Animation> sorter = new TreeMap<String, Animation>();\r
+        \r
+               Collection<Animation> animations = model.getAnimation();\r
+               for (Animation a : animations) {\r
+                       String key = a.getName();\r
+               if (key.equals("")) key = "ERROR (" + a.getResource().getResourceId() + ")";\r
+               sorter.put(key, a);\r
+               }\r
+               \r
+               final TreeMap<String, Animation> fa = sorter;\r
+               \r
+               getShell().getDisplay().asyncExec(new Runnable() {\r
+                       @Override\r
+                       public void run() {\r
+                               for (Entry<String, Animation> e : fa.entrySet()) {\r
+                           animationList.add(e.getKey());\r
+                           animationList.setData(e.getKey(), e.getValue());\r
+                       }\r
+                               animationList.redraw();\r
+                               \r
+                       }\r
+               });\r
+               \r
+       }\r
+       \r
+       private void selectSource(Graph graph,TraversalPath path) {\r
+               //System.out.println(sampleInstance + " " + resource);\r
+               \r
+               if (path == null) {\r
+                       sampleSource = null;\r
+                       return;\r
+               } \r
+               IEntity t = EntityFactory.create(graph,path.getResource());\r
+               if (!t.isInstanceOf(ProcessResource.builtins.Double)) {\r
+                       sampleSource = null;\r
+               } else {\r
+                       sampleSource = path.getResource();\r
+                       samplePath = new ArrayList<Resource>();\r
+                       PathUtils.createPath(samplePath, path ,sampleInstance,sampleSource,oe);\r
+               }\r
+       }\r
+       \r
+       \r
+       \r
+       private void applyAnimation(Graph graph) {\r
+               int animationIndex = animationList.getSelectionIndex();\r
+               if (sampleInstance == null || sampleSource == null || samplePath == null || animationIndex == -1) {\r
+                       throw new RuntimeException("Missing required selections");\r
+                       //return;\r
+               }\r
+               \r
+               java.util.List<Resource> instances = new ArrayList<Resource>();\r
+               java.util.List<Resource> sources = new ArrayList<Resource>();\r
+               browseOthers(graph,instances, sources);\r
+               instances.add(sampleInstance);\r
+               sources.add(sampleSource);\r
+               \r
+               for (int i = 0; i < instances.size(); i++) {\r
+                       IGraphicsNode n = adapter.getNode(instances.get(i));\r
+                       if (!(n instanceof Animatable)) {\r
+                               //throw new RuntimeException("Node is not animatable");\r
+                               continue;\r
+                       }\r
+\r
+                       Animatable animatable = (Animatable) n;\r
+                       Animation a = (Animation) animationList.getData(animationList.getItem(animationIndex));\r
+                       if (!animatable.setAnimation(graph,a.getResource())) {\r
+                               //throw new RuntimeException("Cannot set animation");\r
+                               continue;\r
+                       }\r
+                       ResourceAnimationController c;\r
+                       if (scaleButton.getSelection()) {\r
+                               c = new ScaledResourceAnimationController(sources.get(i),Double.parseDouble(minText.getText()),Double.parseDouble(maxText.getText()));\r
+                       } else {\r
+                               c = new ResourceAnimationController(sources.get(i));\r
+                       }\r
+                       c.addAnimatable(animatable);\r
+                       animationSystem.add(c);\r
+               }\r
+               \r
+       }\r
+       \r
+       private void browseOthers(Graph g, java.util.List<Resource> instances,java.util.List<Resource> sources) {\r
+               java.util.List<Resource> possibleInstances = new ArrayList<Resource>();\r
+               for (Resource n : nodes) {\r
+                       IEntity t = EntityFactory.create(g,n);\r
+                       if (t.isInstanceOf(selectedType) && !n.equals(sampleInstance)) {\r
+                               possibleInstances.add(n.getResource());\r
+                       }\r
+               }\r
+               \r
+               for (Resource instance : possibleInstances) {\r
+                       IEntity source = PathUtils.findSimilar(samplePath,EntityFactory.create(g,instance));\r
+                       if (source != null) {\r
+                               instances.add(instance);\r
+                               sources.add(source.getResource());\r
+                       } else {\r
+                               ErrorLogger.getDefault().logWarning("Cannot find animation source for " + instance, null);\r
+                       }\r
+               }\r
+       }\r
+       \r
+       \r
+       private Collection<Resource> getTypes(Graph g, java.util.List<Resource> instances) {\r
+               Set<Resource> types = new HashSet<Resource>();\r
+               for (Resource r : instances) {\r
+                       IEntity t = EntityFactory.create(g,r);\r
+                       Collection<IEntity> tTypes = t.getTypes();\r
+                       for (IEntity type : tTypes)\r
+                               types.add(type.getResource());\r
+               }\r
+               return types;\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/ConfigureMonitorDialog.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/ConfigureMonitorDialog.java
new file mode 100644 (file)
index 0000000..a771976
--- /dev/null
@@ -0,0 +1,309 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007 VTT Technical Research Centre of Finland and others.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package fi.vtt.simantics.processeditor.dialogs;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.HashSet;\r
+import java.util.Set;\r
+import java.util.TreeMap;\r
+import java.util.Map.Entry;\r
+\r
+import org.eclipse.jface.dialogs.Dialog;\r
+import org.eclipse.jface.dialogs.IDialogConstants;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.events.SelectionAdapter;\r
+import org.eclipse.swt.events.SelectionEvent;\r
+import org.eclipse.swt.events.SelectionListener;\r
+import org.eclipse.swt.layout.FillLayout;\r
+import org.eclipse.swt.layout.GridData;\r
+import org.eclipse.swt.layout.GridLayout;\r
+import org.eclipse.swt.widgets.Button;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.swt.widgets.Control;\r
+import org.eclipse.swt.widgets.Label;\r
+import org.eclipse.swt.widgets.List;\r
+import org.eclipse.swt.widgets.Shell;\r
+import org.simantics.db.Graph;\r
+import org.simantics.db.GraphRequestAdapter;\r
+import org.simantics.db.GraphRequestStatus;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.Session;\r
+import org.simantics.layer0.utils.EntityFactory;\r
+import org.simantics.layer0.utils.IEntity;\r
+import org.simantics.layer0.utils.viewpoints.TraversalPath;\r
+import org.simantics.proconf.browsing.GraphExplorer;\r
+import org.simantics.proconf.g3d.stubs.G3DModel;\r
+import org.simantics.proconf.g3d.tools.OEPathSelectionListener;\r
+\r
+import fi.vtt.simantics.processeditor.ProcessResource;\r
+import fi.vtt.simantics.processeditor.common.PathUtils;\r
+import fi.vtt.simantics.processeditor.monitors.PathContainer;\r
+\r
+public class ConfigureMonitorDialog extends Dialog {\r
+       Session session;\r
+       List typeList;\r
+       java.util.List<Resource> nodes;\r
+\r
+       \r
+       private Composite oeLabelComposite;\r
+       //private Control viewpointControl;\r
+       private Composite oeComposite;\r
+       private GraphExplorer oe;\r
+       \r
+       private Button applyAnimationButton;\r
+       \r
+       Resource selectedType;\r
+       Resource sampleInstance;\r
+       java.util.List<Resource> sampleSource;\r
+       java.util.List<java.util.List<Resource>> samplePath;\r
+\r
+       \r
+       public ConfigureMonitorDialog(Shell parentShell, Session session, java.util.List<Resource> nodes) {\r
+               super(parentShell);\r
+               this.nodes = nodes;\r
+               this.session = session;\r
+               int shellStyle = getShellStyle();\r
+               setShellStyle(shellStyle | SWT.MAX | SWT.RESIZE);\r
+       }\r
+       \r
+       @Override\r
+    protected void configureShell(Shell newShell) {  \r
+        super.configureShell(newShell);\r
+        newShell.setText("Configure monitors");\r
+        \r
+    }\r
+       \r
+       protected Control createDialogArea(Composite parent) {\r
+        Composite composite = (Composite) super.createDialogArea(parent);\r
+        GridLayout layout = new GridLayout(2,true);\r
+               layout.marginHeight = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN);\r
+               layout.marginWidth = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN);\r
+               layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);\r
+               layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);\r
+               composite.setLayout(layout);\r
+               \r
+               Label label = new Label(composite, SWT.WRAP);\r
+        label.setText("Types");\r
+        GridData data = new GridData(GridData.CENTER,GridData.FILL,true,false,1,1);\r
+        data.widthHint = convertHorizontalDLUsToPixels(IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH);\r
+        label.setLayoutData(data);\r
+        label.setFont(parent.getFont());\r
+        \r
+        oeLabelComposite = new Composite(composite,SWT.NONE);\r
+        oeLabelComposite.setLayoutData(data);\r
+        oeLabelComposite.setLayout(new FillLayout(SWT.HORIZONTAL));\r
+        //label = new Label(composite, SWT.WRAP);\r
+        label = new Label(oeLabelComposite, SWT.WRAP);\r
+        label.setText("Monitor source");\r
+//        label.setLayoutData(data);\r
+        label.setFont(parent.getFont());\r
+        \r
+        typeList = new List(composite, SWT.BORDER | SWT.SINGLE | SWT.READ_ONLY | SWT.V_SCROLL);\r
+        typeList.setLayoutData(new GridData(GridData.GRAB_VERTICAL | GridData.VERTICAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL));\r
+        \r
+        oeComposite = new Composite(composite,SWT.BORDER);\r
+        oeComposite.setLayoutData(new GridData(GridData.GRAB_VERTICAL | GridData.VERTICAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL));\r
+        layout = new GridLayout();\r
+        layout.marginWidth = 0;\r
+        layout.marginHeight = 0;\r
+        oeComposite.setLayout(layout);\r
+        session.asyncRead(new GraphRequestAdapter() {\r
+               TreeMap<String, Resource> sorter;\r
+               @Override\r
+               public GraphRequestStatus perform(Graph g) throws Exception {\r
+                       Collection<Resource> types = getTypes(g,nodes);\r
+                \r
+                sorter = new TreeMap<String, Resource>();\r
+                for (Resource type : types) {\r
+                       IEntity t = EntityFactory.create(g, type);\r
+                    String key = t.getName();\r
+                    if (key.equals("")) key = "ERROR (" + type.getResourceId() + ")";\r
+                    sorter.put(key, type);\r
+                }\r
+                \r
+               \r
+                       return GraphRequestStatus.transactionComplete();\r
+               }\r
+               \r
+               @Override\r
+               public void requestCompleted(GraphRequestStatus status) {\r
+                       getShell().getDisplay().asyncExec(new Runnable() {\r
+                               @Override\r
+                               public void run() {\r
+                                        for (Entry<String, Resource> e : sorter.entrySet()) {    \r
+                               typeList.add(e.getKey());\r
+                               typeList.setData(e.getKey(), e.getValue());\r
+                                        }\r
+                               }\r
+                       });\r
+               }\r
+        });\r
+        \r
+        typeList.addSelectionListener(new SelectionListener() {\r
+            public void widgetSelected(SelectionEvent e) {\r
+               session.asyncRead(new GraphRequestAdapter() {\r
+                       @Override\r
+                       public GraphRequestStatus perform(Graph g) throws Exception {\r
+                                String key = typeList.getItem(typeList.getSelectionIndex());\r
+                         selectType(EntityFactory.create(g,(Resource) typeList.getData(key)));\r
+                                return GraphRequestStatus.transactionComplete();\r
+                       }\r
+               });\r
+               \r
+            }\r
+            public void widgetDefaultSelected(SelectionEvent e) {\r
+            }\r
+        });\r
+        \r
+     \r
+        \r
+        Composite buttonComposite = new Composite(composite,SWT.NONE);\r
+        buttonComposite.setLayoutData(new GridData(GridData.END,GridData.FILL,true,false,4,1));\r
+        buttonComposite.setLayout(new FillLayout(SWT.HORIZONTAL));\r
+        \r
+        \r
+        applyAnimationButton = new Button(buttonComposite,SWT.PUSH);\r
+        applyAnimationButton.setText("Apply monitor configuration");\r
+        applyAnimationButton.addSelectionListener(new SelectionAdapter() {\r
+               @Override\r
+               public void widgetSelected(SelectionEvent e) {\r
+                       applyAnimation();\r
+               }\r
+        });\r
+        return composite;\r
+       }\r
+       \r
+       /**\r
+        * Updates type selection:\r
+        * Finds all GraphicsModels that are connected to instances of selected type with HasGraphics-relation\r
+        * and lists them in modelList.\r
+        *\r
+        * @param resource\r
+        */\r
+       private void selectType(IEntity resource) {\r
+               selectedType = resource.getResource();\r
+               \r
+               TreeMap<String, G3DModel> sorter = new TreeMap<String, G3DModel>();\r
+               \r
+               Collection<IEntity> models = resource.getRelatedObjects(ProcessResource.plant3Dresource.HasGraphics);\r
+        for (IEntity model : models) {\r
+               \r
+                       String key = model.getName();\r
+               if (key.equals("")) key = "ERROR (" + model.getResource().getResourceId() + ")";\r
+               sorter.put(key, new G3DModel(model));\r
+        }\r
+        \r
+        if (oe != null) {\r
+               oe.dispose();   \r
+        }\r
+        sampleInstance = null;\r
+        sampleSource = null;\r
+        for (Resource n : nodes) {\r
+               IEntity t = EntityFactory.create(resource.getGraph(),n);\r
+               if (t.isInstanceOf(resource.getResource())) {\r
+                       sampleInstance = n;\r
+                       break;\r
+               }\r
+        }\r
+        if (sampleInstance != null) {\r
+//             oe = new OntologyExplorer("Animation Source",this.getShell(), new OntologyEditorInput(sampleInstance.getId()));\r
+//             if(viewpointControl != null && !viewpointControl.isDisposed()) {\r
+//                     viewpointControl.dispose();\r
+//             }\r
+//             viewpointControl = oe.getControl(oeLabelComposite, 1, OntologyExplorer.ViewpointSelector, SWT.NONE);\r
+//             Control c = oe.getControl(oeComposite, 1, OntologyExplorer.OntologyTree, SWT.MULTI);\r
+//             c.setLayoutData(new GridData(GridData.FILL_BOTH));\r
+//             oe.init(null, ViewpointUtils.getModelledHandler(oe.getGraph(), Builtins.DefaultViewpointId), null, ViewLabelProviderDecorationSettings.DEFAULT, new MenuAboutToShowAction(), new NullAdditionAction(), false);\r
+//             oe.setSelectionScheme(new SourceSelectionScheme(oe));\r
+//             oeComposite.getParent().layout(true,true);\r
+               oe = new GraphExplorer(oeComposite,SWT.MULTI);\r
+               oe.getTree().setLayoutData(new GridData(GridData.FILL_BOTH));\r
+               oe.getViewer().addPostSelectionChangedListener(new OEPathSelectionListener(){\r
+                       @Override\r
+                       protected void pathSelectionUpdated(java.util.List<TraversalPath> paths) {\r
+                               if (paths.size() == 0) {\r
+                       //selectSource(null);\r
+                   } else {\r
+                       final java.util.List<TraversalPath> ps = paths;\r
+                       session.asyncRead(new GraphRequestAdapter() {\r
+                               @Override\r
+                               public GraphRequestStatus perform(Graph g) throws Exception {\r
+                                       selectSource(g,ps);\r
+                                       return GraphRequestStatus.transactionComplete();\r
+                               }\r
+                       });\r
+                       \r
+                   }\r
+                               \r
+                       }\r
+               });\r
+        }\r
+               \r
+       }\r
+       \r
+       \r
+       \r
+       private void selectSource(Graph graph, java.util.List<TraversalPath> resources) {\r
+               if (resources == null) {\r
+                       sampleSource = null;\r
+               }\r
+               for (TraversalPath p : resources) {\r
+                       IEntity t = EntityFactory.create(graph, p.getResource());\r
+                       if (!t.isInstanceOf(ProcessResource.builtins.Double)) {\r
+                               sampleSource = null;\r
+                               return;\r
+                       }\r
+               }\r
+               sampleSource = new ArrayList<Resource>();\r
+               for (TraversalPath p : resources)\r
+                       sampleSource.add(p.getResource());\r
+               \r
+               samplePath = new ArrayList<java.util.List<Resource>>();\r
+               for (int i = 0; i < sampleSource.size(); i++) {\r
+                       TraversalPath tpath = resources.get(i);\r
+                       java.util.List<Resource> path = new ArrayList<Resource>();\r
+                       PathUtils.createPath(path, tpath,sampleInstance,sampleSource.get(i),oe);\r
+                       samplePath.add(path);\r
+               }       \r
+               \r
+       }\r
+       \r
+       private void applyAnimation() {\r
+               \r
+               if (sampleInstance == null || sampleSource == null || samplePath == null ) {\r
+                       throw new RuntimeException("Missing required selections");\r
+                       //return;\r
+               }\r
+\r
+               PathContainer.getInstance().clearPaths(selectedType);\r
+               for (java.util.List<Resource> s : samplePath) {\r
+                       PathContainer.getInstance().addPath(selectedType, s);\r
+               }\r
+       }\r
+       \r
+\r
+       \r
+\r
+\r
+       private Collection<Resource> getTypes(Graph g, java.util.List<Resource> instances) {\r
+               Set<Resource> types = new HashSet<Resource>();\r
+               for (Resource r : instances) {\r
+                       IEntity t = EntityFactory.create(g,r);\r
+                       Collection<IEntity> tTypes = t.getTypes();\r
+                       for (IEntity type : tTypes)\r
+                               types.add(type.getResource());\r
+               }\r
+               return types;\r
+       }\r
+       \r
+       \r
+}\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/ConfigurePipelineAnimationDialog.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/ConfigurePipelineAnimationDialog.java
new file mode 100644 (file)
index 0000000..2735a69
--- /dev/null
@@ -0,0 +1,315 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007 VTT Technical Research Centre of Finland and others.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package fi.vtt.simantics.processeditor.dialogs;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import org.eclipse.jface.dialogs.Dialog;\r
+import org.eclipse.jface.dialogs.IDialogConstants;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.events.SelectionAdapter;\r
+import org.eclipse.swt.events.SelectionEvent;\r
+import org.eclipse.swt.layout.FillLayout;\r
+import org.eclipse.swt.layout.GridData;\r
+import org.eclipse.swt.layout.GridLayout;\r
+import org.eclipse.swt.widgets.Button;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.swt.widgets.Control;\r
+import org.eclipse.swt.widgets.Label;\r
+import org.eclipse.swt.widgets.Shell;\r
+import org.eclipse.swt.widgets.Text;\r
+import org.simantics.db.Graph;\r
+import org.simantics.db.GraphRequestAdapter;\r
+import org.simantics.db.GraphRequestStatus;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.Session;\r
+import org.simantics.layer0.utils.EntityFactory;\r
+import org.simantics.layer0.utils.IEntity;\r
+import org.simantics.layer0.utils.viewpoints.TraversalPath;\r
+import org.simantics.proconf.browsing.GraphExplorer;\r
+import org.simantics.proconf.g3d.animation.AnimationSystem;\r
+import org.simantics.proconf.g3d.base.JmeRenderingComponent;\r
+import org.simantics.proconf.g3d.tools.OEPathSelectionListener;\r
+import org.simantics.utils.ErrorLogger;\r
+\r
+import fi.vtt.simantics.processeditor.ProcessResource;\r
+import fi.vtt.simantics.processeditor.animations.ResourcePipeAnimationController;\r
+import fi.vtt.simantics.processeditor.common.PathUtils;\r
+import fi.vtt.simantics.processeditor.stubs.PipeRun;\r
+\r
+\r
+public class ConfigurePipelineAnimationDialog extends Dialog {\r
+       Session session;\r
+       java.util.List<Resource> nodes;\r
+       \r
+       //private Control viewpointControl1;\r
+       private GraphExplorer oe1;\r
+       \r
+       \r
+       //private Control viewpointControl2;\r
+       private GraphExplorer oe2;\r
+       \r
+       JmeRenderingComponent component;\r
+       \r
+       private Button applyAnimationButton;\r
+       \r
+       Resource sampleInstance;\r
+       Resource sampleSource1;\r
+       Resource sampleSource2;\r
+       java.util.List<Resource> samplePath1;\r
+       java.util.List<Resource> samplePath2;\r
+       AnimationSystem animationSystem;\r
+       \r
+       Button scaleButton1;\r
+       Text minText1;\r
+       Text maxText1;\r
+       \r
+       Button scaleButton2;\r
+       Text minText2;\r
+       Text maxText2;\r
+       \r
+       public ConfigurePipelineAnimationDialog(Shell parentShell, Session session,java.util.List<Resource> nodes, JmeRenderingComponent component, AnimationSystem animationSystem) {\r
+               super(parentShell);\r
+               this.session = session;\r
+               this.nodes = nodes;\r
+               this.component = component;\r
+               this.animationSystem = animationSystem;\r
+               int shellStyle = getShellStyle();\r
+               setShellStyle(shellStyle | SWT.MAX | SWT.RESIZE);\r
+       }\r
+       \r
+       @Override\r
+    protected void configureShell(Shell newShell) {  \r
+        super.configureShell(newShell);\r
+        newShell.setText("Configure pipeline animations");\r
+        \r
+    }\r
+       \r
+       protected Control createDialogArea(Composite parent) {\r
+        Composite composite = (Composite) super.createDialogArea(parent);\r
+        GridLayout layout = new GridLayout(2,true);\r
+               layout.marginHeight = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN);\r
+               layout.marginWidth = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN);\r
+               layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);\r
+               layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);\r
+               composite.setLayout(layout);\r
+               \r
+               Label label = new Label(composite, SWT.WRAP);\r
+        label.setText("Color Change");\r
+        GridData data = new GridData(GridData.CENTER,GridData.FILL,true,false,1,1);\r
+        data.widthHint = convertHorizontalDLUsToPixels(IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH);\r
+        label.setLayoutData(data);\r
+        label.setFont(parent.getFont());\r
+        \r
+        label = new Label(composite, SWT.WRAP);\r
+        label.setText("Particle velocity");\r
+        label.setLayoutData(data);\r
+        label.setFont(parent.getFont());\r
+        \r
+        sampleInstance = nodes.get(0).getResource();\r
+        \r
+//      oe1 = new OntologyExplorer("Animation Source",this.getShell(), new OntologyEditorInput(sampleInstance.getId()));\r
+//     viewpointControl1 = oe1.getControl(composite, 1, OntologyExplorer.ViewpointSelector, SWT.NONE);\r
+//     \r
+//     oe2 = new OntologyExplorer("Animation Source",this.getShell(), new OntologyEditorInput(sampleInstance.getId()));\r
+//     viewpointControl2 = oe2.getControl(composite, 1, OntologyExplorer.ViewpointSelector, SWT.NONE);\r
+//     \r
+//      Control c = oe1.getControl(composite, 1, OntologyExplorer.OntologyTree, SWT.SINGLE|SWT.BORDER);\r
+//     c.setLayoutData(new GridData(GridData.FILL_BOTH));\r
+//     \r
+//     c = oe2.getControl(composite, 1, OntologyExplorer.OntologyTree, SWT.SINGLE|SWT.BORDER);\r
+//     c.setLayoutData(new GridData(GridData.FILL_BOTH));\r
+//     \r
+//      oe1.init(null, ViewpointUtils.getModelledHandler(oe1.getGraph(), Builtins.DefaultViewpointId), null, ViewLabelProviderDecorationSettings.DEFAULT, new MenuAboutToShowAction(), new NullAdditionAction(), false);\r
+//     oe1.setSelectionScheme(new SourceSelectionScheme(oe1));\r
+//     \r
+//     oe2.init(null, ViewpointUtils.getModelledHandler(oe1.getGraph(), Builtins.DefaultViewpointId), null, ViewLabelProviderDecorationSettings.DEFAULT, new MenuAboutToShowAction(), new NullAdditionAction(), false);\r
+//     oe2.setSelectionScheme(new SourceSelectionScheme(oe2));\r
+       \r
+        oe1 = new GraphExplorer(composite,SWT.SINGLE);\r
+        oe1.getTree().setLayoutData(new GridData(GridData.FILL_BOTH));\r
+        \r
+        oe2 = new GraphExplorer(composite,SWT.SINGLE);\r
+        oe2.getTree().setLayoutData(new GridData(GridData.FILL_BOTH));\r
+        \r
+       oe1.getViewer().addPostSelectionChangedListener(new OEPathListener(oe1));\r
+       oe2.getViewer().addPostSelectionChangedListener(new OEPathListener(oe2));\r
+       \r
+       \r
+       Composite buttonComposite = new Composite(composite,SWT.NONE);\r
+        buttonComposite.setLayoutData(new GridData(GridData.END,GridData.FILL,true,false,1,1));\r
+        buttonComposite.setLayout(new FillLayout(SWT.HORIZONTAL));\r
+        \r
+        scaleButton1 = new Button(buttonComposite,SWT.CHECK);\r
+        scaleButton1.setText("Scaling");\r
+        scaleButton1.addSelectionListener(new SelectionAdapter() {\r
+               @Override\r
+               public void widgetSelected(SelectionEvent e) {\r
+                       if (scaleButton1.getSelection()) {\r
+                               minText1.setEnabled(true);\r
+                               maxText1.setEnabled(true);\r
+                       } else {\r
+                               minText1.setEnabled(false);\r
+                               maxText1.setEnabled(false);\r
+                       }\r
+               }\r
+        });\r
+        minText1 = new Text(buttonComposite,SWT.SINGLE|SWT.BORDER);\r
+        minText1.setText("0.0");\r
+        \r
+        maxText1 = new Text(buttonComposite,SWT.SINGLE|SWT.BORDER);\r
+        maxText1.setText("1.0");\r
+        \r
+        minText1.setEnabled(false);\r
+               maxText1.setEnabled(false);\r
+               \r
+               buttonComposite = new Composite(composite,SWT.NONE);\r
+        buttonComposite.setLayoutData(new GridData(GridData.END,GridData.FILL,true,false,1,1));\r
+        buttonComposite.setLayout(new FillLayout(SWT.HORIZONTAL));\r
+        \r
+               scaleButton2 = new Button(buttonComposite,SWT.CHECK);\r
+        scaleButton2.setText("Scaling");\r
+        scaleButton2.addSelectionListener(new SelectionAdapter() {\r
+               @Override\r
+               public void widgetSelected(SelectionEvent e) {\r
+                       if (scaleButton2.getSelection()) {\r
+                               minText2.setEnabled(true);\r
+                               maxText2.setEnabled(true);\r
+                       } else {\r
+                               minText2.setEnabled(false);\r
+                               maxText2.setEnabled(false);\r
+                       }\r
+               }\r
+        });\r
+        minText2 = new Text(buttonComposite,SWT.SINGLE|SWT.BORDER);\r
+        minText2.setText("0.0");\r
+        \r
+        maxText2 = new Text(buttonComposite,SWT.SINGLE|SWT.BORDER);\r
+        maxText2.setText("1.0");\r
+        \r
+        minText2.setEnabled(false);\r
+               maxText2.setEnabled(false);\r
+       \r
+               \r
+               applyAnimationButton = new Button(composite,SWT.PUSH);\r
+        applyAnimationButton.setText("Apply animation");\r
+        applyAnimationButton.addSelectionListener(new SelectionAdapter() {\r
+               @Override\r
+               public void widgetSelected(SelectionEvent e) {\r
+                       session.syncRead(new GraphRequestAdapter() {\r
+                               @Override\r
+                               public GraphRequestStatus perform(Graph g) throws Exception {\r
+                                       applyAnimation(g);\r
+                                       return GraphRequestStatus.transactionComplete();\r
+                               }\r
+                       });\r
+                       \r
+               }\r
+        });\r
+        applyAnimationButton.setLayoutData(new GridData(GridData.END,GridData.FILL,true,false,2,1));\r
+        return composite;\r
+       }\r
+       \r
+       private class OEPathListener extends OEPathSelectionListener {\r
+               GraphExplorer oe;\r
+               \r
+               public OEPathListener(GraphExplorer oe) {\r
+                       this.oe = oe;\r
+               }\r
+\r
+        protected void pathSelectionUpdated(List<TraversalPath> paths) {\r
+            if (paths.size() == 0) {\r
+                //selectSource(null);\r
+            } else {\r
+                selectSource(oe,paths.get(0));\r
+            }\r
+        }\r
+       }\r
+       \r
+       private void selectSource(GraphExplorer oe,TraversalPath path) {\r
+               Graph graph = null;\r
+               IEntity t = EntityFactory.create(graph,path.getResource());\r
+               if (!t.isInstanceOf(ProcessResource.builtins.Double)) \r
+                       return;\r
+               if (oe == oe1) {\r
+                       sampleSource1 = path.getResource();\r
+                       samplePath1 = new ArrayList<Resource>();\r
+                       PathUtils.createPath(samplePath1, path,sampleInstance,sampleSource1,oe);\r
+               } else if (oe == oe2) {\r
+                       sampleSource2 = path.getResource();\r
+                       samplePath2 = new ArrayList<Resource>();\r
+                       PathUtils.createPath(samplePath2, path,sampleInstance,sampleSource2,oe);\r
+               }\r
+       }\r
+       \r
+       \r
+       \r
+       \r
+       private void applyAnimation(Graph graph) {\r
+               if (sampleInstance == null || sampleSource1 == null || sampleSource2 == null || samplePath1 == null|| samplePath2 == null) {\r
+                       throw new RuntimeException("Missing required selections");\r
+                       //return;\r
+               }\r
+               java.util.List<Resource> instances1 = new ArrayList<Resource>();\r
+               java.util.List<Resource> instances2 = new ArrayList<Resource>();\r
+               java.util.List<Resource> sources1 = new ArrayList<Resource>();\r
+               java.util.List<Resource> sources2 = new ArrayList<Resource>();\r
+               browseOthers(instances1, sources1,samplePath1);\r
+               browseOthers(instances2, sources2,samplePath2);\r
+               instances1.add(sampleInstance);\r
+               instances2.add(sampleInstance); // instances1 == instances2\r
+               sources1.add(sampleSource1);\r
+               sources2.add(sampleSource2);\r
+               \r
+               for (int i = 0; i < instances1.size(); i++) {\r
+                       \r
+                       double cMin = 0.0;\r
+                       double cMax = 1.0;\r
+                       double vMin = 0.0;\r
+                       double vMax = 0.0;\r
+                       \r
+                       if (scaleButton1.getSelection()) {\r
+                               cMin = Double.parseDouble(minText1.getText());\r
+                               cMax = Double.parseDouble(maxText1.getText());\r
+                       }\r
+                       if (scaleButton2.getSelection()) {\r
+                               vMin = Double.parseDouble(minText2.getText());\r
+                               vMax = Double.parseDouble(maxText2.getText());\r
+                       }\r
+                       ResourcePipeAnimationController c = new ResourcePipeAnimationController(component, new PipeRun(graph,instances1.get(i)),sources1.get(i),cMin,cMax,sources2.get(i),vMin,vMax);\r
+                       \r
+                       animationSystem.add(c);\r
+               }\r
+               \r
+       }\r
+       \r
+       private void browseOthers(java.util.List<Resource> instances,java.util.List<Resource> sources,java.util.List<Resource> samplePath) {\r
+               Graph graph = null;\r
+               java.util.List<Resource> possibleInstances = new ArrayList<Resource>();\r
+               for (Resource n : nodes) {\r
+                       possibleInstances.add(n);\r
+               }\r
+               \r
+               for (Resource instance : possibleInstances) {\r
+                       IEntity source = PathUtils.findSimilar(samplePath,EntityFactory.create(graph,instance));\r
+                       if (source != null) {\r
+                               instances.add(instance);\r
+                               sources.add(source.getResource());\r
+                       } else {\r
+                               ErrorLogger.getDefault().logWarning("Cannot find animation source for " + instance, null);\r
+                       }\r
+               }\r
+       }\r
+       \r
+       \r
+        \r
+}\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/EquipmentDialog.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/EquipmentDialog.java
new file mode 100644 (file)
index 0000000..cf19430
--- /dev/null
@@ -0,0 +1,27 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007 VTT Technical Research Centre of Finland and others.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package fi.vtt.simantics.processeditor.dialogs;\r
+\r
+import org.eclipse.swt.widgets.Shell;\r
+import org.simantics.db.Session;\r
+\r
+\r
+import fi.vtt.simantics.processeditor.ProcessResource;\r
+\r
+public class EquipmentDialog extends LibraryComponentDialog {\r
+\r
+\r
+       public EquipmentDialog(Shell parentShell, String dialogTitle, Session session) {\r
+               super(parentShell,session,ProcessResource.plant3Dresource.Equipment,dialogTitle);\r
+       \r
+       }\r
+\r
+}\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/LibraryComponentDialog.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/LibraryComponentDialog.java
new file mode 100644 (file)
index 0000000..6909fb6
--- /dev/null
@@ -0,0 +1,195 @@
+package fi.vtt.simantics.processeditor.dialogs;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.Stack;\r
+\r
+import org.eclipse.jface.dialogs.Dialog;\r
+import org.eclipse.jface.dialogs.IDialogConstants;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.events.SelectionEvent;\r
+import org.eclipse.swt.events.SelectionListener;\r
+import org.eclipse.swt.layout.GridData;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.swt.widgets.Control;\r
+import org.eclipse.swt.widgets.Label;\r
+import org.eclipse.swt.widgets.List;\r
+import org.eclipse.swt.widgets.Shell;\r
+import org.simantics.db.Graph;\r
+import org.simantics.db.GraphRequestAdapter;\r
+import org.simantics.db.GraphRequestStatus;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.Session;\r
+import org.simantics.layer0.utils.EntityFactory;\r
+import org.simantics.layer0.utils.IEntity;\r
+import org.simantics.proconf.ui.ProConfUI;\r
+import org.simantics.utils.ErrorLogger;\r
+\r
+import fi.vtt.simantics.processeditor.ProcessResource;\r
+\r
+public class LibraryComponentDialog extends Dialog{ \r
+       \r
+        private List typeList;\r
+     private Resource selectedType = null;\r
+     private Session session;\r
+     private String title;\r
+     \r
+     private Resource primaryType;\r
+     private Collection<Resource> requiredTypes = new ArrayList<Resource>();\r
+     private Collection<Resource> filteredTypes = new ArrayList<Resource>();\r
+     \r
+     public LibraryComponentDialog(Shell shell, Session session, Resource primaryType, String title) {\r
+        super(shell);\r
+        assert(title != null);\r
+        this.session = session;\r
+        this.title = title;\r
+        this.primaryType = primaryType;\r
+     }\r
+     \r
+     \r
+     protected void setFilter(Collection<Resource> filter) {\r
+        this.filteredTypes = filter;\r
+     }\r
+     \r
+     protected void setRequired(Collection<Resource> required) {\r
+        this.requiredTypes = required;\r
+     }\r
+     \r
+     \r
+     @Override\r
+     protected void configureShell(Shell newShell) {\r
+         \r
+         super.configureShell(newShell);\r
+         newShell.setText(title);\r
+     }\r
+\r
+     public Resource getComboValue() {\r
+         return selectedType;\r
+     }\r
+     \r
+     protected Control createDialogArea(Composite parent) {\r
+         Composite composite = (Composite) super.createDialogArea(parent);\r
+         \r
+         Label label = new Label(composite, SWT.WRAP);\r
+         label.setText("Select Component");\r
+         GridData data = new GridData(GridData.GRAB_HORIZONTAL\r
+                 | GridData.GRAB_VERTICAL | GridData.HORIZONTAL_ALIGN_FILL\r
+                 | GridData.VERTICAL_ALIGN_CENTER);\r
+         data.widthHint = convertHorizontalDLUsToPixels(IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH);\r
+         label.setLayoutData(data);\r
+         label.setFont(parent.getFont());\r
+         // TODO : list populating is done in random order; change to alphabetic\r
+         typeList = new List(composite, SWT.BORDER | SWT.SINGLE | SWT.READ_ONLY | SWT.V_SCROLL);\r
+         typeList.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL));\r
+         \r
+         typeList.addSelectionListener(new SelectionListener() {\r
+             public void widgetSelected(SelectionEvent e) {\r
+                 String key = typeList.getItem(typeList.getSelectionIndex());\r
+                 selectedType = (Resource) typeList.getData(key);\r
+             }\r
+             public void widgetDefaultSelected(SelectionEvent e) {\r
+             }\r
+         });\r
+         getShell().setText(title + " loading...");\r
+         session.asyncRead(new GraphRequestAdapter() {\r
+               @Override\r
+               public GraphRequestStatus perform(Graph g) throws Exception {\r
+                       loadComponents(g);\r
+                       return GraphRequestStatus.transactionComplete();\r
+               }\r
+               \r
+               @Override\r
+               public void requestCompleted(GraphRequestStatus status) {\r
+                       getDialogArea().getDisplay().asyncExec(new Runnable() {\r
+                               @Override\r
+                               public void run() {\r
+                                       getShell().setText(title);\r
+                                       if (selectedType == null) {\r
+                               typeList.select(0);\r
+                               selectedType = (Resource)typeList.getData(typeList.getItem(0));\r
+                           }\r
+                               }\r
+                               \r
+                       });\r
+               }\r
+         });\r
+\r
+         GridData data2 = new GridData(GridData.GRAB_HORIZONTAL\r
+                 | GridData.GRAB_VERTICAL | GridData.HORIZONTAL_ALIGN_FILL\r
+                 | GridData.VERTICAL_ALIGN_FILL);\r
+         data2.widthHint = convertHorizontalDLUsToPixels(IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH);\r
+         data2.heightHint = 200;\r
+         typeList.setLayoutData(data2);\r
+         typeList.setFont(parent.getFont());\r
+         \r
+         typeList.showSelection();\r
+         \r
+         applyDialogFont(composite);\r
+         return composite;\r
+     }\r
+     \r
+     private void loadComponents(Graph g) {\r
+               Resource projectResource = ProConfUI.getProject().getResource();\r
+               Stack<Resource> handling = new Stack<Resource>();\r
+               handling.push(projectResource);\r
+               while (!handling.isEmpty()) {\r
+                       final Resource node = handling.pop();\r
+                       if (g.isInstanceOf(node,primaryType)) {\r
+                               IEntity equipment = EntityFactory.create(g, node);\r
+                               Collection<IEntity> graphics = equipment\r
+                                               .getRelatedObjects(ProcessResource.plant3Dresource.HasGraphics);\r
+                               if (graphics.size() != 1) {\r
+                                       ErrorLogger.defaultLogError("Equipment "\r
+                                                       + equipment.getName() + " has " + graphics.size()\r
+                                                       + " + graphical representation!", null);\r
+                               } else {\r
+                                       boolean add = true;\r
+                                       for (Resource r : requiredTypes) {\r
+                                               if (!equipment.isInstanceOf(r)) {\r
+                                                       add = false;\r
+                                                       break;\r
+                                               }\r
+                                       }\r
+                                       if (add) {\r
+                                               for (Resource r : filteredTypes) {\r
+                                                       if (equipment.isInstanceOf(r)) {\r
+                                                               add = false;\r
+                                                               break;\r
+                                                       }\r
+                                               }\r
+                                       }\r
+                                       if (add) {\r
+                                               final String name = equipment.getName();\r
+                                               getDialogArea().getDisplay().asyncExec(new Runnable() {\r
+                                                       public void run() {\r
+                                                               // List won't work with two ore more same names.\r
+                                                               if (typeList.getData(name)!= null) {\r
+                                                                       String n = new String(name);\r
+                                                                       int i = 1;\r
+                                                                       while (true) {\r
+                                                                               n = name +"("+i+")";\r
+                                                                               if (typeList.getData(n)== null) {\r
+                                                                                       typeList.add(n);\r
+                                                                                       typeList.setData(n, node);\r
+                                                                                       break;\r
+                                                                               }\r
+                                                                       }\r
+                                                               } else {\r
+                                                                       typeList.add(name);\r
+                                                                       typeList.setData(name, node);\r
+                                                               }\r
+                                                       }\r
+                                               });\r
+                                       }\r
+                               }\r
+                       } else {\r
+                               handling.addAll(g.getObjects(node,\r
+                                               ProcessResource.builtins.ConsistsOf));\r
+                       }\r
+\r
+               }\r
+               \r
+       }\r
+       \r
+\r
+}\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/NozzleDialog.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/NozzleDialog.java
new file mode 100644 (file)
index 0000000..282c9ce
--- /dev/null
@@ -0,0 +1,27 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007 VTT Technical Research Centre of Finland and others.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package fi.vtt.simantics.processeditor.dialogs;\r
+\r
+import org.eclipse.swt.widgets.Shell;\r
+import org.simantics.db.Session;\r
+\r
+\r
+import fi.vtt.simantics.processeditor.ProcessResource;\r
+\r
+public class NozzleDialog extends LibraryComponentDialog {\r
+\r
+\r
+       public NozzleDialog(Shell parentShell, String dialogTitle, Session session) {\r
+               super(parentShell,session,ProcessResource.plant3Dresource.Nozzle,dialogTitle);\r
+       \r
+       }\r
+\r
+}\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/PipelineComponentDialog.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/PipelineComponentDialog.java
new file mode 100644 (file)
index 0000000..a7510b4
--- /dev/null
@@ -0,0 +1,34 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007 VTT Technical Research Centre of Finland and others.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package fi.vtt.simantics.processeditor.dialogs;\r
+\r
+import java.util.Collection;\r
+\r
+import org.eclipse.swt.widgets.Shell;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.Session;\r
+\r
+\r
+\r
+import fi.vtt.simantics.processeditor.ProcessResource;\r
+\r
+public class PipelineComponentDialog extends LibraryComponentDialog{\r
+\r
\r
+        public PipelineComponentDialog(Shell parentShell, Collection<Resource> requiredTypes, Collection<Resource> filteredTypes, Session session) {\r
+            super(parentShell,session,ProcessResource.plant3Dresource.PipelineComponent,"Select Component");\r
+            if (requiredTypes != null)\r
+               setRequired(requiredTypes);\r
+            if (filteredTypes != null)\r
+               setFilter(filteredTypes);\r
+        }\r
+\r
+}\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/PipelineDialog.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/PipelineDialog.java
new file mode 100644 (file)
index 0000000..5cf1ea4
--- /dev/null
@@ -0,0 +1,132 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007 VTT Technical Research Centre of Finland and others.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package fi.vtt.simantics.processeditor.dialogs;\r
+\r
+import org.eclipse.jface.dialogs.Dialog;\r
+import org.eclipse.jface.dialogs.IDialogConstants;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.events.KeyEvent;\r
+import org.eclipse.swt.events.KeyListener;\r
+import org.eclipse.swt.layout.GridData;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.swt.widgets.Control;\r
+import org.eclipse.swt.widgets.Label;\r
+import org.eclipse.swt.widgets.Shell;\r
+import org.eclipse.swt.widgets.Text;\r
+\r
+public class PipelineDialog extends Dialog implements KeyListener{\r
+       Text pipeRadiusText;\r
+       Text turnRadiusText;\r
+       \r
+       double pipeDiameter = 0.0;\r
+       double turnRadius = 0.0;\r
+       \r
+       public PipelineDialog(Shell parentShell) {\r
+               super(parentShell);\r
+       }\r
+       \r
+       public PipelineDialog(Shell parentShell, double pipeRadius, double turnRadius) {\r
+               super(parentShell);\r
+               this.pipeDiameter = pipeRadius;\r
+               this.turnRadius = turnRadius;\r
+       }\r
+\r
+       \r
+       @Override\r
+       protected void configureShell(Shell newShell) {\r
+               super.configureShell(newShell);\r
+               newShell.setText("Configure new pipeline");\r
+       }\r
+       \r
+       @Override\r
+       protected Control createDialogArea(Composite parent) {\r
+               Composite composite = (Composite) super.createDialogArea(parent);\r
+               Label label = new Label(composite, SWT.WRAP);\r
+        label.setText("Input pipeline specifications");\r
+        GridData data = new GridData(GridData.GRAB_HORIZONTAL\r
+                | GridData.GRAB_VERTICAL | GridData.HORIZONTAL_ALIGN_FILL\r
+                | GridData.VERTICAL_ALIGN_CENTER);\r
+               \r
+        data.widthHint = convertHorizontalDLUsToPixels(IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH);\r
+        label.setLayoutData(data);\r
+        label.setFont(parent.getFont());\r
+        label = new Label(composite, SWT.WRAP);\r
+        label.setText("Pipe diameter");\r
+        label.setLayoutData(data);\r
+        label.setFont(parent.getFont());\r
+        pipeRadiusText = new Text(composite,SWT.BORDER);\r
+        pipeRadiusText.setLayoutData(data);\r
+        label = new Label(composite, SWT.WRAP);\r
+        label.setText("Pipe elbow/turn radius");\r
+        label.setLayoutData(data);\r
+        label.setFont(parent.getFont());\r
+        turnRadiusText = new Text(composite,SWT.BORDER);\r
+               turnRadiusText.setLayoutData(data);\r
+               \r
+               pipeRadiusText.addKeyListener(this);\r
+               turnRadiusText.addKeyListener(this);\r
+               if (pipeDiameter > 0.0 && turnRadius > 0.0) {\r
+                       pipeRadiusText.setText(Double.toString(pipeDiameter));\r
+                       turnRadiusText.setText(Double.toString(turnRadius));\r
+               }\r
+                       \r
+               \r
+               return composite;\r
+       }\r
+       \r
+       @Override\r
+       public int open() {\r
+               return super.open();\r
+       }\r
+       \r
+       \r
+       \r
+       \r
+       public void keyPressed(KeyEvent e) {\r
+               \r
+               \r
+       }\r
+       \r
+       public void keyReleased(KeyEvent e) {\r
+               boolean ok = true;\r
+               try {\r
+                       pipeDiameter = Double.parseDouble(pipeRadiusText.getText());\r
+                       turnRadius = Double.parseDouble(turnRadiusText.getText());\r
+                       if (pipeDiameter <= 0.0)\r
+                               ok = false;\r
+                       if (turnRadius <= 0.0)\r
+                               ok = false;\r
+                       \r
+               } catch (NumberFormatException err) {\r
+                       ok = false;\r
+               }\r
+               if (ok) {\r
+                       this.getButton(IDialogConstants.OK_ID).setEnabled(true);\r
+               } else {\r
+                       this.getButton(IDialogConstants.OK_ID).setEnabled(false);\r
+               }\r
+       }\r
+\r
+\r
+       public double getPipeDiameter() {\r
+               return pipeDiameter;\r
+       }\r
+\r
+\r
+       public double getTurnRadius() {\r
+               return turnRadius;\r
+       }\r
+\r
+\r
+       \r
+       \r
+       \r
+}\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/gizmo/PositionSelectionGizmo.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/gizmo/PositionSelectionGizmo.java
new file mode 100644 (file)
index 0000000..62d3685
--- /dev/null
@@ -0,0 +1,177 @@
+package fi.vtt.simantics.processeditor.gizmo;\r
+\r
+import java.net.URL;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import javax.vecmath.Point3d;\r
+\r
+import org.eclipse.core.runtime.FileLocator;\r
+import org.eclipse.core.runtime.Path;\r
+import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase;\r
+import org.simantics.proconf.g3d.base.VecmathJmeTools;\r
+import org.simantics.proconf.g3d.gizmo.Gizmo;\r
+import org.simantics.utils.datastructures.Pair;\r
+\r
+import com.jme.bounding.BoundingSphere;\r
+import com.jme.image.Image;\r
+import com.jme.image.Texture;\r
+import com.jme.math.Vector3f;\r
+import com.jme.renderer.Renderer;\r
+import com.jme.scene.BillboardNode;\r
+import com.jme.scene.Node;\r
+import com.jme.scene.shape.Quad;\r
+import com.jme.scene.state.AlphaState;\r
+import com.jme.scene.state.LightState;\r
+import com.jme.scene.state.TextureState;\r
+import com.jme.scene.state.ZBufferState;\r
+import com.jme.util.TextureManager;\r
+\r
+import fi.vtt.simantics.processeditor.Activator;\r
+import fi.vtt.simantics.processeditor.actions.PositionType;\r
+\r
+/**\r
+ * Gizmo that allows user to selected insertion point of a component\r
+ * TODO : for splits we want use line between component ends to\r
+ *        position the button, instead of its center point.   \r
+ * \r
+ * @author Marko Luukkainen <Marko.Luukkainen@vtt.fi>\r
+ *\r
+ */\r
+public class PositionSelectionGizmo implements Gizmo {\r
+\r
+       private static String PICK_PREFIX = "insert";\r
+       private static String SPLIT_TEXTURE = "icons/middle.png";\r
+       private static String END_TEXTURE = "icons/plus.png";\r
+       private static String PORT_TEXTURE = END_TEXTURE;\r
+\r
+       private ThreeDimensionalEditorBase parent;\r
+       \r
+       private boolean changed = false;\r
+       private int selected = -1;\r
+       private boolean useDistanceResize = true;\r
+       \r
+       private List<BillboardNode> nodes;\r
+       private List<AlphaState> alphaStates;\r
+       private Node rootNode;\r
+       \r
+       public PositionSelectionGizmo(ThreeDimensionalEditorBase parent, List<Pair<Point3d, PositionType>> positions) {\r
+               this.parent = parent;\r
+               rootNode = new Node();\r
+               rootNode.setCullMode(Node.CULL_NEVER);\r
+               rootNode.setRenderQueueMode(Renderer.QUEUE_TRANSPARENT);\r
+               rootNode.setLightCombineMode(LightState.OFF);\r
+               int i = 0;\r
+               nodes = new ArrayList<BillboardNode>();\r
+               alphaStates = new ArrayList<AlphaState>();\r
+               // create a button (billboard) for each insertion position\r
+\r
+               ZBufferState zs = parent.getRenderingComponent().getDisplaySystem().getRenderer().createZBufferState();\r
+               zs.setFunction(ZBufferState.CF_ALWAYS);\r
+               \r
+               for (Pair<Point3d, PositionType> p : positions) {\r
+                       BillboardNode node = new BillboardNode("");\r
+                       nodes.add(node);\r
+                       Quad quad = new Quad(PICK_PREFIX + i,1.f,1.f);\r
+                       \r
+                       TextureState ts = parent.getRenderingComponent().getDisplaySystem().getRenderer().createTextureState();\r
+                       String filename = "";\r
+                       switch (p.second) {\r
+                       case NEXT:\r
+                       case PREVIOUS:\r
+                               filename = END_TEXTURE;\r
+                               break;\r
+                       case SPLIT:\r
+                               filename = SPLIT_TEXTURE;\r
+                               break;\r
+                       case PORT:\r
+                               filename = PORT_TEXTURE;\r
+                       }\r
+                       URL url = FileLocator.find(Activator.getDefault().getBundle(), new Path(filename),null);\r
+                       Image image = TextureManager.loadImage(url, true);\r
+                       Texture texture = new Texture();\r
+                       texture.setImage(image);\r
+                       texture.setFilter(Texture.FM_LINEAR);\r
+                       ts.setTexture(texture);\r
+                       quad.setRenderState(ts);\r
+                       \r
+                       AlphaState as = parent.getRenderingComponent().getDisplaySystem().getRenderer().createAlphaState();\r
+                       as.setSrcFunction(AlphaState.SB_SRC_ALPHA);\r
+                       as.setDstFunction(AlphaState.DB_ONE_MINUS_SRC_ALPHA);\r
+                       as.setBlendEnabled(true);\r
+                       alphaStates.add(as);\r
+                       quad.setRenderState(as);\r
+                       quad.setRenderState(zs);\r
+                       \r
+                       node.attachChild(quad);\r
+                       node.setLocalTranslation(VecmathJmeTools.get(p.first));\r
+                       quad.setModelBound(new BoundingSphere(0.5f,new Vector3f()));\r
+                       quad.updateModelBound();\r
+                       rootNode.attachChild(node);\r
+                       \r
+                       i++;\r
+               }\r
+       }\r
+       \r
+       \r
+       @Override\r
+       public Node getNode() {\r
+               return rootNode;\r
+       }\r
+       \r
+       @Override\r
+       public String getPickPrefix() {\r
+               return PICK_PREFIX;\r
+       }\r
+       \r
+       @Override\r
+       public boolean isChanged() {\r
+               return changed;\r
+       }\r
+       \r
+       @Override\r
+       public void setChanged(boolean b) {\r
+               changed = b;\r
+       }\r
+       \r
+       @Override\r
+       public void setSelected(String name) {\r
+               if (name == null) {\r
+                       setSelected(-1);\r
+                       return;\r
+               }\r
+               assert(name.startsWith(PICK_PREFIX));\r
+               setSelected(Integer.parseInt(name.substring(PICK_PREFIX.length())));\r
+       }\r
+       \r
+       private void setSelected(int i) {\r
+               if (selected == i)\r
+                       return;\r
+               if (selected != -1) {\r
+                       alphaStates.get(selected).setDstFunction(AlphaState.DB_ONE_MINUS_SRC_ALPHA);\r
+                       nodes.get(selected).getChild(0).setRenderState(alphaStates.get(selected));\r
+               }\r
+               selected = i;\r
+               if (selected != -1) {\r
+                       alphaStates.get(selected).setDstFunction(AlphaState.DB_ONE);\r
+                       nodes.get(selected).getChild(0).setRenderState(alphaStates.get(selected));\r
+               }\r
+               parent.setViewChanged(true);\r
+       }\r
+       \r
+       public int getSelected() {\r
+               return selected;\r
+       }\r
+       \r
+       public void update() {\r
+               if (useDistanceResize) {\r
+                       Vector3f v = VecmathJmeTools.get(parent.getCamera().getCameraPos());\r
+                       for (BillboardNode n : nodes) {\r
+                               float length = v.subtract(n.getWorldTranslation()).length();\r
+                               n.setLocalScale(length * 0.06f);\r
+                       }\r
+               }\r
+       }\r
+\r
+       \r
+}\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/EquipmentEditorAdapter.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/EquipmentEditorAdapter.java
new file mode 100644 (file)
index 0000000..6339ca4
--- /dev/null
@@ -0,0 +1,40 @@
+package fi.vtt.simantics.processeditor.handlers;\r
+\r
+import org.simantics.db.Graph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.proconf.ui.workbench.ResourceEditorInput;\r
+import org.simantics.proconf.ui.workbench.editor.SimpleEditorAdapter;\r
+import org.simantics.utils.ui.BundleUtils;\r
+import org.simantics.utils.ui.workbench.WorkbenchUtils;\r
+\r
+import fi.vtt.simantics.processeditor.Activator;\r
+import fi.vtt.simantics.processeditor.ProcessResource;\r
+\r
+/**\r
+ * EditorAdapter for EquipmentEditor\r
+ * \r
+ * @author Marko Luukkainen <Marko.Luukkainen@vtt.fi>\r
+ *\r
+ */\r
+public class EquipmentEditorAdapter extends SimpleEditorAdapter {\r
+       public EquipmentEditorAdapter() {\r
+               super("Equipment Editor",\r
+                       BundleUtils.getImageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/tank.png"),\r
+                       null,null,null);\r
+       }\r
+\r
+       @Override\r
+       public boolean canHandle(Graph g, Resource r) {\r
+               if(ProcessResource.plant3Dresource == null) return false; \r
+               if(ProcessResource.plant3Dresource.Plant == null) return false; \r
+               if(!g.isInstanceOf(r, ProcessResource.plant3Dresource.Equipment)) return false;\r
+               return true;\r
+       }\r
+\r
+\r
+       @Override\r
+       public void openEditor(Resource r) throws Exception {\r
+               WorkbenchUtils.openEditor("org.simantics.proconf.processeditor.equipmenteditor", new ResourceEditorInput("org.simantics.proconf.processeditor.equipmenteditor",r));\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/NewComponentHandler.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/NewComponentHandler.java
new file mode 100644 (file)
index 0000000..7cb2be9
--- /dev/null
@@ -0,0 +1,290 @@
+package fi.vtt.simantics.processeditor.handlers;\r
+\r
+import java.util.ArrayList;\r
+import java.util.HashMap;\r
+import java.util.List;\r
+import java.util.Map;\r
+\r
+import org.eclipse.core.commands.AbstractHandler;\r
+import org.eclipse.core.commands.ExecutionEvent;\r
+import org.eclipse.core.commands.ExecutionException;\r
+import org.eclipse.jface.dialogs.Dialog;\r
+import org.eclipse.jface.viewers.ISelection;\r
+import org.eclipse.jface.viewers.IStructuredSelection;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.events.ModifyEvent;\r
+import org.eclipse.swt.events.ModifyListener;\r
+import org.eclipse.swt.events.SelectionAdapter;\r
+import org.eclipse.swt.events.SelectionEvent;\r
+import org.eclipse.swt.layout.GridData;\r
+import org.eclipse.swt.widgets.Button;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.swt.widgets.Control;\r
+import org.eclipse.swt.widgets.Display;\r
+import org.eclipse.swt.widgets.Label;\r
+import org.eclipse.swt.widgets.Shell;\r
+import org.eclipse.swt.widgets.Text;\r
+import org.eclipse.ui.handlers.HandlerUtil;\r
+import org.simantics.db.Graph;\r
+import org.simantics.db.GraphRequestAdapter;\r
+import org.simantics.db.GraphRequestStatus;\r
+import org.simantics.db.Resource;\r
+import org.simantics.layer0.stubs.Library;\r
+import org.simantics.layer0.utils.EntityFactory;\r
+import org.simantics.layer0.utils.IEntity;\r
+import org.simantics.layer0.utils.instantiation.InstanceFactory;\r
+import org.simantics.proconf.ui.ProConfUI;\r
+import org.simantics.proconf.ui.utils.ResourceAdaptionUtils;\r
+\r
+import fi.vtt.simantics.processeditor.ProcessResource;\r
+\r
+\r
+/**\r
+ * Handler that creates new pipeline components.\r
+ * \r
+ * @author Marko Luukkainen <Marko.Luukkainen@vtt.fi>\r
+ *\r
+ */\r
+public class NewComponentHandler extends AbstractHandler {\r
+       \r
+       private Map<Resource, String> nameMap;\r
+       \r
+       @Override\r
+       public Object execute(ExecutionEvent event) throws ExecutionException {\r
+               ISelection s = HandlerUtil.getCurrentSelectionChecked(event);\r
+        IStructuredSelection ss = (IStructuredSelection) s;\r
+        if (ss.size() != 1)\r
+            return null;\r
+        final Resource lib = ResourceAdaptionUtils.toSingleResource(ss);\r
+        \r
+        \r
+        \r
+        if (nameMap == null) {\r
+               ProConfUI.getSession().syncRead(new GraphRequestAdapter(){\r
+                       @Override\r
+                       public GraphRequestStatus perform(Graph g) throws Exception {\r
+                               nameMap = new HashMap<Resource, String>();\r
+                               for (Resource r : getComponentTypes()) {\r
+                                       IEntity e = EntityFactory.create(g,r);\r
+                                       nameMap.put(r, e.getName());\r
+                                       for (Resource r2 : getComponentOptions(r)) {\r
+                                               IEntity e2 = EntityFactory.create(g,r2);\r
+                                       nameMap.put(r2, e2.getName());\r
+                                       }\r
+                               }\r
+                               return GraphRequestStatus.transactionComplete();\r
+                       }\r
+               });\r
+        }\r
+        \r
+        ComponentTypeDialog dialog = new ComponentTypeDialog(Display.getDefault().getActiveShell());\r
+        if (dialog.open() == ComponentTypeDialog.CANCEL)\r
+               return null;\r
+        final List<Resource> types = dialog.getSelection();\r
+        final String name = dialog.getName();\r
+               \r
+        if (types.size() == 0 || name == null || name.length() == 0)\r
+               return null;\r
+        \r
+        ProConfUI.getSession().asyncWrite(new GraphRequestAdapter() {\r
+                       @Override\r
+                       public GraphRequestStatus perform(Graph g) throws Exception {\r
+                               // instantiate component\r
+                               IEntity instance = EntityFactory.create(g, InstanceFactory.instantiate(g, types));\r
+                               Library l = new Library(g, lib);\r
+                               l.addStatement(g.getBuiltins().ConsistsOf, instance);\r
+                               instance.setName(name);\r
+                               \r
+                               // TODO : is this correct (instance & inherits)\r
+                               for (Resource type : types) {\r
+                                       instance.addStatement(ProcessResource.builtins.Inherits, type);\r
+                               }\r
+                               \r
+                               // instantiate control point(s)\r
+                               List<Resource> cpTypes = getControlPointTypes(types);\r
+                               boolean isDual = (cpTypes.contains(ProcessResource.plant3Dresource.SizeChangeControlPoint) || \r
+                                                                 cpTypes.contains(ProcessResource.plant3Dresource.OffsettingPoint));\r
+                               IEntity cp = EntityFactory.create(g, InstanceFactory.instantiate(g, cpTypes));\r
+                               instance.addStatement(ProcessResource.plant3Dresource.HasControlPoint, cp);\r
+                               if (isDual) {\r
+                                       IEntity subCP = EntityFactory.create(g, InstanceFactory.instantiate(g, ProcessResource.plant3Dresource.DualSubControlPoint));\r
+                                       cp.addStatement(ProcessResource.plant3Dresource.HasSubPoint, subCP);\r
+                               }\r
+                               // instantiate model\r
+                               Resource modelType = g.getResourceByURI("http://www.vtt.fi/Simantics/CSG/1.0/Types#CSGModel");\r
+                               IEntity model = EntityFactory.create(g, InstanceFactory.instantiate(g, modelType));\r
+                               instance.addStatement(ProcessResource.plant3Dresource.HasGraphics, model);\r
+                               \r
+                               return GraphRequestStatus.transactionComplete();\r
+                       }\r
+               });\r
+               \r
+               \r
+               return null;\r
+       }\r
+       \r
+       /**\r
+        * Returns all possible types for a pipeline component\r
+        * @return\r
+        */\r
+       private List<Resource> getComponentTypes() {\r
+               List<Resource> list = new ArrayList<Resource>();\r
+               list.add(ProcessResource.plant3Dresource.FixedLengthInlineComponent);\r
+               list.add(ProcessResource.plant3Dresource.VariableLengthInlineComponent);\r
+               list.add(ProcessResource.plant3Dresource.VariableAngleTurnComponent);\r
+               list.add(ProcessResource.plant3Dresource.FixedAngleTurnComponent);\r
+               list.add(ProcessResource.plant3Dresource.EndComponent);\r
+               list.add(ProcessResource.plant3Dresource.Nozzle);\r
+               \r
+               return list;\r
+       }\r
+       \r
+       /**\r
+        * Returns optional types for a component type\r
+        * @param type\r
+        * @return\r
+        */\r
+       private List<Resource> getComponentOptions(Resource type) {\r
+               List<Resource> list = new ArrayList<Resource>();\r
+               if (type.equals(ProcessResource.plant3Dresource.FixedLengthInlineComponent)) {\r
+                       list.add(ProcessResource.plant3Dresource.SizeChangeComponent);\r
+                       list.add(ProcessResource.plant3Dresource.OffsetComponent);\r
+               }\r
+               return list;\r
+       }\r
+       \r
+       /**\r
+        * Returns control point type(s) for given control point type. \r
+        * \r
+        * @param types\r
+        * @return\r
+        */\r
+       private List<Resource> getControlPointTypes(List<Resource> types) {\r
+               Resource primaryType = types.get(0);\r
+               List<Resource> cpTypes = new ArrayList<Resource>();\r
+               if (primaryType == ProcessResource.plant3Dresource.FixedLengthInlineComponent) {\r
+                       if (types.size() == 1) {\r
+                               cpTypes.add(ProcessResource.plant3Dresource.FixedLengthControlPoint);\r
+                       } else {\r
+                               if (types.contains(ProcessResource.plant3Dresource.SizeChangeComponent)) {\r
+                                       cpTypes.add(ProcessResource.plant3Dresource.SizeChangeControlPoint);\r
+                               }\r
+                               if (types.contains(ProcessResource.plant3Dresource.OffsetComponent)) {\r
+                                       cpTypes.add(ProcessResource.plant3Dresource.OffsettingPoint);\r
+                               }\r
+                               if (cpTypes.size() == 0) {\r
+                                       throw new RuntimeException("Cannot find control point type for " + primaryType);\r
+                               }\r
+                       }\r
+                       \r
+               } else if (primaryType == ProcessResource.plant3Dresource.VariableLengthInlineComponent) {\r
+                       cpTypes.add(ProcessResource.plant3Dresource.VariableLengthControlPoint);\r
+               } else if (primaryType == ProcessResource.plant3Dresource.FixedAngleTurnComponent) {\r
+                       cpTypes.add(ProcessResource.plant3Dresource.FixedAngleTurnControlPoint);\r
+               } else if (primaryType == ProcessResource.plant3Dresource.VariableAngleTurnComponent) {\r
+                       cpTypes.add(ProcessResource.plant3Dresource.VariableAngleTurnControlPoint);\r
+               } else if (primaryType == ProcessResource.plant3Dresource.EndComponent) {\r
+                       cpTypes.add(ProcessResource.plant3Dresource.EndComponentControlPoint);\r
+               } else if (primaryType == ProcessResource.plant3Dresource.Nozzle) {\r
+                       cpTypes.add(ProcessResource.plant3Dresource.NozzleControlPoint);\r
+               } else {\r
+                       throw new RuntimeException("Cannot find control point type for " + primaryType);\r
+               }\r
+                       \r
+               return cpTypes;\r
+       }\r
+       \r
+       \r
+       private class ComponentTypeDialog extends Dialog {\r
+               \r
+               List<Resource> selected = new ArrayList<Resource>();\r
+               String name;\r
+               \r
+               public ComponentTypeDialog(Shell shell) {\r
+                       super(shell);\r
+               }\r
+               \r
+               @Override\r
+               protected Control createDialogArea(Composite parent) {\r
+                       Composite composite = (Composite) super.createDialogArea(parent);\r
+                       Label label = new Label(composite,SWT.NONE);\r
+                       label.setText("Name:");\r
+                       Text text = new Text(composite,SWT.SINGLE|SWT.BORDER);\r
+                       text.addModifyListener(new ModifyListener() {\r
+                               @Override\r
+                               public void modifyText(ModifyEvent e) {\r
+                                       name = ((Text)e.widget).getText();\r
+                               }\r
+                       });\r
+                       GridData data = new GridData();\r
+                       data.grabExcessHorizontalSpace = true;\r
+                       data.horizontalAlignment = SWT.FILL;\r
+                       text.setLayoutData(data);\r
+                       label = new Label(composite,SWT.NONE);\r
+                       label.setText("Type:");\r
+                       for (Resource r : getComponentTypes()) {\r
+                               final Button b = new Button(composite,SWT.RADIO);\r
+                               b.setText(nameMap.get(r));\r
+                               b.setData(r);\r
+                               b.addSelectionListener(new SelectionAdapter() {\r
+                                       @Override\r
+                                       public void widgetSelected(SelectionEvent e) {\r
+                                               Button button = (Button)e.widget;\r
+                                               Resource res = (Resource)button.getData();\r
+                                               if (button.getSelection()) {\r
+                                                       selected.add(0,res);\r
+                                               } else {\r
+                                                       selected.remove(res);\r
+                                               }\r
+                                       }\r
+                               });\r
+                               data = new GridData();\r
+                               b.setLayoutData(data);\r
+                               for (Resource r2 : getComponentOptions(r)) {\r
+                                       final Button b2 = new Button(composite,SWT.CHECK);\r
+                                       b2.setText(nameMap.get(r2));\r
+                                       b2.setData(r2);\r
+                                       b.addSelectionListener(new SelectionAdapter() {\r
+                                               @Override\r
+                                               public void widgetSelected(SelectionEvent e) {\r
+                                                       b2.setEnabled(b.getSelection());\r
+                                                       Resource res = (Resource)b2.getData();\r
+                                                       if (!b.getSelection()) {\r
+                                                               selected.remove(res);\r
+                                                       } else if (b2.getSelection()) {\r
+                                                               selected.add(res);\r
+                                                       }\r
+                                               }\r
+                                       });\r
+                                       b2.addSelectionListener(new SelectionAdapter() {\r
+                                               @Override\r
+                                               public void widgetSelected(SelectionEvent e) {\r
+                                                       Button button = (Button)e.widget;\r
+                                                       Resource res = (Resource)button.getData();\r
+                                                       if (button.getSelection()) {\r
+                                                               selected.add(res);\r
+                                                       } else {\r
+                                                               selected.remove(res);\r
+                                                       }\r
+                                               }\r
+                                       });\r
+                                       b2.setEnabled(false);\r
+                                       data = new GridData();\r
+                                       data.horizontalIndent = convertWidthInCharsToPixels(2);\r
+                                       b2.setLayoutData(data);\r
+                               }\r
+                       }\r
+                       \r
+                       return composite;\r
+               }\r
+               \r
+               List<Resource> getSelection() {\r
+                       return selected;\r
+               }\r
+               \r
+               public String getName() {\r
+                       return name;\r
+               }\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/NewEquipmentHandler.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/NewEquipmentHandler.java
new file mode 100644 (file)
index 0000000..49eb77e
--- /dev/null
@@ -0,0 +1,110 @@
+package fi.vtt.simantics.processeditor.handlers;\r
+\r
+import org.eclipse.core.commands.AbstractHandler;\r
+import org.eclipse.core.commands.ExecutionEvent;\r
+import org.eclipse.core.commands.ExecutionException;\r
+import org.eclipse.jface.dialogs.Dialog;\r
+import org.eclipse.jface.viewers.ISelection;\r
+import org.eclipse.jface.viewers.IStructuredSelection;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.events.ModifyEvent;\r
+import org.eclipse.swt.events.ModifyListener;\r
+import org.eclipse.swt.layout.GridData;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.swt.widgets.Control;\r
+import org.eclipse.swt.widgets.Display;\r
+import org.eclipse.swt.widgets.Label;\r
+import org.eclipse.swt.widgets.Shell;\r
+import org.eclipse.swt.widgets.Text;\r
+import org.eclipse.ui.handlers.HandlerUtil;\r
+import org.simantics.db.Graph;\r
+import org.simantics.db.GraphRequestAdapter;\r
+import org.simantics.db.GraphRequestStatus;\r
+import org.simantics.db.Resource;\r
+import org.simantics.layer0.stubs.Library;\r
+import org.simantics.layer0.utils.EntityFactory;\r
+import org.simantics.layer0.utils.IEntity;\r
+import org.simantics.layer0.utils.instantiation.InstanceFactory;\r
+import org.simantics.proconf.ui.ProConfUI;\r
+import org.simantics.proconf.ui.utils.ResourceAdaptionUtils;\r
+\r
+import fi.vtt.simantics.processeditor.ProcessResource;\r
+import fi.vtt.simantics.processeditor.stubs.Equipment;\r
+\r
+/**\r
+ * Creates new equipment\r
+ * \r
+ * @author Marko Luukkainen <Marko.Luukkainen@vtt.fi>\r
+ *\r
+ */\r
+public class NewEquipmentHandler extends AbstractHandler {\r
+       \r
+       @Override\r
+       public Object execute(ExecutionEvent event) throws ExecutionException {\r
+               ISelection s = HandlerUtil.getCurrentSelectionChecked(event);\r
+        IStructuredSelection ss = (IStructuredSelection) s;\r
+        if (ss.size() != 1)\r
+            return null;\r
+        final Resource lib = ResourceAdaptionUtils.toSingleResource(ss);\r
+        \r
+        EquipmentDialog dialog = new EquipmentDialog(Display.getDefault().getActiveShell());\r
+        if (dialog.open() == EquipmentDialog.CANCEL)\r
+               return null;\r
+        final String name = dialog.getName();\r
+        if (name == null || name.length() == 0)\r
+               return null;\r
+               ProConfUI.getSession().asyncWrite(new GraphRequestAdapter() {\r
+                       @Override\r
+                       public GraphRequestStatus perform(Graph g) throws Exception {\r
+                               Equipment equipment = Equipment.createDefault(g);\r
+                               Library l = new Library(g, lib);\r
+                               l.addStatement(g.getBuiltins().ConsistsOf, equipment);\r
+                               \r
+                               // TODO : is this correct (instance & inherits)\r
+                               equipment.addStatement(ProcessResource.builtins.Inherits, ProcessResource.plant3Dresource.Equipment);\r
+\r
+                               Resource modelType = g.getResourceByURI("http://www.vtt.fi/Simantics/CSG/1.0/Types#CSGModel");\r
+                               IEntity model = EntityFactory.create(g, InstanceFactory.instantiate(g, modelType));\r
+                               equipment.addStatement(ProcessResource.plant3Dresource.HasGraphics, model);\r
+                               equipment.setName(name);\r
+                               return GraphRequestStatus.transactionComplete();\r
+                       }\r
+               });\r
+               \r
+               \r
+               return null;\r
+       }\r
+       \r
+       private class EquipmentDialog extends Dialog {\r
+               \r
+               private String name;\r
+               \r
+               public EquipmentDialog(Shell shell) {\r
+                       super(shell);\r
+               }\r
+               \r
+               @Override\r
+               protected Control createDialogArea(Composite parent) {\r
+                       Composite composite = (Composite) super.createDialogArea(parent);\r
+                       Label label = new Label(composite,SWT.NONE);\r
+                       label.setText("Name:");\r
+                       Text text = new Text(composite,SWT.SINGLE|SWT.BORDER);\r
+                       text.addModifyListener(new ModifyListener() {\r
+                               @Override\r
+                               public void modifyText(ModifyEvent e) {\r
+                                       name = ((Text)e.widget).getText();\r
+                               }\r
+                       });\r
+                       GridData data = new GridData();\r
+                       data.grabExcessHorizontalSpace = true;\r
+                       data.horizontalAlignment = SWT.FILL;\r
+                       text.setLayoutData(data);\r
+                       return composite;\r
+               }\r
+               \r
+               public String getName() {\r
+                       return name;\r
+               }\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/NewPlantHandler.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/NewPlantHandler.java
new file mode 100644 (file)
index 0000000..45f54cf
--- /dev/null
@@ -0,0 +1,95 @@
+package fi.vtt.simantics.processeditor.handlers;\r
+\r
+import org.eclipse.core.commands.AbstractHandler;\r
+import org.eclipse.core.commands.ExecutionEvent;\r
+import org.eclipse.core.commands.ExecutionException;\r
+import org.eclipse.jface.dialogs.Dialog;\r
+import org.eclipse.jface.viewers.ISelection;\r
+import org.eclipse.jface.viewers.IStructuredSelection;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.events.ModifyEvent;\r
+import org.eclipse.swt.events.ModifyListener;\r
+import org.eclipse.swt.layout.GridData;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.swt.widgets.Control;\r
+import org.eclipse.swt.widgets.Display;\r
+import org.eclipse.swt.widgets.Label;\r
+import org.eclipse.swt.widgets.Shell;\r
+import org.eclipse.swt.widgets.Text;\r
+import org.eclipse.ui.handlers.HandlerUtil;\r
+import org.simantics.db.Graph;\r
+import org.simantics.db.GraphRequestAdapter;\r
+import org.simantics.db.GraphRequestStatus;\r
+import org.simantics.db.Resource;\r
+import org.simantics.layer0.stubs.Library;\r
+import org.simantics.proconf.ui.ProConfUI;\r
+import org.simantics.proconf.ui.utils.ResourceAdaptionUtils;\r
+\r
+import fi.vtt.simantics.processeditor.stubs.Plant;\r
+\r
+public class NewPlantHandler extends AbstractHandler {\r
+       \r
+       @Override\r
+       public Object execute(ExecutionEvent event) throws ExecutionException {\r
+               ISelection s = HandlerUtil.getCurrentSelectionChecked(event);\r
+        IStructuredSelection ss = (IStructuredSelection) s;\r
+        if (ss.size() != 1)\r
+            return null;\r
+        final Resource lib = ResourceAdaptionUtils.toSingleResource(ss);\r
+        \r
+        PlantDialog dialog = new PlantDialog(Display.getDefault().getActiveShell());\r
+        if (dialog.open() == PlantDialog.CANCEL)\r
+               return null;\r
+        final String name = dialog.getName();\r
+        if (name == null || name.length() == 0)\r
+               return null;\r
+        \r
+               ProConfUI.getSession().asyncWrite(new GraphRequestAdapter() {\r
+                       @Override\r
+                       public GraphRequestStatus perform(Graph g) throws Exception {\r
+                               Plant model = Plant.createDefault(g);\r
+                               model.setName(name);\r
+                               Library l = new Library(g, lib);\r
+                               l.addStatement(g.getBuiltins().ConsistsOf, model);\r
+                               \r
+                               return GraphRequestStatus.transactionComplete();\r
+                       }\r
+               });\r
+               \r
+               \r
+               return null;\r
+       }\r
+       \r
+       private class PlantDialog extends Dialog {\r
+               \r
+               private String name;\r
+               \r
+               public PlantDialog(Shell shell) {\r
+                       super(shell);\r
+               }\r
+               \r
+               @Override\r
+               protected Control createDialogArea(Composite parent) {\r
+                       Composite composite = (Composite) super.createDialogArea(parent);\r
+                       Label label = new Label(composite,SWT.NONE);\r
+                       label.setText("Name:");\r
+                       Text text = new Text(composite,SWT.SINGLE|SWT.BORDER);\r
+                       text.addModifyListener(new ModifyListener() {\r
+                               @Override\r
+                               public void modifyText(ModifyEvent e) {\r
+                                       name = ((Text)e.widget).getText();\r
+                               }\r
+                       });\r
+                       GridData data = new GridData();\r
+                       data.grabExcessHorizontalSpace = true;\r
+                       data.horizontalAlignment = SWT.FILL;\r
+                       text.setLayoutData(data);\r
+                       return composite;\r
+               }\r
+               \r
+               public String getName() {\r
+                       return name;\r
+               }\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/PipelineComponentEditorAdapter.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/PipelineComponentEditorAdapter.java
new file mode 100644 (file)
index 0000000..2523fa1
--- /dev/null
@@ -0,0 +1,45 @@
+package fi.vtt.simantics.processeditor.handlers;\r
+\r
+import org.simantics.db.Graph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.proconf.ui.workbench.ResourceEditorInput;\r
+import org.simantics.proconf.ui.workbench.editor.SimpleEditorAdapter;\r
+import org.simantics.utils.ui.BundleUtils;\r
+import org.simantics.utils.ui.workbench.WorkbenchUtils;\r
+\r
+import fi.vtt.simantics.processeditor.Activator;\r
+import fi.vtt.simantics.processeditor.ProcessResource;\r
+\r
+/**\r
+ * EditorAdapter for PipeLineComponentEditor\r
+ * \r
+ * @author Marko Luukkainen <Marko.Luukkainen@vtt.fi>\r
+ *\r
+ */\r
+public class PipelineComponentEditorAdapter extends SimpleEditorAdapter {\r
+       public PipelineComponentEditorAdapter() {\r
+               super("Component Editor",\r
+                       BundleUtils.getImageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/Component.png"),\r
+                       null,null,null);\r
+       }\r
+\r
+       @Override\r
+       public boolean canHandle(Graph g, Resource r) {\r
+               if(ProcessResource.plant3Dresource == null) return false; \r
+               if(ProcessResource.plant3Dresource.Plant == null) return false; \r
+               if(!g.isInstanceOf(r, ProcessResource.plant3Dresource.PipelineComponent)) {\r
+                       if (g.isInstanceOf(r, ProcessResource.plant3Dresource.Nozzle))\r
+                               return true;\r
+                       return false;\r
+               }\r
+               if(g.isInstanceOf(r, ProcessResource.plant3Dresource.CodedComponent)) return false;\r
+               return true;\r
+       }\r
+\r
+\r
+       @Override\r
+       public void openEditor(Resource r) throws Exception {\r
+               WorkbenchUtils.openEditor("org.simantics.proconf.processeditor.componenteditor", new ResourceEditorInput("org.simantics.proconf.processeditor.componenteditor",r));\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/Plant3DEditorAdapter.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/Plant3DEditorAdapter.java
new file mode 100644 (file)
index 0000000..93edd94
--- /dev/null
@@ -0,0 +1,34 @@
+package fi.vtt.simantics.processeditor.handlers;\r
+\r
+import org.simantics.db.Graph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.proconf.ui.workbench.ResourceEditorInput;\r
+import org.simantics.proconf.ui.workbench.editor.SimpleEditorAdapter;\r
+import org.simantics.utils.ui.BundleUtils;\r
+import org.simantics.utils.ui.workbench.WorkbenchUtils;\r
+\r
+import fi.vtt.simantics.processeditor.Activator;\r
+import fi.vtt.simantics.processeditor.ProcessResource;\r
+\r
+public class Plant3DEditorAdapter extends SimpleEditorAdapter {\r
+       public Plant3DEditorAdapter() {\r
+               super("PlantEditor",\r
+                       BundleUtils.getImageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/factory.png"),\r
+                       null,null,null);\r
+       }\r
+\r
+       @Override\r
+       public boolean canHandle(Graph g, Resource r) {\r
+               if(ProcessResource.plant3Dresource == null) return false; \r
+               if(ProcessResource.plant3Dresource.Plant == null) return false; \r
+               return g.isInstanceOf(r, ProcessResource.plant3Dresource.Plant);\r
+       }\r
+\r
+\r
+       @Override\r
+       public void openEditor(Resource r) throws Exception {\r
+               WorkbenchUtils.openEditor("org.simantics.proconf.processeditor.planteditor", new ResourceEditorInput("org.simantics.proconf.processeditor.planteditor",r));\r
+\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/Plant3DProjectAdapter.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/Plant3DProjectAdapter.java
new file mode 100644 (file)
index 0000000..305b636
--- /dev/null
@@ -0,0 +1,14 @@
+package fi.vtt.simantics.processeditor.handlers;\r
+\r
+import org.simantics.db.Graph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.adaption.AdaptionException;\r
+import org.simantics.db.adaption.ResourceAdapter;\r
+\r
+public class Plant3DProjectAdapter implements ResourceAdapter {\r
+       @SuppressWarnings("unchecked")\r
+       @Override\r
+       public <T> T adapt(Graph graph, Resource resource, Resource mia) throws AdaptionException {\r
+               return (T) new Plant3DProjectType(graph,resource);\r
+       }\r
+}\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/Plant3DProjectType.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/Plant3DProjectType.java
new file mode 100644 (file)
index 0000000..f112117
--- /dev/null
@@ -0,0 +1,53 @@
+package fi.vtt.simantics.processeditor.handlers;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+\r
+import org.simantics.db.Builtins;\r
+import org.simantics.db.Graph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.layer0.utils.direct.GraphUtils;\r
+import org.simantics.proconf.ui.projects.IProject;\r
+import org.simantics.proconf.ui.projects.ProjectType;\r
+\r
+public class Plant3DProjectType extends ProjectType{\r
+\r
+       public Plant3DProjectType(Graph graph, Resource projectTypeResource) {\r
+               super(graph, projectTypeResource);\r
+       }\r
+\r
+       @Override\r
+       public Resource createProject(Graph g, String name) throws Exception {\r
+               Resource project = super.createProject(g, name);\r
+               Builtins b = g.getBuiltins();\r
+               {   // Plants\r
+                       Resource modelLibrary = g.newResource();                \r
+               g.addStatement(modelLibrary, b.InstanceOf, b.ModelLibrary);\r
+               GraphUtils.addRelatedScalarString(g, modelLibrary, b.HasName, "Plants");\r
+               g.addStatement(project, b.ConsistsOf, modelLibrary);        \r
+               }\r
+               {   // Equipment\r
+                       Resource modelLibrary = g.newResource();                \r
+               g.addStatement(modelLibrary, b.InstanceOf, b.ModelLibrary);\r
+               GraphUtils.addRelatedScalarString(g, modelLibrary, b.HasName, "Equipment");\r
+               g.addStatement(project, b.ConsistsOf, modelLibrary);        \r
+               }\r
+               return project;\r
+       \r
+       }\r
+       \r
+       @Override\r
+       public IProject loadProject(Graph g, Resource r) {\r
+               \r
+               IProject project = super.loadProject(g, r);\r
+               project.set(DefaultPerspective, "org.simantics.proconf.processeditor.plantmodelling");\r
+               Collection<String> perspectives = new ArrayList<String>();\r
+               perspectives.add("org.simantics.proconf.processeditor.plantmodelling");\r
+               project.set(Perspectives, perspectives);\r
+               \r
+               return project;\r
+       }\r
+       \r
+\r
+       \r
+}\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/BillboardMonitor.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/BillboardMonitor.java
new file mode 100644 (file)
index 0000000..d35d62c
--- /dev/null
@@ -0,0 +1,216 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007 VTT Technical Research Centre of Finland and others.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package fi.vtt.simantics.processeditor.monitors;\r
+\r
+import java.awt.Color;\r
+import java.util.ArrayList;\r
+\r
+import javax.vecmath.Point3d;\r
+import javax.vecmath.Vector3d;\r
+\r
+import org.simantics.db.Graph;\r
+import org.simantics.proconf.g3d.base.G3DTools;\r
+import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase;\r
+import org.simantics.proconf.g3d.base.VecmathJmeTools;\r
+import org.simantics.proconf.g3d.scenegraph.IGraphicsNode;\r
+import org.simantics.proconf.g3d.stubs.G3DNode;\r
+\r
+import com.jme.image.Texture;\r
+import com.jme.math.Vector3f;\r
+import com.jme.renderer.ColorRGBA;\r
+import com.jme.renderer.Renderer;\r
+import com.jme.scene.BillboardNode;\r
+import com.jme.scene.Node;\r
+import com.jme.scene.shape.Quad;\r
+import com.jme.scene.state.AlphaState;\r
+import com.jme.scene.state.MaterialState;\r
+import com.jme.scene.state.RenderState;\r
+import com.jme.scene.state.TextureState;\r
+import com.jme.scene.state.ZBufferState;\r
+import com.jmex.awt.swingui.ImageGraphics;\r
+\r
+\r
+import fi.vtt.simantics.processeditor.ProcessResource;\r
+import fi.vtt.simantics.processeditor.stubs.InlineComponent;\r
+\r
+\r
+\r
+/**\r
+ * A monitor that uses billboard to show it's information. \r
+ * \r
+ * @author Marko Luukkainen\r
+ *\r
+ */\r
+//TODO : should it be variable length / fixed length inline component instead of Straight\r
+\r
+public class BillboardMonitor implements Monitor{\r
+       private enum Type{POSITION,PIPE};\r
+       private Type type;\r
+       private ThreeDimensionalEditorBase editor; \r
+       private BillboardNode monitorNode = null;\r
+       private int monitorSize = 128;\r
+    private ImageGraphics graphics = ImageGraphics.createInstance(monitorSize, monitorSize, 0);\r
+    private Node currentParent = null;\r
+    private IGraphicsNode node = null;\r
+    private boolean useDistanceResize = true;\r
+    \r
+    Point3d start;\r
+    Point3d end;\r
+    Point3d middle;\r
+    \r
+    private MonitorTextProvider provider = new ObjectPropertyProvider();\r
+       \r
+    \r
+       public BillboardMonitor(ThreeDimensionalEditorBase editor) {\r
+               this.editor = editor;\r
+               monitorNode = new BillboardNode("");\r
+               monitorNode.setRenderQueueMode(Renderer.QUEUE_TRANSPARENT);\r
+               ZBufferState zs = editor.getRenderingComponent()\r
+                               .getDisplaySystem().getRenderer().createZBufferState();\r
+               zs.setEnabled(true);\r
+               zs.setFunction(ZBufferState.CF_ALWAYS);\r
+               monitorNode.setRenderState(zs);\r
+               Quad quad = new Quad("");\r
+               quad.initialize(3.f, 3.f);\r
+               monitorNode.attachChild(quad);\r
+               // SWTImageGraphics graphics =\r
+               // SWTImageGraphics.createInstance(64,64, 0);\r
+\r
+               graphics.clearRect(0, 0, monitorSize, monitorSize);\r
+\r
+               // graphics.setFont(new Font("Arial",Font.PLAIN,30));\r
+               // graphics.setColor(Display.getDefault().getSystemColor(SWT.COLOR_GREEN));\r
+               graphics.setColor(new Color(0, 255, 0, 255));\r
+               graphics.drawString("Monitor", 0, 32);\r
+               \r
+               TextureState ts = editor.getRenderingComponent().getDisplaySystem().getRenderer().createTextureState();\r
+               Texture texture = new Texture();\r
+               texture.setApply(Texture.AM_MODULATE);\r
+               // texture.setBlendColor(new ColorRGBA(1, 1, 1, 1));\r
+               texture.setFilter(Texture.MM_LINEAR);\r
+               texture.setMipmapState(Texture.FM_LINEAR);\r
+               texture.setImage(graphics.getImage());\r
+               graphics.update();\r
+               AlphaState as = editor.getRenderingComponent().getDisplaySystem()\r
+                               .getRenderer().createAlphaState();\r
+               as.setBlendEnabled(true);\r
+               as.setSrcFunction(AlphaState.SB_SRC_ALPHA);\r
+               as.setDstFunction(AlphaState.DB_ONE_MINUS_SRC_ALPHA);\r
+        as.setTestEnabled(true);\r
+        as.setTestFunction(AlphaState.TF_GREATER);\r
+               ts.setTexture(texture);\r
+               MaterialState ms = editor.getRenderingComponent().getDisplaySystem().getRenderer().createMaterialState();\r
+               ms.setEmissive(new ColorRGBA(1.f, 1.f, 1.f, 0.f));\r
+               monitorNode.setRenderState(ts);\r
+               monitorNode.setRenderState(as);\r
+               monitorNode.setRenderState(ms);\r
+               graphics.drawLine(0, 33, monitorSize-1, 33);\r
+               graphics.update();\r
+       }\r
+       \r
+       public boolean acceptNode(Graph graph, IGraphicsNode node) {\r
+               Node selectedParent = node.getGroup();\r
+               if (currentParent == null || !selectedParent.equals(currentParent)) {\r
+                       if (node.getG3DNode(graph).getLocalPosition() != null) {\r
+                               return true;\r
+                       } else if (node.getG3DNode(graph).isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent)) {\r
+                               \r
+                               return true;\r
+                       }\r
+               }\r
+\r
+               return false;\r
+       }\r
+       \r
+       public void setNode(Graph graph, IGraphicsNode node) {\r
+               G3DNode n = node.getG3DNode(graph);\r
+               if (n.getLocalPosition() != null) {\r
+                       type = Type.POSITION;\r
+                       monitorNode.setLocalTranslation(new Vector3f(0.f,0.f,0.f));\r
+               } else if (n.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent)) {\r
+                       type = Type.PIPE;\r
+                       InlineComponent ic = new InlineComponent(n);\r
+                       start = G3DTools.getPoint(ic.getControlPoint().getPrevious().getLocalPosition());\r
+                       end = G3DTools.getPoint(ic.getControlPoint().getNext().getLocalPosition());\r
+                       Vector3d dir = new Vector3d(end);\r
+                       dir.sub(start);\r
+                       dir.scale(0.5);\r
+                       middle = new Point3d(start);\r
+                       middle.add(dir);\r
+                       monitorNode.setLocalTranslation(VecmathJmeTools.get(middle));\r
+               } else {\r
+                       return;\r
+               }\r
+               Node selectedParent = node.getGroup();\r
+               this.node = node;\r
+               currentParent = selectedParent;\r
+               monitorNode.removeFromParent();\r
+               currentParent.attachChild(monitorNode);\r
+\r
+               provider.setSource(n);\r
+               update(graph);\r
+       }\r
+       \r
+       public IGraphicsNode getNode() {\r
+               return node;\r
+       }\r
+       \r
+       public void update() {\r
+               if (useDistanceResize) {\r
+                       Vector3f v = VecmathJmeTools.get(editor.getCamera().getCameraPos());\r
+                       v.subtractLocal(monitorNode.getWorldTranslation());\r
+                       float length = v.length();\r
+                       monitorNode.setLocalScale(length * 0.06f);\r
+               }\r
+       }\r
+       \r
+       \r
+       public void update(Graph graph) {\r
+               ArrayList<String> titles = provider.getTexts(graph);\r
+               graphics.clearRect(0, 0, monitorSize, monitorSize);\r
+               int y = 16;\r
+               for (String s : titles) {\r
+                       graphics.drawString(s, 0, y);\r
+                       y += 16;\r
+               }\r
+\r
+               TextureState ts = (TextureState) monitorNode\r
+                               .getRenderState(RenderState.RS_TEXTURE);\r
+               ts.deleteAll(); // FIXME : texture won't be updated without this\r
+               graphics.update();\r
+               update();\r
+       }\r
+       \r
+       public void remove() {\r
+               monitorNode.removeFromParent();\r
+               node = null;\r
+       }\r
+\r
+       /**\r
+        * if true, monitors size is independent of distance to camera. Else monitor's size changes when camera is moved.\r
+        * @return\r
+        */\r
+       public boolean isUseDistanceResize() {\r
+               return useDistanceResize;\r
+       }\r
+\r
+       public void setUseDistanceResize(boolean useDistanceResize) {\r
+               this.useDistanceResize = useDistanceResize;\r
+               if (!useDistanceResize) {\r
+                       monitorNode.setLocalScale(1.f);\r
+               }\r
+       }\r
+       \r
+       public void setTextProvider(MonitorTextProvider provider) {\r
+               this.provider = provider;\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/Monitor.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/Monitor.java
new file mode 100644 (file)
index 0000000..d748b17
--- /dev/null
@@ -0,0 +1,62 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007 VTT Technical Research Centre of Finland and others.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package fi.vtt.simantics.processeditor.monitors;\r
+\r
+import org.simantics.db.Graph;\r
+import org.simantics.proconf.g3d.scenegraph.IGraphicsNode;\r
+\r
+\r
+\r
+\r
+/**\r
+ * Interface for monitors (Textual display of objects properties)\r
+ * \r
+ * @author Marko Luukkainen\r
+ *\r
+ */\r
+public interface Monitor {\r
+       \r
+       /**\r
+        * Returns true if monitor can be attached to node\r
+        * @param node\r
+        * @return\r
+        */\r
+       public boolean acceptNode(Graph graph,IGraphicsNode node);\r
+       \r
+       /**\r
+        * Returns the scene-graph node where monitor is attached\r
+        * @return\r
+        */\r
+       public IGraphicsNode getNode();\r
+\r
+       /**\r
+        * Sets monitored node\r
+        * @param node\r
+        */\r
+       public void setNode(Graph graph,IGraphicsNode node);\r
+       \r
+       /**\r
+        * Updates monitor's texts\r
+        *\r
+        */\r
+       public void update();\r
+       \r
+       public void update(Graph graph);\r
+       \r
+       /**\r
+        * Removes the monitor. \r
+        */\r
+       public void remove();   \r
+       \r
+       \r
+       public void setTextProvider(MonitorTextProvider provider);\r
+       \r
+}\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/MonitorTextProvider.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/MonitorTextProvider.java
new file mode 100644 (file)
index 0000000..08b3b02
--- /dev/null
@@ -0,0 +1,23 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007 VTT Technical Research Centre of Finland and others.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package fi.vtt.simantics.processeditor.monitors;\r
+\r
+import java.util.ArrayList;\r
+\r
+import org.simantics.db.Graph;\r
+import org.simantics.layer0.utils.IEntity;\r
+\r
+\r
+\r
+public interface MonitorTextProvider {\r
+       public void setSource(IEntity instance);\r
+       public ArrayList<String> getTexts(Graph graph);\r
+}\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/ObjectPropertyProvider.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/ObjectPropertyProvider.java
new file mode 100644 (file)
index 0000000..f094560
--- /dev/null
@@ -0,0 +1,64 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007 VTT Technical Research Centre of Finland and others.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package fi.vtt.simantics.processeditor.monitors;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.List;\r
+\r
+import org.simantics.db.Graph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.layer0.utils.EntityFactory;\r
+import org.simantics.layer0.utils.IEntity;\r
+import org.simantics.layer0.utils.ResourceDebugUtils;\r
+\r
+\r
+import fi.vtt.simantics.processeditor.ProcessResource;\r
+\r
+\r
+public class ObjectPropertyProvider implements MonitorTextProvider {\r
+       \r
+       private Resource instance;\r
+       private Resource properties[];\r
+       String name;\r
+       \r
+       public void setSource(IEntity instance) {\r
+               this.instance = instance.getResource();\r
+               Collection<IEntity> props = instance.getRelatedObjects(ProcessResource.builtins.HasProperty);\r
+               List<Resource> res = new ArrayList<Resource>();\r
+               for (IEntity t : props)\r
+                       res.add(t.getResource());\r
+               properties = new Resource[res.size()];\r
+               properties = res.toArray(properties);\r
+               name = ResourceDebugUtils.getReadableNameForEntity(instance);\r
+       }\r
+       \r
+       public ArrayList<String> getTexts(Graph graph) {\r
+               ArrayList<String> titles = new ArrayList<String>();\r
+               if (instance == null)\r
+                       return titles;\r
+               IEntity thing = EntityFactory.create(graph,instance);\r
+               name = ResourceDebugUtils.getReadableNameForEntity(thing);\r
+               titles.add(name);\r
+\r
+               for (Resource p : properties) {\r
+                       thing = EntityFactory.create(graph,p);\r
+                       //if (p.isInstanceOf(Builtins.Double)) {\r
+                               //typeResources = p.getRelatedResources(Builtins.InstanceOf);\r
+                               //name = PropertyUtils.getScalarStringProperty(typeResources[0],Builtins.HasName);\r
+                               name = ResourceDebugUtils.getReadableNameForEntity(thing);\r
+                               titles.add(name);\r
+                       //}\r
+               }\r
+               return titles;\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/PathContainer.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/PathContainer.java
new file mode 100644 (file)
index 0000000..4c2aab7
--- /dev/null
@@ -0,0 +1,61 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007 VTT Technical Research Centre of Finland and others.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package fi.vtt.simantics.processeditor.monitors;\r
+\r
+import java.util.Collection;\r
+import java.util.List;\r
+\r
+import org.simantics.db.Resource;\r
+import org.simantics.layer0.utils.IEntity;\r
+import org.simantics.utils.datastructures.MapList;\r
+\r
+\r
+/**\r
+ * Container for Paths\r
+ * FIXME : singleton\r
+ * TODO : removing paths\r
+ * TODO : prevent adding same path multiple times\r
+ * \r
+ * \r
+ * @author Marko Luukkainen\r
+ *\r
+ */\r
+public class PathContainer {\r
+       \r
+       private static PathContainer instance = new PathContainer();\r
+       \r
+       MapList<Resource, List<Resource>> paths;\r
+       \r
+       private PathContainer() {\r
+               paths = new MapList<Resource, List<Resource>>();\r
+       }\r
+       \r
+       public List<List<Resource>> getPaths(IEntity instance) {\r
+               Collection<IEntity> types = instance.getTypes();\r
+               if (types.size() != 1)\r
+                       throw new UnsupportedOperationException("Multi-instances not supported!");\r
+               Resource type = types.iterator().next().getResource();\r
+               return paths.getValues(type);\r
+       }\r
+       \r
+       public void addPath(Resource type, List<Resource> path) {\r
+               paths.add(type, path);\r
+       }\r
+       \r
+       public void clearPaths(Resource type) {\r
+               paths.remove(type);\r
+       }\r
+       \r
+       public static PathContainer getInstance() {\r
+               return instance;\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/ResourcePathPropertyProvider.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/ResourcePathPropertyProvider.java
new file mode 100644 (file)
index 0000000..7581233
--- /dev/null
@@ -0,0 +1,87 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007 VTT Technical Research Centre of Finland and others.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package fi.vtt.simantics.processeditor.monitors;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.List;\r
+\r
+import org.simantics.db.Graph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.layer0.utils.EntityFactory;\r
+import org.simantics.layer0.utils.IEntity;\r
+import org.simantics.layer0.utils.ResourceDebugUtils;\r
+\r
+import fi.vtt.simantics.processeditor.common.PathUtils;\r
+\r
+\r
+public class ResourcePathPropertyProvider implements MonitorTextProvider {\r
+       \r
+       private Resource instance;\r
+       private List<Resource> properties = new ArrayList<Resource>();\r
+       private List<String> names = new ArrayList<String>();\r
+       private List<String> units = new ArrayList<String>();\r
+       String name;\r
+       \r
+       private MonitorTextProvider provider = new ObjectPropertyProvider();\r
+       \r
+       public void setSource(IEntity instance) {\r
+               this.instance = instance.getResource();\r
+               properties.clear();\r
+               names.clear();\r
+               //units.clear();\r
+               List<List<Resource>> paths = PathContainer.getInstance().getPaths(instance);\r
+               if (paths != null) {\r
+                       for (List<Resource> path : paths) {\r
+                               IEntity source = PathUtils.findSimilar(path, instance);\r
+                               if (source != null)\r
+                                       properties.add(source.getResource());\r
+                       }\r
+               }\r
+               Collection<IEntity> types = instance.getTypes();\r
+               name = ResourceDebugUtils.getReadableNameForEntity(types.iterator().next());\r
+               for (Resource p : properties) {\r
+                       names.add(ResourceDebugUtils.getReadableNameForEntity(EntityFactory.create(instance.getGraph(),p)));\r
+//                     if (p.isInstanceOf(Builtins.Double)) {\r
+//                             typeResources = p.getRelatedResources(Builtins.InstanceOf);\r
+//                             String name = PropertyUtils.getScalarStringProperty(typeResources[0],Builtins.HasName);\r
+//                             Property property = new Property(p);\r
+//                             String abbr = property.getUnitAbbreviation();\r
+//                             names.add(name);\r
+//                             if (abbr != null)\r
+//                                     units.add(abbr);\r
+//                             else\r
+//                                     units.add("");\r
+//                             //titles.add(name + " " + PropertyUtils.getDoubleValue(p)[0] + " " + abbr);\r
+//                     }\r
+               }\r
+               provider.setSource(instance);\r
+       }\r
+       \r
+       public ArrayList<String> getTexts(Graph graph) {\r
+               if (properties.size() == 0)\r
+                       return provider.getTexts(graph);\r
+               ArrayList<String> titles = new ArrayList<String>();\r
+               if (instance == null)\r
+                       return titles;\r
+               \r
+               titles.add(name);\r
+               for (int i = 0; i < properties.size(); i++) {\r
+                       //titles.add(names.get(i) + " " + Double.toString(PropertyUtils.getDoubleValue(properties.get(i))[0]) + " " + units.get(i));\r
+                       // FIXME : check value\r
+                       titles.add(names.get(i) + " " + EntityFactory.create(graph,properties.get(i)).toProperty().getValue());\r
+               }\r
+\r
+               return titles;\r
+       }\r
+       \r
+\r
+}\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/TextMonitor.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/TextMonitor.java
new file mode 100644 (file)
index 0000000..41c60a6
--- /dev/null
@@ -0,0 +1,272 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007 VTT Technical Research Centre of Finland and others.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package fi.vtt.simantics.processeditor.monitors;\r
+\r
+import java.net.URL;\r
+import java.util.ArrayList;\r
+\r
+import javax.vecmath.Point3d;\r
+import javax.vecmath.Vector3d;\r
+\r
+import org.eclipse.core.runtime.FileLocator;\r
+import org.eclipse.core.runtime.Path;\r
+import org.eclipse.swt.graphics.Rectangle;\r
+import org.simantics.db.Graph;\r
+import org.simantics.proconf.g3d.base.G3DTools;\r
+import org.simantics.proconf.g3d.base.MathTools;\r
+import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase;\r
+import org.simantics.proconf.g3d.base.VecmathJmeTools;\r
+import org.simantics.proconf.g3d.scenegraph.IGraphicsNode;\r
+import org.simantics.proconf.g3d.stubs.G3DNode;\r
+\r
+import com.jme.image.Texture;\r
+import com.jme.math.Vector2f;\r
+import com.jme.math.Vector3f;\r
+import com.jme.renderer.ColorRGBA;\r
+import com.jme.renderer.Renderer;\r
+import com.jme.scene.Node;\r
+import com.jme.scene.Text;\r
+import com.jme.scene.shape.Quad;\r
+import com.jme.scene.state.AlphaState;\r
+import com.jme.scene.state.MaterialState;\r
+import com.jme.scene.state.RenderState;\r
+import com.jme.scene.state.TextureState;\r
+import com.jme.util.TextureManager;\r
+\r
+import fi.vtt.simantics.processeditor.ProcessResource;\r
+import fi.vtt.simantics.processeditor.stubs.InlineComponent;\r
+\r
+/**\r
+ * A monitor implemetation that uses JME's text component to show it's information. \r
+ * \r
+ * @author Marko Luukkainen\r
+ *\r
+ */\r
+public class TextMonitor implements Monitor {\r
+       private enum Type{POSITION,PIPE};\r
+       private Type type;\r
+       \r
+       public static String fontLocation = "data/textures/tahoma512.png";\r
+    \r
+       \r
+       private ThreeDimensionalEditorBase editor;\r
+       private ArrayList<Text> texts = new ArrayList<Text>();\r
+       private Node monitorNode = new Node("");\r
+       Node textNode;\r
+       private IGraphicsNode node = null;\r
+       \r
+    Point3d start;\r
+    Point3d end;\r
+    Point3d middle;\r
+    \r
+    float width = 0.f;\r
+    float height = 0.f;\r
+    float textHeight = 0.f;\r
+    \r
+    Quad background;\r
+    \r
+    private MonitorTextProvider provider = new ObjectPropertyProvider();\r
+       \r
+       public TextMonitor(ThreeDimensionalEditorBase editor) {\r
+               this.editor = editor;\r
+               textNode = new Node("");\r
+               \r
+               \r
+               \r
+               AlphaState as1 = editor.getRenderingComponent().getDisplaySystem().getRenderer().createAlphaState();\r
+        as1.setBlendEnabled(true);\r
+        as1.setSrcFunction(AlphaState.SB_SRC_ALPHA);\r
+        as1.setDstFunction(AlphaState.DB_ONE_MINUS_SRC_ALPHA);\r
+        as1.setTestEnabled(true);\r
+        as1.setTestFunction(AlphaState.TF_GREATER);\r
+        as1.setEnabled(true);\r
+        \r
+        MaterialState ms = editor.getRenderingComponent().getDisplaySystem().getRenderer().createMaterialState();\r
+        ms.setEmissive(new ColorRGBA(0.f,1.f,0.f,0.f));\r
+        \r
+        TextureState font = editor.getRenderingComponent().getDisplaySystem().getRenderer().createTextureState();\r
+        /** The texture is loaded from fontLocation */\r
+        font.setTexture(loadFontTexture());\r
+        font.setEnabled(true);\r
+        textNode.setRenderState(font);\r
+        textNode.setRenderState(as1);\r
+        textNode.setRenderState(ms);\r
+        background = new Quad("",100.f,100.f);\r
+        \r
+        MaterialState ms2 = editor.getRenderingComponent().getDisplaySystem().getRenderer().createMaterialState();\r
+        ms2.setEmissive(new ColorRGBA(0.f,0.f,0.f,0.8f));\r
+        ms2.setDiffuse(new ColorRGBA(0.f,0.f,0.f,0.8f));\r
+\r
+        AlphaState as2 = editor.getRenderingComponent().getDisplaySystem().getRenderer().createAlphaState();\r
+        as2.setBlendEnabled(true);\r
+        as2.setSrcFunction(AlphaState.SB_SRC_ALPHA);\r
+        as2.setDstFunction(AlphaState.DB_ONE_MINUS_SRC_ALPHA);\r
+        as2.setTestEnabled(true);\r
+        as2.setTestFunction(AlphaState.TF_GREATER);\r
+        as2.setEnabled(true);\r
+        monitorNode.setRenderState(ms2);\r
+        monitorNode.setRenderState(as2);\r
+        \r
+        background.setRenderQueueMode(Renderer.QUEUE_ORTHO);\r
+        textNode.setRenderQueueMode(Renderer.QUEUE_ORTHO);\r
+        \r
+        monitorNode.attachChild(background);\r
+        monitorNode.attachChild(textNode);\r
+       // editor.getRenderingComponent().getOrthoNode().attachChild(monitorNode);\r
+        \r
+               \r
+       }\r
+       \r
+       public boolean acceptNode(Graph graph,IGraphicsNode node) {\r
+               G3DNode n = node.getG3DNode(graph);\r
+               if (this.node == null || !node.equals(this.node)) {\r
+                       if (n.getLocalPosition() != null) {\r
+                               return true;\r
+                       } else if (n.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent)) {\r
+                               return true;\r
+                       }\r
+               }\r
+\r
+               return false;\r
+\r
+       }\r
+       \r
+       public void setNode(Graph graph, IGraphicsNode node) {\r
+               G3DNode n = node.getG3DNode(graph);\r
+               if (n.getLocalPosition() != null) {\r
+                       type = Type.POSITION;\r
+               } else if (n.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent)) {\r
+                       type = Type.PIPE;\r
+                       InlineComponent ic = new InlineComponent(n);\r
+                       start = G3DTools.getPoint(ic.getControlPoint().getPrevious().getWorldPosition());\r
+                       end = G3DTools.getPoint(ic.getControlPoint().getNext().getWorldPosition());\r
+                       Vector3d dir = new Vector3d(end);\r
+                       dir.sub(start);\r
+                       dir.scale(0.5);\r
+                       middle = new Point3d(start);\r
+                       middle.add(dir);\r
+               } else {\r
+                       return;\r
+               }\r
+               \r
+               this.node = node;\r
+               provider.setSource(n);\r
+               ArrayList<String> titles = provider.getTexts(graph);\r
+               \r
+               for (int i = titles.size() - 1; i < texts.size(); i++) {\r
+                       texts.get(i).removeFromParent();\r
+               }\r
+               while (texts.size() < titles.size()) {\r
+                       Text text = new Text("", "");\r
+                       texts.add(text);\r
+                       textNode.attachChild(text);\r
+               }\r
+               width = 0.f;\r
+               height = 0.f;\r
+               for (int i = 0; i < titles.size(); i++) {\r
+                       Text text = texts.get(i);\r
+                       text.print(titles.get(i));\r
+                       width = Math.max(width,text.getWidth());\r
+                       textHeight = text.getHeight();\r
+                       height += textHeight;\r
+                       textNode.attachChild(text);\r
+               }\r
+               background.resize(width+20.f, height+10.f);\r
+               if (monitorNode.getParent() == null)\r
+                       editor.getScenegraphAdapter().getRoot().attachChild(monitorNode);\r
+               \r
+       }\r
+       \r
+       private void updateText(Graph graph) {\r
+               ArrayList<String> titles = provider.getTexts(graph);\r
+               float newWidth = 0.f;\r
+               for (int i = 0; i < titles.size(); i++) {\r
+                       Text text = texts.get(i);\r
+                       text.print(titles.get(i));\r
+                       newWidth = Math.max(newWidth,text.getWidth());\r
+               }\r
+               if (newWidth != width) {\r
+                       width = newWidth;\r
+                       background.resize(width+20.f, height+10.f);\r
+               }\r
+                       \r
+       }\r
+       \r
+       public void update() {\r
+               if (node == null)\r
+                       return;\r
+               Vector2f v;\r
+                       \r
+               if (type == Type.POSITION) {\r
+                       v = editor.getScreenCoord(VecmathJmeTools.getD(node.getGroup().getWorldTranslation()));\r
+               } else {\r
+                       float mx = editor.getRenderingComponent().getDisplaySystem().getWidth();\r
+                       float my = editor.getRenderingComponent().getDisplaySystem().getHeight();\r
+                       Vector2f s = editor.getScreenCoord(start);\r
+                       Vector2f e = editor.getScreenCoord(end);\r
+                       Vector2f rs = new Vector2f();\r
+                       Vector2f re = new Vector2f();\r
+                       boolean in = MathTools.clipLineRectangle(s, e, new Vector2f(0.f,0.f), new Vector2f(mx,my), rs, re);\r
+                       if (in) {\r
+                               re.subtractLocal(rs);\r
+                               re.multLocal(0.5f);\r
+                               rs.addLocal(re);\r
+                               v = rs;\r
+                       } else {\r
+                               // just a hack to move monitor out of the view\r
+                               v = new Vector2f (mx+width,my+height);\r
+                       }\r
+                       \r
+                       \r
+               }\r
+               background.setLocalTranslation(new Vector3f(v.x,v.y,0.f));\r
+               float y = v.y + (height * 0.5f) - textHeight;\r
+               v.x -= width * 0.5f;\r
+               \r
+               for (Text text : texts) {\r
+                       text.setLocalTranslation(new Vector3f(v.x,y,0.f));\r
+                       y -= textHeight;\r
+               }\r
+               \r
+               \r
+               \r
+       }\r
+       \r
+       @Override\r
+       public void update(Graph graph) {\r
+               updateText(graph);\r
+               update();\r
+       }\r
+       \r
+       public IGraphicsNode getNode() {\r
+               return node;\r
+       }\r
+       \r
+       public void remove() {\r
+               monitorNode.removeFromParent();\r
+               node = null;\r
+       }\r
+       \r
+       protected Texture loadFontTexture() {\r
+               URL url = FileLocator.find(com.jme.eclipse.Activator.getDefault().getBundle(),new Path(fontLocation),null);\r
+        return TextureManager.loadTexture(url, Texture.MM_LINEAR,\r
+                Texture.FM_LINEAR);\r
+       }\r
+       \r
+       public void setTextProvider(MonitorTextProvider provider) {\r
+               this.provider = provider;\r
+       }\r
+       \r
+       \r
+\r
+       \r
+       \r
+}\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/perspectives/Plant3DModellingPerspective.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/perspectives/Plant3DModellingPerspective.java
new file mode 100644 (file)
index 0000000..f7cceaa
--- /dev/null
@@ -0,0 +1,13 @@
+package fi.vtt.simantics.processeditor.perspectives;\r
+\r
+import org.eclipse.ui.IPageLayout;\r
+import org.eclipse.ui.IPerspectiveFactory;\r
+\r
+public class Plant3DModellingPerspective implements IPerspectiveFactory{\r
+       \r
+       @Override\r
+       public void createInitialLayout(IPageLayout layout) {\r
+               \r
+       }\r
+\r
+}\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/perspectives/ViewpointGenerator.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/perspectives/ViewpointGenerator.java
new file mode 100644 (file)
index 0000000..03c7a5c
--- /dev/null
@@ -0,0 +1,108 @@
+package fi.vtt.simantics.processeditor.perspectives;\r
+\r
+import java.util.Collection;\r
+\r
+import org.simantics.db.Builtins;\r
+import org.simantics.layer0.utils.IEntity;\r
+import org.simantics.layer0.utils.Statement;\r
+import org.simantics.layer0.utils.viewpoints.AcceptDecision;\r
+import org.simantics.layer0.utils.viewpoints.AcceptRule;\r
+import org.simantics.layer0.utils.viewpoints.PlainStateFactory;\r
+import org.simantics.layer0.utils.viewpoints.ResourceViewpoint;\r
+import org.simantics.layer0.utils.viewpoints.State;\r
+import org.simantics.layer0.utils.viewpoints.StateFactory;\r
+import org.simantics.layer0.utils.viewpoints.TraversalDecision;\r
+import org.simantics.layer0.utils.viewpoints.TraversalRule;\r
+import org.simantics.layer0.utils.viewpoints.rules.AcceptAllResourceAcceptRule;\r
+\r
+import fi.vtt.simantics.processeditor.ProcessResource;\r
+\r
+public class ViewpointGenerator {\r
+       public static ResourceViewpoint createViewpoint() {\r
+               StateFactory f = new PlainStateFactory();\r
+               final State rootState = f.newState();\r
+               final State projectState = f.newState();\r
+               final State libraryState = f.newState();\r
+               \r
+               return new ResourceViewpoint(new TraversalRule() {\r
+                       @Override\r
+                       public TraversalDecision makeTraversalDecision(State state, Statement statement) {\r
+                               Builtins b = statement.getGraph().getBuiltins();\r
+                               if (state.equals(rootState)) {\r
+                                       if (statement.getObject().isInstanceOf(b.Ontology))\r
+                                               return TraversalDecision.stopTraversal;\r
+                                       if(!statement.getPredicate().equals(b.ConsistsOf))\r
+                                               return TraversalDecision.stopTraversal;\r
+                                       return TraversalDecision.continueTraversal(projectState);\r
+                               } else if (state.equals(projectState)) {\r
+                                       if(!statement.getPredicate().equals(b.ConsistsOf))\r
+                                               return TraversalDecision.stopTraversal;\r
+                                       return TraversalDecision.continueTraversal(libraryState);\r
+                               } else if (state.equals(libraryState)) {\r
+                                       if(!statement.getPredicate().equals(b.ConsistsOf))\r
+                                               return TraversalDecision.stopTraversal;\r
+                                       return TraversalDecision.continueTraversal(libraryState);\r
+                               }\r
+                               return TraversalDecision.stopTraversal;\r
+                       }\r
+                       \r
+                       @Override\r
+                       public boolean areAllStatesRelevant() {\r
+                               return true;\r
+                       }\r
+                       \r
+                       @Override\r
+                       public Collection<State> relevantStates() {\r
+                               return null;\r
+                       }\r
+               }, new AcceptRule<IEntity>() {\r
+               @Override\r
+                       public AcceptDecision makeAcceptDecision(State state, IEntity obj) {\r
+                               Builtins b = obj.getGraph().getBuiltins();\r
+                               //NOSEResource nr = NOSEResource.getInstance(obj.getGraph());\r
+                               if(obj.isInstanceOf(b.Project)) return AcceptDecision.REJECT;\r
+                               else if (obj.isInstanceOf(b.Ontology)) return AcceptDecision.REJECT;\r
+                               else return AcceptDecision.ACCEPT;\r
+                       }\r
+               \r
+                       @Override\r
+                       public boolean areAllStatesRelevant() {\r
+                               return true;\r
+                       }\r
+                       \r
+                       @Override\r
+                       public Collection<State> relevantStates() {\r
+                               return null;\r
+                       }\r
+               }, rootState);\r
+       }\r
+       \r
+       public static ResourceViewpoint createObjectStructureViewpoint() {\r
+               StateFactory f = new PlainStateFactory();\r
+               final State rootState = f.newState();\r
+\r
+               return new ResourceViewpoint(new TraversalRule() {\r
+                       @Override\r
+                       public TraversalDecision makeTraversalDecision(State state,\r
+                                       Statement statement) {\r
+                               if (state.equals(rootState)) {\r
+                                       if (!statement.getPredicate().isSubrelationOf(\r
+                                                       ProcessResource.g3dResource.HasChild))\r
+                                               return TraversalDecision.stopTraversal;\r
+                                       return TraversalDecision.continueTraversal(rootState);\r
+                               }\r
+                               return TraversalDecision.stopTraversal;\r
+                       }\r
+\r
+                       @Override\r
+                       public boolean areAllStatesRelevant() {\r
+                               return true;\r
+                       }\r
+\r
+                       @Override\r
+                       public Collection<State> relevantStates() {\r
+                               return null;\r
+                       }\r
+               }, new AcceptAllResourceAcceptRule(), rootState);\r
+       }\r
+}\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/scenegraph/NonVisibleNode.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/scenegraph/NonVisibleNode.java
new file mode 100644 (file)
index 0000000..240dd86
--- /dev/null
@@ -0,0 +1,29 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007 VTT Technical Research Centre of Finland and others.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package fi.vtt.simantics.processeditor.scenegraph;\r
+\r
+import org.simantics.db.Graph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.proconf.g3d.scenegraph.IGraphicsNode;\r
+import org.simantics.proconf.g3d.scenegraph.NonTransformableNode;\r
+\r
+import fi.vtt.simantics.processeditor.ProcessResource;\r
+\r
+public class NonVisibleNode extends NonTransformableNode {\r
+\r
+    public NonVisibleNode(IGraphicsNode parent, Graph graph, Resource resource) {\r
+        super(parent,resource);\r
+        if (!getG3DNode(graph).isInstanceOf(ProcessResource.plant3Dresource.NonVisibleComponent))\r
+                throw new RuntimeException("Resource must be instance of NonVisibleComponent");\r
+        \r
+    }\r
+\r
+}\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/scenegraph/PipeComponentNode.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/scenegraph/PipeComponentNode.java
new file mode 100644 (file)
index 0000000..2c204a2
--- /dev/null
@@ -0,0 +1,107 @@
+package fi.vtt.simantics.processeditor.scenegraph;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.List;\r
+\r
+import javax.vecmath.AxisAngle4d;\r
+import javax.vecmath.Quat4d;\r
+\r
+import org.simantics.db.Graph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.layer0.utils.EntityFactory;\r
+import org.simantics.layer0.utils.IEntity;\r
+import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase;\r
+import org.simantics.proconf.g3d.scenegraph.IGraphicsNode;\r
+import org.simantics.proconf.g3d.scenegraph.ShapeNode;\r
+\r
+import com.jme.math.Quaternion;\r
+import com.jme.renderer.ColorRGBA;\r
+import com.jme.scene.Geometry;\r
+import com.jme.scene.state.MaterialState;\r
+import com.jme.scene.state.RenderState;\r
+\r
+import fi.vtt.simantics.processeditor.ProcessResource;\r
+import fi.vtt.simantics.processeditor.common.ControlPointTools;\r
+import fi.vtt.simantics.processeditor.common.PipingTools;\r
+import fi.vtt.simantics.processeditor.stubs.CodedComponent;\r
+import fi.vtt.simantics.processeditor.stubs.PipeControlPoint;\r
+import fi.vtt.simantics.processeditor.stubs.Plant3DResource;\r
+import fi.vtt.simantics.processeditor.stubs.SizeChangeControlPoint;\r
+\r
+\r
+/**\r
+ * This is for hard-coded geometries\r
+ * TODO : we need an extension point for geometries,\r
+ *        so that other code-based geometries can be supported\r
+ * \r
+ * \r
+ * @author Marko Luukkainen <Marko.Luukkainen@vtt.fi>\r
+ *\r
+ */\r
+public class PipeComponentNode extends ShapeNode {\r
+       \r
+       enum Type{ELBOW,STRAIGHT,REDUCER};\r
+       \r
+       Type type;\r
+       Resource controlPoint;\r
+\r
+       \r
+       public PipeComponentNode(ThreeDimensionalEditorBase editor, IGraphicsNode parent, Graph graph, Resource resource) {\r
+               super(editor, parent, graph, resource);\r
+               CodedComponent component = new CodedComponent(graph,resource);\r
+               PipeControlPoint cp = component.getControlPoint();\r
+               Plant3DResource p3r = ProcessResource.plant3Dresource;\r
+               controlPoint = cp.getResource();\r
+               \r
+               if (component.isInstanceOf(p3r.Elbow)) {\r
+                       type = Type.ELBOW;      \r
+               } else if (component.isInstanceOf(p3r.Straight)) {\r
+                       type = Type.STRAIGHT;\r
+               } else if (component.isInstanceOf(p3r.Elbow)) {\r
+                       type = Type.REDUCER;\r
+               }\r
+       \r
+       \r
+       }\r
+       \r
+       @Override\r
+       public Collection<RenderState> getMaterial() {\r
+               MaterialState ms = null;\r
+               ms = editor.getRenderingComponent().getDisplaySystem().getRenderer().createMaterialState();\r
+               ms.setEmissive(new ColorRGBA(0.f,0.f,0.f,0.f));\r
+       ms.setSpecular(new ColorRGBA(1.f,1.f,1.f,1.f));\r
+       ms.setEnabled(true);\r
+       ms.setShininess(128.f);\r
+       if (type == Type.ELBOW) {\r
+               ms.setDiffuse(new ColorRGBA(0.5f,0.5f,0.5f,0.f));\r
+               ms.setAmbient(new ColorRGBA(0.5f,0.5f,0.5f,0.f));\r
+       } else if (type == Type.STRAIGHT) {\r
+               ms.setDiffuse(new ColorRGBA(0.75f,0.75f,0.75f,0.f));\r
+               ms.setAmbient(new ColorRGBA(0.75f,0.75f,0.75f,0.f));\r
+       } else {\r
+               ms.setDiffuse(new ColorRGBA(0.6f,0.6f,0.6f,0.f));\r
+               ms.setAmbient(new ColorRGBA(0.6f,0.6f,0.6f,0.f));\r
+       } \r
+               List<RenderState> states = new ArrayList<RenderState>();\r
+               states.add(ms);\r
+               return states;\r
+       }\r
+       \r
+       \r
+       @Override\r
+       public void updateTransform(Graph graph) {\r
+               if (type == Type.REDUCER) {\r
+                       SizeChangeControlPoint sccp = new SizeChangeControlPoint(graph, controlPoint);\r
+                       Quat4d q = ControlPointTools.getControlPointLocalOrientationQuat(sccp, sccp.getRotationAngle()[0], true);\r
+                       update(q);\r
+               } \r
+               if (type != Type.STRAIGHT) {\r
+                       super.updateTransform(graph);\r
+               } else {\r
+                       transform.setLocalTranslation(0.f,0.f,0.f);\r
+                       transform.setLocalRotation(new Quaternion());\r
+               }\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/scenegraph/PipeRunNode.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/scenegraph/PipeRunNode.java
new file mode 100644 (file)
index 0000000..b03a36f
--- /dev/null
@@ -0,0 +1,29 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007 VTT Technical Research Centre of Finland and others.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package fi.vtt.simantics.processeditor.scenegraph;\r
+\r
+import org.simantics.db.Graph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.proconf.g3d.scenegraph.IGraphicsNode;\r
+import org.simantics.proconf.g3d.scenegraph.NonTransformableNode;\r
+\r
+import fi.vtt.simantics.processeditor.ProcessResource;\r
+\r
+public class PipeRunNode extends NonTransformableNode {\r
+\r
+    public PipeRunNode(IGraphicsNode parent, Graph graph, Resource resource) {\r
+        super(parent,resource);\r
+        if (!getG3DNode(graph).isInstanceOf(ProcessResource.plant3Dresource.PipeRun))\r
+                throw new RuntimeException("Resource must be instance of Pipeline");\r
+        \r
+    }\r
+\r
+}\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/scenegraph/PipelineComponentNode.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/scenegraph/PipelineComponentNode.java
new file mode 100644 (file)
index 0000000..07f20eb
--- /dev/null
@@ -0,0 +1,87 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007 VTT Technical Research Centre of Finland and others.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package fi.vtt.simantics.processeditor.scenegraph;\r
+\r
+import javax.vecmath.AxisAngle4d;\r
+\r
+import org.simantics.db.Graph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase;\r
+import org.simantics.proconf.g3d.scenegraph.IGraphicsNode;\r
+import org.simantics.proconf.g3d.scenegraph.ParameterizedModelNode;\r
+\r
+import fi.vtt.simantics.processeditor.ProcessResource;\r
+import fi.vtt.simantics.processeditor.common.ControlPointTools;\r
+import fi.vtt.simantics.processeditor.stubs.PipeControlPoint;\r
+import fi.vtt.simantics.processeditor.stubs.PipelineComponent;\r
+\r
+\r
+\r
+public class PipelineComponentNode extends ParameterizedModelNode {\r
+\r
+    boolean updating = false;\r
+    \r
+    public PipelineComponentNode(ThreeDimensionalEditorBase editor, IGraphicsNode parent, Graph graph, Resource resource) {\r
+        super(editor,parent,graph, resource, ProcessResource.plant3Dresource.HasGraphics);\r
+        PipelineComponent component = new PipelineComponent(graph, resource);\r
+        if(!component.isInstanceOf(ProcessResource.plant3Dresource.PipelineComponent))\r
+            throw new RuntimeException("Resource must be instance of Inline Component " + resource);\r
+        if (!(parent instanceof PipeRunNode))\r
+            throw new RuntimeException("Parent must be instance of PipelineNode " + parent.getResource() + " " + resource);\r
+\r
+        //PipeControlPoint pcp = component.getControlPoint();\r
+//        monitor = new StructuralChangeMonitor(\r
+//                new StructuralChangeListener[] { this }, pcp.getResource(), GlobalIdMap\r
+//                 .get(Layer0Mapping.HAS_PROPERTY));\r
+       updateTransform(graph);\r
+    }\r
+    \r
+//    public void handleUpdate(StructuralChangeMonitor monitor, GraphChangeEvent event) {\r
+//        if (updating)\r
+//            return;\r
+//        if (event.getParameter() instanceof InlineComponentNode)\r
+//            return;\r
+//        if (event.getTransactionId() == null)\r
+//            return;\r
+//        if (event.getParameter() instanceof AbstractGraphicsNode)\r
+//            return;\r
+//\r
+//        updating = true;\r
+//        updateTransform();\r
+//        updating = false;\r
+//    }\r
+    \r
+    public void updateTransform(Graph graph) {\r
+        super.updateTransform(graph);\r
+        /*\r
+        PipelineComponent component = new PipelineComponent(graph,shapeResource);\r
+    \r
+        PipeControlPoint pcp = component.getControlPoint();\r
+        Double angle = component.getAtMostOneRelatedScalarDouble(ProcessResource.plant3Dresource.HasRotationAngle);\r
+               double componentAngle = 0.0;\r
+               if (angle != null)\r
+                       componentAngle = angle;\r
+\r
+               AxisAngle4d aa = ControlPointTools.getControlPointRotation(pcp, componentAngle);\r
+               update(aa);\r
+               */\r
+       }\r
+    \r
+    \r
+    public void dispose() {\r
+        //monitor.dispose();\r
+        super.dispose();\r
+    }\r
+    \r
+\r
+    \r
+\r
+}
\ No newline at end of file
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/tools/ControlPointContribution.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/tools/ControlPointContribution.java
new file mode 100644 (file)
index 0000000..2f3dba8
--- /dev/null
@@ -0,0 +1,431 @@
+package fi.vtt.simantics.processeditor.tools;\r
+\r
+import java.io.ByteArrayInputStream;\r
+import java.io.ByteArrayOutputStream;\r
+import java.net.URL;\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.List;\r
+\r
+import javax.vecmath.AxisAngle4d;\r
+import javax.vecmath.Point3d;\r
+import javax.vecmath.Quat4d;\r
+import javax.vecmath.Vector3d;\r
+\r
+import org.eclipse.core.runtime.FileLocator;\r
+import org.eclipse.core.runtime.Path;\r
+import org.eclipse.jface.action.IMenuManager;\r
+import org.eclipse.jface.action.IToolBarManager;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.events.SelectionAdapter;\r
+import org.eclipse.swt.events.SelectionEvent;\r
+import org.eclipse.swt.layout.FormAttachment;\r
+import org.eclipse.swt.layout.FormData;\r
+import org.eclipse.swt.layout.FormLayout;\r
+import org.eclipse.swt.layout.GridLayout;\r
+import org.eclipse.swt.widgets.Button;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.simantics.db.Graph;\r
+import org.simantics.db.GraphRequestAdapter;\r
+import org.simantics.db.GraphRequestStatus;\r
+import org.simantics.db.Resource;\r
+import org.simantics.proconf.g3d.actions.ContextAction;\r
+import org.simantics.proconf.g3d.base.EditorContribution;\r
+import org.simantics.proconf.g3d.base.G3DTools;\r
+import org.simantics.proconf.g3d.base.MathTools;\r
+import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase;\r
+import org.simantics.proconf.g3d.base.VecmathJmeTools;\r
+import org.simantics.proconf.g3d.common.StructuredResourceSelection;\r
+import org.simantics.utils.ErrorLogger;\r
+\r
+import com.jme.renderer.ColorRGBA;\r
+import com.jme.scene.Geometry;\r
+import com.jme.scene.Node;\r
+import com.jme.scene.Spatial;\r
+import com.jme.scene.TriMesh;\r
+import com.jme.scene.shape.Sphere;\r
+import com.jme.scene.state.MaterialState;\r
+import com.jme.util.export.Savable;\r
+import com.jme.util.export.binary.BinaryImporter;\r
+import com.jmex.model.converters.ObjToJme;\r
+\r
+import fi.vtt.simantics.processeditor.Activator;\r
+import fi.vtt.simantics.processeditor.ProcessResource;\r
+import fi.vtt.simantics.processeditor.common.PipeComponentProvider;\r
+import fi.vtt.simantics.processeditor.stubs.DirectedControlPoint;\r
+import fi.vtt.simantics.processeditor.stubs.PipeControlPoint;\r
+\r
+public class ControlPointContribution implements EditorContribution {\r
+       private List<ContextAction> actions = new ArrayList<ContextAction>();\r
+       private ThreeDimensionalEditorBase parent;\r
+       private Resource componentResource;\r
+       private Resource controlPointResource;\r
+       \r
+       private Composite sideComposite;\r
+       \r
+       private double radius = 0.2;\r
+       private double radius2 = 0.1;\r
+       private double angle = Math.PI / 4.0;\r
+       \r
+       public ControlPointContribution(ThreeDimensionalEditorBase parent) {\r
+               this.parent = parent;\r
+       }\r
+       \r
+       @Override\r
+       public void createControl(Composite parent) {\r
+               FormLayout flayout = new FormLayout();\r
+               parent.setLayout(flayout);\r
+               sideComposite = new Composite(parent,SWT.BORDER);\r
+               FormData data = new FormData();\r
+               data.top = new FormAttachment(0, 0);\r
+               data.left = new FormAttachment(0, 0);\r
+               data.right = new FormAttachment(sideComposite, 0, SWT.LEFT);\r
+               data.bottom = new FormAttachment(100,0);\r
+               this.parent.getRenderingComposite().setLayoutData(data);\r
+               GridLayout layout = new GridLayout(1,false);\r
+               layout.marginHeight = 1;\r
+               layout.marginWidth = 1;\r
+               sideComposite.setLayout(layout);\r
+               data = new FormData();\r
+               data.top = new FormAttachment(0, 0);\r
+               data.bottom = new FormAttachment(100,0);\r
+               data.right = new FormAttachment(100,0);\r
+               sideComposite.setLayoutData(data);\r
+               \r
+               Button showCPButton = new Button(sideComposite,SWT.TOGGLE);\r
+               showCPButton.setText("Show CtrlPts");\r
+               showCPButton.addSelectionListener(new SelectionAdapter() {\r
+                       @Override\r
+                       public void widgetSelected(SelectionEvent e) {\r
+                               Button b = (Button)e.widget;\r
+                               showControlPoints(b.getSelection());\r
+                       }\r
+               });\r
+               \r
+               Button addCPButton = new Button(sideComposite,SWT.PUSH);\r
+               addCPButton.setText("Add CtrlPt");\r
+               addCPButton.addSelectionListener(new SelectionAdapter() {\r
+                       @Override\r
+                       public void widgetSelected(SelectionEvent e) {\r
+                               addControlPoint();\r
+                       }\r
+               });\r
+               \r
+               Button removeCPButton = new Button(sideComposite,SWT.PUSH);\r
+               removeCPButton.setText("Remove CtrlPt");\r
+               removeCPButton.addSelectionListener(new SelectionAdapter() {\r
+                       @Override\r
+                       public void widgetSelected(SelectionEvent e) {\r
+                               \r
+                       }\r
+               });\r
+               \r
+               Button showPipesButton = new Button(sideComposite,SWT.TOGGLE);\r
+               showPipesButton.setText("Pipes");\r
+               showPipesButton.addSelectionListener(new SelectionAdapter() {\r
+                       @Override\r
+                       public void widgetSelected(SelectionEvent e) {\r
+                               Button b = (Button)e.widget;\r
+                               showPipes(b.getSelection());\r
+                       }\r
+               });\r
+               \r
+               \r
+       }\r
+       \r
+       @Override\r
+       public void disposeControl() {\r
+               sideComposite.dispose();        \r
+       }\r
+       \r
+       @Override\r
+       public void fillContextMenu(Graph graph, IMenuManager manager,\r
+                       StructuredResourceSelection selection) {\r
+\r
+       }\r
+       \r
+       @Override\r
+       public void fillLocalPullDown(IMenuManager manager) {\r
+\r
+       }\r
+       \r
+       @Override\r
+       public void fillLocalToolBar(IToolBarManager manager) {\r
+\r
+       }\r
+       \r
+       @Override\r
+       public Collection<ContextAction> getActions() {\r
+               return actions;\r
+       }\r
+       \r
+       @Override\r
+       public String getName() {\r
+               return "Control Points";\r
+       }\r
+       \r
+       List<Node> pipes = new ArrayList<Node>();\r
+       List<Node> controlPoints = new ArrayList<Node>();\r
+       \r
+       private void showPipes(boolean show) {\r
+               if (show) {\r
+                       if (!pipes.isEmpty()) {\r
+                               for (Node n : pipes) {\r
+                                       n.removeFromParent();\r
+                                       n.dispose();\r
+                               }\r
+                               pipes.clear();\r
+                       }\r
+                       parent.getSession().asyncRead(new GraphRequestAdapter() {\r
+                               @Override\r
+                               public GraphRequestStatus perform(Graph g) throws Exception {\r
+                                       PipeControlPoint pcp = new PipeControlPoint(g,controlPointResource);\r
+                                       if (pcp.isInstanceOf(ProcessResource.plant3Dresource.EndComponentControlPoint)) {\r
+                                               Node n = new Node();\r
+                                               TriMesh mesh = new TriMesh();\r
+                                               Point3d p1 = new Point3d(-10.0,0.0,0.0);\r
+                                               Point3d p2 = new Point3d( 0.0,0.0,0.0);\r
+                                               PipeComponentProvider.createStraightGeometry(p1, p2, radius, new Geometry[]{mesh});\r
+                                               n.attachChild(mesh);\r
+                                               parent.getRenderingComponent().getShadowRoot().attachChild(n);\r
+                                               pipes.add(n);\r
+                                               \r
+                                       } else if (pcp.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)) {\r
+                                               \r
+                                               double length = 0.5;\r
+                                               Double d = pcp.getAtMostOneRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength);\r
+                                               if (d != null)\r
+                                                       length = d;\r
+                                               \r
+                                               double offset = 0.0;\r
+                                               d = pcp.getAtMostOneRelatedScalarDouble(ProcessResource.plant3Dresource.HasOffset);\r
+                                               if (d != null)\r
+                                                       offset = d;\r
+                                               \r
+                                               double r = radius;\r
+                                               if (pcp.isInstanceOf(ProcessResource.plant3Dresource.SizeChangeControlPoint)) {\r
+                                                       r = radius2;\r
+                                               }\r
+                                               \r
+                                               Node n = new Node();\r
+                                               TriMesh mesh = new TriMesh();\r
+                                               Point3d p1 = new Point3d(-10.0,0.0,0.0);\r
+                                               Point3d p2 = new Point3d( -length*0.5,0.0,0.0);\r
+                                               \r
+                                               PipeComponentProvider.createStraightGeometry(p1, p2, radius, new Geometry[]{mesh});\r
+                                               n.attachChild(mesh);\r
+                                               parent.getRenderingComponent().getShadowRoot().attachChild(n);\r
+                                               pipes.add(n);\r
+                                               \r
+                                               n = new Node();\r
+                                               mesh = new TriMesh();\r
+                                               p1 = new Point3d(10.0,offset,0.0);\r
+                                               p2 = new Point3d(length*0.5,offset,0.0);\r
+                                               \r
+                                               PipeComponentProvider.createStraightGeometry(p1, p2, r, new Geometry[]{mesh});\r
+                                               n.attachChild(mesh);\r
+                                               parent.getRenderingComponent().getShadowRoot().attachChild(n);\r
+                                               pipes.add(n);   \r
+                                               \r
+                                       } else if (pcp.isInstanceOf(ProcessResource.plant3Dresource.InlineControlPoint)) {\r
+                                               double length = 0.5;\r
+                                               Double d = pcp.getAtMostOneRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength);\r
+                                               if (d != null)\r
+                                                       length = d;\r
+                                               \r
+                                               Node n = new Node();\r
+                                               TriMesh mesh = new TriMesh();\r
+                                               Point3d p1 = new Point3d(-10.0,0.0,0.0);\r
+                                               Point3d p2 = new Point3d( -length*0.5,0.0,0.0);\r
+                                               \r
+                                               PipeComponentProvider.createStraightGeometry(p1, p2, radius, new Geometry[]{mesh});\r
+                                               n.attachChild(mesh);\r
+                                               parent.getRenderingComponent().getShadowRoot().attachChild(n);\r
+                                               pipes.add(n);\r
+                                               \r
+                                               n = new Node();\r
+                                               mesh = new TriMesh();\r
+                                               p1 = new Point3d(10.0,0.0,0.0);\r
+                                               p2 = new Point3d(length*0.5,0.0,0.0);\r
+                                               \r
+                                               PipeComponentProvider.createStraightGeometry(p1, p2, radius, new Geometry[]{mesh});\r
+                                               n.attachChild(mesh);\r
+                                               parent.getRenderingComponent().getShadowRoot().attachChild(n);\r
+                                               pipes.add(n);\r
+                                       } else if (pcp.isInstanceOf(ProcessResource.plant3Dresource.TurnControlPoint)) {\r
+                                               double length = 0.5;\r
+                                               Double d = pcp.getAtMostOneRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength);\r
+                                               if (d != null)\r
+                                                       length = d;\r
+                                               \r
+                                               Node n = new Node();\r
+                                               TriMesh mesh = new TriMesh();\r
+                                               Point3d p1 = new Point3d(-10.0,0.0,0.0);\r
+                                               Point3d p2 = new Point3d( -length*0.5,0.0,0.0);\r
+                                               \r
+                                               PipeComponentProvider.createStraightGeometry(p1, p2, radius, new Geometry[]{mesh});\r
+                                               n.attachChild(mesh);\r
+                                               parent.getRenderingComponent().getShadowRoot().attachChild(n);\r
+                                               pipes.add(n);\r
+                                               \r
+                                               n = new Node();\r
+                                               mesh = new TriMesh();\r
+                                               p1 = new Point3d(10.0,0.0,0.0);\r
+                                               p2 = new Point3d(length*0.5,0.0,0.0);\r
+                                               Quat4d q = new Quat4d();\r
+                                               q.set(new AxisAngle4d(0.0,1.0,0.0,angle));\r
+                                               MathTools.rotate(q, p1, p1);\r
+                                               MathTools.rotate(q, p2, p2);\r
+\r
+                                               PipeComponentProvider.createStraightGeometry(p1, p2, radius, new Geometry[]{mesh});\r
+                                               n.attachChild(mesh);\r
+                                               parent.getRenderingComponent().getShadowRoot().attachChild(n);\r
+                                               pipes.add(n);\r
+                                       } else if (pcp.isInstanceOf(ProcessResource.plant3Dresource.DirectedControlPoint)) {\r
+                                               Node n = new Node();\r
+                                               TriMesh mesh = new TriMesh();\r
+                                               Point3d p1 = new Point3d(10.0,0.0,0.0);\r
+                                               Point3d p2 = new Point3d( 0.0,0.0,0.0);\r
+                                               PipeComponentProvider.createStraightGeometry(p1, p2, radius, new Geometry[]{mesh});\r
+                                               n.attachChild(mesh);\r
+                                               parent.getRenderingComponent().getShadowRoot().attachChild(n);\r
+                                               pipes.add(n);\r
+                                       }\r
+                                       \r
+                                       if(!pcp.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)) {\r
+                                               Collection<PipeControlPoint> subPoints = pcp.getSubPoint();\r
+                                               \r
+                                       }\r
+                                       \r
+                                       parent.setViewChanged(true);\r
+                                       return GraphRequestStatus.transactionComplete();\r
+                               }\r
+                       });\r
+               } else {\r
+                       if (!pipes.isEmpty()) {\r
+                               for (Node n : pipes) {\r
+                                       n.removeFromParent();\r
+                                       n.dispose();\r
+                               }\r
+                               pipes.clear();\r
+                               parent.setViewChanged(true);\r
+                       }\r
+               }\r
+       }\r
+       \r
+       private void showControlPoints(boolean show) {\r
+               if (show) {\r
+                       if (!controlPoints.isEmpty()) {\r
+                               for (Node n : controlPoints) {\r
+                                       n.removeFromParent();\r
+                                       n.dispose();\r
+                               }\r
+                                       \r
+                       }\r
+                       parent.getSession().asyncRead(new GraphRequestAdapter() {\r
+                               @Override\r
+                               public GraphRequestStatus perform(Graph g) throws Exception {\r
+                                       \r
+                                       PipeControlPoint pcp = new PipeControlPoint(g,controlPointResource);\r
+                                       Vector3d p = G3DTools.getVector(pcp.getWorldPosition());\r
+                                       Node n = new Node();\r
+                                       Spatial sphere = new Sphere("",5,8,0.1f);\r
+                                       n.attachChild(sphere);\r
+                                       n.setLocalTranslation(VecmathJmeTools.get(p));\r
+                                       MaterialState ms = parent.getRenderingComponent().getDisplaySystem().getRenderer().createMaterialState();\r
+                                       ms.setDiffuse(new ColorRGBA(1.f,0.f,0.f,0.f));\r
+                                       sphere.setRenderState(ms);\r
+                                       sphere.setName(Long.toString(pcp.getResource().getResourceId()));\r
+                                       parent.getRenderingComponent().getNoShadowRoot().attachChild(n);\r
+                                       controlPoints.add(n);\r
+                                       Collection<PipeControlPoint> subPoints = pcp.getSubPoint();\r
+                                       ms = parent.getRenderingComponent().getDisplaySystem().getRenderer().createMaterialState();\r
+                                       ms.setDiffuse(new ColorRGBA(0.f,1.f,0.f,0.f));\r
+                                       for (PipeControlPoint cp : subPoints) {\r
+                                               p = G3DTools.getVector(cp.getWorldPosition());\r
+                                               n = new Node();\r
+                                               if (cp.isInstanceOf(ProcessResource.plant3Dresource.DirectedControlPoint)) {\r
+                                                       sphere = getDCPMesh();\r
+                                                       if (sphere == null)\r
+                                                               sphere = new Sphere("",5,8,0.1f);\r
+                                               } else {\r
+                                                       sphere = new Sphere("",5,8,0.1f);\r
+                                               }\r
+                                               sphere.setName(Long.toString(cp.getResource().getResourceId()));\r
+                                               n.attachChild(sphere);\r
+                                               n.setLocalTranslation(VecmathJmeTools.get(p));\r
+                                               sphere.setRenderState(ms);\r
+                                               parent.getRenderingComponent().getNoShadowRoot().attachChild(n);\r
+                                               controlPoints.add(n);\r
+                                       }\r
+                                       parent.setViewChanged(true);\r
+                                       return GraphRequestStatus.transactionComplete();\r
+                               }\r
+                       });\r
+               } else {\r
+                       if (!controlPoints.isEmpty()) {\r
+                               for (Node n : controlPoints) {\r
+                                       n.removeFromParent();\r
+                                       n.dispose();\r
+                               }\r
+                               parent.setViewChanged(true);\r
+                       }\r
+               }\r
+       }\r
+       \r
+       @Override\r
+       public void initialize(Graph graph) {\r
+               Resource modelResource = parent.getInputResource();\r
+               Resource inverse = graph.getInverse(ProcessResource.plant3Dresource.HasGraphics);\r
+               Collection<Resource> equipment = graph.getObjects(modelResource, inverse);\r
+               if (equipment.size() != 1)\r
+                       throw new RuntimeException("Cannot find component for model " + modelResource);\r
+               componentResource = equipment.iterator().next();\r
+               Collection<Resource> pcp = graph.getObjects(componentResource, ProcessResource.plant3Dresource.HasControlPoint);\r
+               if (pcp.size() != 1)\r
+                       throw new RuntimeException("Cannot find control point for component " + componentResource);\r
+               controlPointResource = pcp.iterator().next();\r
+       }\r
+       \r
+       @Override\r
+       public void dispose() {\r
+               \r
+       }\r
+       \r
+       @Override\r
+       public void run() {\r
+\r
+       }\r
+       \r
+       private void addControlPoint() {\r
+               parent.getSession().asyncWrite(new GraphRequestAdapter() {\r
+                       @Override\r
+                       public GraphRequestStatus perform(Graph g) throws Exception {\r
+                               DirectedControlPoint dcp = DirectedControlPoint.createDefault(g);\r
+                               PipeControlPoint pcp = new PipeControlPoint(g,controlPointResource);\r
+                               pcp.addStatement(ProcessResource.plant3Dresource.HasSubPoint, dcp);\r
+                               return GraphRequestStatus.transactionComplete();\r
+                       }\r
+               });\r
+       }\r
+       \r
+       private Spatial getDCPMesh() {\r
+               try {\r
+                       ObjToJme converter=new ObjToJme();\r
+                       String file = "data/dcp.obj";\r
+                       URL objFile=FileLocator.find(Activator.getDefault().getBundle(),new Path(file),null);\r
+                       converter.setProperty("mtllib",objFile);\r
+                       ByteArrayOutputStream BO=new ByteArrayOutputStream();\r
+                       //System.out.println("Starting to convert .obj to .jme");\r
+                       converter.convert(objFile.openStream(),BO);\r
+        \r
+                       Savable s = BinaryImporter.getInstance().load(new ByteArrayInputStream(BO.toByteArray()));\r
+                       return (Spatial)s;\r
+               } catch (Exception e) {\r
+                       ErrorLogger.defaultLogError(e);\r
+                       return null;\r
+               }\r
+       }\r
+       \r
+       \r
+}\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/tools/NozzleContribution.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/tools/NozzleContribution.java
new file mode 100644 (file)
index 0000000..91f65ba
--- /dev/null
@@ -0,0 +1,129 @@
+package fi.vtt.simantics.processeditor.tools;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.List;\r
+\r
+import org.eclipse.jface.action.Action;\r
+import org.eclipse.jface.action.IContributionItem;\r
+import org.eclipse.jface.action.IMenuManager;\r
+import org.eclipse.jface.action.IToolBarManager;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.layout.FillLayout;\r
+import org.eclipse.swt.layout.FormAttachment;\r
+import org.eclipse.swt.layout.FormData;\r
+import org.eclipse.swt.layout.FormLayout;\r
+import org.eclipse.swt.widgets.Button;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.swt.widgets.Label;\r
+import org.eclipse.swt.widgets.Text;\r
+import org.simantics.db.Graph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.proconf.g3d.actions.ContextAction;\r
+import org.simantics.proconf.g3d.base.EditorContribution;\r
+import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase;\r
+import org.simantics.proconf.g3d.common.StructuredResourceSelection;\r
+\r
+import fi.vtt.simantics.processeditor.ProcessResource;\r
+\r
+public class NozzleContribution implements EditorContribution {\r
+       private List<ContextAction> actions = new ArrayList<ContextAction>();\r
+       private ThreeDimensionalEditorBase parent;\r
+       private Resource equipmentResource;\r
+       private Composite sideComposite;\r
+       \r
+       public NozzleContribution(ThreeDimensionalEditorBase parent) {\r
+               this.parent = parent;\r
+       }\r
+       \r
+       @Override\r
+       public void createControl(Composite parent) {\r
+               FormLayout flayout = new FormLayout();\r
+               parent.setLayout(flayout);\r
+               sideComposite = new Composite(parent,SWT.BORDER);\r
+               FormData data = new FormData();\r
+               data.top = new FormAttachment(0, 0);\r
+               data.left = new FormAttachment(0, 0);\r
+               data.right = new FormAttachment(sideComposite, 0, SWT.LEFT);\r
+               data.bottom = new FormAttachment(100,0);\r
+               this.parent.getRenderingComposite().setLayoutData(data);\r
+               sideComposite.setLayout(new FillLayout(SWT.VERTICAL));\r
+               data = new FormData();\r
+               data.top = new FormAttachment(0, 0);\r
+               data.bottom = new FormAttachment(100,0);\r
+               data.right = new FormAttachment(100,0);\r
+               sideComposite.setLayoutData(data);\r
+               showNozzles(true);\r
+               \r
+               Button addButton = new Button(sideComposite,SWT.PUSH);\r
+               addButton.setText("Add Nozzle");\r
+               Label label = new Label(sideComposite,SWT.NONE);\r
+               label.setText("Restrictions:");\r
+               Button minButton = new Button(sideComposite,SWT.CHECK);\r
+               minButton.setText("Min");\r
+               Text minText = new Text(sideComposite,SWT.SINGLE | SWT.BORDER);\r
+               Button maxButton = new Button(sideComposite,SWT.CHECK);\r
+               maxButton.setText("Max");\r
+               Text maxText = new Text(sideComposite,SWT.SINGLE | SWT.BORDER);\r
+               minText.setToolTipText("Enter minimum number of nozzles");\r
+               maxText.setToolTipText("Enter maximum number of nozzles");\r
+\r
+       }\r
+       \r
+       @Override\r
+       public void disposeControl() {\r
+               sideComposite.dispose();\r
+               \r
+       }\r
+       @Override\r
+       public void fillContextMenu(Graph graph, IMenuManager manager,\r
+                       StructuredResourceSelection selection) {\r
+\r
+       }\r
+       \r
+       @Override\r
+       public void fillLocalPullDown(IMenuManager manager) {\r
+\r
+       }\r
+       \r
+       @Override\r
+       public void fillLocalToolBar(IToolBarManager manager) {\r
+\r
+       }\r
+       \r
+       @Override\r
+       public Collection<ContextAction> getActions() {\r
+               return actions;\r
+       }\r
+       \r
+       @Override\r
+       public String getName() {\r
+               return "Nozzles";\r
+       }\r
+       \r
+       private void showNozzles(boolean show) {\r
+               \r
+       }\r
+       \r
+       @Override\r
+       public void initialize(Graph graph) {\r
+               Resource modelResource = parent.getInputResource();\r
+               Resource inverse = graph.getInverse(ProcessResource.plant3Dresource.HasGraphics);\r
+               Collection<Resource> equipment = graph.getObjects(modelResource, inverse);\r
+               if (equipment.size() != 1)\r
+                       throw new RuntimeException("Cannot find equipment");\r
+               equipmentResource = equipment.iterator().next();\r
+       }\r
+       \r
+       @Override\r
+       public void dispose() {\r
+               showNozzles(false);\r
+       }\r
+       \r
+       @Override\r
+       public void run() {\r
+\r
+       }\r
+       \r
+       \r
+}\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/tools/PlantEditContribution.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/tools/PlantEditContribution.java
new file mode 100644 (file)
index 0000000..e411131
--- /dev/null
@@ -0,0 +1,330 @@
+package fi.vtt.simantics.processeditor.tools;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.Iterator;\r
+import java.util.List;\r
+\r
+import org.eclipse.jface.action.Action;\r
+import org.eclipse.jface.action.IMenuManager;\r
+import org.eclipse.jface.action.IToolBarManager;\r
+import org.eclipse.jface.dialogs.MessageDialog;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.layout.FormAttachment;\r
+import org.eclipse.swt.layout.FormData;\r
+import org.eclipse.swt.layout.FormLayout;\r
+import org.eclipse.swt.layout.GridData;\r
+import org.eclipse.swt.layout.GridLayout;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.swt.widgets.Text;\r
+import org.simantics.db.Graph;\r
+import org.simantics.db.GraphRequestStatus;\r
+import org.simantics.db.Resource;\r
+import org.simantics.layer0.utils.EntityFactory;\r
+import org.simantics.layer0.utils.IEntity;\r
+import org.simantics.proconf.g3d.actions.ContextAction;\r
+import org.simantics.proconf.g3d.actions.FocusAction;\r
+import org.simantics.proconf.g3d.actions.RemoveAction;\r
+import org.simantics.proconf.g3d.actions.RotateAction;\r
+import org.simantics.proconf.g3d.actions.TranslateAction;\r
+import org.simantics.proconf.g3d.base.EditorContribution;\r
+import org.simantics.proconf.g3d.common.StructuredResourceSelection;\r
+import org.simantics.utils.ui.jface.MenuTools;\r
+\r
+import com.jme.intersection.CollisionData;\r
+import com.jme.intersection.CollisionResults;\r
+import com.jme.intersection.TriangleCollisionResults;\r
+import com.jme.scene.Geometry;\r
+import com.jme.scene.Node;\r
+import com.jme.scene.Spatial;\r
+\r
+import fi.vtt.simantics.processeditor.Activator;\r
+import fi.vtt.simantics.processeditor.ProcessResource;\r
+import fi.vtt.simantics.processeditor.actions.InsertComponentAction;\r
+import fi.vtt.simantics.processeditor.actions.InsertEquipmentAction;\r
+import fi.vtt.simantics.processeditor.actions.InsertNozzleAction;\r
+import fi.vtt.simantics.processeditor.actions.ReversePipelineAction;\r
+import fi.vtt.simantics.processeditor.actions.RoutePipeAction;\r
+import fi.vtt.simantics.processeditor.actions.TranslateElbowAction;\r
+import fi.vtt.simantics.processeditor.actions.TranslateInlineComponentAction;\r
+import fi.vtt.simantics.processeditor.actions.TranslateStraightAction;\r
+import fi.vtt.simantics.processeditor.common.ControlPointTools;\r
+import fi.vtt.simantics.processeditor.stubs.InlineComponent;\r
+import fi.vtt.simantics.processeditor.stubs.PipeControlPoint;\r
+import fi.vtt.simantics.processeditor.views.ProcessEditor;\r
+\r
+public class PlantEditContribution implements EditorContribution {\r
+       private List<ContextAction> actions = new ArrayList<ContextAction>();\r
+       private ProcessEditor parent;\r
+       private Composite infoComposite;\r
+       private Text infoText;\r
+       \r
+       private Action checkInterferencesAction = null;\r
+       \r
+       public PlantEditContribution(ProcessEditor parent) {\r
+               this.parent = parent;\r
+       }\r
+       \r
+       @Override\r
+       public void createControl(Composite parent) {\r
+               FormLayout flayout = new FormLayout();\r
+               parent.setLayout(flayout);\r
+               infoComposite = new Composite(parent, SWT.BORDER);\r
+               FormData data = new FormData();\r
+               data.top = new FormAttachment(0, 0);\r
+               data.left = new FormAttachment(0, 0);\r
+               data.right = new FormAttachment(100, 0);\r
+               data.bottom = new FormAttachment(infoComposite, 0, SWT.TOP);\r
+               this.parent.getRenderingComposite().setLayoutData(data);\r
+               data = new FormData();\r
+               data.left = new FormAttachment(0, 0);\r
+               data.right = new FormAttachment(100, 0);\r
+               data.bottom = new FormAttachment(100, 0);\r
+               data.height = 18;\r
+               infoComposite.setLayoutData(data);\r
+               GridLayout layout = new GridLayout(1,false);\r
+               layout.marginWidth = 1;\r
+               layout.marginHeight = 1;\r
+               infoComposite.setLayout(layout);\r
+               infoText = new Text(infoComposite, SWT.NONE);\r
+               GridData gdata = new GridData();\r
+               gdata.grabExcessHorizontalSpace = true;\r
+               gdata.horizontalAlignment = SWT.FILL;\r
+               infoText.setLayoutData(gdata);\r
+               \r
+       }\r
+       \r
+       @Override\r
+       public void disposeControl() {\r
+               infoComposite.dispose();\r
+               \r
+       }\r
+       \r
+       @Override\r
+       public void dispose() {\r
+\r
+       }\r
+       \r
+       \r
+       \r
+       @Override\r
+       public void fillContextMenu(Graph graph, IMenuManager manager,\r
+                       StructuredResourceSelection selection) {\r
+\r
+       }\r
+       \r
+       @Override\r
+       public void fillLocalPullDown(IMenuManager manager) {\r
+               MenuTools.getOrCreate(parent.getMenuID(),"Advanced", manager).add(checkInterferencesAction);\r
+               \r
+       }\r
+       \r
+       @Override\r
+       public void fillLocalToolBar(IToolBarManager manager) {\r
+\r
+       }\r
+       \r
+       @Override\r
+       public Collection<ContextAction> getActions() {\r
+               return actions;\r
+       }\r
+       \r
+       @Override\r
+       public String getName() {\r
+               return "Plant Editing";\r
+       }\r
+       \r
+       @Override\r
+       public void initialize(Graph graph) {\r
+               actions.add(new TranslateAction(parent){\r
+            @Override\r
+            public boolean usable(Graph graph,List<Resource> resources) {\r
+                if (super.usable(graph, resources)) {\r
+                    for (Resource r : resources) {\r
+                       // FIXME : use new ontology :\r
+                       // 1. lose ends works like end components (just what this code does, but type checks are not correct)\r
+                       // 2. connected components are moved inline. (TranslateInlineAction)\r
+                       IEntity t = EntityFactory.create(graph, r);\r
+                        if (t.isInstanceOf(ProcessResource.plant3Dresource.InlineComponent)) {\r
+                            InlineComponent component = new InlineComponent(t);\r
+                               PipeControlPoint pcp = component.getControlPoint();\r
+                               if (pcp.getNext() != null && pcp.getPrevious() != null)\r
+                                       return false;\r
+                        }\r
+                    }\r
+                    return true;\r
+                }\r
+                return false;\r
+            }\r
+            \r
+            @Override\r
+            public void setInfoText(String text) {\r
+               infoText.setText(text);\r
+            }\r
+        });\r
+        actions.add(new TranslateInlineComponentAction(parent) {\r
+               @Override\r
+               public void setInfoText(String text) {\r
+                       infoText.setText(text);\r
+               }\r
+        });\r
+        actions.add(new TranslateStraightAction(parent) {\r
+               @Override\r
+               public void setInfoText(String text) {\r
+                       infoText.setText(text);\r
+               }\r
+        });\r
+        actions.add(new TranslateElbowAction(parent) {\r
+               @Override\r
+               public void setInfoText(String text) {\r
+                       infoText.setText(text);\r
+               }\r
+        });\r
+        actions.add(new RotateAction(parent){\r
+            @Override\r
+            public boolean usable(Graph graph,List<Resource> resources) {\r
+                if (super.usable(graph,resources)) {\r
+                    for (Resource r : resources) {\r
+                       IEntity t = EntityFactory.create(graph,r);\r
+                       // FIXME : use new ontology\r
+                       // TODO : create rotate action that can rotate inline components\r
+                       // TODO : ontology change: pipes and similar components cannot be rotated, since there is no point to do that.\r
+                       if (t.isInstanceOf(ProcessResource.plant3Dresource.InlineComponent)) {\r
+                               return false;\r
+                       }\r
+                    }\r
+                    return true;\r
+                }\r
+                \r
+                return false;\r
+            }\r
+            \r
+            @Override\r
+            public void setInfoText(String text) {\r
+               infoText.setText(text);\r
+            }\r
+        });\r
+        actions.add(new RemoveAction(parent) {\r
+               @Override\r
+                       public GraphRequestStatus doChanges(Graph graph) {\r
+                               Iterator<Resource> i = parent.getSelectionAdapter().getCurrentSelection().iterator();\r
+                               while (i.hasNext()) {\r
+                                               Resource s = i.next();\r
+                                               IEntity r = EntityFactory.create(graph, s);\r
+                                               if (r.isInstanceOf(ProcessResource.g3dResource.G3DNode)) {\r
+                                                       Collection<IEntity> parentNode= r.getRelatedObjects(ProcessResource.g3dResource.HasParent);\r
+                                                       if (parentNode.size() == 1) {\r
+                                                               Collection<IEntity> rs = r.getRelatedObjects(ProcessResource.plant3Dresource.HasControlPoint);\r
+                                                               for (IEntity cp  : rs) {\r
+                                                                       ControlPointTools.removeControlPoint(new PipeControlPoint(cp));\r
+                                                               }\r
+                                                               r.removeRelatedStatements(ProcessResource.g3dResource.HasParent);\r
+                                                       } else {\r
+                                                               if (parentNode.size() == 0) {\r
+                                                                       parent.showMessage("Object has no parent, don't know what to do!");\r
+                                                               } else {\r
+                                                                       parent.showMessage("Object has more than one parent, don't know what to do!");\r
+                                                               }\r
+                                                       }\r
+                                               }\r
+\r
+                                       }\r
+                                       //parent.getSelectionAdapter().setSelection(new StructuredResourceSelection());\r
+                               return GraphRequestStatus.transactionComplete();\r
+                       }\r
+               });\r
+        actions.add(new FocusAction(parent));\r
+        actions.add(new RoutePipeAction(parent){\r
+               @Override\r
+               public void setInfoText(String text) {\r
+                       infoText.setText(text);\r
+               }\r
+        });   \r
+        actions.add(new InsertComponentAction(parent));\r
+        actions.add(new InsertEquipmentAction(parent));\r
+        actions.add(new InsertNozzleAction(parent));\r
+        actions.add(new ReversePipelineAction(parent));\r
+        \r
+        checkInterferencesAction = new Action() {\r
+               public void run() {\r
+                       CollisionResults results = new TriangleCollisionResults();\r
+                       //getRenderingComponent().getNormalRoot().calculateCollisions(getRenderingComponent().getNormalRoot(), results);\r
+                       collide(parent.getRenderingComponent().getShadowRoot(),parent.getRenderingComponent().getShadowRoot(),results);\r
+                       results = filterResults(results);\r
+                       for (int i = 0; i < results.getNumber(); i++) {\r
+                               CollisionData data = results.getCollisionData(i);\r
+                               Geometry s =  data.getSourceMesh();\r
+                               Geometry t = data.getTargetMesh();\r
+                               MessageDialog dialog = new MessageDialog(parent.getRenderingComposite().getShell(),"Interference " + i + " / " + results.getNumber(), null, "Interference between " + s + " and " + t,MessageDialog.WARNING,new String[]{"Next","Cancel"},0);\r
+                               try {\r
+                                       Resource sid = parent.getScenegraphAdapter().getNodeResource(s.getName());\r
+                                       Resource tid = parent.getScenegraphAdapter().getNodeResource(t.getName());\r
+\r
+                                       StructuredResourceSelection sel = new StructuredResourceSelection();\r
+                                       if (sid == tid) {\r
+                                               sel.add(sid);\r
+                                       } else {\r
+                                               sel.add(sid);\r
+                                               sel.add(tid);\r
+                                       }\r
+                                       parent.getSelectionAdapter().setSelection(sel);\r
+                               } catch(NumberFormatException e) {\r
+                                       \r
+                               }\r
+                               if (dialog.open() == 1)\r
+                                       break;\r
+                       }\r
+               }\r
+               \r
+               private void collide(Spatial s, Spatial p, CollisionResults r) {\r
+                       s.calculateCollisions(p, r);\r
+                       if (s instanceof Node) {\r
+                               Node n = (Node)s;\r
+                               for (Spatial t : n.getChildren())\r
+                                       collide(t,p,r);\r
+                       }\r
+               }\r
+               \r
+               private CollisionResults filterResults(CollisionResults results) {\r
+                       CollisionResults r = new TriangleCollisionResults();\r
+                       for (int i = 0; i < results.getNumber(); i++) {\r
+                               CollisionData d = results.getCollisionData(i);\r
+                               if (d.getSourceMesh() == d.getTargetMesh())\r
+                                       continue;\r
+                               boolean found = false;\r
+                               for (int j = 0; j < r.getNumber(); j++) {\r
+                                       CollisionData d2 = r.getCollisionData(j);\r
+                                       if (d2.getSourceMesh() == d.getSourceMesh() &&\r
+                                               d2.getTargetMesh() == d.getTargetMesh()) {\r
+                                               found = true;\r
+                                               break;\r
+                                       }\r
+                                       if (d2.getSourceMesh() == d.getTargetMesh() &&\r
+                                       d2.getTargetMesh() == d.getSourceMesh()) {\r
+                                       found = true;\r
+                                       break;\r
+                               }               \r
+                               }\r
+                               if (!found) {\r
+                                       if (d.getSourceTris().size() == 0)\r
+                                               continue;\r
+                                       if (d.getTargetTris().size() == 0)\r
+                                               continue;\r
+                                       r.addCollisionData(d);\r
+                               }\r
+                       }\r
+                       return r;\r
+               }\r
+\r
+        };\r
+        checkInterferencesAction.setText("Interferences");\r
+        checkInterferencesAction.setImageDescriptor(Activator.imageDescriptorFromPlugin("fi.vtt.proconf.ode", "icons/silk/delete.png"));\r
+        \r
+       }\r
+       \r
+       @Override\r
+       public void run() {\r
+               \r
+       }\r
+\r
+}\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/tools/PlantVisualizationContribution.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/tools/PlantVisualizationContribution.java
new file mode 100644 (file)
index 0000000..42b93f0
--- /dev/null
@@ -0,0 +1,376 @@
+package fi.vtt.simantics.processeditor.tools;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.List;\r
+import java.util.Stack;\r
+\r
+import org.eclipse.jface.action.Action;\r
+import org.eclipse.jface.action.IMenuManager;\r
+import org.eclipse.jface.action.IToolBarManager;\r
+import org.eclipse.swt.layout.FillLayout;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.simantics.db.Graph;\r
+import org.simantics.db.GraphRequestAdapter;\r
+import org.simantics.db.GraphRequestStatus;\r
+import org.simantics.db.Resource;\r
+import org.simantics.proconf.g3d.actions.ContextAction;\r
+import org.simantics.proconf.g3d.actions.FocusAction;\r
+import org.simantics.proconf.g3d.animation.Animatable;\r
+import org.simantics.proconf.g3d.animation.AnimationController;\r
+import org.simantics.proconf.g3d.animation.AnimationSystem;\r
+import org.simantics.proconf.g3d.animation.TestAnimationController;\r
+import org.simantics.proconf.g3d.animation.ui.AnimationControlCreator;\r
+import org.simantics.proconf.g3d.base.EditorContribution;\r
+import org.simantics.proconf.g3d.common.StructuredResourceSelection;\r
+import org.simantics.proconf.g3d.scenegraph.IGraphicsNode;\r
+import org.simantics.proconf.g3d.stubs.G3DNode;\r
+import org.simantics.utils.ui.jface.MenuTools;\r
+\r
+import fi.vtt.simantics.processeditor.Activator;\r
+import fi.vtt.simantics.processeditor.ProcessResource;\r
+import fi.vtt.simantics.processeditor.animations.PipeAnimationController;\r
+import fi.vtt.simantics.processeditor.dialogs.ConfigureAnimationDialog;\r
+import fi.vtt.simantics.processeditor.dialogs.ConfigureMonitorDialog;\r
+import fi.vtt.simantics.processeditor.dialogs.ConfigurePipelineAnimationDialog;\r
+import fi.vtt.simantics.processeditor.monitors.Monitor;\r
+import fi.vtt.simantics.processeditor.monitors.ResourcePathPropertyProvider;\r
+import fi.vtt.simantics.processeditor.monitors.TextMonitor;\r
+import fi.vtt.simantics.processeditor.stubs.PipeRun;\r
+import fi.vtt.simantics.processeditor.views.ProcessEditor;\r
+\r
+public class PlantVisualizationContribution implements EditorContribution {\r
+       private List<ContextAction> actions = new ArrayList<ContextAction>();\r
+       private ProcessEditor parent;\r
+       \r
+    private AnimationSystem animationSystem = null;\r
+    private Action animatePipesAction = null;\r
+    private Action animateAction = null;\r
+    private Action showMonitorsAction = null;\r
+    private Action configureAnimationAction = null;\r
+    private Action configurePipelineAnimationAction = null;\r
+    private Action configureMonitorAction = null;\r
+    \r
+    private Monitor monitor;\r
+       \r
+       public PlantVisualizationContribution(ProcessEditor parent) {\r
+               this.parent = parent;\r
+       }\r
+       \r
+       @Override\r
+       public void createControl(Composite parent) {\r
+               parent.setLayout(new FillLayout());\r
+               this.parent.getRenderingComposite().setLayoutData(null);\r
+       }\r
+       \r
+       @Override\r
+       public void disposeControl() {\r
+               \r
+       }\r
+       \r
+       @Override\r
+       public void dispose() {\r
+               \r
+       }\r
+       \r
+       @Override\r
+       public void fillContextMenu(Graph graph, IMenuManager manager,\r
+                       StructuredResourceSelection selection) {\r
+               \r
+       }\r
+       \r
+       @Override\r
+       public void fillLocalPullDown(IMenuManager menuManager) {\r
+               MenuTools.getOrCreate(parent.getMenuID(),"Monitors", menuManager).add(showMonitorsAction);\r
+       MenuTools.getOrCreate(parent.getMenuID(),"Monitors", menuManager).add(configureMonitorAction);\r
+       IMenuManager animationMenu = MenuTools.getOrCreate(parent.getMenuID(),"Animations",menuManager);\r
+       animationMenu.add(configureAnimationAction);\r
+       animationMenu.add(configurePipelineAnimationAction);\r
+       MenuTools.getOrCreate(parent.getMenuID(),"Test", animationMenu).add(animateAction);\r
+       MenuTools.getOrCreate(parent.getMenuID(),"Test", animationMenu).add(animatePipesAction);\r
+               \r
+       }\r
+       \r
+//     @Override\r
+//     public void fillMainMenu(List<IContributionItem> list) {\r
+//             MenuTools.getOrCreate("Monitors", list).add(showMonitorsAction);\r
+//     MenuTools.getOrCreate("Monitors", list).add(configureMonitorAction);\r
+//     IMenuManager animationMenu = MenuTools.getOrCreate("Animations",list);\r
+//     animationMenu.add(configureAnimationAction);\r
+//     animationMenu.add(configurePipelineAnimationAction);\r
+//     MenuTools.getOrCreate("Test", animationMenu).add(animateAction);\r
+//     MenuTools.getOrCreate("Test", animationMenu).add(animatePipesAction);\r
+//             \r
+//     }\r
+       \r
+       @Override\r
+       public void fillLocalToolBar(IToolBarManager manager) {\r
+               AnimationControlCreator c = new AnimationControlCreator(getAnimationSystem());\r
+        manager.add(c.createStopAction());\r
+        manager.add(c.createPauseAction());\r
+        manager.add(c.createPlayAction());\r
+               manager.add(showMonitorsAction);\r
+       }\r
+       \r
+       @Override\r
+       public Collection<ContextAction> getActions() {\r
+               return actions;\r
+       }\r
+       \r
+       @Override\r
+       public String getName() {\r
+               return "Plant Visualization";\r
+       }\r
+       \r
+       @Override\r
+       public void run() {\r
+               parent.getSession().syncRead(new GraphRequestAdapter() {\r
+                       @Override\r
+                       public GraphRequestStatus perform(Graph g) throws Exception {\r
+                               getAnimationSystem().run(g,0.01);\r
+                               updateMonitor(g);\r
+                               return GraphRequestStatus.transactionComplete();\r
+                       }\r
+               });\r
+               \r
+               \r
+       }\r
+       \r
+       @Override\r
+       public void initialize(Graph graph) {\r
+                animateAction = new Action("", Action.AS_CHECK_BOX) {\r
+                   public void run() {\r
+                       if (this.isChecked()) {\r
+                               parent.getSession().asyncRead(new GraphRequestAdapter() {\r
+                                       @Override\r
+                                       public GraphRequestStatus perform(Graph g)\r
+                                                       throws Exception {\r
+                                               AnimationController c = new TestAnimationController();\r
+                                                       Collection<IGraphicsNode> nodes = parent.getScenegraphAdapter().getNodes();\r
+                                                       for (IGraphicsNode node : nodes) {\r
+                                                               if (node instanceof Animatable) {\r
+                                                                       Animatable a = (Animatable) node;\r
+                                                                       if (a.setRandomAnimation(g))\r
+                                                                               c.addAnimatable(a);\r
+                                                               }\r
+                                                       }\r
+                                                       animationSystem.add(c);\r
+                                                       return GraphRequestStatus.transactionComplete();\r
+                                       }\r
+                               });\r
+                               \r
+//                                             showMessage("Activated " + animatables.size()\r
+//                                                             + " animations");\r
+                                       } else {\r
+                                               animationSystem.stop();\r
+                                       }\r
+                   }\r
+               };\r
+               \r
+               animateAction.setText("Random animations");\r
+               \r
+               animatePipesAction = new AnimatePipesAction("Pipe animations");\r
+               \r
+               showMonitorsAction = new Action("Interactive Monitor", Action.AS_CHECK_BOX) {\r
+                       public void run() {\r
+                               showMonitors(this.isChecked());\r
+                       }\r
+               };\r
+               showMonitorsAction.setImageDescriptor(Activator.imageDescriptorFromPlugin("fi.vtt.proconf.ode", "icons/silk/monitor.png"));\r
+               \r
+               \r
+               \r
+               configureAnimationAction = new Action() {\r
+                       \r
+                       public void run() {\r
+                               parent.getSession().syncRead(new GraphRequestAdapter(){\r
+                                       List <Resource> list = new ArrayList<Resource>();\r
+                                       @Override\r
+                                       public GraphRequestStatus perform(Graph g) throws Exception {\r
+                                               Stack<G3DNode> stack = new Stack<G3DNode>();\r
+                                               stack.add(parent.getPlant(g).toG3DNode());\r
+                                               while (!stack.isEmpty()) {\r
+                                                       G3DNode n = stack.pop();\r
+                                                       list.add(n.getResource());\r
+                                                       for (G3DNode no : n.getChild())\r
+                                                               stack.push(no);\r
+                                               }\r
+                                               \r
+                                               if (list.size() == 0)\r
+                                                       return GraphRequestStatus.transactionComplete();\r
+                                               \r
+                                               ConfigureAnimationDialog dialog = new ConfigureAnimationDialog(parent.getRenderingComposite().getShell(),parent.getSession(),list,parent.getScenegraphAdapter(),getAnimationSystem());\r
+                                               dialog.open();\r
+                                               return GraphRequestStatus.transactionComplete();\r
+                                       }\r
+                                       \r
+                               });\r
+\r
+                       }\r
+                       \r
+                       \r
+               };\r
+               configureAnimationAction.setText("Configure animations");\r
+               configureAnimationAction.setImageDescriptor(Activator.imageDescriptorFromPlugin("fi.vtt.proconf.ode", "icons/silk/film_edit.png"));\r
+               \r
+               configurePipelineAnimationAction = new Action() {\r
+                       \r
+                       public void run() {\r
+                               parent.getSession().syncRead(new GraphRequestAdapter(){\r
+                                       List <Resource> list = new ArrayList<Resource>();\r
+                                       @Override\r
+                                       public GraphRequestStatus perform(Graph g) throws Exception {\r
+                                               Stack<G3DNode> stack = new Stack<G3DNode>();\r
+                                               stack.add(parent.getPlant(g).toG3DNode());\r
+                                               while (!stack.isEmpty()) {\r
+                                                       G3DNode n = stack.pop();\r
+                                                       if (n.isInstanceOf(ProcessResource.plant3Dresource.PipeRun))\r
+                                                               list.add(n.getResource());\r
+                                                       else //piperun will not contain other piperuns\r
+                                                               for (G3DNode no : n.getChild())\r
+                                                                       stack.push(no);\r
+                                               }\r
+                                               \r
+                                               if (list.size() == 0)\r
+                                                       return GraphRequestStatus.transactionComplete();\r
+                                               \r
+                                               ConfigurePipelineAnimationDialog dialog = new ConfigurePipelineAnimationDialog(parent.getRenderingComposite().getShell(),parent.getSession(),list,parent.getRenderingComponent(),getAnimationSystem());\r
+                                               dialog.open();\r
+                                               return GraphRequestStatus.transactionComplete();\r
+                                       }\r
+                                       \r
+                               });\r
+                               \r
+                       }\r
+                       \r
+                       \r
+               };\r
+               configurePipelineAnimationAction.setText("Configure pipeline animations");\r
+               configurePipelineAnimationAction.setImageDescriptor(Activator.imageDescriptorFromPlugin("fi.vtt.proconf.ode", "icons/silk/film_edit.png"));\r
+               configureMonitorAction = new Action() {\r
+                       \r
+                       public void run() {\r
+                               parent.getSession().syncRead(new GraphRequestAdapter(){\r
+                                       List <Resource> list = new ArrayList<Resource>();\r
+                                       @Override\r
+                                       public GraphRequestStatus perform(Graph g) throws Exception {\r
+                                               Stack<G3DNode> stack = new Stack<G3DNode>();\r
+                                               stack.add(parent.getPlant(g).toG3DNode());\r
+                                               while (!stack.isEmpty()) {\r
+                                                       G3DNode n = stack.pop();\r
+                                                       list.add(n.getResource());\r
+                                                       for (G3DNode no : n.getChild())\r
+                                                               stack.push(no);\r
+                                               }\r
+                                               \r
+                                               if (list.size() == 0)\r
+                                                       return GraphRequestStatus.transactionComplete();\r
+                                               \r
+                                               ConfigureMonitorDialog dialog = new ConfigureMonitorDialog(parent.getRenderingComposite().getShell(),parent.getSession(),list);\r
+                                               dialog.open();\r
+                                               return GraphRequestStatus.transactionComplete();\r
+                                       }\r
+                                       \r
+                               });\r
+                               \r
+                       }\r
+               };\r
+               configureMonitorAction.setText("Configure monitor");\r
+               configureMonitorAction.setImageDescriptor(Activator.imageDescriptorFromPlugin("fi.vtt.proconf.ode", "icons/silk/monitor_edit.png"));\r
+               \r
+               actions.add(new FocusAction(parent));\r
+       }\r
+       \r
+        private AnimationSystem getAnimationSystem() {\r
+               if (animationSystem == null) {\r
+                       animationSystem = new AnimationSystem(parent.getScenegraphAdapter());\r
+               }\r
+               return animationSystem;\r
+        }\r
+        \r
+        protected void updateMonitor(Graph graph) {\r
+               if (showMonitorsAction.isChecked()) {\r
+               \r
+                       List<IGraphicsNode> nodes = parent.getSelectionAdapter().getInteractiveSelectedObjects();\r
+                               if (nodes.size() > 0) {\r
+                                       IGraphicsNode selected = nodes.get(0);\r
+                                       if (monitor.acceptNode(graph,selected))\r
+                                               monitor.setNode(graph,selected);\r
+                               }\r
+                               monitor.update();\r
+               }\r
+           }\r
+           \r
+           protected Monitor createMonitor() {\r
+               Monitor m = new TextMonitor(parent);\r
+               m.setTextProvider(new ResourcePathPropertyProvider());\r
+               return m;\r
+           }\r
+           \r
+           private  void showMonitors(boolean show) {\r
+               if (show) {\r
+                       if (monitor == null) {\r
+                               monitor = createMonitor();\r
+                       }\r
+                       final List <IGraphicsNode> nodes = parent.getSelectionAdapter().getInteractiveSelectedObjects();\r
+                       if (nodes.size() > 0) {\r
+                               parent.getSession().asyncRead(new GraphRequestAdapter() {\r
+                                       @Override\r
+                                       public GraphRequestStatus perform(Graph g) throws Exception {\r
+                                               monitor.setNode(g,nodes.get(0));\r
+                                               return GraphRequestStatus.transactionComplete();\r
+                                       }\r
+                               });\r
+                               \r
+                       }\r
+                       \r
+               } else if (!show && monitor != null) {\r
+                       monitor.remove();\r
+                       parent.setViewChanged(true);\r
+               }\r
+           }\r
+        \r
+        private class AnimatePipesAction extends Action {\r
+\r
+               public AnimatePipesAction(String text) {\r
+                       super(text, Action.AS_CHECK_BOX);\r
+\r
+               }\r
+\r
+               public void run() {\r
+                       if (this.isChecked()) {\r
+                               parent.getSession().syncRead(new GraphRequestAdapter() {\r
+                                       List<PipeRun> list = new ArrayList<PipeRun>();\r
+\r
+                                       @Override\r
+                                       public GraphRequestStatus perform(Graph g) throws Exception {\r
+                                               Stack<G3DNode> stack = new Stack<G3DNode>();\r
+                                               stack.add(parent.getPlant(g).toG3DNode());\r
+                                               while (!stack.isEmpty()) {\r
+                                                       G3DNode n = stack.pop();\r
+                                                       if (n.isInstanceOf(ProcessResource.plant3Dresource.PipeRun))\r
+                                                               list.add(new PipeRun(n));\r
+                                                       else\r
+                                                               //piperun will not contain other piperuns\r
+                                                               for (G3DNode no : n.getChild())\r
+                                                                       stack.push(no);\r
+                                               }\r
+\r
+                                               for (PipeRun n : list) {\r
+                                                       PipeAnimationController c = new PipeAnimationController(parent.getRenderingComponent(), n);\r
+                                                       //animationSystem.add(c);\r
+                                                       getAnimationSystem().add(c);\r
+                                               }\r
+                                               return GraphRequestStatus.transactionComplete();\r
+                                       }\r
+\r
+                               });\r
+\r
+                       } else {\r
+                               //stopAnimations();\r
+                               getAnimationSystem().stop();\r
+                       }\r
+               }\r
+\r
+       }\r
+}\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/EquipmentEditorPart.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/EquipmentEditorPart.java
new file mode 100644 (file)
index 0000000..07283da
--- /dev/null
@@ -0,0 +1,46 @@
+package fi.vtt.simantics.processeditor.views;\r
+\r
+import java.util.Collection;\r
+\r
+import org.eclipse.swt.widgets.Display;\r
+import org.simantics.db.Graph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.management.ISessionContext;\r
+import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase;\r
+import org.simantics.proconf.g3d.base.ThreeDimensionalEditorPart;\r
+import org.simantics.proconf.g3d.shapeeditor.views.ShapeEditorBase;\r
+\r
+import fi.vtt.simantics.processeditor.ProcessResource;\r
+import fi.vtt.simantics.processeditor.tools.NozzleContribution;\r
+\r
+public class EquipmentEditorPart extends ThreeDimensionalEditorPart {\r
+       \r
+       @Override\r
+       protected ThreeDimensionalEditorBase createEditor(ISessionContext session) {\r
+               ShapeEditorBase base = new ShapeEditorBase(session);\r
+               base.addEditorContribution(new NozzleContribution(base));\r
+               return base;\r
+       }\r
+       \r
+       @Override\r
+       public void reload(Graph g) {\r
+               Resource inputResource = getInputResource();\r
+               Collection<Resource> model = g.getObjects(inputResource, ProcessResource.plant3Dresource.HasGraphics);\r
+               if (model.size() != 1)\r
+                       throw new RuntimeException("Cannot find model for equipment " + inputResource);\r
+               Resource modelResource = model.iterator().next();\r
+               if (modelResource != null) {\r
+                       editor.reload(g,modelResource);\r
+               } else {\r
+                       \r
+                        Display d = getSite().getShell().getDisplay();\r
+                   d.asyncExec(new Runnable() {\r
+                       public void run() {\r
+                               editor.showMessage("Failed to load model.");\r
+                           getSite().getPage().closeEditor(EquipmentEditorPart.this,false);\r
+                       }\r
+                   });\r
+               }\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/PipelineComponentEditorPart.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/PipelineComponentEditorPart.java
new file mode 100644 (file)
index 0000000..e94d7d5
--- /dev/null
@@ -0,0 +1,46 @@
+package fi.vtt.simantics.processeditor.views;\r
+\r
+import java.util.Collection;\r
+\r
+import org.eclipse.swt.widgets.Display;\r
+import org.simantics.db.Graph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.management.ISessionContext;\r
+import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase;\r
+import org.simantics.proconf.g3d.base.ThreeDimensionalEditorPart;\r
+import org.simantics.proconf.g3d.shapeeditor.views.ShapeEditorBase;\r
+\r
+import fi.vtt.simantics.processeditor.ProcessResource;\r
+import fi.vtt.simantics.processeditor.tools.ControlPointContribution;\r
+\r
+public class PipelineComponentEditorPart extends ThreeDimensionalEditorPart {\r
+       \r
+       @Override\r
+       protected ThreeDimensionalEditorBase createEditor(ISessionContext session) {\r
+               ShapeEditorBase base = new ShapeEditorBase(session);\r
+               base.addEditorContribution(new ControlPointContribution(base));\r
+               return base;\r
+       }\r
+       \r
+       @Override\r
+       public void reload(Graph g) {\r
+               Resource inputResource = getInputResource();\r
+               Collection<Resource> model = g.getObjects(inputResource, ProcessResource.plant3Dresource.HasGraphics);\r
+               if (model.size() != 1)\r
+                       throw new RuntimeException("Cannot find model for pipeline component " + inputResource);\r
+               Resource modelResource = model.iterator().next();\r
+               if (modelResource != null) {\r
+                       editor.reload(g,modelResource);\r
+               } else {\r
+                       \r
+                        Display d = getSite().getShell().getDisplay();\r
+                   d.asyncExec(new Runnable() {\r
+                       public void run() {\r
+                               editor.showMessage("Failed to load model.");\r
+                           getSite().getPage().closeEditor(PipelineComponentEditorPart.this,false);\r
+                       }\r
+                   });\r
+               }\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/PlantStructureOutlinePage.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/PlantStructureOutlinePage.java
new file mode 100644 (file)
index 0000000..0c7a356
--- /dev/null
@@ -0,0 +1,27 @@
+package fi.vtt.simantics.processeditor.views;\r
+\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.management.ISessionContext;\r
+import org.simantics.layer0.utils.viewpoints.ResourceViewpoint;\r
+import org.simantics.proconf.browsing.views.GraphExplorerOutlinePage;\r
+\r
+import fi.vtt.simantics.processeditor.perspectives.ViewpointGenerator;\r
+\r
+public class PlantStructureOutlinePage extends GraphExplorerOutlinePage {\r
+\r
+       \r
+       public PlantStructureOutlinePage(ISessionContext sessionContext, Resource inputResource) {\r
+               super(sessionContext, inputResource);\r
+       }\r
+       \r
+       @Override\r
+       public void createControl(Composite parent) {\r
+               super.createControl(parent);\r
+       }\r
+\r
+       @Override\r
+       public ResourceViewpoint getViewPoint(ISessionContext sessionContext) {\r
+               return ViewpointGenerator.createObjectStructureViewpoint();\r
+       }\r
+}\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/PlantStructureView.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/PlantStructureView.java
new file mode 100644 (file)
index 0000000..6685e36
--- /dev/null
@@ -0,0 +1,22 @@
+package fi.vtt.simantics.processeditor.views;\r
+\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.simantics.db.management.ISessionContext;\r
+import org.simantics.layer0.utils.viewpoints.ResourceViewpoint;\r
+import org.simantics.proconf.browsing.GraphExplorer;\r
+import org.simantics.proconf.browsing.views.GraphExplorerView;\r
+\r
+import fi.vtt.simantics.processeditor.perspectives.ViewpointGenerator;\r
+\r
+public class PlantStructureView extends GraphExplorerView {\r
+\r
+       @Override\r
+       protected GraphExplorer createExplorer(Composite parent) {\r
+               return super.createExplorer(parent);\r
+       }\r
+       \r
+       @Override\r
+       protected ResourceViewpoint getViewpoint(ISessionContext context) {\r
+               return ViewpointGenerator.createViewpoint();\r
+       }\r
+}\r
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/ProcessEditor.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/ProcessEditor.java
new file mode 100644 (file)
index 0000000..5aae588
--- /dev/null
@@ -0,0 +1,704 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007 VTT Technical Research Centre of Finland and others.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package fi.vtt.simantics.processeditor.views;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.HashMap;\r
+import java.util.List;\r
+import java.util.Map;\r
+\r
+import org.eclipse.jface.action.Action;\r
+import org.eclipse.jface.dialogs.Dialog;\r
+import org.eclipse.jface.dialogs.IDialogConstants;\r
+import org.eclipse.jface.viewers.ISelection;\r
+import org.eclipse.jface.viewers.ISelectionChangedListener;\r
+import org.eclipse.jface.viewers.SelectionChangedEvent;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.events.KeyEvent;\r
+import org.eclipse.swt.events.KeyListener;\r
+import org.eclipse.swt.events.SelectionEvent;\r
+import org.eclipse.swt.events.SelectionListener;\r
+import org.eclipse.swt.layout.GridData;\r
+import org.eclipse.swt.widgets.Button;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.swt.widgets.Control;\r
+import org.eclipse.swt.widgets.Label;\r
+import org.eclipse.swt.widgets.Shell;\r
+import org.eclipse.swt.widgets.Text;\r
+import org.eclipse.ui.IWorkbenchPart;\r
+import org.eclipse.ui.views.contentoutline.IContentOutlinePage;\r
+import org.simantics.db.Graph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.Session;\r
+import org.simantics.db.management.ISessionContext;\r
+import org.simantics.layer0.utils.EntityFactory;\r
+import org.simantics.layer0.utils.IEntity;\r
+import org.simantics.layer0.utils.Property;\r
+import org.simantics.proconf.g3d.base.JmeRenderingComponent;\r
+import org.simantics.proconf.g3d.base.ScenegraphAdapter;\r
+import org.simantics.proconf.g3d.base.ScenegraphAdapterImpl;\r
+import org.simantics.proconf.g3d.base.SelectionAdapter;\r
+import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase;\r
+import org.simantics.proconf.g3d.common.StructuredResourceSelection;\r
+import org.simantics.proconf.g3d.scenegraph.IGeometryNode;\r
+import org.simantics.proconf.g3d.scenegraph.IGraphicsNode;\r
+import org.simantics.proconf.g3d.scenegraph.ISelectableNode;\r
+import org.simantics.proconf.g3d.scenegraph.ParameterizedModelNode;\r
+import org.simantics.proconf.g3d.shapes.FloorShape;\r
+import org.simantics.proconf.g3d.stubs.G3DNode;\r
+import org.simantics.utils.ErrorLogger;\r
+import org.simantics.utils.ui.jface.MenuTools;\r
+\r
+import com.jme.math.Vector3f;\r
+import com.jme.scene.Geometry;\r
+\r
+import fi.vtt.simantics.processeditor.Activator;\r
+import fi.vtt.simantics.processeditor.ProcessResource;\r
+import fi.vtt.simantics.processeditor.actions.InsertComponentAction;\r
+import fi.vtt.simantics.processeditor.actions.InsertEquipmentAction;\r
+import fi.vtt.simantics.processeditor.actions.InsertNozzleAction;\r
+import fi.vtt.simantics.processeditor.actions.RoutePipeAction;\r
+import fi.vtt.simantics.processeditor.common.ControlPointTools;\r
+import fi.vtt.simantics.processeditor.common.PipingRules;\r
+import fi.vtt.simantics.processeditor.scenegraph.NonVisibleNode;\r
+import fi.vtt.simantics.processeditor.scenegraph.PipelineComponentNode;\r
+import fi.vtt.simantics.processeditor.scenegraph.PipeComponentNode;\r
+import fi.vtt.simantics.processeditor.scenegraph.PipeRunNode;\r
+import fi.vtt.simantics.processeditor.stubs.PipeControlPoint;\r
+import fi.vtt.simantics.processeditor.stubs.PipeRun;\r
+import fi.vtt.simantics.processeditor.stubs.Plant;\r
+import fi.vtt.simantics.processeditor.stubs.Plant3DResource;\r
+import fi.vtt.simantics.processeditor.tools.PlantEditContribution;\r
+import fi.vtt.simantics.processeditor.tools.PlantVisualizationContribution;\r
+\r
+public class ProcessEditor extends ThreeDimensionalEditorBase {\r
+    \r
+    private Resource plantResource = null;\r
+    \r
+    //private List<AnimationController> animationControllers = new ArrayList<AnimationController>();\r
+\r
+    private Action configureFloorAction = null;\r
+\r
+    private Geometry floorShape = null;\r
+\r
+    public ProcessEditor(ISessionContext session) {\r
+        super(session);\r
+        addEditorContribution(new PlantEditContribution(this));\r
+        addEditorContribution(new PlantVisualizationContribution(this));\r
+    }\r
+    \r
+    public ProcessEditor(ISessionContext session,JmeRenderingComponent component) {\r
+        super(session,component);\r
+        addEditorContribution(new PlantEditContribution(this));\r
+        addEditorContribution(new PlantVisualizationContribution(this));\r
+    }\r
+    \r
+    @Override\r
+    protected ScenegraphAdapter createScenegraphAdapter() {\r
+       return new ProcessEditorAdapter(session,getRenderingComponent());\r
+    }\r
+    \r
+    @Override\r
+    public void createControl(Graph graph,Composite parent) {\r
+       super.createControl(graph,parent);\r
+\r
+       floorShape = FloorShape.getShape(getRenderingComponent().getDisplaySystem().getRenderer(), 100.f,0.2f);\r
+       getRenderingComponent().getNoCastRoot().attachChild(floorShape);\r
+       floorShape.setLocalTranslation(new Vector3f(0.f,-0.01f,0.f));\r
+    }\r
+\r
+    @Override\r
+    protected void makeActions(Graph graph) {\r
+        super.makeActions(graph);\r
+\r
+        //actions.add(new ShowTrendsAction(this));\r
+\r
+        configureFloorAction = new Action() {\r
+               public void run() {\r
+                       FloorConfigureDialog dialog = new FloorConfigureDialog(ProcessEditor.this.parent.getShell());\r
+                       if (dialog.open() == FloorConfigureDialog.CANCEL)\r
+                               return;\r
+                       if (dialog.isFloorEnabled()) {\r
+                               if (floorShape.getParent() == null)\r
+                                       getRenderingComponent().getNoCastRoot().attachChild(floorShape);\r
+                       } else {\r
+                               floorShape.removeFromParent();\r
+                       }\r
+                       floorShape.setLocalTranslation(new Vector3f(0.f,(float)dialog.getFloorHeight(),0.f));\r
+                       \r
+               }\r
+        };\r
+        configureFloorAction.setText("Configure floor");\r
+        configureFloorAction.setImageDescriptor(Activator.imageDescriptorFromPlugin("fi.vtt.proconf.ode", "icons/silk/shape_align_bottom.png"));\r
+\r
+//        ContextActionFactory extended[] = ContextActionRegistry.getActions("fi.vtt.proconf.shapeeditor.processeditorview");\r
+//        for (ContextActionFactory c : extended) {\r
+//             actions.add(c.createAction(this));\r
+//        }\r
+    }\r
+    \r
+//    protected void stopAnimations() {\r
+//     animationSystem.stop();\r
+//    }\r
+    \r
+    protected void fillLocalPullDown() {\r
+       super.fillLocalPullDown();\r
+       MenuTools.getOrCreate(getMenuID(),"Advanced", menuManager).add(configureFloorAction);\r
+    }\r
+    \r
+    protected class ProcessEditorAdapter extends ScenegraphAdapterImpl {\r
+       \r
+        public ProcessEditorAdapter(Session session, JmeRenderingComponent component) {\r
+                       super(session, component);\r
+        }\r
+        \r
+        private class NormalScengraphQuery extends ScenegraphQuery {\r
+               \r
+               public NormalScengraphQuery(Resource node) {\r
+                               super(node);\r
+                       } \r
+                \r
+                \r
+                @Override\r
+               public void shapeAdded(Graph graph, IGraphicsNode node) {\r
+                        // FIXME : this won't work like in previous ProConf\r
+               }\r
+        }\r
+        \r
+        private Map<Resource,PipeRunControlPointQuery> pipeRunQueries = new HashMap<Resource, PipeRunControlPointQuery>();\r
+\r
+               protected ScenegraphQuery newSubnodeListener(G3DNode node) {\r
+               if (node.isInstanceOf(ProcessResource.plant3Dresource.PipeRun)) {\r
+                   PipeRunControlPointQuery query = new PipeRunControlPointQuery(node.getResource());\r
+                   pipeRunQueries.put(node.getResource(), query);\r
+                   node.getGraph().performQuery(query);\r
+//                 return new SubnodeListener(node) {\r
+//                     @Override\r
+//                     public void shapeAdded(IGraphicsNode node) {\r
+//                         if (node instanceof IGeometryNode) {\r
+//                             updateGeometry((IGeometryNode)node);\r
+//                             \r
+//                         }\r
+//                         node.setVisible(true);\r
+//                     }\r
+//                 };\r
+               }\r
+               return new NormalScengraphQuery(node.getResource());\r
+                \r
+           }\r
+               \r
+               @Override\r
+               protected NodePropertyQuery newRootPropertyListener(G3DNode root) {\r
+                       // currently Plant does not have any properties.\r
+                       return null;\r
+               }\r
+               \r
+               private class TransformationQuery extends NodeTransformationQuery {\r
+                       \r
+                       public TransformationQuery(Resource res) {\r
+                               super(res);\r
+                       }\r
+                       \r
+                       @Override\r
+                       public void shapeUpdated(Graph graph, IGraphicsNode shape) {\r
+                               //if (shape instanceof IGeometryNode) {\r
+                //    updateGeometry((IGeometryNode)shape);\r
+                //} else {\r
+                       shape.updateTransform(graph);\r
+                //}\r
+                       }\r
+               }\r
+               \r
+               @Override\r
+               protected NodeTransformationQuery newTransformationListener(G3DNode root) {\r
+                       return new TransformationQuery(root.getResource());\r
+               }\r
+               \r
+               private class NormalNodePropertyQuery extends org.simantics.proconf.g3d.base.ScenegraphAdapterImpl.NodePropertyQuery {\r
+                       \r
+                       public NormalNodePropertyQuery(Resource resource) {\r
+                               super(resource);\r
+                       }\r
+\r
+                       @Override\r
+                       public void shapeUpdated(Graph graph,IGraphicsNode shape) {\r
+                               if (shape instanceof IGeometryNode) {\r
+                    updateGeometry((IGeometryNode)shape);\r
+                } else {\r
+                       shape.updateTransform(graph);\r
+                }\r
+                       }\r
+               }\r
+        @Override\r
+       protected NodePropertyQuery newPropertyListener(G3DNode node) {\r
+               return new NormalNodePropertyQuery(node.getResource());\r
+       }\r
+   \r
+        @Override\r
+               protected IGraphicsNode instantiateNode(IGraphicsNode parent,\r
+                               G3DNode node) {\r
+                       Plant3DResource p3r = ProcessResource.plant3Dresource;\r
+                       IGraphicsNode newNode = null;\r
+                       try {\r
+                               if (node.isInstanceOf(p3r.Equipment)) {\r
+                                       newNode = new ParameterizedModelNode(\r
+                                                       ProcessEditor.this, parent, node.getGraph(),\r
+                                                       node.getResource(), p3r.HasGraphics);\r
+                               } else if (node.isInstanceOf(p3r.PipeRun)) {\r
+                                       newNode = new PipeRunNode(parent, node.getGraph(), node.getResource());\r
+                               } else if (node.isInstanceOf(p3r.Nozzle)) {\r
+                                       newNode = new ParameterizedModelNode(\r
+                                                       ProcessEditor.this, parent, node.getGraph(),\r
+                                                       node.getResource(), p3r.HasGraphics);\r
+                                       // CodedComponent must be handled first since it uses\r
+                                       // hard-coded geometries\r
+                                       // TODO : is this really necessary, or could we unify\r
+                                       // PipeComponentNode, InlineComponentNode,...\r
+                               } else if (node.isInstanceOf(p3r.CodedComponent)) {\r
+                                       newNode = new PipeComponentNode(ProcessEditor.this,\r
+                                                       parent, node.getGraph(), node.getResource());\r
+                               } else if (node.isInstanceOf(p3r.NonVisibleComponent)) {\r
+                                       newNode = new NonVisibleNode(parent, node.getGraph(), node.getResource());\r
+                               } else if (node.isInstanceOf(p3r.PipelineComponent)) {\r
+                                       newNode = new PipelineComponentNode(ProcessEditor.this,\r
+                                                       parent, node.getGraph(), node.getResource());\r
+                               } \r
+\r
+                               // } else if (node instanceof Shape) // Markers (ar/mobile)\r
+                               // needed this\r
+                               // newNode = new ShapeNode(TestProcessEditor.this,parent,node);\r
+                               if (newNode != null) {\r
+                                       if (newNode instanceof ISelectableNode)\r
+                                               ((ISelectableNode) newNode).setVisible(true);\r
+                                       if (newNode instanceof IGeometryNode) {\r
+                                               updateGeometry((IGeometryNode) newNode);\r
+                                       }\r
+                                       return newNode;\r
+                               }\r
+                       } catch (Exception e) {\r
+                               ErrorLogger.defaultLogError("Cannot handle node " + node.getResource(), e);\r
+                               return null;\r
+                       }\r
+                       ErrorLogger.defaultLogError("Cannot handle node " + node.getResource(), null);\r
+                       return null;\r
+\r
+               }\r
+\r
+               /**\r
+                * This is used to create elbows and straight pipes to pipeline TODO :\r
+                * this should be done with rule-engine!\r
+                * \r
+                * \r
+                * @author Marko Luukkainen\r
+                * \r
+                */\r
+               protected class PipeRunControlPointQuery extends NodeQuery {\r
+                       private List<Resource> removed = new ArrayList<Resource>();\r
+                       private List<Resource> added = new ArrayList<Resource>();\r
+\r
+                       public PipeRunControlPointQuery(Resource r) {\r
+                               super(r);\r
+                               if (DEBUG) System.out.println("Created PipeRunControlPointQuery for " + r);\r
+\r
+                       }\r
+\r
+                       @Override\r
+                       protected Object compute2(Graph graph) {\r
+                               PipeRun run = new PipeRun(graph, nodeResource);\r
+                               Collection<IEntity> cps = run\r
+                                               .getRelatedObjects(ProcessResource.plant3Dresource.HasControlPoints);\r
+                               List<Resource> res = new ArrayList<Resource>();\r
+                               for (IEntity t : cps)\r
+                                       res.add(t.getResource());\r
+                               return res;\r
+                       }\r
+\r
+                       @Override\r
+                       public boolean updated(Graph graph, Object oldResult,\r
+                                       Object newResult) {\r
+                               \r
+                               removed.clear();\r
+                               added.clear();\r
+\r
+                               List<Resource> oldCps = (List<Resource>) oldResult;\r
+                               List<Resource> newCps = (List<Resource>) newResult;\r
+                               if (oldCps == null)\r
+                                       oldCps = new ArrayList<Resource>();\r
+\r
+                               for (Resource r : oldCps) {\r
+                                       if (!newCps.contains(r))\r
+                                               removed.add(r);\r
+                               }\r
+\r
+                               for (Resource r : newCps) {\r
+                                       if (!oldCps.contains(r))\r
+                                               added.add(r);\r
+                               }\r
+                               for (Resource r : removed)\r
+                                       removeControlPoint(graph, r);\r
+                               for (Resource r : added) {\r
+                                       addControlPoint(graph, r);\r
+                                       // ControlPointTools.addControlPoint(new\r
+                                       // PipeRun(graph,pipeRun), new PipeControlPoint(graph, r));\r
+                               }\r
+\r
+                               return (added.size() > 0 || removed.size() > 0);\r
+                       }\r
+                       \r
+                       @Override\r
+                       public void dispose() {\r
+                               super.dispose();\r
+                               for (ControlPointPropertyQuery q : controlPointPropertyQueries.values())\r
+                                       q.dispose();\r
+                               controlPointPropertyQueries.clear();\r
+                       }\r
+                       \r
+                       private Map<Resource,ControlPointPropertyQuery> controlPointPropertyQueries = new HashMap<Resource, ControlPointPropertyQuery>();\r
+                       \r
+                       private void addControlPoint(Graph graph, Resource resource) {\r
+                               ControlPointPropertyQuery query = new ControlPointPropertyQuery(resource);\r
+                               graph.performQuery(query);\r
+                               controlPointPropertyQueries.put(resource,query);\r
+                       }\r
+                       \r
+                       private void removeControlPoint(Graph graph, Resource resource) {\r
+                               ControlPointPropertyQuery query = controlPointPropertyQueries.remove(resource);\r
+                               query.dispose();\r
+                               ControlPointTools.removeControlPoint(new PipeControlPoint(\r
+                                               graph, resource));\r
+                       }\r
+\r
+               }\r
+\r
+               protected class ControlPointPropertyQuery extends NodeQuery {\r
+                       boolean initialized = false;\r
+                       \r
+                       public ControlPointPropertyQuery(Resource r) {\r
+                               super(r);\r
+                               if (DEBUG) System.out.println("Created ControlPointPropertyQuery for " + r);\r
+                       }\r
+                       \r
+                       @Override\r
+               public List<Object> compute2(Graph g) {\r
+                       IEntity t = EntityFactory.create(g,nodeResource);\r
+                       \r
+                       Collection<Property> properties = t.getRelatedProperties(ProcessResource.builtins.HasProperty);\r
+                       List<Object> propertyValues = new ArrayList<Object>();\r
+                       p(properties,propertyValues);\r
+\r
+                       return propertyValues;\r
+               }\r
+               \r
+               private void p(Collection<Property> properties, List<Object> propertyValues) {\r
+                       for (Property p : properties) {\r
+                               Collection<Property> subProperties = p.getRelatedProperties(p.getGraph().getBuiltins().HasProperty);\r
+                               if (subProperties.size() != 0) {\r
+                                       p(subProperties,propertyValues);\r
+                               } \r
+                               if (p.hasValue()){\r
+                                       propertyValues.add(p.getValue());\r
+                               }\r
+                       }\r
+               }\r
+                       \r
+                       @Override\r
+                       public boolean updated(Graph graph, Object oldResult, Object newResult) {\r
+                               PipingRules.pipeControlPointPositionUpdate(graph, this.nodeResource);\r
+                               if (initialized) {\r
+                                       //PipingRules.pipeControlPointPositionUpdate(graph, this.nodeResource);\r
+                               } else {\r
+                                       initialized = true;\r
+                               }\r
+                               return true;\r
+                       }\r
+               }\r
+               \r
+               @Override\r
+               protected void removeNode(Resource parent, Resource r) {\r
+                       super.removeNode(parent, r);\r
+                       PipeRunControlPointQuery q = pipeRunQueries.get(r);\r
+                       if (q != null)\r
+                               q.dispose();\r
+               }\r
+               \r
+               @Override\r
+               public void dispose() {\r
+                       super.dispose();\r
+               }\r
+       }\r
+    \r
+    @Override\r
+    protected void pageSelectionChanged(IWorkbenchPart part, ISelection selection) {\r
+        if (!(selection instanceof StructuredResourceSelection)) {\r
+            return;\r
+        }\r
+        \r
+        StructuredResourceSelection s = (StructuredResourceSelection) selection;\r
+        selectionAdapter.setCurrentSelection(s);\r
+        viewChanged = true;\r
+        \r
+        //if (s.getRootSelection() == null) {\r
+        if (!(part instanceof ProcessEditor)) {\r
+            //System.out.println("ShapeEditorView.pageSelectionChanged() no root selection");\r
+               ((ProcessEditorSelectionAdapter)selectionAdapter).setEditorSelection(true);\r
+            return;\r
+        } \r
+        //if (!s.getRootSelection().getResource().getId().equals(plant.getResource().getId())) {\r
+        ProcessEditor sender = (ProcessEditor)part;\r
+        if (!sender.getPlantResource().equals(plantResource)) {\r
+//          System.out.println("ShapeEditorView.pageSelectionChanged() not right group "\r
+//                  + s.getRootSelection().getResource().getId() + " != " + model.getResource().getId());\r
+               selectionAdapter.setCurrentSelection(new StructuredResourceSelection());\r
+               ((ProcessEditorSelectionAdapter)selectionAdapter).setEditorSelection(false);\r
+          return;\r
+      }\r
+        selectionAdapter.setEditorSelection();\r
+        \r
+    }\r
+\r
+    @Override\r
+    protected void reloadFrom(IEntity thing) {\r
+        if (plantResource != null) {\r
+            throw new UnsupportedOperationException("Reloading instantiated viewer not supported");\r
+        }\r
+        if (thing.isInstanceOf(ProcessResource.plant3Dresource.Plant)) {\r
+            plantResource = thing.getResource();\r
+            G3DNode plant = new G3DNode(thing);\r
+            adapter.setRootNode(plant);\r
+            //adapter.addOutbound(plant);\r
+            ControlPointTools.reloadCache(thing.getGraph(),plant.getResource());\r
+        } else {\r
+            throw new IllegalArgumentException("Resource is not a plant");\r
+        } \r
+    }\r
+\r
+    public Resource getPlantResource() {\r
+        return plantResource;\r
+    }\r
+    \r
+    public Plant getPlant(Graph g) {\r
+       return new Plant(g, plantResource);\r
+    }\r
+    \r
+    @Override\r
+    protected SelectionAdapter createSelectionAdapter() {\r
+       return new ProcessEditorSelectionAdapter(adapter);\r
+    }\r
+    \r
+    protected class ProcessEditorSelectionAdapter extends SelectionAdapter {\r
+       \r
+       \r
+        public ProcessEditorSelectionAdapter(ScenegraphAdapter adapter) {\r
+                       super(adapter);\r
+                       // TODO Auto-generated constructor stub\r
+               }\r
+\r
+               @Override\r
+           protected StructuredResourceSelection filterSelection(ISelection s) {\r
+               if (!(s instanceof StructuredResourceSelection))\r
+                   return new StructuredResourceSelection();\r
+               return (StructuredResourceSelection)s;\r
+           }\r
+\r
+           @Override\r
+           public void setEditorSelection() {\r
+               List<IGraphicsNode> sel = getSelectedObjects();\r
+               for (IGraphicsNode o : adapter.getNodes())\r
+                       if (o instanceof ISelectableNode) {\r
+                               if (sel.contains(o)) {\r
+                               ((ISelectableNode)o).setSelected(true);\r
+                       } else {\r
+                               ((ISelectableNode)o).setSelected(false);\r
+                       }\r
+                       }\r
+               List<Resource> selected = getSelectedResources();\r
+            // TODO : don't know why this code is here, but it seems unnecessary\r
+//             for (Resource r : selected) {\r
+//                 if (!adapter.hasNode(r)) {\r
+//                     // instantiating a new resource : usin this editor's tc\r
+//                     Resource resource = graph.getResource(r.getId());\r
+//                     adapter.addInbound(resource).setSelected(true);\r
+//\r
+//                 }\r
+//             }\r
+               \r
+           }\r
+           \r
+           public void setEditorSelection(boolean addShapes) {\r
+\r
+               List<IGraphicsNode> sel = getSelectedObjects();\r
+               for (IGraphicsNode o : adapter.getNodes())\r
+                       if (o instanceof ISelectableNode) {\r
+                               if (sel.contains(o)) {\r
+                               ((ISelectableNode)o).setSelected(true);\r
+                       } else {\r
+                               ((ISelectableNode)o).setSelected(false);\r
+                       }\r
+                       }\r
+               if (addShapes) {\r
+                       // TODO : don't know why this code is here, but it seems unnecessary\r
+//                 List<Resource> selected = getSelectedResources();\r
+//                 for (Resource r : selected) {\r
+//                     if (!adapter.hasNode(r)) {\r
+//                         if (r.isInstanceOf(GlobalIdMap.get(PSK3DModelingOntologyMapping.EQUIPMENT))) {\r
+//                             Resource group = GraphicsNodeTools.getModelFromResource(r);\r
+//                             if (group != null && group.getId() == plant.getResource().getId()) {\r
+////                                     instantiating a new resource : usin this editor's tc\r
+//                                 Resource resource = graph.getResource(r.getId());\r
+//                                 adapter.addInbound(resource).setSelected(true);\r
+//                             }\r
+//                                 \r
+//                         }\r
+//                     }\r
+//                 }\r
+               }\r
+           }\r
+\r
+           @Override\r
+           protected void setEditorHighlightSelection() {\r
+               List<IGraphicsNode> sel = getInteractiveSelectedObjects();\r
+               for (IGraphicsNode o : adapter.getNodes())\r
+                       if (o instanceof ISelectableNode) {\r
+                               if (sel.contains(o)) {\r
+                               ((ISelectableNode)o).setHighlighted(true);\r
+                       } else {\r
+                               ((ISelectableNode)o).setHighlighted(false);\r
+                       }\r
+                       }\r
+           }\r
+    }\r
+    \r
+    private class FloorConfigureDialog extends Dialog implements KeyListener,SelectionListener {\r
+       \r
+       private boolean floorEnabled = true;\r
+       private double floorHeight = 0.0;\r
+       \r
+       private Text floorHeightText = null;\r
+       private Button floorEnabledButton = null;\r
+       \r
+       public FloorConfigureDialog(Shell shell) {\r
+               super(shell);\r
+       }\r
+       \r
+       @Override\r
+       protected Control createDialogArea(Composite parent) {\r
+               Composite composite = (Composite) super.createDialogArea(parent);\r
+               Label label = new Label(composite, SWT.WRAP);\r
+            label.setText("Configure floor");\r
+            GridData data = new GridData(GridData.GRAB_HORIZONTAL\r
+                    | GridData.GRAB_VERTICAL | GridData.HORIZONTAL_ALIGN_FILL\r
+                    | GridData.VERTICAL_ALIGN_CENTER);\r
+               \r
+            data.widthHint = convertHorizontalDLUsToPixels(IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH);\r
+            label.setLayoutData(data);\r
+            label.setFont(parent.getFont());\r
+            floorEnabledButton = new Button(composite,SWT.CHECK);\r
+            floorEnabledButton.setText("Enabled");\r
+            label = new Label(composite, SWT.WRAP);\r
+            label.setText("Height");\r
+            label.setLayoutData(data);\r
+            label.setFont(parent.getFont());\r
+            floorHeightText = new Text(composite,SWT.NONE);\r
+               \r
+               \r
+            floorHeightText.addKeyListener(this);\r
+               floorEnabledButton.addSelectionListener(this);\r
+               floorEnabledButton.setSelection(floorEnabled);\r
+               floorHeightText.setText(Double.toString(floorHeight));\r
+               \r
+               return composite;\r
+       }\r
+       \r
+       @Override\r
+       protected void configureShell(Shell newShell) {\r
+               super.configureShell(newShell);\r
+               newShell.setText("Configure floor");\r
+       }\r
+       \r
+       public void keyPressed(KeyEvent e) {\r
+               \r
+       }\r
+       \r
+       public void keyReleased(KeyEvent e) {\r
+               boolean ok = true;\r
+               try {\r
+                       floorHeight = Double.parseDouble(floorHeightText.getText());    \r
+               } catch (NumberFormatException err) {\r
+                       ok = false;\r
+               }\r
+               if (ok) {\r
+                       this.getButton(IDialogConstants.OK_ID).setEnabled(true);\r
+               } else {\r
+                       this.getButton(IDialogConstants.OK_ID).setEnabled(false);\r
+               }\r
+       }\r
+       \r
+       public void widgetDefaultSelected(SelectionEvent e) {\r
+               \r
+       }\r
+       \r
+       public void widgetSelected(SelectionEvent e) {\r
+               floorEnabled = floorEnabledButton.getSelection();\r
+       }\r
+\r
+               public boolean isFloorEnabled() {\r
+                       return floorEnabled;\r
+               }\r
+\r
+               public double getFloorHeight() {\r
+                       return floorHeight;\r
+               }\r
+\r
+    }\r
+    \r
+    @Override\r
+    protected void hookDragAndDrop() {\r
+       super.hookDragAndDrop();\r
+       dropTarget.addDropListener(new InsertEquipmentAction(this));\r
+       dropTarget.addDropListener(new InsertNozzleAction(this));\r
+       dropTarget.addDropListener(new InsertComponentAction(this));\r
+       dropTarget.addDropListener(new RoutePipeAction(this));\r
+    }\r
+    \r
+    @Override\r
+       public Object getAdapter(Class adapter) {\r
+               if (adapter == IContentOutlinePage.class) {\r
+                       if (getPlantResource() == null)\r
+                               return null;\r
+                       final PlantStructureOutlinePage page = new PlantStructureOutlinePage(sessionContext,getPlantResource());\r
+                       \r
+                       getSelectionAdapter().addSelectionChangedListener(new ISelectionChangedListener() {\r
+                               @Override\r
+                               public void selectionChanged(SelectionChangedEvent event) {\r
+                                       page.setSelection(event.getSelection());\r
+                                       \r
+                               }\r
+                       });\r
+                       parent.getDisplay().asyncExec(new Runnable() {\r
+                               @Override\r
+                               public void run() {\r
+                                       page.addSelectionChangedListener(new ISelectionChangedListener() {\r
+                                               @Override\r
+                                               public void selectionChanged(SelectionChangedEvent event) {\r
+                                                       selectionAdapter.setSelection(SelectionAdapter.transformSelection(event.getSelection()));\r
+                                               }\r
+                                       });\r
+                               }\r
+                       });\r
+                       \r
+                       \r
+                       \r
+                       return page;\r
+               }\r
+               return null;\r
+       }\r
+}
\ No newline at end of file
diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/ProcessEditorPart.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/ProcessEditorPart.java
new file mode 100644 (file)
index 0000000..a83f40b
--- /dev/null
@@ -0,0 +1,25 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007 VTT Technical Research Centre of Finland and others.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package fi.vtt.simantics.processeditor.views;\r
+\r
+import org.simantics.db.management.ISessionContext;\r
+import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase;\r
+import org.simantics.proconf.g3d.base.ThreeDimensionalEditorPart;\r
+\r
+\r
+public class ProcessEditorPart extends ThreeDimensionalEditorPart {\r
+       \r
+       @Override\r
+       protected ThreeDimensionalEditorBase createEditor(ISessionContext session) {\r
+               return new ProcessEditor(session);\r
+       }\r
+\r
+}\r