]> gerrit.simantics Code Review - simantics/3d.git/commitdiff
Publish Plant3D feature 32/2832/1
authorMarko Luukkainen <marko.luukkainen@semantum.fi>
Thu, 4 Apr 2019 12:55:24 +0000 (15:55 +0300)
committerMarko Luukkainen <marko.luukkainen@semantum.fi>
Thu, 4 Apr 2019 12:55:24 +0000 (15:55 +0300)
Change-Id: If41206e5e25a27b027e4fb260d9ed43b1cbdf951

125 files changed:
org.simantics.plant3d.modeling.feature/.project [new file with mode: 0644]
org.simantics.plant3d.modeling.feature/build.properties [new file with mode: 0644]
org.simantics.plant3d.modeling.feature/feature.xml [new file with mode: 0644]
org.simantics.plant3d.ontology/.classpath [new file with mode: 0644]
org.simantics.plant3d.ontology/.gitignore [new file with mode: 0644]
org.simantics.plant3d.ontology/.project [new file with mode: 0644]
org.simantics.plant3d.ontology/.settings/org.eclipse.jdt.core.prefs [new file with mode: 0644]
org.simantics.plant3d.ontology/META-INF/MANIFEST.MF [new file with mode: 0644]
org.simantics.plant3d.ontology/build.properties [new file with mode: 0644]
org.simantics.plant3d.ontology/graph/images/Component.png [new file with mode: 0644]
org.simantics.plant3d.ontology/graph/images/Component.svg [new file with mode: 0644]
org.simantics.plant3d.ontology/graph/images/Elbow.png [new file with mode: 0644]
org.simantics.plant3d.ontology/graph/images/Elbow.svg [new file with mode: 0644]
org.simantics.plant3d.ontology/graph/images/Nozzle.png [new file with mode: 0644]
org.simantics.plant3d.ontology/graph/images/Nozzle.svg [new file with mode: 0644]
org.simantics.plant3d.ontology/graph/images/Straight.png [new file with mode: 0644]
org.simantics.plant3d.ontology/graph/images/Straight.svg [new file with mode: 0644]
org.simantics.plant3d.ontology/graph/images/eye.png [new file with mode: 0644]
org.simantics.plant3d.ontology/graph/images/eye.svg [new file with mode: 0644]
org.simantics.plant3d.ontology/graph/images/factory.png [new file with mode: 0644]
org.simantics.plant3d.ontology/graph/images/factory.svg [new file with mode: 0644]
org.simantics.plant3d.ontology/graph/images/point.png [new file with mode: 0644]
org.simantics.plant3d.ontology/graph/images/point.svg [new file with mode: 0644]
org.simantics.plant3d.ontology/graph/images/rotate.png [new file with mode: 0644]
org.simantics.plant3d.ontology/graph/images/rotate.svg [new file with mode: 0644]
org.simantics.plant3d.ontology/graph/images/tank.png [new file with mode: 0644]
org.simantics.plant3d.ontology/graph/images/tank.svg [new file with mode: 0644]
org.simantics.plant3d.ontology/graph/images/translate.png [new file with mode: 0644]
org.simantics.plant3d.ontology/graph/images/translate.svg [new file with mode: 0644]
org.simantics.plant3d.ontology/graph/images/translate_d.png [new file with mode: 0644]
org.simantics.plant3d.ontology/graph/images/translate_d.svg [new file with mode: 0644]
org.simantics.plant3d.ontology/graph/plant3d.pgraph [new file with mode: 0644]
org.simantics.plant3d.ontology/graph/plant3d_builtins.pgraph [new file with mode: 0644]
org.simantics.plant3d.ontology/graph/plant3d_viewpoint.pgraph [new file with mode: 0644]
org.simantics.plant3d.ontology/src/org/simantics/plant3d/ontology/Plant3D.java [new file with mode: 0644]
org.simantics.plant3d.product.feature/.project [new file with mode: 0644]
org.simantics.plant3d.product.feature/build.properties [new file with mode: 0644]
org.simantics.plant3d.product.feature/feature.xml [new file with mode: 0644]
org.simantics.plant3d.product/.classpath [new file with mode: 0644]
org.simantics.plant3d.product/.gitignore [new file with mode: 0644]
org.simantics.plant3d.product/.project [new file with mode: 0644]
org.simantics.plant3d.product/.settings/org.eclipse.jdt.core.prefs [new file with mode: 0644]
org.simantics.plant3d.product/META-INF/MANIFEST.MF [new file with mode: 0644]
org.simantics.plant3d.product/build.properties [new file with mode: 0644]
org.simantics.plant3d.product/plant3d.product [new file with mode: 0644]
org.simantics.plant3d.product/plugin.xml [new file with mode: 0644]
org.simantics.plant3d.product/splash.bmp [new file with mode: 0644]
org.simantics.plant3d.product/src/org/simantics/plant3d/product/Activator.java [new file with mode: 0644]
org.simantics.plant3d/.classpath [new file with mode: 0644]
org.simantics.plant3d/.gitignore [new file with mode: 0644]
org.simantics.plant3d/.project [new file with mode: 0644]
org.simantics.plant3d/.settings/org.eclipse.jdt.core.prefs [new file with mode: 0644]
org.simantics.plant3d/META-INF/MANIFEST.MF [new file with mode: 0644]
org.simantics.plant3d/adapters.xml [new file with mode: 0644]
org.simantics.plant3d/build.properties [new file with mode: 0644]
org.simantics.plant3d/icons/Component.png [new file with mode: 0644]
org.simantics.plant3d/icons/Elbow.png [new file with mode: 0644]
org.simantics.plant3d/icons/Nozzle.png [new file with mode: 0644]
org.simantics.plant3d/icons/Straight.png [new file with mode: 0644]
org.simantics.plant3d/icons/factory.png [new file with mode: 0644]
org.simantics.plant3d/icons/middle.png [new file with mode: 0644]
org.simantics.plant3d/icons/middle.svg [new file with mode: 0644]
org.simantics.plant3d/icons/plus.png [new file with mode: 0644]
org.simantics.plant3d/icons/plus.svg [new file with mode: 0644]
org.simantics.plant3d/icons/tank.png [new file with mode: 0644]
org.simantics.plant3d/icons/translate.png [new file with mode: 0644]
org.simantics.plant3d/icons/translate_d.png [new file with mode: 0644]
org.simantics.plant3d/icons/x-axis.png [new file with mode: 0644]
org.simantics.plant3d/icons/x-axis.svg [new file with mode: 0644]
org.simantics.plant3d/icons/y-axis.png [new file with mode: 0644]
org.simantics.plant3d/icons/y-axis.svg [new file with mode: 0644]
org.simantics.plant3d/icons/z-axis.png [new file with mode: 0644]
org.simantics.plant3d/icons/z-axis.svg [new file with mode: 0644]
org.simantics.plant3d/plugin.xml [new file with mode: 0644]
org.simantics.plant3d/src/org/simantics/plant3d/Activator.java [new file with mode: 0644]
org.simantics.plant3d/src/org/simantics/plant3d/actions/AddComponentAction.java [new file with mode: 0644]
org.simantics.plant3d/src/org/simantics/plant3d/actions/AddEquipmentAction.java [new file with mode: 0644]
org.simantics.plant3d/src/org/simantics/plant3d/actions/AddNozzleAction.java [new file with mode: 0644]
org.simantics.plant3d/src/org/simantics/plant3d/actions/RoutePipeAction.java [new file with mode: 0644]
org.simantics.plant3d/src/org/simantics/plant3d/browser/P3DBrowser.java [new file with mode: 0644]
org.simantics.plant3d/src/org/simantics/plant3d/dialog/ComponentContentProvider.java [new file with mode: 0644]
org.simantics.plant3d/src/org/simantics/plant3d/dialog/ComponentLabelProvider.java [new file with mode: 0644]
org.simantics.plant3d/src/org/simantics/plant3d/dialog/ComponentSelectionDialog.java [new file with mode: 0644]
org.simantics.plant3d/src/org/simantics/plant3d/editor/P3DContentOutlinePage.java [new file with mode: 0644]
org.simantics.plant3d/src/org/simantics/plant3d/editor/P3DNodeMap.java [new file with mode: 0644]
org.simantics.plant3d/src/org/simantics/plant3d/editor/Plant3DEditor.java [new file with mode: 0644]
org.simantics.plant3d/src/org/simantics/plant3d/geometry/BallValveGeometryProvider.java [new file with mode: 0644]
org.simantics.plant3d/src/org/simantics/plant3d/geometry/BuiltinGeometryProvider.java [new file with mode: 0644]
org.simantics.plant3d/src/org/simantics/plant3d/geometry/CapGeometryProvider.java [new file with mode: 0644]
org.simantics.plant3d/src/org/simantics/plant3d/geometry/CheckValveGeometryProvider.java [new file with mode: 0644]
org.simantics.plant3d/src/org/simantics/plant3d/geometry/ElbowGeometryProvider.java [new file with mode: 0644]
org.simantics.plant3d/src/org/simantics/plant3d/geometry/HorizontalTankGeometryProvider.java [new file with mode: 0644]
org.simantics.plant3d/src/org/simantics/plant3d/geometry/NozzleGeometryProvider.java [new file with mode: 0644]
org.simantics.plant3d/src/org/simantics/plant3d/geometry/PumpGeometryProvider.java [new file with mode: 0644]
org.simantics.plant3d/src/org/simantics/plant3d/geometry/ReducerGeometryProvider.java [new file with mode: 0644]
org.simantics.plant3d/src/org/simantics/plant3d/geometry/StraightGeometryProvider.java [new file with mode: 0644]
org.simantics.plant3d/src/org/simantics/plant3d/geometry/VerticalTankGeometryProvider.java [new file with mode: 0644]
org.simantics.plant3d/src/org/simantics/plant3d/gizmo/SplitPointSelectionGizmo.java [new file with mode: 0644]
org.simantics.plant3d/src/org/simantics/plant3d/gizmo/TerminalSelectionGizmo.java [new file with mode: 0644]
org.simantics.plant3d/src/org/simantics/plant3d/handlers/NewPlantHandler.java [new file with mode: 0644]
org.simantics.plant3d/src/org/simantics/plant3d/project/P3DPerspectiveFactory.java [new file with mode: 0644]
org.simantics.plant3d/src/org/simantics/plant3d/project/P3DProjectFeature.java [new file with mode: 0644]
org.simantics.plant3d/src/org/simantics/plant3d/property/P3DSelectionProcessor.java [new file with mode: 0644]
org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/EndComponent.java [new file with mode: 0644]
org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/Equipment.java [new file with mode: 0644]
org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/GeometryNode.java [new file with mode: 0644]
org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/IP3DNode.java [new file with mode: 0644]
org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/IP3DVisualNode.java [new file with mode: 0644]
org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/InlineComponent.java [new file with mode: 0644]
org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/Nozzle.java [new file with mode: 0644]
org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/P3DNode.java [new file with mode: 0644]
org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/P3DParentGeometryNode.java [new file with mode: 0644]
org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/P3DParentNode.java [new file with mode: 0644]
org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/P3DRootNode.java [new file with mode: 0644]
org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/ParameterizedNode.java [new file with mode: 0644]
org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/PipeRun.java [new file with mode: 0644]
org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/PipelineComponent.java [new file with mode: 0644]
org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/SchemaBuilder.java [new file with mode: 0644]
org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/TurnComponent.java [new file with mode: 0644]
org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/controlpoint/ControlPointFactory.java [new file with mode: 0644]
org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/controlpoint/PipeControlPoint.java [new file with mode: 0644]
org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/controlpoint/PipingRules.java [new file with mode: 0644]
org.simantics.plant3d/src/org/simantics/plant3d/utils/ComponentUtils.java [new file with mode: 0644]
org.simantics.plant3d/src/org/simantics/plant3d/utils/Item.java [new file with mode: 0644]
org.simantics.plant3d/src/org/simantics/plant3d/utils/P3DUtil.java [new file with mode: 0644]

diff --git a/org.simantics.plant3d.modeling.feature/.project b/org.simantics.plant3d.modeling.feature/.project
new file mode 100644 (file)
index 0000000..e40eea0
--- /dev/null
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>org.simantics.plant3d.modeling.feature</name>
+       <comment></comment>
+       <projects>
+       </projects>
+       <buildSpec>
+               <buildCommand>
+                       <name>org.eclipse.pde.FeatureBuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+       </buildSpec>
+       <natures>
+               <nature>org.eclipse.pde.FeatureNature</nature>
+       </natures>
+</projectDescription>
diff --git a/org.simantics.plant3d.modeling.feature/build.properties b/org.simantics.plant3d.modeling.feature/build.properties
new file mode 100644 (file)
index 0000000..64f93a9
--- /dev/null
@@ -0,0 +1 @@
+bin.includes = feature.xml
diff --git a/org.simantics.plant3d.modeling.feature/feature.xml b/org.simantics.plant3d.modeling.feature/feature.xml
new file mode 100644 (file)
index 0000000..e307342
--- /dev/null
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<feature
+      id="org.simantics.plant3d.modeling"
+      label="Plant3D Feature"
+      version="1.0.0.qualifier"
+      provider-name="VTT">
+
+   <description url="http://www.example.com/description">
+      [Enter Feature Description here.]
+   </description>
+
+   <copyright url="http://www.example.com/copyright">
+      [Enter Copyright Description here.]
+   </copyright>
+
+   <license url="http://www.example.com/license">
+      [Enter License Description here.]
+   </license>
+
+   <includes
+         id="org.jcae.opencascade.lib"
+         version="0.0.0"/>
+
+   <includes
+         id="vtk.lib"
+         version="0.0.0"/>
+
+   <includes
+         id="org.simantics.modeling"
+         version="0.0.0"/>
+
+   <includes
+         id="org.simantics.issues.feature"
+         version="0.0.0"/>
+
+   <includes
+         id="org.simantics.issues.ui.feature"
+         version="0.0.0"/>
+
+   <includes
+         id="org.simantics.g3d.feature"
+         version="0.0.0"/>
+
+   <plugin
+         id="org.simantics.plant3d"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+   <plugin
+         id="org.simantics.plant3d.ontology"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+</feature>
diff --git a/org.simantics.plant3d.ontology/.classpath b/org.simantics.plant3d.ontology/.classpath
new file mode 100644 (file)
index 0000000..ad32c83
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
+       <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+       <classpathentry kind="src" path="src"/>
+       <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/org.simantics.plant3d.ontology/.gitignore b/org.simantics.plant3d.ontology/.gitignore
new file mode 100644 (file)
index 0000000..ae3c172
--- /dev/null
@@ -0,0 +1 @@
+/bin/
diff --git a/org.simantics.plant3d.ontology/.project b/org.simantics.plant3d.ontology/.project
new file mode 100644 (file)
index 0000000..bbacda4
--- /dev/null
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>org.simantics.plant3d.ontology</name>
+       <comment></comment>
+       <projects>
+       </projects>
+       <buildSpec>
+               <buildCommand>
+                       <name>org.simantics.graph.builder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.eclipse.jdt.core.javabuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.eclipse.pde.ManifestBuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.eclipse.pde.SchemaBuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+       </buildSpec>
+       <natures>
+               <nature>org.eclipse.pde.PluginNature</nature>
+               <nature>org.eclipse.jdt.core.javanature</nature>
+               <nature>org.simantics.graph.nature</nature>
+       </natures>
+</projectDescription>
diff --git a/org.simantics.plant3d.ontology/.settings/org.eclipse.jdt.core.prefs b/org.simantics.plant3d.ontology/.settings/org.eclipse.jdt.core.prefs
new file mode 100644 (file)
index 0000000..c537b63
--- /dev/null
@@ -0,0 +1,7 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.6
diff --git a/org.simantics.plant3d.ontology/META-INF/MANIFEST.MF b/org.simantics.plant3d.ontology/META-INF/MANIFEST.MF
new file mode 100644 (file)
index 0000000..f74fbe6
--- /dev/null
@@ -0,0 +1,19 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Plant3D Ontology
+Bundle-SymbolicName: org.simantics.plant3d.ontology
+Bundle-Version: 1.0.0.qualifier
+Bundle-Vendor: VTT
+Require-Bundle: org.eclipse.core.runtime,
+ org.simantics.layer0;bundle-version="1.1.0",
+ org.simantics.g3d.ontology;bundle-version="1.0.0",
+ org.simantics.simulation.ontology;bundle-version="1.1.0",
+ org.simantics.viewpoint.ontology;bundle-version="1.2.0",
+ org.simantics.g3d.csg.ontology;bundle-version="1.0.0",
+ org.simantics.structural.ontology;bundle-version="1.2.0",
+ org.simantics.action.ontology;bundle-version="1.1.0",
+ org.simantics.image2.ontology;bundle-version="1.2.0",
+ org.simantics.silk.ontology;bundle-version="1.1.0",
+ org.simantics.project.ontology;bundle-version="1.2.0"
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6
+Export-Package: org.simantics.plant3d.ontology
diff --git a/org.simantics.plant3d.ontology/build.properties b/org.simantics.plant3d.ontology/build.properties
new file mode 100644 (file)
index 0000000..e85b630
--- /dev/null
@@ -0,0 +1,5 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+               .,\
+               graph.tg
diff --git a/org.simantics.plant3d.ontology/graph/images/Component.png b/org.simantics.plant3d.ontology/graph/images/Component.png
new file mode 100644 (file)
index 0000000..0d43ef5
Binary files /dev/null and b/org.simantics.plant3d.ontology/graph/images/Component.png differ
diff --git a/org.simantics.plant3d.ontology/graph/images/Component.svg b/org.simantics.plant3d.ontology/graph/images/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.plant3d.ontology/graph/images/Elbow.png b/org.simantics.plant3d.ontology/graph/images/Elbow.png
new file mode 100644 (file)
index 0000000..bbaa16e
Binary files /dev/null and b/org.simantics.plant3d.ontology/graph/images/Elbow.png differ
diff --git a/org.simantics.plant3d.ontology/graph/images/Elbow.svg b/org.simantics.plant3d.ontology/graph/images/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.plant3d.ontology/graph/images/Nozzle.png b/org.simantics.plant3d.ontology/graph/images/Nozzle.png
new file mode 100644 (file)
index 0000000..48cf03e
Binary files /dev/null and b/org.simantics.plant3d.ontology/graph/images/Nozzle.png differ
diff --git a/org.simantics.plant3d.ontology/graph/images/Nozzle.svg b/org.simantics.plant3d.ontology/graph/images/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.plant3d.ontology/graph/images/Straight.png b/org.simantics.plant3d.ontology/graph/images/Straight.png
new file mode 100644 (file)
index 0000000..459919e
Binary files /dev/null and b/org.simantics.plant3d.ontology/graph/images/Straight.png differ
diff --git a/org.simantics.plant3d.ontology/graph/images/Straight.svg b/org.simantics.plant3d.ontology/graph/images/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.plant3d.ontology/graph/images/eye.png b/org.simantics.plant3d.ontology/graph/images/eye.png
new file mode 100644 (file)
index 0000000..0e78cfd
Binary files /dev/null and b/org.simantics.plant3d.ontology/graph/images/eye.png differ
diff --git a/org.simantics.plant3d.ontology/graph/images/eye.svg b/org.simantics.plant3d.ontology/graph/images/eye.svg
new file mode 100644 (file)
index 0000000..cfb5620
--- /dev/null
@@ -0,0 +1,122 @@
+<?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="100"
+   height="100"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.44"
+   version="1.0"
+   sodipodi:docname="eye.svg"
+   sodipodi:docbase="D:\dev\icons"
+   inkscape:export-filename="D:\dev\icons\eye.png"
+   inkscape:export-xdpi="14.4"
+   inkscape:export-ydpi="14.4">
+  <defs
+     id="defs4">
+    <linearGradient
+       id="linearGradient4583">
+      <stop
+         style="stop-color:#0049ff;stop-opacity:1;"
+         offset="0"
+         id="stop4585" />
+      <stop
+         style="stop-color:#00b3b3;stop-opacity:1;"
+         offset="1"
+         id="stop4587" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3686">
+      <stop
+         style="stop-color:red;stop-opacity:0;"
+         offset="0"
+         id="stop3688" />
+      <stop
+         style="stop-color:red;stop-opacity:1;"
+         offset="1"
+         id="stop3690" />
+    </linearGradient>
+    <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>
+  </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="50"
+     inkscape:cy="59.95985"
+     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:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:8;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
+       d="M 10,50 C 35.054042,24.945958 64.998554,24.998554 90,50 C 65.010416,74.989584 35.029348,75.029348 10,50 z "
+       id="path3694"
+       sodipodi:nodetypes="ccc" />
+    <path
+       sodipodi:type="arc"
+       style="fill:#009bff;fill-opacity:1;stroke:#009aff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="path3696"
+       sodipodi:cx="50"
+       sodipodi:cy="50"
+       sodipodi:rx="15"
+       sodipodi:ry="15"
+       d="M 65 50 A 15 15 0 1 1  35,50 A 15 15 0 1 1  65 50 z" />
+    <path
+       sodipodi:type="arc"
+       style="fill:black;fill-opacity:1;stroke:black;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="path5476"
+       sodipodi:cx="50"
+       sodipodi:cy="50"
+       sodipodi:rx="4"
+       sodipodi:ry="4"
+       d="M 54 50 A 4 4 0 1 1  46,50 A 4 4 0 1 1  54 50 z" />
+  </g>
+</svg>
diff --git a/org.simantics.plant3d.ontology/graph/images/factory.png b/org.simantics.plant3d.ontology/graph/images/factory.png
new file mode 100644 (file)
index 0000000..aad23e3
Binary files /dev/null and b/org.simantics.plant3d.ontology/graph/images/factory.png differ
diff --git a/org.simantics.plant3d.ontology/graph/images/factory.svg b/org.simantics.plant3d.ontology/graph/images/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.plant3d.ontology/graph/images/point.png b/org.simantics.plant3d.ontology/graph/images/point.png
new file mode 100644 (file)
index 0000000..54bf5e4
Binary files /dev/null and b/org.simantics.plant3d.ontology/graph/images/point.png differ
diff --git a/org.simantics.plant3d.ontology/graph/images/point.svg b/org.simantics.plant3d.ontology/graph/images/point.svg
new file mode 100644 (file)
index 0000000..ee80b68
--- /dev/null
@@ -0,0 +1,112 @@
+<?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://inkscape.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.43"
+   sodipodi:docbase="D:\icons"
+   sodipodi:docname="point.svg"
+   inkscape:export-filename="D:\icons\point.png"
+   inkscape:export-xdpi="14.239033"
+   inkscape:export-ydpi="14.239033">
+  <defs
+     id="defs4">
+    <linearGradient
+       id="linearGradient2185">
+      <stop
+         style="stop-color:#000000;stop-opacity:1;"
+         offset="0"
+         id="stop2187" />
+      <stop
+         style="stop-color:#8b8386;stop-opacity:1;"
+         offset="1"
+         id="stop2189" />
+    </linearGradient>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2185"
+       id="radialGradient2191"
+       cx="84.418854"
+       cy="1015.6063"
+       fx="84.418854"
+       fy="1015.6063"
+       r="43.646465"
+       gradientTransform="matrix(1,0,0,0.56088,0,445.9732)"
+       gradientUnits="userSpaceOnUse" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="7.9306931"
+     inkscape:cx="50"
+     inkscape:cy="50"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     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:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       id="rect2180"
+       width="100"
+       height="100"
+       x="0"
+       y="952.36218" />
+    <path
+       sodipodi:type="arc"
+       style="fill:url(#radialGradient2191);fill-opacity:1.0;stroke:#000000;stroke-width:5.71116147;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="path1310"
+       sodipodi:cx="84.418854"
+       sodipodi:cy="1015.6063"
+       sodipodi:rx="40.790886"
+       sodipodi:ry="21.624844"
+       d="M 125.20974 1015.6063 A 40.790886 21.624844 0 1 1  43.627968,1015.6063 A 40.790886 21.624844 0 1 1  125.20974 1015.6063 z"
+       transform="matrix(0.509861,0,0,0.962098,6.958081,25.24936)" />
+    <path
+       style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:15.00183201;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="M 12.500916,1002.2352 C 12.501295,1002.2352 12.501299,1002.2352 12.501299,1002.2352"
+       id="path2193" />
+    <path
+       style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:15.00483513;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="M 87.502418,1002.3598 C 87.50283,1002.3598 87.502834,1002.3598 87.502834,1002.3598"
+       id="path1315" />
+    <path
+       style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:15.0117321;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="M 50.005866,1039.8563 C 50.005866,1039.8561 50.005866,1039.8561 50.005866,1039.8561"
+       id="path1317" />
+    <path
+       style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:15.00583363;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="M 50.002917,964.85927 C 50.002917,964.85904 50.002917,964.85904 50.002917,964.85904"
+       id="path1319" />
+  </g>
+</svg>
diff --git a/org.simantics.plant3d.ontology/graph/images/rotate.png b/org.simantics.plant3d.ontology/graph/images/rotate.png
new file mode 100644 (file)
index 0000000..bcc829f
Binary files /dev/null and b/org.simantics.plant3d.ontology/graph/images/rotate.png differ
diff --git a/org.simantics.plant3d.ontology/graph/images/rotate.svg b/org.simantics.plant3d.ontology/graph/images/rotate.svg
new file mode 100644 (file)
index 0000000..1b8d04b
--- /dev/null
@@ -0,0 +1,108 @@
+<?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://inkscape.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.43"
+   version="1.0"
+   inkscape:export-filename="C:\Documents and Settings\Make\Desktop\rotate.png"
+   inkscape:export-xdpi="14"
+   inkscape:export-ydpi="14"
+   sodipodi:docname="rotate.svg"
+   sodipodi:docbase="C:\Documents and Settings\Make\Desktop">
+  <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" />
+  </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="50"
+     inkscape:cy="52.718966"
+     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(#linearGradient2190);fill-opacity:1.0;fill-rule:nonzero;stroke:#009c00;stroke-width:4;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       d="M 50.15,10.00577 C 27.990385,10.00577 10.00577,27.990385 10.00577,50.15 C 10.00577,72.309615 27.990385,90.29423 50.15,90.29423 C 61.229808,90.29423 71.260847,85.793059 78.526954,78.526954 L 64.351021,64.351021 C 60.717969,67.984074 55.689904,70.222115 50.15,70.222115 C 39.070192,70.222115 30.077885,61.229808 30.077885,50.15 C 30.077885,39.070192 39.070192,30.077885 50.15,30.077885 C 55.689904,30.077885 60.717969,32.315926 64.351021,35.948979 L 50.15,50.15 L 90.29423,50.15 L 90.29423,10.00577 L 78.526954,21.773046 C 71.260847,14.506941 61.229808,10.00577 50.15,10.00577 z "
+       id="path2162"
+       inkscape:export-xdpi="14"
+       inkscape:export-ydpi="14" />
+  </g>
+</svg>
diff --git a/org.simantics.plant3d.ontology/graph/images/tank.png b/org.simantics.plant3d.ontology/graph/images/tank.png
new file mode 100644 (file)
index 0000000..44015a3
Binary files /dev/null and b/org.simantics.plant3d.ontology/graph/images/tank.png differ
diff --git a/org.simantics.plant3d.ontology/graph/images/tank.svg b/org.simantics.plant3d.ontology/graph/images/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.plant3d.ontology/graph/images/translate.png b/org.simantics.plant3d.ontology/graph/images/translate.png
new file mode 100644 (file)
index 0000000..21f5284
Binary files /dev/null and b/org.simantics.plant3d.ontology/graph/images/translate.png differ
diff --git a/org.simantics.plant3d.ontology/graph/images/translate.svg b/org.simantics.plant3d.ontology/graph/images/translate.svg
new file mode 100644 (file)
index 0000000..b600c2f
--- /dev/null
@@ -0,0 +1,117 @@
+<?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="C:\Documents and Settings\Make\Desktop\rotate.png"
+   inkscape:export-xdpi="14"
+   inkscape:export-ydpi="14"
+   sodipodi:docname="translate.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="39.637306"
+     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 49.935233,9.5929652 L 33.746512,25.781686 L 41.840873,25.781686 L 41.840873,41.970406 L 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 41.840873,58.159127 L 41.840873,74.347847 L 33.746512,74.347847 L 49.935233,90.536568 L 66.123954,74.347847 L 58.029594,74.347847 L 58.029594,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 58.029594,41.970406 L 58.029594,25.781686 L 66.123954,25.781686 L 49.935233,9.5929652 z "
+       id="path1879" />
+  </g>
+</svg>
diff --git a/org.simantics.plant3d.ontology/graph/images/translate_d.png b/org.simantics.plant3d.ontology/graph/images/translate_d.png
new file mode 100644 (file)
index 0000000..f4b3b60
Binary files /dev/null and b/org.simantics.plant3d.ontology/graph/images/translate_d.png differ
diff --git a/org.simantics.plant3d.ontology/graph/images/translate_d.svg b/org.simantics.plant3d.ontology/graph/images/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.plant3d.ontology/graph/plant3d.pgraph b/org.simantics.plant3d.ontology/graph/plant3d.pgraph
new file mode 100644 (file)
index 0000000..8edc9f6
--- /dev/null
@@ -0,0 +1,158 @@
+L0 = <http://www.simantics.org/Layer0-1.1>
+PROJ = <http://www.simantics.org/Project-1.2>
+SIM = <http://www.simantics.org/Simulation-1.1>
+//STR = <http://www.simantics.org/Structural-1.2>
+G3D = <http://www.simantics.org/G3D-0.1>
+
+P3D = <http://www.simantics.org/Plant3D-0.1> : L0.Ontology
+    @L0.new
+    L0.HasResourceClass "org.simantics.plant3d.ontology.Plant3D" : L0.String
+    
+P3D.ImportedOntologies : PROJ.NamespaceRequirement
+    L0.HasDescription "Specifies the ontologies required by a Plant3D Feature." : L0.String
+    PROJ.RequiresNamespace
+        "http://www.simantics.org/Layer0-1.0" : L0.URI
+        "http://www.simantics.org/Simulation-1.0" : L0.URI
+        
+P3D.Node <T G3D.Node 
+  
+P3D.Plant <T G3D.RootNode <T P3D.Node
+
+
+P3D.childen <R G3D.children
+
+P3D.hasGeometry <R L0.IsWeaklyRelatedTo
+   
+P3D.LibraryComponent <T P3D.Node
+
+P3D.Equipment <T P3D.LibraryComponent
+
+P3D.PipeRun <T P3D.Node
+
+P3D.PipelineComponent <T P3D.LibraryComponent
+
+P3D.Nozzle <T P3D.LibraryComponent
+    //[HasPipeDiameter card "1"]
+    //[HasLength card "1"]
+
+P3D.PipelineComponentTag <R L0.IsWeaklyRelatedTo
+
+P3D.SingleConnectedComponent <R P3D.PipelineComponentTag 
+    L0.HasDescription "A component that is connected to only one component" : L0.String
+P3D.DualConnectedComponent <R P3D.PipelineComponentTag 
+    L0.HasDescription "A component that is connected to two components" : L0.String
+P3D.MultiConnectedComponent <R P3D.PipelineComponentTag 
+    L0.HasDescription "A component that is connected to more than two components" : L0.String
+
+P3D.InlineComponent <T P3D.PipelineComponent
+    L0.HasDescription "Component that connects to two or more components, and maintains direction of (main) pipe run. Centerline of main pipeline may have offset: with offset there is two control points for main pipeline, and without offset, there is only one control point for main pipeline. The component may also join two pipe runs together: then there is always one control point for one pipe run." : L0.String
+    //[HasLength card "1"]
+P3D.EndComponent <T P3D.PipelineComponent
+    L0.HasDescription "Component that ends the pipe run Component may contain other control points" : L0.String
+P3D.TurnComponent <T P3D.PipelineComponent
+    L0.HasDescription "Component that changes direction of the pipeline Component that connects to two or more components, and specifies connectivity of main pipe run. Is base type for elbows, pipe bends, etc., but also for components that won't maintain main pipeline direction (inline component). CHECK!!!" : L0.String
+    //[HasTurnAngle card "1"]
+    
+P3D.FixedLengthInlineComponent <R P3D.PipelineComponentTag
+    L0.HasDescription "Inline component that has fixed length" : L0.String
+    //[HasRotationAngle card "1"]
+P3D.VariableLengthInlineComponent <R P3D.PipelineComponentTag
+    L0.HasDescription "Inline component whose length can be changed" : L0.String
+P3D.FixedAngleTurnComponent <R P3D.PipelineComponentTag
+    L0.HasDescription "Turn Component that has specific turning angle that cannot be changed" : L0.String
+    //[HasRotationAngle card "1"]
+P3D.VariableAngleTurnComponent <R P3D.PipelineComponentTag
+    L0.HasDescription "Turn Component whose turning angle can be modified Contains always one control point (there are no contradictory cases / how to calculate?)" : L0.String
+    //[HasTurnRadius card "1"]
+P3D.SizeChangeComponent <R P3D.PipelineComponentTag
+    L0.HasDescription "Component that changes pipe run along main pipeline. (Spec change)" : L0.String
+P3D.OffsetComponent<R P3D.PipelineComponentTag
+    L0.HasDescription "Component that offsets the center of piperun." : L0.String  
+P3D.CodeComponent <T P3D.PipelineComponentTag
+    L0.HasDescription "Compoenent that cannot be added directly by user" : L0.String
+P3D.NonVisibleComponent <R P3D.PipelineComponentTag
+    L0.HasDescription "(Pseudo) Component that cannot bee seen." : L0.String
+
+    
+
+
+// relation and property definitions
+
+P3D.Connects <R L0.IsWeaklyRelatedTo
+    L0.HasDomain P3D.PipelineComponent
+    L0.HasRange P3D.PipelineComponent
+P3D.HasNext <R P3D.Connects
+    L0.HasDescription "Next point in the piperun" : L0.String
+    L0.InverseOf P3D.NextInverse <R L0.IsWeaklyRelatedTo
+P3D.HasPrevious <R P3D.Connects
+    L0.HasDescription "Previous point in the piperun" : L0.String
+    L0.InverseOf P3D.PreviousInverse <R L0.IsWeaklyRelatedTo
+// connections for branches (Objmap requires separate relations!?)
+P3D.HasBranch0 <R P3D.Connects
+P3D.HasBranch1 <R P3D.Connects
+P3D.HasBranch2 <R P3D.Connects
+P3D.HasBranch3 <R P3D.Connects
+P3D.HasBranch4 <R P3D.Connects
+P3D.HasBranch5 <R P3D.Connects
+P3D.HasBranch6 <R P3D.Connects
+P3D.HasBranch7 <R P3D.Connects
+P3D.HasBranch8 <R P3D.Connects
+P3D.HasBranch9 <R P3D.Connects
+    
+P3D.HasPipeDiameter <R G3D.hasNonTransformation
+    L0.HasRange L0.Double
+//P3D.HasLength <R G3D.hasNonTransformation
+//    L0.HasRange L0.Double
+//P3D.HasTurnAngle <R G3D.hasNonTransformation
+//    L0.HasRange L0.Double
+//P3D.HasRotationAngle <R G3D.hasTransformation
+//    L0.HasRange L0.Double
+//P3D.HasOffset <R L0.HasProperty
+//    L0.HasRange L0.Double
+//HasRelativePosition <R HasProperty
+//    HasRange [Position]
+//HasRelativeDirection <R HasProperty
+//    HasRange [Tuple3]
+//HasDirection <R HasProperty
+//    HasRange [Tuple3]  
+P3D.HasTurnRadius <R G3D.hasNonTransformation
+    L0.HasRange L0.Double   
+P3D.IsReversed <R L0.HasProperty
+    L0.HasRange L0.Boolean
+P3D.HasTurnAxis <R G3D.hasTransformation
+    L0.HasRange G3D.Tuple3D
+    
+P3D.HasNozzleDefinition <R L0.HasProperty
+    L0.HasDomain P3D.Equipment
+    L0.HasRange P3D.Nozzle
+    L0.HasDescription "This relation is used to connect nozzles to equipment in the template. For instantiated equipment nozzles must be connected with HasNozzle relation." : L0.String  
+P3D.HasNozzle <R G3D.children
+    L0.InverseOf P3D.NozzleOf
+    L0.HasDomain P3D.Equipment
+    L0.HasRange P3D.Nozzle
+    L0.HasDescription "Used to connect nozzles to equipment." : L0.String
+P3D.HasNozzleRestriction <R L0.HasProperty
+    L0.HasDescription "Used in template equipment to restrict amount of nozzles. If template has as many nozzleDefinitions that maximum count in this restriction, user cannot add new nozzles to the equipment instance." : L0.String
+
+P3D.HasNozzleId <R L0.HasProperty
+    L0.HasDomain P3D.Nozzle
+    L0.HasRange L0.Integer
+
+P3D.HasPipeRun <R L0.IsWeaklyRelatedTo
+    L0.HasDomain P3D.Nozzle
+    L0.HasRange P3D.PipeRun
+    
+P3D.HasAlternativePipeRun <R L0.IsRelatedTo
+    L0.HasDomain P3D.PipelineComponent
+    L0.HasRange P3D.PipeRun
+    
+P3D.Parameter <T L0.Entity
+    
+P3D.hasParameter <R L0.IsRelatedTo
+   L0.HasDomain P3D.Node
+   L0.HasRange P3D.Parameter    
+    
+P3D.hasParameterValue <R L0.IsRelatedTo : L0.FunctionalRelation
+   L0.HasDomain P3D.Parameter
+   L0.HasRange L0.Literal
+   
\ No newline at end of file
diff --git a/org.simantics.plant3d.ontology/graph/plant3d_builtins.pgraph b/org.simantics.plant3d.ontology/graph/plant3d_builtins.pgraph
new file mode 100644 (file)
index 0000000..5c38687
--- /dev/null
@@ -0,0 +1,124 @@
+L0 = <http://www.simantics.org/Layer0-1.1>
+P3D = <http://www.simantics.org/Plant3D-0.1>
+
+
+P3D.Builtin : L0.Library
+
+P3D.Builtin.GeometryProvider <T L0.Entity
+P3D.Builtin.NozzleGeometryProvider : P3D.Builtin.GeometryProvider
+P3D.Builtin.HorizontalTankGeometryProvider : P3D.Builtin.GeometryProvider
+P3D.Builtin.VerticalTankGeometryProvider : P3D.Builtin.GeometryProvider
+P3D.Builtin.StraightGeometryProvider : P3D.Builtin.GeometryProvider
+P3D.Builtin.ElbowGeometryProvider : P3D.Builtin.GeometryProvider
+P3D.Builtin.ReducerGeometryProvider : P3D.Builtin.GeometryProvider
+P3D.Builtin.PumpGeometryProvider : P3D.Builtin.GeometryProvider
+P3D.Builtin.BallValveGeometryProvider : P3D.Builtin.GeometryProvider
+P3D.Builtin.CheckValveGeometryProvider : P3D.Builtin.GeometryProvider
+P3D.Builtin.CapGeometryProvider : P3D.Builtin.GeometryProvider
+
+P3D.Builtin.ConcentricReducer <T P3D.InlineComponent : P3D.InlineComponent
+    @L0.assert P3D.hasGeometry P3D.Builtin.ReducerGeometryProvider
+    @L0.tag P3D.SizeChangeComponent
+    @L0.tag P3D.FixedLengthInlineComponent
+    @L0.tag P3D.DualConnectedComponent
+//  HasRotationAngle "0.0" : Double
+//  HasControlPoint 
+//    _ : SizeChangeControlPoint
+P3D.Builtin.EccentricReducer <T P3D.InlineComponent : P3D.InlineComponent 
+    @L0.tag P3D.OffsetComponent
+    @L0.tag P3D.SizeChangeComponent
+    @L0.tag P3D.FixedLengthInlineComponent
+    @L0.tag P3D.DualConnectedComponent
+//  HasRotationAngle "0.0" : Double
+//  HasControlPoint 
+//    _ : SizeChangeControlPoint : OffsettingPoint
+P3D.Builtin.Elbow <T P3D.TurnComponent : P3D.TurnComponent  
+    @L0.tag P3D.VariableAngleTurnComponent
+    @L0.tag P3D.DualConnectedComponent
+    @L0.assert P3D.hasGeometry P3D.Builtin.ElbowGeometryProvider
+//  HasLength "0.0" : Double
+//  HasTurnRadius "0.0" : Double
+//  HasTurnAngle "0.0" : Double
+//  HasControlPoint 
+//    _ : VariableAngleTurnControlPoint
+P3D.Builtin.Straight <T P3D.InlineComponent : P3D.InlineComponent
+    @L0.tag P3D.DualConnectedComponent
+    @L0.tag P3D.VariableLengthInlineComponent
+    @L0.assert P3D.hasGeometry P3D.Builtin.StraightGeometryProvider
+//  HasLength "0.0" : Double
+//  HasControlPoint 
+//    _ : VariableLengthControlPoint
+P3D.Builtin.BranchSplitComponent <T P3D.InlineComponent : P3D.InlineComponent
+    @L0.tag P3D.CodeComponent
+    @L0.tag P3D.FixedLengthInlineComponent
+    @L0.tag P3D.NonVisibleComponent
+//  HasLength "0.0" : Double          
+//  HasControlPoint
+//    _ : BranchControlPoint
+//P3D.Builtin.Vessel : P3D.Equipment
+//    @L0.tag L0.Abstract
+//P3D.Builtin.VerticalVessel <T P3D.Builtin.Vessel
+    //[HasHeight card "1"]
+//P3D.Builtin.HorizontalVessel <T P3D.Builtin.Vessel
+    //[HasLength card "1"]
+    
+    
+P3D.Builtin.Nozzle <T P3D.Nozzle : P3D.Nozzle
+      @L0.assert P3D.hasGeometry P3D.Builtin.NozzleGeometryProvider
+P3D.Builtin.HorizontalTank <T P3D.Equipment : P3D.Equipment
+     @L0.assert P3D.hasGeometry P3D.Builtin.HorizontalTankGeometryProvider
+     @L0.assert P3D.hasParameter
+         _ :P3D.Parameter
+           L0.HasName "radius" : L0.String
+           P3D.hasParameterValue 0.2 : L0.Double
+     @L0.assert P3D.hasParameter
+         _ :P3D.Parameter
+           L0.HasName "length" : L0.String
+           P3D.hasParameterValue 1.0 : L0.Double
+P3D.Builtin.VerticalTank <T P3D.Equipment : P3D.Equipment
+     @L0.assert P3D.hasGeometry P3D.Builtin.VerticalTankGeometryProvider
+     @L0.assert P3D.hasParameter
+         _ :P3D.Parameter
+           L0.HasName "radius" : L0.String
+           P3D.hasParameterValue 0.2 : L0.Double
+     @L0.assert P3D.hasParameter
+         _ :P3D.Parameter
+           L0.HasName "height" : L0.String
+           P3D.hasParameterValue 1.0 : L0.Double
+P3D.Builtin.Pump <T P3D.Equipment : P3D.Equipment
+     @L0.assert P3D.hasGeometry P3D.Builtin.PumpGeometryProvider
+     @L0.assert P3D.hasParameter
+         _ :P3D.Parameter
+           L0.HasName "width" : L0.String
+           P3D.hasParameterValue 0.25 : L0.Double
+     @L0.assert P3D.hasParameter
+         _ :P3D.Parameter
+           L0.HasName "length" : L0.String
+           P3D.hasParameterValue 0.5 : L0.Double
+           
+P3D.Builtin.BallValve <T P3D.InlineComponent : P3D.InlineComponent
+    @L0.tag P3D.DualConnectedComponent
+    @L0.tag P3D.FixedLengthInlineComponent
+    @L0.assert P3D.hasGeometry P3D.Builtin.BallValveGeometryProvider
+    @L0.assert P3D.hasParameter
+         _ :P3D.Parameter
+           L0.HasName "radius" : L0.String
+           P3D.hasParameterValue 0.1 : L0.Double
+           
+P3D.Builtin.CheckValve <T P3D.InlineComponent : P3D.InlineComponent
+    @L0.tag P3D.DualConnectedComponent
+    @L0.tag P3D.FixedLengthInlineComponent
+    @L0.assert P3D.hasGeometry P3D.Builtin.CheckValveGeometryProvider
+    @L0.assert P3D.hasParameter
+         _ :P3D.Parameter
+           L0.HasName "radius" : L0.String
+           P3D.hasParameterValue 0.1 : L0.Double
+           
+P3D.Builtin.Cap <T P3D.EndComponent : P3D.InlineComponent
+    @L0.assert P3D.hasGeometry P3D.Builtin.CapGeometryProvider
+    @L0.assert P3D.hasParameter
+         _ :P3D.Parameter
+           L0.HasName "radius" : L0.String
+           P3D.hasParameterValue 0.1 : L0.Double
+     
diff --git a/org.simantics.plant3d.ontology/graph/plant3d_viewpoint.pgraph b/org.simantics.plant3d.ontology/graph/plant3d_viewpoint.pgraph
new file mode 100644 (file)
index 0000000..c2d02ad
--- /dev/null
@@ -0,0 +1,73 @@
+L0 = <http://www.simantics.org/Layer0-1.1>
+VP = <http://www.simantics.org/Viewpoint-1.2>
+PROJ = <http://www.simantics.org/Project-1.2>
+SIM = <http://www.simantics.org/Simulation-1.1>
+IMAGE = <http://www.simantics.org/Image2-1.2>
+ACT = <http://www.simantics.org/Action-1.1>
+P3D = <http://www.simantics.org/Plant3D-0.1>
+CSG = <http://www.simantics.org/CSG-0.1>
+SILK = <http://www.simantics.org/Silk-1.1>
+
+
+PBC = P3D.P3DBrowseContext : VP.BrowseContext
+    VP.BrowseContext.IsIncludedIn PROJ.ProjectBrowseContext
+    @VP.constantImageRule P3D.Plant IMAGES.Factory
+    @VP.constantImageRule P3D.Equipment IMAGES.Tank
+    @VP.constantImageRule P3D.TurnComponent IMAGES.Elbow
+    @VP.constantImageRule P3D.Nozzle IMAGES.Nozzle
+    @VP.constantImageRule P3D.InlineComponent IMAGES.Component
+    @VP.constantImageRule P3D.Builtin.Straight IMAGES.Straight
+    @VP.constantImageRule P3D.EndComponent IMAGES.Component
+    @VP.constantImageRule P3D.PipeRun IMAGES.Straight
+    @VP.relationChildRule PROJ.Project L0.ConsistsOf P3D.Plant
+    @VP.relationChildRule P3D.Node P3D.childen P3D.Node
+    @VP.relationChildRule P3D.Node P3D.HasNozzle P3D.Node
+
+
+IMAGES = P3D.Images : L0.Library
+IMAGES.Component : IMAGE.PngImage
+    @L0.loadBytes "images/Component.png"
+IMAGES.Elbow : IMAGE.PngImage
+    @L0.loadBytes "images/Elbow.png"
+IMAGES.Factory : IMAGE.PngImage
+    @L0.loadBytes "images/factory.png"
+IMAGES.Nozzle : IMAGE.PngImage
+    @L0.loadBytes "images/Nozzle.png"
+IMAGES.Straight : IMAGE.PngImage
+    @L0.loadBytes "images/Straight.png"
+IMAGES.Tank : IMAGE.PngImage
+    @L0.loadBytes "images/tank.png"
+    
+MAC = P3D.P3DActionContext : VP.BrowseContext
+    VP.BrowseContext.IsIncludedIn PROJ.ProjectActionContext    
+
+
+MAC.newContribution : L0.Template
+    @template %actionContext %label %action %image
+        %actionContext
+            VP.BrowseContext.HasActionContribution _ : VP.ActionContribution
+                L0.HasLabel %label
+                VP.ActionContribution.HasImage %image
+                VP.ActionContribution.HasCategory VP.NewActionCategory
+                VP.ActionContribution.HasNodeType P3D.Plant
+                VP.ActionContribution.HasAction %action
+    
+MAC.newTypeContribution : L0.Template
+    @template %actionContext %label %action %type %image
+        %actionContext
+            VP.BrowseContext.HasActionContribution _ : VP.ActionContribution
+                L0.HasLabel %label
+                VP.ActionContribution.HasImage %image
+                VP.ActionContribution.HasCategory VP.NewActionCategory
+                VP.ActionContribution.HasNodeType %type
+                VP.ActionContribution.HasAction %action
+                
+MAC.editTypeContribution : L0.Template
+    @template %actionContext %label %action %type %image
+        %actionContext
+            VP.BrowseContext.HasActionContribution _ : VP.ActionContribution
+                L0.HasLabel %label
+                VP.ActionContribution.HasImage %image
+                VP.ActionContribution.HasCategory VP.EditActionCategory
+                VP.ActionContribution.HasNodeType %type
+                VP.ActionContribution.HasAction %action
\ No newline at end of file
diff --git a/org.simantics.plant3d.ontology/src/org/simantics/plant3d/ontology/Plant3D.java b/org.simantics.plant3d.ontology/src/org/simantics/plant3d/ontology/Plant3D.java
new file mode 100644 (file)
index 0000000..394da93
--- /dev/null
@@ -0,0 +1,349 @@
+package org.simantics.plant3d.ontology;
+
+import org.simantics.db.RequestProcessor;
+import org.simantics.db.Resource;
+import org.simantics.db.ReadGraph;
+import org.simantics.db.request.Read;
+import org.simantics.db.Session;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.service.QueryControl;
+
+public class Plant3D {
+    
+    public final Resource Builtin;
+    public final Resource Builtin_BallValve;
+    public final Resource Builtin_BallValveGeometryProvider;
+    public final Resource Builtin_BranchSplitComponent;
+    public final Resource Builtin_Cap;
+    public final Resource Builtin_CapGeometryProvider;
+    public final Resource Builtin_CheckValve;
+    public final Resource Builtin_CheckValveGeometryProvider;
+    public final Resource Builtin_ConcentricReducer;
+    public final Resource Builtin_EccentricReducer;
+    public final Resource Builtin_Elbow;
+    public final Resource Builtin_ElbowGeometryProvider;
+    public final Resource Builtin_GeometryProvider;
+    public final Resource Builtin_HorizontalTank;
+    public final Resource Builtin_HorizontalTankGeometryProvider;
+    public final Resource Builtin_Nozzle;
+    public final Resource Builtin_NozzleGeometryProvider;
+    public final Resource Builtin_Pump;
+    public final Resource Builtin_PumpGeometryProvider;
+    public final Resource Builtin_ReducerGeometryProvider;
+    public final Resource Builtin_Straight;
+    public final Resource Builtin_StraightGeometryProvider;
+    public final Resource Builtin_VerticalTank;
+    public final Resource Builtin_VerticalTankGeometryProvider;
+    public final Resource CodeComponent;
+    public final Resource Connects;
+    public final Resource DualConnectedComponent;
+    public final Resource EndComponent;
+    public final Resource Equipment;
+    public final Resource FixedAngleTurnComponent;
+    public final Resource FixedLengthInlineComponent;
+    public final Resource HasAlternativePipeRun;
+    public final Resource HasBranch0;
+    public final Resource HasBranch1;
+    public final Resource HasBranch2;
+    public final Resource HasBranch3;
+    public final Resource HasBranch4;
+    public final Resource HasBranch5;
+    public final Resource HasBranch6;
+    public final Resource HasBranch7;
+    public final Resource HasBranch8;
+    public final Resource HasBranch9;
+    public final Resource HasNext;
+    public final Resource HasNozzle;
+    public final Resource HasNozzleDefinition;
+    public final Resource HasNozzleDefinition_Inverse;
+    public final Resource HasNozzleId;
+    public final Resource HasNozzleId_Inverse;
+    public final Resource HasNozzleRestriction;
+    public final Resource HasNozzleRestriction_Inverse;
+    public final Resource HasPipeDiameter;
+    public final Resource HasPipeDiameter_Inverse;
+    public final Resource HasPipeRun;
+    public final Resource HasPrevious;
+    public final Resource HasTurnAxis;
+    public final Resource HasTurnAxis_Inverse;
+    public final Resource HasTurnRadius;
+    public final Resource HasTurnRadius_Inverse;
+    public final Resource Images;
+    public final Resource Images_Component;
+    public final Resource Images_Elbow;
+    public final Resource Images_Factory;
+    public final Resource Images_Nozzle;
+    public final Resource Images_Straight;
+    public final Resource Images_Tank;
+    public final Resource ImportedOntologies;
+    public final Resource InlineComponent;
+    public final Resource IsReversed;
+    public final Resource IsReversed_Inverse;
+    public final Resource LibraryComponent;
+    public final Resource MultiConnectedComponent;
+    public final Resource NextInverse;
+    public final Resource Node;
+    public final Resource NonVisibleComponent;
+    public final Resource Nozzle;
+    public final Resource NozzleOf;
+    public final Resource OffsetComponent;
+    public final Resource P3DActionContext;
+    public final Resource P3DActionContext_editTypeContribution;
+    public final Resource P3DActionContext_newContribution;
+    public final Resource P3DActionContext_newTypeContribution;
+    public final Resource P3DBrowseContext;
+    public final Resource Parameter;
+    public final Resource PipeRun;
+    public final Resource PipelineComponent;
+    public final Resource PipelineComponentTag;
+    public final Resource Plant;
+    public final Resource PreviousInverse;
+    public final Resource SingleConnectedComponent;
+    public final Resource SizeChangeComponent;
+    public final Resource TurnComponent;
+    public final Resource VariableAngleTurnComponent;
+    public final Resource VariableLengthInlineComponent;
+    public final Resource childen;
+    public final Resource childen_Inverse;
+    public final Resource hasGeometry;
+    public final Resource hasParameter;
+    public final Resource hasParameterValue;
+        
+    public static class URIs {
+        public static final String Builtin = "http://www.simantics.org/Plant3D-0.1/Builtin";
+        public static final String Builtin_BallValve = "http://www.simantics.org/Plant3D-0.1/Builtin/BallValve";
+        public static final String Builtin_BallValveGeometryProvider = "http://www.simantics.org/Plant3D-0.1/Builtin/BallValveGeometryProvider";
+        public static final String Builtin_BranchSplitComponent = "http://www.simantics.org/Plant3D-0.1/Builtin/BranchSplitComponent";
+        public static final String Builtin_Cap = "http://www.simantics.org/Plant3D-0.1/Builtin/Cap";
+        public static final String Builtin_CapGeometryProvider = "http://www.simantics.org/Plant3D-0.1/Builtin/CapGeometryProvider";
+        public static final String Builtin_CheckValve = "http://www.simantics.org/Plant3D-0.1/Builtin/CheckValve";
+        public static final String Builtin_CheckValveGeometryProvider = "http://www.simantics.org/Plant3D-0.1/Builtin/CheckValveGeometryProvider";
+        public static final String Builtin_ConcentricReducer = "http://www.simantics.org/Plant3D-0.1/Builtin/ConcentricReducer";
+        public static final String Builtin_EccentricReducer = "http://www.simantics.org/Plant3D-0.1/Builtin/EccentricReducer";
+        public static final String Builtin_Elbow = "http://www.simantics.org/Plant3D-0.1/Builtin/Elbow";
+        public static final String Builtin_ElbowGeometryProvider = "http://www.simantics.org/Plant3D-0.1/Builtin/ElbowGeometryProvider";
+        public static final String Builtin_GeometryProvider = "http://www.simantics.org/Plant3D-0.1/Builtin/GeometryProvider";
+        public static final String Builtin_HorizontalTank = "http://www.simantics.org/Plant3D-0.1/Builtin/HorizontalTank";
+        public static final String Builtin_HorizontalTankGeometryProvider = "http://www.simantics.org/Plant3D-0.1/Builtin/HorizontalTankGeometryProvider";
+        public static final String Builtin_Nozzle = "http://www.simantics.org/Plant3D-0.1/Builtin/Nozzle";
+        public static final String Builtin_NozzleGeometryProvider = "http://www.simantics.org/Plant3D-0.1/Builtin/NozzleGeometryProvider";
+        public static final String Builtin_Pump = "http://www.simantics.org/Plant3D-0.1/Builtin/Pump";
+        public static final String Builtin_PumpGeometryProvider = "http://www.simantics.org/Plant3D-0.1/Builtin/PumpGeometryProvider";
+        public static final String Builtin_ReducerGeometryProvider = "http://www.simantics.org/Plant3D-0.1/Builtin/ReducerGeometryProvider";
+        public static final String Builtin_Straight = "http://www.simantics.org/Plant3D-0.1/Builtin/Straight";
+        public static final String Builtin_StraightGeometryProvider = "http://www.simantics.org/Plant3D-0.1/Builtin/StraightGeometryProvider";
+        public static final String Builtin_VerticalTank = "http://www.simantics.org/Plant3D-0.1/Builtin/VerticalTank";
+        public static final String Builtin_VerticalTankGeometryProvider = "http://www.simantics.org/Plant3D-0.1/Builtin/VerticalTankGeometryProvider";
+        public static final String CodeComponent = "http://www.simantics.org/Plant3D-0.1/CodeComponent";
+        public static final String Connects = "http://www.simantics.org/Plant3D-0.1/Connects";
+        public static final String DualConnectedComponent = "http://www.simantics.org/Plant3D-0.1/DualConnectedComponent";
+        public static final String EndComponent = "http://www.simantics.org/Plant3D-0.1/EndComponent";
+        public static final String Equipment = "http://www.simantics.org/Plant3D-0.1/Equipment";
+        public static final String FixedAngleTurnComponent = "http://www.simantics.org/Plant3D-0.1/FixedAngleTurnComponent";
+        public static final String FixedLengthInlineComponent = "http://www.simantics.org/Plant3D-0.1/FixedLengthInlineComponent";
+        public static final String HasAlternativePipeRun = "http://www.simantics.org/Plant3D-0.1/HasAlternativePipeRun";
+        public static final String HasBranch0 = "http://www.simantics.org/Plant3D-0.1/HasBranch0";
+        public static final String HasBranch1 = "http://www.simantics.org/Plant3D-0.1/HasBranch1";
+        public static final String HasBranch2 = "http://www.simantics.org/Plant3D-0.1/HasBranch2";
+        public static final String HasBranch3 = "http://www.simantics.org/Plant3D-0.1/HasBranch3";
+        public static final String HasBranch4 = "http://www.simantics.org/Plant3D-0.1/HasBranch4";
+        public static final String HasBranch5 = "http://www.simantics.org/Plant3D-0.1/HasBranch5";
+        public static final String HasBranch6 = "http://www.simantics.org/Plant3D-0.1/HasBranch6";
+        public static final String HasBranch7 = "http://www.simantics.org/Plant3D-0.1/HasBranch7";
+        public static final String HasBranch8 = "http://www.simantics.org/Plant3D-0.1/HasBranch8";
+        public static final String HasBranch9 = "http://www.simantics.org/Plant3D-0.1/HasBranch9";
+        public static final String HasNext = "http://www.simantics.org/Plant3D-0.1/HasNext";
+        public static final String HasNozzle = "http://www.simantics.org/Plant3D-0.1/HasNozzle";
+        public static final String HasNozzleDefinition = "http://www.simantics.org/Plant3D-0.1/HasNozzleDefinition";
+        public static final String HasNozzleDefinition_Inverse = "http://www.simantics.org/Plant3D-0.1/HasNozzleDefinition/Inverse";
+        public static final String HasNozzleId = "http://www.simantics.org/Plant3D-0.1/HasNozzleId";
+        public static final String HasNozzleId_Inverse = "http://www.simantics.org/Plant3D-0.1/HasNozzleId/Inverse";
+        public static final String HasNozzleRestriction = "http://www.simantics.org/Plant3D-0.1/HasNozzleRestriction";
+        public static final String HasNozzleRestriction_Inverse = "http://www.simantics.org/Plant3D-0.1/HasNozzleRestriction/Inverse";
+        public static final String HasPipeDiameter = "http://www.simantics.org/Plant3D-0.1/HasPipeDiameter";
+        public static final String HasPipeDiameter_Inverse = "http://www.simantics.org/Plant3D-0.1/HasPipeDiameter/Inverse";
+        public static final String HasPipeRun = "http://www.simantics.org/Plant3D-0.1/HasPipeRun";
+        public static final String HasPrevious = "http://www.simantics.org/Plant3D-0.1/HasPrevious";
+        public static final String HasTurnAxis = "http://www.simantics.org/Plant3D-0.1/HasTurnAxis";
+        public static final String HasTurnAxis_Inverse = "http://www.simantics.org/Plant3D-0.1/HasTurnAxis/Inverse";
+        public static final String HasTurnRadius = "http://www.simantics.org/Plant3D-0.1/HasTurnRadius";
+        public static final String HasTurnRadius_Inverse = "http://www.simantics.org/Plant3D-0.1/HasTurnRadius/Inverse";
+        public static final String Images = "http://www.simantics.org/Plant3D-0.1/Images";
+        public static final String Images_Component = "http://www.simantics.org/Plant3D-0.1/Images/Component";
+        public static final String Images_Elbow = "http://www.simantics.org/Plant3D-0.1/Images/Elbow";
+        public static final String Images_Factory = "http://www.simantics.org/Plant3D-0.1/Images/Factory";
+        public static final String Images_Nozzle = "http://www.simantics.org/Plant3D-0.1/Images/Nozzle";
+        public static final String Images_Straight = "http://www.simantics.org/Plant3D-0.1/Images/Straight";
+        public static final String Images_Tank = "http://www.simantics.org/Plant3D-0.1/Images/Tank";
+        public static final String ImportedOntologies = "http://www.simantics.org/Plant3D-0.1/ImportedOntologies";
+        public static final String InlineComponent = "http://www.simantics.org/Plant3D-0.1/InlineComponent";
+        public static final String IsReversed = "http://www.simantics.org/Plant3D-0.1/IsReversed";
+        public static final String IsReversed_Inverse = "http://www.simantics.org/Plant3D-0.1/IsReversed/Inverse";
+        public static final String LibraryComponent = "http://www.simantics.org/Plant3D-0.1/LibraryComponent";
+        public static final String MultiConnectedComponent = "http://www.simantics.org/Plant3D-0.1/MultiConnectedComponent";
+        public static final String NextInverse = "http://www.simantics.org/Plant3D-0.1/NextInverse";
+        public static final String Node = "http://www.simantics.org/Plant3D-0.1/Node";
+        public static final String NonVisibleComponent = "http://www.simantics.org/Plant3D-0.1/NonVisibleComponent";
+        public static final String Nozzle = "http://www.simantics.org/Plant3D-0.1/Nozzle";
+        public static final String NozzleOf = "http://www.simantics.org/Plant3D-0.1/NozzleOf";
+        public static final String OffsetComponent = "http://www.simantics.org/Plant3D-0.1/OffsetComponent";
+        public static final String P3DActionContext = "http://www.simantics.org/Plant3D-0.1/P3DActionContext";
+        public static final String P3DActionContext_editTypeContribution = "http://www.simantics.org/Plant3D-0.1/P3DActionContext/editTypeContribution";
+        public static final String P3DActionContext_newContribution = "http://www.simantics.org/Plant3D-0.1/P3DActionContext/newContribution";
+        public static final String P3DActionContext_newTypeContribution = "http://www.simantics.org/Plant3D-0.1/P3DActionContext/newTypeContribution";
+        public static final String P3DBrowseContext = "http://www.simantics.org/Plant3D-0.1/P3DBrowseContext";
+        public static final String Parameter = "http://www.simantics.org/Plant3D-0.1/Parameter";
+        public static final String PipeRun = "http://www.simantics.org/Plant3D-0.1/PipeRun";
+        public static final String PipelineComponent = "http://www.simantics.org/Plant3D-0.1/PipelineComponent";
+        public static final String PipelineComponentTag = "http://www.simantics.org/Plant3D-0.1/PipelineComponentTag";
+        public static final String Plant = "http://www.simantics.org/Plant3D-0.1/Plant";
+        public static final String PreviousInverse = "http://www.simantics.org/Plant3D-0.1/PreviousInverse";
+        public static final String SingleConnectedComponent = "http://www.simantics.org/Plant3D-0.1/SingleConnectedComponent";
+        public static final String SizeChangeComponent = "http://www.simantics.org/Plant3D-0.1/SizeChangeComponent";
+        public static final String TurnComponent = "http://www.simantics.org/Plant3D-0.1/TurnComponent";
+        public static final String VariableAngleTurnComponent = "http://www.simantics.org/Plant3D-0.1/VariableAngleTurnComponent";
+        public static final String VariableLengthInlineComponent = "http://www.simantics.org/Plant3D-0.1/VariableLengthInlineComponent";
+        public static final String childen = "http://www.simantics.org/Plant3D-0.1/childen";
+        public static final String childen_Inverse = "http://www.simantics.org/Plant3D-0.1/childen/Inverse";
+        public static final String hasGeometry = "http://www.simantics.org/Plant3D-0.1/hasGeometry";
+        public static final String hasParameter = "http://www.simantics.org/Plant3D-0.1/hasParameter";
+        public static final String hasParameterValue = "http://www.simantics.org/Plant3D-0.1/hasParameterValue";
+    }
+    
+    public static Resource getResourceOrNull(ReadGraph graph, String uri) {
+        try {
+            return graph.getResource(uri);
+        } catch(DatabaseException e) {
+            System.err.println(e.getMessage());
+            return null;
+        }
+    }
+    
+    public Plant3D(ReadGraph graph) {
+        Builtin = getResourceOrNull(graph, URIs.Builtin);
+        Builtin_BallValve = getResourceOrNull(graph, URIs.Builtin_BallValve);
+        Builtin_BallValveGeometryProvider = getResourceOrNull(graph, URIs.Builtin_BallValveGeometryProvider);
+        Builtin_BranchSplitComponent = getResourceOrNull(graph, URIs.Builtin_BranchSplitComponent);
+        Builtin_Cap = getResourceOrNull(graph, URIs.Builtin_Cap);
+        Builtin_CapGeometryProvider = getResourceOrNull(graph, URIs.Builtin_CapGeometryProvider);
+        Builtin_CheckValve = getResourceOrNull(graph, URIs.Builtin_CheckValve);
+        Builtin_CheckValveGeometryProvider = getResourceOrNull(graph, URIs.Builtin_CheckValveGeometryProvider);
+        Builtin_ConcentricReducer = getResourceOrNull(graph, URIs.Builtin_ConcentricReducer);
+        Builtin_EccentricReducer = getResourceOrNull(graph, URIs.Builtin_EccentricReducer);
+        Builtin_Elbow = getResourceOrNull(graph, URIs.Builtin_Elbow);
+        Builtin_ElbowGeometryProvider = getResourceOrNull(graph, URIs.Builtin_ElbowGeometryProvider);
+        Builtin_GeometryProvider = getResourceOrNull(graph, URIs.Builtin_GeometryProvider);
+        Builtin_HorizontalTank = getResourceOrNull(graph, URIs.Builtin_HorizontalTank);
+        Builtin_HorizontalTankGeometryProvider = getResourceOrNull(graph, URIs.Builtin_HorizontalTankGeometryProvider);
+        Builtin_Nozzle = getResourceOrNull(graph, URIs.Builtin_Nozzle);
+        Builtin_NozzleGeometryProvider = getResourceOrNull(graph, URIs.Builtin_NozzleGeometryProvider);
+        Builtin_Pump = getResourceOrNull(graph, URIs.Builtin_Pump);
+        Builtin_PumpGeometryProvider = getResourceOrNull(graph, URIs.Builtin_PumpGeometryProvider);
+        Builtin_ReducerGeometryProvider = getResourceOrNull(graph, URIs.Builtin_ReducerGeometryProvider);
+        Builtin_Straight = getResourceOrNull(graph, URIs.Builtin_Straight);
+        Builtin_StraightGeometryProvider = getResourceOrNull(graph, URIs.Builtin_StraightGeometryProvider);
+        Builtin_VerticalTank = getResourceOrNull(graph, URIs.Builtin_VerticalTank);
+        Builtin_VerticalTankGeometryProvider = getResourceOrNull(graph, URIs.Builtin_VerticalTankGeometryProvider);
+        CodeComponent = getResourceOrNull(graph, URIs.CodeComponent);
+        Connects = getResourceOrNull(graph, URIs.Connects);
+        DualConnectedComponent = getResourceOrNull(graph, URIs.DualConnectedComponent);
+        EndComponent = getResourceOrNull(graph, URIs.EndComponent);
+        Equipment = getResourceOrNull(graph, URIs.Equipment);
+        FixedAngleTurnComponent = getResourceOrNull(graph, URIs.FixedAngleTurnComponent);
+        FixedLengthInlineComponent = getResourceOrNull(graph, URIs.FixedLengthInlineComponent);
+        HasAlternativePipeRun = getResourceOrNull(graph, URIs.HasAlternativePipeRun);
+        HasBranch0 = getResourceOrNull(graph, URIs.HasBranch0);
+        HasBranch1 = getResourceOrNull(graph, URIs.HasBranch1);
+        HasBranch2 = getResourceOrNull(graph, URIs.HasBranch2);
+        HasBranch3 = getResourceOrNull(graph, URIs.HasBranch3);
+        HasBranch4 = getResourceOrNull(graph, URIs.HasBranch4);
+        HasBranch5 = getResourceOrNull(graph, URIs.HasBranch5);
+        HasBranch6 = getResourceOrNull(graph, URIs.HasBranch6);
+        HasBranch7 = getResourceOrNull(graph, URIs.HasBranch7);
+        HasBranch8 = getResourceOrNull(graph, URIs.HasBranch8);
+        HasBranch9 = getResourceOrNull(graph, URIs.HasBranch9);
+        HasNext = getResourceOrNull(graph, URIs.HasNext);
+        HasNozzle = getResourceOrNull(graph, URIs.HasNozzle);
+        HasNozzleDefinition = getResourceOrNull(graph, URIs.HasNozzleDefinition);
+        HasNozzleDefinition_Inverse = getResourceOrNull(graph, URIs.HasNozzleDefinition_Inverse);
+        HasNozzleId = getResourceOrNull(graph, URIs.HasNozzleId);
+        HasNozzleId_Inverse = getResourceOrNull(graph, URIs.HasNozzleId_Inverse);
+        HasNozzleRestriction = getResourceOrNull(graph, URIs.HasNozzleRestriction);
+        HasNozzleRestriction_Inverse = getResourceOrNull(graph, URIs.HasNozzleRestriction_Inverse);
+        HasPipeDiameter = getResourceOrNull(graph, URIs.HasPipeDiameter);
+        HasPipeDiameter_Inverse = getResourceOrNull(graph, URIs.HasPipeDiameter_Inverse);
+        HasPipeRun = getResourceOrNull(graph, URIs.HasPipeRun);
+        HasPrevious = getResourceOrNull(graph, URIs.HasPrevious);
+        HasTurnAxis = getResourceOrNull(graph, URIs.HasTurnAxis);
+        HasTurnAxis_Inverse = getResourceOrNull(graph, URIs.HasTurnAxis_Inverse);
+        HasTurnRadius = getResourceOrNull(graph, URIs.HasTurnRadius);
+        HasTurnRadius_Inverse = getResourceOrNull(graph, URIs.HasTurnRadius_Inverse);
+        Images = getResourceOrNull(graph, URIs.Images);
+        Images_Component = getResourceOrNull(graph, URIs.Images_Component);
+        Images_Elbow = getResourceOrNull(graph, URIs.Images_Elbow);
+        Images_Factory = getResourceOrNull(graph, URIs.Images_Factory);
+        Images_Nozzle = getResourceOrNull(graph, URIs.Images_Nozzle);
+        Images_Straight = getResourceOrNull(graph, URIs.Images_Straight);
+        Images_Tank = getResourceOrNull(graph, URIs.Images_Tank);
+        ImportedOntologies = getResourceOrNull(graph, URIs.ImportedOntologies);
+        InlineComponent = getResourceOrNull(graph, URIs.InlineComponent);
+        IsReversed = getResourceOrNull(graph, URIs.IsReversed);
+        IsReversed_Inverse = getResourceOrNull(graph, URIs.IsReversed_Inverse);
+        LibraryComponent = getResourceOrNull(graph, URIs.LibraryComponent);
+        MultiConnectedComponent = getResourceOrNull(graph, URIs.MultiConnectedComponent);
+        NextInverse = getResourceOrNull(graph, URIs.NextInverse);
+        Node = getResourceOrNull(graph, URIs.Node);
+        NonVisibleComponent = getResourceOrNull(graph, URIs.NonVisibleComponent);
+        Nozzle = getResourceOrNull(graph, URIs.Nozzle);
+        NozzleOf = getResourceOrNull(graph, URIs.NozzleOf);
+        OffsetComponent = getResourceOrNull(graph, URIs.OffsetComponent);
+        P3DActionContext = getResourceOrNull(graph, URIs.P3DActionContext);
+        P3DActionContext_editTypeContribution = getResourceOrNull(graph, URIs.P3DActionContext_editTypeContribution);
+        P3DActionContext_newContribution = getResourceOrNull(graph, URIs.P3DActionContext_newContribution);
+        P3DActionContext_newTypeContribution = getResourceOrNull(graph, URIs.P3DActionContext_newTypeContribution);
+        P3DBrowseContext = getResourceOrNull(graph, URIs.P3DBrowseContext);
+        Parameter = getResourceOrNull(graph, URIs.Parameter);
+        PipeRun = getResourceOrNull(graph, URIs.PipeRun);
+        PipelineComponent = getResourceOrNull(graph, URIs.PipelineComponent);
+        PipelineComponentTag = getResourceOrNull(graph, URIs.PipelineComponentTag);
+        Plant = getResourceOrNull(graph, URIs.Plant);
+        PreviousInverse = getResourceOrNull(graph, URIs.PreviousInverse);
+        SingleConnectedComponent = getResourceOrNull(graph, URIs.SingleConnectedComponent);
+        SizeChangeComponent = getResourceOrNull(graph, URIs.SizeChangeComponent);
+        TurnComponent = getResourceOrNull(graph, URIs.TurnComponent);
+        VariableAngleTurnComponent = getResourceOrNull(graph, URIs.VariableAngleTurnComponent);
+        VariableLengthInlineComponent = getResourceOrNull(graph, URIs.VariableLengthInlineComponent);
+        childen = getResourceOrNull(graph, URIs.childen);
+        childen_Inverse = getResourceOrNull(graph, URIs.childen_Inverse);
+        hasGeometry = getResourceOrNull(graph, URIs.hasGeometry);
+        hasParameter = getResourceOrNull(graph, URIs.hasParameter);
+        hasParameterValue = getResourceOrNull(graph, URIs.hasParameterValue);
+    }
+    
+    public static Plant3D getInstance(ReadGraph graph) {
+        Session session = graph.getSession();
+        Plant3D ret = session.peekService(Plant3D.class);
+        if(ret == null) {
+            QueryControl qc = graph.getService(QueryControl.class);
+            ret = new Plant3D(qc.getIndependentGraph(graph));
+            session.registerService(Plant3D.class, ret);
+        }
+        return ret;
+    }
+    
+    public static Plant3D getInstance(RequestProcessor session) throws DatabaseException {
+        Plant3D ret = session.peekService(Plant3D.class);
+        if(ret == null) {
+            ret = session.syncRequest(new Read<Plant3D>() {
+                public Plant3D perform(ReadGraph graph) throws DatabaseException {
+                    QueryControl qc = graph.getService(QueryControl.class);
+                    return new Plant3D(qc.getIndependentGraph(graph));
+                }
+            });
+            session.registerService(Plant3D.class, ret);
+        }
+        return ret;
+    }
+    
+}
+
diff --git a/org.simantics.plant3d.product.feature/.project b/org.simantics.plant3d.product.feature/.project
new file mode 100644 (file)
index 0000000..e08a90e
--- /dev/null
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>org.simantics.plant3d.product.feature</name>
+       <comment></comment>
+       <projects>
+       </projects>
+       <buildSpec>
+               <buildCommand>
+                       <name>org.eclipse.pde.FeatureBuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+       </buildSpec>
+       <natures>
+               <nature>org.eclipse.pde.FeatureNature</nature>
+       </natures>
+</projectDescription>
diff --git a/org.simantics.plant3d.product.feature/build.properties b/org.simantics.plant3d.product.feature/build.properties
new file mode 100644 (file)
index 0000000..64f93a9
--- /dev/null
@@ -0,0 +1 @@
+bin.includes = feature.xml
diff --git a/org.simantics.plant3d.product.feature/feature.xml b/org.simantics.plant3d.product.feature/feature.xml
new file mode 100644 (file)
index 0000000..d5fcf10
--- /dev/null
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<feature
+      id="org.simantics.plant3d.product.feature"
+      label="Feature"
+      version="1.0.0.qualifier">
+
+   <description url="http://www.example.com/description">
+      [Enter Feature Description here.]
+   </description>
+
+   <copyright url="http://www.example.com/copyright">
+      [Enter Copyright Description here.]
+   </copyright>
+
+   <license url="http://www.example.com/license">
+      [Enter License Description here.]
+   </license>
+
+   <includes
+         id="org.eclipse.equinox.executable"
+         version="0.0.0"/>
+
+   <includes
+         id="org.simantics.eclipsec.launcher"
+         version="0.0.0"/>
+
+   <includes
+         id="org.simantics.help"
+         version="0.0.0"/>
+
+   <includes
+         id="org.simantics.workbench"
+         version="0.0.0"/>
+
+   <includes
+         id="org.simantics.plant3d.modeling"
+         version="0.0.0"/>
+
+   <plugin
+         id="org.simantics.plant3d.product"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+</feature>
diff --git a/org.simantics.plant3d.product/.classpath b/org.simantics.plant3d.product/.classpath
new file mode 100644 (file)
index 0000000..ad32c83
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
+       <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+       <classpathentry kind="src" path="src"/>
+       <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/org.simantics.plant3d.product/.gitignore b/org.simantics.plant3d.product/.gitignore
new file mode 100644 (file)
index 0000000..ae3c172
--- /dev/null
@@ -0,0 +1 @@
+/bin/
diff --git a/org.simantics.plant3d.product/.project b/org.simantics.plant3d.product/.project
new file mode 100644 (file)
index 0000000..5ace73e
--- /dev/null
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>org.simantics.plant3d.product</name>
+       <comment></comment>
+       <projects>
+       </projects>
+       <buildSpec>
+               <buildCommand>
+                       <name>org.eclipse.jdt.core.javabuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.eclipse.pde.ManifestBuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.eclipse.pde.SchemaBuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+       </buildSpec>
+       <natures>
+               <nature>org.eclipse.pde.PluginNature</nature>
+               <nature>org.eclipse.jdt.core.javanature</nature>
+       </natures>
+</projectDescription>
diff --git a/org.simantics.plant3d.product/.settings/org.eclipse.jdt.core.prefs b/org.simantics.plant3d.product/.settings/org.eclipse.jdt.core.prefs
new file mode 100644 (file)
index 0000000..c537b63
--- /dev/null
@@ -0,0 +1,7 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.6
diff --git a/org.simantics.plant3d.product/META-INF/MANIFEST.MF b/org.simantics.plant3d.product/META-INF/MANIFEST.MF
new file mode 100644 (file)
index 0000000..4730f35
--- /dev/null
@@ -0,0 +1,11 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Product
+Bundle-SymbolicName: org.simantics.plant3d.product;singleton:=true
+Bundle-Version: 1.0.0.qualifier
+Bundle-Activator: org.simantics.plant3d.product.Activator
+Require-Bundle: org.eclipse.core.runtime,
+ org.eclipse.ui;bundle-version="3.7.0"
+Bundle-ActivationPolicy: lazy
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6
+Bundle-Vendor: VTT
diff --git a/org.simantics.plant3d.product/build.properties b/org.simantics.plant3d.product/build.properties
new file mode 100644 (file)
index 0000000..e1d2dea
--- /dev/null
@@ -0,0 +1,6 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+               .,\
+               plugin.xml,\
+               splash.bmp
diff --git a/org.simantics.plant3d.product/plant3d.product b/org.simantics.plant3d.product/plant3d.product
new file mode 100644 (file)
index 0000000..66e34df
--- /dev/null
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?pde version="3.5"?>
+
+<product name="Simantics Plant3D" uid="P3D.product" id="org.simantics.plant3d.product.product" application="org.simantics.workbench.application" version="0.0.1" useFeatures="true" includeLaunchers="true">
+
+   <aboutInfo>
+      <text>
+         Simantics Plant3D
+      </text>
+   </aboutInfo>
+
+   <configIni use="default">
+   </configIni>
+
+   <launcherArgs>
+      <programArgs>--launcher.XXMaxPermSize
+192m
+-fixerrors</programArgs>
+      <vmArgs>-ea 
+-Xmx600M
+-Xshare:off
+-XX:MaxPermSize=192m
+-Djava.net.preferIPv4Stack=true
+-Dide.gc=true</vmArgs>
+      <vmArgsMac>-XstartOnFirstThread -Dorg.eclipse.swt.internal.carbon.smallFonts</vmArgsMac>
+   </launcherArgs>
+
+   <windowImages/>
+
+   <splash
+      location="org.simantics.plant3d.product" />
+   <launcher name="plant3d">
+      <solaris/>
+      <win useIco="false">
+         <bmp/>
+      </win>
+   </launcher>
+
+
+   <vm>
+   </vm>
+
+
+   <plugins>
+   </plugins>
+
+   <features>
+      <feature id="org.simantics.plant3d.product.feature" version="1.0.0.qualifier"/>
+   </features>
+
+
+</product>
diff --git a/org.simantics.plant3d.product/plugin.xml b/org.simantics.plant3d.product/plugin.xml
new file mode 100644 (file)
index 0000000..c7215ca
--- /dev/null
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<plugin>
+   <extension
+         id="product"
+         point="org.eclipse.core.runtime.products">
+      <product
+            application="org.simantics.workbench.application"
+            name="Simantics Plant3D">
+         <property
+               name="appName"
+               value="Simantics Plant3D">
+         </property>
+         <property
+               name="aboutText"
+               value="Simantics Plant3D">
+         </property>
+      </product>
+   </extension>
+
+</plugin>
diff --git a/org.simantics.plant3d.product/splash.bmp b/org.simantics.plant3d.product/splash.bmp
new file mode 100644 (file)
index 0000000..aca08ba
Binary files /dev/null and b/org.simantics.plant3d.product/splash.bmp differ
diff --git a/org.simantics.plant3d.product/src/org/simantics/plant3d/product/Activator.java b/org.simantics.plant3d.product/src/org/simantics/plant3d/product/Activator.java
new file mode 100644 (file)
index 0000000..87c1fac
--- /dev/null
@@ -0,0 +1,30 @@
+package org.simantics.plant3d.product;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+public class Activator implements BundleActivator {
+
+       private static BundleContext context;
+
+       static BundleContext getContext() {
+               return context;
+       }
+
+       /*
+        * (non-Javadoc)
+        * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
+        */
+       public void start(BundleContext bundleContext) throws Exception {
+               Activator.context = bundleContext;
+       }
+
+       /*
+        * (non-Javadoc)
+        * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
+        */
+       public void stop(BundleContext bundleContext) throws Exception {
+               Activator.context = null;
+       }
+
+}
diff --git a/org.simantics.plant3d/.classpath b/org.simantics.plant3d/.classpath
new file mode 100644 (file)
index 0000000..ad32c83
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
+       <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+       <classpathentry kind="src" path="src"/>
+       <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/org.simantics.plant3d/.gitignore b/org.simantics.plant3d/.gitignore
new file mode 100644 (file)
index 0000000..ae3c172
--- /dev/null
@@ -0,0 +1 @@
+/bin/
diff --git a/org.simantics.plant3d/.project b/org.simantics.plant3d/.project
new file mode 100644 (file)
index 0000000..c40cd1a
--- /dev/null
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>org.simantics.plant3d</name>
+       <comment></comment>
+       <projects>
+       </projects>
+       <buildSpec>
+               <buildCommand>
+                       <name>org.eclipse.jdt.core.javabuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.eclipse.pde.ManifestBuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.eclipse.pde.SchemaBuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+       </buildSpec>
+       <natures>
+               <nature>org.eclipse.pde.PluginNature</nature>
+               <nature>org.eclipse.jdt.core.javanature</nature>
+       </natures>
+</projectDescription>
diff --git a/org.simantics.plant3d/.settings/org.eclipse.jdt.core.prefs b/org.simantics.plant3d/.settings/org.eclipse.jdt.core.prefs
new file mode 100644 (file)
index 0000000..c537b63
--- /dev/null
@@ -0,0 +1,7 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.6
diff --git a/org.simantics.plant3d/META-INF/MANIFEST.MF b/org.simantics.plant3d/META-INF/MANIFEST.MF
new file mode 100644 (file)
index 0000000..6f2e691
--- /dev/null
@@ -0,0 +1,39 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Plant3d
+Bundle-SymbolicName: org.simantics.plant3d;singleton:=true
+Bundle-Version: 1.0.0.qualifier
+Bundle-Activator: org.simantics.plant3d.Activator
+Bundle-Vendor: VTT
+Require-Bundle: org.eclipse.core.runtime,
+ org.eclipse.ui,
+ org.eclipse.ui,
+ org.simantics.db;bundle-version="1.1.0",
+ org.simantics.db.common;bundle-version="1.1.0",
+ org.simantics.db.layer0;bundle-version="1.1.0",
+ org.simantics.project;bundle-version="1.0.1",
+ org.simantics.plant3d.ontology;bundle-version="1.0.0",
+ org.simantics.g3d;bundle-version="1.0.0",
+ org.simantics.g3d.ontology;bundle-version="1.0.0",
+ org.simantics.g3d.csg.ontology;bundle-version="1.0.0",
+ org.simantics.selectionview;bundle-version="1.0.0",
+ org.simantics.selectionview.ontology;bundle-version="1.0.0",
+ org.simantics.browsing.ui.swt;bundle-version="1.1.0",
+ vtk;bundle-version="5.8.0",
+ org.simantics.g3d.vtk;bundle-version="1.0.0",
+ javax.vecmath;bundle-version="1.5.2",
+ org.eclipse.ui.views;bundle-version="3.5.1",
+ org.simantics.opencascade;bundle-version="1.0.0",
+ org.jcae.opencascade;bundle-version="6.5.2",
+ org.eclipse.ui.console;bundle-version="3.5.100",
+ org.simantics.objmap2;bundle-version="1.0.0",
+ org.apache.log4j;bundle-version="1.2.15",
+ org.simantics.ui;bundle-version="1.0.0",
+ org.simantics.opencascade.vtk;bundle-version="1.0.0",
+ org.simantics.browsing.ui.platform;bundle-version="1.1.0",
+ org.simantics.structural.ui;bundle-version="1.1.1"
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6
+Bundle-ActivationPolicy: lazy
+Export-Package: org.simantics.plant3d.editor,
+ org.simantics.plant3d.property,
+ org.simantics.plant3d.scenegraph
diff --git a/org.simantics.plant3d/adapters.xml b/org.simantics.plant3d/adapters.xml
new file mode 100644 (file)
index 0000000..4fc03c1
--- /dev/null
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<adapters>
+<target interface="org.simantics.opencascade.SolidModelProvider">
+ <resource uri="http://www.simantics.org/Plant3D-0.1/Builtin/ElbowGeometryProvider"
+  class="org.simantics.plant3d.geometry.ElbowGeometryProvider">
+  <this />
+ </resource>
+ <resource uri="http://www.simantics.org/Plant3D-0.1/Builtin/NozzleGeometryProvider"
+  class="org.simantics.plant3d.geometry.NozzleGeometryProvider">
+  <this />
+ </resource>
+ <resource uri="http://www.simantics.org/Plant3D-0.1/Builtin/ReducerGeometryProvider"
+  class="org.simantics.plant3d.geometry.ReducerGeometryProvider">
+  <this />
+ </resource>
+ <resource uri="http://www.simantics.org/Plant3D-0.1/Builtin/StraightGeometryProvider"
+  class="org.simantics.plant3d.geometry.StraightGeometryProvider">
+  <this />
+ </resource>
+ <resource uri="http://www.simantics.org/Plant3D-0.1/Builtin/HorizontalTankGeometryProvider"
+  class="org.simantics.plant3d.geometry.HorizontalTankGeometryProvider">
+  <this />
+ </resource>
+  <resource uri="http://www.simantics.org/Plant3D-0.1/Builtin/VerticalTankGeometryProvider"
+  class="org.simantics.plant3d.geometry.VerticalTankGeometryProvider">
+  <this />
+ </resource>
+ <resource uri="http://www.simantics.org/Plant3D-0.1/Builtin/PumpGeometryProvider"
+  class="org.simantics.plant3d.geometry.PumpGeometryProvider">
+  <this />
+ </resource>
+ <resource uri="http://www.simantics.org/Plant3D-0.1/Builtin/BallValveGeometryProvider"
+  class="org.simantics.plant3d.geometry.BallValveGeometryProvider">
+  <this />
+ </resource>
+ <resource uri="http://www.simantics.org/Plant3D-0.1/Builtin/CheckValveGeometryProvider"
+  class="org.simantics.plant3d.geometry.CheckValveGeometryProvider">
+  <this />
+ </resource>
+  <resource uri="http://www.simantics.org/Plant3D-0.1/Builtin/CapGeometryProvider"
+  class="org.simantics.plant3d.geometry.CapGeometryProvider">
+  <this />
+ </resource>
+</target>
+</adapters>
\ No newline at end of file
diff --git a/org.simantics.plant3d/build.properties b/org.simantics.plant3d/build.properties
new file mode 100644 (file)
index 0000000..c6d4e0a
--- /dev/null
@@ -0,0 +1,7 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+               .,\
+               plugin.xml,\
+               adapters.xml,\
+               icons/
diff --git a/org.simantics.plant3d/icons/Component.png b/org.simantics.plant3d/icons/Component.png
new file mode 100644 (file)
index 0000000..0d43ef5
Binary files /dev/null and b/org.simantics.plant3d/icons/Component.png differ
diff --git a/org.simantics.plant3d/icons/Elbow.png b/org.simantics.plant3d/icons/Elbow.png
new file mode 100644 (file)
index 0000000..bbaa16e
Binary files /dev/null and b/org.simantics.plant3d/icons/Elbow.png differ
diff --git a/org.simantics.plant3d/icons/Nozzle.png b/org.simantics.plant3d/icons/Nozzle.png
new file mode 100644 (file)
index 0000000..48cf03e
Binary files /dev/null and b/org.simantics.plant3d/icons/Nozzle.png differ
diff --git a/org.simantics.plant3d/icons/Straight.png b/org.simantics.plant3d/icons/Straight.png
new file mode 100644 (file)
index 0000000..459919e
Binary files /dev/null and b/org.simantics.plant3d/icons/Straight.png differ
diff --git a/org.simantics.plant3d/icons/factory.png b/org.simantics.plant3d/icons/factory.png
new file mode 100644 (file)
index 0000000..aad23e3
Binary files /dev/null and b/org.simantics.plant3d/icons/factory.png differ
diff --git a/org.simantics.plant3d/icons/middle.png b/org.simantics.plant3d/icons/middle.png
new file mode 100644 (file)
index 0000000..4e3d03e
Binary files /dev/null and b/org.simantics.plant3d/icons/middle.png differ
diff --git a/org.simantics.plant3d/icons/middle.svg b/org.simantics.plant3d/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.plant3d/icons/plus.png b/org.simantics.plant3d/icons/plus.png
new file mode 100644 (file)
index 0000000..1d6b816
Binary files /dev/null and b/org.simantics.plant3d/icons/plus.png differ
diff --git a/org.simantics.plant3d/icons/plus.svg b/org.simantics.plant3d/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.plant3d/icons/tank.png b/org.simantics.plant3d/icons/tank.png
new file mode 100644 (file)
index 0000000..44015a3
Binary files /dev/null and b/org.simantics.plant3d/icons/tank.png differ
diff --git a/org.simantics.plant3d/icons/translate.png b/org.simantics.plant3d/icons/translate.png
new file mode 100644 (file)
index 0000000..21f5284
Binary files /dev/null and b/org.simantics.plant3d/icons/translate.png differ
diff --git a/org.simantics.plant3d/icons/translate_d.png b/org.simantics.plant3d/icons/translate_d.png
new file mode 100644 (file)
index 0000000..f4b3b60
Binary files /dev/null and b/org.simantics.plant3d/icons/translate_d.png differ
diff --git a/org.simantics.plant3d/icons/x-axis.png b/org.simantics.plant3d/icons/x-axis.png
new file mode 100644 (file)
index 0000000..8eb8a0d
Binary files /dev/null and b/org.simantics.plant3d/icons/x-axis.png differ
diff --git a/org.simantics.plant3d/icons/x-axis.svg b/org.simantics.plant3d/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.plant3d/icons/y-axis.png b/org.simantics.plant3d/icons/y-axis.png
new file mode 100644 (file)
index 0000000..ca60724
Binary files /dev/null and b/org.simantics.plant3d/icons/y-axis.png differ
diff --git a/org.simantics.plant3d/icons/y-axis.svg b/org.simantics.plant3d/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.plant3d/icons/z-axis.png b/org.simantics.plant3d/icons/z-axis.png
new file mode 100644 (file)
index 0000000..11a5741
Binary files /dev/null and b/org.simantics.plant3d/icons/z-axis.png differ
diff --git a/org.simantics.plant3d/icons/z-axis.svg b/org.simantics.plant3d/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.plant3d/plugin.xml b/org.simantics.plant3d/plugin.xml
new file mode 100644 (file)
index 0000000..e256683
--- /dev/null
@@ -0,0 +1,259 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<plugin>
+   <extension
+         point="org.eclipse.ui.editors">
+      <editor
+            class="org.simantics.plant3d.editor.Plant3DEditor"
+            default="false"
+            icon="icons/factory.png"
+            id="org.simantics.plant3d.editor"
+            name="Plant3D Editor">
+      </editor>
+   </extension>
+   <extension
+         point="org.simantics.ui.resourceEditorAdapter">
+      <adapter
+            editorId="org.simantics.plant3d.editor"
+            image="icons/factory.png"
+            label="Plant3D Editor"
+            priority="1"
+            type_uris="http://www.simantics.org/Plant3D-0.1/Plant">
+      </adapter>
+   </extension>
+   <extension
+         point="org.eclipse.ui.perspectives">
+      <perspective
+            class="org.simantics.plant3d.project.P3DPerspectiveFactory"
+            icon="icons/factory.png"
+            id="org.simantics.plant3d.perspective"
+            name="Plant3D">
+      </perspective>
+   </extension>
+   <extension
+         point="org.eclipse.ui.perspectiveExtensions">
+      <perspectiveExtension
+            targetID="org.simantics.plant3d.perspective">
+         <view
+               id="org.simantics.plant3d.ModelBrowser"
+               minimized="false"
+               ratio="0.3"
+               relationship="left"
+               relative="org.eclipse.ui.editorss">
+         </view>
+         <view
+               id="org.simantics.browsing.ui.graph.propertyView"
+               minimized="false"
+               ratio="0.7"
+               relationship="bottom"
+               relative="org.eclipse.ui.editorss"
+               visible="true">
+         </view>
+         <view
+               id="org.simantics.browsing.ui.graph.propertyView:*"
+               minimized="false"
+               relationship="stack"
+               relative="org.simantics.browsing.ui.graph.propertyView"
+               visible="false">
+         </view>
+         <view
+               id="org.simantics.browsing.ui.graph.propertyViewPinned:*"
+               minimized="false"
+               relationship="stack"
+               relative="org.simantics.browsing.ui.graph.propertyView"
+               visible="false">
+         </view>
+         <view
+               id="org.eclipse.ui.views.ContentOutline"
+               minimized="false"
+               ratio="0.8"
+               relationship="right"
+               relative="org.eclipse.ui.editorss"
+               visible="true">
+         </view>
+      </perspectiveExtension>
+   </extension>
+   <extension
+         point="org.eclipse.ui.views">
+      <view
+            class="org.simantics.plant3d.browser.P3DBrowser:browseContext=http://www.simantics.org/CSG-0.1/CSGBrowseContext;browseContext=http://www.simantics.org/Plant3D-0.1/P3DBrowseContext"
+            icon="icons/factory.png"
+            id="org.simantics.plant3d.ModelBrowser"
+            name="Model Browser"
+            restorable="true">
+      </view>
+   </extension>
+   <extension
+         point="org.eclipse.ui.menus">
+      <menuContribution
+            allPopups="false"
+            locationURI="menu:#FileNewMenu">
+         <command
+               commandId="org.simantics.plant3d.newPlant"
+               label="New Plant"
+               style="push">
+         </command>
+      </menuContribution>
+      <menuContribution
+            allPopups="false"
+            locationURI="toolbar:org.eclipse.ui.main.toolbar">
+         <toolbar
+               id="org.simantics.plant3d.toolbar">
+            <separator
+                  name="view"
+                  visible="true">
+            </separator>
+            <command
+                  commandId="org.simantics.g3d.parallelperspective"
+                  icon="platform:/plugin/com.famfamfam.silk/icons/image.png"
+                  label="Parallel perspective"
+                  style="toggle">
+            </command>
+            <command
+                  commandId="org.simantics.g3d.viewdir"
+                  icon="icons/x-axis.png"
+                  label="View X+"
+                  style="push">
+               <parameter
+                     name="org.simantics.g3d.viewDirection"
+                     value="1,0,0">
+               </parameter>
+            </command>
+            <command
+                  commandId="org.simantics.g3d.viewdir"
+                  icon="icons/x-axis.png"
+                  label="View X-"
+                  style="push">
+               <parameter
+                     name="org.simantics.g3d.viewDirection"
+                     value="-1,0,0">
+               </parameter>
+            </command>
+            <command
+                  commandId="org.simantics.g3d.viewdir"
+                  icon="icons/y-axis.png"
+                  label="View Y+"
+                  style="push">
+               <parameter
+                     name="org.simantics.g3d.viewDirection"
+                     value="0,1,0">
+               </parameter>
+            </command>
+            <command
+                  commandId="org.simantics.g3d.viewdir"
+                  icon="icons/y-axis.png"
+                  label="View Y-"
+                  style="push">
+               <parameter
+                     name="org.simantics.g3d.viewDirection"
+                     value="0,-1,0">
+               </parameter>
+            </command>
+            <command
+                  commandId="org.simantics.g3d.viewdir"
+                  icon="icons/z-axis.png"
+                  label="View Z+"
+                  style="push">
+               <parameter
+                     name="org.simantics.g3d.viewDirection"
+                     value="0,0,1">
+               </parameter>
+            </command>
+            <command
+                  commandId="org.simantics.g3d.viewdir"
+                  icon="icons/z-axis.png"
+                  label="View Z-"
+                  style="push">
+               <parameter
+                     name="org.simantics.g3d.viewDirection"
+                     value="0,0,-1">
+               </parameter>
+            </command>
+         </toolbar>
+      </menuContribution>
+   </extension>
+   <extension
+         point="org.eclipse.ui.commands">
+      <category
+            id="org.simantics.plant3d.category"
+            name="Plant3D commands">
+      </category>
+      <command
+            category="org.simantics.plant3d.category"
+            id="org.simantics.plant3d.newPlant"
+            name="New Plant">
+      </command>
+   </extension>
+   <extension
+         point="org.eclipse.ui.handlers">
+      <handler
+            class="org.simantics.plant3d.handlers.NewPlantHandler"
+            commandId="org.simantics.plant3d.newPlant">
+      </handler>
+      <handler
+            class="org.simantics.g3d.vtk.handlers.ParallelPerspectiveHandler"
+            commandId="org.simantics.g3d.parallelperspective">
+         <activeWhen>
+            <with
+                  variable="activeEditor">
+               <and>
+                  <instanceof
+                        value="org.simantics.plant3d.editor.Plant3DEditor">
+                  </instanceof>
+               </and>
+            </with>
+         </activeWhen>
+      </handler>
+      <handler
+            class="org.simantics.g3d.vtk.handlers.CameraPositionHandler"
+            commandId="org.simantics.g3d.viewdir">
+         <activeWhen>
+            <with
+                  variable="activeEditor">
+               <and>
+                  <instanceof
+                        value="org.simantics.plant3d.editor.Plant3DEditor">
+                  </instanceof>
+               </and>
+            </with>
+         </activeWhen>
+      </handler>
+   </extension>
+   <extension
+         point="org.simantics.project.feature">
+      <feature
+            class="org.simantics.plant3d.project.P3DProjectFeature"
+            id="org.simantics.plant3d.project.feature"
+            label="Plant3D Project"
+            published="true">
+         <installGroup
+               id="org.simantics.plant3d.installGroup"
+               version="[1.0.0,2.0.0)">
+         </installGroup>
+      </feature>
+   </extension>
+   <extension
+         point="org.eclipse.ui.contexts">
+      <context
+            id="org.simantics.plant3d.context"
+            name="Plant3D Context">
+      </context>
+   </extension>
+   <extension
+         point="org.simantics.ui.perspectiveContextBinding">
+      <binding
+            contextIds="org.simantics.plant3d.context"
+            perspectiveId="org.simantics.plant3d.perspective">
+      </binding>
+   </extension>
+   <extension
+         point="org.simantics.browsing.ui.common.selectionProcessorBinding">
+      <binding
+            browseContext="http://www.simantics.org/Project-1.0/ProjectBrowseContext">
+         <implementation
+               class="org.simantics.plant3d.property.P3DSelectionProcessor">
+         </implementation>
+      </binding>
+   </extension>
+
+</plugin>
diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/Activator.java b/org.simantics.plant3d/src/org/simantics/plant3d/Activator.java
new file mode 100644 (file)
index 0000000..dcb18b5
--- /dev/null
@@ -0,0 +1,50 @@
+package org.simantics.plant3d;
+
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.osgi.framework.BundleContext;
+
+/**
+ * The activator class controls the plug-in life cycle
+ */
+public class Activator extends AbstractUIPlugin {
+
+       // The plug-in ID
+       public static final String PLUGIN_ID = "org.simantics.plant3d"; //$NON-NLS-1$
+
+       // The shared instance
+       private static Activator plugin;
+       
+       /**
+        * The constructor
+        */
+       public Activator() {
+       }
+
+       /*
+        * (non-Javadoc)
+        * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
+        */
+       public void start(BundleContext context) throws Exception {
+               super.start(context);
+               plugin = this;
+       }
+
+       /*
+        * (non-Javadoc)
+        * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)
+        */
+       public void stop(BundleContext context) throws Exception {
+               plugin = null;
+               super.stop(context);
+       }
+
+       /**
+        * Returns the shared instance
+        *
+        * @return the shared instance
+        */
+       public static Activator getDefault() {
+               return plugin;
+       }
+
+}
diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/actions/AddComponentAction.java b/org.simantics.plant3d/src/org/simantics/plant3d/actions/AddComponentAction.java
new file mode 100644 (file)
index 0000000..bf220dd
--- /dev/null
@@ -0,0 +1,268 @@
+package org.simantics.plant3d.actions;
+
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.vecmath.Vector3d;
+
+import org.eclipse.swt.widgets.Display;
+import org.simantics.g3d.scenegraph.NodeMap;
+import org.simantics.g3d.scenegraph.base.INode;
+import org.simantics.g3d.vtk.action.vtkAction;
+import org.simantics.g3d.vtk.common.InteractiveVtkPanel;
+import org.simantics.plant3d.Activator;
+import org.simantics.plant3d.dialog.ComponentSelectionDialog;
+import org.simantics.plant3d.gizmo.TerminalSelectionGizmo;
+import org.simantics.plant3d.scenegraph.InlineComponent;
+import org.simantics.plant3d.scenegraph.P3DRootNode;
+import org.simantics.plant3d.scenegraph.PipeRun;
+import org.simantics.plant3d.scenegraph.PipelineComponent;
+import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint;
+import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint.Direction;
+import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint.PositionType;
+import org.simantics.plant3d.scenegraph.controlpoint.PipingRules;
+import org.simantics.plant3d.utils.ComponentUtils;
+import org.simantics.plant3d.utils.Item;
+import org.simantics.plant3d.utils.Item.Type;
+import org.simantics.utils.threads.AWTThread;
+import org.simantics.utils.threads.ThreadUtils;
+import org.simantics.utils.ui.ExceptionUtils;
+
+import vtk.vtkProp;
+
+public class AddComponentAction extends vtkAction {
+       
+
+       private P3DRootNode root;
+       private PipelineComponent component;
+       private NodeMap<vtkProp,INode> nodeMap;
+       
+       private TerminalSelectionGizmo gizmo;
+       
+       private Set<PositionType> allowed = new HashSet<PositionType>();
+       
+       private Item toAdd = null;
+       
+       public AddComponentAction(InteractiveVtkPanel panel, P3DRootNode root) {
+               super(panel);
+               this.root = root;
+               setText("Add Component");
+               setImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/Component.png"));
+               nodeMap = root.getNodeMap();
+               gizmo = new TerminalSelectionGizmo(panel);
+       }
+       
+       public void setComponent(PipelineComponent component) {
+               this.component = component;
+               
+               allowed.clear();
+               if (component.getNext() == null) {
+                       allowed.add(PositionType.NEXT);
+               }
+               if (component.getPrevious() == null) {
+                       allowed.add(PositionType.PREVIOUS);
+               }
+               if (component instanceof InlineComponent && !component.getControlPoint().isFixed()){
+                       allowed.add(PositionType.SPLIT);
+               }
+               setEnabled(allowed.size() > 0);
+       }
+       
+       private Double length;
+       private Double angle;
+       private Double diameter;
+       private Double turnRadius;
+       
+       @Override
+       public void run() {
+               ComponentSelectionDialog dialog = new ComponentSelectionDialog(Display.getCurrent().getActiveShell(), allowed);
+               if (dialog.open() == ComponentSelectionDialog.CANCEL)
+                       return;
+               toAdd = dialog.getSelected();
+               if (toAdd == null)
+                       return;
+               this.length = dialog.getLength();
+               this.angle = dialog.getAngle();
+               this.diameter = dialog.getDiameter();
+               this.turnRadius = dialog.getTurnRadius();
+               allowed = dialog.filterAllowed();
+               gizmo.setComponent(component, allowed);
+               super.run();
+               panel.repaint();
+       }
+       
+       @Override
+       public void keyPressed(KeyEvent e) {
+               if (e.getKeyCode() == KeyEvent.VK_ESCAPE)
+                       panel.useDefaultAction();
+               
+               
+       }
+       
+       public void attach() {
+               if (component == null)
+                       return;
+               
+               super.attach();
+               ThreadUtils.asyncExec(AWTThread.getThreadAccess(), new Runnable() {
+                       public void run() {
+                               attachUI();
+                       }
+               });
+               
+       }
+       
+       public void deattach() {
+//             deactivate();
+               component = null;
+               nodeMap.commit();
+               deattachUI();
+               super.deattach();
+               panel.repaint();
+       }
+       
+       private void attachUI() {
+               //panel.setCursor(activeCursor);
+               gizmo.attach(panel.GetRenderer());
+       }
+       
+       private void deattachUI() {
+               //panel.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
+               gizmo.deattach();
+       }
+       
+       @Override
+       public void mouseMoved(MouseEvent e) {
+               panel.getDefaultAction().mouseMoved(e);
+       }
+       
+       @Override
+       public void mousePressed(MouseEvent e) {
+               panel.getDefaultAction().mousePressed(e);
+       }
+
+       @Override
+       public void mouseReleased(MouseEvent e) {
+               panel.getDefaultAction().mouseReleased(e);
+       }
+       
+       @Override
+       public void mouseDragged(MouseEvent e) {
+               panel.getDefaultAction().mouseDragged(e);
+       }
+       
+       public void doInsert(PositionType position) {
+               try  {
+                       PipelineComponent newComponent = ComponentUtils.createComponent(root,toAdd.getUri());
+                       PipeControlPoint newPcp = newComponent.getControlPoint();
+                       
+                       PipeControlPoint toPcp = component.getControlPoint();
+                       Vector3d start = new Vector3d();
+                       Vector3d end = new Vector3d();
+                       Vector3d dir = new Vector3d();
+                       toPcp.getInlineControlPointEnds(start, end, dir);
+                       dir.normalize();
+                       
+                       switch (position) {
+                       case NEXT: 
+                               if (toPcp.isDualInline())
+                                       toPcp = toPcp.getSubPoint().get(0);
+                               
+                               break;
+                       case PREVIOUS:
+                               if (toPcp.isDualSub())
+                                       toPcp = toPcp.parent;
+                       }
+                       PipeRun pipeRun = toPcp.getPipeRun();
+                       
+                       if (!toAdd.isSizeChange()) {
+                               String name = component.getPipeRun().getUniqueName(toAdd.getName());
+                               newComponent.setName(name);
+
+                               pipeRun.addChild(newComponent);
+                               if (toAdd.isVariable()) {
+                                       // TODO: these options are not stored into DB. Should they?!
+                                       if (toAdd.getType() == Type.INLINE) {
+                                               newPcp.setLength(length);
+//                                             newPcp.setFixed(true);
+                                       } else if (toAdd.getType() == Type.TURN) {
+                                               newPcp.setTurnAngle(angle);
+//                                             newPcp.setFixed(true);
+                                       }
+                               }
+                               newComponent.updateParameters();
+
+                               dir.scale(newComponent.getControlPoint().getLength()*0.5);
+                               start.sub(dir);
+                               end.add(dir);
+                               switch (position) {
+                               case NEXT: 
+                                       if (toPcp.isDualInline())
+                                               toPcp = toPcp.getSubPoint().get(0);
+                                       newPcp.insert(toPcp, Direction.NEXT);
+                                       newPcp.setWorldPosition(end);
+                                       break;
+                               case PREVIOUS:
+                                       if (toPcp.isDualSub())
+                                               toPcp = toPcp.parent;
+                                       newPcp.insert(toPcp, Direction.PREVIOUS);
+                                       newPcp.setWorldPosition(start);
+                                       break;
+                               case SPLIT:
+                                       PipingRules.splitVariableLengthComponent(newComponent, (InlineComponent)component, true);
+                               }
+                       } else {
+                               
+                               
+                               PipeRun other = new PipeRun();
+                               String n = root.getUniqueName("PipeRun");
+                               other.setName(n);
+                               other.setPipeDiameter(diameter);
+                               other.setTurnRadius(turnRadius);
+                               root.addChild(other);
+                               
+                               
+                               
+                               if (position == PositionType.NEXT) {
+                                       PipingRules.addSizeChange(false, pipeRun, other, (InlineComponent)newComponent, toPcp, null);
+                                       newPcp.setWorldPosition(end);
+                       } else if (position == PositionType.PREVIOUS){
+                               PipingRules.addSizeChange(true, pipeRun, other, (InlineComponent)newComponent, toPcp, null);
+                               newPcp.setWorldPosition(start);
+                       }
+                               // TODO : chicken-egg problem
+                               newComponent.updateParameters();
+                               dir.scale(newComponent.getControlPoint().getLength()*0.5);
+                               start.sub(dir);
+                               end.add(dir);
+                               if (position == PositionType.NEXT) {
+                                       newPcp.setWorldPosition(end);
+                               } else if (position == PositionType.PREVIOUS){
+                                       newPcp.setWorldPosition(start);
+                               }
+                       }
+                       
+                       
+               } catch (Exception e) {
+                       ExceptionUtils.logAndShowError("Cannot add component", e);
+               }
+       }
+       
+       public void mouseClicked(MouseEvent e) {
+               if (e.getClickCount() == 1 && e.getButton() == MouseEvent.BUTTON1) {
+                       int type = panel.getPickType();
+                       panel.setPickType(0);
+                       vtkProp[] picked = panel.pick(e.getX(), e.getY());
+                       panel.setPickType(type);
+                       PositionType position = gizmo.getPickedPosition(picked);
+                       if (position != null) {
+                               doInsert(position);
+                               panel.useDefaultAction();
+                               return;
+                       }
+               } 
+               panel.getDefaultAction().mouseClicked(e);
+       }
+}
diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/actions/AddEquipmentAction.java b/org.simantics.plant3d/src/org/simantics/plant3d/actions/AddEquipmentAction.java
new file mode 100644 (file)
index 0000000..6c66909
--- /dev/null
@@ -0,0 +1,33 @@
+package org.simantics.plant3d.actions;
+
+import org.eclipse.jface.action.Action;
+import org.simantics.plant3d.scenegraph.Equipment;
+import org.simantics.plant3d.scenegraph.P3DRootNode;
+import org.simantics.plant3d.utils.Item;
+import org.simantics.utils.ui.ExceptionUtils;
+
+public class AddEquipmentAction extends Action {
+
+       P3DRootNode root;
+       private Item item;
+       
+       public AddEquipmentAction(P3DRootNode root, Item item) {
+               this.root = root;
+               this.item = item;
+               setText("Add " + item.getName());
+       }
+       
+       @Override
+       public void run() {
+               try {
+                       Equipment equipment = root.createEquipment();
+                       equipment.setType(item.getUri());
+                       String n = root.getUniqueName(item.getName());
+                       equipment.setName(n);
+                       root.addChild(equipment);
+                       root.getNodeMap().commit();
+               } catch (Exception e) {
+                       ExceptionUtils.logAndShowError("Cannot create equipment",e);
+               }
+       }
+}
diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/actions/AddNozzleAction.java b/org.simantics.plant3d/src/org/simantics/plant3d/actions/AddNozzleAction.java
new file mode 100644 (file)
index 0000000..e6b8ecd
--- /dev/null
@@ -0,0 +1,49 @@
+package org.simantics.plant3d.actions;
+
+import org.eclipse.jface.action.Action;
+import org.simantics.plant3d.Activator;
+import org.simantics.plant3d.scenegraph.Equipment;
+import org.simantics.plant3d.scenegraph.Nozzle;
+import org.simantics.plant3d.scenegraph.P3DRootNode;
+import org.simantics.plant3d.scenegraph.PipeRun;
+import org.simantics.plant3d.utils.Item;
+import org.simantics.utils.ui.ExceptionUtils;
+
+public class AddNozzleAction extends Action {
+
+       P3DRootNode root;
+       private Item item;
+       private Equipment equipment;
+       
+       public AddNozzleAction(P3DRootNode root, Item item) {
+               this.root = root;
+               this.item = item;
+               setText("Add " + item.getName());
+               setImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/Nozzle.png"));
+       }
+       
+       public void setEquipment(Equipment equipment) {
+               this.equipment = equipment;
+       }
+       
+       @Override
+       public void run() {
+               try {
+                       Nozzle nozzle = root.createNozzle();
+                       nozzle.setType(item.getUri());
+                       String n = root.getUniqueName(item.getName());
+                       nozzle.setName(n);
+                       PipeRun pipeRun = new PipeRun();
+                       n = root.getUniqueName("PipeRun");
+                       pipeRun.setName(n);
+                       nozzle.setPipeRun(pipeRun);
+                       
+                       equipment.addChild(nozzle);
+                       //root.addChild(nozzle);
+                       root.addChild(pipeRun);
+                       root.getNodeMap().commit();
+               } catch (Exception e) {
+                       ExceptionUtils.logAndShowError("Cannot create equipment",e);
+               }
+       }
+}
diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/actions/RoutePipeAction.java b/org.simantics.plant3d/src/org/simantics/plant3d/actions/RoutePipeAction.java
new file mode 100644 (file)
index 0000000..0310311
--- /dev/null
@@ -0,0 +1,1188 @@
+package org.simantics.plant3d.actions;
+
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.vecmath.Point3d;
+import javax.vecmath.Tuple3d;
+import javax.vecmath.Vector3d;
+
+import org.simantics.g3d.math.MathTools;
+import org.simantics.g3d.math.Ray;
+import org.simantics.g3d.scenegraph.NodeMap;
+import org.simantics.g3d.scenegraph.base.INode;
+import org.simantics.g3d.tools.ConstraintDetector;
+import org.simantics.g3d.tools.DummyConstraintDetector;
+import org.simantics.g3d.vtk.action.vtkAction;
+import org.simantics.g3d.vtk.common.InteractiveVtkPanel;
+import org.simantics.g3d.vtk.gizmo.TranslateAxisGizmo;
+import org.simantics.g3d.vtk.utils.vtkUtil;
+import org.simantics.plant3d.Activator;
+import org.simantics.plant3d.gizmo.SplitPointSelectionGizmo;
+import org.simantics.plant3d.gizmo.TerminalSelectionGizmo;
+import org.simantics.plant3d.ontology.Plant3D;
+import org.simantics.plant3d.scenegraph.EndComponent;
+import org.simantics.plant3d.scenegraph.InlineComponent;
+import org.simantics.plant3d.scenegraph.Nozzle;
+import org.simantics.plant3d.scenegraph.P3DRootNode;
+import org.simantics.plant3d.scenegraph.PipeRun;
+import org.simantics.plant3d.scenegraph.PipelineComponent;
+import org.simantics.plant3d.scenegraph.TurnComponent;
+import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint;
+import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint.Direction;
+import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint.PositionType;
+import org.simantics.plant3d.scenegraph.controlpoint.PipingRules;
+import org.simantics.plant3d.utils.ComponentUtils;
+import org.simantics.utils.threads.AWTThread;
+import org.simantics.utils.threads.ThreadUtils;
+import org.simantics.utils.ui.ExceptionUtils;
+
+import vtk.vtkProp;
+import vtk.vtkTextActor;
+
+public class RoutePipeAction extends vtkAction {
+       enum LockType {
+               X, Y, Z, XY, YZ, XZ, NONE, CUSTOM
+       };
+
+       LockType lock = LockType.NONE;
+       private double BRANCH_SNAP_DISTANCE = 0.05;
+       private double NOZZLE_SNAP_DISTANCE = 0.05;
+
+       private double istep = 10.0;
+       private int decimals = 2;
+
+       private P3DRootNode root;
+       private PipelineComponent startComponent;
+       private PipeRun pipeRun;
+
+       private TranslateAxisGizmo translateAxisGizmo = new TranslateAxisGizmo();
+       private SplitPointSelectionGizmo splitPointSelectionGizmo;
+       private TerminalSelectionGizmo terminalSelectionGizmo;
+       private NodeMap<vtkProp,INode> nodeMap;
+       
+       private enum ToolState{NOT_ACTIVE, INITIALIZING, SELECTING_POSITION, SELECTING_SPLIT, ROUTING};
+       private ToolState state = ToolState.NOT_ACTIVE;
+       
+       private ConstraintDetector detector = new DummyConstraintDetector();
+       
+       private boolean useDefault = false;
+       private Vector3d direction = null;
+       private Vector3d previousPosition = null;
+       private Vector3d currentPosition = null;
+       
+       boolean step = false;
+       
+       PipelineComponent endTo = null;
+    PositionType endType = null;
+    PipeControlPoint endPort = null;
+    
+    boolean reversed = false;
+    
+    private Set<PositionType> allowed = new HashSet<PositionType>();
+    
+       
+       public RoutePipeAction(InteractiveVtkPanel panel, P3DRootNode root) {
+               super(panel);
+               this.root = root;
+               setText("Route Pipe");
+               setImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/Straight.png"));
+               nodeMap = root.getNodeMap();
+               splitPointSelectionGizmo = new SplitPointSelectionGizmo(panel);
+               terminalSelectionGizmo = new TerminalSelectionGizmo(panel);
+       }
+       
+       public void setComponent(PipelineComponent component) {
+               this.startComponent = component;
+               allowed.clear();
+               if (this.startComponent.getNext() == null)
+                       allowed.add(PositionType.NEXT);
+               if (this.startComponent.getPrevious() == null && !(this.startComponent instanceof Nozzle))
+                       allowed.add(PositionType.PREVIOUS);
+               if (this.startComponent instanceof InlineComponent && !this.startComponent.getControlPoint().isFixed())
+                       allowed.add(PositionType.SPLIT);
+               setEnabled(allowed.size() > 0);
+       }
+       
+       public void deattach() {
+               deactivate();
+               startComponent = null;
+               nodeMap.commit();
+               deattachUI();
+               super.deattach();
+               panel.repaint();
+       }
+       
+       public void attach() {
+               if (startComponent == null)
+                       return;
+               
+               super.attach();
+               ThreadUtils.asyncExec(AWTThread.getThreadAccess(), new Runnable() {
+                       public void run() {
+//                             attachUI();
+                               try {
+                                       activate();
+                               } catch (Exception e) {
+                                       deattach();
+                                       ExceptionUtils.logAndShowError(e);
+                               }
+                               
+                       }
+               });
+               
+       }
+       
+//     private void attachUI() {
+//             //panel.setCursor(activeCursor);
+//             translateAxisGizmo.attach(panel.GetRenderer());
+//     }
+       
+       private void deattachUI() {
+               //panel.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
+               if (translateAxisGizmo.isAttached())
+                       translateAxisGizmo.deattach();
+               if (splitPointSelectionGizmo.isAttached())
+                       splitPointSelectionGizmo.deattach();
+               if (terminalSelectionGizmo.isAttached())
+                       terminalSelectionGizmo.deattach();
+               if (infoActor != null) {
+                       panel.GetRenderer().RemoveActor(infoActor);
+                       infoActor.Delete();
+                       infoActor = null;
+               }
+       }
+       
+       private List<PipelineComponent> added = new ArrayList<PipelineComponent>();
+       
+       @Override
+       public void keyPressed(KeyEvent e) {
+               if (e.getKeyCode() == KeyEvent.VK_ESCAPE)
+                       panel.useDefaultAction();
+               if (lock != LockType.CUSTOM) {
+                       if ((e.getModifiersEx() & KeyEvent.SHIFT_DOWN_MASK) > 0) {
+                               if (e.getKeyCode() == KeyEvent.VK_X) {
+                                       if (lock != LockType.XY && lock != LockType.XZ) {
+                                               setLockType(LockType.XY, false);
+                                       } else if (lock == LockType.XY) {
+                                               setLockType(LockType.XZ, false);
+                                       } else {
+                                               setLockType(LockType.NONE, false);
+                                       }
+                               }
+                               if (e.getKeyCode() == KeyEvent.VK_Y) {
+                                       if (lock != LockType.XY && lock != LockType.YZ) {
+                                               setLockType(LockType.XY, false);
+                                       } else if (lock == LockType.XY) {
+                                               setLockType(LockType.YZ, false);
+                                       } else {
+                                               setLockType(LockType.NONE, false);
+                                       }
+                               }
+                               if (e.getKeyCode() == KeyEvent.VK_Z) {
+                                       if (lock != LockType.XZ && lock != LockType.YZ) {
+                                               setLockType(LockType.XZ, false);
+                                       } else if (lock == LockType.XZ) {
+                                               setLockType(LockType.YZ, false);
+                                       } else {
+                                               setLockType(LockType.NONE, false);
+                                       }
+                               }
+                       } else {
+                               if (e.getKeyCode() == KeyEvent.VK_X) {
+                                       if (lock != LockType.X)
+                                               setLockType(LockType.X,false);
+                                       else
+                                               setLockType(LockType.NONE,false);
+                               }
+                               if (e.getKeyCode() == KeyEvent.VK_Y) {
+                                       if (lock != LockType.Y)
+                                               setLockType(LockType.Y,false);
+                                       else
+                                               setLockType(LockType.NONE, false);
+                               }
+                               if (e.getKeyCode() == KeyEvent.VK_Z) {
+                                       if (lock != LockType.Z)
+                                               setLockType(LockType.Z, false);
+                                       else
+                                               setLockType(LockType.NONE, false);
+                               }
+                       }
+               }
+               if (e.getKeyCode() == KeyEvent.VK_C) {
+                       useDefault = !useDefault;
+                       System.out.println("UseDefault " + useDefault);
+               }
+               
+               
+               
+               
+               update();
+               
+       }
+       
+       
+       private void update() {
+               panel.repaint();
+       }
+       private void update(double x, double y) {
+               switch (state) {
+       case NOT_ACTIVE:
+               return; // TODO : throw Exception?
+       case INITIALIZING:
+               return;
+       case SELECTING_POSITION:
+               return;
+       case SELECTING_SPLIT:
+               return;
+       case ROUTING:
+               updateRouting(x,y);
+               break;
+       }
+       return;
+       }
+       
+       boolean startRemovable = false;
+       
+       private void activate() throws Exception {
+               state = ToolState.INITIALIZING;
+               added.clear();
+               
+               if (allowed.size() == 1) {
+                       pipeRun = startComponent.getPipeRun();
+                       PipeControlPoint start = startComponent.getControlPoint();
+                       boolean requiresBranching = false;
+                       if (start.getNext() == null)
+                               reversed = false;
+                       else if (start.getPrevious() == null) {
+                               reversed = true;
+                       } else {
+                               requiresBranching = true;
+                       }
+                       
+                       if (requiresBranching) {
+                               activateSplit(start);
+                       } else {
+                               activateNextPrev(start);
+                       }
+               } else if (allowed.size() == 0) {
+                       panel.useDefaultAction();
+                       state = ToolState.NOT_ACTIVE;
+                       return;
+               } else {
+                       terminalSelectionGizmo.setComponent(startComponent, allowed);
+                       terminalSelectionGizmo.attach(panel.GetRenderer());
+                       state = ToolState.SELECTING_POSITION;
+                       panel.repaint();
+               }
+               
+       }
+       
+       
+       
+       private void activateNextPrev(PipeControlPoint start) throws Exception{
+               if (!reversed && start.isDualInline())
+                       start = start.getSubPoint().get(0);
+               else if (reversed && start.isDualSub())
+                       start = start.parent;
+               
+               pipeRun = start.getPipeRun();
+               setPreviousPosition(start.getWorldPosition());
+               
+               boolean startWithTurn = false;
+               if (startComponent instanceof Nozzle) {
+                       direction = startComponent.getControlPoint().getDirectedControlPointDirection();
+                       lock = LockType.CUSTOM;
+               } else if (startComponent instanceof PipelineComponent){
+                       if (startComponent instanceof InlineComponent) {
+                               direction = startComponent.getControlPoint().getPathLegDirection(reversed ? Direction.PREVIOUS : Direction.NEXT);
+                               lock = LockType.CUSTOM;
+                               if (startComponent.getType().equals(Plant3D.URIs.Builtin_Straight)) {
+                                       startWithTurn = true;
+                                       direction = null;
+                                       lock = LockType.NONE;
+                               } 
+                               Vector3d v = new Vector3d();
+                               if (!reversed) {
+                                       start.getControlPointEnds(v, previousPosition);
+                               } else {
+                                       start.getControlPointEnds(previousPosition,v);
+                               }
+                       } else if (startComponent instanceof TurnComponent) {
+                               if (start.isFixed()) {
+                                       direction = startComponent.getControlPoint().getPathLegDirection(reversed ? Direction.PREVIOUS : Direction.NEXT);
+                                       lock = LockType.CUSTOM;
+                               } else {
+                                       direction = null;
+                                       lock = LockType.NONE;
+                               }
+                       } else if (startComponent instanceof EndComponent) {
+                               throw new Exception("Not supported");
+                       }
+                       
+               } else {
+                       throw new Exception("Not supported");
+               }
+               currentPosition = new Vector3d(previousPosition);
+               state = ToolState.ROUTING;
+               if (direction != null) {
+                       direction.normalize();
+                       
+               } 
+               startRemovable = start.isDeletable();
+               start.setDeletable(false);
+               
+               if (startWithTurn) {
+                       addPoint();
+               } else {
+                       if (direction != null)
+                               currentPosition.add(direction);
+                       InlineComponent straight = ComponentUtils.createStraight(root);
+                       PipeControlPoint straightCP = straight.getControlPoint();
+                       straight.setName(pipeRun.getUniqueName("Pipe"));
+                       pipeRun.addChild(straight);
+                       added.add(straight);
+       
+                       if (!reversed) {
+                               start.setNext(straightCP);
+                               straightCP.setPrevious(start);
+                       } else {
+                               start.setPrevious(straightCP);
+                               straightCP.setNext(start);
+                       }
+               }
+               translateAxisGizmo.attach(panel.GetRenderer());
+               setPreviousPosition(previousPosition);
+               updateCurrentPoint();
+       }
+       
+       private void setPreviousPosition(Vector3d v) {
+               previousPosition = new Vector3d(v);
+               if (translateAxisGizmo.isAttached())
+                       translateAxisGizmo.setPosition(previousPosition);
+       }
+       
+       private void activateBranch(PipeControlPoint start) throws Exception{
+               pipeRun = start.getPipeRun();
+               setPreviousPosition(start.getWorldPosition());
+               
+               direction = null;
+               lock = LockType.NONE;
+               
+               currentPosition = new Vector3d(previousPosition);
+               state = ToolState.ROUTING;
+               if (direction != null) {
+                       direction.normalize();
+                       
+               } 
+               startRemovable = start.isDeletable();
+               start.setDeletable(false);
+               
+               
+               if (direction != null)
+                       currentPosition.add(direction);
+               InlineComponent straight = ComponentUtils.createStraight(root);
+               PipeControlPoint straightCP = straight.getControlPoint();
+               straight.setName(pipeRun.getUniqueName("Pipe"));
+               pipeRun.addChild(straight);
+               added.add(straight);
+
+               if (!reversed) {
+                       start.setNext(straightCP);
+                       straightCP.setPrevious(start);
+                       
+               } else {
+                       start.setPrevious(straightCP);
+                       straightCP.setNext(start);
+                       
+               }
+               
+               translateAxisGizmo.attach(panel.GetRenderer());
+               setPreviousPosition(previousPosition);
+               updateCurrentPoint();
+       }
+       
+       private void activateSplit(PipeControlPoint start) throws Exception{
+               Point3d p1 = new Point3d();
+               Point3d p2 = new Point3d();
+               start.getInlineControlPointEnds(p1, p2);
+               splitPointSelectionGizmo.setSplit(p1, p2);
+               splitPointSelectionGizmo.attach(panel.GetRenderer());
+               state = ToolState.SELECTING_SPLIT;
+       }
+       public void deactivate() {
+               for (PipelineComponent component : added) {
+                       component.getControlPoint().setDeletable(true);
+               }
+               
+               added.clear();
+               startComponent.getControlPoint().setDeletable(startRemovable);
+
+               direction = null;
+
+               setLockType(LockType.NONE, true);
+               startComponent = null;
+               endTo = null;
+               endPort = null;
+               endType = null;
+               pipeRun = null;
+               allowed.clear();
+               currentPosition = null;
+               previousPosition = null;
+               startRemovable = false;
+               detector.clearConstraintHighlights();
+               state = ToolState.NOT_ACTIVE;
+               setEnabled(false);
+               
+
+       }
+       
+       private void setLockType(LockType type, boolean force) {
+               if (force || lock != LockType.CUSTOM) {
+                       lock = type;
+                       
+                       switch (lock) {
+                       case CUSTOM:
+                       case NONE:
+                               translateAxisGizmo.setType(6);
+                               break;
+                       case X:
+                               translateAxisGizmo.setType(0);
+                               break;
+                       case Y:
+                               translateAxisGizmo.setType(1);
+                               break;
+                       case Z:
+                               translateAxisGizmo.setType(2);
+                               break;
+                       case XY:
+                               translateAxisGizmo.setType(3);
+                               break;
+                       case XZ:
+                               translateAxisGizmo.setType(4);
+                               break;
+                       case YZ:
+                               translateAxisGizmo.setType(5);
+                               break;
+                               
+                       }
+               }
+       }
+       
+       @Override
+       public void mousePressed(MouseEvent e) {
+               if (useDefault) {
+                       panel.getDefaultAction().mousePressed(e);
+               }
+       }
+
+       @Override
+       public void mouseReleased(MouseEvent e) {
+               if (useDefault) {
+                       panel.getDefaultAction().mouseReleased(e);
+               }
+       }
+       
+       @Override
+       public void mouseClicked(MouseEvent e) {
+               if (useDefault) {
+                       panel.getDefaultAction().mouseClicked(e);
+                       return;
+               }
+               if (state == ToolState.ROUTING) {
+                       try {
+                               if (e.getClickCount() == 1) {
+                           if (e.getButton() == MouseEvent.BUTTON1) {
+                               if (this.added.size() > 0) {
+                                 
+                                   setLockType(LockType.NONE,true);
+                                   if (endTo != null) {
+                                       
+                                       endPiping();
+                                   } else {
+                                       addPoint();
+                                   }
+                               } else {
+                                       throw new RuntimeException("kjf");
+               //                      // user was selecting position of branch
+               //                    lastPoint.set(startPoint);
+               //                    controlPoints.add(new Point3d(startPoint));
+               //                    if (selectionLine != null)
+               //                      selectionLine.removeFromParent();
+               //                    selectionLine = null;
+                               }
+                           } else if (e.getButton() ==MouseEvent.BUTTON2){
+               //                detector.updateConstraintReference();
+                           } else if (e.getButton() == MouseEvent.BUTTON3){      
+                               endPiping();
+                           }
+                       }
+                       } catch(Exception err) {
+                               err.printStackTrace();
+                       }
+               } else if (state == ToolState.SELECTING_POSITION) {
+                       if (e.getClickCount() == 1 && e.getButton() == MouseEvent.BUTTON1) {
+                               int type = panel.getPickType();
+                               panel.setPickType(0);
+                               vtkProp[] picked = panel.pick(e.getX(), e.getY());
+                               panel.setPickType(type);
+                               PositionType position = terminalSelectionGizmo.getPickedPosition(picked);
+                               if (position != null) {
+                                       terminalSelectionGizmo.deattach();
+                                       try {
+                                       if (position == PositionType.SPLIT) {
+                                               activateSplit(startComponent.getControlPoint());
+                                       } else if (position == PositionType.NEXT || position == PositionType.PREVIOUS) {
+                                               reversed = position == PositionType.PREVIOUS;
+                                               activateNextPrev(startComponent.getControlPoint());
+                                       } else {
+                                               panel.useDefaultAction();
+                                       }
+                                       } catch (Exception err) {
+                                               ExceptionUtils.logAndShowError(err);
+                                               panel.useDefaultAction();
+                                       }
+                               }
+                       } 
+               } else if (state == ToolState.SELECTING_SPLIT) {
+                       if (e.getClickCount() == 1 && e.getButton() == MouseEvent.BUTTON1) {
+                               Tuple3d t = splitPointSelectionGizmo.getSplitPoint();
+                               splitPointSelectionGizmo.deattach();
+                               if (t == null) {
+                                       panel.useDefaultAction();
+                                       return;
+                               }
+                               try {
+                                       Vector3d pos = new Vector3d(t);
+                                       InlineComponent branchSplit = createBranchSplit((InlineComponent)startComponent, pos);
+                                       PipeControlPoint branchSplitCP = branchSplit.getControlPoint();
+                                       reversed = false;
+                                       PipeRun newRun = new PipeRun();
+                                       String n = root.getUniqueName("PipeRun");
+                                       newRun.setName(n);
+                                       root.addChild(newRun);
+                                       PipeControlPoint pcp = new PipeControlPoint(branchSplit,newRun);
+                                       branchSplitCP.children.add(pcp);
+                                       pcp.parent = branchSplitCP;
+                                       pcp.setWorldOrientation(branchSplitCP.getWorldOrientation());
+                                       pcp.setWorldPosition(branchSplitCP.getWorldPosition());
+                                       startComponent = branchSplit;
+                                       activateBranch(pcp);
+                               } catch (Exception err) {
+                                       ExceptionUtils.logAndShowError(err);
+                                       panel.useDefaultAction();
+                               }
+                       }
+               }
+               
+       }
+       
+       private InlineComponent createBranchSplit(InlineComponent component, Vector3d pos) throws Exception{
+               InlineComponent branchSplit = ComponentUtils.createBranchSplit(root);
+               String branchName = component.getPipeRun().getUniqueName("Branch");
+               branchSplit.setName(branchName);
+               component.getPipeRun().addChild(branchSplit);
+               PipeControlPoint branchSplitCP = branchSplit.getControlPoint();
+               branchSplitCP.setWorldPosition(pos);
+               PipingRules.splitVariableLengthComponent(branchSplit, component, false);
+               return branchSplit;
+       }
+       
+       @Override
+       public void mouseMoved(MouseEvent e) {
+               if (useDefault) {
+                       panel.getDefaultAction().mouseMoved(e);
+                       return;
+               }
+               step = ((e.getModifiers() & MouseEvent.CTRL_DOWN_MASK) > 0);
+               update(e.getX(), e.getY());
+       }
+       
+       @Override
+       public void mouseDragged(MouseEvent e) {
+               if (useDefault)
+                       panel.getDefaultAction().mouseDragged(e);
+       }
+       
+
+       
+       
+       private List<INode> isOverNode(int x, int y) {
+               List<INode> nodes = new ArrayList<INode>(); 
+               vtkProp picked[] = panel.pick2(x, y);
+               if (picked !=null) {
+                       for (int i = 0; i < picked.length; i++) {
+                               nodes.add(nodeMap.getNode(picked[i]));
+                       }
+               }
+               return nodes;
+       }
+       
+        
+     
+        private void updateRouting(double x, double y) {
+//             if(input.keyPressed(KeyEvent.VK_ESCAPE)) {
+//                 controlPoints.clear();
+//                 end();
+//                 return;
+//             }
+//             if (input.keyPressed(KeyEvent.VK_C)) {
+//                     useCamera = !useCamera;
+//                     cameraAction.setChecked(useCamera);
+//             }
+               if (useDefault) {
+                       //panel.getDefaultAction().update();
+                       return;
+               }
+               
+               endTo = null;
+               endType = null;
+               endPort = null;
+
+               Ray ray = vtkUtil.createMouseRay(panel.GetRenderer(),x, y);
+               Vector3d o = new Vector3d(ray.pos);
+               Vector3d d = ray.dir;
+               
+               
+               if (!updateCurrentPoint(o, d))
+                   return;
+               //Point3d startPoint = new Point3d();
+               double mu[] = new double[2];
+               
+               
+               
+               INode hoverObject = null;
+               
+               List<INode> hover = isOverNode((int)x,(int)y);
+               if (hover.size() > 0) {
+                       hoverObject = hover.get(0);
+               } 
+//             System.out.println(hoverObject + " " + getLast());
+               if (hoverObject != null) {
+                       if (hoverObject.equals(getLast()) ) {
+                               boolean set = false;
+                               for (int i = 1; i < hover.size(); i++) {
+                                       hoverObject = hover.get(i);
+                                       if (!getLast().equals(hoverObject)) {
+                                               set = true;
+                                               break;
+                                       }
+                               }
+                               if (!set)
+                                       hoverObject = null;
+                       }
+               }
+//             System.out.println(hoverObject);
+                 if (hoverObject != null) {
+                            
+                         if (lock == LockType.NONE) {
+                                 if (hoverObject instanceof Nozzle && endingToNozzle(hoverObject,o,d)) {
+                                         endTo = (Nozzle)hoverObject;
+                                 } else if (hoverObject instanceof InlineComponent && ((InlineComponent)hoverObject).isVariableLength()) {
+                                         endTo = (InlineComponent)hoverObject;
+                                         endType = endingToStraight(endTo,mu,o,d);     
+                                 } else if (hoverObject instanceof PipelineComponent && (endPort = endingToComponent(hoverObject,o,d)) != null) {
+                                         endTo = (PipelineComponent)hoverObject;
+                                 } else {
+                                         updateRoute(o,d); 
+                                 }
+                         } else {  
+                                 if (hoverObject instanceof InlineComponent && ((InlineComponent)hoverObject).isVariableLength() && (endType = endingLockToStraight(hoverObject,mu)) != null) {
+                                         endTo = (InlineComponent)hoverObject;;
+                                 } else if (hoverObject instanceof Nozzle && endingLockToNozzle(hoverObject)) {
+                                         endTo = (Nozzle)hoverObject;
+                                 } else if ((hoverObject instanceof PipelineComponent) &&  ((endPort = endingLockToComponent(hoverObject)) != null)) {
+                                         endTo = (PipelineComponent)hoverObject;
+                                 } else {
+                                         updateRoute(o,d);
+                                 }
+                         }
+                         if (added.contains(endTo))
+                                 endTo = null;
+                     
+               } else {
+                   updateRoute(o,d);
+               }
+                 
+               panel.repaint();
+               
+
+        
+               
+           }
+           
+           private boolean updateCurrentPoint(Vector3d o, Vector3d d) {
+
+               Vector3d point = new Vector3d(this.previousPosition);
+               
+               switch(lock) {
+               case X:
+                   MathTools.intersectStraightStraight(point, new Vector3d(1.0,0.0,0.0), o,d, currentPosition, new Vector3d());
+                   if (step) {
+                       currentPosition.x = Math.round(istep * currentPosition.x) / istep;
+                       BigDecimal bx = new BigDecimal(currentPosition.x);
+                       bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);
+                       currentPosition.x = bx.doubleValue();
+                   }
+                   break;
+               case Y:
+                   MathTools.intersectStraightStraight(point, new Vector3d(0.0,1.0,0.0), o,d, currentPosition, new Vector3d());
+                   if (step) {
+                       currentPosition.y = Math.round(istep * currentPosition.y) / istep;
+                       BigDecimal bx = new BigDecimal(currentPosition.y);
+                       bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);
+                       currentPosition.y = bx.doubleValue();
+                   }
+                   break;
+               case Z:
+                   MathTools.intersectStraightStraight(point, new Vector3d(0.0,0.0,1.0), o,d, currentPosition, new Vector3d());
+                   if (step) {
+                       currentPosition.z = Math.round(istep * currentPosition.z) / istep;
+                       BigDecimal bx = new BigDecimal(currentPosition.z);
+                       bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);
+                       currentPosition.z = bx.doubleValue();
+                   }break;
+               case XY:
+                   MathTools.intersectStraightPlane(o, d, point, new Vector3d(0.0,0.0,1.0), currentPosition);
+                   break;
+               case XZ:
+                   MathTools.intersectStraightPlane(o, d, point, new Vector3d(0.0,1.0,0.0), currentPosition);
+                   break;
+               case YZ:
+                   MathTools.intersectStraightPlane(o, d, point, new Vector3d(1.0,0.0,0.0), currentPosition);
+                   break;
+               case NONE:
+                       Vector3d normal = new Vector3d(panel.GetRenderer().GetActiveCamera().GetDirectionOfProjection());
+                   normal.normalize();
+                   
+                   MathTools.intersectStraightPlane(o, d, point, normal, currentPosition);
+                   break;
+               case CUSTOM:
+                       MathTools.intersectStraightStraight(point, new Vector3d(direction), o,d, currentPosition, new Vector3d());
+                   double dist = MathTools.distanceFromPlane(new Vector3d(currentPosition), direction, previousPosition);
+                       if (dist < 0.0)
+                               currentPosition.set(previousPosition);
+                   break;
+               default:
+                   return false;
+               }
+               return true;
+           }
+           
+           private Vector3d getLockDir() {
+               switch (lock) {
+               case CUSTOM:
+                       return direction;
+               case X:
+                       return new Vector3d(1,0,0);
+               case Y:
+                       return new Vector3d(0,1,0);
+               case Z:
+                       return new Vector3d(0,0,1);
+               }
+               return null;
+           }
+           
+           private void updateRoute(Vector3d o, Vector3d d) {
+               detector.clearConstraintHighlights();
+               Point3d previousPipePoint = new Point3d(previousPosition);
+               String s = "";
+               if (lock == LockType.NONE) {
+                   Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint));
+                   if (p != null)
+                       currentPosition = new Vector3d(p);
+                   s += detector.getSnapString();
+
+               } else {
+                   Vector3d dir = new Vector3d(currentPosition);
+                   dir.sub(previousPipePoint);
+                   Point3d p = detector.getPointSnap(new Vector3d(previousPipePoint), dir);
+                   if (p != null)
+                       currentPosition = new Vector3d(p);
+                   s += detector.getSnapString();
+
+               }
+               
+               updateCurrentPoint();
+               s += currentPosition.toString();
+               setInfoText(s);
+           }
+           
+           vtkTextActor infoActor;
+           
+           private void setInfoText(String text) {
+               //System.out.println(text);
+               if (infoActor == null) {
+                       infoActor = new vtkTextActor();
+                       infoActor.GetTextProperty().SetColor(0.0, 0.0, 0.0);
+                       infoActor.GetTextProperty().ShadowOff();
+                       infoActor.GetTextProperty().ItalicOff();
+                       infoActor.GetTextProperty().BoldOff();
+                       infoActor.GetTextProperty().SetFontSize(18);
+                       infoActor.GetTextProperty().Delete();
+                       infoActor.GetProperty().SetColor(0.0, 0.0, 0.0);
+                       infoActor.GetProperty().Delete();
+
+                               
+                       infoActor.SetPosition(10,10);
+                               panel.GetRenderer().AddActor(infoActor);
+               }
+               infoActor.SetInput(text);
+           }
+           
+           private boolean endingToNozzle(INode nozzleNode,Vector3d o, Vector3d d) {
+               Nozzle nozzle = (Nozzle)nozzleNode;
+               PipeControlPoint pcp  =nozzle.getControlPoint();
+               if (pcp != null && (pcp.getNext() != null ||
+                                           pcp.getPrevious() != null))
+                       return false; // nozzle is already connected to pipe
+               currentPosition = pcp.getWorldPosition();
+               Point3d previousPipePoint = new Point3d(previousPosition);
+               Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint));
+               if (p != null) {
+                   if (MathTools.distance(p, currentPosition) > NOZZLE_SNAP_DISTANCE) {
+                       return false;
+                   }
+               } 
+               
+               updateCurrentPoint();
+               
+               setInfoText("Connect to nozzle " + currentPosition);
+               return true;
+           
+           }
+           
+           private PositionType endingToStraight(INode straightNode, double mu[], Vector3d o, Vector3d d) {
+               InlineComponent s = (InlineComponent)straightNode;
+               String info = "";
+               Point3d sStart = new Point3d();
+               Point3d sEnd = new Point3d();
+               s.getControlPointEnds(sStart, sEnd);
+               //detector.clearConstraintHighlights();
+               
+               Point3d previousPipePoint = new Point3d(previousPosition);
+               //String st = "";
+               if (lock == LockType.NONE) {
+                   Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint));
+                   if (p != null) {
+                       currentPosition = new Vector3d(p);
+                       // snapping is detected, check if snapped point can create branch with straight
+                       PositionType t = endingLockToStraight(s, mu);
+                       if (t != null)
+                           return t;
+                       // if not, we'll have to remove highlight that was added when snapped point was detected
+                       detector.clearConstraintHighlights();
+                   } 
+                     
+
+                   Vector3d sDir = new Vector3d(sEnd);
+                   sDir.sub(sStart);
+                   MathTools.intersectStraightStraight(sStart, sDir, o, d, currentPosition, new Point3d(), mu);
+                   
+
+               } else {
+                   throw new RuntimeException("Lock shouldn't be on");
+
+               }
+               
+               updateCurrentPoint();
+               
+               // branch point must lie between straight's ends. If connection point is exactly
+               // on straight end user may want to connect pipes to each other
+               // TODO : take account sizes of inline components)
+               // TODO : actually make connection if its detected
+               boolean connectPrev = false;
+               boolean connectNext = false;
+               
+               if (mu[0] < 0.0) {
+                   currentPosition.set(sStart);
+                   connectPrev = true;
+               }
+               else if (mu[0] > 1.0) {
+                   currentPosition.set(sEnd);
+                   connectNext = true;
+               }
+               boolean connect = false;
+               if (connectPrev) {
+                   PipeControlPoint pcp = s.getControlPoint();
+                   if (pcp.getPrevious() == null)
+                       connect = true;
+               } else if (connectNext) {
+                       PipeControlPoint pcp = s.getControlPoint();
+                   if (pcp.getNext() == null)
+                       connect = true;
+               }
+               
+               updateCurrentPoint();
+               
+               if (connect)
+                   info += "Connect pipes :";
+               else
+                   info += "Make Branch :";
+               
+               setInfoText(info + currentPosition + " " + Math.max(0.0, Math.min(mu[0], 1.0)));
+               if (connect) {
+                       if (connectNext) {
+                               return PositionType.NEXT;
+                       } else {
+                               return PositionType.PREVIOUS;
+                       }
+                               
+               }
+               return PositionType.SPLIT;
+                       
+           }
+           
+           private PipeControlPoint endingToComponent(INode componentNode, Vector3d o, Vector3d d) {
+               PipelineComponent component = (PipelineComponent)componentNode;
+               PipeControlPoint pcp = component.getControlPoint();
+               if (component instanceof EndComponent) {
+                       if (pcp.getNext() != null || pcp.getPrevious() != null)
+                               return null;
+                       return pcp;
+               } else if (component instanceof TurnComponent) {
+                       if (pcp.getNext() == null || pcp.getPrevious() == null)
+                               return pcp;
+                       return null;
+               } else if (component instanceof InlineComponent) {
+                       // TODO : scan all empty pcps of the component and select closest one.
+                       if (pcp.getNext() == null || pcp.getPrevious() == null)
+                               return pcp;
+                       return null;
+               }
+
+               return null;
+           }
+           
+           private PositionType endingLockToStraight(INode straightNode, double mu[]) {
+               InlineComponent s = (InlineComponent)straightNode;
+               Point3d sStart = new Point3d();//G3DTools.getPoint(s.getHasControlPoint().getPreviousPoint().getLocalPosition());
+               Point3d sEnd = new Point3d(); //G3DTools.getPoint(s.getHasControlPoint().getNextPoint().getLocalPosition());
+               s.getControlPoint().getInlineControlPointEnds(sStart, sEnd);  
+               Vector3d sDir = new Vector3d(sEnd);
+               sDir.sub(sStart);
+               Vector3d dir = new Vector3d(currentPosition);
+               Point3d prev = new Point3d(previousPosition);
+               dir.sub(prev);
+               // intersection point in pipe where branch would be inserted to
+               Vector3d branchPoint = new Vector3d();
+               // intersection point in straight pipe that is currently routed
+               Vector3d routePoint = new Vector3d();
+               MathTools.intersectStraightStraight(sStart, sDir, new Vector3d(prev), dir, branchPoint, routePoint, mu);
+               routePoint.sub(branchPoint);
+               // startPoint of branch must be between pipe ends
+               // TODO : take account sizes of elbows (or other components)
+               // branch point must be between pipe ends and intersection points must be quite close to each othert
+               if (mu[0] > 0.0 && mu[0] < 1.0 && routePoint.lengthSquared() < BRANCH_SNAP_DISTANCE) {
+                   currentPosition.set(branchPoint);
+                   
+                   updateCurrentPoint();
+                   
+                   setInfoText("Make branch (l) :" + currentPosition + " " + Math.max(0.0, Math.min(mu[0], 1.0)) + " " + routePoint.lengthSquared());
+                   return PositionType.SPLIT;
+               }
+               return null;
+           }
+           
+           private boolean endingLockToNozzle(INode nozzleNode) {
+               Nozzle nozzle = (Nozzle)nozzleNode;
+                Vector3d dir = new Vector3d(currentPosition);
+                Point3d prev = new Point3d(previousPosition);
+                dir.sub(prev);
+                Vector3d nozzleLoc = nozzle.getWorldPosition();
+                double u[] = new double[1];
+                Vector3d closest = MathTools.closestPointOnStraight(new Point3d(nozzleLoc), new Point3d(prev), new Vector3d(dir), u);
+                double dist = MathTools.distanceSquared(nozzleLoc,closest);
+                if (dist < BRANCH_SNAP_DISTANCE) {
+                        // FIXME : directions should be checked (insert an elbow)
+                        currentPosition.set(nozzleLoc);
+                        updateCurrentPoint();
+                        setInfoText("Connect to nozzle (l) :" + currentPosition);
+                        return true;
+                } 
+                //System.out.println(u[0]);
+               return false;
+           }
+           
+           private PipeControlPoint endingLockToComponent(INode componentNode) {
+               // we'll must scan all free pcp's and their direction to accept the connection.
+               return null;
+           }
+           
+           private void addPoint() throws Exception {
+               InlineComponent previous = (InlineComponent)getLast();
+               PipeControlPoint previousCP = previous.getControlPoint();
+               TurnComponent turn = ComponentUtils.createTurn(root);
+               InlineComponent straight = ComponentUtils.createStraight(root);
+               PipeControlPoint turnCP = turn.getControlPoint();
+               PipeControlPoint straightCP = straight.getControlPoint();
+               straight.setName(pipeRun.getUniqueName("Pipe"));
+               turn.setName(pipeRun.getUniqueName("Elbow"));
+               pipeRun.addChild(turn);
+               pipeRun.addChild(straight);
+               added.add(turn);
+               added.add(straight);
+               
+               turnCP.setDeletable(false); // mark turnCP nonDeletable so that PipingRules won't delete it immediately.
+               
+               if (!reversed) {
+                       previousCP.setNext(turnCP);
+                       turnCP.setPrevious(previousCP);
+                       turnCP.setNext(straightCP);
+                       straightCP.setPrevious(turnCP);
+               } else {
+                       previousCP.setPrevious(turnCP);
+                       turnCP.setNext(previousCP);
+                       turnCP.setPrevious(straightCP);
+                       straightCP.setNext(turnCP);
+               }
+               
+               turnCP.setWorldPosition(currentPosition);
+               turnCP.setTurnAngle(0.0);
+               turnCP.setLength(0.0);
+               straightCP.setWorldPosition(currentPosition);
+               straightCP.setLength(0.0);
+               
+               setPreviousPosition(currentPosition);
+               updateCurrentPoint();
+               
+               
+               
+           }
+           
+           /**
+            * Updates tool graphics for current point 
+            */
+           private void updateCurrentPoint() {
+//             PipeComponentProvider.createStraightEdges(pipeShapes.get(pipeShapes.size() - 1), controlPoints.get(controlPoints.size() - 1), currentPoint, pipeDiameter*0.5);
+               InlineComponent straight = (InlineComponent)added.get(added.size()-1);
+               // FIXME : does not take account space the the previous elbow reserves. 
+               Vector3d v = new Vector3d();
+               v.sub(currentPosition, previousPosition);
+               double length = v.length();
+               v.scale(0.5);
+               v.add(previousPosition);
+               straight.getControlPoint().setWorldPosition(v);
+               straight.getControlPoint().setLength(length);
+               try {
+                               PipingRules.positionUpdate(straight.getControlPoint(),false);
+                       } catch (Exception e) {
+                               // TODO Auto-generated catch block
+                               e.printStackTrace();
+                       }
+           }
+           
+           private PipelineComponent getLast() {
+               if (added.size() == 0)
+                       return startComponent;
+               return added.get(added.size()-1);
+           }
+          
+           
+           /**
+            * Removes last point from pipeline
+            */
+           public void removePoint() {
+               if (added.size() < 3)
+                       return;
+               InlineComponent straight = (InlineComponent)added.remove(added.size()-1);
+               TurnComponent turn = (TurnComponent)added.remove(added.size()-1);
+               straight.getControlPoint().remove();
+               turn.getControlPoint().remove();
+               if (added.size() > 1) {
+                       setPreviousPosition(added.get(added.size()-2).getWorldPosition());
+               } else {
+                       setPreviousPosition(startComponent.getWorldPosition());
+                       if (direction != null)
+                               setLockType(LockType.CUSTOM, true);
+               }
+               
+           }
+           
+           private void endPiping() throws Exception {
+               state = ToolState.NOT_ACTIVE;
+                
+               if (endTo != null) {
+                       PipeControlPoint endCP = endTo.getControlPoint();
+                       if (endType == null || endType == PositionType.NEXT || endType == PositionType.PREVIOUS) {
+                               
+                               PipelineComponent current = getLast();
+                               PipeControlPoint currentCP = current.getControlPoint();
+                               
+                               boolean requiresReverse = false;
+                               if (!reversed && endCP.getPrevious() != null) {
+                                       requiresReverse = true;
+                               } else if (reversed && endCP.getNext() != null) {
+                                       requiresReverse = true;
+                               }
+                               PipeRun other = endCP.getPipeRun();
+                               boolean mergeRuns = pipeRun.equalSpecs(other);
+                               
+                               if (requiresReverse) {
+                                       // Pipe line must be traversible with next/previous relations without direction change.
+                                       // Now the component, where we are connecting the created pipeline is defined in different order.
+                                       PipingRules.reverse(other);
+                                       
+                               }
+                               if (mergeRuns) {
+                                       // Runs have compatible specs and must be merged
+                                       if (pipeRun != other) // FIXME: temporary workaround.
+                                               PipingRules.merge(pipeRun, other);
+                                       if (!reversed) {
+                                               currentCP.setNext(endCP);
+                                               endCP.setPrevious(currentCP);
+                                       } else {
+                                               currentCP.setPrevious(endCP);
+                                               endCP.setNext(currentCP);
+                                       }
+                               } else {
+                                       // Runs do not have compatible specs, and a reducer must be attached in between.
+                                       InlineComponent reducer = ComponentUtils.createReducer(root);
+                                       PipeControlPoint pcp = reducer.getControlPoint();
+                                       PipeControlPoint ocp = pcp.getSubPoint().get(0);
+                                       
+                                       Vector3d endPos = endCP.getWorldPosition();
+                                       Vector3d currentPos = currentCP.getWorldPosition();
+                                       Vector3d v = new Vector3d(endPos);
+                                       v.sub(currentPos);
+                                       v.scale(0.5);
+                                       v.add(currentPos);
+                                       
+                                       PipingRules.addSizeChange(reversed, pipeRun, other, reducer, currentCP, endCP);
+                                       
+                                       pcp.setWorldPosition(v);
+                                       reducer.updateParameters();
+                               }
+                               
+                       } else if (endType == PositionType.SPLIT) {
+                               InlineComponent branchSplit = createBranchSplit((InlineComponent)endTo, currentPosition);
+                                       PipeControlPoint branchSplitCP = branchSplit.getControlPoint();
+                                       PipeControlPoint pcp = new PipeControlPoint(branchSplit,pipeRun);
+                                       branchSplitCP.children.add(pcp);
+                                       pcp.parent = branchSplitCP;
+                                       pcp.setWorldOrientation(branchSplitCP.getWorldOrientation());
+                                       pcp.setWorldPosition(branchSplitCP.getWorldPosition());
+                                       
+                                       PipelineComponent current = getLast();
+                               PipeControlPoint currentCP = current.getControlPoint();
+                               
+                               
+                               if(!reversed) {
+                                       pcp.setPrevious(currentCP);
+                                       currentCP.setNext(pcp);
+                               } else {
+                                       pcp.setNext(currentCP);
+                                       currentCP.setPrevious(pcp);
+                               }
+                                       
+                       }
+                       PipingRules.positionUpdate(endCP);
+               }
+               panel.useDefaultAction();
+           }
+}
diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/browser/P3DBrowser.java b/org.simantics.plant3d/src/org/simantics/plant3d/browser/P3DBrowser.java
new file mode 100644 (file)
index 0000000..176fbaa
--- /dev/null
@@ -0,0 +1,15 @@
+package org.simantics.plant3d.browser;
+
+import java.util.Set;
+
+import org.simantics.structural.ui.modelBrowser.ModelBrowser2;
+
+public class P3DBrowser extends ModelBrowser2 {
+       
+       
+       @Override
+       protected Set<String> getBrowseContexts() {
+               return browseContexts;
+       }
+
+}
diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/dialog/ComponentContentProvider.java b/org.simantics.plant3d/src/org/simantics/plant3d/dialog/ComponentContentProvider.java
new file mode 100644 (file)
index 0000000..fe55fdf
--- /dev/null
@@ -0,0 +1,26 @@
+package org.simantics.plant3d.dialog;
+
+import java.util.List;
+
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+import org.simantics.plant3d.utils.Item;
+
+public class ComponentContentProvider implements IStructuredContentProvider {
+       
+       @Override
+       public Object[] getElements(Object inputElement) {
+               List<Item> list = (List<Item>)inputElement;
+               return list.toArray();
+       }
+       
+       @Override
+       public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+               
+       }
+       @Override
+       public void dispose() {
+               
+       }
+
+}
diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/dialog/ComponentLabelProvider.java b/org.simantics.plant3d/src/org/simantics/plant3d/dialog/ComponentLabelProvider.java
new file mode 100644 (file)
index 0000000..ab32c89
--- /dev/null
@@ -0,0 +1,16 @@
+package org.simantics.plant3d.dialog;
+
+import org.eclipse.jface.viewers.LabelProvider;
+import org.simantics.plant3d.utils.Item;
+
+public class ComponentLabelProvider extends LabelProvider{
+       
+       @Override
+       public String getText(Object element) {
+               Item item = (Item)element;
+               return item.getName();
+       }
+       
+       
+
+}
diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/dialog/ComponentSelectionDialog.java b/org.simantics.plant3d/src/org/simantics/plant3d/dialog/ComponentSelectionDialog.java
new file mode 100644 (file)
index 0000000..33d5882
--- /dev/null
@@ -0,0 +1,332 @@
+package org.simantics.plant3d.dialog;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.ListViewer;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.KeyAdapter;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.ExpandBar;
+import org.eclipse.swt.widgets.ExpandItem;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint.PositionType;
+import org.simantics.plant3d.utils.Item;
+import org.simantics.plant3d.utils.Item.Type;
+import org.simantics.plant3d.utils.P3DUtil;
+import org.simantics.utils.ui.ExceptionUtils;
+
+public class ComponentSelectionDialog extends Dialog implements ISelectionChangedListener{
+
+       private Item selected;
+       private Set<PositionType> allowed;
+       private Set<PositionType> filterAllowed;
+       private Double angle;
+       private Double length;
+       
+       private Text lengthText;
+       private Text angleText;
+       
+       private Double diameter;
+       private Double turnRadius;
+       
+       private Text diameterText;
+       private Text turnRadiusText;
+       
+       private boolean inlineSplit = false;
+       
+       
+       public ComponentSelectionDialog(Shell parentShell, Set<PositionType> allowed) {
+               super(parentShell);
+               this.allowed = allowed;
+               filterAllowed = new HashSet<PositionType>();
+       }
+       
+       @Override
+       protected Control createDialogArea(Composite parent) {
+               Composite composite = new Composite(parent, SWT.NONE);
+               GridLayout layout = new GridLayout(2,false);
+               layout.marginHeight = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN);
+               layout.marginWidth = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN);
+               layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);
+               layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);
+               composite.setLayout(layout);
+               composite.setLayoutData(new GridData(GridData.FILL_BOTH));
+               applyDialogFont(composite);
+               
+               // TODO : we need better classification than inline,turn, and end:
+               // * fixed length inlines
+               // * fixed angle turns
+               // * size changes (requires input for pipe run specs)
+               // * variable length inlines (input for length)
+               // * variable angle turns (input for angle)
+               // * ends
+               
+               List<Item> ends = null;
+               List<Item> turns = null;
+               List<Item> inlines = null;
+               try {
+                       ends = P3DUtil.getEnds();
+                       turns= P3DUtil.getTurns();
+                       inlines = P3DUtil.getInlines();
+               } catch (DatabaseException e) {
+                       Label label = new Label(composite, SWT.NONE);
+                       label.setText("Cannot load pipeline components: " + e.getMessage());
+                       ExceptionUtils.logError(e);
+                       return composite;
+               }
+               
+               ExpandBar expandBar = new ExpandBar(composite, SWT.NONE);
+               
+               
+               ExpandItem inlineItem = new ExpandItem(expandBar, SWT.NONE);
+               inlineItem.setText("Inline");
+               ListViewer inlineViewer = new ListViewer(expandBar);
+               inlineViewer.setLabelProvider(new ComponentLabelProvider());
+               inlineViewer.setContentProvider(new ComponentContentProvider());
+               
+               ExpandItem turnItem = new ExpandItem(expandBar, SWT.NONE);
+               turnItem.setText("Turn");
+               ListViewer turnViewer = new ListViewer(expandBar);
+               turnViewer.setLabelProvider(new ComponentLabelProvider());
+               turnViewer.setContentProvider(new ComponentContentProvider());
+               
+               ExpandItem endItem = new ExpandItem(expandBar, SWT.NONE);
+               endItem.setText("End");
+               ListViewer endViewer = new ListViewer(expandBar);
+               endViewer.setLabelProvider(new ComponentLabelProvider());
+               endViewer.setContentProvider(new ComponentContentProvider());
+               
+               
+               inlineItem.setControl(inlineViewer.getList());
+               turnItem.setControl(turnViewer.getList());
+               endItem.setControl(endViewer.getList());
+               
+               inlineViewer.setInput(inlines);
+               turnViewer.setInput(turns);
+               endViewer.setInput(ends);
+               
+               inlineItem.setHeight(inlineViewer.getList().computeSize(SWT.DEFAULT, SWT.DEFAULT).y);
+               turnItem.setHeight(turnViewer.getList().computeSize(SWT.DEFAULT, SWT.DEFAULT).y);
+               endItem.setHeight(endViewer.getList().computeSize(SWT.DEFAULT, SWT.DEFAULT).y);
+               
+               inlineViewer.addSelectionChangedListener(this);
+               turnViewer.addSelectionChangedListener(this);
+               endViewer.addSelectionChangedListener(this);
+               
+               GridDataFactory.fillDefaults().grab(true, true).align(SWT.FILL, SWT.FILL).span(2, 1).applyTo(expandBar);
+               GridDataFactory.fillDefaults().minSize(500, 500).hint(500, 500).applyTo(composite);
+               
+               
+               Label label = new Label(composite, SWT.NONE);
+               label.setText("Length");
+               lengthText = new Text(composite, SWT.SINGLE|SWT.BORDER);
+               label = new Label(composite, SWT.NONE);
+               label.setText("Angle");
+               angleText = new Text(composite, SWT.SINGLE|SWT.BORDER);
+               
+               label = new Label(composite, SWT.NONE);
+               label.setText("Diameter");
+               diameterText = new Text(composite, SWT.SINGLE|SWT.BORDER);
+               label = new Label(composite, SWT.NONE);
+               label.setText("Turn Radius");
+               turnRadiusText = new Text(composite, SWT.SINGLE|SWT.BORDER);
+               
+               lengthText.setEnabled(false);
+               angleText.setEnabled(false);
+               turnRadiusText.setEnabled(false);
+               diameterText.setEnabled(false);
+               
+               lengthText.addKeyListener(new KeyAdapter() {
+                       @Override
+                       public void keyReleased(KeyEvent e) {
+                               try {
+                                       length = Double.parseDouble(lengthText.getText());
+                               } catch (NumberFormatException err) {
+                                       length = null;
+                               }
+                               validate();
+                       }
+               });
+               
+               angleText.addKeyListener(new KeyAdapter() {
+                       @Override
+                       public void keyReleased(KeyEvent e) {
+                               try {
+                                       angle = Double.parseDouble(angleText.getText());
+                               } catch (NumberFormatException err) {
+                                       angle = null;
+                               }
+                               validate();
+                       }
+               });
+               
+               diameterText.addKeyListener(new KeyAdapter() {
+                       @Override
+                       public void keyReleased(KeyEvent e) {
+                               try {
+                                       diameter = Double.parseDouble(diameterText.getText());
+                               } catch (NumberFormatException err) {
+                                       diameter = null;
+                               }
+                               validate();
+                       }
+               });
+               
+               turnRadiusText.addKeyListener(new KeyAdapter() {
+                       @Override
+                       public void keyReleased(KeyEvent e) {
+                               try {
+                                       turnRadius = Double.parseDouble(turnRadiusText.getText());
+                               } catch (NumberFormatException err) {
+                                       turnRadius = null;
+                               }
+                               validate();
+                       }
+               });
+               
+               GridDataFactory.fillDefaults().grab(true, false).align(SWT.FILL, SWT.TOP).applyTo(lengthText);
+               GridDataFactory.fillDefaults().grab(true, false).align(SWT.FILL, SWT.TOP).applyTo(angleText);
+               GridDataFactory.fillDefaults().grab(true, false).align(SWT.FILL, SWT.TOP).applyTo(diameterText);
+               GridDataFactory.fillDefaults().grab(true, false).align(SWT.FILL, SWT.TOP).applyTo(turnRadiusText);
+               
+               if (!allowed.contains(PositionType.NEXT) && !allowed.contains(PositionType.PREVIOUS)) {
+                       turnViewer.getList().setEnabled(false);
+                       endViewer.getList().setEnabled(false);
+                       inlineSplit = true;
+               }
+               
+               return composite;
+       }
+       
+       
+       @Override
+       public void selectionChanged(SelectionChangedEvent event) {
+               IStructuredSelection sel = (IStructuredSelection)event.getSelection();
+               selected = (Item)sel.getFirstElement();
+               validate();                     
+       }
+       
+       private void validate() {
+               filterAllowed.clear();
+               Set<PositionType> filterAllowed = new HashSet<PositionType>();
+               boolean ok = true;
+               if (selected.isCode())// TODO : instead of disabling the button, we should filter the content.
+                       ok = false;
+               
+               if (selected.isVariable()) {
+                       if (selected.getType() == Type.INLINE) {
+                               filterAllowed.add(PositionType.NEXT);
+                               filterAllowed.add(PositionType.PREVIOUS);
+                               if (inlineSplit) {
+                                       lengthText.setEnabled(false);
+                                       angleText.setEnabled(false);
+                                       ok = false;
+                                       
+                               } else {
+                                       lengthText.setEnabled(true);
+                                       angleText.setEnabled(false);
+                                       if (length == null)
+                                               ok = false;
+                               }
+                       } else if (selected.getType() == Type.TURN) {
+                               filterAllowed.add(PositionType.NEXT);
+                               filterAllowed.add(PositionType.PREVIOUS);
+                               lengthText.setEnabled(false);
+                               angleText.setEnabled(true);
+                               if (angle == null)
+                                       ok = false;
+                       } else {
+                               // this should not happen
+                               lengthText.setEnabled(false);
+                               angleText.setEnabled(false);
+                       }
+               } else {
+                       lengthText.setEnabled(false);
+                       angleText.setEnabled(false);                    
+               }
+               if (selected.isSizeChange()) {
+                       filterAllowed.add(PositionType.NEXT);
+                       filterAllowed.add(PositionType.PREVIOUS);
+                       if (inlineSplit) {
+                               turnRadiusText.setEnabled(false);
+                               diameterText.setEnabled(false);
+                               ok = false;
+                       } else {
+                               turnRadiusText.setEnabled(true);
+                               diameterText.setEnabled(true);
+                               if (diameter == null || turnRadius == null)
+                                       ok = false;
+                       }
+                       
+               } else {
+                       turnRadiusText.setEnabled(false);
+                       diameterText.setEnabled(false);
+               }
+               if (!selected.isSizeChange() && !selected.isVariable()) {
+                       switch (selected.getType()) {
+                               case END:
+                                       filterAllowed.add(PositionType.NEXT);
+                                       filterAllowed.add(PositionType.PREVIOUS);
+                                       break;
+                               case NOZZLE:
+                               case EQUIPMENT:
+                                       break;
+                               case INLINE:
+                                       filterAllowed.add(PositionType.NEXT);
+                                       filterAllowed.add(PositionType.PREVIOUS);
+                                       filterAllowed.add(PositionType.SPLIT);
+                               case TURN:
+                                       filterAllowed.add(PositionType.NEXT);
+                                       filterAllowed.add(PositionType.PREVIOUS);
+                       }
+               }
+               
+               for (PositionType t : filterAllowed) {
+                       if (allowed.contains(t))
+                               this.filterAllowed.add(t);
+               }
+       
+               getButton(OK).setEnabled(ok); 
+       }
+       
+       public Item getSelected() {
+               return selected;
+       }
+       
+       public Double getAngle() {
+               return angle;
+       }
+       
+       public Double getLength() {
+               return length;
+       }
+       
+       public Double getDiameter() {
+               return diameter;
+       }
+       
+       public Double getTurnRadius() {
+               return turnRadius;
+       }
+       
+       public Set<PositionType> filterAllowed() {
+               return filterAllowed;
+       }
+       
+
+}
diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/editor/P3DContentOutlinePage.java b/org.simantics.plant3d/src/org/simantics/plant3d/editor/P3DContentOutlinePage.java
new file mode 100644 (file)
index 0000000..c675b11
--- /dev/null
@@ -0,0 +1,151 @@
+package org.simantics.plant3d.editor;
+
+import org.eclipse.jface.action.IMenuListener;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.resource.LocalResourceManager;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.swt.events.MenuDetectEvent;
+import org.eclipse.swt.events.MenuDetectListener;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Menu;
+import org.simantics.db.Resource;
+import org.simantics.g3d.scenegraph.base.INode;
+import org.simantics.g3d.scenegraph.base.ParentNode;
+import org.simantics.g3d.vtk.common.NodeSelectionProvider2;
+import org.simantics.g3d.vtk.common.VTKContentOutlinePage;
+import org.simantics.plant3d.Activator;
+import org.simantics.plant3d.scenegraph.EndComponent;
+import org.simantics.plant3d.scenegraph.Equipment;
+import org.simantics.plant3d.scenegraph.InlineComponent;
+import org.simantics.plant3d.scenegraph.Nozzle;
+import org.simantics.plant3d.scenegraph.P3DRootNode;
+import org.simantics.plant3d.scenegraph.PipeRun;
+import org.simantics.plant3d.scenegraph.PipelineComponent;
+import org.simantics.plant3d.scenegraph.TurnComponent;
+import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint;
+
+public class P3DContentOutlinePage extends VTKContentOutlinePage<Resource, Object>{
+       
+       private static final boolean DEBUG = false;
+       protected Menu contextMenu;
+       
+       private LocalResourceManager manager = new LocalResourceManager(JFaceResources.getResources());
+       
+       private Image nozzleImage;
+       private Image pipeImage;
+       private Image tankImage;
+       private Image elbowImage;
+       private Image componentImage;
+       
+       public  P3DContentOutlinePage(ParentNode<? extends INode> rootNode, NodeSelectionProvider2<Resource,Object> provider) {
+               super(rootNode,provider);
+               
+               nozzleImage = manager.createImage(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/Nozzle.png"));
+               pipeImage = manager.createImage(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/Straight.png"));
+               tankImage = manager.createImage(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/tank.png"));
+               elbowImage = manager.createImage(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/Elbow.png"));
+               componentImage = manager.createImage(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/Component.png"));
+       }
+       
+       @Override
+       protected void createProviders(TreeViewer viewer) {
+               viewer.setContentProvider(new ScenegraphContentProvider() {
+                       @Override
+                       public Object[] getChildren(Object parentElement) {
+                               if (parentElement instanceof P3DRootNode) {
+                                       return ((P3DRootNode)parentElement).getChild().toArray();
+                               }
+                               if (!DEBUG) {
+                                       if (parentElement instanceof PipeRun) {
+                                               return ((PipeRun)parentElement).getSortedChild().toArray();
+                                       }
+                               } else {
+                                       if (parentElement instanceof PipelineComponent) {
+                                               return new Object[]{((PipelineComponent) parentElement).getControlPoint()};
+                                       } else if (parentElement instanceof PipeControlPoint) {
+                                               return new Object[]{((PipeControlPoint) parentElement).getPipelineComponent()};
+                                       }
+                               }
+                               return super.getChildren(parentElement);
+                       }
+                       
+                       @Override
+                       public boolean hasChildren(Object element) {
+                               if (element instanceof P3DRootNode) {
+                                       return ((P3DRootNode)element).getChild().size() > 0;
+                               }
+                               if (!DEBUG) {
+                                       if (element instanceof PipeRun) {
+                                               return ((PipeRun)element).getChild().size() > 0;
+                                       }
+                               } else {
+                                       if (element instanceof PipelineComponent) {
+                                               return ((PipelineComponent) element).getControlPoint() != null;
+                                       } else if (element instanceof PipeControlPoint) {
+                                               return ((PipeControlPoint) element).getPipelineComponent() != null;
+                                       }
+                               }
+                               return super.hasChildren(element);
+                       }
+               });
+               viewer.setLabelProvider(new P3DLabelProvider());
+               
+               hookContextMenu(viewer);
+               viewer.getTree().addMenuDetectListener(new MenuDetectListener() {
+
+                       @Override
+                       public void menuDetected(MenuDetectEvent e) {
+                               contextMenu.setLocation(e.x, e.y);
+                               contextMenu.setVisible(true);
+                       }
+               });
+               
+       }
+       
+       @Override
+       public void dispose() {
+               manager.dispose();
+               super.dispose();
+       }
+       
+       protected void hookContextMenu(TreeViewer viewer) {
+        MenuManager menuMgr = new MenuManager("#PopupMenu");
+        menuMgr.setRemoveAllWhenShown(true);
+        menuMgr.addMenuListener(new IMenuListener() {
+            public void menuAboutToShow(IMenuManager manager) {
+               createContextMenu(manager);
+            }
+        });
+        contextMenu = menuMgr.createContextMenu(viewer.getTree());
+       }
+       
+       protected void createContextMenu(IMenuManager manager) {
+               
+       }
+
+       private class P3DLabelProvider extends ScenegraphLabelProvider {
+               @Override
+               public Image getImage(Object element) {
+                       if (element instanceof PipelineComponent) {
+                               PipelineComponent comp = (PipelineComponent)element;
+                               if (comp instanceof TurnComponent) {
+                                       return elbowImage;
+                               } else if (comp instanceof EndComponent) {
+                                       return componentImage;
+                               } else if (comp instanceof Nozzle) {
+                                       return nozzleImage;
+                               } else if (comp.getControlPoint().isFixed()) {
+                                       return componentImage;
+                               }
+                               return pipeImage;
+                       } else if (element instanceof Equipment) {
+                               return tankImage;
+                       } else if (element instanceof PipeRun) {
+                               return pipeImage;
+                       }
+                       return null;
+               }
+       }
+}
diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/editor/P3DNodeMap.java b/org.simantics.plant3d/src/org/simantics/plant3d/editor/P3DNodeMap.java
new file mode 100644 (file)
index 0000000..b098951
--- /dev/null
@@ -0,0 +1,246 @@
+package org.simantics.plant3d.editor;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.Session;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.g3d.ontology.G3D;
+import org.simantics.g3d.scenegraph.base.INode;
+import org.simantics.g3d.scenegraph.base.ParentNode;
+import org.simantics.g3d.vtk.common.AbstractVTKNodeMap;
+import org.simantics.g3d.vtk.common.InteractiveVtkPanel;
+import org.simantics.objmap.graph.IMapping;
+import org.simantics.plant3d.ontology.Plant3D;
+import org.simantics.plant3d.scenegraph.IP3DNode;
+import org.simantics.plant3d.scenegraph.IP3DVisualNode;
+import org.simantics.plant3d.scenegraph.P3DParentNode;
+import org.simantics.plant3d.scenegraph.P3DRootNode;
+import org.simantics.plant3d.scenegraph.ParameterizedNode;
+import org.simantics.plant3d.scenegraph.PipeRun;
+import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint;
+import org.simantics.plant3d.scenegraph.controlpoint.PipingRules;
+import org.simantics.utils.threads.AWTThread;
+
+import vtk.vtkProp;
+import vtk.vtkProp3D;
+
+public class P3DNodeMap extends AbstractVTKNodeMap<INode> {
+       
+       private static final boolean DEBUG = false;
+
+       public P3DNodeMap(Session session, IMapping mapping, InteractiveVtkPanel panel, P3DRootNode rootNode) {
+               super(session, mapping, panel, rootNode);
+               rootNode.setNodeMap(this);
+       }
+       @Override
+       protected void updateActor(INode n, Set<String> ids) {
+               if (DEBUG) System.out.println("P3DNodeMap update " + n);
+               if (!(n instanceof IP3DVisualNode)) {
+                       if (n instanceof PipeControlPoint) {
+                               n = ((PipeControlPoint)n).getPipelineComponent();
+                               if (n == null)
+                                       return;
+                       } else {
+                               return;
+                       }
+               }
+               
+               IP3DVisualNode node = (IP3DVisualNode)n;
+               
+               if (DEBUG) {
+                       System.out.print("P3DNodeMap update " + node);
+                       for (String s : ids)
+                               System.out.print(" " + s);
+                       System.out.println();
+               }
+               
+               if (ids.contains(Plant3D.URIs.hasGeometry)) {
+                       node.visualize(panel);
+                       updateRenderObjectsFor(node);
+                       updateTransform(node);
+               } 
+               if (n instanceof ParameterizedNode) {
+                       ParameterizedNode geom = (ParameterizedNode)n;
+                       for (String id : geom.getParameterMap().keySet()) {
+                               if (ids.contains(id)) {
+                                       node.visualize(panel);
+                                       updateRenderObjectsFor(node);
+                                       updateTransform(node);
+                                       break;
+                               }
+                       }
+               } else if (n instanceof PipeRun) {
+                       // FIXME: may require rule based update!
+                       PipeRun run = (PipeRun)n;
+                       Set<String> ids2 = new HashSet<String>();
+                       ids2.add(Plant3D.URIs.hasGeometry);
+                       for (PipeControlPoint pcp : run.getControlPoints()) {
+                               updateActor(pcp, ids2);
+                       }
+               }
+               
+               if (ids.contains(G3D.URIs.hasPosition) || 
+                       ids.contains(G3D.URIs.hasOrientation) ||
+                       ids.contains(G3D.URIs.hasWorldPosition) ||
+                       ids.contains(G3D.URIs.hasWorldOrientation)) {
+                       updateTransform(node);
+               }
+       }
+       
+       private void updateTransform(IP3DNode node) {
+               if (DEBUG) System.out.println("P3DNodeMap update Transform " + node);
+
+               node.update(panel.GetRenderer());
+               
+               if (node instanceof ParentNode<?>) {
+                       ParentNode<IP3DNode> p = (ParentNode<IP3DNode>)node;
+                       for (IP3DNode n : p.getNodes())
+                               updateTransform(n);
+               }
+       }
+
+       @Override
+       protected Collection<vtkProp> getActors(INode n) {
+               List<vtkProp> props = new ArrayList<vtkProp>();
+               if (!(n instanceof IP3DVisualNode))
+                       return props;
+               IP3DVisualNode node = (IP3DVisualNode)n;
+               for (vtkProp3D p : ((IP3DVisualNode)node).getActors())
+                       props.add(p);
+               
+               return props;
+       }
+       
+       @Override
+       protected void removeActor(INode n) {
+               if (DEBUG) System.out.println("P3DNodeMap.removeActor " + n);
+               if (!(n instanceof IP3DVisualNode))
+                       return;
+               IP3DVisualNode node = (IP3DVisualNode)n;
+               remActor(node);
+               
+               if (node instanceof P3DParentNode<?>) {
+                       for (IP3DNode n2 : ((P3DParentNode<?>)node).getNodes())
+                               if (n2 instanceof IP3DVisualNode)
+                                       removeActor((IP3DVisualNode)n2);
+               }
+       }
+       
+       @Override
+       protected void addActor(INode n) {
+               if (DEBUG) System.out.println("P3DNodeMap.addActor " + n);
+               if (!(n instanceof IP3DVisualNode))
+                       return;
+               IP3DVisualNode node = (IP3DVisualNode)n;
+               
+               if (hasActor(node))
+                       return;
+               if (Thread.currentThread() != AWTThread.getThreadAccess().getThread())
+                       throw new RuntimeException("Illegal thread.");
+               
+               panel.lock();
+               
+               node.visualize(panel);
+
+               for (vtkProp3D act : node.getActors()) {
+                       nodeToActor.add(node, act);
+            actorToNode.put(act, node);
+               }
+               
+               if (node instanceof P3DParentNode<?>) {
+                       for (IP3DNode n2 : ((P3DParentNode<?>)node).getNodes())
+                               if (n2 instanceof IP3DVisualNode)
+                                       addActor((IP3DVisualNode)n2);
+               }
+               
+               updateTransform(node);
+
+        panel.unlock();
+
+       }
+       
+       
+       
+       private boolean hasActor(IP3DVisualNode node) {
+               List<vtkProp> list = nodeToActor.getValues(node);
+               if (list == null || list.size() == 0)
+                       return false;
+               return true;
+       }
+       
+       private void remActor(IP3DVisualNode node) {
+               if (Thread.currentThread() != AWTThread.getThreadAccess().getThread())
+                       throw new RuntimeException("Illegal thread.");
+
+               List<vtkProp> list = nodeToActor.getValues(node);
+               if (list != null) {
+                       for (vtkProp obj : list) {
+                               actorToNode.remove(obj);        
+                       }
+                       nodeToActor.remove(node);
+                       panel.lock();
+                       
+                       node.stopVisualize();
+                       
+                       panel.unlock();
+               }
+       }
+       
+       @Override
+       protected void update(ReadGraph graph) throws DatabaseException {
+               validate();
+//             System.out.println("Graph updates");
+               super.update(graph);
+               validate();
+       }
+       
+       @Override
+       public void commit() {
+               validate();
+//             System.out.println("Graph commit");
+               super.commit();
+               
+       }
+       @Override
+       protected void doCommit() {
+//             System.out.println("Do commit");
+               validate();
+               super.doCommit();
+       }
+       
+       private void validate() {
+               for (INode node : rootNode.getNodes()) {
+                       if (node instanceof PipeRun)
+                               PipingRules.validate((PipeRun)node);
+               }
+       }
+       
+       @Override
+       public synchronized void preRender() {
+//             System.out.println("P3DNodeMap preRender");
+//             super.preRender();
+               try {
+//                     boolean b = false;
+//                     synchronized (syncMutex) {
+//                             b = PipingRules.update();
+//                     }
+//                     if (b)
+//                             super.preRender();
+                       boolean b = true;
+                       while (b) {
+                               updateCycle();
+                               b = PipingRules.update();
+                       }
+               } catch (Exception e) {
+                       e.printStackTrace();
+               }
+               
+       }
+
+}
diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/editor/Plant3DEditor.java b/org.simantics.plant3d/src/org/simantics/plant3d/editor/Plant3DEditor.java
new file mode 100644 (file)
index 0000000..9d0c3b8
--- /dev/null
@@ -0,0 +1,498 @@
+package org.simantics.plant3d.editor;
+
+import java.awt.Component;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.jface.action.IMenuListener;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.Session;
+import org.simantics.db.common.request.ReadRequest;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.g3d.scenegraph.IG3DNode;
+import org.simantics.g3d.scenegraph.NodeMap;
+import org.simantics.g3d.scenegraph.base.INode;
+import org.simantics.g3d.vtk.action.RemoveAction;
+import org.simantics.g3d.vtk.action.RotateAction;
+import org.simantics.g3d.vtk.action.TranslateAction;
+import org.simantics.g3d.vtk.action.vtkCameraAndSelectorAction;
+import org.simantics.g3d.vtk.common.HoverHighlighter;
+import org.simantics.g3d.vtk.common.InteractiveVtkPanel;
+import org.simantics.g3d.vtk.common.NodeSelectionProvider2;
+import org.simantics.g3d.vtk.common.SelectionHighlighter;
+import org.simantics.g3d.vtk.shape.vtkShape;
+import org.simantics.g3d.vtk.utils.vtkPanelUtil;
+import org.simantics.objmap.graph.IMapping;
+import org.simantics.objmap.graph.Mappings;
+import org.simantics.objmap.graph.schema.IMappingSchema;
+import org.simantics.plant3d.actions.AddComponentAction;
+import org.simantics.plant3d.actions.AddEquipmentAction;
+import org.simantics.plant3d.actions.AddNozzleAction;
+import org.simantics.plant3d.actions.RoutePipeAction;
+import org.simantics.plant3d.scenegraph.EndComponent;
+import org.simantics.plant3d.scenegraph.Equipment;
+import org.simantics.plant3d.scenegraph.IP3DNode;
+import org.simantics.plant3d.scenegraph.InlineComponent;
+import org.simantics.plant3d.scenegraph.Nozzle;
+import org.simantics.plant3d.scenegraph.P3DRootNode;
+import org.simantics.plant3d.scenegraph.PipeRun;
+import org.simantics.plant3d.scenegraph.PipelineComponent;
+import org.simantics.plant3d.scenegraph.SchemaBuilder;
+import org.simantics.plant3d.scenegraph.TurnComponent;
+import org.simantics.plant3d.scenegraph.controlpoint.ControlPointFactory;
+import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint;
+import org.simantics.plant3d.scenegraph.controlpoint.PipingRules;
+import org.simantics.plant3d.utils.ComponentUtils;
+import org.simantics.plant3d.utils.Item;
+import org.simantics.plant3d.utils.P3DUtil;
+import org.simantics.selectionview.StandardPropertyPage;
+import org.simantics.ui.workbench.IPropertyPage;
+import org.simantics.ui.workbench.IResourceEditorInput;
+import org.simantics.ui.workbench.ResourceEditorPart;
+import org.simantics.utils.threads.AWTThread;
+import org.simantics.utils.threads.ThreadUtils;
+import org.simantics.utils.ui.ExceptionUtils;
+import org.simantics.utils.ui.SWTAWTComponent;
+
+import vtk.vtkActor;
+import vtk.vtkAxesActor;
+import vtk.vtkCameraPass;
+import vtk.vtkDefaultPass;
+import vtk.vtkLightsPass;
+import vtk.vtkOrientationMarkerWidget;
+import vtk.vtkRenderPassCollection;
+import vtk.vtkRenderer;
+import vtk.vtkSequencePass;
+
+
+public class Plant3DEditor extends ResourceEditorPart {
+
+       private Composite parent;
+       private Resource input;
+       private InteractiveVtkPanel panel;
+       private SWTAWTComponent component;
+       
+       private P3DRootNode rootNode;
+       private IMapping<Resource,Object> mapping;
+       
+       private NodeSelectionProvider2<Resource,Object> selectionProvider;
+       
+       private vtkCameraAndSelectorAction cameraAction;
+       private TranslateAction translateAction;
+       private RotateAction rotateAction;
+       private RemoveAction removeAction;
+       private RoutePipeAction routePipeAction;
+       private AddComponentAction addComponentAction;
+       
+       private P3DNodeMap nodeMap;
+       
+       @Override
+       public void createPartControl(Composite parent) {
+               this.parent = parent;
+               parent.setLayout (new FillLayout ());
+               component = new SWTAWTComponent(parent,SWT.NONE) {
+                       
+                       @Override
+                       protected Component createSwingComponent() {
+                               if (panel == null) {
+                                       panel = new InteractiveVtkPanel();
+                                       vtkPanelUtil.registerPanel(panel);
+                                       createScene();
+                               }
+                               return panel;
+                       }
+               };
+
+               IResourceEditorInput rei = (IResourceEditorInput)getEditorInput();
+               input = rei.getResource();
+               
+               
+               //IActionBars actionBars = getEditorSite().getActionBars();
+
+               hookContextMenu();
+               
+               component.syncPopulate();
+               
+               panel.addMouseListener(new java.awt.event.MouseAdapter() {
+                       @Override
+                       public void mouseClicked(final java.awt.event.MouseEvent e) {
+                               if (e.getButton() == java.awt.event.MouseEvent.BUTTON3) {
+                                       Display.getDefault().asyncExec(new Runnable() {
+                                               public void run() {
+                                                       contextMenu.setLocation(e.getXOnScreen(), e.getYOnScreen());
+                                                       contextMenu.setVisible(true);
+                                               }
+                                       });
+                               }
+                       }
+               });
+               
+
+               cameraAction = new vtkCameraAndSelectorAction(panel);   
+               panel.setDefaultAction(cameraAction);
+               panel.useDefaultAction();
+               panel.setPickType(4);
+               
+               try {
+                       ControlPointFactory.preloadCache();
+                       ComponentUtils.preloadCache();
+               } catch (Exception e) {
+                       ExceptionUtils.logAndShowError("Cannot open Plant3D editor",e);
+                       return;
+               }
+               
+               try {
+                       getSession().syncRequest(new ReadRequest() {
+                               
+                               @SuppressWarnings({ "rawtypes", "unchecked" })
+                               @Override
+                               public void run(ReadGraph graph) throws DatabaseException {
+                                       PipingRules.setEnabled(false);
+                                       IMappingSchema<Resource, Object> schema = getSchema(graph);
+                                       mapping = Mappings.createWithListening(schema);
+                                       rootNode = (P3DRootNode)mapping.map(graph, input);
+                                       // update control points.
+                                       // TODO : this should be optimized.
+                                       try {
+                                               for (INode node : rootNode.getChild()) {
+                                                       if (node instanceof PipeRun) {
+                                                               for (PipelineComponent pc : ((PipeRun) node).getChild())
+                                                                       pc.sync();
+                                                       } else if (node instanceof Equipment) {
+                                                               for (PipelineComponent pc : ((Equipment) node).getChild())
+                                                                       pc.sync();
+                                                       }
+                                               }
+                                               
+                                               for (INode node : rootNode.getChild()) {
+                                                       if (node instanceof PipeRun) {
+                                                               for (PipelineComponent pc : ((PipeRun) node).getChild())
+                                                                       pc.sync2();
+                                                       } else if (node instanceof Equipment) {
+                                                               for (PipelineComponent pc : ((Equipment) node).getChild())
+                                                                       pc.sync2();
+                                                       }
+                                               }
+                                               for (INode node : rootNode.getChild()) {
+                                                       if (node instanceof PipeRun) {
+                                                               PipingRules.validate((PipeRun)node);
+                                                       }
+                                               }
+                                               PipingRules.setEnabled(true);
+                                               for (INode node : rootNode.getChild()) {
+                                                       if (node instanceof PipeRun) {
+                                                               PipeRun run = (PipeRun)node;
+                                                               for (PipeControlPoint pcp : run.getControlPoints())
+                                                                       PipingRules.positionUpdate(pcp);
+                                                                       
+                                                       }
+                                               }
+                                       } catch (Exception e) {
+                                               throw new DatabaseException(e);
+                                       }
+                                       nodeMap = createNodeMap(getSession(), mapping, panel,rootNode);
+                               }
+                       });
+                       
+                       if (rootNode == null)
+                               throw new RuntimeException("Scenegraph loading failed.");
+                       populate();
+                       
+                       selectionProvider = new NodeSelectionProvider2<Resource,Object>(this,mapping,nodeMap);
+
+                       cameraAction.addSelectionChangedListener(selectionProvider);
+
+                       cameraAction.addHoverChangedListener(new HoverHighlighter(panel,nodeMap));
+                       selectionProvider.addSelectionChangedListener(new SelectionHighlighter(panel,nodeMap));
+                       
+                       getSite().setSelectionProvider(selectionProvider);
+                       getSite().getPage().addPostSelectionListener(selectionProvider);
+                       
+                       //outlinePage = new ScenegraphOutlinePage(rootNode);
+                       
+                       
+                       parent.addDisposeListener(new DisposeListener() {
+                               
+                               @Override
+                               public void widgetDisposed(DisposeEvent e) {
+                                       getSite().getPage().removePostSelectionListener(selectionProvider);
+                                       
+                                       ThreadUtils.asyncExec(AWTThread.getThreadAccess(), new Runnable() {
+                                               
+                                               @Override
+                                               public void run() {
+                                                       PipingRules.setEnabled(false);
+                                                       nodeMap.delete();
+                                                       PipingRules.setEnabled(true);
+                                                       vtkPanelUtil.unregisterPanel(panel);
+
+                                               }
+                                       });
+                                       mapping.dispose();
+                                       component.dispose();
+                                       
+                                       
+                               }
+                       });
+               } catch (DatabaseException e1) {
+                       ExceptionUtils.logAndShowError("Cannot open Plant3D editor",e1);
+                       return;
+               }
+               
+               translateAction = new TranslateAction(panel,nodeMap);
+               rotateAction = new RotateAction(panel,nodeMap);
+               removeAction = new RemoveAction(nodeMap) {
+                       public void setNode(IG3DNode node) {
+                               super.setNode(node);
+                               
+                               
+                       }
+               };
+               routePipeAction = new RoutePipeAction(panel,rootNode);
+               addComponentAction = new AddComponentAction(panel, rootNode);
+               
+       }
+       
+       public void populate() {
+               ThreadUtils.asyncExec(AWTThread.getThreadAccess(), new Runnable() {
+                       
+                       @Override
+                       public void run() {
+                               nodeMap.populate();
+                       }
+               });
+               
+       }
+       
+       protected IMappingSchema<Resource, Object> getSchema(ReadGraph graph) throws DatabaseException {
+               IMappingSchema<Resource,Object> schema = SchemaBuilder.getSchema(graph);
+               return schema;
+       }
+       
+       protected P3DNodeMap createNodeMap(Session session, IMapping<Resource, Object> mapping, InteractiveVtkPanel panel, P3DRootNode rootNode) {
+                return new P3DNodeMap(session, mapping, panel,rootNode);
+       }
+       
+       @Override
+       public void setFocus() {
+               component.setFocus();
+       }
+       
+       private void createScene() {
+               vtkRenderer ren1 = panel.GetRenderer();
+               
+               boolean multiPass = false;
+               if (multiPass) {
+                       
+                       vtkLightsPass lightsPass = new vtkLightsPass();
+                       vtkDefaultPass defaultPass = new vtkDefaultPass();
+                       
+                       
+                       vtkRenderPassCollection passes = new vtkRenderPassCollection();
+                       passes.AddItem(lightsPass);
+                       passes.AddItem(defaultPass);
+                       
+                       vtkSequencePass seq = new vtkSequencePass();
+                       seq.SetPasses(passes);
+                       
+               
+                       
+                       vtkCameraPass cameraPass = new vtkCameraPass();
+                       cameraPass.SetDelegatePass(seq);
+                       
+                       ren1.SetPass(cameraPass);
+                       
+               }
+//             ren1.GetRenderWindow().LineSmoothingOn();
+//             ren1.GetRenderWindow().PointSmoothingOn();
+//             ren1.GetRenderWindow().PolygonSmoothingOn();
+//             ren1.GetRenderWindow().SetMultiSamples(2);
+
+               
+
+               ren1.SetBackground2(1,1,1); // background color white
+               ren1.SetBackground(0.9,0.9,0.9);
+               ren1.SetGradientBackground(true);
+
+          // vtkActor grid = vtkShape.createGridActor(8,1.0,1|2|4);
+           vtkActor grid = vtkShape.createGridActor(8,1.0, 2 );
+           grid.SetPickable(0);
+           ren1.AddActor(grid);
+           panel.addDeletable(grid);
+           
+           {
+                   vtkAxesActor axes = new vtkAxesActor();
+                   axes.GetXAxisCaptionActor2D().GetCaptionTextProperty().SetColor(0,0,0);
+                   axes.GetYAxisCaptionActor2D().GetCaptionTextProperty().SetColor(0,0,0);
+                   axes.GetZAxisCaptionActor2D().GetCaptionTextProperty().SetColor(0,0,0);
+                   axes.GetXAxisCaptionActor2D().GetCaptionTextProperty().SetShadow(0);
+                   axes.GetYAxisCaptionActor2D().GetCaptionTextProperty().SetShadow(0);
+                   axes.GetZAxisCaptionActor2D().GetCaptionTextProperty().SetShadow(0);
+                   axes.GetXAxisCaptionActor2D().GetCaptionTextProperty().ItalicOff();
+                   axes.GetYAxisCaptionActor2D().GetCaptionTextProperty().ItalicOff();
+                   axes.GetZAxisCaptionActor2D().GetCaptionTextProperty().ItalicOff();
+                   axes.GetXAxisCaptionActor2D().GetCaptionTextProperty().Delete();
+                   axes.GetYAxisCaptionActor2D().GetCaptionTextProperty().Delete();
+                   axes.GetZAxisCaptionActor2D().GetCaptionTextProperty().Delete();
+                   axes.GetXAxisCaptionActor2D().Delete();
+                   axes.GetYAxisCaptionActor2D().Delete();
+                   axes.GetZAxisCaptionActor2D().Delete();
+                   vtkOrientationMarkerWidget widget = new vtkOrientationMarkerWidget();
+                   widget.SetOutlineColor(0.9300, 0.5700, 0.1300 );
+                   widget.SetOrientationMarker(axes);
+                   widget.SetInteractor(panel.getRenderWindowInteractor());
+                   //widget.SetViewport(0.8, 0.0, 1.0, 0.2); // bottom right
+                   //widget.SetViewport(0.0, 0.0, 0.4, 0.4);
+                   widget.SetViewport(0.0, 0.0, 0.2, 0.2);  // bottom left
+                   widget.SetEnabled(1);
+                   widget.InteractiveOff();
+           }
+
+               
+       }
+       
+       protected Menu contextMenu;
+       
+       protected void hookContextMenu() {
+        MenuManager menuMgr = new MenuManager("#PopupMenu");
+        menuMgr.setRemoveAllWhenShown(true);
+        menuMgr.addMenuListener(new IMenuListener() {
+            public void menuAboutToShow(IMenuManager manager) {                
+               createContextMenu(manager);
+            }
+        });
+
+        contextMenu = menuMgr.createContextMenu(parent);
+    }
+       
+       protected void createContextMenu(IMenuManager m) {
+               List<IG3DNode> selected = selectionProvider.getSelectedNodes();
+               try {
+                       if (selected.size() == 0) {
+                               for (Item eq : P3DUtil.getEquipments()) {
+                                       m.add(new AddEquipmentAction(rootNode, eq));
+                               }
+                       } else if (selected.size() == 1) {
+                               IP3DNode node = (IP3DNode)selected.get(0);
+                               if (node instanceof Equipment) {
+                                       m.add(translateAction);
+                                       m.add(rotateAction);
+                                       for (Item eq : P3DUtil.getNozzles()) {
+                                               AddNozzleAction add = new AddNozzleAction(rootNode, eq);
+                                               add.setEquipment((Equipment)node);
+                                               m.add(add);
+                                       }
+                               } else if (node instanceof Nozzle) {
+                                       m.add(translateAction);
+                                       m.add(rotateAction);
+                                       Nozzle nozzle = (Nozzle)node;
+                                       m.add(routePipeAction);
+                                       routePipeAction.setComponent(nozzle);
+                                       routePipeAction.setEnabled(nozzle.getNext() == null && nozzle.getPrevious() == null);
+                                       m.add(addComponentAction);
+                                       addComponentAction.setComponent(nozzle);
+                               } else if (node instanceof TurnComponent) {
+                                       m.add(translateAction);
+                                       TurnComponent component = (TurnComponent)node;
+                                       m.add(routePipeAction);
+                                       routePipeAction.setComponent(component);
+                                       routePipeAction.setEnabled(component.getNext() == null || component.getPrevious() == null);
+                                       m.add(addComponentAction);
+                                       addComponentAction.setComponent(component);
+                               } else if (node instanceof EndComponent) {
+                                       m.add(translateAction);
+                                       m.add(addComponentAction);
+                                       addComponentAction.setComponent((PipelineComponent)node);
+                               } else if (node instanceof InlineComponent) {
+                                       //m.add(translateInlineAction);
+                                       InlineComponent component = (InlineComponent)node;
+                                       m.add(routePipeAction);
+                                       routePipeAction.setComponent(component);
+                                       m.add(addComponentAction);
+                                       addComponentAction.setComponent(component);
+                               }
+                               
+                               m.add(removeAction);
+                               translateAction.setNode(node);
+                               rotateAction.setNode(node);
+                               removeAction.setNode(node);
+                               
+                       } 
+               } catch (DatabaseException e) {
+               ExceptionUtils.logAndShowError(e);
+       }
+       }
+       
+       private IContentOutlinePage createOutline() {
+               if (rootNode == null || selectionProvider == null)
+                       return null;
+               //IContentOutlinePage outlinePage = new VTKContentOutlinePage<Resource,Object>(rootNode, selectionProvider);
+               IContentOutlinePage outlinePage = new P3DContentOutlinePage(rootNode, selectionProvider) {
+                       protected void createContextMenu(IMenuManager manager) {
+                               Plant3DEditor.this.createContextMenu(manager);
+                       };
+               };
+               outlinePage.addSelectionChangedListener(new ISelectionChangedListener() {
+                       
+                       @Override
+                       public void selectionChanged(SelectionChangedEvent event) {
+                               selectionProvider.selectionChanged(event);
+                       }
+               });
+               return outlinePage;
+       }
+
+       @SuppressWarnings("rawtypes")
+       @Override
+       public Object getAdapter(Class adapter) {
+               if (IPropertyPage.class.equals(adapter))
+                       return new StandardPropertyPage(getSite(),getPropertyContexts());
+               if (IContentOutlinePage.class.equals(adapter)) {
+                       return createOutline();
+               }
+               if (NodeMap.class.equals(adapter)) {
+                       return nodeMap;
+               }
+               if (INode.class.equals(adapter)) {
+                       return rootNode;
+               }
+               if (IMapping.class.equals(adapter)) {
+                       return mapping;
+               }
+               if (InteractiveVtkPanel.class.equals(adapter)) {
+                       return panel;
+               }
+               if (ISelectionProvider.class.equals(adapter))
+                       return selectionProvider;
+               return super.getAdapter(adapter);
+       }
+       
+       public Set<String> getPropertyContexts() {
+               Set<String> result = new HashSet<String>();
+               result.add("http://www.simantics.org/Project-1.0/ProjectBrowseContext");
+               return result;
+       }
+       
+       public P3DRootNode getRootNode() {
+               return rootNode;
+       }
+       
+       public IMapping<Resource, Object> getMapping() {
+               return mapping;
+       }
+}
diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/geometry/BallValveGeometryProvider.java b/org.simantics.plant3d/src/org/simantics/plant3d/geometry/BallValveGeometryProvider.java
new file mode 100644 (file)
index 0000000..b0da882
--- /dev/null
@@ -0,0 +1,48 @@
+package org.simantics.plant3d.geometry;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+
+import org.jcae.opencascade.jni.TopoDS_Shape;
+import org.simantics.db.Resource;
+import org.simantics.g3d.math.MathTools;
+import org.simantics.opencascade.OccTriangulator;
+
+public class BallValveGeometryProvider extends BuiltinGeometryProvider {
+       
+       public BallValveGeometryProvider(Resource resource) {
+               super(resource);
+       }
+
+       private double radius = 0.01;
+       
+       @Override
+       public Collection<TopoDS_Shape> getModel() throws Exception {
+               TopoDS_Shape cyl = OccTriangulator.makeCylinder(new double[] {-radius*2, 0.0, 0.0}, new double[] { 1.0, 0.0, 0.0 }, radius, radius*4);
+               TopoDS_Shape sph = OccTriangulator.makeSphere(0, 0, 0, radius*1.5);
+               TopoDS_Shape shape = OccTriangulator.makeCompound(new TopoDS_Shape[]{cyl, sph});
+               cyl.delete();
+               sph.delete();
+               return Collections.singletonList(shape);
+       }
+       
+       @Override
+       public void setProperties(Map<String, Object> props) {
+               if (props.containsKey("radius")) {
+                       radius = (Double)props.get("radius");
+               }
+               if (radius < MathTools.NEAR_ZERO)
+                       radius = MathTools.NEAR_ZERO;
+               
+       }
+       
+       @Override
+       public void updateCalculatedProperties(Map<String, Object> returnProps) {
+               returnProps.put("length", radius*4);
+               
+       }
+       
+       
+
+}
diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/geometry/BuiltinGeometryProvider.java b/org.simantics.plant3d/src/org/simantics/plant3d/geometry/BuiltinGeometryProvider.java
new file mode 100644 (file)
index 0000000..5250cc9
--- /dev/null
@@ -0,0 +1,29 @@
+package org.simantics.plant3d.geometry;
+
+import java.util.Map;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.simantics.db.Resource;
+import org.simantics.opencascade.ParametricSolidModelProvider;
+
+public abstract class BuiltinGeometryProvider implements ParametricSolidModelProvider, IAdaptable{
+       
+       private Resource resource;
+       
+       public BuiltinGeometryProvider(Resource resource) {
+               this.resource = resource;
+       }
+       
+       @Override
+       public Object getAdapter(Class adapter) {
+               if (Resource.class == adapter)
+                       return resource;
+               return null;
+       }
+       
+       @Override
+       public void updateCalculatedProperties(Map<String, Object> returnProps) {
+               
+       }
+
+}
diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/geometry/CapGeometryProvider.java b/org.simantics.plant3d/src/org/simantics/plant3d/geometry/CapGeometryProvider.java
new file mode 100644 (file)
index 0000000..4161d94
--- /dev/null
@@ -0,0 +1,96 @@
+package org.simantics.plant3d.geometry;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+
+import org.jcae.opencascade.jni.BRepBuilderAPI_MakeEdge;
+import org.jcae.opencascade.jni.BRepBuilderAPI_MakeFace;
+import org.jcae.opencascade.jni.BRepBuilderAPI_MakeWire;
+import org.jcae.opencascade.jni.BRepPrimAPI_MakeRevol;
+import org.jcae.opencascade.jni.GC_MakeArcOfCircle;
+import org.jcae.opencascade.jni.GC_MakeSegment;
+import org.jcae.opencascade.jni.TopoDS_Edge;
+import org.jcae.opencascade.jni.TopoDS_Face;
+import org.jcae.opencascade.jni.TopoDS_Shape;
+import org.jcae.opencascade.jni.TopoDS_Wire;
+import org.simantics.db.Resource;
+import org.simantics.g3d.math.MathTools;
+
+public class CapGeometryProvider extends BuiltinGeometryProvider {
+       
+       public CapGeometryProvider(Resource resource) {
+               super(resource);
+       }
+
+       private double radius = 0.01;
+       
+       @Override
+       public Collection<TopoDS_Shape> getModel() throws Exception {
+//             TopoDS_Shape cyl = OccTriangulator.makeCylinder(new double[] {0.0, 0.0, 0.0}, new double[] { 1.0, 0.0, 0.0 }, radius, radius*0.25);
+//             return Collections.singletonList(cyl);
+               double length = radius * 0.5;
+               double p0[] = new double[]{    length,        0.0,0.0};
+               double p1[] = new double[]{length*0.8, radius*0.6,0.0};
+               double p2[] = new double[]{length*0.5,     radius,0.0};
+               double p3[] = new double[]{       0.0,     radius,0.0};
+               double p4[] = new double[]{       0.0,        0.0,0.0};
+               GC_MakeArcOfCircle m1 = new GC_MakeArcOfCircle(p0,p1,p2);
+               GC_MakeSegment s1 = new GC_MakeSegment(p2,p3);
+               GC_MakeSegment s2 = new GC_MakeSegment(p3,p4);
+               
+               BRepBuilderAPI_MakeEdge edge = new BRepBuilderAPI_MakeEdge(m1.value());
+               TopoDS_Edge e1 = (TopoDS_Edge)edge.shape();
+               edge.delete();
+               
+               edge = new BRepBuilderAPI_MakeEdge(s1.value());
+               TopoDS_Edge e2 = (TopoDS_Edge)edge.shape();
+               edge.delete();
+               
+               edge = new BRepBuilderAPI_MakeEdge(s2.value());
+               TopoDS_Edge e3 = (TopoDS_Edge)edge.shape();
+               edge.delete();
+               
+               BRepBuilderAPI_MakeWire wire =  new BRepBuilderAPI_MakeWire(e1,e2,e3);
+               TopoDS_Wire w = (TopoDS_Wire)wire.shape();
+               wire.delete();
+               
+               BRepBuilderAPI_MakeFace face = new BRepBuilderAPI_MakeFace(w);
+               TopoDS_Face F = (TopoDS_Face) face.shape();
+               face.delete();
+               
+               BRepPrimAPI_MakeRevol revol = new BRepPrimAPI_MakeRevol(F,new double[]{0.0,0.0,0.0,1.0,0.0,0.0}); 
+               TopoDS_Shape shape = revol.shape();
+               revol.delete();
+       
+               m1.delete();
+               s1.delete();
+               s2.delete();
+               e1.delete();
+               e2.delete();
+               e3.delete();
+               w.delete();
+               F.delete();
+               
+               return Collections.singletonList(shape);
+       }
+       
+       @Override
+       public void setProperties(Map<String, Object> props) {
+               if (props.containsKey("radius")) {
+                       radius = (Double)props.get("radius");
+               }
+               if (radius < MathTools.NEAR_ZERO)
+                       radius = MathTools.NEAR_ZERO;
+               
+       }
+       
+       @Override
+       public void updateCalculatedProperties(Map<String, Object> returnProps) {
+               returnProps.put("length", radius*4);
+               
+       }
+       
+       
+
+}
diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/geometry/CheckValveGeometryProvider.java b/org.simantics.plant3d/src/org/simantics/plant3d/geometry/CheckValveGeometryProvider.java
new file mode 100644 (file)
index 0000000..85f4c7a
--- /dev/null
@@ -0,0 +1,47 @@
+package org.simantics.plant3d.geometry;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+
+import org.jcae.opencascade.jni.TopoDS_Shape;
+import org.simantics.db.Resource;
+import org.simantics.g3d.math.MathTools;
+import org.simantics.opencascade.OccTriangulator;
+
+public class CheckValveGeometryProvider extends BuiltinGeometryProvider {
+       
+       public CheckValveGeometryProvider(Resource resource) {
+               super(resource);
+       }
+
+       private double radius = 0.01;
+       
+       @Override
+       public Collection<TopoDS_Shape> getModel() throws Exception {
+               double l = radius*0.2;
+               TopoDS_Shape cyl = OccTriangulator.makeCylinder(new double[] {-radius, 0.0, 0.0}, new double[] { 1.0, 0.0, 0.0 }, radius, l);
+               TopoDS_Shape con = OccTriangulator.makeCone(new double[] {-radius, 0.0, 0.0}, new double[] { 1.0, 0.0, 0.0 }, radius*0.1, radius,radius*2);
+               TopoDS_Shape shape = OccTriangulator.makeFuse(cyl, con);
+               cyl.delete();
+               con.delete();
+               return Collections.singletonList(shape);
+       }
+       
+       @Override
+       public void setProperties(Map<String, Object> props) {
+               if (props.containsKey("radius")) {
+                       radius = (Double)props.get("radius");
+               }
+               if (radius < MathTools.NEAR_ZERO)
+                       radius = MathTools.NEAR_ZERO;
+               
+       }
+       
+       @Override
+       public void updateCalculatedProperties(Map<String, Object> returnProps) {
+               returnProps.put("length", radius*2);
+               
+       }
+
+}
diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/geometry/ElbowGeometryProvider.java b/org.simantics.plant3d/src/org/simantics/plant3d/geometry/ElbowGeometryProvider.java
new file mode 100644 (file)
index 0000000..46aea58
--- /dev/null
@@ -0,0 +1,47 @@
+package org.simantics.plant3d.geometry;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+
+import org.jcae.opencascade.jni.TopoDS_Shape;
+import org.simantics.db.Resource;
+import org.simantics.g3d.math.MathTools;
+import org.simantics.opencascade.OccTriangulator;
+
+public class ElbowGeometryProvider extends BuiltinGeometryProvider  {
+       
+       public ElbowGeometryProvider(Resource resource) {
+               super(resource);
+       }
+
+       private double radius = 0.01;
+       private double turnRadius = 0.05;
+       private double turnAngle = Math.PI * 0.5;
+       
+       @Override
+       public Collection<TopoDS_Shape> getModel() throws Exception {
+               double t = Math.tan((Math.PI - turnAngle) * 0.5);
+               double R = 0.0;
+               if (t > MathTools.NEAR_ZERO)
+                       R = turnRadius / t;
+               TopoDS_Shape shape = OccTriangulator.makeTorus(new double[]{-R,0.0,-turnRadius}, new double[] { 0.0, 1.0, 0.0 }, turnRadius, radius,0.0,Math.PI*2.0,turnAngle);
+//             System.out.println("Create elbow tr:" + turnRadius + " r:" + radius + " angle:"  +turnAngle + " " + R);
+               return Collections.singletonList(shape);
+       }
+       
+       @Override
+       public void setProperties(Map<String, Object> props) {
+               if (props.containsKey("turnRadius"))
+                       turnRadius = (Double)props.get("turnRadius");
+               if (props.containsKey("turnAngle"))
+                       turnAngle = (Double)props.get("turnAngle");
+               if (props.containsKey("radius")) {
+                       radius = (Double)props.get("radius");
+               }
+               if (radius < MathTools.NEAR_ZERO)
+                       radius = MathTools.NEAR_ZERO;
+       }
+
+}
+
diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/geometry/HorizontalTankGeometryProvider.java b/org.simantics.plant3d/src/org/simantics/plant3d/geometry/HorizontalTankGeometryProvider.java
new file mode 100644 (file)
index 0000000..7a3dc41
--- /dev/null
@@ -0,0 +1,101 @@
+package org.simantics.plant3d.geometry;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+
+import org.jcae.opencascade.jni.BRepBuilderAPI_MakeEdge;
+import org.jcae.opencascade.jni.BRepBuilderAPI_MakeFace;
+import org.jcae.opencascade.jni.BRepBuilderAPI_MakeWire;
+import org.jcae.opencascade.jni.BRepPrimAPI_MakeRevol;
+import org.jcae.opencascade.jni.GC_MakeArcOfCircle;
+import org.jcae.opencascade.jni.GC_MakeSegment;
+import org.jcae.opencascade.jni.TopoDS_Edge;
+import org.jcae.opencascade.jni.TopoDS_Face;
+import org.jcae.opencascade.jni.TopoDS_Shape;
+import org.jcae.opencascade.jni.TopoDS_Wire;
+import org.simantics.db.Resource;
+import org.simantics.opencascade.OccTriangulator;
+
+public class HorizontalTankGeometryProvider extends BuiltinGeometryProvider  {
+       
+       public HorizontalTankGeometryProvider(Resource resource) {
+               super(resource);
+       }
+
+       private double length = 1.0;
+       private double radius = 0.2;
+       
+       @Override
+       public Collection<TopoDS_Shape> getModel() throws Exception {
+               
+               double p0[] = new double[]{-length*0.50,        0.0,0.0};
+               double p1[] = new double[]{-length*0.488, radius*0.6,0.0};
+               double p2[] = new double[]{-length*0.46,     radius,0.0};
+               double p3[] = new double[]{ length*0.46,     radius,0.0};
+               double p4[] = new double[]{ length*0.488, radius*0.6,0.0};
+               double p5[] = new double[]{ length*0.50,        0.0,0.0};
+               
+               GC_MakeArcOfCircle m1 = new GC_MakeArcOfCircle(p0,p1,p2);
+               GC_MakeSegment s1 = new GC_MakeSegment(p2,p3);
+               GC_MakeArcOfCircle m2 = new GC_MakeArcOfCircle(p3,p4,p5);
+               
+               BRepBuilderAPI_MakeEdge edge = new BRepBuilderAPI_MakeEdge(m1.value());
+               TopoDS_Edge e1 = (TopoDS_Edge)edge.shape();
+               edge.delete();
+               
+               edge = new BRepBuilderAPI_MakeEdge(s1.value());
+               TopoDS_Edge e2 = (TopoDS_Edge)edge.shape();
+               edge.delete();
+               
+               edge = new BRepBuilderAPI_MakeEdge(m2.value());
+               TopoDS_Edge e3 = (TopoDS_Edge)edge.shape();
+               edge.delete();
+               
+               BRepBuilderAPI_MakeWire wire =  new BRepBuilderAPI_MakeWire(e1,e2,e3);
+               TopoDS_Wire w = (TopoDS_Wire)wire.shape();
+               wire.delete();
+               
+               BRepBuilderAPI_MakeFace face = new BRepBuilderAPI_MakeFace(w);
+               TopoDS_Face F = (TopoDS_Face) face.shape();
+               face.delete();
+               
+               BRepPrimAPI_MakeRevol revol = new BRepPrimAPI_MakeRevol(F,new double[]{0.0,0.0,0.0,1.0,0.0,0.0}); 
+               TopoDS_Shape shape = revol.shape();
+               revol.delete();
+       
+               m1.delete();
+               s1.delete();
+               m2.delete();
+               e1.delete();
+               e2.delete();
+               e3.delete();
+               w.delete();
+               F.delete();
+               
+               TopoDS_Shape shape2 = OccTriangulator.makeTranslation(shape, 0.0, radius, 0.0);
+               shape.delete();
+               shape = shape2;
+               TopoDS_Shape box = OccTriangulator.makeBox(-length*0.4, 0.0, -radius*0.5, -length*0.3, radius, radius*0.5);
+               shape2 = OccTriangulator.makeFuse(shape, box);
+               shape.delete();
+               box.delete();
+               box = OccTriangulator.makeBox(length*0.3, 0.0, -radius*0.5, length*0.4, radius, radius*0.5);
+               shape = OccTriangulator.makeFuse(shape2, box);
+               shape2.delete();
+               box.delete();
+               
+               return Collections.singletonList(shape);
+       }
+       
+       @Override
+       public void setProperties(Map<String, Object> props) {
+               if (props.containsKey("length"))
+                       length = (Double)props.get("length");
+               if (props.containsKey("radius")) {
+                       radius = (Double)props.get("radius");
+               }
+               
+       }
+
+}
diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/geometry/NozzleGeometryProvider.java b/org.simantics.plant3d/src/org/simantics/plant3d/geometry/NozzleGeometryProvider.java
new file mode 100644 (file)
index 0000000..cdfe73c
--- /dev/null
@@ -0,0 +1,40 @@
+package org.simantics.plant3d.geometry;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+
+import org.jcae.opencascade.jni.TopoDS_Shape;
+import org.simantics.db.Resource;
+import org.simantics.opencascade.OccTriangulator;
+
+public class NozzleGeometryProvider extends BuiltinGeometryProvider  {
+       
+       public NozzleGeometryProvider(Resource resource) {
+               super(resource);
+       }
+
+       private double length = 0.1;
+       private double radius = 0.01;
+       
+       @Override
+       public Collection<TopoDS_Shape> getModel() throws Exception {
+               TopoDS_Shape shape = OccTriangulator.makeCylinder(new double[] {-length, 0.0, 0.0}, new double[] { 1.0, 0.0, 0.0 }, radius, length);
+               TopoDS_Shape shape2 = OccTriangulator.makeCylinder(new double[] {-length*0.25, 0.0, 0.0}, new double[] { 1.0, 0.0, 0.0 }, radius*1.2, length*0.25);
+               TopoDS_Shape shape3 = OccTriangulator.makeCompound(new TopoDS_Shape[]{shape,shape2});
+               shape.delete();
+               shape2.delete();
+               return Collections.singletonList(shape3);
+       }
+       
+       @Override
+       public void setProperties(Map<String, Object> props) {
+               if (props.containsKey("length"))
+                       length = (Double)props.get("length");
+               if (props.containsKey("radius")) {
+                       radius = (Double)props.get("radius");
+               }
+               
+       }
+
+}
diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/geometry/PumpGeometryProvider.java b/org.simantics.plant3d/src/org/simantics/plant3d/geometry/PumpGeometryProvider.java
new file mode 100644 (file)
index 0000000..a7c32a6
--- /dev/null
@@ -0,0 +1,72 @@
+package org.simantics.plant3d.geometry;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+
+import org.jcae.opencascade.jni.BRepBuilderAPI_MakeEdge;
+import org.jcae.opencascade.jni.BRepBuilderAPI_MakeFace;
+import org.jcae.opencascade.jni.BRepBuilderAPI_MakeWire;
+import org.jcae.opencascade.jni.BRepPrimAPI_MakeRevol;
+import org.jcae.opencascade.jni.GC_MakeArcOfCircle;
+import org.jcae.opencascade.jni.GC_MakeSegment;
+import org.jcae.opencascade.jni.TopoDS_Edge;
+import org.jcae.opencascade.jni.TopoDS_Face;
+import org.jcae.opencascade.jni.TopoDS_Shape;
+import org.jcae.opencascade.jni.TopoDS_Wire;
+import org.simantics.db.Resource;
+import org.simantics.opencascade.OccTriangulator;
+
+public class PumpGeometryProvider extends BuiltinGeometryProvider  {
+       
+       public PumpGeometryProvider(Resource resource) {
+               super(resource);
+       }
+
+       private double length = 0.5;
+       private double width = 0.25;
+       
+       @Override
+       public Collection<TopoDS_Shape> getModel() throws Exception {
+               double h = width * 0.5;
+               double h2 = width * 0.1;
+               double ld2 = length * 0.5;
+               double wd2 = width * 0.5;
+               
+               double r1 = width * 0.5;
+               double r2 = r1 *0.2;
+               double r3 = r1 *0.5;
+               
+               double l1 = length * 0.2;
+               double l2 = length * 0.2;
+               double l2b = l2 + length * 0.1;
+               double l3 = length * 0.6;
+               
+               double dir[] = new double[]{1.0,0.0,0.0};
+               
+               TopoDS_Shape foundation = OccTriangulator.makeBox(-ld2, 0.0, -wd2, ld2, h2, wd2);
+               TopoDS_Shape rotator = OccTriangulator.makeCylinder(new double[]{-ld2,h+h2,0.0}, dir, r1, l1);
+               TopoDS_Shape axis = OccTriangulator.makeCylinder(new double[]{-ld2+l1,h+h2,0.0}, dir, r2, l2b);
+               TopoDS_Shape motor = OccTriangulator.makeCylinder(new double[]{-ld2+l1+l2,h+h2,0.0}, dir, r3, l3);
+               TopoDS_Shape motorBox = OccTriangulator.makeBox(-ld2+l1+l2, h2, -r3, ld2, h2+h-r3, r3);
+               
+               TopoDS_Shape shape = OccTriangulator.makeCompound(new TopoDS_Shape[]{foundation,rotator,axis,motor,motorBox});
+               foundation.delete();
+               rotator.delete();
+               axis.delete();
+               motor.delete();
+               motorBox.delete();
+               return Collections.singletonList(shape);
+       }
+       
+       @Override
+       public void setProperties(Map<String, Object> props) {
+               if (props.containsKey("length"))
+                       length = (Double)props.get("length");
+               if (props.containsKey("width")) {
+                       width = (Double)props.get("width");
+               }
+               
+       }
+
+}
diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/geometry/ReducerGeometryProvider.java b/org.simantics.plant3d/src/org/simantics/plant3d/geometry/ReducerGeometryProvider.java
new file mode 100644 (file)
index 0000000..d3387f7
--- /dev/null
@@ -0,0 +1,57 @@
+package org.simantics.plant3d.geometry;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+
+import org.jcae.opencascade.jni.TopoDS_Shape;
+import org.simantics.db.Resource;
+import org.simantics.g3d.math.MathTools;
+import org.simantics.opencascade.OccTriangulator;
+
+public class ReducerGeometryProvider extends BuiltinGeometryProvider  {
+       
+       public ReducerGeometryProvider(Resource resource) {
+               super(resource);
+       }
+
+       private double radius = 0.01;
+       private double radius2 = 0.02;
+       
+       @Override
+       public Collection<TopoDS_Shape> getModel() throws Exception {
+//             GP_Circ circ = new GP_Circ(new double[]{-length*0.5, 0.0, 0.0,1.0,0.0,0.0}, radius);
+//             GP_Circ circ2 = new GP_Circ(new double[]{length*0.5, 0.0, 0.0,1.0,0.0,0.0}, radius2);
+//             System.out.println("Reducer " + length  + " " + radius + " " + radius2);
+               double length = Math.max(0.1, Math.abs(radius-radius2)*4.0);
+               TopoDS_Shape shape;
+               if (Math.abs(radius-radius2) < MathTools.NEAR_ZERO) {
+                       shape = OccTriangulator.makeCylinder(new double[] {-length*0.5, 0.0, 0.0}, new double[] { 1.0, 0.0, 0.0 }, radius, length);
+               } else {
+                       shape = OccTriangulator.makeCone(new double[] {-length*0.5, 0.0, 0.0}, new double[] { 1.0, 0.0, 0.0 }, radius,radius2, length);
+               }
+               return Collections.singletonList(shape);
+       }
+       
+       @Override
+       public void setProperties(Map<String, Object> props) {
+
+               
+               if (props.containsKey("radius")) {
+                       radius = (Double)props.get("radius");
+               }
+               if (props.containsKey("radius2")) {
+                       radius2 = (Double)props.get("radius2");
+               }
+               
+               
+               
+       }
+       
+       @Override
+       public void updateCalculatedProperties(Map<String, Object> returnProps) {
+               returnProps.put("length", Math.max(0.1, Math.abs(radius-radius2)*4.0));
+               
+       }
+
+}
diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/geometry/StraightGeometryProvider.java b/org.simantics.plant3d/src/org/simantics/plant3d/geometry/StraightGeometryProvider.java
new file mode 100644 (file)
index 0000000..ac63f91
--- /dev/null
@@ -0,0 +1,44 @@
+package org.simantics.plant3d.geometry;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+
+import org.jcae.opencascade.jni.TopoDS_Shape;
+import org.simantics.db.Resource;
+import org.simantics.g3d.math.MathTools;
+import org.simantics.opencascade.OccTriangulator;
+
+public class StraightGeometryProvider extends BuiltinGeometryProvider {
+       
+       public StraightGeometryProvider(Resource resource) {
+               super(resource);
+       }
+
+       private double length = 1.0;
+       private double radius = 0.01;
+       
+       @Override
+       public Collection<TopoDS_Shape> getModel() throws Exception {
+               TopoDS_Shape shape = OccTriangulator.makeCylinder(new double[] {-length*0.5, 0.0, 0.0}, new double[] { 1.0, 0.0, 0.0 }, radius, length);
+//             System.out.println("Create straight l:" + length + " r:" + radius);
+               return Collections.singletonList(shape);
+       }
+       
+       @Override
+       public void setProperties(Map<String, Object> props) {
+               if (props.containsKey("length"))
+                       length = (Double)props.get("length");
+               if (props.containsKey("radius")) {
+                       radius = (Double)props.get("radius");
+               }
+               if (length < 0.0)
+                       length = 0.0;
+               if (radius < MathTools.NEAR_ZERO)
+                       radius = MathTools.NEAR_ZERO;
+               
+       }
+       
+       
+
+}
diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/geometry/VerticalTankGeometryProvider.java b/org.simantics.plant3d/src/org/simantics/plant3d/geometry/VerticalTankGeometryProvider.java
new file mode 100644 (file)
index 0000000..5cb078e
--- /dev/null
@@ -0,0 +1,87 @@
+package org.simantics.plant3d.geometry;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+
+import org.jcae.opencascade.jni.BRepBuilderAPI_MakeEdge;
+import org.jcae.opencascade.jni.BRepBuilderAPI_MakeFace;
+import org.jcae.opencascade.jni.BRepBuilderAPI_MakeWire;
+import org.jcae.opencascade.jni.BRepPrimAPI_MakeRevol;
+import org.jcae.opencascade.jni.GC_MakeArcOfCircle;
+import org.jcae.opencascade.jni.GC_MakeSegment;
+import org.jcae.opencascade.jni.TopoDS_Edge;
+import org.jcae.opencascade.jni.TopoDS_Face;
+import org.jcae.opencascade.jni.TopoDS_Shape;
+import org.jcae.opencascade.jni.TopoDS_Wire;
+import org.simantics.db.Resource;
+
+public class VerticalTankGeometryProvider extends BuiltinGeometryProvider  {
+       
+       public VerticalTankGeometryProvider(Resource resource) {
+               super(resource);
+       }
+
+       private double height = 1.0;
+       private double radius = 0.2;
+       
+       @Override
+       public Collection<TopoDS_Shape> getModel() throws Exception {
+               
+               double p0[] = new double[]{       0.0,     height,0.0};
+               double p1[] = new double[]{radius*0.6,height*0.98,0.0};
+               double p2[] = new double[]{    radius,height*0.94,0.0};
+               double p3[] = new double[]{    radius,        0.0,0.0};
+               double p4[] = new double[]{       0.0,        0.0,0.0};
+               
+               GC_MakeArcOfCircle m1 = new GC_MakeArcOfCircle(p0,p1,p2);
+               GC_MakeSegment s1 = new GC_MakeSegment(p2,p3);
+               GC_MakeSegment s2 = new GC_MakeSegment(p3,p4);
+               
+               BRepBuilderAPI_MakeEdge edge = new BRepBuilderAPI_MakeEdge(m1.value());
+               TopoDS_Edge e1 = (TopoDS_Edge)edge.shape();
+               edge.delete();
+               
+               edge = new BRepBuilderAPI_MakeEdge(s1.value());
+               TopoDS_Edge e2 = (TopoDS_Edge)edge.shape();
+               edge.delete();
+               
+               edge = new BRepBuilderAPI_MakeEdge(s2.value());
+               TopoDS_Edge e3 = (TopoDS_Edge)edge.shape();
+               edge.delete();
+               
+               BRepBuilderAPI_MakeWire wire =  new BRepBuilderAPI_MakeWire(e1,e2,e3);
+               TopoDS_Wire w = (TopoDS_Wire)wire.shape();
+               wire.delete();
+               
+               BRepBuilderAPI_MakeFace face = new BRepBuilderAPI_MakeFace(w);
+               TopoDS_Face F = (TopoDS_Face) face.shape();
+               face.delete();
+               
+               BRepPrimAPI_MakeRevol revol = new BRepPrimAPI_MakeRevol(F,new double[]{0.0,0.0,0.0,0.0,1.0,0.0}); 
+               TopoDS_Shape shape = revol.shape();
+               revol.delete();
+       
+               m1.delete();
+               s1.delete();
+               s2.delete();
+               e1.delete();
+               e2.delete();
+               e3.delete();
+               w.delete();
+               F.delete();
+
+               return Collections.singletonList(shape);
+       }
+       
+       @Override
+       public void setProperties(Map<String, Object> props) {
+               if (props.containsKey("height"))
+                       height = (Double)props.get("height");
+               if (props.containsKey("radius")) {
+                       radius = (Double)props.get("radius");
+               }
+               
+       }
+
+}
diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/gizmo/SplitPointSelectionGizmo.java b/org.simantics.plant3d/src/org/simantics/plant3d/gizmo/SplitPointSelectionGizmo.java
new file mode 100644 (file)
index 0000000..336fdbd
--- /dev/null
@@ -0,0 +1,151 @@
+package org.simantics.plant3d.gizmo;
+
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseMotionListener;
+import java.util.ArrayList;
+import java.util.Collection;
+
+import javax.vecmath.AxisAngle4d;
+import javax.vecmath.Point3d;
+import javax.vecmath.Tuple3d;
+import javax.vecmath.Vector2d;
+import javax.vecmath.Vector3d;
+
+import org.simantics.g3d.math.MathTools;
+import org.simantics.g3d.math.Ray;
+import org.simantics.g3d.scenegraph.RenderListener;
+import org.simantics.g3d.shape.Color4d;
+import org.simantics.g3d.shape.Cone;
+import org.simantics.g3d.shape.Cylinder;
+import org.simantics.g3d.shape.Mesh;
+import org.simantics.g3d.vtk.common.InteractiveVtkPanel;
+import org.simantics.g3d.vtk.gizmo.vtkGizmo;
+import org.simantics.g3d.vtk.shape.MeshActor;
+import org.simantics.g3d.vtk.utils.vtkUtil;
+
+import vtk.vtkProp;
+
+public class SplitPointSelectionGizmo extends vtkGizmo {
+       
+       MeshActor actor;
+       
+       InteractiveVtkPanel panel;
+       private RenderListener listener;
+       private MouseMotionListener mouseListener;
+       
+       Point3d start;
+       Point3d end;
+       Vector3d dir;
+       
+       Vector2d mousePos = new Vector2d();
+       
+       Vector3d pa = new Vector3d();
+       Vector3d pb = new Vector3d();
+       
+       Tuple3d splitPoint = null;
+       
+       public SplitPointSelectionGizmo(InteractiveVtkPanel panel) {
+               this.panel = panel;
+               
+               int res = 16;
+               
+               Mesh cone_x = Cone.create(0.1, res);
+               cone_x.rotate(MathTools.getQuat(new AxisAngle4d(0,0,-1,Math.PI*0.5)));
+               cone_x.translate(new Vector3d(0.8,0,0));
+               
+               Mesh tube_x = Cylinder.create(MathTools.ORIGIN, new Vector3d(0.8,0,0), 0.05, res);
+               tube_x.add(cone_x);
+               
+               Color4d z_col = new Color4d(0,1,0,1);
+               tube_x.setColor(z_col);
+               
+               actor = new MeshActor();
+               actor.setMesh(tube_x);
+               
+               this.listener = new RenderListener() {
+                       @Override
+                       public void preRender() {
+                               Ray ray = vtkUtil.createMouseRay(getRenderer(), mousePos.x, mousePos.y);
+                               //ray.dir.add(ray.pos);
+                               //if (MathTools.intersectLineLine(start, end, ray.pos, ray.dir, pa, pb)) {
+                               double mu[] = new double[2];
+                               if (MathTools.intersectStraightStraight(start, dir, ray.pos, ray.dir, pa, pb,mu)) {
+                                       splitPoint = pa;
+                                       if (mu[0] < 0.0)
+                                               splitPoint = start;
+                                       else if (mu[0] > 1.0)
+                                               splitPoint = end;
+                                       Vector3d dir = new Vector3d(splitPoint);
+                                       dir.sub(pb);
+                                       double length = dir.length();
+                                       dir.scale(1.0/length);
+                                       AxisAngle4d aa = MathTools.createRotation(MathTools.X_AXIS, dir);
+                                       setRotation(aa);
+                                       setScale(length);
+                                       setPosition(pb);
+                                       actor.SetVisibility(1);
+                               } else {
+                                       splitPoint = null;
+                                       actor.SetVisibility(0);
+                               }
+                               
+                       }
+                       
+                       @Override
+                       public void postRender() {
+                               
+                       }
+               };
+               
+               this.mouseListener = new MouseMotionListener() {
+                       
+                       @Override
+                       public void mouseMoved(MouseEvent e) {
+                               mousePos.x = e.getX();
+                               mousePos.y = e.getY();
+                               SplitPointSelectionGizmo.this.panel.repaint();
+                       }
+                       
+                       @Override
+                       public void mouseDragged(MouseEvent e) {
+                               mousePos.x = e.getX();
+                               mousePos.y = e.getY();
+                               SplitPointSelectionGizmo.this.panel.repaint();
+                       }
+               };
+
+       }
+       
+       public void setSplit(Point3d start, Point3d end) {
+               this.start = start;
+               this.end = end;
+               dir = new Vector3d(end);
+               dir.sub(start);
+       }
+       
+       @Override
+       public void attach(Object renderingPart) {
+               super.attach(renderingPart);
+               panel.addListener(listener);
+               panel.addMouseMotionListener(mouseListener);
+       }
+       
+       @Override
+       public void deattach() {
+               panel.removeListener(listener);
+               panel.removeMouseMotionListener(mouseListener);
+               super.deattach();
+       }
+       
+       @Override
+       public Collection<vtkProp> getGizmo() {
+               Collection<vtkProp> coll = new ArrayList<vtkProp>();
+               coll.add(actor);
+               return coll;
+       }
+       
+       public Tuple3d getSplitPoint() {
+               return splitPoint;
+       }
+
+}
diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/gizmo/TerminalSelectionGizmo.java b/org.simantics.plant3d/src/org/simantics/plant3d/gizmo/TerminalSelectionGizmo.java
new file mode 100644 (file)
index 0000000..422e022
--- /dev/null
@@ -0,0 +1,251 @@
+package org.simantics.plant3d.gizmo;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+
+import javax.vecmath.Point2d;
+import javax.vecmath.Vector3d;
+
+import org.simantics.g3d.scenegraph.RenderListener;
+import org.simantics.g3d.tools.PluginTools;
+import org.simantics.g3d.vtk.common.InteractiveVtkPanel;
+import org.simantics.g3d.vtk.gizmo.vtkGizmo;
+import org.simantics.g3d.vtk.utils.vtkUtil;
+import org.simantics.plant3d.Activator;
+import org.simantics.plant3d.scenegraph.InlineComponent;
+import org.simantics.plant3d.scenegraph.PipelineComponent;
+import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint.PositionType;
+
+import vtk.vtkCellArray;
+import vtk.vtkFloatArray;
+import vtk.vtkPNGReader;
+import vtk.vtkPoints;
+import vtk.vtkPolyData;
+import vtk.vtkPolyDataMapper2D;
+import vtk.vtkPolygon;
+import vtk.vtkProp;
+import vtk.vtkRenderer;
+import vtk.vtkTexture;
+import vtk.vtkTexturedActor2D;
+
+public class TerminalSelectionGizmo extends vtkGizmo {
+       
+
+       
+       vtkTexturedActor2D prevProp;
+       vtkTexturedActor2D nextProp;
+       vtkTexturedActor2D middleProp;
+       
+       boolean showPrev = false;
+       boolean showNext = false;
+       boolean showMiddle = false;
+       
+       Vector3d middle = new Vector3d();
+       Vector3d prev = new Vector3d();
+       Vector3d next = new Vector3d();
+       
+       InteractiveVtkPanel panel;
+       
+       private RenderListener listener;
+       public TerminalSelectionGizmo(InteractiveVtkPanel panel) {
+               this.panel = panel;
+               this.listener = new RenderListener() {
+                       
+                       @Override
+                       public void preRender() {
+
+                               if (showMiddle) {
+                                       Point2d p = vtkUtil.getScreenCoordinates(getRenderer(), middle);
+                                       middleProp.SetDisplayPosition((int)p.x, (int)p.y);
+                               }
+                               if (showPrev) {
+                                       Point2d p = vtkUtil.getScreenCoordinates(getRenderer(), prev);
+                                       prevProp.SetDisplayPosition((int)p.x, (int)p.y);
+                               }
+                               if (showNext) {
+                                       Point2d p = vtkUtil.getScreenCoordinates(getRenderer(), next);
+                                       nextProp.SetDisplayPosition((int)p.x, (int)p.y);
+                               }
+                       }
+                       
+                       @Override
+                       public void postRender() {
+                               
+                               
+                       }
+               };
+       }
+       
+       @Override
+       public void attach(Object renderingPart) {
+               if (nextProp == null) {
+                       loadData();
+                       
+               }
+               panel.addListener(listener);
+               
+               super.attach(renderingPart);
+               
+       }
+       
+       @Override
+       public Collection<vtkProp> getGizmo() {
+               List<vtkProp> list = new ArrayList<vtkProp>();
+               if (showPrev) {
+                       list.add(prevProp);
+               }
+               if (showNext) {
+                       list.add(nextProp);
+                       
+               }
+               if (showMiddle) {
+                       list.add(middleProp);
+               }
+               return list;
+       }
+       
+       protected void attachActors() {
+               vtkRenderer ren = getRenderer();
+               if (showPrev) {
+                       ren.AddActor(prevProp);
+               }
+               if (showNext) {
+                       ren.AddActor(nextProp);
+               }
+               if (showMiddle) {
+                       ren.AddActor(middleProp);
+               }
+               
+       }
+       
+       @Override
+       protected void deattachActors() {
+               panel.removeListener(listener);
+               vtkRenderer ren = getRenderer();
+               ren.RemoveActor(prevProp);
+               ren.RemoveActor(nextProp);
+               ren.RemoveActor(middleProp);
+       }
+       
+       public void setComponent(PipelineComponent component, Set<PositionType> allowed) {
+//             showPrev = component.getPrevious() == null;
+//             showNext = component.getNext() == null;
+//             showMiddle = (component instanceof InlineComponent) && !component.getControlPoint().isFixed();
+               showPrev = allowed.contains(PositionType.PREVIOUS);
+               showNext = allowed.contains(PositionType.NEXT);
+               showMiddle = allowed.contains(PositionType.SPLIT);
+       
+               middle = component.getControlPoint().getWorldPosition();
+               component.getControlPoint().getControlPointEnds(prev, next);
+
+       }
+       
+       private void loadData() {
+               String middleTexFile = PluginTools.getAbsolutePath(Activator.getDefault().getBundle(), "icons/middle.png");
+               String plusTexFile = PluginTools.getAbsolutePath(Activator.getDefault().getBundle(), "icons/plus.png");
+               if (middleTexFile == null || plusTexFile == null)
+                       throw new RuntimeException("Cannot resolve required image files.");
+               
+               vtkPoints points = new vtkPoints();
+               points.InsertNextPoint(-8, -8, 0.0);
+               points.InsertNextPoint( 8, -8, 0.0);
+               points.InsertNextPoint( 8,  8, 0.0);
+               points.InsertNextPoint(-8,  8, 0.0);
+               
+               
+               vtkCellArray cellArray = new vtkCellArray();
+               vtkPolygon polygon = new vtkPolygon();
+               polygon.GetPointIds().SetNumberOfIds(4);
+               polygon.GetPointIds().SetId(0, 0);
+               polygon.GetPointIds().SetId(1, 1);
+               polygon.GetPointIds().SetId(2, 2);
+               polygon.GetPointIds().SetId(3, 3);
+               
+               cellArray.InsertNextCell(polygon);
+               
+               vtkPolyData quad = new vtkPolyData();
+               quad.SetPoints(points);
+               quad.SetPolys(cellArray);
+               
+               vtkFloatArray texCoords = new vtkFloatArray();
+               
+               texCoords.SetNumberOfComponents(2);
+               
+               texCoords.InsertNextTuple2(0.0, 0.0);
+               texCoords.InsertNextTuple2(1.0, 0.0);
+               texCoords.InsertNextTuple2(1.0, 1.0);
+               texCoords.InsertNextTuple2(0.0, 1.0);
+               
+               quad.GetPointData().SetTCoords(texCoords);
+
+               vtkPNGReader middleReader = new vtkPNGReader();
+               middleReader.SetFileName(middleTexFile);
+               
+               vtkPNGReader plusReader = new vtkPNGReader();
+               plusReader.SetFileName(plusTexFile);
+               
+               vtkTexture middleTex = new vtkTexture();
+               middleTex.SetInputConnection(middleReader.GetOutputPort());
+               middleTex.SetInterpolate(1);
+               
+               vtkTexture plusTex = new vtkTexture();
+               plusTex.SetInputConnection(plusReader.GetOutputPort());
+               plusTex.SetInterpolate(1);
+               
+               vtkPolyDataMapper2D mapper = new vtkPolyDataMapper2D();
+               mapper.SetInput(quad);
+
+               nextProp = new vtkTexturedActor2D();
+               prevProp = new vtkTexturedActor2D();
+               middleProp = new vtkTexturedActor2D();
+               
+               nextProp.SetMapper(mapper);
+               nextProp.SetTexture(plusTex);
+               nextProp.SetPickable(1);
+               
+               prevProp.SetMapper(mapper);
+               prevProp.SetTexture(plusTex);
+               prevProp.SetPickable(1);
+               
+               middleProp.SetMapper(mapper);
+               middleProp.SetTexture(middleTex);
+               middleProp.SetPickable(1);
+               
+               
+               plusReader.GetOutputPort().Delete();
+               plusReader.Delete();
+               middleReader.GetOutputPort().Delete();
+               middleReader.Delete();
+               middleTex.Delete();
+               plusTex.Delete();
+               
+               mapper.Delete();
+               quad.GetPointData().Delete();
+               quad.Delete();
+               points.Delete();
+               polygon.GetPointIds().Delete();
+               polygon.Delete();
+               cellArray.Delete();
+               texCoords.Delete();
+               
+       }
+       
+       
+       public PositionType getPickedPosition(vtkProp[] picked) {
+               if (picked == null)
+                       return null;
+               for (vtkProp p : picked) {
+                       if (p.equals(middleProp))
+                               return PositionType.SPLIT;
+                       if (p.equals(nextProp))
+                               return PositionType.NEXT;
+                       if (p.equals(prevProp))
+                               return PositionType.PREVIOUS;
+               }
+               return null;
+       }
+       
+
+}
diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/handlers/NewPlantHandler.java b/org.simantics.plant3d/src/org/simantics/plant3d/handlers/NewPlantHandler.java
new file mode 100644 (file)
index 0000000..42e64cf
--- /dev/null
@@ -0,0 +1,54 @@
+package org.simantics.plant3d.handlers;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.simantics.Simantics;
+import org.simantics.db.Resource;
+import org.simantics.db.WriteGraph;
+import org.simantics.db.common.request.WriteRequest;
+import org.simantics.db.common.utils.NameUtils;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.layer0.Layer0;
+import org.simantics.plant3d.Activator;
+import org.simantics.plant3d.utils.P3DUtil;
+
+public class NewPlantHandler extends AbstractHandler {
+
+       @Override
+       public Object execute(ExecutionEvent event) throws ExecutionException {
+               final Resource library = Simantics.getProject().get();
+               
+               Job job = new Job("Create Plant ") {
+                       @Override
+                       protected IStatus run(IProgressMonitor monitor) {
+                               monitor.beginTask("Create Plant" , IProgressMonitor.UNKNOWN);
+                               try {
+                                       Simantics.getSession().syncRequest(new WriteRequest() {
+                                               
+                                               @Override
+                                               public void perform(WriteGraph graph) throws DatabaseException {
+                                                       Layer0 l0 = Layer0.getInstance(graph);
+                                                       String modelName = NameUtils.findFreshName(graph, "Plant", library);
+                                                       Resource model = P3DUtil.createModel(graph, modelName);
+                                                       graph.claim(library, l0.ConsistsOf, model);
+                                                       
+                                               }
+                                       });
+                                       return Status.OK_STATUS;
+                               } catch (DatabaseException e) {
+                                       return new Status(IStatus.ERROR, Activator.PLUGIN_ID, getName() + " failed.",e);
+                               }
+                       }
+                       
+                       
+               };
+               job.setUser(true);
+               job.schedule();
+               return null;
+       }
+}
diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/project/P3DPerspectiveFactory.java b/org.simantics.plant3d/src/org/simantics/plant3d/project/P3DPerspectiveFactory.java
new file mode 100644 (file)
index 0000000..fd2e5d1
--- /dev/null
@@ -0,0 +1,14 @@
+package org.simantics.plant3d.project;
+
+import org.eclipse.ui.IPageLayout;
+import org.eclipse.ui.IPerspectiveFactory;
+
+public class P3DPerspectiveFactory implements IPerspectiveFactory {
+
+       @Override
+       public void createInitialLayout(IPageLayout layout) {
+               layout.setEditorAreaVisible(true);
+
+       }
+
+}
diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/project/P3DProjectFeature.java b/org.simantics.plant3d/src/org/simantics/plant3d/project/P3DProjectFeature.java
new file mode 100644 (file)
index 0000000..a39292f
--- /dev/null
@@ -0,0 +1,21 @@
+package org.simantics.plant3d.project;
+
+import org.simantics.project.ProjectKeys;
+import org.simantics.project.exception.ProjectException;
+import org.simantics.project.features.AbstractProjectFeature;
+import org.simantics.project.features.IProjectFeature;
+
+public class P3DProjectFeature extends AbstractProjectFeature implements IProjectFeature {
+
+       private static final String DEFAULT_PERSPECTIVE = "org.simantics.plant3d.perspective";
+       
+       public P3DProjectFeature() {
+               // TODO Auto-generated constructor stub
+       }
+       
+        @Override
+               public void configure() throws ProjectException {
+                        getProjectElement().setHint(ProjectKeys.DEFAULT_PERSPECTIVE, DEFAULT_PERSPECTIVE);
+               }
+
+}
diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/property/P3DSelectionProcessor.java b/org.simantics.plant3d/src/org/simantics/plant3d/property/P3DSelectionProcessor.java
new file mode 100644 (file)
index 0000000..5494160
--- /dev/null
@@ -0,0 +1,169 @@
+package org.simantics.plant3d.property;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.IWorkbenchSite;
+import org.simantics.Simantics;
+import org.simantics.browsing.ui.swt.PartNameListener;
+import org.simantics.browsing.ui.swt.widgets.impl.WidgetSupport;
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.common.utils.NameUtils;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.management.ISessionContext;
+import org.simantics.db.request.Read;
+import org.simantics.g3d.property.PropertyTabContributor;
+import org.simantics.g3d.property.PropertyTabUtil;
+import org.simantics.g3d.scenegraph.IG3DNode;
+import org.simantics.g3d.tools.AdaptationUtils;
+import org.simantics.g3d.vtk.property.VTKPropertyTabContributor;
+import org.simantics.objmap.structural.StructuralResource;
+import org.simantics.selectionview.BasicPropertyTab;
+import org.simantics.selectionview.ComparableTabContributor;
+import org.simantics.selectionview.PropertyTabContributorImpl;
+import org.simantics.selectionview.SelectionProcessor;
+import org.simantics.utils.datastructures.Callback;
+
+import vtk.vtkProp;
+
+public class P3DSelectionProcessor implements SelectionProcessor<Object, ReadGraph>  {
+       
+       private static final boolean DEBUG = false;
+       @Override
+       public Collection<?> process(Object selection, ReadGraph backend) {
+//          System.out.println(getClass().getSimpleName() + " incoming selection: " + ObjectUtils.toString(selection));
+
+
+                Collection<ComparableTabContributor> result = new ArrayList<ComparableTabContributor>();
+                Collection<Resource> resourceCollection = AdaptationUtils.adaptToCollection(selection, Resource.class);
+                Collection<StructuralResource> structuralResourceCollection = AdaptationUtils.adaptToCollection(selection, StructuralResource.class);
+                Collection<vtkProp> propCollection = AdaptationUtils.adaptToCollection(selection, vtkProp.class);
+                Collection<IG3DNode> nodeCollection = AdaptationUtils.adaptToCollection(selection, IG3DNode.class);
+                boolean readOnly = false;
+                if (resourceCollection.size() == 0 && structuralResourceCollection.size() > 0) {
+                        for (StructuralResource sr : structuralResourceCollection) {
+                                if (sr.isStructural() && !sr.isStructuralRoot())
+                                        readOnly = true;
+                                 resourceCollection.add(sr.getResource());
+                        }
+                }
+                
+               
+                if (nodeCollection.size() == 1) {
+                        IG3DNode node = nodeCollection.iterator().next();
+                        List<PropertyTabContributor> contributors = PropertyTabUtil.getContributors(node);
+                        int i = 100;
+                        for (PropertyTabContributor c : contributors) {
+                                result.add(new ComparableTabContributor(c, i--, node, c.getId()));
+                        }
+                }
+            
+                if (DEBUG) {
+                        if (propCollection.size() == 1) {
+                                vtkProp prop = propCollection.iterator().next();
+                                if (prop == null)
+                                        throw new NullPointerException();
+                                result.add(new ComparableTabContributor(new VTKPropertyTabContributor(), -2, prop, "VTK"));
+                        }
+                        
+                        if (resourceCollection.size() > 0) {
+                                if (resourceCollection.size() > 1)
+                                result.add(new ComparableTabContributor(new MultiSelectionTabContibutor(),0, resourceCollection, "Graph"));
+                                else if (resourceCollection.size() == 1){
+                                try {
+                                               Resource r = resourceCollection.iterator().next();
+                                       result.add(new ComparableTabContributor(new P3DBasicPropertyTab(!readOnly), 0, r, "Graph"));
+                                                       
+                                } catch (Exception e) {
+                                        e.printStackTrace();
+                                }
+                                }
+                        }  
+                }
+                
+                if(result.size() == 0) {
+                        result.add(new ComparableTabContributor(new NoneSelectionTabContributor(),0, resourceCollection, "Empty"));
+                }
+            
+               return result;
+       }
+       
+       public class P3DBasicPropertyTab extends BasicPropertyTab {
+               
+               boolean enabled;
+               public P3DBasicPropertyTab(boolean enabled) {
+                       this.enabled = enabled;
+               }
+                public void updatePartName(ISelection forSelection, Callback<String> updateCallback) {
+                       Read<String> read = getPartNameReadRequest(forSelection);
+                       if (read == null) {
+                           updateCallback.run("Override to control part name (PropertyTabContributorImpl.updatePartName)");
+                       } else {
+                           Simantics.getSession().asyncRequest(read, new PartNameListener(updateCallback));
+                       }
+                   }
+                public Read<String> getPartNameReadRequest(ISelection forSelection) {
+                        final Resource r  =  AdaptationUtils.adaptToSingle(forSelection, Resource.class);
+                        if (r == null)
+                                return null;
+                        return new Read<String>() {
+                                @Override
+                               public String perform(ReadGraph graph) throws DatabaseException {
+                                       return NameUtils.getSafeName(graph, r);         
+                               }
+                       };
+                }
+                
+                @Override
+               public void createControls(Composite body, IWorkbenchSite site,
+                               ISessionContext context, WidgetSupport support) {
+                       // TODO Auto-generated method stub
+                       super.createControls(body, site, context, support);
+                       ((Composite)parameterExplorer.getExplorerControl()).setEnabled(enabled);
+               }
+       }
+       
+       
+       
+       public class MultiSelectionTabContibutor extends PropertyTabContributorImpl {
+               public void createControls(org.eclipse.swt.widgets.Composite body, org.eclipse.ui.IWorkbenchSite site, org.simantics.db.management.ISessionContext context, org.simantics.browsing.ui.swt.widgets.impl.WidgetSupport support) {
+                       //Composite composite = new Composite(body, SWT.NONE);
+               }
+               
+               public Read<String> getPartNameReadRequest(ISelection forSelection) {
+                        final Collection<Resource> coll =  AdaptationUtils.adaptToCollection(forSelection, Resource.class);
+                        if (coll.size() == 0)
+                                return null;
+                        return new Read<String>() {
+                                @Override
+                               public String perform(ReadGraph graph) throws DatabaseException {
+                                       String title = "";
+                                       for (Resource r : coll) {
+                                               title += NameUtils.getSafeName(graph, r) +",";
+                                       }
+                                       System.out.println(title);
+                                       return title.substring(0,title.length()-1);             
+                               }
+                       };
+                }
+       }
+       
+       public class NoneSelectionTabContributor extends PropertyTabContributorImpl {
+               @Override
+               public void createControls(Composite body, IWorkbenchSite site,
+                               ISessionContext context, WidgetSupport support) {
+                       //Composite composite = new Composite(body, SWT.NONE);
+                       
+               }
+               
+               public void updatePartName(ISelection forSelection, Callback<String> updateCallback) {
+                       updateCallback.run("No Selection");
+               }
+       }
+       
+
+}
diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/EndComponent.java b/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/EndComponent.java
new file mode 100644 (file)
index 0000000..5df76c0
--- /dev/null
@@ -0,0 +1,53 @@
+package org.simantics.plant3d.scenegraph;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.simantics.g3d.scenegraph.base.ParentNode;
+import org.simantics.objmap.graph.annotations.DynamicGraphType;
+import org.simantics.objmap.graph.annotations.GetType;
+import org.simantics.objmap.graph.annotations.SetType;
+import org.simantics.plant3d.ontology.Plant3D;
+import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint;
+import org.simantics.plant3d.scenegraph.controlpoint.ControlPointFactory;
+
+@DynamicGraphType(Plant3D.URIs.EndComponent)
+public class EndComponent extends PipelineComponent {
+
+       private String type;
+       PipeControlPoint controlPoint;
+       
+       @GetType(Plant3D.URIs.EndComponent)
+       public String getType() {
+               return type;
+       }
+       
+       @SetType(Plant3D.URIs.EndComponent)
+       public void setType(String type) throws Exception {
+               this.type = type;
+               controlPoint = ControlPointFactory.create(this);
+               
+       }
+       
+       @Override
+       public PipeControlPoint getControlPoint() {
+               return controlPoint;
+       }
+       
+       @Override
+       public void setParent(ParentNode<?> parent, String name) {
+               super.setParent(parent, name);
+               setPipeRun((PipeRun)parent);
+       }
+       
+       @Override
+       public Map<String, Object> updateParameterMap() {
+               Map<String,Object> map = new HashMap<String, Object>();
+               
+               PipeRun pipeRun = getPipeRun();
+               if (pipeRun != null) {
+                       map.put("radius", pipeRun.getPipeDiameter() * 0.5);
+               }
+               return map;
+       }
+}
diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/Equipment.java b/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/Equipment.java
new file mode 100644 (file)
index 0000000..3bac765
--- /dev/null
@@ -0,0 +1,125 @@
+package org.simantics.plant3d.scenegraph;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import javax.vecmath.Quat4d;
+import javax.vecmath.Vector3d;
+
+import org.simantics.g3d.math.MathTools;
+import org.simantics.g3d.property.annotations.CompoundGetPropertyValue;
+import org.simantics.g3d.property.annotations.CompoundSetPropertyValue;
+import org.simantics.objmap.graph.annotations.CompoundRelatedGetValue;
+import org.simantics.objmap.graph.annotations.CompoundRelatedSetValue;
+import org.simantics.objmap.graph.annotations.DynamicGraphType;
+import org.simantics.objmap.graph.annotations.GetType;
+import org.simantics.objmap.graph.annotations.RelatedElementsAdd;
+import org.simantics.objmap.graph.annotations.RelatedElementsGet;
+import org.simantics.objmap.graph.annotations.RelatedElementsRem;
+import org.simantics.objmap.graph.annotations.SetType;
+import org.simantics.plant3d.ontology.Plant3D;
+import org.simantics.plant3d.scenegraph.controlpoint.PipingRules;
+
+
+@DynamicGraphType(Plant3D.URIs.Equipment)
+public class Equipment extends P3DParentGeometryNode<Nozzle> {
+
+       private String type;
+       
+       @GetType(Plant3D.URIs.Equipment)
+       public String getType() {
+               return type;
+       }
+       
+       @SetType(Plant3D.URIs.Equipment)
+       public void setType(String type) {
+               this.type = type;
+       }
+       
+       
+       @RelatedElementsAdd(Plant3D.URIs.HasNozzle)
+       public void addChild(Nozzle node) {
+               Set<Integer> ids = new HashSet<Integer>();
+               for (Nozzle n : getChild()) {
+                       ids.add(n.getNozzleId());
+               }
+               int newId = 0;
+               while (ids.contains(newId))
+                       newId++;
+               addNode(Plant3D.URIs.HasNozzle,node);
+               node.setNozzleId(newId);
+       }
+       
+       @RelatedElementsGet(Plant3D.URIs.HasNozzle)
+       public Collection<Nozzle> getChild() {
+               return getNodes(Plant3D.URIs.HasNozzle);
+       }
+       
+       @RelatedElementsRem(Plant3D.URIs.HasNozzle)
+       public void remChild(Nozzle node) {
+               removeNode(Plant3D.URIs.HasNozzle, node);
+       }
+       
+       @Override
+       @CompoundRelatedGetValue(objRelation=Plant3D.URIs.hasParameter,objType=Plant3D.URIs.Parameter,valRelation=Plant3D.URIs.hasParameterValue)
+       @CompoundGetPropertyValue(name="Parameters",tabId="Parameters",value="parameters")
+       public Map<String, Object> getParameterMap() {
+               return super.getParameterMap();
+       }
+       
+       @Override
+       @CompoundRelatedSetValue(Plant3D.URIs.hasParameter)
+       @CompoundSetPropertyValue(value="parameters")
+       public void setParameterMap(Map<String, Object> parameters) {
+               super.setParameterMap(parameters);
+       }
+       
+       @Override
+       protected double[] getColor() {
+               return new double[]{1,0,0};
+       }
+       
+       @Override
+       protected double[] getSelectedColor() {
+               return new double[]{0.5,0,0.5};
+       }
+       
+       @Override
+       public void setPosition(Vector3d position) {
+               if (MathTools.equals(position, getPosition()))
+                       return;
+               super.setPosition(position);
+               for (Nozzle n : getChild()) {
+                       n.getControlPoint()._setWorldPosition(n.getWorldPosition());
+                       n.getControlPoint()._setWorldOrientation(n.getWorldOrientation());
+               }
+               for (Nozzle n : getChild()) {
+                       try {
+                               PipingRules.requestUpdate(n.getControlPoint());
+                       } catch (Exception e) {
+                               e.printStackTrace();
+                       }
+               }
+       }
+       
+       @Override
+       public void setOrientation(Quat4d orientation) {
+               if (MathTools.equals(orientation, getOrientation()))
+                       return;
+               super.setOrientation(orientation);
+               for (Nozzle n : getChild()) {
+                       n.getControlPoint()._setWorldPosition(n.getWorldPosition());
+                       n.getControlPoint()._setWorldOrientation(n.getWorldOrientation());
+               }
+               for (Nozzle n : getChild()) {
+                       try {
+                               PipingRules.requestUpdate(n.getControlPoint());
+                       } catch (Exception e) {
+                               e.printStackTrace();
+                       }
+               }
+       }
+
+}
diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/GeometryNode.java b/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/GeometryNode.java
new file mode 100644 (file)
index 0000000..8d7ba9d
--- /dev/null
@@ -0,0 +1,239 @@
+package org.simantics.plant3d.scenegraph;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.jcae.opencascade.jni.TopoDS_Shape;
+import org.simantics.g3d.math.MathTools;
+import org.simantics.g3d.scenegraph.NodeHighlighter;
+import org.simantics.g3d.vtk.utils.vtkUtil;
+import org.simantics.objmap.graph.annotations.RelatedGetObj;
+import org.simantics.objmap.graph.annotations.RelatedSetObj;
+import org.simantics.opencascade.OccTriangulator;
+import org.simantics.opencascade.ParametricSolidModelProvider;
+import org.simantics.opencascade.SolidModelProvider;
+import org.simantics.opencascade.vtk.vtkSolidObject;
+import org.simantics.plant3d.ontology.Plant3D;
+
+import vtk.vtkActor;
+import vtk.vtkPanel;
+import vtk.vtkProp3D;
+import vtk.vtkProperty;
+import vtk.vtkRenderer;
+
+public abstract class GeometryNode extends P3DNode implements ParameterizedNode, NodeHighlighter {
+       
+       private TopoDS_Shape solidModel;
+       private vtkSolidObject solidObject;
+       
+       private Map<String,Object> currentParameters;
+       private Map<String,Object> calculatedParameters;
+       
+       private boolean parametersUpdated = true;
+       
+       public GeometryNode() {
+               currentParameters = new HashMap<String, Object>();
+               calculatedParameters = new HashMap<String, Object>();
+       }
+       
+       @Override
+       public void visualize(vtkPanel panel) {
+               if (solidModelProvider != null) {
+                       
+                       updateParameters();
+                       if (solidModel == null || parametersUpdated) {
+                               createGeometry();       
+                       }
+               }
+               if ((solidObject == null || parametersUpdated) && solidModel != null) {
+                       solidObject = new vtkSolidObject(panel, solidModel);
+               }
+               if (solidObject != null) {
+                       solidObject.visualizeSolid(true,true, false,false);
+                       updateVisuals(true, true);
+               }
+               parametersUpdated = false;
+
+       }
+       
+       public void updateParameters() {
+               if (solidModelProvider instanceof ParametricSolidModelProvider) {
+                       ((ParametricSolidModelProvider)solidModelProvider).setProperties(currentParameters);
+                       ((ParametricSolidModelProvider)solidModelProvider).updateCalculatedProperties(calculatedParameters);
+               }
+       }
+       
+       private void createGeometry() {
+               Collection<TopoDS_Shape> shapes;
+               try {
+                       shapes = solidModelProvider.getModel();
+                       if (shapes.size() == 1) {
+                               solidModel = shapes.iterator().next();
+                       } else { 
+                               solidModel = OccTriangulator.makeCompound(shapes.toArray(new TopoDS_Shape[shapes.size()]));
+                               for (TopoDS_Shape shape : shapes) {
+                                       shape.delete();
+                               }
+                       }
+//                             shapes.clear();
+               } catch (Exception e) {
+                       // TODO Auto-generated catch block
+                       e.printStackTrace();
+               }
+       }
+       
+       public Map<String, Object> getParameterMap() {
+               return Collections.unmodifiableMap(currentParameters);
+       }
+       
+       public Map<String, Object> getCalculatedParameters() {
+               return calculatedParameters;
+       }
+       
+       public void setParametersUpdated(boolean parametersUpdated) {
+               this.parametersUpdated = parametersUpdated;
+       }
+       
+       public void setParameterMap(Map<String, Object> parameters) {
+               for (String id : parameters.keySet()) {
+                       Object currentValue = currentParameters.get(id);
+                       Object newValue = parameters.get(id);
+                       if (currentValue == newValue)
+                               continue;
+                       if (currentValue instanceof Double) {
+                               if (Math.abs((Double)currentValue-(Double)newValue) < MathTools.NEAR_ZERO)
+                                       continue;
+                       }
+                       currentParameters.put(id, newValue);
+                       parametersUpdated = true;
+                       firePropertyChanged(id);
+               }
+       }
+       
+       private SolidModelProvider solidModelProvider;
+       
+       @RelatedGetObj(Plant3D.URIs.hasGeometry)
+       public SolidModelProvider getGeometry() {
+               return solidModelProvider;
+       }
+       
+       @RelatedSetObj(Plant3D.URIs.hasGeometry)
+       public void setGeometry(final SolidModelProvider provider) {
+               if (provider != null && provider.equals(solidModelProvider))
+                       return;
+
+               if (solidModelProvider != null) {
+                       deleteData();
+               }
+               solidModelProvider = provider;
+               firePropertyChanged(Plant3D.URIs.hasGeometry);
+       }
+       
+       private void deleteData() {
+               solidModelProvider = null;
+               if (solidObject != null) {
+                       solidObject.clearActors();
+                       solidObject = null;
+               }
+               if (solidModel != null) {
+                       solidModel.delete();
+                       solidModel = null;
+               }
+       }
+       
+       @Override
+       public Collection<vtkProp3D> getActors() {
+               List<vtkProp3D> list = new ArrayList<vtkProp3D>();
+               if (solidObject != null)
+                       list.addAll(solidObject.getActors());
+               return list;
+       }
+       
+       @Override
+       public void stopVisualize() {
+               if (solidObject != null) {
+                       solidObject.clearActorsAWT();
+                       solidObject = null;
+               }
+               if (solidModel != null) {
+                       solidModel.delete();
+                       solidModel = null;
+               }
+               
+       }
+       
+       private boolean selected = false;
+       private boolean hover = false;
+       
+       @Override
+       public void highlight(HighlightEventType type) {
+               if (type == HighlightEventType.Selection || type == HighlightEventType.ClearSelection) {
+                       selected = type == HighlightEventType.Selection;
+//                     hingeA.visualizeSolid(selected,true,false);
+//                     hingeB.visualizeSolid(selected,true,false);
+                       updateVisuals(true, false);
+//                     update(null);
+               } else {
+                       hover = type == HighlightEventType.Hover;
+                       updateVisuals(false, true);
+               }
+               
+               
+       }
+       
+       protected double[] getSelectedColor() {
+               return new double[]{1,0,0};
+       }
+       
+       protected double[] getColor() {
+               return new double[]{1,1,0};
+       }
+       
+       private void updateVisuals(boolean s, boolean h) {
+               if (solidObject != null) {
+                       if (s) {
+                               double color[];
+                               if (selected) {
+                                       color = getSelectedColor();
+                               
+                               } else {
+                                       color = getColor();
+
+                               }
+                               for (vtkProp3D prop : solidObject.getSolid()) {
+                                       vtkProperty property = ((vtkActor)prop).GetProperty();
+                                       property.SetColor(color);
+                                       property.Delete();
+                               }
+                       }
+                       if (h) {
+                               double color[] = new double[]{0,0,0};
+                               if (hover)
+                                       color = new double[]{1,0,1};
+                               for (vtkProp3D prop : solidObject.getEdges()) {
+                                       vtkProperty property = ((vtkActor)prop).GetProperty();
+                                       property.SetColor(color);
+                                       property.Delete();
+                               }
+                               
+                       }
+               } else {
+//                     if (s) {
+//                             axes.addToRenderer();
+//                             axes.setAxesVisibility(selected);
+//                     }
+               }
+       }
+       
+       public void update(vtkRenderer ren) {
+               vtkUtil.updateTransform(getActors(), getWorldPosition(), getWorldOrientation());
+       }
+       
+       public TopoDS_Shape getSolidModel() {
+               return solidModel;
+       }
+}
diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/IP3DNode.java b/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/IP3DNode.java
new file mode 100644 (file)
index 0000000..56086af
--- /dev/null
@@ -0,0 +1,11 @@
+package org.simantics.plant3d.scenegraph;
+
+import org.simantics.g3d.scenegraph.IG3DNode;
+
+import vtk.vtkRenderer;
+
+public interface IP3DNode extends IG3DNode {
+       
+       public void update(vtkRenderer ren);
+
+}
diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/IP3DVisualNode.java b/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/IP3DVisualNode.java
new file mode 100644 (file)
index 0000000..ff568b5
--- /dev/null
@@ -0,0 +1,19 @@
+package org.simantics.plant3d.scenegraph;
+
+import java.util.Collection;
+
+import vtk.vtkPanel;
+import vtk.vtkProp3D;
+import vtk.vtkRenderer;
+
+public interface IP3DVisualNode extends IP3DNode {
+       public String getName();
+       public void setName(String name);
+       
+       public void visualize(vtkPanel panel);
+       public void stopVisualize();
+       
+       public void update(vtkRenderer ren);
+       
+       public Collection<vtkProp3D> getActors();
+}
diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/InlineComponent.java b/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/InlineComponent.java
new file mode 100644 (file)
index 0000000..88b1fab
--- /dev/null
@@ -0,0 +1,81 @@
+package org.simantics.plant3d.scenegraph;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.simantics.g3d.scenegraph.base.ParentNode;
+import org.simantics.objmap.graph.annotations.DynamicGraphType;
+import org.simantics.objmap.graph.annotations.GetType;
+import org.simantics.objmap.graph.annotations.SetType;
+import org.simantics.plant3d.ontology.Plant3D;
+import org.simantics.plant3d.scenegraph.controlpoint.ControlPointFactory;
+import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint;
+
+@DynamicGraphType(Plant3D.URIs.InlineComponent)
+public class InlineComponent extends PipelineComponent {
+
+       private String type;
+       private PipeControlPoint controlPoint;
+       
+       @GetType(Plant3D.URIs.InlineComponent)
+       public String getType() {
+               return type;
+       }
+       
+       @SetType(Plant3D.URIs.InlineComponent)
+       public void setType(String type) throws Exception{
+               this.type = type;
+               controlPoint = ControlPointFactory.create(this);
+               
+       }
+       
+       @Override
+       public PipeControlPoint getControlPoint() {
+               return controlPoint;
+       }
+       
+       @Override
+       public void setParent(ParentNode<?> parent, String name) {
+               super.setParent(parent, name);
+               setPipeRun((PipeRun)parent);
+       }
+       
+       public boolean isVariableLength() {
+               return !controlPoint.isFixed();
+       }
+       
+       @Override
+       public void updateParameters() {
+               super.updateParameters();
+               if (!isVariableLength()) {
+                       Map<String,Object> calculated = getCalculatedParameters();
+                       if (calculated.containsKey("length")) {
+                               controlPoint.setLength((Double)calculated.get("length"));
+                       }
+               }
+       }
+       
+       @Override
+       public Map<String, Object> updateParameterMap() {
+               Map<String,Object> map = new HashMap<String, Object>();
+               if (controlPoint != null) {
+                       if (!Double.isNaN(controlPoint.getLength()))
+                               map.put("length", controlPoint.getLength());
+                       if (controlPoint.isDualInline()) {
+                               PipeControlPoint sub = controlPoint.getSubPoint().get(0);
+                               PipeRun pipeRun = sub.getPipeRun();
+                               if (pipeRun != null) {
+                                       map.put("radius2", pipeRun.getPipeDiameter() * 0.5);
+                               }
+                       }
+               }
+                       
+               PipeRun pipeRun = getPipeRun();
+               if (pipeRun != null) {
+                       map.put("radius", pipeRun.getPipeDiameter() * 0.5);
+               }
+               return map;
+       }
+       
+       
+}
diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/Nozzle.java b/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/Nozzle.java
new file mode 100644 (file)
index 0000000..9c4ad6f
--- /dev/null
@@ -0,0 +1,153 @@
+package org.simantics.plant3d.scenegraph;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.vecmath.Quat4d;
+import javax.vecmath.Vector3d;
+
+import org.simantics.g3d.property.annotations.GetPropertyValue;
+import org.simantics.objmap.graph.annotations.DynamicGraphType;
+import org.simantics.objmap.graph.annotations.GetType;
+import org.simantics.objmap.graph.annotations.RelatedGetObj;
+import org.simantics.objmap.graph.annotations.RelatedGetValue;
+import org.simantics.objmap.graph.annotations.RelatedSetObj;
+import org.simantics.objmap.graph.annotations.RelatedSetValue;
+import org.simantics.objmap.graph.annotations.SetType;
+import org.simantics.plant3d.ontology.Plant3D;
+import org.simantics.plant3d.scenegraph.controlpoint.ControlPointFactory;
+import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint;
+
+
+@DynamicGraphType(Plant3D.URIs.Nozzle)
+public class Nozzle extends PipelineComponent {
+       
+       private String type;
+       private PipeControlPoint controlPoint;
+       
+       @GetType(Plant3D.URIs.Nozzle)
+       public String getType() {
+               return type;
+       }
+       
+       @SetType(Plant3D.URIs.Nozzle)
+       public void setType(String type) throws Exception{
+               this.type = type;
+               _createCP();
+               
+       }
+       
+       private int id = 0;
+       
+       @RelatedGetValue(Plant3D.URIs.HasNozzleId)
+       @GetPropertyValue(name="Nozzle ID", value=Plant3D.URIs.HasNozzleId, tabId="Default")
+       public int getNozzleId() {
+               return id;
+       }
+       
+       @RelatedSetValue(Plant3D.URIs.HasNozzleId)
+       public void setNozzleId(int id) {
+               if (id == this.id)
+                       return;
+               this.id = id;
+               firePropertyChanged(Plant3D.URIs.HasNozzleId);
+       }
+       
+       private void _createCP() throws Exception{
+               if (controlPoint != null)
+                       return;
+               if (getPipeRun() != null) {
+                       controlPoint = ControlPointFactory.create(this);
+                       // TODO : these should not be needed.
+                       controlPoint.setDeletable(false);
+                       controlPoint.setFixed(true);
+               }
+       }
+       
+       @RelatedSetObj(Plant3D.URIs.HasPipeRun)
+       @Override
+       public void setPipeRun(PipeRun pipeRun) {
+               super.setPipeRun(pipeRun);
+               try {
+                       _createCP();
+               } catch (Exception e) {
+                       // TODO Auto-generated catch block
+                       e.printStackTrace();
+               }
+               
+               firePropertyChanged(Plant3D.URIs.HasPipeRun);
+       }
+       
+       @RelatedGetObj(Plant3D.URIs.HasPipeRun)
+       @Override
+       public PipeRun getPipeRun() {
+               return super.getPipeRun();
+       }
+       
+       @Override
+       public PipeControlPoint getControlPoint() {
+               return controlPoint;
+       }
+       
+       
+       @Override
+       public void setPosition(Vector3d position) {
+               super.setPosition(position);
+               updateCP();
+       }
+       
+       @Override
+       public void setOrientation(Quat4d orientation) {
+               super.setOrientation(orientation);
+               updateCP();
+       }
+       
+       private void updateCP() {
+               if (controlPoint == null)
+                       return;
+               if (controlPoint.getPipeRun() == null)
+                       return;
+               controlPoint._setWorldPosition(getWorldPosition());
+               controlPoint._setWorldOrientation(getWorldOrientation());
+       }
+       
+       
+       @Override
+       public Map<String, Object> updateParameterMap() {
+               Map<String,Object> map = new HashMap<String, Object>();
+               
+               PipeRun pipeRun = getPipeRun();
+               if (pipeRun != null) {
+                       map.put("length", pipeRun.getPipeDiameter() * 2.0);
+                       map.put("radius", pipeRun.getPipeDiameter() * 0.5);
+               }
+               return map;
+       }
+       
+       @Override
+       protected double[] getColor() {
+               return new double[]{0.7,0.7,0.7};
+       }
+       
+       @Override
+       protected double[] getSelectedColor() {
+               return new double[]{0.5,0,0.5};
+       }
+       
+       public boolean isConnected() {
+               PipeControlPoint pcp = getControlPoint();
+               return (pcp.getNext() != null || pcp.getPrevious() != null);
+       }
+       
+       public boolean isNextConnected() {
+               PipeControlPoint pcp = getControlPoint();
+               return (pcp.getNext() != null);
+       }
+       
+       public boolean isPrevConnected() {
+               PipeControlPoint pcp = getControlPoint();
+               return (pcp.getNext() != null);
+       }
+       
+
+}
diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/P3DNode.java b/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/P3DNode.java
new file mode 100644 (file)
index 0000000..84e1535
--- /dev/null
@@ -0,0 +1,34 @@
+package org.simantics.plant3d.scenegraph;
+
+import org.simantics.g3d.property.annotations.GetPropertyValue;
+import org.simantics.g3d.property.annotations.SetPropertyValue;
+import org.simantics.g3d.scenegraph.G3DNode;
+import org.simantics.layer0.Layer0;
+import org.simantics.objmap.graph.annotations.RelatedGetValue;
+import org.simantics.objmap.graph.annotations.RelatedSetValue;
+
+public abstract class P3DNode extends G3DNode implements IP3DVisualNode {
+       private String name;
+       
+
+       @RelatedGetValue(Layer0.URIs.HasName)
+       @GetPropertyValue(value = Layer0.URIs.HasName, tabId = "Default", name = "Name")
+       public String getName() {
+               return name;
+       }
+       
+       @RelatedSetValue(Layer0.URIs.HasName)
+       @SetPropertyValue(Layer0.URIs.HasName)
+       public void setName(String name) {
+               if (name == null)
+                       return;
+               this.name = name;
+               firePropertyChanged(Layer0.URIs.HasName);
+       }
+       
+       @Override
+       public String toString() {
+               return getName();
+       }
+       
+}
diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/P3DParentGeometryNode.java b/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/P3DParentGeometryNode.java
new file mode 100644 (file)
index 0000000..c749200
--- /dev/null
@@ -0,0 +1,235 @@
+package org.simantics.plant3d.scenegraph;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.jcae.opencascade.jni.TopoDS_Shape;
+import org.simantics.g3d.math.MathTools;
+import org.simantics.g3d.scenegraph.NodeHighlighter;
+import org.simantics.g3d.vtk.utils.vtkUtil;
+import org.simantics.objmap.graph.annotations.RelatedGetObj;
+import org.simantics.objmap.graph.annotations.RelatedSetObj;
+import org.simantics.opencascade.OccTriangulator;
+import org.simantics.opencascade.ParametricSolidModelProvider;
+import org.simantics.opencascade.SolidModelProvider;
+import org.simantics.opencascade.vtk.vtkSolidObject;
+import org.simantics.plant3d.ontology.Plant3D;
+
+import vtk.vtkActor;
+import vtk.vtkPanel;
+import vtk.vtkProp3D;
+import vtk.vtkProperty;
+import vtk.vtkRenderer;
+
+public class P3DParentGeometryNode<T extends IP3DNode> extends P3DParentNode<T> implements ParameterizedNode, NodeHighlighter{
+       private TopoDS_Shape solidModel;
+       private vtkSolidObject solidObject;
+       
+       private Map<String,Object> currentParameters;
+       private Map<String,Object> calculatedParameters;
+       
+       private boolean parametersUpdated = true;
+       
+       
+       public P3DParentGeometryNode() {
+               currentParameters = new HashMap<String, Object>();
+               calculatedParameters = new HashMap<String, Object>();
+       }
+       
+       @Override
+       public void visualize(vtkPanel ren) {
+               if (solidModelProvider != null) {
+                       
+                       updateParameters();
+                       
+                       if (solidModel == null || parametersUpdated) {
+                               createGeometry();       
+                       }
+               }
+               if ((solidObject == null || parametersUpdated) && solidModel != null) {
+                       solidObject = new vtkSolidObject(ren, solidModel);
+               }
+               if (solidObject != null) {
+                       solidObject.visualizeSolid(true,true, false,false);
+                       updateVisuals(true, true);
+               }
+               parametersUpdated = false;
+
+       }
+       
+       public void updateParameters() {
+               if (solidModelProvider instanceof ParametricSolidModelProvider) {
+                       ((ParametricSolidModelProvider)solidModelProvider).setProperties(currentParameters);
+                       ((ParametricSolidModelProvider)solidModelProvider).updateCalculatedProperties(calculatedParameters);
+               }
+       }
+       
+       private void createGeometry() {
+               Collection<TopoDS_Shape> shapes;
+               try {
+                       shapes = solidModelProvider.getModel();
+                       if (shapes.size() == 1) {
+                               solidModel = shapes.iterator().next();
+                       } else { 
+                               solidModel = OccTriangulator.makeCompound(shapes.toArray(new TopoDS_Shape[shapes.size()]));
+                               for (TopoDS_Shape shape : shapes) {
+                                       shape.delete();
+                               }
+                       }
+//                             shapes.clear();
+               } catch (Exception e) {
+                       // TODO Auto-generated catch block
+                       e.printStackTrace();
+               }
+       }
+       
+       
+       
+       public Map<String, Object> getParameterMap() {
+               return Collections.unmodifiableMap(currentParameters);
+       }
+       
+       public void setParameterMap(Map<String, Object> parameters) {
+               for (String id : parameters.keySet()) {
+                       Object currentValue = currentParameters.get(id);
+                       Object newValue = parameters.get(id);
+                       if (currentValue == newValue)
+                               continue;
+                       if (currentValue instanceof Double) {
+                               if (Math.abs((Double)currentValue-(Double)newValue) < MathTools.NEAR_ZERO)
+                                       continue;
+                       }
+                       currentParameters.put(id, newValue);
+                       parametersUpdated = true;
+                       firePropertyChanged(id);
+               }
+       }
+       
+       
+       private SolidModelProvider solidModelProvider;
+       
+       @RelatedGetObj(Plant3D.URIs.hasGeometry)
+       public SolidModelProvider getGeometry() {
+               return solidModelProvider;
+       }
+       
+       @RelatedSetObj(Plant3D.URIs.hasGeometry)
+       public void setGeometry(final SolidModelProvider provider) {
+               if (provider != null && provider.equals(solidModelProvider))
+                       return;
+
+               if (solidModelProvider != null) {
+                       deleteData();
+               }
+               solidModelProvider = provider;
+               firePropertyChanged(Plant3D.URIs.hasGeometry);
+       }
+       
+       private void deleteData() {
+               solidModelProvider = null;
+               if (solidObject != null) {
+                       solidObject.clearActors();
+                       solidObject = null;
+               }
+               if (solidModel != null) {
+                       solidModel.delete();
+                       solidModel = null;
+               }
+       }
+       
+       @Override
+       public Collection<vtkProp3D> getActors() {
+               List<vtkProp3D> list = new ArrayList<vtkProp3D>();
+               if (solidObject != null)
+                       list.addAll(solidObject.getActors());
+               return list;
+       }
+       
+       @Override
+       public void stopVisualize() {
+               if (solidObject != null) {
+                       solidObject.clearActorsAWT();
+                       solidObject = null;
+               }
+               if (solidModel != null) {
+                       solidModel.delete();
+                       solidModel = null;
+               }
+               
+       }
+       
+       private boolean selected = false;
+       private boolean hover = false;
+       
+       @Override
+       public void highlight(HighlightEventType type) {
+               if (type == HighlightEventType.Selection || type == HighlightEventType.ClearSelection) {
+                       selected = type == HighlightEventType.Selection;
+//                     hingeA.visualizeSolid(selected,true,false);
+//                     hingeB.visualizeSolid(selected,true,false);
+                       updateVisuals(true, false);
+//                     update(null);
+               } else {
+                       hover = type == HighlightEventType.Hover;
+                       updateVisuals(false, true);
+               }
+               
+               
+       }
+       
+       protected double[] getSelectedColor() {
+               return new double[]{1,0,0};
+       }
+       
+       protected double[] getColor() {
+               return new double[]{1,1,0};
+       }
+       
+       private void updateVisuals(boolean s, boolean h) {
+               if (solidObject != null) {
+                       if (s) {
+                               double color[];
+                               if (selected) {
+                                       color = getSelectedColor();
+                               
+                               } else {
+                                       color = getColor();
+
+                               }
+                               for (vtkProp3D prop : solidObject.getSolid()) {
+                                       vtkProperty property = ((vtkActor)prop).GetProperty();
+                                       property.SetColor(color);
+                                       property.Delete();
+                               }
+                       }
+                       if (h) {
+                               double color[] = new double[]{0,0,0};
+                               if (hover)
+                                       color = new double[]{1,0,1};
+                               for (vtkProp3D prop : solidObject.getEdges()) {
+                                       vtkProperty property = ((vtkActor)prop).GetProperty();
+                                       property.SetColor(color);
+                                       property.Delete();
+                               }
+                               
+                       }
+               } else {
+//                     if (s) {
+//                             axes.addToRenderer();
+//                             axes.setAxesVisibility(selected);
+//                     }
+               }
+       }
+       
+       public void update(vtkRenderer ren) {
+               vtkUtil.updateTransform(getActors(), getWorldPosition(), getWorldOrientation());
+       }
+       
+       public TopoDS_Shape getSolidModel() {
+               return solidModel;
+       }
+}
diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/P3DParentNode.java b/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/P3DParentNode.java
new file mode 100644 (file)
index 0000000..08c289d
--- /dev/null
@@ -0,0 +1,194 @@
+package org.simantics.plant3d.scenegraph;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.vecmath.Quat4d;
+import javax.vecmath.Vector3d;
+
+import org.simantics.g3d.math.MathTools;
+import org.simantics.g3d.ontology.G3D;
+import org.simantics.g3d.property.annotations.GetPropertyValue;
+import org.simantics.g3d.property.annotations.PropertyContributor;
+import org.simantics.g3d.property.annotations.SetPropertyValue;
+import org.simantics.g3d.scenegraph.IG3DNode;
+import org.simantics.g3d.scenegraph.base.ParentNode;
+import org.simantics.g3d.tools.NodeTools;
+import org.simantics.layer0.Layer0;
+import org.simantics.objmap.graph.annotations.RelatedGetValue;
+import org.simantics.objmap.graph.annotations.RelatedSetValue;
+
+@PropertyContributor
+public abstract class P3DParentNode<T extends IP3DNode> extends ParentNode<T> implements IP3DVisualNode {
+       
+       private String name;
+       
+
+       
+       
+       @RelatedGetValue(Layer0.URIs.HasName)
+       @GetPropertyValue(value = Layer0.URIs.HasName, tabId = "Default", name = "Name")
+       public String getName() {
+               return name;
+       }
+       
+       @RelatedSetValue(Layer0.URIs.HasName)
+       @SetPropertyValue(Layer0.URIs.HasName)
+       public void setName(String name) {
+               if (name == null)
+                       return;
+               this.name = name;
+               firePropertyChanged(Layer0.URIs.HasName);
+       }
+       
+       @Override
+       public String toString() {
+               return getName();
+       }
+       
+       private Vector3d position = new Vector3d();
+       private Quat4d orientation = MathTools.getIdentityQuat();
+       
+       @Override
+       @GetPropertyValue(value = G3D.URIs.hasOrientation, tabId = "Transform", name = "Orientation")
+       public Quat4d getOrientation() {
+               return orientation;
+       }
+       
+       @RelatedGetValue(G3D.URIs.hasOrientation)
+       public double[] getOrientationArr() {
+               double arr[] = new double[4];
+               orientation.get(arr);
+               return arr;
+               
+       }
+       
+       @Override
+       @GetPropertyValue(value = G3D.URIs.hasPosition, tabId = "Transform", name = "Position")
+       public Vector3d getPosition() {
+               return position;
+       }
+       
+       @RelatedGetValue(G3D.URIs.hasPosition)
+       public double[] getPositionArr() {
+               double arr[] = new double[3];
+               position.get(arr);
+               return arr;
+       }
+       
+       @Override
+       @SetPropertyValue(G3D.URIs.hasOrientation)
+       public void setOrientation(Quat4d orientation) {
+               assert(orientation != null);
+               this.orientation = orientation;
+               
+               firePropertyChanged(G3D.URIs.hasOrientation);
+       }
+       
+       @Override
+       @SetPropertyValue(G3D.URIs.hasPosition)
+       public void setPosition(Vector3d position) {
+               assert(position != null);
+               this.position = position;
+               
+               firePropertyChanged(G3D.URIs.hasPosition);
+       }
+       
+       @RelatedSetValue(G3D.URIs.hasOrientation)
+       public void setOrientation(double[] arr) {
+               if (arr == null)
+                       return;
+               setOrientation(new Quat4d(arr));
+       }
+       
+       @RelatedSetValue(G3D.URIs.hasPosition)
+       public void setPosition(double[] arr) {
+               if (arr == null)
+                       return;
+               setPosition(new Vector3d(arr));
+       }
+       
+       @Override
+       @GetPropertyValue(value = G3D.URIs.hasWorldPosition, tabId = "Transform", name = "World Position")
+       public Vector3d getWorldPosition() {
+               IG3DNode parent = (IG3DNode)getParent();
+               if (parent == null)
+                       return position;
+               return NodeTools.getWorldPosition(parent, new Vector3d(position));
+       }
+       
+       
+       public Vector3d getWorldPosition(Vector3d localPosition) {
+               return NodeTools.getWorldPosition(this,localPosition);
+       }
+
+       
+       @Override
+       @GetPropertyValue(value = G3D.URIs.hasWorldOrientation, tabId = "Transform", name = "World Orientation")
+       public Quat4d getWorldOrientation() {
+               return getWorldOrientation(new Quat4d(orientation));
+       }
+       
+       public Quat4d getWorldOrientation(Quat4d localOrientation) {
+               IG3DNode parent = (IG3DNode)getParent();
+               if (parent == null)
+                       return localOrientation;
+               return NodeTools.getWorldOrientation(parent, localOrientation);
+       }
+       
+       @Override
+       public Vector3d getLocalPosition(Vector3d worldPosition) {
+               IG3DNode parent = (IG3DNode)getParent();
+               if (parent == null)
+                       return worldPosition;
+               return NodeTools.getLocalPosition(parent,new Vector3d(worldPosition));
+       }
+       
+       @Override
+       public Quat4d getLocalOrientation(Quat4d worldOrientation) {
+               IG3DNode parent = (IG3DNode)getParent();
+               if (parent == null)
+                       return worldOrientation;
+               return NodeTools.getLocalOrientation(parent, new Quat4d(worldOrientation));
+       }
+       
+       @Override
+       @SetPropertyValue(G3D.URIs.hasWorldPosition)
+       public void setWorldPosition(Vector3d position) {
+               Vector3d localPos = getLocalPosition(position);
+               setPosition(localPos);
+       }
+       
+       @Override
+       @SetPropertyValue(G3D.URIs.hasWorldOrientation)
+       public void setWorldOrientation(Quat4d orientation) {
+               Quat4d localOr = getLocalOrientation(orientation);
+               setOrientation(localOr);
+       }
+       
+       @Override
+       public Object getAdapter(Class adapter) {
+               if (IG3DNode.class == adapter)
+                       return this;
+               return null;
+       }
+       
+       public String getUniqueName(String prefix) {
+               Set<String> names = new HashSet<String>();
+               for (IP3DNode node : getNodes()) {
+                       if (!(node instanceof IP3DVisualNode))
+                               continue;
+                       IP3DVisualNode n = (IP3DVisualNode)node;
+                       names.add(n.getName());
+               }
+               int i = 1;
+               while (true) {
+                       String genName = prefix + "_" + i;
+                       if (!names.contains(genName))
+                               return genName;
+                       i++;
+               }
+       }
+
+    
+}
diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/P3DRootNode.java b/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/P3DRootNode.java
new file mode 100644 (file)
index 0000000..5a96860
--- /dev/null
@@ -0,0 +1,170 @@
+package org.simantics.plant3d.scenegraph;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.vecmath.Quat4d;
+import javax.vecmath.Vector3d;
+
+import org.simantics.g3d.math.MathTools;
+import org.simantics.g3d.scenegraph.IG3DNode;
+import org.simantics.g3d.scenegraph.NodeMap;
+import org.simantics.g3d.scenegraph.NodeMapProvider;
+import org.simantics.g3d.scenegraph.base.INode;
+import org.simantics.g3d.scenegraph.base.NodeException;
+import org.simantics.g3d.scenegraph.base.ParentNode;
+import org.simantics.objmap.graph.annotations.GraphType;
+import org.simantics.objmap.graph.annotations.RelatedElementsAdd;
+import org.simantics.objmap.graph.annotations.RelatedElementsGet;
+import org.simantics.objmap.graph.annotations.RelatedElementsRem;
+import org.simantics.plant3d.editor.P3DNodeMap;
+import org.simantics.plant3d.ontology.Plant3D;
+
+import vtk.vtkProp;
+
+@GraphType(Plant3D.URIs.Plant)
+public class P3DRootNode extends ParentNode<INode> implements IG3DNode, NodeMapProvider<vtkProp , INode> {
+       
+       
+       @RelatedElementsAdd(Plant3D.URIs.childen)
+       public void addChild(IP3DVisualNode node) {
+               addNode(Plant3D.URIs.childen,node);
+       }
+       
+       @RelatedElementsGet(Plant3D.URIs.childen)
+       public Collection<INode> getChild() {
+               return getNodes(Plant3D.URIs.childen);
+       }
+       
+       @RelatedElementsRem(Plant3D.URIs.childen)
+       public void remChild(IP3DNode node) {
+               removeNode(Plant3D.URIs.childen, node);
+       }
+       
+       private P3DNodeMap nodeMap;
+       
+       public void setNodeMap(P3DNodeMap nodeMap) {
+               this.nodeMap = nodeMap;
+       }
+       
+       @Override
+       public NodeMap<vtkProp, INode> getNodeMap() {
+               return nodeMap;
+       }
+       
+       @Override
+       public ParentNode<?> getParent() {
+               return null;
+       }
+       
+       @Override
+       public ParentNode<?> getRootNode() {
+               return this;
+       }
+       
+       public javax.vecmath.Quat4d getOrientation() {
+               return MathTools.getIdentityQuat();
+       };
+       
+       @Override
+       public Vector3d getPosition() {
+               return new Vector3d();
+       }
+       
+       @Override
+       public Quat4d getWorldOrientation() {
+               return MathTools.getIdentityQuat();
+       }
+       
+       @Override
+       public Vector3d getWorldPosition() {
+               return new Vector3d();
+       }
+       
+       @Override
+       public Quat4d getWorldOrientation(Quat4d localOrientation) {
+               return localOrientation;
+       }
+       
+       @Override
+       public Vector3d getWorldPosition(Vector3d localPosition) {
+               return localPosition;
+       }
+       
+       @Override
+       public Quat4d getLocalOrientation(Quat4d worldOrientation) {
+               return worldOrientation;
+       }
+       
+       @Override
+       public Vector3d getLocalPosition(Vector3d worldPosition) {
+               return worldPosition;
+       }
+       
+       @Override
+       public void setPosition(Vector3d position) {
+               throw new NodeException("Cannot set root node position");
+       }
+       
+       @Override
+       public void setOrientation(Quat4d orientation) {
+               throw new NodeException("Cannot set root node orientation");
+       }
+       
+       @Override
+       public void setWorldOrientation(Quat4d orientation) {
+               throw new NodeException("Cannot set root node orientation");
+       }
+       
+       @Override
+       public void setWorldPosition(Vector3d position) {
+               throw new NodeException("Cannot set root node orientation");
+       }
+       
+       public String getUniqueName(String prefix) {
+               Set<String> names = new HashSet<String>();
+               for (INode node : getChild()) {
+                       if (!(node instanceof IP3DVisualNode))
+                               continue;
+                       IP3DVisualNode n = (IP3DVisualNode)node;
+                       names.add(n.getName());
+               }
+               int i = 1;
+               while (true) {
+                       String genName = prefix + "_" + i;
+                       if (!names.contains(genName))
+                               return genName;
+                       i++;
+               }
+       }
+
+       
+       @SuppressWarnings("rawtypes")
+       @Override
+       public Object getAdapter(Class adapter) {
+               if (NodeMap.class == adapter)
+                       return nodeMap;
+               return null;
+       }
+       
+       public Nozzle createNozzle() {
+               return new Nozzle();
+       }
+       
+       public Equipment createEquipment() {
+               return new Equipment();
+       }
+       
+       public InlineComponent createInline() {
+               return new InlineComponent();
+       }
+       
+       public EndComponent createEnd() {
+               return new EndComponent();
+       }
+       
+       public TurnComponent createTurn() {
+               return new TurnComponent();
+       }
+}
diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/ParameterizedNode.java b/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/ParameterizedNode.java
new file mode 100644 (file)
index 0000000..7aa0e80
--- /dev/null
@@ -0,0 +1,14 @@
+package org.simantics.plant3d.scenegraph;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.simantics.g3d.scenegraph.IG3DNode;
+
+public interface ParameterizedNode extends IG3DNode {
+
+       
+       public Map<String,Object> getParameterMap();
+       public void setParameterMap(Map<String,Object> parameters);
+       
+}
diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/PipeRun.java b/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/PipeRun.java
new file mode 100644 (file)
index 0000000..2932f1d
--- /dev/null
@@ -0,0 +1,161 @@
+package org.simantics.plant3d.scenegraph;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import org.simantics.g3d.math.MathTools;
+import org.simantics.g3d.property.annotations.GetPropertyValue;
+import org.simantics.g3d.property.annotations.PropertyTabBlacklist;
+import org.simantics.g3d.property.annotations.SetPropertyValue;
+import org.simantics.g3d.scenegraph.IG3DNode;
+import org.simantics.objmap.graph.annotations.GraphType;
+import org.simantics.objmap.graph.annotations.RelatedElementsAdd;
+import org.simantics.objmap.graph.annotations.RelatedElementsGet;
+import org.simantics.objmap.graph.annotations.RelatedElementsRem;
+import org.simantics.objmap.graph.annotations.RelatedGetValue;
+import org.simantics.objmap.graph.annotations.RelatedSetValue;
+import org.simantics.plant3d.ontology.Plant3D;
+import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint;
+
+import vtk.vtkPanel;
+import vtk.vtkProp3D;
+import vtk.vtkRenderer;
+
+@GraphType(Plant3D.URIs.PipeRun)
+@PropertyTabBlacklist("Transform")
+public class PipeRun extends P3DParentNode<IP3DNode> {
+       
+       private double pipeDiameter = 0.1;
+       private double turnRadius = 0.2;
+       
+       @Override
+       public void update(vtkRenderer ren) {
+               
+       }
+       
+       @Override
+       public void visualize(vtkPanel panel) {
+               
+       }
+       
+       @Override
+       public Collection<vtkProp3D> getActors() {
+               return Collections.EMPTY_LIST;
+       }
+       
+       @Override
+       public void stopVisualize() {
+               
+       }
+       
+       @RelatedGetValue(Plant3D.URIs.HasTurnRadius)
+       @GetPropertyValue(value=Plant3D.URIs.HasTurnRadius, name = "Elbow radius")
+       public double getTurnRadius() {
+               return turnRadius;
+       }
+       
+       @RelatedSetValue(Plant3D.URIs.HasTurnRadius)
+       @SetPropertyValue(Plant3D.URIs.HasTurnRadius)
+       public void setTurnRadius(double turnRadius) {
+               this.turnRadius = turnRadius;
+               firePropertyChanged(Plant3D.URIs.HasTurnRadius);
+       }
+       
+       @RelatedGetValue(Plant3D.URIs.HasPipeDiameter)
+       @GetPropertyValue(value=Plant3D.URIs.HasPipeDiameter, name = "Diameter")
+       public double getPipeDiameter() {
+               return pipeDiameter;
+       }
+       
+       @RelatedSetValue(Plant3D.URIs.HasPipeDiameter)
+       @SetPropertyValue(Plant3D.URIs.HasPipeDiameter)
+       public void setPipeDiameter(double pipeDiameter) {
+               this.pipeDiameter = pipeDiameter;       
+               firePropertyChanged(Plant3D.URIs.HasPipeDiameter);
+       }
+       
+       @RelatedElementsAdd(Plant3D.URIs.childen)
+       public void addChild(PipelineComponent node) {
+               addNode(Plant3D.URIs.childen,node);
+       }
+       
+       @RelatedElementsGet(Plant3D.URIs.childen)
+       public Collection<PipelineComponent> getChild() {
+               Collection<PipelineComponent> coll = new ArrayList<PipelineComponent>();
+               for (IG3DNode n : getNodes(Plant3D.URIs.childen)) {
+                       coll.add((PipelineComponent)n);
+               }
+               return coll;
+       }
+       
+       @RelatedElementsRem(Plant3D.URIs.childen)
+       public void remChild(PipelineComponent node) {
+               removeNode(Plant3D.URIs.childen, node);
+       }
+
+       
+       public List<PipelineComponent> getSortedChild() {
+               List<PipelineComponent> coll = new ArrayList<PipelineComponent>();
+               for (IG3DNode n : getNodes(Plant3D.URIs.childen)) {
+                       coll.add((PipelineComponent)n);
+               }
+               Collections.sort(coll, new ComponentComparator());
+               return coll;
+       }
+       public void addChild(PipeControlPoint node) {
+               addNode("pipecp",node);
+       }
+       
+       public void remChild(PipeControlPoint node) {
+               removeNode("pipecp", node);
+       }
+       
+       public void deattachChild(PipeControlPoint node) {
+               deattachNode("pipecp", node);
+       }
+       
+       public Collection<PipeControlPoint> getControlPoints() {
+               Collection<PipeControlPoint> coll = new ArrayList<PipeControlPoint>();
+               for (IG3DNode n : getNodes("pipecp")) {
+                       coll.add((PipeControlPoint)n);
+               }
+               return coll;
+       }
+       
+       public boolean equalSpecs(PipeRun other) {
+               if (!MathTools.equals(pipeDiameter,other.pipeDiameter))
+                       return false;
+               if (!MathTools.equals(turnRadius,other.turnRadius))
+                       return false;
+               return true;
+       }
+       
+       private class ComponentComparator implements Comparator<PipelineComponent> {
+               @Override
+               public int compare(PipelineComponent o1, PipelineComponent o2) {
+                       if (o1 == o2)
+                               return 0;
+                       int i = 1;
+                       PipelineComponent c = o1.getPrevious();
+                       while (c != null) {
+                               if (c == o2)
+                                       return i;
+                               c = c.getPrevious();
+                               i++;
+                       }
+                       i = -1;
+                       c = o1.getNext();
+                       while (c != null) {
+                               if (c == o2)
+                                       return i;
+                               c = c.getNext();
+                               i--;
+                       }
+                       return 0;
+                       
+               }
+       }
+}
diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/PipelineComponent.java b/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/PipelineComponent.java
new file mode 100644 (file)
index 0000000..8fe597c
--- /dev/null
@@ -0,0 +1,394 @@
+package org.simantics.plant3d.scenegraph;
+
+import java.util.Collections;
+import java.util.Map;
+
+import javax.vecmath.Quat4d;
+import javax.vecmath.Tuple3d;
+import javax.vecmath.Vector3d;
+
+import org.simantics.g3d.math.MathTools;
+import org.simantics.g3d.property.annotations.GetPropertyValue;
+import org.simantics.g3d.property.annotations.PropertyContributor;
+import org.simantics.objmap.graph.annotations.RelatedGetObj;
+import org.simantics.objmap.graph.annotations.RelatedSetObj;
+import org.simantics.plant3d.ontology.Plant3D;
+import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint;
+import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint.Type;
+import org.simantics.plant3d.scenegraph.controlpoint.PipingRules;
+
+/**
+ * 
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>
+ *
+ */
+@PropertyContributor
+public abstract class PipelineComponent extends GeometryNode {
+
+       
+       private PipeRun pipeRun;
+       private PipeRun alternativePipeRun;
+       private PipelineComponent next;
+       private PipelineComponent previous;
+       
+       /**
+        * Sets the pipe run.
+        * 
+        * With in-line,turn, and end components, the pipe run is the parent object in the scene-graph.
+        * With nozzles, the pipe run setting is explicit (nozzle has to be linked to the piperun, since the parent object is equipment).
+        * With size change components (in-line), there is also alternative pipe run, which must match the next component's pipe run.
+        * 
+        * @param pipeRun
+        */
+       public void setPipeRun(PipeRun pipeRun) {
+               if (pipeRun == this.pipeRun)
+                       return;
+               this.pipeRun = pipeRun;
+               if (getControlPoint() != null) {
+                       getControlPoint().deattach();
+                       if (pipeRun != null) {
+                               pipeRun.addChild(getControlPoint());
+                       }
+               }
+               updateParameters();
+       }
+       
+       @RelatedGetObj(Plant3D.URIs.HasAlternativePipeRun)
+       public PipeRun getAlternaitvePipeRun() {
+               return alternativePipeRun;
+       }
+       
+       @RelatedSetObj(Plant3D.URIs.HasAlternativePipeRun)
+       public void setAlternativePipeRun(PipeRun pipeRun) {
+               if (this.alternativePipeRun == pipeRun)
+                       return;
+               this.alternativePipeRun = pipeRun;
+               if (getControlPoint().isDualInline()) {
+                       PipeControlPoint sub = getControlPoint().getSubPoint().get(0);
+                       if (sub.getParent() != this.alternativePipeRun)
+                               this.alternativePipeRun.addChild(sub);
+               }
+               firePropertyChanged(Plant3D.URIs.HasAlternativePipeRun);
+       }
+       
+       @Override
+       public void updateParameters() {
+               setParameterMap(updateParameterMap());
+               super.updateParameters();
+       }
+       
+       public abstract void setType(String typeURI) throws Exception;
+       
+       @RelatedGetObj(Plant3D.URIs.HasNext)
+       public PipelineComponent getNext() {
+               return next;
+       }
+       
+       @RelatedSetObj(Plant3D.URIs.HasNext)
+       public void setNext(PipelineComponent comp) {
+               if (next == comp)
+                       return;
+               this.next = comp;
+               syncNext();
+               firePropertyChanged(Plant3D.URIs.HasNext);
+               if (comp != null)
+                       comp.sync();
+//             System.out.println(this + " next " + comp);
+       }
+       
+       
+       @RelatedGetObj(Plant3D.URIs.HasPrevious)
+       public PipelineComponent getPrevious() {
+               return previous;
+       }
+       
+       @RelatedSetObj(Plant3D.URIs.HasPrevious)
+       public void setPrevious(PipelineComponent comp) {
+               if (previous == comp)
+                       return;
+               this.previous = comp;
+               
+               firePropertyChanged(Plant3D.URIs.HasPrevious);
+               if (comp != null)
+                       comp.sync();
+//             System.out.println(this + " prev " + comp);
+       }
+       private PipelineComponent branch0;
+       
+       @RelatedGetObj(Plant3D.URIs.HasBranch0)
+       public PipelineComponent getBranch0() {
+               return branch0;
+       }
+       
+       @RelatedSetObj(Plant3D.URIs.HasBranch0)
+       public void setBranch0(PipelineComponent comp) {
+               if (branch0 == comp)
+                       return;
+               this.branch0 = comp;
+               syncBranch0();
+               firePropertyChanged(Plant3D.URIs.HasBranch0);
+               if (comp != null)
+                       comp.sync();
+//             System.out.println(this + " next " + comp);
+       }
+
+
+       
+       private PipeControlPoint getBranchPoint() {
+               PipeControlPoint branchPoint;
+               if (getControlPoint().getSubPoint().size() > 0) {
+                       branchPoint = getControlPoint().getSubPoint().get(0);
+               } else {
+                       if (branch0.getPipeRun() == null)
+                               return null;
+                       branchPoint = new PipeControlPoint(this,branch0.getPipeRun());
+                       branchPoint.setFixed(false);
+                       branchPoint.setType(Type.END);
+                       branchPoint.parent = getControlPoint();
+                       getControlPoint().children.add(branchPoint);
+                       branchPoint.setWorldOrientation(getControlPoint().getWorldOrientation());
+                       branchPoint.setWorldPosition(getControlPoint().getWorldPosition());
+               }
+               return branchPoint;
+       }
+       
+       private boolean _connectNext(PipeControlPoint pcp, PipeControlPoint nextPCP) {
+               if (nextPCP == null)
+                       return false;
+               if (pcp.getNext() != nextPCP) {
+                       pcp.setNext(nextPCP);
+               }
+               if (pcp.isDualInline()) {
+                       PipeControlPoint sub = pcp.getSubPoint().get(0);
+                       if (sub.getNext() != nextPCP)
+                               sub.setNext(nextPCP);
+               }
+               return true;
+       }
+       
+       private boolean  _connectPrev(PipeControlPoint pcp, PipeControlPoint prevPCP) {
+               if (prevPCP == null)
+                       return false;
+               if (prevPCP.isDualInline())
+                       prevPCP = prevPCP.getSubPoint().get(0);
+               if (pcp.getPrevious() != prevPCP) {
+                       pcp.setPrevious(prevPCP);
+               }
+               if (pcp.isDualInline()) {
+                       PipeControlPoint sub = pcp.getSubPoint().get(0);
+                       if (sub.getPrevious() != prevPCP)
+                               sub.setPrevious(prevPCP);
+               }
+               return true;
+       }
+       
+       
+       
+       private boolean syncNext() {
+               
+               if (getControlPoint() != null) {
+                       if (next != null ) {
+                               if (next.getControlPoint() != null && next.getPipeRun() != null) {
+                                       
+                                       // TODO, relying that the other direction is connected.
+                                       boolean nxt = next.getPrevious() == this;
+                                       boolean br0 = next.getBranch0() == this;
+                                       if (nxt){
+                                               return _connectNext(getControlPoint(), next.getControlPoint()); 
+                                       } else if (br0) {
+                                               return _connectNext(getControlPoint(), next.getBranchPoint());
+                                       }
+                               } else {
+                                       return false;
+                               }
+                               
+                       } else if (getControlPoint().getPrevious() != null) {
+                               getControlPoint().setNext(null);
+                       }
+               } else {
+                       return false;
+               }
+               return true;
+       }
+       
+       private boolean syncPrevious() {
+
+               if (getControlPoint() != null) {
+                       if (previous != null ) {
+                               if (previous.getControlPoint() != null && previous.getPipeRun() != null) {
+                                       
+                                       // TODO, relying that the other direction is connected.
+                                       boolean prev = previous.getNext() == this;
+                                       boolean br0 = previous.getBranch0() == this;
+                                       if (prev){
+                                               return _connectPrev(getControlPoint(), previous.getControlPoint());     
+                                       } else if (br0) {
+                                               return _connectPrev(getControlPoint(), previous.getBranchPoint());
+                                       }
+                               } else {
+                                       return false;
+                               }
+                               
+                       } else if (getControlPoint().getPrevious() != null) {
+                               getControlPoint().setPrevious(null);
+                       }
+               } else {
+                       return false;
+               }
+               return true;
+       }
+       
+       private boolean syncBranch0() {
+               if (getControlPoint() != null) {
+                       if (getControlPoint().isDualInline()) {
+                               branch0 = null;
+                               return false;
+                       }
+                       if (branch0 != null) {
+                               if (branch0.getControlPoint() != null  && branch0.getPipeRun() != null) {
+                                       PipeControlPoint branchPoint = getBranchPoint();
+                                       PipeControlPoint pcp = branch0.getControlPoint();
+                                       // TODO, relying that the other direction is connected.
+                                       boolean next = branch0.getPrevious() == this; // this --> branch0
+                                       boolean prev = branch0.getNext() == this;
+                                       if (next) {
+                                               _connectNext(branchPoint, pcp);
+                                       } else if (prev){
+                                               _connectPrev(branchPoint, pcp); 
+                                       }
+                               } else {
+                                       return false;
+                               }
+                               
+                       } else if (getControlPoint().getSubPoint().size() > 0) { // TODO : this may cause problems? (Removes branch point, before branch has been set?)
+                               getControlPoint().getSubPoint().get(0).remove();
+                               getControlPoint().children.clear();
+                       }
+               } else {
+                       return false;
+               }
+               return true;
+       }
+       
+       public void sync() {
+               syncPrevious();
+               syncNext();
+               syncBranch0();
+       }
+       
+       public void sync2() {
+//             if (getControlPoint().isDualInline()) {
+//                     PipeControlPoint sub = getControlPoint().getSubPoint().get(0);
+//                     next.getControlPoint().getPipeRun().addChild(sub);
+//             }
+               getControlPoint()._setWorldOrientation(getWorldOrientation());
+               getControlPoint()._setWorldPosition(getWorldPosition());
+       }
+       
+       public Map<String,Object> updateParameterMap() {
+               return Collections.EMPTY_MAP;
+       }
+       
+       public PipeRun getPipeRun() {
+               return pipeRun;
+       }
+       
+       public abstract String getType();
+       public abstract PipeControlPoint getControlPoint();
+       
+       @Override
+       public void remove() {
+               PipeControlPoint pcp = getControlPoint();
+               if (pcp != null) {
+                       pcp.remove();
+               }
+               super.remove();
+       }
+       
+       @Override
+       protected double[] getColor() {
+               if (getControlPoint() == null || !getControlPoint().isFixed())
+                       return new double[]{0.7,0.7,0.7};
+               else
+                       return new double[]{1.0,0.0,0.0};
+       }
+       
+       @Override
+       protected double[] getSelectedColor() {
+               return new double[]{0.5,0,0.5};
+       }
+       
+       @Override
+       public void setOrientation(Quat4d orientation) {
+               if (MathTools.equals(orientation, getOrientation()))
+                       return;
+               super.setOrientation(orientation);
+               if (getControlPoint() != null) {
+                       getControlPoint()._setWorldOrientation(getWorldOrientation());
+                       try {
+                               PipingRules.requestUpdate(getControlPoint());
+                       } catch (Exception e) {
+                               // TODO Auto-generated catch block
+                               e.printStackTrace();
+                       }       
+               }
+       }
+       
+       @Override
+       public void setPosition(Vector3d position) {
+               if (MathTools.equals(position, getPosition()))
+                       return;
+               super.setPosition(position);
+               if (getControlPoint() != null) {
+                       getControlPoint()._setWorldPosition(getWorldPosition());
+                       try {
+                               PipingRules.requestUpdate(getControlPoint());
+                       } catch (Exception e) {
+                               // TODO Auto-generated catch block
+                               e.printStackTrace();
+                       }
+               }
+       }
+       
+       
+       public void _setWorldPosition(Vector3d position) {
+               Vector3d localPos = getLocalPosition(position);
+               super.setPosition(localPos);
+       }
+       
+       public void _setWorldOrientation(Quat4d orientation) {
+               Quat4d localOr = getLocalOrientation(orientation);
+               super.setOrientation(localOr);
+       }
+       
+       @GetPropertyValue(name="Flow Length", value="flowlength", tabId = "Default")
+       public Double getFlowLength() {
+               PipeControlPoint pcp = getControlPoint(); 
+               if (pcp == null)
+                       return null;
+               switch (pcp.getType()) {
+                       case INLINE:
+                               return pcp.getLength();
+                       case END:
+                               return null;
+                       case TURN: {
+                               double r = getPipeRun().getTurnRadius();
+                               double a = pcp.getTurnAngle();
+                               return a*r;
+                       }
+                        default:
+                                return null;
+               }
+       }
+       
+       public void getControlPointEnds(Tuple3d p1, Tuple3d p2) {
+               getControlPoint().getControlPointEnds(p1, p2);
+       }
+       
+       public Vector3d getNormal() {
+               Vector3d v = new Vector3d();
+               MathTools.rotate(getWorldOrientation(), MathTools.Z_AXIS, v);
+               return v;
+       }
+       
+}
diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/SchemaBuilder.java b/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/SchemaBuilder.java
new file mode 100644 (file)
index 0000000..761e170
--- /dev/null
@@ -0,0 +1,45 @@
+package org.simantics.plant3d.scenegraph;
+
+import org.simantics.Simantics;
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.request.Read;
+import org.simantics.objmap.graph.schema.IMappingSchema;
+import org.simantics.objmap.graph.schema.MappingSchemas;
+import org.simantics.objmap.graph.schema.SimpleSchema;
+import org.simantics.opencascade.SolidModelProvider;
+import org.simantics.plant3d.ontology.Plant3D;
+
+public class SchemaBuilder {
+       public static IMappingSchema<Resource,Object> getSchema() throws DatabaseException{
+               return Simantics.getSession().syncRequest(new Read<IMappingSchema<Resource,Object>>() {
+                       @Override
+                       public IMappingSchema<Resource,Object> perform(ReadGraph g)
+                                       throws DatabaseException {
+                               return getSchema(g);
+                       }
+               });
+       }
+       
+       public static IMappingSchema<Resource,Object> getSchema(ReadGraph g) throws DatabaseException{
+               try {
+                       SimpleSchema schema = new SimpleSchema();
+                       schema.addLinkType(MappingSchemas.fromAnnotations(g, Equipment.class));
+                       schema.addLinkType(MappingSchemas.fromAnnotations(g, InlineComponent.class));
+                       schema.addLinkType(MappingSchemas.fromAnnotations(g, TurnComponent.class));
+                       schema.addLinkType(MappingSchemas.fromAnnotations(g, EndComponent.class));
+                       schema.addLinkType(MappingSchemas.fromAnnotations(g, Nozzle.class));
+                       schema.addLinkType(MappingSchemas.fromAnnotations(g, P3DRootNode.class));
+                       schema.addLinkType(MappingSchemas.fromAnnotations(g, PipeRun.class));
+                       
+                       schema.addLinkType(MappingSchemas.fromAdaptable(g, Plant3D.URIs.Builtin_GeometryProvider, SolidModelProvider.class));
+                       return schema;
+               } catch (IllegalAccessException e) {
+                       throw new DatabaseException(e);
+               } catch (InstantiationException e) {
+                       throw new DatabaseException(e);
+               }
+       }
+       
+}
diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/TurnComponent.java b/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/TurnComponent.java
new file mode 100644 (file)
index 0000000..6050b60
--- /dev/null
@@ -0,0 +1,83 @@
+package org.simantics.plant3d.scenegraph;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.vecmath.Vector3d;
+
+import org.simantics.g3d.math.MathTools;
+import org.simantics.g3d.property.annotations.GetPropertyValue;
+import org.simantics.g3d.scenegraph.base.ParentNode;
+import org.simantics.objmap.graph.annotations.DynamicGraphType;
+import org.simantics.objmap.graph.annotations.GetType;
+import org.simantics.objmap.graph.annotations.SetType;
+import org.simantics.plant3d.ontology.Plant3D;
+import org.simantics.plant3d.scenegraph.controlpoint.ControlPointFactory;
+import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint;
+
+@DynamicGraphType(Plant3D.URIs.TurnComponent)
+public class TurnComponent extends PipelineComponent {
+
+       
+       private String type;
+       private PipeControlPoint controlPoint;
+       
+       @GetType(Plant3D.URIs.TurnComponent)
+       public String getType() {
+               return type;
+       }
+       
+       @SetType(Plant3D.URIs.TurnComponent)
+       public void setType(String type) throws Exception{
+               this.type = type;
+               controlPoint = ControlPointFactory.create(this);
+       }
+       
+       @Override
+       public PipeControlPoint getControlPoint() {
+               return controlPoint;
+       }
+       
+       @Override
+       public void setParent(ParentNode<?> parent, String name) {
+               super.setParent(parent, name);
+               setPipeRun((PipeRun)parent);
+       }
+       
+       @Override
+       public Map<String, Object> updateParameterMap() {
+               Map<String,Object> map = new HashMap<String, Object>();
+               
+               PipeRun pipeRun = getPipeRun();
+               if (pipeRun != null) {
+                       map.put("turnRadius", pipeRun.getTurnRadius());
+                       map.put("radius", pipeRun.getPipeDiameter() * 0.5);
+               }
+               if (controlPoint != null && controlPoint.getTurnAngle() != null  && !Double.isNaN(controlPoint.getTurnAngle())) {
+                       map.put("turnAngle", controlPoint.getTurnAngle());
+               }
+               return map;
+       }
+       
+       
+       public Double getTurnAngle() {
+               return getControlPoint().getTurnAngle();
+       }
+       
+       @GetPropertyValue(name="Turn Angle", value="turn angle", tabId = "Default")
+       public Double getTurnAngleDeg() {
+               Double d = getControlPoint().getTurnAngle();
+               if (d == null)
+                       return null;
+               return MathTools.radToDeg(d);
+       }
+       
+       public Vector3d getTurnAxis() {
+               return getControlPoint().getTurnAxis();
+       }
+       
+       @Override
+       public Vector3d getNormal() {
+               return getTurnAxis();
+       }
+}
diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/controlpoint/ControlPointFactory.java b/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/controlpoint/ControlPointFactory.java
new file mode 100644 (file)
index 0000000..193cdd2
--- /dev/null
@@ -0,0 +1,134 @@
+package org.simantics.plant3d.scenegraph.controlpoint;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.simantics.Simantics;
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.request.Read;
+import org.simantics.plant3d.ontology.Plant3D;
+import org.simantics.plant3d.scenegraph.PipelineComponent;
+import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint.Type;
+import org.simantics.plant3d.utils.Item;
+import org.simantics.plant3d.utils.P3DUtil;
+
+public class ControlPointFactory {
+       
+       private static Map<String,Instruction> cache = new HashMap<String, Instruction>();
+       
+       
+       public static void preloadCache() throws Exception {
+               List<Item> items = P3DUtil.getEnds();
+               items.addAll(P3DUtil.getInlines());
+               items.addAll(P3DUtil.getNozzles());
+               items.addAll(P3DUtil.getTurns());
+               
+               for (Item item : items) {
+                       Instruction inst = createInstruction(item.getUri());
+                       cache.put(item.getUri(), inst);
+               }
+       }
+       
+       public static PipeControlPoint create(PipelineComponent component) throws Exception {
+               Instruction inst = cache.get(component.getType());
+               if (inst == null) {
+                       inst = createInstruction(component.getType());
+                       cache.put(component.getType(), inst);
+               }
+               if (inst == null) {
+                       return null;
+               }
+               
+               PipeControlPoint pcp = new PipeControlPoint(component);
+               pcp.setType(inst.type);
+               pcp.setFixed(inst.fixed);
+               switch(inst.type) {
+               case END:
+                       
+                       break;
+               case INLINE:
+                       if (inst.isOffset || inst.isSizeChange) {
+                               PipeControlPoint sub = new PipeControlPoint(component);
+                               pcp.children.add(sub);
+                               sub.parent = pcp;
+                               sub.setType(inst.type);
+                               sub.setFixed(inst.fixed);
+                               sub.setSub(true);
+//                             pcp.setOffset(0.0);
+                               if (inst.isOffset)
+                                       pcp.setOffset(0.0);
+                       }
+                       
+                       break;
+               case TURN:
+                       
+                       break;
+               }
+               return pcp;
+       }
+       
+       
+       private static class Instruction {
+               Type type;
+               boolean fixed;
+               boolean isOffset;
+               boolean isSizeChange;
+               
+               
+       }
+       
+       private static Instruction createInstruction(final String type) throws Exception {
+               return Simantics.getSession().syncRequest(new Read<Instruction>() {
+                       @Override
+                       public Instruction perform(ReadGraph graph) throws DatabaseException {
+                               Resource res = graph.getResource(type);
+                               Plant3D p3d = Plant3D.getInstance(graph);
+                               Instruction i = new Instruction();
+                               i.fixed = false;
+                               i.isOffset = false;
+                               i.isSizeChange = false;
+                               i.type = Type.INLINE;
+                               if (graph.isInheritedFrom(res, p3d.Nozzle)) {
+                                       i.fixed = true;
+                                       i.isOffset = false;
+                                       i.isSizeChange = false;
+                                       i.type = Type.END;
+                               } else if (graph.isInheritedFrom(res, p3d.InlineComponent)){
+                                       
+                                       i.type = Type.INLINE;
+                                       if (graph.hasStatement(res,p3d.VariableLengthInlineComponent)) {
+                                               i.fixed = false;
+                                       } else if (graph.hasStatement(res,p3d.FixedLengthInlineComponent)) {
+                                               i.fixed = true;
+                                       }
+                                       
+                                       if (graph.hasStatement(res,p3d.SizeChangeComponent)) {
+                                               i.isSizeChange = true;
+                                       }
+                                       
+                                       if (graph.hasStatement(res,p3d.OffsetComponent)) {
+                                               i.isOffset = true;
+                                       }
+                                       
+                               } else if (graph.isInheritedFrom(res, p3d.TurnComponent)) {
+                                       i.type = Type.TURN;
+                                       if (graph.hasStatement(res,p3d.VariableAngleTurnComponent)) {
+                                               i.fixed = false;
+                                       } else if (graph.hasStatement(res,p3d.FixedAngleTurnComponent)) {
+                                               i.fixed = true; 
+                                       }
+                               } else if (graph.isInheritedFrom(res, p3d.EndComponent)) {
+                                       i.fixed = false;
+                                       i.type = Type.END;
+                               } else {
+                                       return null;
+                               }
+                               return i;
+                       }
+               });
+       }
+
+}
diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/controlpoint/PipeControlPoint.java b/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/controlpoint/PipeControlPoint.java
new file mode 100644 (file)
index 0000000..02bce62
--- /dev/null
@@ -0,0 +1,1077 @@
+package org.simantics.plant3d.scenegraph.controlpoint;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import javax.vecmath.AxisAngle4d;
+import javax.vecmath.Matrix3d;
+import javax.vecmath.Quat4d;
+import javax.vecmath.Tuple3d;
+import javax.vecmath.Vector3d;
+
+import org.simantics.g3d.math.MathTools;
+import org.simantics.g3d.property.annotations.GetPropertyValue;
+import org.simantics.g3d.scenegraph.G3DNode;
+import org.simantics.plant3d.scenegraph.IP3DNode;
+import org.simantics.plant3d.scenegraph.PipeRun;
+import org.simantics.plant3d.scenegraph.PipelineComponent;
+
+import vtk.vtkRenderer;
+
+
+public class PipeControlPoint extends G3DNode implements IP3DNode {
+       
+       public enum Type{INLINE,TURN,END};
+       public enum Direction{NEXT,PREVIOUS};
+       public enum PositionType {SPLIT,NEXT,PREVIOUS,PORT}
+       
+       private PipelineComponent component;
+       
+       private Type type;
+       private boolean fixed = true;
+       private boolean deletable = true;
+       private boolean sub = false;
+       
+       public PipeControlPoint(PipelineComponent component) {
+               this.component = component;
+               if (component.getPipeRun() != null)
+                       component.getPipeRun().addChild(this);
+               
+       }
+       
+       public PipeControlPoint(PipelineComponent component, PipeRun piperun) {
+               this.component = component;
+               piperun.addChild(this);
+       }
+       
+       @Override
+       public void update(vtkRenderer ren) {
+               try {
+                       PipingRules.requestUpdate(this);
+               } catch (Exception e) {
+                       e.printStackTrace();
+               }
+               
+       }
+       
+       public PipeRun getPipeRun() {
+               return (PipeRun)getParent();
+       }
+       
+       public PipelineComponent getPipelineComponent() {
+               return component;
+       }
+       
+       public Type getType() {
+               return type;
+       }
+       
+       public void setType(Type type) {
+               this.type = type;
+       }
+       
+       @GetPropertyValue(name="Fixed",tabId="Debug",value="fixed")
+       public boolean isFixed() {
+               return fixed;
+       }
+       
+       
+       public void setFixed(boolean fixed) {
+               this.fixed = fixed;
+       }
+       
+       public void setSub(boolean sub) {
+               this.sub = sub;
+       }
+               
+       @GetPropertyValue(name="Deletable",tabId="Debug",value="deletable")
+       public boolean isDeletable() {
+               return deletable;
+       }
+       
+       public void setDeletable(boolean deletable) {
+               this.deletable = deletable;
+       }
+       
+       public boolean isPathLegEnd() {
+               return type != Type.INLINE;
+       }
+       
+       public boolean isEnd() {
+               return type == Type.END;
+       }
+       
+       public boolean isTurn() {
+               return type == Type.TURN;
+       }
+       
+       public boolean isInline() {
+               return type == Type.INLINE;
+       }
+       
+       public boolean isDirected() {
+               return fixed && isEnd();
+       }
+       
+       public boolean isNonDirected() {
+               return !fixed && isEnd();
+       }
+       
+       public boolean isVariableLength() {
+               return !fixed && isInline();
+       }
+       
+       public boolean isVariableAngle() {
+               return !fixed && isTurn();
+       }
+       
+       public boolean isBranchEnd() {
+               return deletable && isEnd();
+       }
+       
+       public boolean isOffset() {
+               return offset != null;
+       }
+       
+       public boolean isDualSub() {
+               return parent != null && sub;
+       }
+       
+       public boolean isDualInline() {
+               return children.size() == 1 && children.get(0).isDualSub();
+       }
+       
+       public boolean isSizeChange() {
+               if (children.size() == 0)
+                       return false;
+               if (!isDualInline())
+                       return false;
+               return getPipeRun() != children.get(0).getPipeRun();
+       }
+
+       
+       private PipeControlPoint next;
+       private PipeControlPoint previous;
+       
+       public PipeControlPoint getNext() {
+               return next;
+       }
+       
+       public PipeControlPoint getPrevious() {
+               return previous;
+       }
+       
+       public void setNext(PipeControlPoint next) {
+               if (isEnd() && previous != null && next != null)
+                       throw new RuntimeException("End control points are allowed to have only one connection");
+//             if (next != null && getPipeRun() == null)
+//                     throw new RuntimeException("Cannot connect control point befor piperun has been set");
+               this.next = next;
+               if (component != null) {
+                       if (parent == null || sub)
+                               component.setNext(next != null ? next.component : null);
+                       else
+                               component.setBranch0(next != null ? next.component : null);
+               }
+       }
+       
+       public void setPrevious(PipeControlPoint previous) {
+               if (isEnd() && next != null && previous != null)
+                       throw new RuntimeException("End control points are allowed to have only one connection");
+//             if (previous != null && getPipeRun() == null)
+//                     throw new RuntimeException("Cannot connect control point befor piperun has been set");
+               this.previous = previous;
+               if (component != null)
+                       if (parent == null || sub)
+                               component.setPrevious(previous != null ? previous.component : null);
+                       else
+                               component.setBranch0(previous != null ? previous.component : null);
+       }
+       
+       public PipeControlPoint parent;
+       public List<PipeControlPoint> children = new ArrayList<PipeControlPoint>();
+       
+       public List<PipeControlPoint> getSubPoint() {
+               return children;
+       }
+       
+       public PipeControlPoint getParentPoint() {
+               return parent;
+       }
+       
+       
+       
+
+       
+       
+       
+       
+       private double length;
+       private Double turnAngle;
+       private Vector3d turnAxis;
+
+       private Double offset;
+       private Double rotationAngle;
+       
+       @GetPropertyValue(name="Length",tabId="Debug",value="length")
+       public double getLength() {
+               return length;
+       }
+       
+       public void setLength(double l) {
+               if (Double.isInfinite(l) || Double.isNaN(l)) {
+                       return;
+               }
+               if (Math.abs(this.length-l) < MathTools.NEAR_ZERO)
+                       return;
+               this.length = l;
+               firePropertyChanged("length");
+               if (isDualInline())
+                       getSubPoint().get(0).setLength(l);
+       }
+       
+       @GetPropertyValue(name="Turn Angle",tabId="Debug",value="turnAngle")
+       public Double getTurnAngle() {
+               return turnAngle;
+       }
+       
+       @GetPropertyValue(name="Turn Axis",tabId="Debug",value="turnAxis")
+       public Vector3d getTurnAxis() {
+               return turnAxis;
+       }
+       
+       @GetPropertyValue(name="Offset",tabId="Debug",value="offset")
+       public Double getOffset() {
+               return offset;
+       }
+       
+       @GetPropertyValue(name="Rotation Angle",tabId="Debug",value="rotationAngle")
+       public Double getRotationAngle() {
+               return rotationAngle;
+       }
+       
+       public void setTurnAngle(Double turnAngle) {
+               if (Double.isInfinite(turnAngle) || Double.isNaN(turnAngle)) {
+                       return;
+               }
+               if (this.turnAngle != null && Math.abs(this.turnAngle-turnAngle) < MathTools.NEAR_ZERO)
+                       return;
+               this.turnAngle = turnAngle;
+               firePropertyChanged("turnAngle");
+       }
+       
+       public void setTurnAxis(Vector3d turnAxis) {
+               this.turnAxis = turnAxis;
+               firePropertyChanged("turnAxis");
+       }
+       
+       public void setOffset(Double offset) {
+               if (Double.isInfinite(offset) || Double.isNaN(offset)) {
+                       return;
+               }
+               if (this.offset != null && Math.abs(this.offset-offset) < MathTools.NEAR_ZERO)
+                       return;
+               this.offset = offset;
+               firePropertyChanged("offset");
+       }
+       
+       public void setRotationAngle(Double rotationAngle) {
+               if (Double.isInfinite(rotationAngle) || Double.isNaN(rotationAngle)) {
+                       return;
+               }
+               if (this.rotationAngle != null && Math.abs(this.rotationAngle-rotationAngle) < MathTools.NEAR_ZERO)
+                       return;
+               this.rotationAngle = rotationAngle;
+               firePropertyChanged("rotationAngle");
+       }
+       
+       public Vector3d getSizeChangeOffsetVector(Vector3d dir) {
+               if (rotationAngle == null)
+                       rotationAngle = 0.0;
+               Quat4d q = getControlPointOrientationQuat(dir, rotationAngle);
+               Vector3d v = new Vector3d(0.0,0.0,offset);
+       Vector3d offset = new Vector3d();
+       MathTools.rotate(q, v, offset);
+       return offset;
+       }
+       
+       @GetPropertyValue(name="Next",tabId="Debug",value="next")
+       private String getNextString() {
+               if (next == null)
+                       return null;
+               return next.toString();
+       }
+       
+       @GetPropertyValue(name="Previous",tabId="Debug",value="previous")
+       private String getPrevString() {
+               if (previous == null)
+                       return null;
+               return previous.toString();
+       }
+       
+        public Quat4d getControlPointOrientationQuat(double angle) {
+                
+                if (turnAxis == null) {
+                        Vector3d dir = getPathLegDirection(Direction.NEXT);
+                        if (dir.lengthSquared() > MathTools.NEAR_ZERO)
+                                dir.normalize();
+                        return getControlPointOrientationQuat(dir, angle);
+                } else {
+                        Vector3d dir = getPathLegDirection(Direction.PREVIOUS);
+                        dir.negate();
+                        if (dir.lengthSquared() > MathTools.NEAR_ZERO)
+                                dir.normalize();
+                        return getControlPointOrientationQuat(dir, turnAxis, angle);
+                }
+        }
+        
+       
+       
+        public static Quat4d getControlPointOrientationQuat(Vector3d dir, double angle) {
+                       if (dir.lengthSquared() < MathTools.NEAR_ZERO)
+                               return MathTools.getIdentityQuat();
+               
+               
+                       Vector3d up = new Vector3d(0.0, 1.0, 0.0);
+                       double a = up.angle(dir);
+                       if (a < 0.1 || (Math.PI - a) < 0.1) {
+                               up.set(1.0, 0.0, 0.0);
+                       }
+                       
+
+                       return getControlPointOrientationQuat(dir, up, angle);
+           }
+        
+        public static Quat4d getControlPointOrientationQuat(Vector3d dir, Vector3d up,  double angle) {
+                       if (dir.lengthSquared() < MathTools.NEAR_ZERO)
+                               return MathTools.getIdentityQuat();
+               
+               final Vector3d front = new Vector3d(1.0,0.0,0.0);
+               
+               Quat4d q1 = new Quat4d();
+
+
+                       Vector3d right = new Vector3d();
+
+                       right.cross(dir, up);
+                       up.cross(right, dir);
+                       right.normalize();
+                       up.normalize();
+
+                       Matrix3d m = new Matrix3d();
+                       m.m00 = dir.x;
+                       m.m10 = dir.y;
+                       m.m20 = dir.z;
+                       m.m01 = up.x;
+                       m.m11 = up.y;
+                       m.m21 = up.z;
+                       m.m02 = right.x;
+                       m.m12 = right.y;
+                       m.m22 = right.z;
+
+                       //q1.set(m); MathTools contains more stable conversion
+                       MathTools.getQuat(m, q1);
+
+//                     if (DEBUG) System.out.println("PipingTools.getPipeComponentOrientationQuat() " + dir+ " " + up + " " + right);
+
+                       Quat4d q2 = new Quat4d();
+                       q2.set(new AxisAngle4d(front, angle));
+                       q1.mul(q2);
+                       return q1;
+           }
+       
+       public Vector3d getDirection() {
+               return getDirectedControlPointDirection();
+       }
+       
+       
+       
+       
+       
+
+       
+       public void insert(PipeControlPoint previous, PipeControlPoint next) {
+               // inserting an offsetpoint is error, 
+               if (isDualSub())
+                       throw new RuntimeException();
+               // size change control point cannot be inserted this way, because it ends PipeRun
+               if (isSizeChange())
+                       throw new RuntimeException();
+               PipeRun piperun = previous.getPipeRun();
+               // and just to make sure that control point structure is not corrupted
+               if (getPipeRun() != null) {
+                       if (piperun != getPipeRun() || piperun != next.getPipeRun())
+                               throw new RuntimeException();
+               } else {
+                       piperun.addChild(this);
+               }
+               
+               // insert new BranchControlPoint between straight's control points
+               PipeControlPoint previousNext = previous.getNext();
+               PipeControlPoint previousPrevious = previous.getPrevious();
+               
+               PipeControlPoint offsetCP = null;
+               if (isOffset()) {
+                       offsetCP = getSubPoint().get(0);
+               }
+               if (previousNext != null && previousNext == next) {
+                       if (previous.isDualInline()) {
+                               throw new RuntimeException();
+                       }
+                       if (next.isDualSub()) {
+                               throw new RuntimeException();
+                       }
+                       previous.setNext(this);
+                       this.setPrevious(previous);
+                       if (previous.isDualSub()) {
+                               previous.getParentPoint().setNext(this);
+                       }
+                       this.setNext(next);
+                       
+                       if (offsetCP == null) {
+                               next.setPrevious(this);
+                       } else {
+                               next.setPrevious(offsetCP);
+                               offsetCP.setNext(next);
+                               offsetCP.setPrevious(previous);
+                       }
+                       
+                       if (next.isDualInline()) {
+                               next.getSubPoint().get(0).setPrevious(this);
+                       }
+               } else if (previousPrevious != null && previousPrevious == next) {
+                        // control point were given in reverse order 
+                       if (next.isDualInline())
+                               throw new RuntimeException();
+                       if (previous.isDualSub())
+                               throw new RuntimeException();
+                       
+                       this.setNext(previous);
+                       if (offsetCP == null) {
+                               previous.setNext(this);
+                       } else {
+                               previous.setPrevious(offsetCP);
+                               offsetCP.setNext(previous);
+                               offsetCP.setPrevious(next);
+                       }
+                       if (previous.isDualInline()) {
+                               previous.getSubPoint().get(0).setPrevious(this);
+                       }
+                       this.setPrevious(next);
+                       next.setNext(this);
+                       if (next.isDualSub()) {
+                               next.getParentPoint().setNext(this);
+                       }
+                       
+               } else {
+                       throw new RuntimeException();
+               }       
+               
+               PipingRules.validate(piperun);
+       }
+       
+       
+       
+       public void insert(PipeControlPoint pcp, Direction direction) {
+               if (isDualSub())
+                       throw new RuntimeException();
+               if (direction == Direction.NEXT) {
+                       // if direction is next, user must have given OffsetPoint
+                       if (pcp.isDualInline())
+                               throw new RuntimeException();
+                       // basic next/prev links
+                       pcp.setNext(this);
+                       this.setPrevious(pcp);
+                       // and last take care of sizechange / offset points
+                       if (pcp.isDualSub()) {
+                               pcp.getParentPoint().setNext(this);
+                       }
+                       if (isDualInline()) {
+                               getSubPoint().get(0).setPrevious(this);
+                       }
+               } else {
+                       // if direction is previous, user must have given sizechange
+                       if (pcp.isDualSub())
+                               throw new RuntimeException();
+                       // previous direction is more complicated, since if newCP is SizeChangeControlPoint,
+                       // we must link pcp to newCP's OffsetPoint
+                       PipeControlPoint nocp = null;
+                       if (isDualInline()) {
+                               nocp = getSubPoint().get(0);
+                               nocp.setNext(pcp);
+                       }
+                       if (nocp == null) {
+                               pcp.setPrevious(this);
+                       } else {
+                               pcp.setPrevious(nocp);
+                       }
+                       this.setNext(pcp);
+                       if (pcp.isDualInline()) {
+                               PipeControlPoint ocp = pcp.getSubPoint().get(0);
+                               if (nocp == null)
+                                       ocp.setPrevious(this);
+                               else
+                                       ocp.setPrevious(nocp);
+                       }
+                       
+               }
+               PipingRules.validate(getPipeRun());
+       }
+       
+       public Vector3d getDirectedControlPointDirection() {
+               assert (isDirected());
+               Vector3d dir = new Vector3d();
+               MathTools.rotate(getWorldOrientation(), new Vector3d(1.0, 0.0, 0.0), dir);
+               dir.normalize();
+               return dir;
+       }
+       
+       public Vector3d getPathLegDirection(Direction direction) {
+               if (direction == Direction.NEXT) {
+                       if (next != null) {
+                               PipeControlPoint pcp = this;
+                               if (pcp.isDualInline()) {
+                                       pcp = pcp.getSubPoint().get(0);
+                               }
+                               Vector3d v = new Vector3d();
+                               v.sub(next.getWorldPosition(),pcp.getWorldPosition());
+                               return v;
+                       } else {
+                               if (isVariableAngle())
+                                       throw new RuntimeException("Cannot calculate path leg direction for unconnected variable angle control point");
+                               if (previous == null) {
+                                       if (!isDirected())
+                                               throw new RuntimeException("Cannot calculate path leg direction for unconnected control point");
+                                       return getDirectedControlPointDirection();
+                                       
+                               } else {
+                                       if (isInline()) {
+                                               Vector3d v = new Vector3d();
+                                               v.sub(getWorldPosition(),previous.getWorldPosition());
+                                               return v;
+                                       } else if (isDirected()) {
+                                               return getDirectedControlPointDirection();
+                                       } else if (isEnd()) {
+                                               Vector3d v = new Vector3d();
+                                               v.sub(getWorldPosition(),previous.getWorldPosition());
+                                               return v;
+                                       }
+                                       throw new RuntimeException("Missing implementation");
+                               }
+                       }
+               } else {
+                       if (previous != null) {
+                               PipeControlPoint pcp = this;
+                               if (isDualSub()) 
+                                       pcp = getParentPoint();
+                               Vector3d v = new Vector3d();
+                               v.sub(previous.getWorldPosition(),pcp.getWorldPosition());
+                               return v;
+                       } else {
+                               if (isVariableAngle())
+                                       throw new RuntimeException("Cannot calculate path leg direction for unconnected variable angle control point");
+                               if (next == null)  {
+                                       if (!isDirected())
+                                               throw new RuntimeException("Cannot calculate path leg direction for unconnected control point");
+                                       Vector3d v = getDirectedControlPointDirection();
+                                       v.negate();
+                                       return v;
+                               } else {
+                                       if (isInline()) {
+                                               Vector3d v = new Vector3d();
+                                               v.sub(getWorldPosition(),next.getWorldPosition());
+                                               return v;
+                                       } else if (isDirected()) {
+                                               Vector3d v = getDirectedControlPointDirection();
+                                               v.negate();
+                                               return v;
+                                       } else if (isEnd()) {
+                                               Vector3d v = new Vector3d();
+                                               v.sub(getWorldPosition(),next.getWorldPosition());
+                                               return v;
+                                       }
+                                       throw new RuntimeException("Missing implementation");
+                               }
+                       }
+               }
+       }
+       
+       public void getInlineControlPointEnds(Tuple3d p1, Tuple3d p2) {
+               assert (isInline());
+               
+               Vector3d pos = getWorldPosition();
+               Vector3d dir = getPathLegDirection(Direction.NEXT);
+               dir.normalize();
+               dir.scale(length * 0.5);
+               p1.set(pos);
+               p2.set(pos);
+               p1.sub(dir);
+               p2.add(dir);
+       }
+       
+       public void getControlPointEnds(Tuple3d p1, Tuple3d p2) {
+               Vector3d pos = getWorldPosition();
+               Vector3d dir1 = getPathLegDirection(Direction.PREVIOUS);
+               dir1.normalize();
+               Vector3d dir2 = getPathLegDirection(Direction.NEXT);
+               dir2.normalize();
+               if (isInline()) {
+                       dir1.scale(length * 0.5);
+                       dir2.scale(length * 0.5);
+               } else {
+                       dir1.scale(length);
+                       dir2.scale(length);
+               }
+               p1.set(pos);
+               p2.set(pos);
+               p1.add(dir1);
+               p2.add(dir2);
+       }
+       
+       public void getInlineControlPointEnds(Tuple3d p1, Tuple3d p2, Vector3d dir) {
+               assert (isInline());
+               
+               Vector3d pos = getWorldPosition();
+               dir.set(getPathLegDirection(Direction.NEXT));
+               dir.normalize();
+               dir.scale(length * 0.5);
+               p1.set(pos);
+               p2.set(pos);
+               p1.sub(dir);
+               p2.add(dir);
+       }
+       
+       public void getInlineControlPointEnds(Tuple3d center, Tuple3d p1, Tuple3d p2, Vector3d dir) {
+               assert (isInline());
+               
+               Vector3d pos = getWorldPosition();
+               center.set(pos);
+               dir.set(getPathLegDirection(Direction.NEXT));
+               dir.normalize();
+               dir.scale(length * 0.5);
+               p1.set(pos);
+               p2.set(pos);
+               p1.sub(dir);
+               p2.add(dir);
+       }
+       
+       public double getInlineLength() {
+               if (type == Type.TURN)
+                       return length;
+               else if (type == Type.INLINE)
+                       return length * 0.5;
+               return 0;
+       }
+       
+       public Vector3d getRealPosition(PositionType type) {
+               Vector3d pos = getWorldPosition();
+               switch (type) {
+               case NEXT: {
+                       Vector3d dir = getPathLegDirection(Direction.NEXT);
+                       double length = getInlineLength();
+                       dir.normalize();
+                       dir.scale(length);
+                       pos.add(dir);
+                       break;
+               }
+               case PREVIOUS: {
+                       Vector3d dir = getPathLegDirection(Direction.PREVIOUS);
+                       double length = getInlineLength();
+                       dir.normalize();
+                       dir.scale(length);
+                       pos.add(dir);
+                       break;
+               }
+               case PORT:
+                       // IEntity portDir = pcp.getSingleRelatedObject(ProcessResource.plant3Dresource.HasDirection);
+                       // TODO : how we calculated needed space for a port; does it has an offset from control point's position or not?
+                       break;
+               case SPLIT:
+                       // do nothing
+                       break;
+                       
+               }
+               return pos;
+       }
+       
+       public void getInlineMovement(Tuple3d start, Tuple3d end) {
+               // FIXME : check type of neighbor components and allow movement on top of variable length components,
+               //         find proper range for movement (pcp's position is not)
+               PipeControlPoint p = previous.getPrevious();
+               PipeControlPoint n = next.getNext();
+               start.set(p.getWorldPosition());
+               end.set(n.getWorldPosition());
+       }
+       
+       public PipeControlPoint findNextEnd() {
+               ArrayList<PipeControlPoint> t = new ArrayList<PipeControlPoint>();
+        return findNextEnd( t);
+       }
+       
+       public PipeControlPoint findPreviousEnd() {
+               ArrayList<PipeControlPoint> t = new ArrayList<PipeControlPoint>();
+        return findPreviousEnd(t);
+       }
+       
+       public PipeControlPoint findNextEnd(List<PipeControlPoint> nextList) {
+                while (true) {
+            PipeControlPoint pcp = null;
+            PipeControlPoint p = null;
+            if (nextList.size() == 0)
+                p = this;
+                
+            else
+                p = nextList.get(nextList.size() - 1);
+
+            pcp = p.getNext();
+            if (pcp == null) {
+               pcp = p;
+               if (nextList.size() > 0)
+                       nextList.remove(nextList.size() - 1);
+//             if (DEBUG) System.out.println(" " + pcp.getResource() + " not full");
+               return pcp;
+               //break;
+            }
+            if (pcp.isPathLegEnd()) {
+               //if (DEBUG) System.out.println(" " + pcp.getResource());
+                return pcp;
+            } else {
+                nextList.add(pcp);
+               // if (DEBUG) System.out.print(" " + pcp.getResource());
+            }
+        }
+       }
+       
+       public PipeControlPoint findPreviousEnd(List<PipeControlPoint> prevList) {
+               while (true) {
+                       PipeControlPoint pcp = null;
+                       PipeControlPoint p = null;
+                       if (prevList.size() == 0)
+                               p = this;
+
+                       else
+                               p = prevList.get(prevList.size() - 1);
+
+                       pcp = p.getPrevious();
+                       if (pcp == null) {
+                               pcp = p;
+                               if (prevList.size() > 0)
+                                       prevList.remove(prevList.size() - 1);
+//                             if (DEBUG) System.out.println(" " + pcp.getResource() + " not full");
+                               return pcp;
+                       }
+                       if (pcp.isPathLegEnd()) {
+//                             if (DEBUG)      System.out.println(" " + pcp.getResource());
+                               return pcp;
+                       } else {
+                               prevList.add(pcp);
+//                             if (DEBUG)System.out.print(" " + pcp.getResource());
+                       }
+               }
+       }
+       
+       public void _remove() {
+               if (component == null && next == null && previous == null)
+                       return;
+               if (isDualInline() || isDualSub()) {
+                       removeDualPoint();
+                       return;
+               }
+               PipeRun pipeRun = getPipeRun();
+               if (pipeRun == null)
+                       return;
+               
+               PipeControlPoint additionalRemove = null;
+               if (!PipingRules.isEnabled()) {
+                       setPrevious(null);
+                       setNext(null);
+               } else {
+
+                       PipeControlPoint currentPrev = previous;
+                       PipeControlPoint currentNext = next;
+                       if (currentNext == null && currentPrev == null) {
+                               removeComponent();
+                               pipeRun.remChild(this);
+                               return;
+                       }
+                       if (currentNext != null && currentPrev != null) {
+                               boolean link = true;
+                               if (currentNext.isBranchEnd()) {
+                                       link = false;
+//                                     currentNext.setPrevious(null);
+//                                     currentNext.setNext(null);
+                                       currentNext.remove();
+                                       currentNext = null;
+                                       setNext(null);
+                               }
+                               if (currentPrev.isBranchEnd()) {
+                                       link = false;
+//                                     currentPrev.setPrevious(null);
+//                                     currentPrev.setNext(null);
+                                       currentPrev.remove();
+                                       currentPrev = null;
+                                       setPrevious(null);
+                               }
+                               if (link && currentPrev.isDirected() && currentNext.isDirected()) {
+                                       link = false;
+                               }
+                               if (currentNext == null) {
+                                       // Nothing to do
+                               } else if (currentNext.isDualInline()) {
+                                       PipeControlPoint sccp = currentNext;
+                                       PipeControlPoint ocp = sccp.getSubPoint().get(0);
+                                       if (ocp == null) {
+                                               throw new RuntimeException("Removing PipeControlPoint " + this+ " structure damaged, no offset control point");
+                                       }
+                                       if (link) {
+                                               sccp.setPrevious(currentPrev);
+                                               ocp.setPrevious(currentPrev);
+                                       } else {
+                                               sccp.setPrevious(null);
+                                               ocp.setPrevious(null);
+                                       }
+                                       setNext(null);
+                               } else if (currentNext.isDualSub()) {
+                                       throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged, next control point is offset control point");
+                               } else if (currentNext.previous == this) {
+                                       if (link) {
+                                               currentNext.setPrevious(currentPrev);
+                                       } else {
+                                               currentNext.setPrevious(null);
+                                       }
+                                       setNext(null);
+                               } else {
+                                       throw new RuntimeException("Removing PipeControlPoint "+ this+ " structure damaged");
+                               }
+                               if (currentPrev == null) {
+                                       // Nothing to do
+                               } else if (currentPrev.isDualInline()) {
+                                       throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged, previous control point is size change control point");
+                               } else if (currentPrev.isDualSub()) {
+                                       PipeControlPoint ocp = currentPrev;
+                                       PipeControlPoint sccp = ocp.getParentPoint();
+                                       if (sccp == null)
+                                               throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged, no size change control point");
+                                       if (link) {
+                                               ocp.setNext(currentNext);
+                                               sccp.setNext(currentNext);
+                                       } else {
+                                               ocp.setNext(null);
+                                               sccp.setNext(null);
+                                       }
+                                       setPrevious(null);
+                               } else if (currentPrev.next == this) {
+                                       if (link)
+                                               currentPrev.setNext(currentNext);
+                                       else
+                                               currentPrev.setNext(null);
+                                       
+                                       setPrevious(null);
+                               } else {
+                                       throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged");
+                               }
+                               if (link) {
+                                       if (currentNext.isVariableLength() && currentPrev.isVariableLength()) {
+                                               // we have to join them into single variable length component.
+                                               additionalRemove = currentPrev;
+                                               //currentPrev.remove();
+                                       }
+                               } else {
+                                       // FIXME : pipe run must be split into two parts, since the control point structure is no more continuous. 
+                               }
+                       } else if (next != null) {
+                               if (next.isDualInline()) {
+                                       PipeControlPoint sccp = next;
+                                       PipeControlPoint ocp = sccp.getSubPoint().get(0);
+                                       if (ocp == null) {
+                                               throw new RuntimeException("Removing PipeControlPoint " + this+ " structure damaged, no offset control point");
+                                       }
+                                       sccp.setPrevious(null);
+                                       ocp.setPrevious(null);
+                               } else if (next.isDualSub()) {
+                                       throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged, next control point is offset control point");
+                               } else if (next.previous == this) {
+                                       next.setPrevious(null);
+                               } else {
+                                       throw new RuntimeException("Removing PipeControlPoint "+ this+ " structure damaged");
+                               }
+                               setNext(null);
+                       } else {  //(previous != null)
+                               if(previous.isDualInline()) {
+                                       throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged, previous control point is size change control point");
+                               } else if (previous.isDualSub()) {
+                                       PipeControlPoint ocp = previous;
+                                       PipeControlPoint sccp = ocp.getParentPoint();
+                                       if (sccp == null) {
+                                               throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged, no size change control point");
+                                       }
+                                       ocp.setNext(null);
+                                       sccp.setNext(null);
+                               } else if (previous.next == this) {
+                                       previous.setNext(null);
+                               } else {
+                                       throw new RuntimeException("Removing PipeControlPoint "+ this+ " structure damaged");
+                               }
+                               setPrevious(null);
+                       }
+                       if (children.size() > 0 ) {
+                               removeSubPoints();
+                       } else if (parent!= null) {
+                               removeParentPoint();
+                       }
+                       
+               }
+               
+               removeComponent();
+               pipeRun.remChild(this);
+               checkRemove(pipeRun);
+               if (PipingRules.isEnabled() && pipeRun.getParent() != null && pipeRun.getControlPoints().size() > 0)
+                       PipingRules.validate(pipeRun);
+               if (additionalRemove != null)
+                       additionalRemove.remove();
+       }
+       
+       public void remove() {
+               PipeControlPoint currentPrev = previous;
+               PipeControlPoint currentNext = next;
+               _remove();
+               try {
+                       if (currentNext != null)
+                               PipingRules.requestUpdate(currentNext);
+                       if (currentPrev != null)
+                               PipingRules.requestUpdate(currentPrev);
+               } catch (Exception e) {
+                       e.printStackTrace();
+               }
+       }
+       
+       private void checkRemove(PipeRun pipeRun) {
+               Collection<PipeControlPoint> points = pipeRun.getControlPoints();
+               if (points.size() == 0) {
+                       pipeRun.remove();
+               } else if (points.size() == 1) {
+                       PipeControlPoint pcp = points.iterator().next();
+                       if (pcp.isDeletable())
+                               pcp._remove();
+               }
+       }
+       
+       private void removeDualPoint() {
+               if (previous != null)
+                       previous.setNext(null);
+               if (next != null)
+                       next.setPrevious(null);
+               PipeControlPoint ocp;
+               PipeControlPoint sccp;
+               if (isDualInline()) {
+                       sccp = this;
+                       ocp = getSubPoint().get(0);
+               } else {
+                       ocp = this;
+                       sccp = getParentPoint();
+               }
+               PipeRun p1 = ocp.getPipeRun();
+               PipeRun p2 = sccp.getPipeRun();
+               
+               ocp.removeComponent();
+               sccp.removeComponent();
+               
+               p1.remChild(ocp);
+               p2.remChild(sccp);
+               
+               ocp.setNext(null);
+               ocp.setPrevious(null);
+               sccp.setNext(null);
+               sccp.setPrevious(null);
+               
+               checkRemove(p1);
+               checkRemove(p2);
+       }
+       
+       private void removeSubPoints() {
+               for (PipeControlPoint p : children) {
+                       // TODO : this may affect delete routine, since classification of the point changes.
+                       p.parent = null;
+                       p._remove();
+               }
+               children.clear();
+       }
+       
+       private void removeParentPoint() {
+               throw new RuntimeException("Child points cannot be removed directly");
+       }
+       
+       private void removeComponent() {
+               if (component == null)
+                       return;
+               PipelineComponent next = component.getNext();
+               PipelineComponent prev = component.getNext();
+               if (next != null) {
+                       if (next.getNext() == component)
+                               next.setNext(null);
+                       else if (next.getPrevious() == component)
+                               next.setPrevious(null);
+               }
+               if (prev != null) {
+                       if (prev.getNext() == component)
+                               prev.setNext(null);
+                       else if (prev.getPrevious() == component)
+                               prev.setPrevious(null);
+               }
+               PipelineComponent comp = component;
+               component = null;
+               comp.remove();
+       }
+       
+       @Override
+       public void setOrientation(Quat4d orientation) {
+               if (MathTools.equals(orientation, getOrientation()))
+                       return;
+               super.setOrientation(orientation);
+               if (getParentPoint() == null && component != null)
+                       component._setWorldOrientation(getWorldOrientation());
+               for (PipeControlPoint sub : getSubPoint()) {
+                       sub.setWorldPosition(getWorldPosition());
+                       sub.setWorldOrientation(getWorldOrientation());
+               }
+       }
+       
+       @Override
+       public void setPosition(Vector3d position) {
+               if (MathTools.equals(position, getPosition()))
+                       return;
+               super.setPosition(position);
+               if (getParentPoint() == null && component != null)
+                       component._setWorldPosition(getWorldPosition());
+               for (PipeControlPoint sub : getSubPoint()) {
+                       sub.setWorldPosition(getWorldPosition());
+                       sub.setWorldOrientation(getWorldOrientation());
+               }
+       }
+
+       
+       public void _setWorldPosition(Vector3d position) {
+               Vector3d localPos = getLocalPosition(position);
+               super.setPosition(localPos);
+               for (PipeControlPoint sub : getSubPoint()) {
+                       sub.setWorldPosition(getWorldPosition());
+                       sub.setWorldOrientation(getWorldOrientation());
+               }
+       }
+       
+       public void _setWorldOrientation(Quat4d orientation) {
+               Quat4d localOr = getLocalOrientation(orientation);
+               super.setOrientation(localOr);
+               for (PipeControlPoint sub : getSubPoint()) {
+                       sub.setWorldPosition(getWorldPosition());
+                       sub.setWorldOrientation(getWorldOrientation());
+               }
+       }
+       
+       @Override
+       public String toString() {
+               return getClass().getName() + "@" + Integer.toHexString(hashCode());
+       }
+
+}
diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/controlpoint/PipingRules.java b/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/controlpoint/PipingRules.java
new file mode 100644 (file)
index 0000000..d7c53d4
--- /dev/null
@@ -0,0 +1,1651 @@
+package org.simantics.plant3d.scenegraph.controlpoint;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.vecmath.Point3d;
+import javax.vecmath.Quat4d;
+import javax.vecmath.Vector3d;
+
+import org.simantics.g3d.math.MathTools;
+import org.simantics.plant3d.scenegraph.InlineComponent;
+import org.simantics.plant3d.scenegraph.Nozzle;
+import org.simantics.plant3d.scenegraph.P3DRootNode;
+import org.simantics.plant3d.scenegraph.PipeRun;
+import org.simantics.plant3d.scenegraph.PipelineComponent;
+import org.simantics.plant3d.scenegraph.TurnComponent;
+import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint.Direction;
+import org.simantics.plant3d.utils.ComponentUtils;
+import org.simantics.utils.ui.ErrorLogger;
+
+public class PipingRules {
+       private static final boolean DEBUG = false;
+       private static final boolean DUMMY = false;
+
+       private static final double MIN_TURN_ANGLE = 0.01;
+
+       private static final int REMOVE_NONE = 0;
+       private static final int REMOVE_START = 1;
+       private static final int REMOVE_END = 2;
+       private static final int REMOVE_BOTH = 3;
+       
+//     private P3DRootNode root;
+       
+//     public PipingRules(P3DRootNode root) {
+//             this.root = root;
+//     }
+
+       private enum PathLegUpdateType {
+               NONE, PREV, NEXT, PREV_S, NEXT_S
+       };
+       
+       private static boolean enabled = true;
+       private static boolean updating = false;
+       private static boolean allowInsertRemove = true;
+       private static boolean triedIR = false;
+
+       
+       private static List<PipeControlPoint> updates = new ArrayList<PipeControlPoint>();
+       
+       private static Object mutex = new Object();
+       
+       public static void requestUpdate(PipeControlPoint pcp) {
+               if (DEBUG) System.out.println("PipingRules request " + pcp);
+               synchronized (mutex) {
+               if (!updates.contains(pcp))
+                       updates.add(pcp);
+               }
+       }
+       
+       public static synchronized boolean update() throws Exception {
+               if (updates.size() == 0)
+                       return false;
+               List<PipeControlPoint> temp = new ArrayList<PipeControlPoint>(updates.size());
+               synchronized(mutex) {
+                       temp.addAll(updates);
+                       updates.clear();
+               }
+               
+               for (PipeControlPoint pcp : temp)
+                       positionUpdate(pcp);
+               return true;
+       }
+       
+       public static boolean positionUpdate(PipeControlPoint pcp) throws Exception {
+               
+               return positionUpdate(pcp, true);
+       }
+       
+       public static boolean positionUpdate(PipeControlPoint pcp, boolean allowIR) throws Exception {
+               if (updating || !enabled)
+                       return true;
+               if (pcp.getPipeRun() == null)
+                       return false;
+               try {
+                       if (DEBUG) System.out.println("PipingRules " + pcp);
+                       updating = true;
+                       allowInsertRemove = allowIR;
+                       triedIR = false;
+                       validate(pcp.getPipeRun());
+                       if (pcp.isPathLegEnd()) {
+                               updatePathLegEndControlPoint(pcp); // FXIME: Rules won't work properly, if they are not run twice.
+                               updatePathLegEndControlPoint(pcp);
+                       } else {
+                               updateInlineControlPoint(pcp);
+                               updateInlineControlPoint(pcp);
+                       }
+                       validate(pcp.getPipeRun());
+                       if (!allowInsertRemove)
+                               return !triedIR;
+                       return true;
+               } finally {
+                       updating = false;
+//                     System.out.println("PipingRules done " + pcp);
+               }
+       }
+       
+       public static void setEnabled(boolean enabled) {
+               PipingRules.enabled = enabled;
+               if(!enabled)
+                       updates.clear();
+       }
+       
+       public static boolean isEnabled() {
+               return enabled;
+       }
+       
+//     private void commit() {
+//             root.getNodeMap().commit();
+//     }
+
+       public static class ExpandIterInfo {
+               // these two are turn control points
+               private PipeControlPoint start;
+               private PipeControlPoint end;
+               private int type;
+
+               public ExpandIterInfo() {
+
+               }
+
+               public ExpandIterInfo(PipeControlPoint tcp, int type) {
+                       if (type == REMOVE_START)
+                               start = tcp;
+                       else
+                               end = tcp;
+                       this.type = type;
+               }
+
+               public ExpandIterInfo(PipeControlPoint start, PipeControlPoint end) {
+                       this.start = start;
+                       this.end = end;
+                       this.type = REMOVE_BOTH;
+               }
+
+               public PipeControlPoint getEnd() {
+                       return end;
+               }
+
+               public void setEnd(PipeControlPoint end) {
+                       this.end = end;
+               }
+
+               public PipeControlPoint getStart() {
+                       return start;
+               }
+
+               public void setStart(PipeControlPoint start) {
+                       this.start = start;
+               }
+
+               public int getType() {
+                       return type;
+               }
+
+               public void setType(int type) {
+                       this.type = type;
+               }
+
+       }
+
+       private static void updatePathLegEndControlPoint(PipeControlPoint pcp) throws Exception {
+               if (DEBUG)
+                       System.out.println("PipingRules.updatePathLegEndControlPoint() " + pcp);
+               if (pcp.getNext() != null) {
+                       updatePathLegNext(pcp, pcp, PathLegUpdateType.NEXT_S);
+               }
+               if (pcp.getPrevious() != null) {
+                       updatePathLegPrev(pcp, pcp, PathLegUpdateType.PREV_S);
+               }
+
+       }
+
+       private static void updateInlineControlPoint(PipeControlPoint pcp) throws Exception {
+               if (DEBUG)
+                       System.out.println("PipingRules.updateInlineControlPoint() " + pcp);
+               PipeControlPoint start = pcp.findPreviousEnd();
+               updatePathLegNext(start, pcp, PathLegUpdateType.NONE);
+       }
+
+       private static PipeControlPoint insertElbow(PipeControlPoint pcp1, PipeControlPoint pcp2, Vector3d pos) throws Exception{
+               if (DEBUG)
+                       System.out.println("PipingRules.insertElbow() " + pcp1 + " " + pcp2 + " " + pos);
+               if (pcp1.getNext() == pcp2 && pcp2.getPrevious() == pcp1) {
+                       
+               } else if (pcp1.getNext() == pcp2 && pcp1.isDualInline() && pcp2.getPrevious() == pcp1.getSubPoint().get(0)) {
+                       pcp1 = pcp1.getSubPoint().get(0);       
+               } else if (pcp1.getPrevious() == pcp2 && pcp2.getNext() == pcp1) {
+                       PipeControlPoint t = pcp1;
+                       pcp1 = pcp2;
+                       pcp2 = t;
+               } else if (pcp2.isDualInline() && pcp1.getPrevious() == pcp2.getSubPoint().get(0) && pcp2.getNext() == pcp1) {
+                       PipeControlPoint t = pcp1;
+                       pcp1 = pcp2.getSubPoint().get(0);
+                       pcp2 = t;
+               } else {
+                       throw new RuntimeException();
+               }
+               TurnComponent elbow = ComponentUtils.createTurn((P3DRootNode)pcp1.getRootNode());
+               PipeControlPoint pcp = elbow.getControlPoint();
+               if (pcp1.isDualInline())
+                       pcp1 = pcp1.getSubPoint().get(0);
+               String name = pcp1.getPipeRun().getUniqueName("Elbow");
+               elbow.setName(name);
+               pcp1.getPipeRun().addChild(elbow);
+
+               pcp.insert(pcp1, pcp2);
+
+               pcp.setWorldPosition(pos);
+               validate(pcp.getPipeRun());
+               return pcp;
+       }
+       
+       private static PipeControlPoint insertStraight(PipeControlPoint pcp1, PipeControlPoint pcp2, Vector3d pos, double length) throws Exception {
+               if (DEBUG)
+                       System.out.println("PipingRules.insertStraight() " + pcp1 + " " + pcp2 + " " + pos);
+               if (pcp1.getNext() == pcp2 && pcp2.getPrevious() == pcp1) {
+                       
+               } else if (pcp1.getNext() == pcp2 && pcp1.isDualInline() && pcp2.getPrevious() == pcp1.getSubPoint().get(0)) {
+                       pcp1 = pcp1.getSubPoint().get(0);       
+               } else if (pcp1.getPrevious() == pcp2 && pcp2.getNext() == pcp1) {
+                       PipeControlPoint t = pcp1;
+                       pcp1 = pcp2;
+                       pcp2 = t;
+               } else if (pcp2.isDualInline() && pcp1.getPrevious() == pcp2.getSubPoint().get(0) && pcp2.getNext() == pcp1) {
+                       PipeControlPoint t = pcp1;
+                       pcp1 = pcp2.getSubPoint().get(0);
+                       pcp2 = t;
+               } else {
+                       throw new RuntimeException();
+               }
+               InlineComponent component = ComponentUtils.createStraight((P3DRootNode)pcp1.getRootNode());
+               PipeControlPoint scp = component.getControlPoint();
+               if (pcp1.isDualInline())
+                       pcp1 = pcp1.getSubPoint().get(0);
+               String name = pcp1.getPipeRun().getUniqueName("Pipe");
+               component.setName(name);
+               pcp1.getPipeRun().addChild(component);
+               
+               scp.insert(pcp1, pcp2);
+
+               scp.setWorldPosition(pos);
+               scp.setLength(length);
+               validate(scp.getPipeRun());
+               return scp;
+       }
+       
+       private static PipeControlPoint insertStraight(PipeControlPoint pcp, Direction direction , Vector3d pos, double length) throws Exception {
+               if (DEBUG)
+                       System.out.println("PipingRules.insertStraight() " + pcp + " " + direction + " " + pos);
+               
+               InlineComponent component = ComponentUtils.createStraight((P3DRootNode)pcp.getRootNode());
+               PipeControlPoint scp = component.getControlPoint();
+               if (pcp.isDualInline() && direction == Direction.NEXT)
+                       pcp = pcp.getSubPoint().get(0);
+               String name = pcp.getPipeRun().getUniqueName("Pipe");
+               component.setName(name);
+               pcp.getPipeRun().addChild(component);
+               
+               scp.insert(pcp,direction);
+
+               scp.setWorldPosition(pos);
+               scp.setLength(length);
+               validate(scp.getPipeRun());
+               return scp;
+       }
+
+       private static void updatePathLegNext(PipeControlPoint start, PipeControlPoint updated, PathLegUpdateType lengthChange) throws Exception {
+               ArrayList<PipeControlPoint> list = new ArrayList<PipeControlPoint>();
+               PipeControlPoint end = start.findNextEnd(list);
+               // this is for inline cp that is also path leg end
+               if (start.equals(updated))
+                       lengthChange = PathLegUpdateType.NEXT;
+               else if (end.equals(updated))
+                       lengthChange = PathLegUpdateType.PREV;
+               updatePathLegNext(start, list, end, updated, lengthChange);
+       }
+
+       private static void updatePathLegNext(PipeControlPoint start, ArrayList<PipeControlPoint> list, PipeControlPoint end, PipeControlPoint updated, PathLegUpdateType lengthChange) throws Exception {
+               updatePathLeg(start, list, end, false, 0, new ArrayList<ExpandIterInfo>(), updated, lengthChange);
+       }
+
+       private static class UpdateStruct2 {
+               public PipeControlPoint start;
+               public Vector3d startPoint;
+               public ArrayList<PipeControlPoint> list;
+               public PipeControlPoint end;
+               public Vector3d endPoint;
+               public Vector3d dir;
+               public Vector3d offset;
+               public boolean hasOffsets;
+               public int iter;
+               public boolean reversed;
+               public ArrayList<ExpandIterInfo> toRemove;
+               public PipeControlPoint updated;
+
+               public UpdateStruct2(PipeControlPoint start, Vector3d startPoint, ArrayList<PipeControlPoint> list, PipeControlPoint end, Vector3d endPoint, Vector3d dir, Vector3d offset, boolean hasOffsets, int iter, boolean reversed, ArrayList<ExpandIterInfo> toRemove, PipeControlPoint updated) {
+                       if (start == null || end == null)
+                               throw new NullPointerException();
+                       this.start = start;
+                       this.startPoint = startPoint;
+                       this.list = list;
+                       this.end = end;
+                       this.endPoint = endPoint;
+                       this.dir = dir;
+                       this.offset = offset;
+                       this.hasOffsets = hasOffsets;
+                       this.iter = iter;
+                       this.reversed = reversed;
+                       this.toRemove = toRemove;
+                       this.updated = updated;
+                       
+                       if (!MathTools.isValid(startPoint) || 
+                               !MathTools.isValid(endPoint) || 
+                               !MathTools.isValid(dir)) {
+                               throw new RuntimeException();
+                       }
+               }
+
+               public String toString() {
+                       return start + " " + end+ " " + dir + " " + hasOffsets + " " + offset + " " + iter + " " + toRemove.size();
+               }
+
+       }
+
+       private static boolean calculateOffset(Vector3d startPoint, Vector3d endPoint, ArrayList<PipeControlPoint> list, Vector3d dir, Vector3d offset) {
+               boolean hasOffsets = false;
+               dir.set(startPoint);
+               dir.sub(endPoint);
+               if (dir.lengthSquared() > MathTools.NEAR_ZERO)
+                       dir.normalize();
+               offset.set(0.0, 0.0, 0.0);
+               for (PipeControlPoint icp : list) {
+                       if (icp.isOffset()) {
+                               hasOffsets = true;
+                               offset.add(icp.getSizeChangeOffsetVector(dir));
+                       } else if (icp.isDualSub())
+                               ErrorLogger.defaultLogError("Updating pipe run, found offset controlpoint " + icp, new Exception("ASSERT!"));
+               }
+               return hasOffsets;
+       }
+
+       /**
+        * @param start
+        *            starting point of the pipe run
+        * @param list
+        *            list of inline control points in the pipe run
+        * @param end
+        *            ending point of the pipe run
+        * @param reversed
+        *            boolean flag indicating wether start or end control point was
+        *            modified (if true then end point was modified)
+        * @throws TransactionException
+        */
+       private static void updatePathLeg(PipeControlPoint start, ArrayList<PipeControlPoint> list, PipeControlPoint end, boolean reversed, int iter, ArrayList<ExpandIterInfo> toRemove, PipeControlPoint updated, PathLegUpdateType lengthChange) throws Exception {
+               if (start == end)
+                       return;
+               // FIXME: direction is calculated wrong way!
+               boolean hasOffsets = false;
+               Vector3d offset = new Vector3d();
+               Vector3d startPoint = start.getWorldPosition();
+               Vector3d endPoint = end.getWorldPosition();
+               Vector3d dir = new Vector3d();
+               hasOffsets = calculateOffset(startPoint, endPoint, list, dir, offset);
+               updatePathLeg(new UpdateStruct2(start, startPoint, list, end, endPoint, dir, offset, hasOffsets, iter, reversed, toRemove, updated), lengthChange);
+
+       }
+
+       private static void updatePathLeg(UpdateStruct2 u, PathLegUpdateType lengthChange) throws Exception {
+               int directed = 0;
+               if (u.start.isDirected())
+                       directed++;
+               if (u.end.isDirected())
+                       directed++;
+               switch (directed) {
+               case 0:
+                       updateFreePathLeg(u, lengthChange);
+                       break;
+               case 1:
+                       updateDirectedPathLeg(u, lengthChange);
+                       break;
+               case 2:
+                       updateDualDirectedPathLeg(u, lengthChange);
+                       break;
+               }
+
+       }
+
+       private static void updateFreePathLeg(UpdateStruct2 u, PathLegUpdateType lengthChange) throws Exception {
+               if (DEBUG)
+                       System.out.println("PipingRules.updateFreePipeRun " + u + " " + lengthChange);
+               checkExpandPathLeg(u, lengthChange);
+               if (u.start.isInline() || u.end.isInline())
+                       processPathLeg(u, true, false);
+       }
+
+       private static void updateInlineControlPoints(UpdateStruct2 u, boolean checkSizes) throws Exception{
+               if (DEBUG)
+                       System.out.println("PipingRules.updateInlineControlPoints() " + u);
+
+               if (!u.hasOffsets) {
+                       // FIXME : cache positions
+                       if (!checkSizes) {
+                               Vector3d start = new Vector3d(u.startPoint);
+                               Vector3d end = new Vector3d(u.endPoint);
+                               // create offsets.
+                               MathTools.mad(start, u.dir, 0.1);
+                               MathTools.mad(end, u.dir, -0.1);
+                               for (PipeControlPoint icp : u.list) {
+                                       updateInlineControlPoint(icp, start, end, u.dir);
+                               }
+                               return;
+                       }
+
+                       ArrayList<PipeControlPoint> pathLegPoints = new ArrayList<PipeControlPoint>();
+                       pathLegPoints.add(u.start);
+                       for (PipeControlPoint icp : u.list) {
+                               // updateInlineControlPoint(icp, u.startPoint,
+                               // u.endPoint,u.dir);
+                               updateBranchControlPointBranches(icp);
+                               pathLegPoints.add(icp);
+                       }
+                       pathLegPoints.add(u.end);
+
+                       // TODO : values can be cached in the loop
+                       for (int i = 1; i < pathLegPoints.size(); i++) {
+                               PipeControlPoint icp = pathLegPoints.get(i);
+
+                               PipeControlPoint prev;
+                               Vector3d prevPos;
+                               prev = pathLegPoints.get(i - 1);
+                               prevPos = prev.getWorldPosition();
+                               Vector3d currentPos = icp.getWorldPosition();
+
+                               if (icp.isVariableLength()) {
+                                       if (i != pathLegPoints.size() - 1) {
+                                               PipeControlPoint next;
+                                               Vector3d nextPos;
+                                               next = pathLegPoints.get(i + 1);
+                                               nextPos = next.getWorldPosition();
+                                               Vector3d dir = new Vector3d(nextPos);
+                                               dir.sub(prevPos);
+                                               double l = dir.lengthSquared(); // distance between
+                                                                                                               // control points
+                                                                                                               // (square)
+                                               double l2prev = prev.getInlineLength(); // distance
+                                                                                                                                                                       // taken
+                                                                                                                                                                       // by
+                                                                                                                                                                       // components
+                                               double l2next = next.getInlineLength();
+                                               double l2 = l2prev + l2next;
+                                               double l2s = MathTools.square(l2);
+                                               if (l2s < l) { // check if there is enough space for
+                                                                               // variable length component.
+                                                       // components fit
+                                                       dir.normalize();
+                                                       double length = Math.sqrt(l) - l2; // true length of
+                                                                                                                               // the variable
+                                                                                                                               // length
+                                                                                                                               // component
+                                                       dir.scale(length * 0.5 + l2prev); // calculate
+                                                                                                                               // center
+                                                                                                                               // position of
+                                                                                                                               // the component
+                                                       dir.add(prevPos);
+                                                       icp.setWorldPosition(dir);
+                                                       icp.setLength(length);
+                                               } else {
+                                                       // components leave no space to the component and it
+                                                       // must be removed
+                                                       if (icp.isDeletable())
+                                                               icp._remove();
+                                               }
+
+                                       } else {
+                                               // this is variable length component at the end of the
+                                               // piperun.
+                                               // the problem is that we want to keep unconnected end
+                                               // of the component in the same
+                                               // place, but center of the component must be moved.
+                                               double currentLength = icp.getLength();
+                                               
+                                               Vector3d dir = new Vector3d();
+                                               dir.sub(currentPos, prevPos);
+                                               
+                                               if (currentLength < MathTools.NEAR_ZERO) {
+                                                       currentLength = (dir.length() - prev.getInlineLength()) * 2.0;
+                                               }
+                                               
+                                               if (dir.lengthSquared() > MathTools.NEAR_ZERO)
+                                                       dir.normalize();
+                                               Point3d endPos = new Point3d(dir);
+                                               endPos.scale(currentLength * 0.5);
+                                               endPos.add(currentPos); // this is the free end of the
+                                                                                               // component
+
+                                               double offset = prev.getInlineLength();
+                                               Point3d beginPos = new Point3d(dir);
+                                               beginPos.scale(offset);
+                                               beginPos.add(prevPos); // this is the connected end of
+                                                                                               // the component
+
+                                               double l = beginPos.distance(endPos);
+                                               
+                                               if (Double.isNaN(l))
+                                                       System.out.println();
+
+                                               dir.scale(l * 0.5);
+                                               beginPos.add(dir); // center position
+
+                                               if (DEBUG)
+                                                       System.out.println("PipingRules.updateInlineControlPoints() setting variable length to " + l);
+                                               icp.setLength(l);
+
+                                               icp.setWorldPosition(new Vector3d(beginPos));
+                                       }
+
+
+                               } else if (!prev.isVariableLength()) {
+                                       // If this and previous control point are not variable
+                                       // length pcps, we'll have to check if there is no empty
+                                       // space between them.
+                                       // I there is, we'll have to create new variable length
+                                       // component between them.
+                                       Vector3d dir = new Vector3d(currentPos);
+                                       dir.sub(prevPos);
+                                       double l = dir.lengthSquared();
+                                       double l2prev = prev.getInlineLength();
+                                       double l2next = icp.getInlineLength();
+                                       double l2 = l2prev + l2next;
+                                       double l2s = l2 * l2;
+                                       if (l > l2s) {
+                                               if (allowInsertRemove) {
+                                                       dir.normalize();
+                                                       double length = Math.sqrt(l) - l2; // true length of the
+                                                                                                                               // variable length
+                                                                                                                               // component
+                                                       dir.scale(length * 0.5 + l2prev); // calculate center
+                                                                                                                               // position of the
+                                                                                                                               // component
+                                                       dir.add(prevPos);
+                                                       PipeControlPoint scp = insertStraight(prev, icp, dir, length);
+                                               } else {
+                                                       triedIR = true;
+                                               }
+                                       }
+                               }
+                       }
+               } else {
+                       u.endPoint.sub(u.offset);
+                       // FIXME : straights
+                       for (PipeControlPoint icp : u.list) {
+                               updateInlineControlPoint(icp, u.startPoint, u.endPoint, u.dir);
+                               updateBranchControlPointBranches(icp);
+                               
+                               if (icp.isOffset()) {
+                                       // TODO : offset vector is already calculated and should be
+                                       // cached
+                                       u.offset = icp.getSizeChangeOffsetVector(u.dir);
+                                       updateOffsetPoint(icp, u.offset);
+                                       u.startPoint.add(u.offset);
+                                       u.endPoint.add(u.offset);
+                               }
+                       }
+               }
+       }
+
+       private static void ppNoOffset(UpdateStruct2 u) throws Exception {
+               if (DEBUG)
+                       System.out.println("PipingRules.ppNoOffset() " + u);
+               Vector3d offset = new Vector3d();
+               if (u.hasOffsets) {
+                       u.dir.normalize();
+                       for (PipeControlPoint icp : u.list) {
+                               if (icp.isOffset()) {
+                                       offset.add(icp.getSizeChangeOffsetVector(u.dir));
+                               } else if (icp.isDualSub())
+                                       ErrorLogger.defaultLogError("Updating pipe run, found offset controlpoint " + icp, new Exception("ASSERT!"));
+                       }
+               }
+               u.offset = offset;
+               checkExpandPathLeg(u, PathLegUpdateType.NONE);
+       }
+
+       private static void ppNoDir(PipeControlPoint start, Vector3d startPoint, ArrayList<PipeControlPoint> list, PipeControlPoint end, Vector3d endPoint, boolean hasOffsets, int iter, boolean reversed, ArrayList<ExpandIterInfo> toRemove, PipeControlPoint updated) throws Exception {
+               if (DEBUG)
+                       System.out.println("PipingRules.ppNoDir() " + start + " " + end + " " + iter + " " + toRemove.size());
+               // FIXME : extra loop (dir should be calculated here)
+               Vector3d dir = new Vector3d();
+               Vector3d offset = new Vector3d();
+               hasOffsets = calculateOffset(startPoint, endPoint, list, dir, offset);
+               ppNoOffset(new UpdateStruct2(start, startPoint, list, end, endPoint, dir, null, hasOffsets, iter, reversed, toRemove, updated));
+       }
+
+       private static void checkExpandPathLeg(UpdateStruct2 u, PathLegUpdateType lengthChange) throws Exception {
+               checkExpandPathLeg(u, lengthChange, false);
+       }
+       
+       private static void checkExpandPathLeg(UpdateStruct2 u, PathLegUpdateType lengthChange, boolean forceUpdate) throws Exception {
+               if (DEBUG)
+                       System.out.println("PipingRules.checkExpandPathLeg() " + u + " " + lengthChange);
+               if (lengthChange != PathLegUpdateType.NONE) {
+                       // FIXME : turns cannot be checked before inline cps are updated,
+                       // since their position affects calculation of turns
+                       processPathLeg(u, forceUpdate, false);
+                       int type = checkTurns(u, lengthChange);
+                       if (type == REMOVE_NONE) {
+                               processPathLeg(u, forceUpdate, true);
+                       } else {
+                               expandPathLeg(u, type);
+                       }
+               } else {
+                       processPathLeg(u, forceUpdate, true);
+               }
+       }
+
+       private static void updateDirectedPathLeg(UpdateStruct2 u, PathLegUpdateType lengthChange) throws Exception {
+               if (DEBUG)
+                       System.out.println("PipingRules.updateDirectedPipeRun() " + u + " " + lengthChange);
+               PipeControlPoint dcp;
+               PipeControlPoint other;
+               boolean canMoveOther = false;
+               boolean dcpStart = false;
+               boolean inlineEnd = false;
+               Vector3d position;
+               if (u.start.isDirected()) {
+                       dcp = u.start;
+                       other = u.end;
+                       position = u.startPoint;
+                       dcpStart = true;
+                       if (!u.reversed)
+                               canMoveOther = true;
+                       inlineEnd = u.end.isInline();
+                               
+               } else {
+                       dcp = u.end;
+                       other = u.start;
+                       position = u.endPoint;
+                       if (u.reversed)
+                               canMoveOther = true;
+                       inlineEnd = u.start.isInline();
+               }
+
+               Vector3d directedDirection = dcp.getDirection();
+               Point3d directedEndPoint = new Point3d(u.endPoint);
+               if (u.hasOffsets)
+                       directedEndPoint.add(u.offset);
+
+               double mu[] = new double[2];
+
+               Vector3d closest;
+               Vector3d t = new Vector3d();
+
+               if (dcpStart) {
+                       closest = MathTools.closestPointOnStraight(directedEndPoint, u.startPoint, directedDirection, mu);
+                       t.sub(closest, directedEndPoint);
+               } else {
+                       closest = MathTools.closestPointOnStraight(u.startPoint, directedEndPoint, directedDirection, mu);
+                       t.sub(closest, u.startPoint);
+               }
+
+               double distance = t.lengthSquared();
+               boolean aligned = (distance < 0.002);
+               if (aligned) {
+                       checkExpandPathLeg(u, lengthChange, inlineEnd);
+                       
+               } else {
+                       if (u.iter > 0) {
+                               backIter(u);
+                       } else {
+                               PipeControlPoint nextToMoved;
+
+                               if (u.list.size() > 0)
+                                       if (dcpStart)
+                                               nextToMoved = u.list.get(0);
+                                       else
+                                               nextToMoved = u.list.get(u.list.size() - 1);
+                               else if (dcpStart)
+                                       nextToMoved = u.end;
+                               else
+                                       nextToMoved = u.start;
+                               if (other.isVariableAngle()) {
+
+                                       // TODO calculate needed space from next run end.
+                                       if (mu[0] < 1.0) {
+                                               if (dcpStart) {
+                                                       closest.set(u.startPoint);
+                                               } else {
+                                                       closest.set(u.endPoint);
+                                               }
+                                               closest.add(directedDirection);
+                                       }
+
+                                       if (canMoveOther) {
+                                               if (DEBUG)
+                                                       System.out.println("PipingRules.updateDirectedPipeRun() moved end " + other + " to " + closest);
+                                               other.setWorldPosition(closest);
+                                               if (dcpStart) {
+                                                       ppNoOffset(new UpdateStruct2(u.start, u.startPoint, u.list, u.end, new Vector3d(closest), directedDirection, null, u.hasOffsets, u.iter, u.reversed, u.toRemove, u.updated));
+                                                       if (u.end.getNext() != null)
+                                                               updatePathLegNext(u.end, u.updated, PathLegUpdateType.NEXT);
+                                               } else {
+                                                       ppNoOffset(new UpdateStruct2(u.start, new Vector3d(closest), u.list, u.end, u.endPoint, directedDirection, null, u.hasOffsets, u.iter, u.reversed, u.toRemove, u.updated));
+                                                       if (u.start.getPrevious() != null)
+                                                               updatePathLegPrev(u.start, u.updated, PathLegUpdateType.PREV);
+                                               }
+                                       } else {
+                                               // TODO : calculate needed space from next run end.
+                                               if (allowInsertRemove)
+                                                       insertElbowUpdate(u, dcp, nextToMoved, dcpStart, position, directedDirection);
+                                                       
+                                               else
+                                                       triedIR = true;
+                                       }
+                               } else if (other.isNonDirected() && other.getParentPoint() != null) {
+                                       // FIXME : this code was for updating branches
+                                       Vector3d bintersect = new Vector3d();
+                                       PipeControlPoint bcp = other.getParentPoint();
+                                       if (bcp != null && canMoveOther) {
+                                               Point3d bstart = new Point3d();
+                                               Point3d bend = new Point3d();
+                                               Vector3d bdir = new Vector3d();
+                                               bcp.getInlineControlPointEnds(bstart, bend, bdir);
+                                               Vector3d nintersect = new Vector3d();
+
+                                               MathTools.intersectStraightStraight(position, directedDirection, bend, bdir, nintersect, bintersect, mu);
+                                               Vector3d dist = new Vector3d(nintersect);
+                                               dist.sub(bintersect);
+                                               canMoveOther = mu[1] > 0.0 && mu[1] < 1.0 && dist.lengthSquared() < 0.01;
+                                       } else {
+                                               // TODO : endControlPoints are undirected: calculcate
+                                               // correct position for it
+                                               throw new UnsupportedOperationException("not implemented");
+                                       }
+                                       if (canMoveOther) {
+                                               if (DEBUG)
+                                                       System.out.println("PipingRules.updateDirectedPipeRun() moved end " + other + " to " + bintersect);
+                                               // is required branch position is in possible range
+                                               bcp.setWorldPosition(bintersect);
+                                               if (dcpStart) {
+                                                       checkExpandPathLeg(new UpdateStruct2(u.start, u.startPoint, u.list, u.end, new Vector3d(bintersect), directedDirection, u.offset, u.hasOffsets, u.iter, u.reversed, u.toRemove, u.updated), lengthChange);
+                                               } else {
+                                                       checkExpandPathLeg(new UpdateStruct2(u.start, new Vector3d(bintersect), u.list, u.end, u.endPoint, directedDirection, u.offset, u.hasOffsets, u.iter, u.reversed, u.toRemove, u.updated), lengthChange);
+                                               }
+                                       } else {
+                                               // branch cannot be moved into right position, new turn
+                                               // / elbow must be inserted
+                                               if (allowInsertRemove)
+                                                       insertElbowUpdate(u, dcp, nextToMoved, dcpStart, position, directedDirection);
+                                               else
+                                                       triedIR = true;
+                                       }
+
+                               } else { // assume that control point cannot be moved, but can
+                                                       // be rotated
+                                       if (allowInsertRemove)
+                                               insertElbowUpdate(u, dcp, nextToMoved, dcpStart, position, directedDirection);
+                                       else
+                                               triedIR = true;
+                               }
+                       }
+               }
+               
+               
+       }
+
+       private static void updateDualDirectedPathLeg(UpdateStruct2 u, PathLegUpdateType lengthChange) throws Exception {
+               if (DEBUG)
+                       System.out.println("PipingRules.updateDualDirectedPipeRun() " + u + " " + lengthChange);
+               
+               PipeControlPoint dcp1 = u.start;
+               PipeControlPoint dcp2 = u.end;
+               Point3d position1 = new Point3d(u.startPoint);
+               Point3d position2 = new Point3d(u.endPoint);
+               Point3d position1offset = new Point3d(position1);
+               position1offset.sub(u.offset);
+               Point3d position2offset = new Point3d(position2);
+               position2offset.add(u.offset);
+               Vector3d dir1 = dcp1.getDirection();
+               Vector3d dir2 = dcp2.getDirection();
+               Vector3d p1 = MathTools.closestPointOnStraight(position1offset, position2, dir2);
+               Vector3d p2 = MathTools.closestPointOnStraight(position2offset, position1, dir1);
+               double d1 = position1.distance(new Point3d(p1));
+               double d2 = position2.distance(new Point3d(p2));
+
+               boolean aligned = (d1 < 0.01 && d2 < 0.01);
+               if (aligned) {
+                       processPathLeg(u);
+               } else {
+                       if (u.iter > 0) {
+                               backIter(u);
+                       } else if (allowInsertRemove){
+                               PipeControlPoint dcp;
+                               PipeControlPoint next;
+                               if (!u.reversed) {
+                                       dcp = dcp1;
+                                       if (u.list.size() > 0)
+                                               next = u.list.get(0);
+                                       else
+                                               next = dcp2;
+                               } else {
+                                       dcp = dcp2;
+                                       if (u.list.size() > 0)
+                                               next = u.list.get(u.list.size() - 1);
+                                       else
+                                               next = dcp1;
+                               }
+                               
+                               p1 = dcp.getWorldPosition();
+                               // FIXME: calculate position of the elbows properly.
+                               if (!u.reversed)
+                                       p1.add(dir1);
+                               else
+                                       p1.add(dir2);
+
+                               if (!u.reversed)
+                                       p2 = MathTools.closestPointOnStraight(new Point3d(p1), position2, dir2);
+                               else
+                                       p2 = MathTools.closestPointOnStraight(new Point3d(p1), position1, dir1);
+
+                               
+                               PipeControlPoint tcp1 = insertElbow(dcp, next, p1);
+                               PipeControlPoint tcp2 = insertElbow(tcp1, next, p2);
+
+                               if (DEBUG)
+                                       System.out.println("PipingRules.updateDualDirectedPipeRun() created two turns " + tcp1 + " " + tcp2);
+
+                               if (!u.reversed) {
+                                       Vector3d dd = new Vector3d(p2);
+                                       dd.sub(p1);
+                                       dir2.negate();
+                                       updatePathLegNext(u.start, u.updated, PathLegUpdateType.NONE);
+                                       updatePathLegNext(tcp1, u.updated, PathLegUpdateType.NONE);
+                                       if (!u.reversed)
+                                               updatePathLegNext(tcp2, u.updated, PathLegUpdateType.NONE);
+                                       else
+                                               updatePathLegPrev(tcp2, u.updated, PathLegUpdateType.NONE);
+                               } else {
+                                       Vector3d dd = new Vector3d(p1);
+                                       dd.sub(p2);
+                                       dir2.negate();
+                                       updatePathLegNext(tcp1, u.updated, PathLegUpdateType.NONE);
+                                       updatePathLegNext(tcp2, u.updated, PathLegUpdateType.NONE);
+                                       if (!u.reversed)
+                                               updatePathLegNext(u.start, u.updated, PathLegUpdateType.NONE);
+                                       else
+                                               updatePathLegPrev(u.start, u.updated, PathLegUpdateType.NONE);
+                               }
+                       } else {
+                               triedIR = true;
+                       }
+               }
+               
+       }
+
+       private static void insertElbowUpdate(UpdateStruct2 u, PipeControlPoint dcp, PipeControlPoint next, boolean dcpStart, Vector3d position, Vector3d directedDirection) throws Exception{
+
+               Vector3d closest = new Vector3d(position);
+               closest.add(directedDirection);
+               PipeControlPoint tcp = null;
+               if (dcpStart)
+                       tcp = insertElbow(dcp, next, new Vector3d(closest));
+               else
+                       tcp = insertElbow(next, dcp, new Vector3d(closest));
+
+               if (DEBUG)
+                       System.out.println("PipingRules.updateDirectedPipeRun() inserted " + tcp);
+
+               if (dcpStart) {
+                       // update pipe run from new turn to other end
+                       ppNoDir(tcp, new Vector3d(closest), u.list, u.end, u.endPoint, u.hasOffsets, u.iter, u.reversed, u.toRemove, u.updated);
+                       // update pipe run from directed to new turn
+                       processPathLeg(new UpdateStruct2(u.start, u.startPoint, new ArrayList<PipeControlPoint>(), tcp, new Vector3d(closest), directedDirection, new Vector3d(), false, 0, false, new ArrayList<ExpandIterInfo>(), u.updated));
+               } else {
+                       // update pipe run from other end to new turn
+                       ppNoDir(u.start, u.startPoint, u.list, tcp, new Vector3d(closest), u.hasOffsets, u.iter, u.reversed, u.toRemove, u.updated);
+                       // update pipe run from new turn to directed
+                       processPathLeg(new UpdateStruct2(tcp, new Vector3d(closest), new ArrayList<PipeControlPoint>(), u.end, u.endPoint, directedDirection, new Vector3d(), false, 0, false, new ArrayList<ExpandIterInfo>(), u.updated));
+               }
+       }
+
+       /**
+        * Checks if turns can be removed (turn angle near zero)
+        */
+       private static int checkTurns(UpdateStruct2 u, PathLegUpdateType lengthChange) throws Exception {
+               if (DEBUG)
+                       System.out.println("PipingRules.checkTurns() " + u.start + " " + u.end);
+               boolean startRemoved = false;
+               boolean endRemoved = false;
+               if (u.start.isVariableAngle()) {
+                       // this won't work properly if inline control points are not updated
+                       PipeControlPoint startPrev = u.start.getPrevious();
+                       if (startPrev != null) {
+                               double a;
+                               if (!u.hasOffsets) {
+                                       a = updateTurnControlPointTurn(u.start, startPrev, u.end);
+                               } else {
+                                       Vector3d ep = new Vector3d(u.endPoint);
+                                       ep.add(u.offset);
+                                       a = updateTurnControlPointTurn(u.start, u.startPoint, startPrev.getPosition(), ep);
+
+                               }
+                               if (a < MIN_TURN_ANGLE && u.start.isDeletable())
+                                       startRemoved = true;
+                               else if (lengthChange == PathLegUpdateType.PREV || lengthChange == PathLegUpdateType.PREV_S) {
+                                       PathLegUpdateType type;
+                                       if (lengthChange == PathLegUpdateType.PREV_S)
+                                               type = PathLegUpdateType.PREV;
+                                       else
+                                               type = PathLegUpdateType.NONE;
+                                       updatePathLegPrev(u.start, u.start, type);
+                               }
+                       }
+               }
+               if (u.end.isVariableAngle()) {
+
+                       PipeControlPoint endNext = u.end.getNext();
+                       if (endNext != null) {
+                               double a;
+                               if (!u.hasOffsets) {
+                                       a = updateTurnControlPointTurn(u.end, u.start, endNext);
+                               } else {
+                                       Vector3d sp = new Vector3d(u.startPoint);
+                                       sp.sub(u.offset);
+                                       a = updateTurnControlPointTurn(u.end, u.endPoint, sp, endNext.getPosition());
+                               }
+                               if (a < MIN_TURN_ANGLE && u.end.isDeletable())
+                                       endRemoved = true;
+                               else if (lengthChange == PathLegUpdateType.NEXT || lengthChange == PathLegUpdateType.NEXT_S) {
+                                       PathLegUpdateType type;
+                                       if (lengthChange == PathLegUpdateType.NEXT_S)
+                                               type = PathLegUpdateType.NEXT;
+                                       else
+                                               type = PathLegUpdateType.NONE;
+                                       updatePathLegNext(u.end, u.end, type);
+                               }
+                       }
+               }
+               if (DEBUG)
+                       System.out.println("PipingRules.checkTurns() res " + startRemoved + " " + endRemoved);
+               if (!startRemoved && !endRemoved)
+                       return REMOVE_NONE;
+               if (startRemoved && endRemoved)
+                       return REMOVE_BOTH;
+               if (startRemoved)
+                       return REMOVE_START;
+               return REMOVE_END;
+       }
+
+       /**
+        * Expands piperun search over turns that are going to be removed
+        * 
+        */
+       private static void expandPathLeg(UpdateStruct2 u, int type) throws Exception {
+               if (DEBUG)
+                       System.out.println("PipingRules.expandPipeline " + u.start + " " + u.end);
+               ArrayList<PipeControlPoint> newList = new ArrayList<PipeControlPoint>();
+               switch (type) {
+               case REMOVE_NONE:
+                       throw new RuntimeException("Error in piping rules");
+               case REMOVE_START:
+                       u.toRemove.add(new ExpandIterInfo(u.start, REMOVE_START));
+                       u.start = u.start.findPreviousEnd();
+                       u.startPoint = u.start.getPosition();
+                       u.start.findNextEnd(newList);
+                       newList.addAll(u.list);
+                       u.list = newList;
+                       break;
+               case REMOVE_END:
+                       u.toRemove.add(new ExpandIterInfo(u.end, REMOVE_END));
+                       u.end = u.end.findNextEnd(newList);
+                       u.endPoint = u.end.getPosition();
+                       u.list.addAll(newList);
+                       break;
+               case REMOVE_BOTH:
+                       u.toRemove.add(new ExpandIterInfo(u.start, u.end));
+                       u.start = u.start.findPreviousEnd();
+                       u.startPoint = u.start.getPosition();
+                       u.start.findNextEnd(newList);
+                       newList.addAll(u.list);
+                       u.list = newList;
+                       newList = new ArrayList<PipeControlPoint>();
+                       u.end = u.end.findNextEnd(newList);
+                       u.endPoint = u.end.getPosition();
+                       u.list.addAll(newList);
+                       break;
+               default:
+                       throw new RuntimeException("Error in piping rules");
+
+               }
+               u.offset = new Vector3d();
+               if (u.hasOffsets) {
+                       u.dir.normalize();
+                       for (PipeControlPoint icp : u.list) {
+                               if (icp.isOffset()) {
+                                       u.offset.add(icp.getSizeChangeOffsetVector(u.dir));
+                               } else if (icp.isDualSub())
+                                       ErrorLogger.defaultLogError("Updating pipe run, found offset controlpoint " + icp, new Exception("ASSERT!"));
+                       }
+               }
+               if (DEBUG)
+                       System.out.println("PipingRules.expandPipeline expanded " + u.start + " " + u.end);
+               u.iter++;
+               updatePathLeg(u, PathLegUpdateType.NONE);
+       }
+
+       /**
+        * reverts one iteration of turn removing back)
+        */
+       private static void backIter(UpdateStruct2 u) throws Exception {
+
+               if (DEBUG)
+                       System.out.println("PipingRules.backIter" + u.start + " " + u.end);
+               if (u.iter == 0)
+                       throw new RuntimeException("Error in piping rules");
+               ExpandIterInfo info = u.toRemove.get(u.toRemove.size() - 1);
+               u.toRemove.remove(u.toRemove.size() - 1);
+               if (info.getType() == REMOVE_START || info.getType() == REMOVE_BOTH) {
+                       while (u.list.size() > 0) {
+                               PipeControlPoint icp = u.list.get(0);
+                               if (icp.getPrevious().equals(info.getStart()))
+                                       break;
+                               u.list.remove(icp);
+                       }
+                       u.start = info.getStart();
+               }
+               if (info.getType() == REMOVE_END || info.getType() == REMOVE_BOTH) {
+                       while (u.list.size() > 0) {
+                               PipeControlPoint icp = u.list.get(u.list.size() - 1);
+                               if (icp.getNext().equals(info.getEnd()))
+                                       break;
+                               u.list.remove(icp);
+                       }
+                       u.end = info.getEnd();
+               }
+               u.offset = new Vector3d();
+               if (u.hasOffsets) {
+                       u.dir.normalize();
+                       for (PipeControlPoint icp : u.list) {
+                               if (icp.isOffset()) {
+                                       u.offset.add(icp.getSizeChangeOffsetVector(u.dir));
+                               } else if (icp.isDualSub())
+                                       ErrorLogger.defaultLogError("Updating pipe run, found offset controlpoint " + icp, new Exception("ASSERT!"));
+                       }
+               }
+               processPathLeg(u);
+
+       }
+
+       /**
+        * Processes pipe run (removes necessary turns and updates run ends)
+        */
+       // 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 {
+
+       private static void processPathLeg(UpdateStruct2 u) throws Exception {
+               if (DEBUG)
+                       System.out.println("PipingRules.processPathLeg " + u.start + " " + u.end);
+               processPathLeg(u, true, true);
+       }
+
+       private static void processPathLeg(UpdateStruct2 u, boolean updateEnds, boolean updateInline) throws Exception {
+               if (DEBUG)
+                       System.out.println("PipingRules.processPathLeg " + u.start + " " + u.end);
+
+               if (u.toRemove.size() > 0) {
+                       for (ExpandIterInfo info : u.toRemove) {
+                               if (info.getStart() != null) {
+                                       info.getStart()._remove();
+                               }
+                               if (info.getEnd() != null) {
+                                       info.getEnd()._remove();
+                               }
+                       }
+                       // ControlPointTools.removeControlPoint may remove mo0re than one
+                       // CP;
+                       // we must populate inline CP list again.
+                       u.list.clear();
+                       u.start.findNextEnd( u.list);
+               }
+               // FIXME : inline CPs are update twice because their positions must be
+               // updated before and after ends.
+               updateInlineControlPoints(u, false);
+               
+               if (updateEnds) {
+                       if (u.start.isTurn()) {
+                               updateTurnControlPointTurn(u.start, u.start.getPrevious(), u.start.getNext());
+//                             updatePathLegPrev(u.start, u.start, PathLegUpdateType.NONE);
+                       } else if (u.start.isEnd()) {
+                               updateEndComponentControlPoint(u.start, u.startPoint, u.endPoint);
+                       } else if (u.start.isInline()) {
+                               updateControlPointOrientation(u.start);
+                       }
+                       if (u.end.isTurn()) {
+                               updateTurnControlPointTurn(u.end, u.end.getPrevious(), u.end.getNext());
+//                             updatePathLegNext(u.end, u.end, PathLegUpdateType.NONE);
+                       } else if (u.end.isEnd()) {
+                               updateEndComponentControlPoint(u.end, u.startPoint, u.endPoint);
+                       } else if (u.end.isInline()) {
+                               updateControlPointOrientation(u.end);
+                       }
+
+               } else {
+                       if (u.start.isEnd()) {
+                               updateEndComponentControlPoint(u.start, u.startPoint, u.endPoint);
+                       }
+                       if (u.end.isEnd()) {
+                               updateEndComponentControlPoint(u.end, u.startPoint, u.endPoint);
+                       }
+               }
+               if (updateInline)
+                       updateInlineControlPoints(u, true);
+
+       }
+
+       /**
+        * Processes pipe run and recalculates offset
+        */
+       // 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
+       // {
+       private static void processPathLegNoOffset(UpdateStruct2 u) throws Exception {
+               if (DEBUG)
+                       System.out.println("PipingRules.processPathLeg " + u.start + " " + u.end);
+               Vector3d offset = new Vector3d();
+               if (u.hasOffsets) {
+                       u.dir.normalize();
+                       for (PipeControlPoint icp : u.list) {
+                               if (icp.isOffset()) {
+                                       offset.add(icp.getSizeChangeOffsetVector(u.dir));
+                               } else if (icp.isDualSub()) {
+                                       ErrorLogger.defaultLogError("Updating pipe run, found offset controlpoint " + icp, new Exception("ASSERT!"));
+                               }
+                       }
+               }
+               processPathLeg(u);
+       }
+
+       private static void updateOffsetPoint(PipeControlPoint sccp, Vector3d offset) {
+               Vector3d world = sccp.getWorldPosition();
+               world.add(offset);
+               PipeControlPoint ocp = sccp.getSubPoint().iterator().next();
+               ocp.setWorldPosition(world);
+       }
+
+       private static void updatePathLegPrev(PipeControlPoint start, PipeControlPoint updated, PathLegUpdateType lengthChange) throws Exception {
+               ArrayList<PipeControlPoint> list = new ArrayList<PipeControlPoint>();
+               PipeControlPoint end = start.findPreviousEnd(list);
+               updatePathLegPrev(start, list, end, updated, lengthChange);
+       }
+
+       private static void updatePathLegPrev(PipeControlPoint start, ArrayList<PipeControlPoint> list, PipeControlPoint end, PipeControlPoint updated, PathLegUpdateType lengthChange) throws Exception {
+               // reverses the list
+               ArrayList<PipeControlPoint> nextList = new ArrayList<PipeControlPoint>();
+               for (PipeControlPoint icp : list) {
+                       if (icp.isDualSub()) {
+                               nextList.add(0, icp.getParentPoint());
+                       } else {
+                               nextList.add(0, icp);
+                       }
+
+               }
+               updatePathLeg(end, nextList, start, true, 0, new ArrayList<ExpandIterInfo>(), updated, lengthChange);
+
+       }
+
+       /**
+        * Updates InlineControlPoints position when straight pipe's end(s) have
+        * been changed)
+        * 
+        * @param pipeline
+        * @param icp
+        * @param nextPoint
+        * @param prevPoint
+        */
+       private static void updateInlineControlPoint(PipeControlPoint icp, Vector3d nextPoint, Vector3d prevPoint, Vector3d dir) {
+               if (DEBUG)
+                       System.out.println("PipingRules.updateInlineControlPoint() " + icp);
+
+               Vector3d inlinePoint = icp.getWorldPosition();
+               if (DEBUG)
+                       System.out.print("InlineControlPoint update " + icp + " " + inlinePoint + " " + prevPoint + " " + nextPoint);
+               Vector3d newInlinePoint = null;
+               boolean branchUpdate = false;
+               PipeControlPoint becp = null;
+               for (PipeControlPoint pcp : icp.getSubPoint())
+                       if (pcp.isNonDirected()) {
+                               branchUpdate = true;
+                               becp = pcp;
+                               break;
+                       }
+
+               if (DUMMY || !branchUpdate) {
+                       newInlinePoint = MathTools.closestPointOnEdge(new Vector3d(inlinePoint), new Vector3d(nextPoint), new Vector3d(prevPoint));
+               } else {
+
+                       // FIXME : can only handle one branch
+                       PipeControlPoint p = null;
+                       if (becp.getNext() != null) {
+                               p = becp.findNextEnd();
+                       } else if (becp.getPrevious() != null) {
+                               p = becp.findPreviousEnd();
+                       }
+                       if (p == null) {
+                               newInlinePoint = MathTools.closestPointOnEdge(new Vector3d(inlinePoint), new Vector3d(nextPoint), new Vector3d(prevPoint));
+                       } else {
+                               Vector3d branchLegEnd = p.getWorldPosition();
+                               Vector3d dir2 = new Vector3d(inlinePoint);
+                               dir2.sub(branchLegEnd);
+                               Vector3d dir1 = new Vector3d(nextPoint);
+                               dir1.sub(prevPoint);
+                               newInlinePoint = new Vector3d();
+                               double mu[] = new double[2];
+                               MathTools.intersectStraightStraight(new Vector3d(prevPoint), dir1, new Vector3d(branchLegEnd), dir2, newInlinePoint, new Vector3d(), mu);
+                               if (DEBUG)
+                                       System.out.println(mu[0]);
+                               // FIXME : reserve space
+                               if (mu[0] < 0.0) {
+                                       newInlinePoint = new Vector3d(prevPoint);
+                               } else if (mu[0] > 1.0) {
+                                       newInlinePoint = new Vector3d(nextPoint);
+                               }
+                       }
+               }
+               if (DEBUG)
+                       System.out.println(" " + newInlinePoint);
+
+               icp.setWorldPosition(newInlinePoint);
+               updateControlPointOrientation(icp);
+       }
+
+       /**
+        * Updates InlineControlPoints position when straight pipe's end(s) have
+        * been changed)
+        * 
+        * @param pipeline
+        * @param icp
+        * @param nextPoint
+        * @param prevPoint
+        */
+       private static void updateEndComponentControlPoint(PipeControlPoint ecp, Vector3d start, Vector3d end) throws Exception {
+               if (DEBUG)
+                       System.out.println("PipingRules.updateEndComponentControlPoint() " + ecp);
+               // PipeControlPoint next = ecp.getNext();
+               // PipeControlPoint prev = ecp.getPrevious();
+               // if (next != null) {
+               // end = G3DTools.getPoint(next.getLocalPosition());
+               // start = G3DTools.getPoint(ecp.getLocalPosition());
+               // } else if (prev != null) {
+               // end = G3DTools.getPoint(ecp.getLocalPosition());
+               // start = G3DTools.getPoint(prev.getLocalPosition());
+               // } else {
+               // // TODO : warning?
+               // return;
+               // }
+               // Vector3d dir = new Vector3d (end);
+               // dir.sub(start);
+               // dir.normalize();
+               // G3DTools.setTuple(ecp.getDirection(), dir);
+               if (!ecp.isFixed())
+                       updateControlPointOrientation(ecp);
+
+               for (PipeControlPoint pcp : ecp.getSubPoint()) {
+                       // TODO update position
+                       updatePathLegEndControlPoint(pcp);
+               }
+       }
+
+       private static void updateControlPointOrientation(PipeControlPoint pcp) {
+               // FIXME : hack to bypass variable length components orientation
+//             if (pcp.getAtMostOneRelatedObject(ProcessResource.g3dResource.HasWorldOrientation) == null)
+//                     return;
+//             if (pcp.rotationAngle == null)
+//                     return;
+               Double angleO = pcp.getRotationAngle();
+               double angle = 0.0;
+               if (angleO != null)
+                       angle = angleO;
+
+               Quat4d q = pcp.getControlPointOrientationQuat(angle);
+               pcp.setWorldOrientation(q);
+       }
+
+       /**
+        * Updates all branches when branch's position has been changed
+        * 
+        * @param bcp
+        */
+       private static void updateBranchControlPointBranches(PipeControlPoint bcp) throws Exception {
+               if (DEBUG)
+                       System.out.println("PipingRules.updateBranchControlPointBranches() " + bcp);
+               if (bcp.isDualInline())
+                       return;
+               Collection<PipeControlPoint> branches = bcp.getSubPoint();
+               if (branches.size() == 0) {
+                       if (DEBUG)
+                               System.out.println("No Branches found");
+                       return;
+               }
+               
+               for (PipeControlPoint pcp : branches) {
+                       updatePathLegEndControlPoint(pcp);
+               }
+       }
+
+       /**
+        * Recalculates turn control point's internal data (turn angle and offset)
+        * 
+        * @param tcp
+        * @param prev
+        * @param next
+        */
+       private static double updateTurnControlPointTurn(PipeControlPoint tcp, PipeControlPoint prev, PipeControlPoint next) {
+               if (DEBUG)
+                       System.out.println("PipingTools.updateTurnControlPointTurn()" + tcp);
+               if (next == null || prev == null)
+                       return Math.PI; // FIXME : argh
+               Vector3d middlePoint = tcp.getWorldPosition();
+               Vector3d nextPoint = next.getWorldPosition();
+               Vector3d prevPoint = prev.getWorldPosition();
+               return updateTurnControlPointTurn(tcp, middlePoint, prevPoint, nextPoint);
+       }
+
+       /**
+        * Recalculates turn control point's internal data (turn angle and offset)
+        * 
+        * @param tcp
+        * @param middlePoint
+        * @param nextPoint
+        * @param prevPoint
+        */
+       private static double updateTurnControlPointTurn(PipeControlPoint tcp, Vector3d middlePoint, Vector3d prevPoint, Vector3d nextPoint) {
+
+               Vector3d dir1 = new Vector3d(middlePoint);
+               dir1.sub(prevPoint);
+               Vector3d dir2 = new Vector3d(nextPoint);
+               dir2.sub(middlePoint);
+               if (DEBUG)
+                       System.out.println("PipingTools.updateTurnControlPointTurn " + tcp + " " + prevPoint + " " + middlePoint + " " + nextPoint);
+               return updateTurnControlPointTurn(tcp, dir1, dir2);
+       }
+
+       private static double updateTurnControlPointTurn(PipeControlPoint tcp, Vector3d dir1, Vector3d dir2) {
+               double turnAngle = dir1.angle(dir2);
+
+               double angle = Math.PI - turnAngle;
+
+               Vector3d turnAxis = new Vector3d();
+               turnAxis.cross(dir1, dir2);
+               if (turnAxis.lengthSquared() > MathTools.NEAR_ZERO) {
+                       double elbowRadius = tcp.getPipelineComponent().getPipeRun().getTurnRadius();
+                       double R = elbowRadius / Math.tan(angle * 0.5);
+                       
+                       turnAxis.normalize();
+                       tcp.setTurnAngle(turnAngle);
+                       tcp.setLength(R);// setComponentOffsetValue(R);
+                       tcp.setTurnAxis(turnAxis);
+//                     tcp.setPosition(tcp.getPosition());
+               } else {
+                       turnAngle = 0.0;
+                       tcp.setTurnAngle(0.0);
+                       tcp.setLength(0.0);
+                       tcp.setTurnAxis(MathTools.Y_AXIS);
+               }
+               updateControlPointOrientation(tcp);
+               if (DEBUG)
+                       System.out.println("PipingTools.updateTurnControlPointTurn " + dir1 + " " + dir2 + " " + turnAngle + " " + turnAxis);
+               return turnAngle;
+       }
+       
+       public static List<PipeControlPoint> getControlPoints(PipeRun pipeRun) {
+               List<PipeControlPoint> list = new ArrayList<PipeControlPoint>();
+               if (pipeRun.getControlPoints().size() == 0)
+                       return list;
+               PipeControlPoint pcp = pipeRun.getControlPoints().iterator().next();
+               while (pcp.getPrevious() != null) {
+                       PipeControlPoint prev = pcp.getPrevious();
+                       if (prev.getPipeRun() != pipeRun)
+                               break;
+                       pcp = prev;
+               }
+               if (pcp.isDualSub()) {
+                       pcp = pcp.getParentPoint();
+               }
+               list.add(pcp);
+               while (pcp.getNext() != null) {
+                       pcp = pcp.getNext();
+                       if (pcp.getPipeRun() != pipeRun)
+                               break;
+                       list.add(pcp);
+               }
+               return list;
+       }
+       
+       public static void reverse(PipeRun pipeRun) {
+               List<PipeControlPoint> list = getControlPoints(pipeRun);
+               if (list.size() <= 1)
+                       return; // nothing to do.
+               
+               for (int i = 0 ; i < list.size(); i++) {
+                       boolean first = i == 0;
+                       boolean last = i == list.size() - 1;
+                       PipeControlPoint current = list.get(i);
+                       PipeControlPoint currentSub = null;
+                       if (current.isDualInline())
+                               currentSub = current.getSubPoint().get(0);
+                       if (first) {
+                               PipeControlPoint next = list.get(i+1);
+                               if (next.isDualInline())
+                                       next = next.getSubPoint().get(0);
+                               current.setNext(null);
+                               current.setPrevious(next);
+                               if (currentSub != null) {
+                                       currentSub.setNext(null);
+                                       currentSub.setPrevious(next);           
+                               }
+                       } else if (last) {
+                               PipeControlPoint prev = list.get(i-1);
+                               
+                               current.setPrevious(null);
+                               current.setNext(prev);
+                               
+                               if (currentSub != null) {
+                                       currentSub.setPrevious(null);
+                                       currentSub.setNext(prev);               
+                               }
+                       } else {
+                               PipeControlPoint prev = list.get(i-1);
+                               PipeControlPoint next = list.get(i+1);
+                               if (next.isDualInline())
+                                       next = next.getSubPoint().get(0);
+                               
+                               
+                               current.setPrevious(next);
+                               current.setNext(prev);
+                               
+                               if (currentSub != null) {
+                                       currentSub.setPrevious(next);
+                                       currentSub.setNext(prev);               
+                               }
+                               
+                       }
+               }
+       }
+       
+       public static void merge(PipeRun run1, PipeRun r2) {
+               Map<PipeControlPoint, Vector3d> positions = new HashMap<PipeControlPoint, Vector3d>();
+               Map<PipeControlPoint, Quat4d> orientations = new HashMap<PipeControlPoint, Quat4d>();
+               for (PipeControlPoint pcp : r2.getControlPoints()) {
+                       positions.put(pcp, pcp.getWorldPosition());
+                       orientations.put(pcp, pcp.getWorldOrientation());
+               }
+               for (PipeControlPoint pcp : r2.getControlPoints()) {
+                       r2.deattachChild(pcp);
+                       run1.addChild(pcp);
+                       PipelineComponent component = pcp.getPipelineComponent();
+                       if (component != null) {
+                               if (!(component instanceof Nozzle)) {
+                                       component.deattach();
+                                       run1.addChild(component);
+                               } else {
+                                       Nozzle n = (Nozzle)component;
+                                       n.setPipeRun(run1);
+                               }
+                       }
+               }
+               r2.remove();
+               
+       }
+       
+       public static void validate(PipeRun pipeRun) {
+               if (pipeRun == null)
+                       return;
+               Collection<PipeControlPoint> pcps = pipeRun.getControlPoints();
+               int count = 0;
+               for (PipeControlPoint pcp : pcps) {
+                       if (pcp.getParentPoint() == null || pcp.getParentPoint().getPipeRun() != pipeRun)
+                               count++;
+               }
+               List<PipeControlPoint> runPcps = getControlPoints(pipeRun);
+               if (runPcps.size() != count) {
+                       System.out.println("Run is not connected");
+               }
+               for (PipeControlPoint pcp : pcps) {
+                       if (pcp.getParentPoint() == null) {
+                               PipeControlPoint sub = null;
+                               if (pcp.isDualInline())
+                                       sub = pcp.getSubPoint().get(0);
+                               PipeControlPoint next = pcp.getNext();
+                               PipeControlPoint prev = pcp.getPrevious();
+                               if (next != null) {
+                                       if (!(next.getPrevious() == pcp || next.getPrevious() == sub)) {
+                                               System.out.println("Inconsistency between " + pcp + " -> " +next );
+                                       }
+                               }
+                               if (prev != null) {
+                                       PipeControlPoint prevParent = null;
+                                       if (prev.isDualSub()) {
+                                               prevParent = prev.getParentPoint();
+                                       } else if (prev.isDualInline()) {
+                                               System.out.println("Inconsistency between " + pcp + " <-- " +prev );
+                                       }
+                                       if (!(prev.getNext() == pcp && (prevParent == null || prevParent.getNext() == pcp))) {
+                                               System.out.println("Inconsistency between " + pcp + " <-- " +prev );
+                                       }
+                               }
+                       }
+               }
+       }
+       
+       public static void splitVariableLengthComponent(PipelineComponent newComponent, InlineComponent splittingComponent, boolean assignPos) throws Exception{
+               assert(!splittingComponent.getControlPoint().isFixed());
+               assert(!(newComponent instanceof  InlineComponent && !newComponent.getControlPoint().isFixed()));
+               PipeControlPoint newCP = newComponent.getControlPoint();
+               PipeControlPoint splittingCP = splittingComponent.getControlPoint();
+               PipeControlPoint nextCP = splittingCP.getNext();
+               PipeControlPoint prevCP = splittingCP.getPrevious();
+               
+               /* there are many different cases to insert new component when
+                  it splits existing VariableLengthinlineComponent.
+           
+              1. VariableLengthComponet is connected from both sides:
+                 - insert new component between VariableLength component and component connected to it
+                 - insert new VariableLengthComponent between inserted component and component selected in previous step
+               
+                  2. VariableLengthComponent is connected from one side
+                    - Use previous case or:
+                    - Insert new component to empty end
+                    - Insert new VariableLength component to inserted components empty end
+                    
+                  3. VariableLength is not connected to any component.
+                    - Should not be possible, at least in current implementation.
+                    - Could be done using second case
+
+               */
+               
+               if (nextCP == null && prevCP == null) {
+                       // this should not be possible
+                       throw new RuntimeException("VariableLengthComponent " + splittingComponent + " is not connected to anything.");
+               }
+               double reservedLength = splittingComponent.getControlPoint().getLength();
+               double newLength = newComponent.getControlPoint().getLength();
+               
+               
+               Point3d next = new Point3d();
+               Point3d prev = new Point3d();
+               splittingCP.getInlineControlPointEnds(prev, next);
+               
+               Vector3d newPos = null;
+               if (assignPos) {
+                       newPos = new Vector3d(prev);
+                       Vector3d dir = new Vector3d(next);
+                       dir.sub(prev);
+                       dir.scale(0.5);
+                       newPos.add(dir);
+                       newComponent.setWorldPosition(newPos);
+               } else {
+                       newPos = newComponent.getWorldPosition();
+               }
+               
+               
+
+               Vector3d dir = new Vector3d(next);
+               dir.sub(prev);
+               dir.normalize();
+               dir.scale(newLength * 0.5);
+               Point3d vn = new Point3d(newPos);
+               Point3d vp = new Point3d(newPos);
+               vn.add(dir);
+               vp.sub(dir);
+               double ln = vn.distance(next);
+               double lp = vp.distance(prev);
+               vp.interpolate(prev, 0.5);
+               vn.interpolate(next, 0.5);
+               
+               
+               PipeControlPoint newVariableLengthCP = null;//insertStraight(pcp1, pcp2, pos, length);
+               if (nextCP == null) {
+                       newCP.insert(splittingCP, Direction.NEXT);
+                       newVariableLengthCP = insertStraight(newCP, Direction.NEXT, new Vector3d(vn), ln);
+                       splittingCP.setWorldPosition(new Vector3d(vp));
+//                     ControlPointTools.setWorldPosition(splittingCP, vp);
+//                     splittingCP.setRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength, lp);
+               } else if (prevCP == null) {
+                       newCP.insert(splittingCP, Direction.PREVIOUS);
+                       newVariableLengthCP = insertStraight(newCP, Direction.PREVIOUS, new Vector3d(vp), lp);
+                       splittingCP.setWorldPosition(new Vector3d(vn));
+//                     splittingCP.setRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength, ln);
+               } else {
+                       newCP.insert(splittingCP, nextCP);
+                       newVariableLengthCP = insertStraight(newCP, nextCP, new Vector3d(vn), ln);
+                       splittingCP.setWorldPosition(new Vector3d(vp));
+//                     splittingCP.setRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength, lp);
+               }
+               positionUpdate(newCP);
+
+       }
+       
+       public static void addSizeChange(boolean reversed, PipeRun pipeRun, PipeRun other, InlineComponent reducer, PipeControlPoint previous, PipeControlPoint next) {
+               PipeControlPoint pcp = reducer.getControlPoint();
+               PipeControlPoint ocp = pcp.getSubPoint().get(0);
+               if (!reversed) {
+                       String name = pipeRun.getUniqueName("Reducer");
+                       reducer.setName(name);
+                       pipeRun.addChild(reducer);
+                       other.addChild(ocp);
+                       reducer.setAlternativePipeRun(other);
+                       
+                       previous.setNext(pcp);
+                       pcp.setPrevious(previous);
+                       ocp.setPrevious(previous);
+                       if (next != null) {
+                               pcp.setNext(next);
+                               ocp.setNext(next);
+                               next.setPrevious(ocp);
+                       }
+               } else {
+                       String name = other.getUniqueName("Reducer");
+                       reducer.setName(name);
+                       other.addChild(reducer);
+                       pipeRun.addChild(ocp);
+                       reducer.setAlternativePipeRun(pipeRun);
+                       
+                       if (next != null) {
+                               next.setNext(pcp);
+                               pcp.setPrevious(next);
+                               ocp.setPrevious(next);
+                       }
+                       pcp.setNext(previous);
+                       ocp.setNext(previous);
+                       previous.setPrevious(ocp);
+               }
+       }
+}
diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/utils/ComponentUtils.java b/org.simantics.plant3d/src/org/simantics/plant3d/utils/ComponentUtils.java
new file mode 100644 (file)
index 0000000..af64f18
--- /dev/null
@@ -0,0 +1,154 @@
+package org.simantics.plant3d.utils;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.simantics.Simantics;
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.common.request.ReadRequest;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.layer0.Layer0;
+import org.simantics.opencascade.SolidModelProvider;
+import org.simantics.plant3d.ontology.Plant3D;
+import org.simantics.plant3d.scenegraph.EndComponent;
+import org.simantics.plant3d.scenegraph.InlineComponent;
+import org.simantics.plant3d.scenegraph.Nozzle;
+import org.simantics.plant3d.scenegraph.P3DRootNode;
+import org.simantics.plant3d.scenegraph.PipelineComponent;
+import org.simantics.plant3d.scenegraph.TurnComponent;
+
+public class ComponentUtils {
+
+       
+       private static Map<String,Class<? extends PipelineComponent>> clazzes = new HashMap<String, Class<? extends PipelineComponent>>();
+       private static Map<String,SolidModelProvider> providers = new HashMap<String,SolidModelProvider>();
+       
+       public static void preloadCache() {
+               Simantics.getSession().asyncRequest(new ReadRequest() {
+                       
+                       @Override
+                       public void run(ReadGraph graph) throws DatabaseException {
+                               List<String> types = new ArrayList<String>();
+                               types.add(Plant3D.URIs.Builtin_Straight);
+                               types.add(Plant3D.URIs.Builtin_Elbow);
+                               types.add(Plant3D.URIs.Builtin_ConcentricReducer);
+                               types.add(Plant3D.URIs.Builtin_BranchSplitComponent);
+//                             types.add(Plant3D.URIs.Builtin_EccentricReducer);
+                               
+                               for (String typeURI : types) {
+                                       load(graph, typeURI);
+                               }
+                       }
+               });
+       }
+       
+       private static SolidModelProvider getProvider(ReadGraph graph, Resource type) throws DatabaseException {
+               
+               Layer0 l0 = Layer0.getInstance(graph);
+               Plant3D p3d = Plant3D.getInstance(graph);
+               Resource geom = graph.getPossibleObject(type,p3d.hasGeometry);
+               if (geom == null) {
+                       for (Resource a : graph.getObjects(type, l0.Asserts)) {
+                               if (p3d.hasGeometry.equals(graph.getPossibleObject(a, l0.HasPredicate))) {
+                                       geom = graph.getPossibleObject(a, l0.HasObject);
+                                       break;
+                               }
+                       }
+               }
+               if (geom != null) {
+                       SolidModelProvider provider = graph.adapt(geom, SolidModelProvider.class);
+                       return provider;
+               }
+               return null;
+       }
+       
+       private static Class<? extends PipelineComponent> getClazz(ReadGraph graph, Resource type) throws DatabaseException {
+               Plant3D p3d = Plant3D.getInstance(graph);
+               if (graph.isInheritedFrom(type, p3d.InlineComponent))
+                       return InlineComponent.class;
+               if (graph.isInheritedFrom(type, p3d.TurnComponent))
+                       return TurnComponent.class;
+               if (graph.isInheritedFrom(type, p3d.EndComponent))
+                       return EndComponent.class;
+               if (graph.isInheritedFrom(type, p3d.Nozzle))
+                       return Nozzle.class;
+               return null;
+       }
+       
+       private static void load(ReadGraph graph, String typeURI) throws DatabaseException {
+               Plant3D p3d = Plant3D.getInstance(graph);
+               Resource type = graph.getResource(typeURI);
+               
+               SolidModelProvider provider = getProvider(graph, type);
+               if (provider != null || graph.hasStatement(type,p3d.NonVisibleComponent)) {
+                       providers.put(typeURI, provider);
+                       ComponentUtils.clazzes.put(typeURI,getClazz(graph, type));
+                       return;
+               }
+               throw new DatabaseException("Cannot find component for " + typeURI);
+       }
+       
+       private static void load(final String typeURI) throws DatabaseException {
+               Simantics.getSession().syncRequest(new ReadRequest() {
+                       
+                       @Override
+                       public void run(ReadGraph graph) throws DatabaseException {
+                               load(graph,typeURI);    
+                       }
+               });
+       }
+       
+       public static PipelineComponent createComponent(P3DRootNode root, String typeURI) throws Exception {
+               Class<? extends PipelineComponent> type = clazzes.get(typeURI);
+               SolidModelProvider provider = providers.get(typeURI);
+               if (type == null || provider == null) {
+                       load(typeURI);
+                       type = clazzes.get(typeURI);
+                       provider = providers.get(typeURI);
+               }
+               //PipelineComponent component = type.newInstance();
+               PipelineComponent component = null;
+               if (type == InlineComponent.class) {
+                       component = root.createInline();
+               } else if (type == TurnComponent.class) {
+                       component = root.createTurn();
+               } else if (type == EndComponent.class) {
+                       component = root.createTurn();
+               } else if (type == Nozzle.class) {
+                       component = root.createNozzle();
+               }
+               component.setType(typeURI);
+               component.setGeometry(provider);
+               return component;
+       }
+       
+       public static InlineComponent createStraight(P3DRootNode root) throws Exception{
+               InlineComponent component = root.createInline();
+               component.setType(Plant3D.URIs.Builtin_Straight);
+               component.setGeometry(providers.get(Plant3D.URIs.Builtin_Straight));
+               return component;
+       }
+       
+       public static TurnComponent createTurn(P3DRootNode root) throws Exception {
+               TurnComponent elbow = root.createTurn();
+               elbow.setType(Plant3D.URIs.Builtin_Elbow);
+               elbow.setGeometry(providers.get(Plant3D.URIs.Builtin_Elbow));
+               return elbow;
+       }
+       
+       public static InlineComponent createReducer(P3DRootNode root) throws Exception {
+               InlineComponent component = root.createInline();
+               component.setType(Plant3D.URIs.Builtin_ConcentricReducer);
+               component.setGeometry(providers.get(Plant3D.URIs.Builtin_ConcentricReducer));
+               return component;
+       }
+       
+       public static InlineComponent createBranchSplit(P3DRootNode root) throws Exception {
+               InlineComponent component = root.createInline();
+               component.setType(Plant3D.URIs.Builtin_BranchSplitComponent);
+               return component;
+       }
+}
diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/utils/Item.java b/org.simantics.plant3d/src/org/simantics/plant3d/utils/Item.java
new file mode 100644 (file)
index 0000000..61ef6c9
--- /dev/null
@@ -0,0 +1,79 @@
+package org.simantics.plant3d.utils;
+
+public class Item {
+       
+       public enum Type{EQUIPMENT,INLINE,TURN,END,NOZZLE};
+       
+       private String uri;
+       private String name;
+       
+       private Type type;
+       private boolean code = false;
+       private boolean variable = false;
+       private boolean sizeChange = false;
+
+       
+       public Item(String type, String name) {
+               this.uri = type;
+               this.name = name;
+       }
+       
+       
+       
+       public String getUri() {
+               return uri;
+       }
+       
+       public String getName() {
+               return name;
+       }
+       
+       public Type getType() {
+               return type;
+       }
+       
+       public void setType(Type type) {
+               this.type = type;
+       }
+       
+       public boolean isCode() {
+               return code;
+       }
+
+
+
+       public void setCode(boolean code) {
+               this.code = code;
+       }
+       
+       public boolean isVariable() {
+               return variable;
+       }
+       
+       public void setVariable(boolean variable) {
+               this.variable = variable;
+       }
+       
+       public boolean isSizeChange() {
+               return sizeChange;
+       }
+       
+       public void setSizeChange(boolean sizeChange) {
+               this.sizeChange = sizeChange;
+       }
+
+
+
+       @Override
+       public boolean equals(Object obj) {
+               if (obj.getClass() != getClass())
+                       return false;
+               return uri.equals(((Item)obj).uri);
+       }
+       
+       @Override
+       public int hashCode() {
+               return uri.hashCode();
+       }
+
+}
diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/utils/P3DUtil.java b/org.simantics.plant3d/src/org/simantics/plant3d/utils/P3DUtil.java
new file mode 100644 (file)
index 0000000..b34f4f0
--- /dev/null
@@ -0,0 +1,162 @@
+package org.simantics.plant3d.utils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.simantics.Simantics;
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.WriteGraph;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.request.Read;
+import org.simantics.layer0.Layer0;
+import org.simantics.plant3d.ontology.Plant3D;
+import org.simantics.plant3d.utils.Item.Type;
+import org.simantics.ui.SimanticsUI;
+
+public class P3DUtil {
+       
+       public static List<Item> getEquipments() throws DatabaseException {
+               return Simantics.getSession().syncRequest(new Read<List<Item>>() {
+                       @Override
+                       public List<Item> perform(ReadGraph graph) throws DatabaseException {
+                               Plant3D p3d = Plant3D.getInstance(graph);
+                               Resource project = Simantics.getProject().get();
+                               Resource builtins = graph.getResource(Plant3D.URIs.Builtin);
+                               List<Item> actions = getItems(graph, project,p3d.Equipment);
+                               actions.addAll(getItems(graph, builtins,p3d.Equipment));
+                               return actions;
+                       }
+                       
+                       
+               });
+       }
+       
+       public static List<Item> getNozzles() throws DatabaseException {
+               return Simantics.getSession().syncRequest(new Read<List<Item>>() {
+                       @Override
+                       public List<Item> perform(ReadGraph graph) throws DatabaseException {
+                               Plant3D p3d = Plant3D.getInstance(graph);
+                               ItemQuery query = new ItemQuery(p3d.Nozzle);
+                               return graph.syncRequest(query);
+                       }
+               });
+       }
+       
+       private static class ItemQuery implements Read<List<Item>> {
+               private Resource type;
+               public ItemQuery(Resource type) {
+                       this.type = type;
+               }
+               
+               @Override
+               public List<Item> perform(ReadGraph graph) throws DatabaseException {
+                       Resource project = Simantics.getProject().get();
+                       Resource builtins = graph.getResource(Plant3D.URIs.Builtin);
+                       List<Item> actions = getItems(graph, project,type);
+                       actions.addAll(getItems(graph, builtins,type));
+                       return actions;
+               }
+       }
+       
+       public static List<Item> getEnds() throws DatabaseException {
+               return Simantics.getSession().syncRequest(new Read<List<Item>>() {
+                       @Override
+                       public List<Item> perform(ReadGraph graph) throws DatabaseException {
+                               Plant3D p3d = Plant3D.getInstance(graph);
+                               ItemQuery query = new ItemQuery(p3d.EndComponent);
+                               return graph.syncRequest(query);
+                       }
+               });
+       }
+       
+       public static List<Item> getTurns() throws DatabaseException {
+               return Simantics.getSession().syncRequest(new Read<List<Item>>() {
+                       @Override
+                       public List<Item> perform(ReadGraph graph) throws DatabaseException {
+                               Plant3D p3d = Plant3D.getInstance(graph);
+                               ItemQuery query = new ItemQuery(p3d.TurnComponent);
+                               return graph.syncRequest(query);
+                       }
+               });
+       }
+       
+       public static List<Item> getInlines() throws DatabaseException {
+               return Simantics.getSession().syncRequest(new Read<List<Item>>() {
+                       @Override
+                       public List<Item> perform(ReadGraph graph) throws DatabaseException {
+                               Plant3D p3d = Plant3D.getInstance(graph);
+                               ItemQuery query = new ItemQuery(p3d.InlineComponent);
+                               return graph.syncRequest(query);
+                       }
+               });
+       }
+       
+       private static List<Item> getItems(ReadGraph graph, Resource lib, Resource type) throws DatabaseException{
+               Plant3D p3d = Plant3D.getInstance(graph);
+               Layer0 l0 = Layer0.getInstance(graph);
+               List<Item> result = new ArrayList<Item>();
+               for (Resource r : graph.getObjects(lib, l0.ConsistsOf)) {
+                       if (graph.isInstanceOf(r, type) ) {
+                               Resource geom = graph.getPossibleObject(r,p3d.hasGeometry);
+                               if (geom != null || graph.hasStatement(r,p3d.NonVisibleComponent)) {
+                                       
+                                       result.add(createItem(graph, r));
+                               }
+                       } 
+                       if (graph.isInheritedFrom(r, type)) {
+                               boolean asserts = false;
+                               for (Resource a : graph.getObjects(r, l0.Asserts)) {
+                                       if (p3d.hasGeometry.equals(graph.getPossibleObject(a, l0.HasPredicate))) {
+                                               asserts = true;
+                                               break;
+                                       }
+                               }
+                               if (asserts) {          
+                                       result.add(createItem(graph, r));
+                               }
+                       }
+               }
+               return result;
+       }
+       
+       private static Item createItem(ReadGraph graph, Resource r) throws DatabaseException {
+               Layer0 l0 = Layer0.getInstance(graph);
+               Plant3D p3d = Plant3D.getInstance(graph);
+               String name = graph.getRelatedValue(r, l0.HasName);
+               String uri = graph.getURI(r);
+               Item item = new Item(uri, name);
+               if (graph.isInstanceOf(r, p3d.Equipment))
+                       item.setType(Type.EQUIPMENT);
+               else if (graph.isInstanceOf(r, p3d.InlineComponent))
+                       item.setType(Type.INLINE);
+               else if (graph.isInstanceOf(r, p3d.EndComponent))
+                       item.setType(Type.END);
+               else if (graph.isInstanceOf(r, p3d.TurnComponent))
+                       item.setType(Type.TURN);
+               else if (graph.isInstanceOf(r, p3d.Nozzle))
+                       item.setType(Type.NOZZLE);
+               else 
+                       throw new RuntimeException("Cannot detect type for " + r);
+               
+               if (graph.hasStatement(r, p3d.CodeComponent))
+                       item.setCode(true);
+               if (graph.hasStatement(r, p3d.VariableAngleTurnComponent) ||
+                   graph.hasStatement(r, p3d.VariableLengthInlineComponent))
+                       item.setVariable(true);
+               if (graph.hasStatement(r, p3d.SizeChangeComponent))
+                       item.setSizeChange(true);
+               return item;
+       }
+       
+       public static Resource createModel(WriteGraph graph, String name) throws DatabaseException{
+               Layer0 l0 = Layer0.getInstance(graph);
+               Plant3D p3d = Plant3D.getInstance(graph);
+               Resource model = graph.newResource();
+               graph.claim(model, l0.InstanceOf, p3d.Plant);
+               graph.claimLiteral(model, l0.HasName, name);
+               
+               return model;
+       }
+
+}