From: luukkainen Date: Mon, 29 Sep 2008 11:10:38 +0000 (+0000) Subject: latest release (0.41), third attempt X-Git-Tag: simantics-1.19.0~21 X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=commitdiff_plain;h=f9ce67e72c8bebd4683d49a1ac5fa99aacdfa6db;p=simantics%2F3d.git latest release (0.41), third attempt git-svn-id: https://www.simantics.org/svn/simantics/3d/trunk@6851 ac1ea38d-2e2b-0410-8846-a27921b304fc --- diff --git a/org.simantics.proconf.processeditor/.classpath b/org.simantics.proconf.processeditor/.classpath new file mode 100644 index 00000000..02159672 --- /dev/null +++ b/org.simantics.proconf.processeditor/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/org.simantics.proconf.processeditor/.project b/org.simantics.proconf.processeditor/.project new file mode 100644 index 00000000..4f2fb460 --- /dev/null +++ b/org.simantics.proconf.processeditor/.project @@ -0,0 +1,28 @@ + + + org.simantics.proconf.processeditor + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/org.simantics.proconf.processeditor/META-INF/MANIFEST.MF b/org.simantics.proconf.processeditor/META-INF/MANIFEST.MF new file mode 100644 index 00000000..2c2e6e9d --- /dev/null +++ b/org.simantics.proconf.processeditor/META-INF/MANIFEST.MF @@ -0,0 +1,26 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Processeditor Plug-in +Bundle-SymbolicName: fi.vtt.simantics.processeditor;singleton:=true +Bundle-Version: 1.0.0 +Bundle-Activator: fi.vtt.simantics.processeditor.Activator +Bundle-Vendor: VTT +Require-Bundle: org.eclipse.ui, + org.eclipse.core.runtime, + com.jme.eclipse, + org.simantics.g2d.stubs, + org.simantics.proconf.ui, + org.simantics.proconf.g3d, + org.simantics.proconf.image, + org.simantics.layer0.stubs, + org.simantics.layer0.utils, + org.simantics.utils, + org.simantics.utils.datastructures, + javax.vecmath, + org.simantics.proconf.ode, + org.simantics.proconf.browsing, + org.simantics.utils.ui, + org.simantics.utils.ui.workbench, + org.simantics.proconf.g3d.shapeeditor, + org.eclipse.ui.views +Eclipse-LazyStart: true diff --git a/org.simantics.proconf.processeditor/build.properties b/org.simantics.proconf.processeditor/build.properties new file mode 100644 index 00000000..6f20375d --- /dev/null +++ b/org.simantics.proconf.processeditor/build.properties @@ -0,0 +1,5 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + plugin.xml diff --git a/org.simantics.proconf.processeditor/data/dcp.mtl b/org.simantics.proconf.processeditor/data/dcp.mtl new file mode 100644 index 00000000..e30d811c --- /dev/null +++ b/org.simantics.proconf.processeditor/data/dcp.mtl @@ -0,0 +1,2 @@ +# Blender3D MTL File: dcp.blend +# Material Count: 0 diff --git a/org.simantics.proconf.processeditor/data/dcp.obj b/org.simantics.proconf.processeditor/data/dcp.obj new file mode 100644 index 00000000..8b19e699 --- /dev/null +++ b/org.simantics.proconf.processeditor/data/dcp.obj @@ -0,0 +1,476 @@ +# Blender v242 OBJ File: dcp.blend +# www.blender3d.org +mtllib dcp.mtl +o Sphere_Sphere +v 0.092388 -0.000000 -0.038268 +v -0.092388 0.014645 -0.035355 +v -0.070711 0.027060 -0.065328 +v -0.038268 0.035355 -0.085355 +v 0.000000 0.038268 -0.092388 +v 0.038268 0.035355 -0.085355 +v 0.070711 0.027060 -0.065328 +v 0.092388 0.014645 -0.035355 +v 0.092388 0.027060 -0.027060 +v 0.070711 0.050000 -0.050000 +v 0.038268 0.065328 -0.065328 +v 0.000000 0.070711 -0.070711 +v -0.038268 0.065328 -0.065328 +v -0.070711 0.050000 -0.050000 +v -0.092388 0.027060 -0.027060 +v -0.092388 0.035355 -0.014645 +v -0.070711 0.065328 -0.027060 +v -0.038268 0.085355 -0.035355 +v 0.000000 0.092388 -0.038268 +v 0.038268 0.085355 -0.035355 +v 0.070711 0.065328 -0.027060 +v 0.092388 0.035355 -0.014645 +v 0.092388 0.038268 0.000000 +v 0.070711 0.070711 0.000000 +v 0.038268 0.092388 0.000000 +v 0.000000 0.100000 0.000000 +v -0.038268 0.092388 -0.000000 +v -0.070711 0.070711 -0.000000 +v -0.092388 0.038268 -0.000000 +v -0.092388 0.035355 0.014645 +v -0.070711 0.065328 0.027060 +v -0.038268 0.085355 0.035355 +v 0.000000 0.092388 0.038268 +v 0.038268 0.085355 0.035355 +v 0.070711 0.065328 0.027060 +v 0.092388 0.035355 0.014645 +v 0.092388 0.027060 0.027060 +v 0.070711 0.050000 0.050000 +v 0.038268 0.065328 0.065328 +v 0.000000 0.070711 0.070711 +v -0.038268 0.065328 0.065328 +v -0.070711 0.050000 0.050000 +v -0.092388 0.027060 0.027060 +v -0.092388 0.014645 0.035355 +v -0.070711 0.027060 0.065328 +v -0.038268 0.035355 0.085355 +v -0.000000 0.038268 0.092388 +v 0.038268 0.035355 0.085355 +v 0.070711 0.027060 0.065328 +v 0.092388 0.014645 0.035355 +v 0.092388 -0.000000 0.038268 +v 0.070711 -0.000000 0.070711 +v 0.038268 -0.000000 0.092388 +v -0.000000 0.000000 0.100000 +v -0.038268 -0.000000 0.092388 +v -0.070711 -0.000000 0.070711 +v -0.092388 0.000000 0.038268 +v -0.092388 -0.014645 0.035355 +v -0.070711 -0.027060 0.065328 +v -0.038268 -0.035355 0.085355 +v -0.000000 -0.038268 0.092388 +v 0.038268 -0.035355 0.085355 +v 0.070711 -0.027060 0.065328 +v 0.092388 -0.014645 0.035355 +v 0.092388 -0.027060 0.027060 +v 0.070711 -0.050000 0.050000 +v 0.038268 -0.065328 0.065328 +v -0.000000 -0.070711 0.070711 +v -0.038268 -0.065328 0.065328 +v -0.070711 -0.050000 0.050000 +v -0.092388 -0.027060 0.027060 +v -0.100000 -0.000000 0.000000 +v -0.092388 -0.035355 0.014645 +v -0.070711 -0.065328 0.027060 +v -0.038268 -0.085355 0.035355 +v -0.000000 -0.092388 0.038268 +v 0.038268 -0.085355 0.035355 +v 0.070711 -0.065328 0.027060 +v 0.092388 -0.035355 0.014645 +v 0.092388 -0.038268 0.000000 +v 0.070711 -0.070711 0.000000 +v 0.038268 -0.092388 0.000000 +v 0.000000 -0.100000 0.000000 +v -0.038268 -0.092388 -0.000000 +v -0.070711 -0.070711 -0.000000 +v -0.092388 -0.038268 -0.000000 +v -0.092388 -0.035355 -0.014645 +v -0.070711 -0.065328 -0.027060 +v -0.038268 -0.085355 -0.035355 +v 0.000000 -0.092388 -0.038268 +v 0.038268 -0.085355 -0.035355 +v 0.070711 -0.065328 -0.027060 +v 0.092388 -0.035355 -0.014645 +v 0.092388 -0.027060 -0.027060 +v 0.070711 -0.050000 -0.050000 +v 0.038268 -0.065328 -0.065328 +v 0.000000 -0.070711 -0.070711 +v -0.038268 -0.065328 -0.065328 +v -0.070711 -0.050000 -0.050000 +v -0.092388 -0.027060 -0.027060 +v -0.092388 -0.014645 -0.035355 +v -0.070711 -0.027060 -0.065328 +v -0.038268 -0.035355 -0.085355 +v 0.000000 -0.038268 -0.092388 +v 0.038268 -0.035355 -0.085355 +v 0.070711 -0.027060 -0.065328 +v 0.092388 -0.014645 -0.035355 +v 0.070711 0.000000 -0.070711 +v 0.038268 0.000000 -0.092388 +v 0.000000 0.000000 -0.100000 +v -0.038268 0.000000 -0.092388 +v -0.070711 0.000000 -0.070711 +v -0.092388 0.000000 -0.038268 +v 0.232388 -0.014645 -0.035355 +v 0.232388 -0.027060 -0.027060 +v 0.232388 -0.035355 -0.014645 +v 0.232388 -0.038268 0.000000 +v 0.232388 -0.035355 0.014645 +v 0.232388 -0.027060 0.027060 +v 0.232388 -0.014645 0.035355 +v 0.232388 -0.000000 0.038268 +v 0.232388 0.014645 0.035355 +v 0.232388 0.027060 0.027060 +v 0.232388 0.035355 0.014645 +v 0.232388 0.038268 0.000000 +v 0.232388 0.035355 -0.014645 +v 0.232388 0.027060 -0.027060 +v 0.232388 0.014645 -0.035355 +v 0.232388 -0.000000 -0.038268 +v 0.231045 -0.000000 -0.153073 +v 0.231045 0.058579 -0.141421 +v 0.511493 -0.000000 0.000000 +v 0.231045 0.108239 -0.108239 +v 0.231045 0.141421 -0.058579 +v 0.231045 0.153073 0.000000 +v 0.231045 0.141421 0.058579 +v 0.231045 0.108239 0.108239 +v 0.231045 0.058579 0.141421 +v 0.231045 -0.000000 0.153073 +v 0.231045 -0.058579 0.141421 +v 0.231045 -0.108239 0.108239 +v 0.231045 -0.141421 0.058579 +v 0.231045 -0.153073 0.000000 +v 0.231045 -0.141421 -0.058579 +v 0.231045 -0.108239 -0.108239 +v 0.231045 -0.058579 -0.141421 +vn -0.999929 -0.002325 0.011699 +vn -0.999929 -0.006629 0.009917 +vn -0.999929 -0.009918 0.006627 +vn -0.999929 -0.011699 0.002327 +vn -0.999929 -0.011699 -0.002327 +vn -0.999929 -0.009918 -0.006627 +vn -0.999929 -0.006627 -0.009918 +vn -0.999929 -0.002327 -0.011699 +vn -0.999929 0.002327 -0.011699 +vn -0.999929 0.006627 -0.009918 +vn -0.999929 0.009918 -0.006627 +vn -0.999929 0.011699 -0.002327 +vn -0.999929 0.011699 0.002327 +vn -0.999929 0.009918 0.006627 +vn -0.999929 0.006627 0.009918 +vn -0.999929 0.002327 0.011699 +vn -1.000000 0.000000 0.000000 +vn -0.924070 0.146245 -0.353099 +vn -0.924070 0.000000 -0.382183 +vn -0.707602 0.270394 -0.652791 +vn -0.707602 0.000000 -0.706565 +vn -0.383129 0.353465 -0.853359 +vn -0.383129 0.000000 -0.923673 +vn 0.000000 0.382672 -0.923856 +vn 0.000000 0.000000 -1.000000 +vn 0.383129 0.353465 -0.853359 +vn 0.383129 0.000000 -0.923673 +vn 0.707602 0.270394 -0.652791 +vn 0.707602 0.000000 -0.706565 +vn 0.474532 0.336833 -0.813227 +vn 0.474532 0.000000 -0.880215 +vn 0.707602 0.499619 -0.499619 +vn 0.474532 0.622395 -0.622395 +vn 0.383129 0.653127 -0.653127 +vn 0.000000 0.707083 -0.707083 +vn -0.383129 0.653127 -0.653127 +vn -0.707602 0.499619 -0.499619 +vn -0.924070 0.270241 -0.270241 +vn -0.924070 0.353099 -0.146245 +vn -0.707602 0.652791 -0.270394 +vn -0.383129 0.853359 -0.353465 +vn 0.000000 0.923856 -0.382672 +vn 0.383129 0.853359 -0.353465 +vn 0.707602 0.652791 -0.270394 +vn 0.474532 0.813227 -0.336833 +vn 0.707602 0.706565 0.000000 +vn 0.474532 0.880215 0.000000 +vn 0.383129 0.923673 0.000000 +vn 0.000000 1.000000 0.000000 +vn -0.383129 0.923673 0.000000 +vn -0.707602 0.706565 0.000000 +vn -0.924070 0.382183 0.000000 +vn -0.924070 0.353099 0.146245 +vn -0.707602 0.652791 0.270394 +vn -0.383129 0.853359 0.353465 +vn 0.000000 0.923856 0.382672 +vn 0.383129 0.853359 0.353465 +vn 0.707602 0.652791 0.270394 +vn 0.474532 0.813227 0.336833 +vn 0.707602 0.499619 0.499619 +vn 0.474532 0.622395 0.622395 +vn 0.383129 0.653127 0.653127 +vn 0.000000 0.707083 0.707083 +vn -0.383129 0.653127 0.653127 +vn -0.707602 0.499619 0.499619 +vn -0.924070 0.270241 0.270241 +vn -0.924070 0.146245 0.353099 +vn -0.707602 0.270394 0.652791 +vn -0.383129 0.353465 0.853359 +vn 0.000000 0.382672 0.923856 +vn 0.383129 0.353465 0.853359 +vn 0.707602 0.270394 0.652791 +vn 0.474532 0.336833 0.813227 +vn 0.707602 0.000000 0.706565 +vn 0.474532 0.000000 0.880215 +vn 0.383129 0.000000 0.923673 +vn 0.000000 0.000000 1.000000 +vn -0.383129 0.000000 0.923673 +vn -0.707602 0.000000 0.706565 +vn -0.924070 0.000000 0.382183 +vn -0.924070 -0.146245 0.353099 +vn -0.707602 -0.270394 0.652791 +vn -0.383129 -0.353465 0.853359 +vn 0.000000 -0.382672 0.923856 +vn 0.383129 -0.353465 0.853359 +vn 0.707602 -0.270394 0.652791 +vn 0.474532 -0.336833 0.813227 +vn 0.707602 -0.499619 0.499619 +vn 0.474532 -0.622395 0.622395 +vn 0.383129 -0.653127 0.653127 +vn 0.000000 -0.707083 0.707083 +vn -0.383129 -0.653127 0.653127 +vn -0.707602 -0.499619 0.499619 +vn -0.924070 -0.270241 0.270241 +vn -0.924070 -0.353099 0.146245 +vn -0.707602 -0.652791 0.270394 +vn -0.383129 -0.853359 0.353465 +vn 0.000000 -0.923856 0.382672 +vn 0.383129 -0.853359 0.353465 +vn 0.707602 -0.652791 0.270394 +vn 0.474532 -0.813227 0.336833 +vn 0.707602 -0.706565 0.000000 +vn 0.474532 -0.880215 0.000000 +vn 0.383129 -0.923673 0.000000 +vn 0.000000 -1.000000 0.000000 +vn -0.383129 -0.923673 0.000000 +vn -0.707602 -0.706565 0.000000 +vn -0.924070 -0.382183 0.000000 +vn -0.924070 -0.353099 -0.146245 +vn -0.707602 -0.652791 -0.270394 +vn -0.383129 -0.853359 -0.353465 +vn 0.000000 -0.923856 -0.382672 +vn 0.383129 -0.853359 -0.353465 +vn 0.707602 -0.652791 -0.270394 +vn 0.474532 -0.813227 -0.336833 +vn 0.707602 -0.499619 -0.499619 +vn 0.474532 -0.622395 -0.622395 +vn 0.383129 -0.653127 -0.653127 +vn 0.000000 -0.707083 -0.707083 +vn -0.383129 -0.653127 -0.653127 +vn -0.707602 -0.499619 -0.499619 +vn -0.924070 -0.270241 -0.270241 +vn -0.924070 -0.146245 -0.353099 +vn -0.707602 -0.270394 -0.652791 +vn -0.383129 -0.353465 -0.853359 +vn 0.000000 -0.382672 -0.923856 +vn 0.383129 -0.353465 -0.853359 +vn 0.707602 -0.270394 -0.652791 +vn 0.474532 -0.336833 -0.813227 +vn -0.718070 0.000000 -0.695944 +vn -0.718070 -0.266305 -0.642964 +vn -0.718070 -0.492080 -0.492080 +vn -0.718070 -0.642964 -0.266305 +vn -0.718070 -0.695944 0.000000 +vn -0.718070 -0.642964 0.266305 +vn -0.718070 -0.492080 0.492080 +vn -0.718070 -0.266305 0.642964 +vn -0.718070 0.000000 0.695944 +vn -0.718070 0.266305 0.642964 +vn -0.718070 0.492080 0.492080 +vn -0.718070 0.642964 0.266305 +vn -0.718070 0.695944 0.000000 +vn -0.718070 0.642964 -0.266305 +vn -0.718070 0.492080 -0.492080 +vn -0.718070 0.266305 -0.642964 +vn -0.526292 0.000000 -0.850276 +vn -0.526292 0.325388 -0.785546 +vn 1.000000 0.000000 0.000000 +vn -0.526292 0.601245 -0.601245 +vn -0.526292 0.785546 -0.325388 +vn -0.526292 0.850276 0.000000 +vn -0.526292 0.785546 0.325388 +vn -0.526292 0.601245 0.601245 +vn -0.526292 0.325388 0.785546 +vn -0.526292 0.000000 0.850276 +vn -0.526292 -0.325388 0.785546 +vn -0.526292 -0.601245 0.601245 +vn -0.526292 -0.785546 0.325388 +vn -0.526292 -0.850276 0.000000 +vn -0.526292 -0.785546 -0.325388 +vn -0.526292 -0.601245 -0.601245 +vn -0.526292 -0.325388 -0.785546 +usemtl (null) +usemtl (null) +s off +f 129//1 128//1 131//1 130//1 +f 128//2 127//2 133//2 131//2 +f 127//3 126//3 134//3 133//3 +f 126//4 125//4 135//4 134//4 +f 125//5 124//5 136//5 135//5 +f 124//6 123//6 137//6 136//6 +f 123//7 122//7 138//7 137//7 +f 122//8 121//8 139//8 138//8 +f 121//9 120//9 140//9 139//9 +f 120//10 119//10 141//10 140//10 +f 119//11 118//11 142//11 141//11 +f 118//12 117//12 143//12 142//12 +f 117//13 116//13 144//13 143//13 +f 116//14 115//14 145//14 144//14 +f 115//15 114//15 146//15 145//15 +f 114//16 129//16 130//16 146//16 +s 1 +f 72//17 2//18 113//19 +f 113//19 2//18 3//20 112//21 +f 112//21 3//20 4//22 111//23 +f 111//23 4//22 5//24 110//25 +f 110//25 5//24 6//26 109//27 +f 109//27 6//26 7//28 108//29 +f 8//30 1//31 108//29 7//28 +f 7//28 10//32 9//33 8//30 +f 6//26 11//34 10//32 7//28 +f 5//24 12//35 11//34 6//26 +f 4//22 13//36 12//35 5//24 +f 3//20 14//37 13//36 4//22 +f 2//18 15//38 14//37 3//20 +f 72//17 15//38 2//18 +f 72//17 16//39 15//38 +f 15//38 16//39 17//40 14//37 +f 14//37 17//40 18//41 13//36 +f 13//36 18//41 19//42 12//35 +f 12//35 19//42 20//43 11//34 +f 11//34 20//43 21//44 10//32 +f 10//32 21//44 22//45 9//33 +f 21//44 24//46 23//47 22//45 +f 20//43 25//48 24//46 21//44 +f 19//42 26//49 25//48 20//43 +f 18//41 27//50 26//49 19//42 +f 17//40 28//51 27//50 18//41 +f 16//39 29//52 28//51 17//40 +f 72//17 29//52 16//39 +f 72//17 30//53 29//52 +f 29//52 30//53 31//54 28//51 +f 28//51 31//54 32//55 27//50 +f 27//50 32//55 33//56 26//49 +f 26//49 33//56 34//57 25//48 +f 25//48 34//57 35//58 24//46 +f 24//46 35//58 36//59 23//47 +f 35//58 38//60 37//61 36//59 +f 34//57 39//62 38//60 35//58 +f 33//56 40//63 39//62 34//57 +f 32//55 41//64 40//63 33//56 +f 31//54 42//65 41//64 32//55 +f 30//53 43//66 42//65 31//54 +f 72//17 43//66 30//53 +f 72//17 44//67 43//66 +f 43//66 44//67 45//68 42//65 +f 42//65 45//68 46//69 41//64 +f 41//64 46//69 47//70 40//63 +f 40//63 47//70 48//71 39//62 +f 39//62 48//71 49//72 38//60 +f 38//60 49//72 50//73 37//61 +f 49//72 52//74 51//75 50//73 +f 48//71 53//76 52//74 49//72 +f 47//70 54//77 53//76 48//71 +f 46//69 55//78 54//77 47//70 +f 45//68 56//79 55//78 46//69 +f 44//67 57//80 56//79 45//68 +f 72//17 57//80 44//67 +f 72//17 58//81 57//80 +f 57//80 58//81 59//82 56//79 +f 56//79 59//82 60//83 55//78 +f 55//78 60//83 61//84 54//77 +f 54//77 61//84 62//85 53//76 +f 53//76 62//85 63//86 52//74 +f 52//74 63//86 64//87 51//75 +f 63//86 66//88 65//89 64//87 +f 62//85 67//90 66//88 63//86 +f 61//84 68//91 67//90 62//85 +f 60//83 69//92 68//91 61//84 +f 59//82 70//93 69//92 60//83 +f 58//81 71//94 70//93 59//82 +f 72//17 71//94 58//81 +f 72//17 73//95 71//94 +f 71//94 73//95 74//96 70//93 +f 70//93 74//96 75//97 69//92 +f 69//92 75//97 76//98 68//91 +f 68//91 76//98 77//99 67//90 +f 67//90 77//99 78//100 66//88 +f 66//88 78//100 79//101 65//89 +f 78//100 81//102 80//103 79//101 +f 77//99 82//104 81//102 78//100 +f 76//98 83//105 82//104 77//99 +f 75//97 84//106 83//105 76//98 +f 74//96 85//107 84//106 75//97 +f 73//95 86//108 85//107 74//96 +f 72//17 86//108 73//95 +f 72//17 87//109 86//108 +f 86//108 87//109 88//110 85//107 +f 85//107 88//110 89//111 84//106 +f 84//106 89//111 90//112 83//105 +f 83//105 90//112 91//113 82//104 +f 82//104 91//113 92//114 81//102 +f 81//102 92//114 93//115 80//103 +f 92//114 95//116 94//117 93//115 +f 91//113 96//118 95//116 92//114 +f 90//112 97//119 96//118 91//113 +f 89//111 98//120 97//119 90//112 +f 88//110 99//121 98//120 89//111 +f 87//109 100//122 99//121 88//110 +f 72//17 100//122 87//109 +f 72//17 101//123 100//122 +f 100//122 101//123 102//124 99//121 +f 99//121 102//124 103//125 98//120 +f 98//120 103//125 104//126 97//119 +f 97//119 104//126 105//127 96//118 +f 96//118 105//127 106//128 95//116 +f 95//116 106//128 107//129 94//117 +f 1//31 107//129 106//128 108//29 +f 105//127 109//27 108//29 106//128 +f 104//126 110//25 109//27 105//127 +f 103//125 111//23 110//25 104//126 +f 102//124 112//21 111//23 103//125 +f 101//123 113//19 112//21 102//124 +f 72//17 113//19 101//123 +f 107//129 1//31 129//130 114//131 +f 94//117 107//129 114//131 115//132 +f 93//115 94//117 115//132 116//133 +f 80//103 93//115 116//133 117//134 +f 79//101 80//103 117//134 118//135 +f 65//89 79//101 118//135 119//136 +f 64//87 65//89 119//136 120//137 +f 51//75 64//87 120//137 121//138 +f 50//73 51//75 121//138 122//139 +f 37//61 50//73 122//139 123//140 +f 36//59 37//61 123//140 124//141 +f 23//47 36//59 124//141 125//142 +f 22//45 23//47 125//142 126//143 +f 9//33 22//45 126//143 127//144 +f 8//30 9//33 127//144 128//145 +f 1//31 8//30 128//145 129//130 +f 130//146 131//147 132//148 +f 131//147 133//149 132//148 +f 133//149 134//150 132//148 +f 134//150 135//151 132//148 +f 135//151 136//152 132//148 +f 136//152 137//153 132//148 +f 137//153 138//154 132//148 +f 138//154 139//155 132//148 +f 139//155 140//156 132//148 +f 140//156 141//157 132//148 +f 141//157 142//158 132//148 +f 142//158 143//159 132//148 +f 143//159 144//160 132//148 +f 144//160 145//161 132//148 +f 145//161 146//162 132//148 +f 146//162 130//146 132//148 diff --git a/org.simantics.proconf.processeditor/icons/Component.png b/org.simantics.proconf.processeditor/icons/Component.png new file mode 100644 index 00000000..0d43ef5b Binary files /dev/null and b/org.simantics.proconf.processeditor/icons/Component.png differ diff --git a/org.simantics.proconf.processeditor/icons/Component.svg b/org.simantics.proconf.processeditor/icons/Component.svg new file mode 100644 index 00000000..eaf30346 --- /dev/null +++ b/org.simantics.proconf.processeditor/icons/Component.svg @@ -0,0 +1,128 @@ + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/org.simantics.proconf.processeditor/icons/Elbow.png b/org.simantics.proconf.processeditor/icons/Elbow.png new file mode 100644 index 00000000..bbaa16ea Binary files /dev/null and b/org.simantics.proconf.processeditor/icons/Elbow.png differ diff --git a/org.simantics.proconf.processeditor/icons/Elbow.svg b/org.simantics.proconf.processeditor/icons/Elbow.svg new file mode 100644 index 00000000..611748ac --- /dev/null +++ b/org.simantics.proconf.processeditor/icons/Elbow.svg @@ -0,0 +1,127 @@ + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + diff --git a/org.simantics.proconf.processeditor/icons/Nozzle.png b/org.simantics.proconf.processeditor/icons/Nozzle.png new file mode 100644 index 00000000..48cf03e8 Binary files /dev/null and b/org.simantics.proconf.processeditor/icons/Nozzle.png differ diff --git a/org.simantics.proconf.processeditor/icons/Nozzle.svg b/org.simantics.proconf.processeditor/icons/Nozzle.svg new file mode 100644 index 00000000..0dd815c8 --- /dev/null +++ b/org.simantics.proconf.processeditor/icons/Nozzle.svg @@ -0,0 +1,110 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/org.simantics.proconf.processeditor/icons/Straight.png b/org.simantics.proconf.processeditor/icons/Straight.png new file mode 100644 index 00000000..459919e5 Binary files /dev/null and b/org.simantics.proconf.processeditor/icons/Straight.png differ diff --git a/org.simantics.proconf.processeditor/icons/Straight.svg b/org.simantics.proconf.processeditor/icons/Straight.svg new file mode 100644 index 00000000..117e6ec1 --- /dev/null +++ b/org.simantics.proconf.processeditor/icons/Straight.svg @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + diff --git a/org.simantics.proconf.processeditor/icons/bubble.png b/org.simantics.proconf.processeditor/icons/bubble.png new file mode 100644 index 00000000..410e2686 Binary files /dev/null and b/org.simantics.proconf.processeditor/icons/bubble.png differ diff --git a/org.simantics.proconf.processeditor/icons/bubble.svg b/org.simantics.proconf.processeditor/icons/bubble.svg new file mode 100644 index 00000000..f52235f8 --- /dev/null +++ b/org.simantics.proconf.processeditor/icons/bubble.svg @@ -0,0 +1,127 @@ + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + diff --git a/org.simantics.proconf.processeditor/icons/crosshair.png b/org.simantics.proconf.processeditor/icons/crosshair.png new file mode 100644 index 00000000..379424ea Binary files /dev/null and b/org.simantics.proconf.processeditor/icons/crosshair.png differ diff --git a/org.simantics.proconf.processeditor/icons/crosshair.svg b/org.simantics.proconf.processeditor/icons/crosshair.svg new file mode 100644 index 00000000..8c73e69d --- /dev/null +++ b/org.simantics.proconf.processeditor/icons/crosshair.svg @@ -0,0 +1,78 @@ + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/org.simantics.proconf.processeditor/icons/factory.png b/org.simantics.proconf.processeditor/icons/factory.png new file mode 100644 index 00000000..aad23e32 Binary files /dev/null and b/org.simantics.proconf.processeditor/icons/factory.png differ diff --git a/org.simantics.proconf.processeditor/icons/factory.svg b/org.simantics.proconf.processeditor/icons/factory.svg new file mode 100644 index 00000000..e05205cb --- /dev/null +++ b/org.simantics.proconf.processeditor/icons/factory.svg @@ -0,0 +1,308 @@ + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.simantics.proconf.processeditor/icons/middle.png b/org.simantics.proconf.processeditor/icons/middle.png new file mode 100644 index 00000000..4e3d03e7 Binary files /dev/null and b/org.simantics.proconf.processeditor/icons/middle.png differ diff --git a/org.simantics.proconf.processeditor/icons/middle.svg b/org.simantics.proconf.processeditor/icons/middle.svg new file mode 100644 index 00000000..670c3b42 --- /dev/null +++ b/org.simantics.proconf.processeditor/icons/middle.svg @@ -0,0 +1,190 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/org.simantics.proconf.processeditor/icons/plus.png b/org.simantics.proconf.processeditor/icons/plus.png new file mode 100644 index 00000000..1d6b816f Binary files /dev/null and b/org.simantics.proconf.processeditor/icons/plus.png differ diff --git a/org.simantics.proconf.processeditor/icons/plus.svg b/org.simantics.proconf.processeditor/icons/plus.svg new file mode 100644 index 00000000..7338a019 --- /dev/null +++ b/org.simantics.proconf.processeditor/icons/plus.svg @@ -0,0 +1,184 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/org.simantics.proconf.processeditor/icons/tank.png b/org.simantics.proconf.processeditor/icons/tank.png new file mode 100644 index 00000000..44015a37 Binary files /dev/null and b/org.simantics.proconf.processeditor/icons/tank.png differ diff --git a/org.simantics.proconf.processeditor/icons/tank.svg b/org.simantics.proconf.processeditor/icons/tank.svg new file mode 100644 index 00000000..8e8784f1 --- /dev/null +++ b/org.simantics.proconf.processeditor/icons/tank.svg @@ -0,0 +1,184 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/org.simantics.proconf.processeditor/icons/translate_d.png b/org.simantics.proconf.processeditor/icons/translate_d.png new file mode 100644 index 00000000..f4b3b608 Binary files /dev/null and b/org.simantics.proconf.processeditor/icons/translate_d.png differ diff --git a/org.simantics.proconf.processeditor/icons/translate_d.svg b/org.simantics.proconf.processeditor/icons/translate_d.svg new file mode 100644 index 00000000..16669294 --- /dev/null +++ b/org.simantics.proconf.processeditor/icons/translate_d.svg @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + diff --git a/org.simantics.proconf.processeditor/icons/x-axis.png b/org.simantics.proconf.processeditor/icons/x-axis.png new file mode 100644 index 00000000..8eb8a0d5 Binary files /dev/null and b/org.simantics.proconf.processeditor/icons/x-axis.png differ diff --git a/org.simantics.proconf.processeditor/icons/x-axis.svg b/org.simantics.proconf.processeditor/icons/x-axis.svg new file mode 100644 index 00000000..e5c2293f --- /dev/null +++ b/org.simantics.proconf.processeditor/icons/x-axis.svg @@ -0,0 +1,82 @@ + + + + + + + + + image/svg+xml + + + + + + + X + + + diff --git a/org.simantics.proconf.processeditor/icons/x-plane.png b/org.simantics.proconf.processeditor/icons/x-plane.png new file mode 100644 index 00000000..6b57f1ee Binary files /dev/null and b/org.simantics.proconf.processeditor/icons/x-plane.png differ diff --git a/org.simantics.proconf.processeditor/icons/x-plane.svg b/org.simantics.proconf.processeditor/icons/x-plane.svg new file mode 100644 index 00000000..316d3ce6 --- /dev/null +++ b/org.simantics.proconf.processeditor/icons/x-plane.svg @@ -0,0 +1,89 @@ + + + + + + + + + image/svg+xml + + + + + + + X + + + + diff --git a/org.simantics.proconf.processeditor/icons/y-axis.png b/org.simantics.proconf.processeditor/icons/y-axis.png new file mode 100644 index 00000000..ca60724b Binary files /dev/null and b/org.simantics.proconf.processeditor/icons/y-axis.png differ diff --git a/org.simantics.proconf.processeditor/icons/y-axis.svg b/org.simantics.proconf.processeditor/icons/y-axis.svg new file mode 100644 index 00000000..65eddcf5 --- /dev/null +++ b/org.simantics.proconf.processeditor/icons/y-axis.svg @@ -0,0 +1,83 @@ + + + + + + + + + image/svg+xml + + + + + + + Y + + + diff --git a/org.simantics.proconf.processeditor/icons/y-plane.png b/org.simantics.proconf.processeditor/icons/y-plane.png new file mode 100644 index 00000000..59c3a2bb Binary files /dev/null and b/org.simantics.proconf.processeditor/icons/y-plane.png differ diff --git a/org.simantics.proconf.processeditor/icons/y-plane.svg b/org.simantics.proconf.processeditor/icons/y-plane.svg new file mode 100644 index 00000000..69d38142 --- /dev/null +++ b/org.simantics.proconf.processeditor/icons/y-plane.svg @@ -0,0 +1,89 @@ + + + + + + + + + image/svg+xml + + + + + + + Y + + + + diff --git a/org.simantics.proconf.processeditor/icons/z-axis.png b/org.simantics.proconf.processeditor/icons/z-axis.png new file mode 100644 index 00000000..11a57417 Binary files /dev/null and b/org.simantics.proconf.processeditor/icons/z-axis.png differ diff --git a/org.simantics.proconf.processeditor/icons/z-axis.svg b/org.simantics.proconf.processeditor/icons/z-axis.svg new file mode 100644 index 00000000..02e200dc --- /dev/null +++ b/org.simantics.proconf.processeditor/icons/z-axis.svg @@ -0,0 +1,83 @@ + + + + + + + + + image/svg+xml + + + + + + + Z + + + diff --git a/org.simantics.proconf.processeditor/icons/z-plane.png b/org.simantics.proconf.processeditor/icons/z-plane.png new file mode 100644 index 00000000..d6e9f708 Binary files /dev/null and b/org.simantics.proconf.processeditor/icons/z-plane.png differ diff --git a/org.simantics.proconf.processeditor/icons/z-plane.svg b/org.simantics.proconf.processeditor/icons/z-plane.svg new file mode 100644 index 00000000..d1a654c3 --- /dev/null +++ b/org.simantics.proconf.processeditor/icons/z-plane.svg @@ -0,0 +1,89 @@ + + + + + + + + + image/svg+xml + + + + + + + Z + + + + diff --git a/org.simantics.proconf.processeditor/plugin.xml b/org.simantics.proconf.processeditor/plugin.xml new file mode 100644 index 00000000..33501414 --- /dev/null +++ b/org.simantics.proconf.processeditor/plugin.xml @@ -0,0 +1,266 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/Activator.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/Activator.java new file mode 100644 index 00000000..9f2ad49d --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/Activator.java @@ -0,0 +1,97 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor; + +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.BundleContext; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.management.ISessionContext; +import org.simantics.db.management.ISessionContextChangedListener; +import org.simantics.db.management.SessionContextChangedEvent; +import org.simantics.proconf.ui.ProConfUI; + + + + +/** + * The activator class controls the plug-in life cycle + */ +public class Activator extends AbstractUIPlugin { + + // The plug-in ID + public static final String PLUGIN_ID = "fi.vtt.simantics.processeditor"; + + // 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; + ProConfUI.getSessionContextProvider().addContextChangedListener(new ISessionContextChangedListener() { + @Override + public void sessionContextChanged(SessionContextChangedEvent event) { + ISessionContext ctx = event.getNewValue(); + if (ctx != null) { + ctx.getSession().asyncRead(new GraphRequestAdapter() { + public GraphRequestStatus perform(Graph g) throws Exception { + ProcessResource.initialize(g); + return GraphRequestStatus.transactionComplete(); + }; + }); + } else { + ProcessResource.deinitialize(); + } + } + }); + try { + ProConfUI.getSession().asyncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + ProcessResource.initialize(g); + return GraphRequestStatus.transactionComplete(); + } + }); + } catch (Exception e) { + + } + } + + /* + * (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.proconf.processeditor/src/fi/vtt/simantics/processeditor/ProcessResource.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/ProcessResource.java new file mode 100644 index 00000000..a7df93c9 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/ProcessResource.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor; + +import org.simantics.db.Builtins; +import org.simantics.db.Graph; +import org.simantics.proconf.g3d.stubs.G3DResource; + +import fi.vtt.simantics.processeditor.common.ControlPointTools; +import fi.vtt.simantics.processeditor.stubs.Plant3DResource; + +public class ProcessResource { + public static Builtins builtins; + public static G3DResource g3dResource; + public static Plant3DResource plant3Dresource; + + + public static void initialize(Graph g) { + ProcessResource.builtins = Builtins.getInstance(g); + ProcessResource.g3dResource = G3DResource.getInstance(g); + ProcessResource.plant3Dresource = Plant3DResource.getInstance(g); + ControlPointTools.initialize(); + } + + public static void deinitialize() { + builtins = null; + g3dResource = null; + plant3Dresource = null; + ControlPointTools.deinitialize(); + } + + public static boolean isInitialized() { + return builtins != null; + } +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/InsertComponentAction.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/InsertComponentAction.java new file mode 100644 index 00000000..50f8fed4 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/InsertComponentAction.java @@ -0,0 +1,403 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.actions; + +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.util.ArrayList; +import java.util.List; + +import javax.vecmath.Point3d; + +import org.eclipse.swt.widgets.Display; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.GraphRequestWithResult; +import org.simantics.db.Resource; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.proconf.g3d.actions.InteractiveAction; +import org.simantics.proconf.g3d.base.G3DAPI; +import org.simantics.proconf.g3d.base.G3DTools; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.common.StructuredResourceSelection; +import org.simantics.proconf.g3d.dnd.DropListener; +import org.simantics.proconf.g3d.scenegraph.IGraphicsNode; +import org.simantics.utils.datastructures.Pair; + +import fi.vtt.simantics.processeditor.Activator; +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.common.ControlPointTools; +import fi.vtt.simantics.processeditor.common.PipingTools2; +import fi.vtt.simantics.processeditor.common.PipingTools2.Direction; +import fi.vtt.simantics.processeditor.dialogs.PipelineComponentDialog; +import fi.vtt.simantics.processeditor.gizmo.PositionSelectionGizmo; +import fi.vtt.simantics.processeditor.stubs.PipeControlPoint; +import fi.vtt.simantics.processeditor.stubs.PipelineComponent; + + + +/** + * Action that inserts new components into pipe run. + * - VariableLengthInlineComponents cannot be inserted with this action + * - Assumes that SizeChangeComponent is dual connected + * + * + * @author Marko Luukkainen + * + */ +public class InsertComponentAction extends InteractiveAction implements DropListener, SplitPointListener { + + Resource typeResource; // type of inserted component + Resource targetResource; // component where we are inserting new one + Resource selectedPosition; // selected control point for insertion + PositionType selectedType; // selected position type + List> insertPositions; + List> insertPoints; + PositionSelectionGizmo gizmo = null; + + boolean activated = false; + + private SelectSplitPointAction splitPointAction; + + public InsertComponentAction(ThreeDimensionalEditorBase parent) { + super(parent); + splitPointAction = new SelectSplitPointAction(parent,this); + } + + @Override + public void init() { + this.setText("Insert Component"); + this.setToolTipText("Inserts a Component into Pipeline"); + this.setImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/Component.png")); + } + + @Override + public boolean usable(Graph graph, List resources) { + if (!(resources.size() == 1)) { + return false; + } + IEntity target = EntityFactory.create(graph,resources.get(0)); + + if (!target.isInstanceOf(ProcessResource.plant3Dresource.PipelineComponent)) { + return false; + } + PipelineComponent ic = new PipelineComponent(target); + PipeControlPoint pcp = ic.getControlPoint(); + // one possibility: adding new component to unconnected position + // TODO : how about inserting new components between existing ones. + // TODO : can there be fixed length components that can be split (for example fixed length pipe) + if (pcp.getNext() == null && pcp.getPrevious() == null) + return true; + if (ic.isInstanceOf(ProcessResource.plant3Dresource.InlineComponent) && (pcp.getNext() == null || pcp.getPrevious() == null)) + return true; + for (PipeControlPoint p : pcp.getSubPoint()) + // SubPoint's other connection is always null + // Exception: size change components offset point (that is subpoint) + // does have one or both ends connected, but it won't matter + // here because previous test fould return true, if insertion + // is possible: + // TODO : here we assume that Size Change Component is dual connected + if (p.getNext() == null && p.getPrevious() == null) + return true; + + if (target.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent)) { + // last option to insert component is split variable length component. + // If user chooses to split the component, inserted component must be + // inline component, but not size change component + return true; + } + return false; + } + + @Override + public void activate() { + insertPositions = null; + if (targetResource == null) { + List mos = parent.getSelectionAdapter().getSelectedObjects(); + if (mos.size() != 1) { + end(); + return; + } + IGraphicsNode startNode = mos.get(0); + targetResource = startNode.getResource(); + } + if (selectedPosition == null) { + updateInsertPositions(); + } + if (typeResource == null) { + + List filter = new ArrayList(); + filter.add(ProcessResource.plant3Dresource.VariableLengthInlineComponent); + + boolean containsEnd = false; + for (Pair p : insertPoints) { + if (p.second == PositionType.NEXT || p.second == PositionType.PREVIOUS) { + containsEnd = true; + break; + } + + } + if(!containsEnd) + filter.add(ProcessResource.plant3Dresource.EndComponent); + + PipelineComponentDialog dialog = new PipelineComponentDialog(Display.getCurrent().getActiveShell(),null, filter , parent.getSession()); + if (dialog.open() == PipelineComponentDialog.CANCEL) { + end(); + return; + } + typeResource = dialog.getComboValue(); + updateInsertPositions(); + } + + activated = true; + } + + private void updateInsertPositions() { + parent.getSession().syncRead(new GraphRequestAdapter() { + + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + insertPositions = getInsertPositions(g,targetResource,typeResource); + insertPoints = new ArrayList>(); + for (Pair p : insertPositions) { + IEntity entity = EntityFactory.create(g,p.first); + Point3d pos = ControlPointTools.getRealPosition(entity, p.second); + insertPoints.add(new Pair(pos,p.second)); + } + return GraphRequestStatus.transactionComplete(); + } + }); + } + + /** + * Finds possible locations of inserted component + * + * TODO (s): currently allows only inline, non size change components to split variable length component + * assumes that size change component is DualConnected component + * + * @param g + * @param target + * @param acceptSplit + * @return + */ + private List> getInsertPositions(Graph g, Resource target, Resource typeResource) { + + boolean acceptSplit = true; + boolean checkSubPoints = !g.isInstanceOf(target, ProcessResource.plant3Dresource.DualInlineControlPoint); + if (typeResource != null) + acceptSplit = g.isInstanceOf(typeResource, ProcessResource.plant3Dresource.InlineComponent) && + !g.isInstanceOf(typeResource, ProcessResource.plant3Dresource.SizeChangeComponent); + + + List> insertPositions = new ArrayList>(); + PipelineComponent ic = new PipelineComponent(g,target); + PipeControlPoint pcp = ic.getControlPoint(); + if (pcp.getNext() == null) { + insertPositions.add(new Pair(pcp.getResource(),PositionType.NEXT)); + } + if (pcp.getPrevious() == null) { + insertPositions.add(new Pair(pcp.getResource(),PositionType.PREVIOUS)); + } + if (checkSubPoints) { + for (PipeControlPoint p : pcp.getSubPoint()) { + if (p.getNext() == null && p.getPrevious() == null) { + insertPositions.add(new Pair(p.getResource(),PositionType.PORT)); + } + } + } + if (acceptSplit && ic.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent)) { + insertPositions.add(new Pair(pcp.getResource(),PositionType.SPLIT)); + } + return insertPositions; + } + + @Override + public void update() { + if (splitPointAction.active()) { + splitPointAction.update(); + return; + } + if (!activated) { + return; + } + if (insertPositions == null) + return; + if (insertPositions.size() == 0) { + end(); + return; + } + if (insertPositions.size() == 1) { + activated = false; + insertComponent(insertPositions.get(0)); + return; + } + + if (gizmo == null) { + gizmo = new PositionSelectionGizmo(parent,insertPoints); + parent.setGizmo(gizmo); + parent.getRenderingComponent().getNoShadowRoot().attachChild(gizmo.getNode()); + } + gizmo.update(); + if (gizmo.getSelected() >= 0 && input.mouseClicked() && input.clickButton() == MouseEvent.BUTTON1) { + activated = false; + insertComponent(insertPositions.get(gizmo.getSelected())); + } + if (input.keyPressed(KeyEvent.VK_ESCAPE)) { + end(); + } + } + + private void insertComponent(Pair position) { + selectedPosition = position.first; + selectedType = position.second; + switch (selectedType) { + case NEXT: + case PREVIOUS: + case PORT: + parent.getSession().asyncWrite(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + IEntity pcp = EntityFactory.create(g,selectedPosition); + Point3d point = ControlPointTools.getRealPosition(pcp, selectedType); + IEntity component = instantiateComponent(g,point); + PipingTools2.insertComponent(component, EntityFactory.create(g, targetResource), pcp , Direction.NEXT); + endThreaded(); + return GraphRequestStatus.transactionComplete(); + } + + + }); + break; + case SPLIT: + parent.getSession().asyncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + PipeControlPoint pcp = new PipeControlPoint(g,selectedPosition); + Point3d p1 = new Point3d(); + Point3d p2 = new Point3d(); + ControlPointTools.getInlineControlPointEnds(pcp, p1, p2); + splitPointAction.setSplit(p1, p2); + splitPointAction.activate(); + return GraphRequestStatus.transactionComplete(); + } + }); + break; + } + } + + private void endThreaded() { + parent.getRenderingComposite().getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + end(); + } + }); + } + + @Override + public void setSplitPoint(final Point3d point) { + splitPointAction.deactivate(); + if (point == null) { + end(); + return; + } + parent.getSession().asyncWrite(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + IEntity component = instantiateComponent(g,point); + PipingTools2.splitVariableLengthComponent(component, EntityFactory.create(g,targetResource)); + + return GraphRequestStatus.transactionComplete(); + } + + @Override + public void requestCompleted(GraphRequestStatus status) { + parent.getRenderingComposite().getDisplay().asyncExec(new Runnable(){ + @Override + public void run() { + end(); + + } + }); + } + }); + } + + /** + * instantiates selected component + * @param worldPosition position of the new component + */ + private PipelineComponent instantiateComponent(Graph g,Point3d worldPosition) { + PipelineComponent target = new PipelineComponent(g,targetResource); + IEntity piperun = target.getParent(); + PipelineComponent instance = PipingTools2.instantiatePipelineComponent(g,piperun.getResource(), typeResource); + G3DTools.resetTransformation(instance); + //G3DAPI.addNodeWorld(piperun, instance); + G3DAPI.setWorldPosition(instance, worldPosition); + return instance; + } + + @Override + public void deactivate() { + typeResource = null; + targetResource = null; + selectedPosition = null; + selectedType = null; + insertPoints = null; + insertPositions = null; + if (gizmo != null) { + parent.setGizmo(null); + gizmo = null; + } + } + + public boolean acceptDrop(StructuredResourceSelection s, Resource[] ids) { + if(s.size() != 1) + return false; + if (ids == null) + return false; + if (ids.length != 1) + return false; + + final Resource type = ids[0]; + final Resource target = s.getSelectionList().get(0); + GraphRequestWithResult query = new GraphRequestWithResult() { + @Override + public Boolean performWithResult(Graph g) throws Exception { + IEntity entity = EntityFactory.create(g, type); + // dropped type must be pipeline component + if (!entity.isInstanceOf(ProcessResource.plant3Dresource.PipelineComponent)) + return false; + // but not variable length inline component + if (entity.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent)) + return false; + if (entity.getRelatedObjects(ProcessResource.plant3Dresource.HasGraphics).size() != 1) + return false; + + List> insertPositions = getInsertPositions(g,target,type); + return insertPositions.size() > 0; + } + }; + + parent.getSession().syncRead(query); + + return query.getResult(); + } + + public void doDrop(StructuredResourceSelection s, Resource[] ids) { + typeResource = ids[0]; + targetResource = s.getSelectionList().get(0); + parent.setCurrentAction(this); + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/InsertEquipmentAction.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/InsertEquipmentAction.java new file mode 100644 index 00000000..26556b82 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/InsertEquipmentAction.java @@ -0,0 +1,115 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.actions; + +import java.util.List; + +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.GraphRequestWithResult; +import org.simantics.db.Resource; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.proconf.g3d.actions.ContextAction; +import org.simantics.proconf.g3d.base.G3DAPI; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.common.StructuredResourceSelection; +import org.simantics.proconf.g3d.dnd.DropListener; +import org.simantics.proconf.g3d.stubs.G3DNode; + + + +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.common.PipingTools2; +import fi.vtt.simantics.processeditor.dialogs.EquipmentDialog; +import fi.vtt.simantics.processeditor.stubs.Equipment; + +public class InsertEquipmentAction extends ContextAction implements DropListener{ + + + public InsertEquipmentAction(ThreeDimensionalEditorBase parent) { + super(parent); + this.setText("Insert Equipment"); + } + + @Override + public void run() { + EquipmentDialog dialog = new EquipmentDialog(parent.getRenderingComposite().getShell(),"Insert Equipment",parent.getSession()); + if (dialog.open() == EquipmentDialog.CANCEL) + return; + final Resource typeResource = dialog.getComboValue(); + parent.getSession().asyncWrite(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + createEquipment(g,typeResource); + return GraphRequestStatus.transactionComplete(); + } + }); + } + + + + + private void createEquipment(Graph graph,Resource typeResource) { + + //G3DNode instanceNode = new G3DNode(graph, instance); + Equipment instanceNode = PipingTools2.instantiateEquipment(graph, typeResource); + G3DNode plant = parent.getScenegraphAdapter().getRootNode().getG3DNode(graph); + + G3DAPI.addNodeWorld(plant, instanceNode); + + //parent.getSelectionAdapter().updateSelection(new StructuredResourceSelection(instance))); + } + + public boolean usable(Graph graph,List resources) { + return (resources.size() == 0); + } + + + + public boolean acceptDrop(StructuredResourceSelection s, Resource[] ids) { + if(!s.isEmpty()) + return false; + if (ids == null) + return false; + if (ids.length != 1) + return false; + final Resource r = ids[0]; + GraphRequestWithResult query = new GraphRequestWithResult() { + @Override + public Boolean performWithResult(Graph g) throws Exception { + IEntity t = EntityFactory.create(g, r); + if(!t.isInheritedFrom(ProcessResource.plant3Dresource.Equipment)) + return false; + if (t.getRelatedObjects(ProcessResource.plant3Dresource.HasGraphics).size() == 1) + return true; + return false; + } + }; + + parent.getSession().syncRead(query); + return query.getResult(); + } + + public void doDrop(StructuredResourceSelection s, Resource[] ids) { + final Resource typeResource = ids[0]; + parent.getSession().asyncWrite(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + createEquipment(g,typeResource); + return GraphRequestStatus.transactionComplete(); + } + }); + + + } +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/InsertNozzleAction.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/InsertNozzleAction.java new file mode 100644 index 00000000..91733ab0 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/InsertNozzleAction.java @@ -0,0 +1,139 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.actions; + +import java.util.List; + +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.GraphRequestWithResult; +import org.simantics.db.Resource; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.layer0.utils.instantiation.Instance; +import org.simantics.layer0.utils.instantiation.InstanceFactory; +import org.simantics.proconf.g3d.actions.WriteAction; +import org.simantics.proconf.g3d.base.G3DAPI; +import org.simantics.proconf.g3d.base.G3DTools; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.common.StructuredResourceSelection; +import org.simantics.proconf.g3d.dnd.DropListener; + +import fi.vtt.simantics.processeditor.Activator; +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.common.PipingTools2; +import fi.vtt.simantics.processeditor.dialogs.NozzleDialog; +import fi.vtt.simantics.processeditor.stubs.Equipment; +import fi.vtt.simantics.processeditor.stubs.Nozzle; + + + +public class InsertNozzleAction extends WriteAction implements DropListener { + + Resource equipmentResource = null; + Resource nozzleType = null; + + public InsertNozzleAction(ThreeDimensionalEditorBase parent) { + super(parent,false); + } + + @Override + public boolean canActivate() { + NozzleDialog dialog = new NozzleDialog(parent.getRenderingComposite().getShell(),"Select a nozzle", parent.getSession()); + if (dialog.open() == NozzleDialog.CANCEL) { + equipmentResource = null; + return false; + } + Resource type = dialog.getComboValue(); + if (type == null) { + equipmentResource = null; + return false; + } + nozzleType = type; + return true; + } + + @Override + public GraphRequestStatus doChanges(Graph graph) throws Exception { + createNozzle(graph); + return GraphRequestStatus.transactionComplete(); + } + + private void createNozzle(Graph graph) { + assert(nozzleType != null); + assert(equipmentResource != null); + + Nozzle n = PipingTools2.instantiateNozzle(graph, nozzleType); + + Equipment equipment = new Equipment(graph, equipmentResource); + + G3DAPI.addNodeLocal(equipment,ProcessResource.plant3Dresource.HasNozzle, n); + //parent.getSelectionAdapter().updateSelection(new StructuredResourceSelection(n.getResource())); + equipment = null; + } + + public boolean usable(Graph graph, List resources) { + if (resources.size() != 1) { + return false; + } + Resource r = resources.iterator().next(); + IEntity t = EntityFactory.create(graph,r); + if (t.isInstanceOf(ProcessResource.plant3Dresource.Equipment)) { + equipmentResource = r; + return true; + } + return false; + } + + @Override + public void init() { + setText("Insert Nozzle"); + this.setImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/Nozzle.png")); + } + + public boolean acceptDrop(StructuredResourceSelection s, Resource[] ids) { + if(s.size() != 1) + return false; + if (ids == null) + return false; + if (ids.length != 1) + return false; + final Resource r = ids[0]; + final Resource selectedResource = s.iterator().next(); + GraphRequestWithResult query = new GraphRequestWithResult() { + @Override + public Boolean performWithResult(Graph g) throws Exception { + IEntity t = EntityFactory.create(g,r); + if (!t.isInheritedFrom(ProcessResource.plant3Dresource.Nozzle)) + return false; + t = EntityFactory.create(g,selectedResource); + if (t.isInstanceOf(ProcessResource.plant3Dresource.Equipment)) { + return true; + } + return false; + } + }; + parent.getSession().syncRead(query); + return query.getResult(); + } + + public void doDrop(StructuredResourceSelection s, Resource[] ids) { + equipmentResource = s.iterator().next(); + parent.getSession().asyncWrite(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + createNozzle(g); + return GraphRequestStatus.transactionComplete(); + } + }); + } +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/PositionType.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/PositionType.java new file mode 100644 index 00000000..0ab3a5b7 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/PositionType.java @@ -0,0 +1,15 @@ +package fi.vtt.simantics.processeditor.actions; + + +/** + * Position types for inserting new components and routing new pipe + * + * @author Marko Luukkainen + * + */ +public enum PositionType { + SPLIT, + NEXT, + PREVIOUS, + PORT +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/ReversePipelineAction.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/ReversePipelineAction.java new file mode 100644 index 00000000..a75d7e0d --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/ReversePipelineAction.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.actions; + +import java.util.List; + +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Resource; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.proconf.g3d.actions.WriteAction; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; + + +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.common.PipingTools2; +import fi.vtt.simantics.processeditor.stubs.PipelineComponent; + +public class ReversePipelineAction extends WriteAction { + + public ReversePipelineAction(ThreeDimensionalEditorBase parent) { + super(parent,false); + } + + @Override + public boolean usable(Graph graph, List resources) { + if (resources.size() != 1) + return false; + IEntity t = EntityFactory.create(graph, resources.get(0)); + return (t.isInstanceOf(ProcessResource.plant3Dresource.PipelineComponent)); + } + + @Override + public GraphRequestStatus doChanges(Graph graph) throws Exception { + Resource r = parent.getSelectionAdapter().getSelectedResources().get(0); + PipelineComponent comp = new PipelineComponent(graph, r); + PipingTools2.reversePipeRun(PipingTools2.getPipeRun(comp)); + + return GraphRequestStatus.transactionComplete(); + } + + + @Override + public void init() { + this.setText("Reverse pipeline"); + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/RoutePipeAction.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/RoutePipeAction.java new file mode 100644 index 00000000..00d7ac34 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/RoutePipeAction.java @@ -0,0 +1,1342 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.actions; + +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; + +import javax.vecmath.Point3d; +import javax.vecmath.Vector3d; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IToolBarManager; +import org.eclipse.jface.resource.ImageDescriptor; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.GraphRequestWithResult; +import org.simantics.db.Resource; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.proconf.g3d.actions.InteractiveAction; +import org.simantics.proconf.g3d.base.ConstraintDetector; +import org.simantics.proconf.g3d.base.G3DAPI; +import org.simantics.proconf.g3d.base.G3DTools; +import org.simantics.proconf.g3d.base.MathTools; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.common.StructuredResourceSelection; +import org.simantics.proconf.g3d.dnd.DropListener; +import org.simantics.proconf.g3d.scenegraph.IGraphicsNode; +import org.simantics.utils.datastructures.Pair; + +import com.jme.renderer.ColorRGBA; +import com.jme.scene.Geometry; +import com.jme.scene.Line; +import com.jme.scene.state.MaterialState; + +import fi.vtt.simantics.processeditor.Activator; +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.common.ControlPointTools; +import fi.vtt.simantics.processeditor.common.PipeComponentProvider; +import fi.vtt.simantics.processeditor.common.PipingTools2; +import fi.vtt.simantics.processeditor.common.PipingTools2.Direction; +import fi.vtt.simantics.processeditor.dialogs.PipelineDialog; +import fi.vtt.simantics.processeditor.gizmo.PositionSelectionGizmo; +import fi.vtt.simantics.processeditor.stubs.BranchEndControlPoint; +import fi.vtt.simantics.processeditor.stubs.PipeControlPoint; +import fi.vtt.simantics.processeditor.stubs.PipeRun; +import fi.vtt.simantics.processeditor.stubs.PipelineComponent; +import fi.vtt.simantics.processeditor.stubs.VariableLengthInlineComponent; +import fi.vtt.simantics.processeditor.views.ProcessEditor; + +/** + * Action for Routing Pipes + * + * FIXME : does several thing that should be done by PipingTools. + * TODO : instead of using lines to show route of pipe, generate pipe and change it real-time + * + * @author MLMARKO + * + */ +public class RoutePipeAction extends InteractiveAction implements DropListener, SplitPointListener { + + + private static final ImageDescriptor X_AXIS_ICON = Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/x-axis.png"); + private static final ImageDescriptor Y_AXIS_ICON = Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/y-axis.png"); + private static final ImageDescriptor Z_AXIS_ICON = Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/z-axis.png"); + private static final ImageDescriptor X_PLANE_ICON = Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/x-plane.png"); + private static final ImageDescriptor Y_PLANE_ICON = Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/y-plane.png"); + private static final ImageDescriptor Z_PLANE_ICON = Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/z-plane.png"); + + private static final ImageDescriptor CAMERA_ICON = Activator.imageDescriptorFromPlugin("org.simantics.proconf.g3d", "icons/eye.png"); + + + private Action xAxisAction; + private Action yAxisAction; + private Action zAxisAction; + private Action xPlaneAction; + private Action yPlaneAction; + private Action zPlaneAction; + + private Action cameraAction; + + ConstraintDetector detector = null; + + public RoutePipeAction(ThreeDimensionalEditorBase parent) { + super(parent); + detector = new ConstraintDetector(parent); + xAxisAction = new Action("X",Action.AS_RADIO_BUTTON) { + public void run() { + if (lock == LockType.X) + setLockType(LockType.NONE,false); + else + setLockType(LockType.X,false); + } + }; + xAxisAction.setImageDescriptor(X_AXIS_ICON); + xAxisAction.setToolTipText("Lock X-Axis"); + yAxisAction = new Action("Y",Action.AS_RADIO_BUTTON) { + public void run() { + if (lock == LockType.Y) + setLockType(LockType.NONE,false); + else + setLockType(LockType.Y,false); + } + }; + yAxisAction.setImageDescriptor(Y_AXIS_ICON); + yAxisAction.setToolTipText("Lock Y-Axis"); + zAxisAction = new Action("Z",Action.AS_RADIO_BUTTON) { + public void run() { + if (lock == LockType.Z) + setLockType(LockType.NONE,false); + else + setLockType(LockType.Z,false); + } + }; + zAxisAction.setImageDescriptor(Z_AXIS_ICON); + zAxisAction.setToolTipText("Lock Z-Axis"); + xPlaneAction = new Action("X",Action.AS_RADIO_BUTTON) { + public void run() { + if (lock == LockType.YZ) + setLockType(LockType.NONE,false); + else + setLockType(LockType.YZ,false); + } + }; + xPlaneAction.setImageDescriptor(X_PLANE_ICON); + xPlaneAction.setToolTipText("Lock X-Plane"); + yPlaneAction = new Action("Y",Action.AS_RADIO_BUTTON) { + public void run() { + if (lock == LockType.XZ) + setLockType(LockType.NONE,false); + else + setLockType(LockType.XZ,false); + } + }; + yPlaneAction.setImageDescriptor(Y_PLANE_ICON); + yPlaneAction.setToolTipText("Lock Y-Plane"); + zPlaneAction = new Action("Z",Action.AS_RADIO_BUTTON) { + public void run() { + if (lock == LockType.XY) + setLockType(LockType.NONE,false); + else + setLockType(LockType.XY,false); + } + }; + zPlaneAction.setImageDescriptor(Z_PLANE_ICON); + zPlaneAction.setToolTipText("Lock Z-Plane"); + cameraAction = new Action("C", Action.AS_CHECK_BOX) { + public void run() { + useCamera = this.isChecked(); + } + }; + cameraAction.setImageDescriptor(CAMERA_ICON); + cameraAction.setToolTipText("Use camera"); + splitPointAction = new SelectSplitPointAction(parent,this); + + } + + public void fillToolBar(IToolBarManager manager) { + + manager.add(cameraAction); + cameraAction.setChecked(useCamera); + manager.add(xAxisAction); + manager.add(yAxisAction); + manager.add(zAxisAction); + manager.add(xPlaneAction); + manager.add(yPlaneAction); + manager.add(zPlaneAction); + + } + + enum LockType {NONE,X,Y,Z,XY,YZ,XZ,CUSTOM}; + LockType lock = LockType.NONE; + + private void setLockType(LockType type, boolean force) { + if (force || lock != LockType.CUSTOM) { + lock = type; + } + xAxisAction.setChecked(false); + yAxisAction.setChecked(false); + zAxisAction.setChecked(false); + xPlaneAction.setChecked(false); + yPlaneAction.setChecked(false); + zPlaneAction.setChecked(false); + xAxisAction.setEnabled(true); + yAxisAction.setEnabled(true); + zAxisAction.setEnabled(true); + xPlaneAction.setEnabled(true); + yPlaneAction.setEnabled(true); + zPlaneAction.setEnabled(true); + switch (lock) { + case X: + xAxisAction.setChecked(true); + break; + case Y: + yAxisAction.setChecked(true); + break; + case Z: + zAxisAction.setChecked(true); + break; + case XY: + zPlaneAction.setChecked(true); + break; + case XZ: + yPlaneAction.setChecked(true); + break; + case YZ: + xPlaneAction.setChecked(true); + break; + case CUSTOM: + xAxisAction.setEnabled(false); + yAxisAction.setEnabled(false); + zAxisAction.setEnabled(false); + xPlaneAction.setEnabled(false); + yPlaneAction.setEnabled(false); + zPlaneAction.setEnabled(false); + break; + } + } + + private double BRANCH_SNAP_DISTANCE = 0.05; + private double NOZZLE_SNAP_DISTANCE = 0.05; + + private double istep = 10.0; + private int decimals = 2; + + private double pipeDiameter = 0.2; + private double elbowRadius = 0.5; + private double eps = 0.001; + + private ArrayList controlPoints = new ArrayList(); + + private Point3d currentPoint = new Point3d(); + private Point3d lastPoint = new Point3d(); + + private Vector3d customLockDir = null; + + private Line selectionLine; + private List pipeShapes = new ArrayList(); + private MaterialState ms; + + + private Resource selectedPort = null; + private PositionType selectedType = null; + private Resource beginComponentResource = null; + + private Resource endComponentResource = null; + private Resource endComponentPort = null; + private PositionType endPortType = null; + + private Resource highlightedResource = null; + + private boolean useCamera = false; + + private List> positions = null; + + private SelectSplitPointAction splitPointAction; + private PositionSelectionGizmo gizmo = null; + + + + private enum ToolState{NOT_ACTIVE, INITIALIZING, SELECTING_POSITION, SELECTING_SPLIT, ROUTING}; + private ToolState state = ToolState.NOT_ACTIVE; + + @Override + public void activate() { + state = ToolState.INITIALIZING; + controlPoints.clear(); + if (beginComponentResource == null) { + List mos = parent.getSelectionAdapter().getSelectedObjects(); + if (mos.size() != 1) { + end(); + return; + } + beginComponentResource = mos.get(0).getResource(); + } + parent.getSession().asyncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + positions = checkStartNode(g,beginComponentResource); + if (positions.size() == 0) { + positions = null; + end(); + } else { + state = ToolState.SELECTING_POSITION; + } + return GraphRequestStatus.transactionComplete(); + } + }); + + if (ms == null) { + ms = parent.getRenderingComponent().getDisplaySystem().getRenderer().createMaterialState(); + ms.setEmissive(new ColorRGBA(1.f,1.f,1.f,1.f)); + } + + } + + + + @Override + public void deactivate() { + for (Line l : pipeShapes) + l.removeFromParent(); + pipeShapes.clear(); + if (selectionLine != null) + selectionLine.removeFromParent(); + selectionLine = null; + customLockDir = null; + + setLockType(LockType.NONE,true); + beginComponentResource = null; + endComponentResource = null; + detector.clearConstraintHighlights(); + state = ToolState.NOT_ACTIVE; + selectedPort = null; + selectedType = null; + + } + + private List> checkStartNode(Graph g, Resource resource) { + List> positions = new ArrayList>(); + + IEntity beginComponent = EntityFactory.create(g, resource); + + if (beginComponent.isInstanceOf(ProcessResource.plant3Dresource.Nozzle)) { + if (PipingTools2.isFreeNozzle(beginComponent)) { + + positions.add(new Pair(beginComponent.getSingleRelatedObject(ProcessResource.plant3Dresource.HasControlPoint).getResource(),PositionType.NEXT)); + } + } else if (beginComponent.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent)) { + // variable length inline component is exception from other pipeline components, + // since a new pipe can branch it + VariableLengthInlineComponent vlic = new VariableLengthInlineComponent(beginComponent); + PipeControlPoint pcp = vlic.getControlPoint(); + if (pcp.getNext() == null) { + + positions.add(new Pair(pcp.getResource(),PositionType.NEXT)); + } else if (pcp.getPrevious() == null) { + + positions.add(new Pair(pcp.getResource(),PositionType.PREVIOUS)); + } + positions.add(new Pair(pcp.getResource(),PositionType.SPLIT)); + } else if (beginComponent.isInstanceOf(ProcessResource.plant3Dresource.EndComponent)) { + PipelineComponent component = new PipelineComponent(beginComponent); + PipeControlPoint pcp = component.getControlPoint(); + if (pcp.getNext() == null && pcp.getPrevious() == null) { + throw new RuntimeException("End component " + beginComponent.getResource() + " is not connected to anything."); + //positions.add(new Pair(pcp.getResource(),PositionType.NEXT)); + } + for (PipeControlPoint p : pcp.getSubPoint()) { + if (p.getNext() == null && p.getPrevious() == null) { + positions.add(new Pair(p.getResource(),PositionType.NEXT)); + } + } + } else if (beginComponent.isInstanceOf(ProcessResource.plant3Dresource.PipelineComponent)) { + + PipelineComponent component = new PipelineComponent(beginComponent); + + PipeControlPoint pcp = component.getControlPoint(); + if (pcp.getNext() == null) { + positions.add(new Pair(pcp.getResource(),PositionType.NEXT)); + } else if (pcp.getPrevious() == null) { + positions.add(new Pair(pcp.getResource(),PositionType.PREVIOUS)); + } + if (!beginComponent.isInstanceOf(ProcessResource.plant3Dresource.SizeChangeComponent)|| + !beginComponent.isInstanceOf(ProcessResource.plant3Dresource.OffsetComponent)) { + for (PipeControlPoint p : pcp.getSubPoint()) { + if (p.getNext() == null && p.getPrevious() == null) { + positions.add(new Pair(p.getResource(),PositionType.NEXT)); + } + } + } + } else { + return positions; + } + return positions; + } + + @Override + public void update() { + + switch (state) { + case NOT_ACTIVE: + return; // TODO : throw Exception? + case INITIALIZING: + return; + case SELECTING_POSITION: + updateSelectPosition(); + break; + case SELECTING_SPLIT: + updateSelectSplit(); + break; + case ROUTING: + updateRouting(); + break; + } + return; + } + + private void updateSelectPosition() { + + if (positions == null) { + throw new RuntimeException("positions must be loaded before select position can be activated"); + } + if (selectedPort != null) { + throw new RuntimeException("position is already selected"); + } + if (positions.size() == 1) { + selectedPort = positions.get(0).first; + selectedType = positions.get(0).second; + state = ToolState.INITIALIZING; + + + + if (requiresNewPipeRun()){ + if(!getNewPipeRunSpecs()) { + end(); + return; + } + } + if (selectedType == PositionType.SPLIT) { + startSplitting(); + } else { + startRouting(); + } + + } else if (gizmo == null) { + state = ToolState.INITIALIZING; // asyncRead! + parent.getSession().asyncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + List> pos = new ArrayList>(); + for (Pair p : positions) { + IEntity entity = EntityFactory.create(g,p.first); + Point3d position = ControlPointTools.getRealPosition(entity, p.second); + pos.add(new Pair(position,p.second)); + } + gizmo = new PositionSelectionGizmo(parent, pos); + parent.setGizmo(gizmo); + parent.getRenderingComponent().getNoShadowRoot().attachChild(gizmo.getNode()); + state = ToolState.SELECTING_POSITION; + return GraphRequestStatus.transactionComplete(); + } + }); + + } else { + gizmo.update(); + + if (input.keyPressed(KeyEvent.VK_ESCAPE)) { + state = ToolState.INITIALIZING; + parent.setGizmo(null); + gizmo = null; + end(); + return; + } + + if (gizmo.getSelected() >= 0 && input.mouseClicked() && input.clickButton() == MouseEvent.BUTTON1) { + state = ToolState.INITIALIZING; // asyncRead! + parent.setGizmo(null); + selectedPort = positions.get(gizmo.getSelected()).first; + selectedType = positions.get(gizmo.getSelected()).second; + gizmo = null; + + if (selectedType == PositionType.SPLIT) { + startSplitting(); + return; + } else { + startRouting(); + } + } + + if (useCamera) { + parent.getDefaultAction().update(); + return; + } + } + + } + + private boolean requiresNewPipeRun() { + GraphRequestWithResult createsNewPipeline = new GraphRequestWithResult() { + @Override + public Boolean performWithResult(Graph g) throws Exception { + if(g.isInstanceOf(selectedPort, ProcessResource.plant3Dresource.NozzleControlPoint)) + return true; + if (selectedType == PositionType.SPLIT) + return true; + return false; + + } + }; + parent.getSession().syncRead(createsNewPipeline); + return createsNewPipeline.getResult(); + } + + private boolean getNewPipeRunSpecs() { + PipelineDialog dialog; + dialog = new PipelineDialog(parent.getRenderingComposite().getShell(),pipeDiameter,elbowRadius); + if (dialog.open() == PipelineDialog.CANCEL) { + end(); + return false; + } + pipeDiameter = dialog.getPipeDiameter(); + elbowRadius = dialog.getTurnRadius(); + return true; + } + + private void startRouting() { + state = ToolState.INITIALIZING; + parent.getSession().asyncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + PipeControlPoint pcp = new PipeControlPoint(g,selectedPort); + lastPoint = ControlPointTools.getRealPosition(pcp, selectedType);//G3DTools.getPoint(pcp.getWorldPosition()); + if (pcp.isInstanceOf(ProcessResource.plant3Dresource.DirectedControlPoint)) { + lock = LockType.CUSTOM; + customLockDir = ControlPointTools.getDirectedControlPointDirection(pcp); + } else if (pcp.isInstanceOf(ProcessResource.plant3Dresource.FixedLengthControlPoint)|| + pcp.isInstanceOf(ProcessResource.plant3Dresource.TurnControlPoint)) { + lock = LockType.CUSTOM; + if (selectedType == PositionType.NEXT) + customLockDir = ControlPointTools.getPathLegDirection(pcp, Direction.NEXT); + else + customLockDir = ControlPointTools.getPathLegDirection(pcp, Direction.PREVIOUS); + } else { + lock = LockType.NONE; + } + IEntity pipeRun = ControlPointTools.getPipeRun(pcp); + if (pipeRun != null) { + pipeDiameter = pipeRun.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasPipeDiameter); + elbowRadius = pipeRun.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasTurnRadius); + } + return GraphRequestStatus.transactionComplete(); + } + + @Override + public void requestCompleted(GraphRequestStatus status) { + createLine(); + state = ToolState.ROUTING; + } + }); + } + + private void startSplitting() { + parent.getSession().asyncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + PipeControlPoint pcp = new PipeControlPoint(g,selectedPort); + Point3d p1 = new Point3d(); + Point3d p2 = new Point3d(); + ControlPointTools.getInlineControlPointEnds(pcp, p1, p2); + splitPointAction.setSplit(p1, p2); + splitPointAction.activate(); + state = ToolState.SELECTING_SPLIT; + return GraphRequestStatus.transactionComplete(); + } + }); + } + + + private void updateSelectSplit() { + if (splitPointAction.active()) { + splitPointAction.update(); + return; + } else { + throw new RuntimeException("SplitPointAction should be active"); + } + } + + @Override + public void setSplitPoint(Point3d point) { + splitPointAction.deactivate(); + if (point == null) { + end(); + return; + } else { + + + lastPoint = point; + createLine(); + state = ToolState.ROUTING; + } + } + + private void updateRouting() { + if(input.keyPressed(KeyEvent.VK_ESCAPE)) { + controlPoints.clear(); + end(); + return; + } + if (input.keyPressed(KeyEvent.VK_C)) { + useCamera = !useCamera; + cameraAction.setChecked(useCamera); + } + if (useCamera) { + parent.getDefaultAction().update(); + return; + } + + parent.getSession().syncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + + Vector3d o = new Vector3d(); + Vector3d d = new Vector3d(); + parent.createPickRay(o, d); + if (!updateCurrentPoint(o, d)) + return GraphRequestStatus.transactionComplete(); + //Point3d startPoint = new Point3d(); + double mu[] = new double[2]; + + IEntity endTo = null; + PositionType endType = null; + IEntity endPort = null; + + if (parent.getSelectionAdapter().getHighlightSelection().size() > 0) { + highlightedResource = parent.getSelectionAdapter().getHighlightSelection().getSelectionList().get(0); + } else { + highlightedResource = null; + } + + if (highlightedResource != null) { + IEntity highlightNode = EntityFactory.create(g,highlightedResource); + + if (lock == LockType.NONE) { + if (highlightNode.isInstanceOf(ProcessResource.plant3Dresource.Nozzle) && endingToNozzle(highlightNode,o,d)) { + endTo = highlightNode; + } else if (highlightNode.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent)) { + endTo = highlightNode; + endType = endingToStraight(new VariableLengthInlineComponent(highlightNode),mu,o,d); + } else if (highlightNode.isInstanceOf(ProcessResource.plant3Dresource.PipelineComponent) && (endPort = endingToComponent(highlightNode,o,d)) != null) { + endTo = highlightNode; + } else { + updateRoute(o,d); + } + } else { + if (highlightNode.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent) && (endType = endingLockToStraight(new VariableLengthInlineComponent(highlightNode),mu)) != null) { + endTo = highlightNode; + } else if (highlightNode.isInstanceOf(ProcessResource.plant3Dresource.Nozzle) && endingLockToNozzle(highlightNode)) { + endTo = highlightNode; + } else if (highlightNode.isInstanceOf(ProcessResource.plant3Dresource.PipelineComponent) && (endPort = endingLockToComponent(highlightNode)) != null) { + endTo = highlightNode; + } else { + updateRoute(o,d); + } + } + + + } else { + updateRoute(o,d); + } + + parent.setViewChanged(true); + if (input.mouseClicked()) { + if (input.clickButton() == MouseEvent.BUTTON1) { + if (controlPoints.size() > 0) { + addPoint(); + setLockType(LockType.NONE,true); + if (endTo != null) { + endComponentResource = endTo.getResource(); + if (endPort != null) + endComponentPort = endPort.getResource(); + endPortType = endType; + + endPiping(); + } + } 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 (input.clickButton() == MouseEvent.BUTTON2){ + detector.updateConstraintReference(); + } else if (input.clickButton() == MouseEvent.BUTTON3){ + endPiping(); + } + } + + return GraphRequestStatus.transactionComplete(); + } + }); + + } + + private void createLine() { + controlPoints.add(new Point3d(lastPoint)); + Line line = new Line(); + line.setRenderState(ms); + + PipeComponentProvider.createStraightEdges(line, currentPoint, currentPoint, pipeDiameter*0.5); + pipeShapes.add(line); + parent.getRenderingComponent().getNoShadowRoot().attachChild(line); + line.setCullMode(Geometry.CULL_NEVER); + } + + + /** + * Adds current point to pipeline + * + */ + private void addPoint() { + + controlPoints.add(new Point3d(currentPoint)); + Line line = new Line(); + line.setRenderState(ms); + PipeComponentProvider.createStraightEdges(line, controlPoints.get(controlPoints.size() - 1), currentPoint, pipeDiameter*0.5); + pipeShapes.add(line); + parent.getRenderingComponent().getNoShadowRoot().attachChild(line); + line.setCullMode(Geometry.CULL_NEVER); + lastPoint.set(currentPoint); + } + + /** + * 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); + } + + /** + * Removes last point from pipeline + */ + public void removePoint() { + if (controlPoints.size() < 2) + return; + controlPoints.remove(controlPoints.size() - 1); + + pipeShapes.get(pipeShapes.size() - 1).removeFromParent(); + pipeShapes.remove(pipeShapes.size() - 1); + PipeComponentProvider.createStraightEdges(pipeShapes.get(pipeShapes.size() - 1), controlPoints.get(controlPoints.size() - 1), currentPoint, pipeDiameter*0.5); + + lastPoint.set(controlPoints.get(controlPoints.size()-1)); + if (controlPoints.size() < 2 && customLockDir != null) { + setLockType(LockType.CUSTOM, true); + } + } + + + + private boolean endingToNozzle(IEntity nozzle,Vector3d o, Vector3d d) { + IEntity pcp = nozzle.getSingleRelatedObject(ProcessResource.plant3Dresource.HasControlPoint); + if (pcp != null && (pcp.getAtMostOneRelatedObject(ProcessResource.plant3Dresource.HasNext) != null || + pcp.getAtMostOneRelatedObject(ProcessResource.plant3Dresource.HasPrevious) != null)) + return false; // nozzle is already connected to pipe + currentPoint = G3DTools.getPoint(nozzle.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition)); + Point3d previousPipePoint = controlPoints.get(controlPoints.size() - 1); + Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint)); + if (p != null) { + if (p.distance(currentPoint) > NOZZLE_SNAP_DISTANCE) { + return false; + } + } + + updateCurrentPoint(); + + setInfoText("Connect to nozzle " + currentPoint); + return true; + + } + + private PositionType endingToStraight(VariableLengthInlineComponent s, double mu[], Vector3d o, Vector3d d) { + String info = ""; + Point3d sStart = new Point3d(); + Point3d sEnd = new Point3d(); + //detector.clearConstraintHighlights(); + + Point3d previousPipePoint = controlPoints.get(controlPoints.size() - 1); + //String st = ""; + if (lock == LockType.NONE) { + Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint)); + if (p != null) { + currentPoint = 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(); + } + + PipingTools2.getInlineComponentEnds(s, sStart, sEnd); + Vector3d sDir = new Vector3d(sEnd); + sDir.sub(sStart); + MathTools.intersectStraightStraight(sStart, sDir, o, d, currentPoint, 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) { + currentPoint.set(sStart); + connectPrev = true; + } + else if (mu[0] > 1.0) { + currentPoint.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 + currentPoint + " " + 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 IEntity endingToComponent(IEntity component, Vector3d o, Vector3d d) { + // TODO : scan all empty pcps of the component and select closest one. + return null; + } + + private PositionType endingLockToStraight(VariableLengthInlineComponent s, double mu[]) { + + Point3d sStart = new Point3d();//G3DTools.getPoint(s.getHasControlPoint().getPreviousPoint().getLocalPosition()); + Point3d sEnd = new Point3d(); //G3DTools.getPoint(s.getHasControlPoint().getNextPoint().getLocalPosition()); + PipingTools2.getInlineComponentEnds(s, sStart, sEnd); + Vector3d sDir = new Vector3d(sEnd); + sDir.sub(sStart); + Vector3d dir = new Vector3d(currentPoint); + Point3d prev = controlPoints.get(controlPoints.size() - 1); + 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) { + currentPoint.set(branchPoint); + + updateCurrentPoint(); + + setInfoText("Make branch (l) :" + currentPoint + " " + Math.max(0.0, Math.min(mu[0], 1.0)) + " " + routePoint.lengthSquared()); + return PositionType.SPLIT; + } + return null; + } + + private boolean endingLockToNozzle(IEntity nozzle) { + Vector3d dir = new Vector3d(currentPoint); + Point3d prev = controlPoints.get(controlPoints.size() - 1); + dir.sub(prev); + Point3d nozzleLoc = G3DTools.getPoint(nozzle.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition)); + double u[] = new double[1]; + Vector3d closest = MathTools.closestPointOnStraight(new Point3d(nozzleLoc), new Point3d(prev), new Vector3d(dir), u); + double dist = nozzleLoc.distanceSquared(new Point3d(closest)); + if (dist < BRANCH_SNAP_DISTANCE) { + // FIXME : directions should be checked (insert an elbow) + currentPoint.set(nozzleLoc); + updateCurrentPoint(); + setInfoText("Connect to nozzle (l) :" + currentPoint); + return true; + } + //System.out.println(u[0]); + return false; + } + + private IEntity endingLockToComponent(IEntity component) { + // we'll must scan all free pcp's and their direction to accept the connection. + return null; + } + + private void updateRoute(Vector3d o, Vector3d d) { + detector.clearConstraintHighlights(); + Point3d previousPipePoint = controlPoints.get(controlPoints.size() - 1); + String s = ""; + if (lock == LockType.NONE) { + Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint)); + if (p != null) + currentPoint = p; + s += detector.getSnapString(); + + } else { + Vector3d dir = new Vector3d(currentPoint); + dir.sub(previousPipePoint); + Point3d p = detector.getPointSnap(new Vector3d(previousPipePoint), dir); + if (p != null) + currentPoint = p; + s += detector.getSnapString(); + + } + + updateCurrentPoint(); + s += currentPoint.toString(); + setInfoText(s); + } + + private boolean updateCurrentPoint(Vector3d o, Vector3d d) { + if (lock != LockType.CUSTOM) { + if (input.keyPressed(KeyEvent.VK_X)) { + if (lock == LockType.X) + setLockType(LockType.YZ,false); + else + setLockType(LockType.X,false); + } + if (input.keyPressed(KeyEvent.VK_Y)) { + if (lock == LockType.Y) + setLockType(LockType.XZ,false); + else + setLockType(LockType.Y,false); + } + if (input.keyPressed(KeyEvent.VK_Z)) { + if (lock == LockType.Z) + setLockType(LockType.XY,false); + else + setLockType(LockType.Z,false); + } + if (input.keyPressed(KeyEvent.VK_N)) { + setLockType(LockType.NONE,false); + } + if (input.keyPressed(KeyEvent.VK_BACK_SPACE)) { + removePoint(); + } + } + Vector3d point = new Vector3d(lastPoint); + boolean step = ((input.moveModifiers() & MouseEvent.CTRL_DOWN_MASK) > 0); + switch(lock) { + case X: + MathTools.intersectStraightStraight(point, new Vector3d(1.0,0.0,0.0), o,d, currentPoint, new Vector3d()); + if (step) { + currentPoint.x = Math.round(istep * currentPoint.x) / istep; + BigDecimal bx = new BigDecimal(currentPoint.x); + bx.setScale(decimals, BigDecimal.ROUND_HALF_UP); + currentPoint.x = bx.doubleValue(); + } + break; + case Y: + MathTools.intersectStraightStraight(point, new Vector3d(0.0,1.0,0.0), o,d, currentPoint, new Vector3d()); + if (step) { + currentPoint.y = Math.round(istep * currentPoint.y) / istep; + BigDecimal bx = new BigDecimal(currentPoint.y); + bx.setScale(decimals, BigDecimal.ROUND_HALF_UP); + currentPoint.y = bx.doubleValue(); + } + break; + case Z: + MathTools.intersectStraightStraight(point, new Vector3d(0.0,0.0,1.0), o,d, currentPoint, new Vector3d()); + if (step) { + currentPoint.z = Math.round(istep * currentPoint.z) / istep; + BigDecimal bx = new BigDecimal(currentPoint.z); + bx.setScale(decimals, BigDecimal.ROUND_HALF_UP); + currentPoint.z = bx.doubleValue(); + }break; + case XY: + MathTools.intersectStraightPlane(o, d, point, new Vector3d(0.0,0.0,1.0), currentPoint); + break; + case XZ: + MathTools.intersectStraightPlane(o, d, point, new Vector3d(0.0,1.0,0.0), currentPoint); + break; + case YZ: + MathTools.intersectStraightPlane(o, d, point, new Vector3d(1.0,0.0,0.0), currentPoint); + break; + case NONE: + Vector3d normal = parent.getCamera().getUnNormalizedHeading(); + normal.normalize(); + + MathTools.intersectStraightPlane(o, d, point, normal, currentPoint); + break; + case CUSTOM: + MathTools.intersectStraightStraight(point, new Vector3d(customLockDir), o,d, currentPoint, new Vector3d()); + double dist = MathTools.distanceFromPlane(new Vector3d(currentPoint), customLockDir, lastPoint); + if (dist < 0.0) + currentPoint.set(lastPoint); + break; + default: + return false; + } + return true; + } + + + private ArrayList filterPoints() { + ArrayList filteredControlPoints = new ArrayList(); + + // this loop filters control points that are not needed + for (int i = 0; i < controlPoints.size() - 2; i++) { + Point3d start = controlPoints.get(i); + if (i == 0) + filteredControlPoints.add(start); + + Point3d middle = controlPoints.get(i+1); + Point3d end = controlPoints.get(i+2); + + Vector3d dir1 = new Vector3d(middle); + dir1.sub(start); + Vector3d dir2 = new Vector3d(end); + dir2.sub(middle); + double angle = dir1.angle(dir2); + if (angle > eps && angle < (Math.PI - eps)) + filteredControlPoints.add(middle); + // if angle is near PI pipe turns back to where it started + // if angle is near zero, pipe is straight and there's no need for control point + + if (i == controlPoints.size() - 3) + filteredControlPoints.add(end); + + } + return filteredControlPoints; + } + + private PipeControlPoint connectPipeStart(Graph graph, PipeRun pipeRun, boolean reversed) { + PipeControlPoint pcp = new PipeControlPoint(graph,selectedPort); + IEntity beginComponent = EntityFactory.create(graph,beginComponentResource); + if (beginComponent.isInstanceOf(ProcessResource.plant3Dresource.Nozzle)) { + PipingTools2.linkNozzleAndPipeRun(beginComponent, pipeRun); + // TODO : set diameters same + //reversed = false; + + } else if (beginComponent.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent)) { + switch (selectedType) { + case NEXT: + { + PipeControlPoint tcp = createTurn(graph, pipeRun, 0); + connectControlPoints(pcp, tcp, reversed); + return tcp; + } + case PREVIOUS: + { + PipeControlPoint tcp = createTurn(graph, pipeRun, 0); + connectControlPoints(pcp, tcp, reversed); + return tcp; + } + case SPLIT: + //reversed = false; + // 1. create (non visible) splitting component. + PipelineComponent newComponent = PipingTools2.instantiatePipelineComponent(graph, PipingTools2.getPipeRun(beginComponent).getResource(), ProcessResource.plant3Dresource.BranchSplitComponent); + PipeControlPoint mainCP = newComponent.getControlPoint(); + // 2. create control point for the branch + BranchEndControlPoint becp = BranchEndControlPoint.createDefault(graph); + mainCP.addSubPoint(becp); + pipeRun.addControlPoints(becp); + pcp = becp.toPipeControlPoint(); + ControlPointTools.setWorldPosition(mainCP, controlPoints.get(0)); + + PipingTools2.splitVariableLengthComponent(newComponent, beginComponent); + } + } else if (beginComponent.isInstanceOf(ProcessResource.plant3Dresource.PipelineComponent)) { + //if (selectedType == PositionType.PREVIOUS) + //reversed = true; + //else + //reversed = false; + } else { + throw new RuntimeException("unknown starting component"); + } + + return pcp; + } + + private PipeControlPoint connectPipeEnd(Graph graph, PipeRun pipeline, boolean reversed) { + PipeControlPoint pcp = null; + IEntity endComponent = null; + if (endComponentResource != null) + endComponent = EntityFactory.create(graph, endComponentResource); + if (endComponent == null) { + return null; + } else if (endComponent.isInstanceOf(ProcessResource.plant3Dresource.Nozzle)){ + pcp = new PipeControlPoint(endComponent.getSingleRelatedObject(ProcessResource.plant3Dresource.HasControlPoint)); + PipingTools2.linkNozzleAndPipeRun(endComponent, pipeline); + } else if (endComponent.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent)) { + assert(endPortType != null); + if (endPortType == PositionType.SPLIT) { + //System.out.println(lastPoint + " " + currentPoint + " " + positions.get(positions.size() - 1)); + Point3d pos = lastPoint; + // 1. create (non visible) splitting component. + PipelineComponent newComponent = PipingTools2.instantiatePipelineComponent(graph, PipingTools2.getPipeRun(endComponent).getResource(), ProcessResource.plant3Dresource.BranchSplitComponent); + + PipeControlPoint mainCP = newComponent.getControlPoint(); + // 2. create control point for the branch + BranchEndControlPoint becp = BranchEndControlPoint.createDefault(graph); + mainCP.addSubPoint(becp); + pipeline.addControlPoints(becp); + pcp = becp.toPipeControlPoint(); + ControlPointTools.setWorldPosition(mainCP, pos); + + PipingTools2.splitVariableLengthComponent(newComponent, endComponent); + } else { + + } + } else if (endComponent.isInstanceOf(ProcessResource.plant3Dresource.FixedLengthInlineComponent)) { + // attach to selected port, reverse the piperun if needed + pcp = new PipeControlPoint(graph,endComponentPort); + if (!reversed && pcp.getPrevious() != null || reversed && pcp.getNext() != null) { + PipingTools2.reversePipeRun(ControlPointTools.getPipeRun(pcp)); + } + } + return pcp; + } + + private PipeControlPoint createTurn(Graph coreTC,PipeRun pipeRun, int i) { + PipelineComponent elbow = PipingTools2.instantiatePipelineComponent(coreTC,pipeRun.getResource(), ProcessResource.plant3Dresource.Elbow); + G3DAPI.setWorldPosition(elbow, controlPoints.get(i)); + return elbow.getControlPoint(); + } + + private PipeControlPoint createInline(Graph graph, PipeRun pipeRun, int i) { + Point3d p1 = controlPoints.get(i-1); + Point3d p2 = controlPoints.get(i); + Vector3d v = new Vector3d(p2); + v.sub(p1); + double length = v.length(); + v.scale(0.5); + v.add(p1); + PipelineComponent straight = PipingTools2.instantiatePipelineComponent(graph,pipeRun.getResource(), ProcessResource.plant3Dresource.Straight); + G3DAPI.setWorldPosition(straight, v); + straight.setRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength, length); + return straight.getControlPoint(); + + } + + private void connectControlPoints(PipeControlPoint previous, PipeControlPoint pcp, boolean reversed) { + if (previous != null) { + PipeControlPoint sccp; + PipeControlPoint ocp; + if (previous.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)) { + sccp = previous; + ocp = sccp.getSubPoint().iterator().next(); + } else if (previous.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)) { + ocp = previous; + sccp = ocp.getSubPointOf(); + } else { + if (!reversed) { + previous.setNext(pcp); + pcp.setPrevious(previous); + } else { + previous.setPrevious(pcp); + pcp.setNext(previous); + } + return; + } + if (!reversed) { + sccp.setNext(pcp); + ocp.setNext(pcp); + pcp.setPrevious(ocp); + } else { + sccp.setPrevious(pcp); + ocp.setPrevious(pcp); + pcp.setNext(sccp); + } + + } + } + + private void endPiping() { + state = ToolState.NOT_ACTIVE; + + if (controlPoints.size() > 2) // if there's only two control points, filtering does nothing + controlPoints = filterPoints(); + + if (controlPoints.size() > 1) { + parent.getSession().asyncWrite(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph graph) throws Exception { + PipeRun pipeline = null; + boolean reversed; + PipelineComponent beginComponent = new PipelineComponent(graph,beginComponentResource); + if (beginComponent.isInstanceOf(ProcessResource.plant3Dresource.Nozzle) || + selectedType == PositionType.SPLIT) { + + +// + pipeline = PipeRun.createDefault(graph); + ((ProcessEditor) parent).getPlant(graph).addChild(pipeline); + pipeline.setPipeDiameter(pipeDiameter); + pipeline.setTurnRadius(elbowRadius); + reversed = false; + } else if (beginComponent.isInstanceOf(ProcessResource.plant3Dresource.SizeChangeComponent)|| + beginComponent.isInstanceOf(ProcessResource.plant3Dresource.OffsetComponent)){ + PipeControlPoint pcp = new PipeControlPoint(graph,selectedPort); + if (selectedType == PositionType.NEXT) { + // get the piperun from offsetpoint + reversed = false; + pipeline = pcp.getSubPoint().iterator().next().getControlPointOfPipeRun(); + } else if (selectedType == PositionType.PREVIOUS) { + reversed = true; + pipeline = pcp.getControlPointOfPipeRun(); + } else { + throw new RuntimeException("Wrong PsoitionType " + selectedType + " for a SizeChangeComponent"); + } + + } else if (beginComponent.isInstanceOf(ProcessResource.plant3Dresource.PipelineComponent)) { + + pipeline = new PipeRun(beginComponent.getParent()); + if (selectedType == PositionType.PREVIOUS) { + reversed = true; + } else { + reversed = false; + } + } else { + throw new RuntimeException("Cannot start routing pipe : object not supported!"); + } + + PipeControlPoint previous = null; + for (int i = 0; i < controlPoints.size(); i++) { + PipeControlPoint pcp = null; + if (i == 0) { + pcp = connectPipeStart(graph, pipeline,reversed); + + } else { + pcp = createInline(graph, pipeline, i); + connectControlPoints(previous, pcp, reversed); + previous = pcp; + if (i == controlPoints.size() - 1) { + pcp = connectPipeEnd(graph, pipeline, reversed); + } else { + + pcp = createTurn(graph,pipeline,i); + } + } + + if (pcp != null) { + connectControlPoints(previous, pcp, reversed); + //pipeline.addSgetHasControlPointSet().add(pcp); + previous = pcp; + } + } + return GraphRequestStatus.transactionComplete(); + } + + @Override + public void requestCompleted(GraphRequestStatus status) { + endThreaded(); + } + }); + + + + } else { + endThreaded(); + } + } + + private void endThreaded() { + parent.getRenderingComposite().getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + end(); + } + }); + } + + @Override + public void init() { + this.setText("Route pipe"); + this.setToolTipText("Starts routing a new pipeline"); + this.setImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/Straight.png")); + } + + @Override + public boolean usable(Graph g, List resources) { + if (resources.size() != 1) { + return false; + } + return checkStartNode(g,resources.get(0)).size() > 0; + } + + + + public boolean acceptDrop(StructuredResourceSelection s, Resource[] ids) { + if (s.size() != 1) + return false; + if (ids == null) + return false; + if (ids.length != 1) + return false; + final Resource dropped = ids[0]; + final Resource target = s.iterator().next(); + GraphRequestWithResult query = new GraphRequestWithResult() { + @Override + public Boolean performWithResult(Graph g) throws Exception { + if(!g.isInstanceOf(dropped, ProcessResource.plant3Dresource.VariableLengthInlineComponent)) + return false; + // TODO : check that type is not abstract + List list = new ArrayList(); + list.add(target); + return usable(g, list); + } + }; + parent.getSession().syncRead(query); + return query.getResult(); + } + + public void doDrop(StructuredResourceSelection s, Resource[] ids) { + beginComponentResource = s.iterator().next(); + parent.setCurrentAction(this); + } + + public void setInfoText(String text) { + + } + +} \ No newline at end of file diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/SelectSplitPointAction.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/SelectSplitPointAction.java new file mode 100644 index 00000000..1b004e98 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/SelectSplitPointAction.java @@ -0,0 +1,135 @@ +package fi.vtt.simantics.processeditor.actions; + +import java.awt.event.MouseEvent; +import java.util.List; + +import javax.vecmath.Point3d; +import javax.vecmath.Vector3d; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.proconf.g3d.actions.InteractiveAction; +import org.simantics.proconf.g3d.base.MathTools; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.base.VecmathJmeTools; + +import com.jme.math.Vector3f; +import com.jme.renderer.ColorRGBA; +import com.jme.scene.Line; +import com.jme.scene.state.MaterialState; +import com.jme.util.geom.BufferUtils; + +public class SelectSplitPointAction extends InteractiveAction { + + Point3d start; + Point3d end; + Vector3d dir; + + Line line; + + boolean activated; + + SplitPointListener listener; + + public SelectSplitPointAction(ThreeDimensionalEditorBase parent, SplitPointListener listener) { + super(parent); + this.listener = listener; + } + + + public void setSplit(Point3d start, Point3d end) { + this.start = start; + this.end = end; + dir = new Vector3d(end); + dir.sub(start); + } + + + @Override + public void activate() { + if (start == null) throw new RuntimeException("Starting split action without information about range"); + +// start = new Point3d(); +// end = new Point3d(); +// PipingTools.getStraightPipeEnds(PipingTools.getPipeline(straight), +// straight, startStart, startEnd); + + line = new Line(); + MaterialState ms = parent.getRenderingComponent().getDisplaySystem().getRenderer().createMaterialState(); + ms.setEmissive(new ColorRGBA(1.f,1.f,1.f,1.f)); + line.setRenderState(ms); + parent.getRenderingComponent().getNoShadowRoot().attachChild(line); + activated = true; + + } + + @Override + public boolean usable(Graph graph, List resources) { +// if (resources.size() != 1) +// return false; +// IEntity entity = EntityFactory.create(graph, resources.get(0)); +// if (entity.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent)) { +// return true; +// } + // This is not a standalone action + return false; + } + + @Override + public void deactivate() { + line.removeFromParent(); + activated = false; + start = null; + end = null; + dir = null; + + } + + public boolean active() { + return activated; + } + + @Override + public void update() { + if (!activated) { + return; + } + if (input.mouseClicked() && input.clickButton() == MouseEvent.BUTTON3) { + listener.setSplitPoint(null); + activated = false; + return; + } + Vector3d o = new Vector3d(); + Vector3d d = new Vector3d(); + parent.createPickRay(o, d); + + Vector3d normal = parent.getCamera().getUnNormalizedHeading(); + normal.normalize(); + normal.negate(); + // reference point for selection line + Vector3d point = new Vector3d(start); + Vector3d currentPoint = new Vector3d(); + MathTools.intersectStraightPlane(o, d, point, normal, currentPoint); + Point3d startPoint = new Point3d(); + double mu[] = new double[2]; + MathTools.intersectStraightStraight(start, dir, o, d, startPoint, + new Point3d(), mu); + // startPoint of branch must be between pipe ends + // TODO : take account sizes of elbows (or other components) + if (mu[0] < 0.0) + startPoint.set(start); + else if (mu[0] > 1.0) + startPoint.set(end); + + Vector3f verts[] = new Vector3f[2]; + verts[0] = VecmathJmeTools.get(startPoint); + verts[1] = VecmathJmeTools.get(currentPoint); + line.reconstruct(BufferUtils.createFloatBuffer(verts), null, null, null); + + parent.setViewChanged(true); + if (input.mouseClicked() && input.clickButton() == MouseEvent.BUTTON1) { + listener.setSplitPoint(new Point3d(startPoint)); + } + + } +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/SplitPointListener.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/SplitPointListener.java new file mode 100644 index 00000000..d766ad39 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/SplitPointListener.java @@ -0,0 +1,19 @@ +package fi.vtt.simantics.processeditor.actions; + +import javax.vecmath.Point3d; + +/** + * SplitPointListener is used by SplitPointAction to pass the selected split point. + * Implementing class must set itself as active action into editor (SplitPointAction won't close automatically). + * + * @author Marko Luukkainen + * + */ +public interface SplitPointListener { + + /** + * Sets selected split point, or null if user cancelled the action. + * @param point + */ + public void setSplitPoint(Point3d point); +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/TranslateElbowAction.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/TranslateElbowAction.java new file mode 100644 index 00000000..b500e0c2 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/TranslateElbowAction.java @@ -0,0 +1,232 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.actions; + +import java.util.List; + +import javax.vecmath.AxisAngle4f; +import javax.vecmath.Point3d; +import javax.vecmath.Vector3d; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.proconf.g3d.actions.ConstrainedTransformAction; +import org.simantics.proconf.g3d.actions.TranslateActionConstraints; +import org.simantics.proconf.g3d.base.G3DAPI; +import org.simantics.proconf.g3d.base.G3DTools; +import org.simantics.proconf.g3d.base.MathTools; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.gizmo.TransformInlineGizmo; +import org.simantics.proconf.g3d.scenegraph.IGraphicsNode; +import org.simantics.proconf.g3d.stubs.G3DNode; + +import fi.vtt.simantics.processeditor.Activator; +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.common.ControlPointTools; +import fi.vtt.simantics.processeditor.stubs.DirectedControlPoint; +import fi.vtt.simantics.processeditor.stubs.PipeControlPoint; +import fi.vtt.simantics.processeditor.stubs.VariableAngleTurnComponent; + +public class TranslateElbowAction extends ConstrainedTransformAction { + + TransformInlineGizmo gizmo; + List mos; + Vector3d dir; + Vector3d orgPos; + double istep = 10.0; + int decimals = 2; + + private Resource pcpResource; + + public TranslateElbowAction(ThreeDimensionalEditorBase parent) { + super(parent); + gizmo = new TransformInlineGizmo(component.getDisplaySystem().getRenderer()); + + + } + + public void init() { + this.setText("Translate directed"); + this.setToolTipText("Translate the elbow in connections direction"); + this.setImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/translate_d.png")); + } + + + + @Override + public boolean usable(Graph graph, List resources) { + // TODO : it should be possible to move multiple components on the same straight + // TODO : checking against elbow and dcp; these are not correct! + if (resources.size() != 1) + return false; + IEntity r = EntityFactory.create(graph,resources.get(0)); + if (r.isInstanceOf(ProcessResource.plant3Dresource.VariableAngleTurnComponent)) { + VariableAngleTurnComponent e = new VariableAngleTurnComponent(r); + PipeControlPoint pcp = e.getControlPoint(); + PipeControlPoint prev = ControlPointTools.findPreviousEnd(pcp); + PipeControlPoint next = ControlPointTools.findNextEnd(pcp); + DirectedControlPoint dcp = null; + int directedCount = 0; + if (prev != null && prev.isInstanceOf(ProcessResource.plant3Dresource.DirectedControlPoint)) { + directedCount++; + dcp = new DirectedControlPoint(prev); + } + if (next != null && next.isInstanceOf(ProcessResource.plant3Dresource.DirectedControlPoint)) { + directedCount++; + dcp = new DirectedControlPoint(next); + } + if (directedCount == 1) { + orgPos = G3DTools.getVector(dcp.getWorldPosition()); + dir = ControlPointTools.getDirectedControlPointDirection(dcp); + pcpResource = pcp.getResource(); + return true; + } + } + return false; + + } + + @Override + public void deactivate() { + parent.setGizmo(null); + super.deactivate(); + } + + @Override + public void activate() { + parent.setGizmo(gizmo); + + String text = ""; + mos = parent.getSelectionAdapter().getSelectedObjects(); +// for (IGraphicsNode mo : mos) { +// text += GraphicsNodeTools.getWorldTranslation(mo.getGraphicsNode());//mo.getWorldPosition() + " "; +// } + + mos.iterator().next().getGroup().attachChild(gizmo.getNode()); + setInfoText(text); + + Vector3d front = new Vector3d(1.0,0.0,0.0); + Vector3d current = new Vector3d(dir); + float angle = (float)current.angle(front); + AxisAngle4f aa; + if (angle < 0.01 || (Math.PI - angle) < 0.01) { + aa = new AxisAngle4f(); + } else { + current.normalize(); + Vector3d right = new Vector3d(); + right.cross(front, current); + + right.normalize(); + if (right.lengthSquared() < 0.01) { + aa = new AxisAngle4f(); + } else { + aa = new AxisAngle4f((float) right.x, (float) right.y, (float) right.z, angle); + } + } + gizmo.setRotation(aa); + + updateGizmo(); + TranslateActionConstraints.addConstraints(new Resource[]{pcpResource}, detector); + parent.setViewChanged(true); + } + + + + Vector3d getTranslate() { + Vector3d translate = new Vector3d(); + Vector3d o = new Vector3d(); + Vector3d d = new Vector3d(); + parent.createPickRay(o, d); + //Vector3d p = gizmo.getPosition(); + if (gizmo.isSelected()) { + double s[] = new double[1]; + + Vector3d i1 = new Vector3d(); + Vector3d i2 = new Vector3d(); + s = new double[2]; + MathTools.intersectStraightStraight(orgPos, dir,o, d, i2, i1,s); + translate.set(dir); + if (s[0] < 0.0) + s[0] = 0.0; + + translate.scale(s[0]); + translate.add(orgPos); + + if (useConstraints) { + Vector3d t = new Vector3d(translate); +// FIXME : snapped point may be outside of proper range + Point3d snap = detector.getPointSnap2(t, dir); + if (snap != null) { + translate = new Vector3d(snap); + } + } + + return translate; + } + return null; + } + + Vector3d prevTranslate = new Vector3d(); + + @Override + public void doChanges(Graph g) throws Exception { + if (input.mousePressed()) { + //prevTranslate = getTranslate(); + + } + if (input.mouseClicked()) { + end(); + return; + } + if (!input.mouseDragged()) { + parent.getDefaultAction().update(); + return; + } + parent.setViewChanged(true); + + + List mos = parent.getSelectionAdapter().getSelectedObjects(); + Vector3d translate = getTranslate(); + + if (translate == null) { + //cameraRotateAction.update(); + parent.getDefaultAction().update(); + updateGizmo(); + return; + } + + String text = ""; + for (IGraphicsNode mo : mos) { + G3DNode node = mo.getG3DNode(g); + G3DAPI.setWorldPosition(node, translate); + //G3DTools.setTuple3(node.getW, translation) + //G3DTools.setLocalTranslation(node,translate); + // mo.setLocalTranslation(translate); + text += G3DTools.getVector(node.getWorldPosition()) + " " + translate;// mo.getWorldPosition() + " " + + + } + setInfoText(text); + + updateGizmo(); + + } + + protected void updateGizmo() { + gizmo.update(camera.getCameraPos(),component); + } + + public void setInfoText(String text) { + + } + +} \ No newline at end of file diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/TranslateInlineComponentAction.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/TranslateInlineComponentAction.java new file mode 100644 index 00000000..ebb66498 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/TranslateInlineComponentAction.java @@ -0,0 +1,234 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.actions; + +import java.util.List; + +import javax.vecmath.Point3d; +import javax.vecmath.Vector3d; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IToolBarManager; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Resource; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.proconf.g3d.actions.ConstrainedTransformAction; +import org.simantics.proconf.g3d.base.G3DAPI; +import org.simantics.proconf.g3d.base.G3DTools; +import org.simantics.proconf.g3d.base.MathTools; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.gizmo.TransformInlineGizmo; +import org.simantics.proconf.g3d.scenegraph.IGraphicsNode; +import org.simantics.proconf.g3d.stubs.G3DNode; + +import fi.vtt.simantics.processeditor.Activator; +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.common.PipingTools2; +import fi.vtt.simantics.processeditor.stubs.InlineComponent; +import fi.vtt.simantics.processeditor.stubs.PipeControlPoint; + + +public class TranslateInlineComponentAction extends ConstrainedTransformAction { + + TransformInlineGizmo gizmo; + List mos; + Point3d start; + Point3d end; + Vector3d dir; + double istep = 10.0; + int decimals = 2; + + public TranslateInlineComponentAction(ThreeDimensionalEditorBase parent) { + super(parent); + gizmo = new TransformInlineGizmo(component.getDisplaySystem().getRenderer()); + + } + + public void init() { + this.setText("Translate"); + this.setToolTipText("Translate the object"); + this.setImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/translate_d.png")); + } + + + + @Override + public boolean usable(Graph graph, List resources) { + // TODO : it should be possible to move multiple components on the same straight + if (resources.size() != 1) + return false; + IEntity r = EntityFactory.create(graph,resources.get(0)); + PipeControlPoint pcp = null; + if (r.isInstanceOf(ProcessResource.plant3Dresource.FixedLengthInlineComponent)) { + InlineComponent component = new InlineComponent(r); + pcp = component.getControlPoint(); + } else { + return false; + } + if (pcp.getNext() == null || pcp.getPrevious() == null) + return false; + return true; + } + + @Override + public void deactivate() { + parent.setGizmo(null); + super.deactivate(); + } + + @Override + public void activate() { + parent.setGizmo(gizmo); + + String text = ""; + mos = parent.getSelectionAdapter().getSelectedObjects(); +// for (IGraphicsNode mo : mos) { +// text += GraphicsNodeTools.getWorldTranslation(mo.getGraphicsNode());//mo.getWorldPosition() + " "; +// } + + mos.iterator().next().getGroup().attachChild(gizmo.getNode()); + setInfoText(text); + + + start = new Point3d(); + end = new Point3d(); + dir = new Vector3d(); + parent.getSession().syncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + + InlineComponent ic = new InlineComponent(mos.iterator().next().getG3DNode(g)); + PipingTools2.getInlineMovement(ic, start, end); + + //PipingTools2.getInlineComponentEnds(ic, start, end); + dir.set(end); + dir.sub(start); + + return GraphRequestStatus.transactionComplete(); + } + }); + + updateGizmo(); + parent.setViewChanged(true); + } + + + + Vector3d getTranslate() { + Vector3d translate = new Vector3d(); + Vector3d o = new Vector3d(); + Vector3d d = new Vector3d(); + parent.createPickRay(o, d); + //Vector3d p = gizmo.getPosition(); + if (gizmo.isSelected()) { + double s[] = new double[1]; + + Vector3d i1 = new Vector3d(); + Vector3d i2 = new Vector3d(); + s = new double[2]; + MathTools.intersectStraightStraight( start, dir,o, d, i2, i1,s); + translate.set(dir); + if (s[0] < 0.0) + s[0] = 0.0; + else if (s[0] > 1.0) + s[0] = 1.0; + translate.scale(s[0]); + translate.add(start); + + if (useConstraints) { + Vector3d t = new Vector3d(translate); +// FIXME : snapped point may be outside of proper range + Point3d snap = detector.getPointSnap2(t, dir); + if (snap != null) { + translate = new Vector3d(snap); + } + } + + return translate; + } + return null; + } + + Vector3d prevTranslate = new Vector3d(); + + @Override + public void doChanges(Graph graph) throws Exception { + if (input.mousePressed()) { + //prevTranslate = getTranslate(); + + } + if (input.mouseClicked()) { + end(); + return; + } + if (!input.mouseDragged()) { + parent.getDefaultAction().update(); + return; + } + parent.setViewChanged(true); + + + List mos = parent.getSelectionAdapter().getSelectedObjects(); + Vector3d translate = getTranslate(); + + if (translate == null) { + //cameraRotateAction.update(); + parent.getDefaultAction().update(); + updateGizmo(); + return; + } + //translate.sub(prevTranslate); + +// if ((input.dragModifiers() & MouseEvent.CTRL_MASK) > 0) { +// String text = ""; +// for (IGraphicsNode mo : mos) { +// +// Point3d p = mo.getWorldPosition(); +// p.add(translate); +// p.x = Math.round(istep * p.x) / istep; +// BigDecimal bx = new BigDecimal(p.x); +// bx.setScale(decimals, BigDecimal.ROUND_HALF_UP); +// p.x = bx.doubleValue(); +// +// +// text += p + " "; +// mo.setWorldTranslation(p); +// +// } +// this.parent.setInfoText(text); +// +// } else { + String text = ""; + for (IGraphicsNode mo : mos) { + G3DNode node = mo.getG3DNode(graph); + G3DAPI.setWorldPosition(node, translate); + //G3DTools.setLocalTranslation(node, translate); + //mo.setLocalTranslation(translate); + text += G3DTools.getVector(node.getWorldPosition()) +" " + translate;//mo.getWorldPosition() + " " + translate; + } + setInfoText(text); +// } + updateGizmo(); + + } + + protected void updateGizmo() { + gizmo.update(camera.getCameraPos(),component); + } + + public void setInfoText(String text) { + + } + +} \ No newline at end of file diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/TranslateStraightAction.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/TranslateStraightAction.java new file mode 100644 index 00000000..84d3a641 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/TranslateStraightAction.java @@ -0,0 +1,404 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.actions; + +import java.util.List; + +import javax.vecmath.AxisAngle4f; +import javax.vecmath.Point3d; +import javax.vecmath.Vector3d; + +import org.eclipse.jface.action.IToolBarManager; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Resource; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.proconf.g3d.actions.ConstrainedTransformAction; +import org.simantics.proconf.g3d.actions.TranslateActionConstraints; +import org.simantics.proconf.g3d.base.G3DTools; +import org.simantics.proconf.g3d.base.MathTools; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.gizmo.AbstractGizmo; +import org.simantics.proconf.g3d.gizmo.TransformGizmo; +import org.simantics.proconf.g3d.gizmo.TransformInlineGizmo; + +import fi.vtt.simantics.processeditor.common.ControlPointTools; +import fi.vtt.simantics.processeditor.common.PipingTools2; +import fi.vtt.simantics.processeditor.stubs.FixedLengthInlineComponent; +import fi.vtt.simantics.processeditor.stubs.PipeControlPoint; + +import fi.vtt.simantics.processeditor.Activator; +import fi.vtt.simantics.processeditor.ProcessResource; + + +/** + * Action that allows translating VariableLengthInlineComontolPoints. + * + * TODO : Action won't show two gizmos when both ends can be moved + * TODO : With loose ends, gizmo is in the middle of component, when it should be positioned on the end of the component + * + * + * @author Marko Luukkainen + * + */ +public class TranslateStraightAction extends ConstrainedTransformAction { + + private static final int CONNECTED = 0; + private static final int LOOSE = 1; + + private AbstractGizmo gizmo; + private TransformGizmo transformGizmo; + private TransformInlineGizmo transformInlineGizmo; + + + //private Straight straight; + //private PipeControlPoint pcp; + + private Resource pcpResource; + + private int type; + + Vector3d prevTranslate = new Vector3d(); + + Point3d start; + Point3d end; + Vector3d dir; + double istep = 10.0; + int decimals = 2; + public TranslateStraightAction(ThreeDimensionalEditorBase parent) { + super(parent); + transformGizmo = new TransformGizmo(component.getDisplaySystem().getRenderer()); + transformInlineGizmo = new TransformInlineGizmo(component.getDisplaySystem().getRenderer()); + } + + public void init() { + this.setText("Translate"); + this.setToolTipText("Translate one end of a straight"); + this.setImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/translate_d.png")); + } + + @Override + public boolean usable(Graph graph, List resources) { + if (resources.size() != 1) + return false; + + IEntity r = EntityFactory.create(graph,resources.get(0)); + if (!r.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent)) { + return false; + } + FixedLengthInlineComponent flic = new FixedLengthInlineComponent(r); + PipeControlPoint scp = flic.getControlPoint(); + PipeControlPoint start = scp.getPrevious(); + PipeControlPoint end = scp.getNext(); + + if (start == null) { + pcpResource = scp.getResource(); + type = LOOSE; + return true; + } + if (end == null) { + pcpResource = scp.getResource(); + type = LOOSE; + return true; + } + if (start.isInstanceOf(ProcessResource.plant3Dresource.BranchEndControlPoint)) { + pcpResource = graph.getObjects(start.getResource(), ProcessResource.plant3Dresource.SubPointOf).iterator().next(); + type = CONNECTED; + return true; + } + if (end.isInstanceOf(ProcessResource.plant3Dresource.BranchEndControlPoint)) { + pcpResource = graph.getObjects(end.getResource(), ProcessResource.plant3Dresource.SubPointOf).iterator().next(); + type = CONNECTED; + return true; + } + + + return false; + + } + + @Override + public void deactivate() { + super.deactivate(); + parent.setGizmo(null); + + } + + @Override + public void activate() { + parent.getSession().syncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + PipeControlPoint pcp = new PipeControlPoint(g,pcpResource); + if (type == CONNECTED) { + gizmo = transformInlineGizmo; + + start = new Point3d(); + end = new Point3d(); + dir = new Vector3d(); + //ControlPointTools.getInlineControlPointEnds(pcp, start, end, dir); + ControlPointTools.getInlineMovement(pcp, start, end); + + //PipingTools2.getInlineComponentEnds(ic, start, end); + dir.set(end); + dir.sub(start); + + //System.out.println(start + " " + end + " " + dir); + Vector3d front = new Vector3d(1.0,0.0,0.0); + Vector3d current = new Vector3d(dir); + float angle = (float)current.angle(front); + AxisAngle4f aa; + if (angle < 0.01 || (Math.PI - angle) < 0.01) { + aa = new AxisAngle4f(); + } else { + current.normalize(); + Vector3d right = new Vector3d(); + right.cross(front, current); + + right.normalize(); + if (right.lengthSquared() < 0.01) { + aa = new AxisAngle4f(); + } else { + aa = new AxisAngle4f((float) right.x, (float) right.y, (float) right.z, angle); + } + } + transformInlineGizmo.setRotation(aa); + + } else { + gizmo = transformGizmo; + } + parent.setGizmo(gizmo); + + component.getNoShadowRoot().attachChild(gizmo.getNode()); + + updateGizmo(pcp); + TranslateActionConstraints.addConstraints(new Resource[]{pcpResource}, detector); + parent.setViewChanged(true); + + return GraphRequestStatus.transactionComplete(); + } + }); + + } + + + // FIXME : copy-paste from TranslateInlineAction.getTranslate() + Vector3d getTranslate() { + Vector3d translate = new Vector3d(); + Vector3d o = new Vector3d(); + Vector3d d = new Vector3d(); + parent.createPickRay(o, d); + // Vector3d p = gizmo.getPosition(); + if (((TransformInlineGizmo) gizmo).isSelected()) { + double s[] = new double[1]; + + Vector3d i1 = new Vector3d(); + Vector3d i2 = new Vector3d(); + s = new double[2]; + MathTools.intersectStraightStraight(start, dir, o, d, i2, i1, s); + translate.set(dir); + if (s[0] < 0.0) + s[0] = 0.0; + else if (s[0] > 1.0) + s[0] = 1.0; + translate.scale(s[0]); + translate.add(start); + + if (useConstraints) { + Vector3d t = new Vector3d(translate); + // FIXME : snapped point may be outside of proper range + Point3d snap = detector.getPointSnap2(t, dir); + if (snap != null) { + translate = new Vector3d(snap); + } + } + + return translate; + } + return null; + } + // FIXME : copy-paste from TranslateAction.getTranslate(Vector3d v) + Vector3d getTranslate(PipeControlPoint pcp, Vector3d offset) { + Vector3d translate = new Vector3d(); + Vector3d o = new Vector3d(); + Vector3d d = new Vector3d(); + parent.createPickRay(o, d); + Vector3d p = ((TransformGizmo)gizmo).getPosition(); + Vector3d dir = null; + switch (((TransformGizmo)gizmo).getSelected()) { + case TransformGizmo.XYZ : + Vector3d normal = camera.getUnNormalizedHeading(); + normal.normalize(); + double s[] = new double[1]; + Vector3d r = new Vector3d(); + if (MathTools.intersectStraightPlane(o, d, p, normal, r)) { + r.sub(p); + translate.x = r.x; + translate.y = r.y; + translate.z = r.z; + } + break; + case TransformGizmo.X : + dir = new Vector3d(1.0,0.0,0.0); + Vector3d i1 = new Vector3d(); + Vector3d i2 = new Vector3d(); + s = new double[2]; + MathTools.intersectStraightStraight( p, dir,o, d, i2, i1,s); + translate.x = s[0]; + + break; + case TransformGizmo.Y : + dir = new Vector3d(0.0,1.0,0.0); + i1 = new Vector3d(); + i2 = new Vector3d(); + s = new double[2]; + MathTools.intersectStraightStraight( p, dir,o, d, i2, i1,s); + translate.y = s[0]; + break; + case TransformGizmo.Z : + dir = new Vector3d(0.0,0.0,1.0); + i1 = new Vector3d(); + i2 = new Vector3d(); + s = new double[2]; + MathTools.intersectStraightStraight( p, dir,o, d, i2, i1,s); + translate.z = s[0]; + break; + case TransformGizmo.XY : + normal = new Vector3d(0.0,0.0,1.0); + s = new double[1]; + r = new Vector3d(); + if (MathTools.intersectStraightPlane(o, d, p, normal, r)) { + r.sub(p); + translate.x = r.x; + translate.y = r.y; + } + break; + case TransformGizmo.XZ : + normal = new Vector3d(0.0,1.0,0.0); + s = new double[1]; + r = new Vector3d(); + if (MathTools.intersectStraightPlane(o, d, p, normal, r)) { + r.sub(p); + translate.x = r.x; + translate.z = r.z; + } + break; + case TransformGizmo.YZ : + normal = new Vector3d(1.0,0.0,0.0); + s = new double[1]; + r = new Vector3d(); + if (MathTools.intersectStraightPlane(o, d, p, normal, r)) { + r.sub(p); + translate.y = r.y; + translate.z = r.z; + } + break; + default : + + return null; + } + //System.out.println(translate + " " + offset); + translate.sub(offset); + + if (useConstraints) { + switch (((TransformGizmo)gizmo).getSelected()) { + case TransformGizmo.X: + case TransformGizmo.Y: + case TransformGizmo.Z: + Vector3d t = new Vector3d(translate); + // TODO : to the test against all translated objects and snap to closest one + Point3d pos = G3DTools.getPoint(pcp.getLocalPosition()); + t.add(pos); + Point3d snap = detector.getPointSnap2(t, dir); + if (snap != null) { + // System.out.print("t: " + translate); + translate = new Vector3d(snap); + translate.sub(pos); + // System.out.println(" " + translate); + } + break; + + } + } + //System.out.println(translate); + return translate; + } + + + + @Override + public void doChanges(Graph graph) throws Exception { + PipeControlPoint pcp = new PipeControlPoint(graph, pcpResource); + if (input.mousePressed()) { + if (type == LOOSE) + prevTranslate = getTranslate(pcp,new Vector3d()); + + } + if (input.mouseClicked()) { + //System.out.println("end"); + end(); + return; + } + if (!input.mouseDragged()) { + parent.getDefaultAction().update(); + return; + } + detector.clearConstraintHighlights(); + parent.setViewChanged(true); + + + Vector3d translate; + if (type == CONNECTED) + translate = getTranslate(); + else + translate = getTranslate(pcp,prevTranslate); + + if (translate == null) { + //cameraRotateAction.update(); + parent.getDefaultAction().update(); + updateGizmo(pcp); + return; + } + + String text = ""; + + if (type == CONNECTED) { + G3DTools.setTuple3(pcp.getWorldPosition(), translate); + // mo.setLocalTranslation(translate); + //text += GraphicsNodeTools.getWorldTranslation(mo.getGraphicsNode()) + " " + translate;// mo.getWorldPosition() + if (useConstraints) + text+=detector.getSnapString(); + + } else { + G3DTools.addTuple3(pcp.getWorldPosition(), translate); + // mo.modifyWorldTranslation(translate); + //text += GraphicsNodeTools.getWorldTranslation(mo.getGraphicsNode()) + " ";//mo.getWorldPosition() + " "; + if (useConstraints) + text+=detector.getSnapString(); + + } + + setInfoText(text); + updateGizmo(pcp); + + } + + protected void updateGizmo(PipeControlPoint pcp) { + gizmo.update(G3DTools.getVector(pcp.getWorldPosition()), camera.getCameraPos(), component); + } + + public void setInfoText(String text) { + + } + +} \ No newline at end of file diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/adapters/InlineComponentConstraintAdapter.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/adapters/InlineComponentConstraintAdapter.java new file mode 100644 index 00000000..e21bda74 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/adapters/InlineComponentConstraintAdapter.java @@ -0,0 +1,36 @@ +package fi.vtt.simantics.processeditor.adapters; + +import javax.vecmath.Point3d; +import javax.vecmath.Vector3d; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.db.adaption.AdaptionException; +import org.simantics.db.adaption.ResourceAdapter; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.proconf.g3d.base.Constraint; + +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.common.PipingTools2; + +public class InlineComponentConstraintAdapter implements ResourceAdapter { + @SuppressWarnings("unchecked") + @Override + public T adapt(Graph graph, Resource resource, Resource mia) throws AdaptionException { + Constraint c = new Constraint(); + assert(graph.isInstanceOf(resource, ProcessResource.plant3Dresource.InlineComponent)); + IEntity ent = EntityFactory.create(graph,resource); + Point3d center = new Point3d(); + Point3d p1 = new Point3d(); + Point3d p2 = new Point3d(); + Vector3d dir = new Vector3d(); + PipingTools2.getInlineComponentEnds(ent, center, p1, p2, dir); + c.points.add(center); + c.points.add(p1); + c.points.add(p2); + c.dirs.add(dir); + return (T) c; + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/adapters/NozzleConstraintAdapter.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/adapters/NozzleConstraintAdapter.java new file mode 100644 index 00000000..33b8075f --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/adapters/NozzleConstraintAdapter.java @@ -0,0 +1,32 @@ +package fi.vtt.simantics.processeditor.adapters; + +import javax.vecmath.Point3d; +import javax.vecmath.Vector3d; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.db.adaption.AdaptionException; +import org.simantics.db.adaption.ResourceAdapter; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.proconf.g3d.base.Constraint; +import org.simantics.proconf.g3d.base.G3DTools; + +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.common.PipingTools2; + +public class NozzleConstraintAdapter implements ResourceAdapter { + @SuppressWarnings("unchecked") + @Override + public T adapt(Graph graph, Resource resource, Resource mia) throws AdaptionException { + Constraint c = new Constraint(); + assert(graph.isInstanceOf(resource, ProcessResource.plant3Dresource.Nozzle)); + IEntity ent = EntityFactory.create(graph,resource); + Vector3d dir = PipingTools2.getNozzleDirection(ent); + Point3d center = G3DTools.getPoint(ent.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition)); + c.points.add(center); + c.dirs.add(dir); + return (T) c; + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/adapters/TurnComponentConstraintAdapter.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/adapters/TurnComponentConstraintAdapter.java new file mode 100644 index 00000000..4df00b55 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/adapters/TurnComponentConstraintAdapter.java @@ -0,0 +1,42 @@ +package fi.vtt.simantics.processeditor.adapters; + +import javax.vecmath.Point3d; +import javax.vecmath.Vector3d; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.db.adaption.AdaptionException; +import org.simantics.db.adaption.ResourceAdapter; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.proconf.g3d.base.Constraint; +import org.simantics.proconf.g3d.base.G3DTools; + +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.actions.PositionType; +import fi.vtt.simantics.processeditor.common.ControlPointTools; +import fi.vtt.simantics.processeditor.common.PipingTools2.Direction; + +public class TurnComponentConstraintAdapter implements ResourceAdapter { + @SuppressWarnings("unchecked") + @Override + public T adapt(Graph graph, Resource resource, Resource mia) throws AdaptionException { + Constraint c = new Constraint(); + assert(graph.isInstanceOf(resource, ProcessResource.plant3Dresource.TurnComponent)); + IEntity ent = EntityFactory.create(graph,resource); + IEntity pcp = ent.getSingleRelatedObject(ProcessResource.plant3Dresource.HasControlPoint); + + Point3d center = G3DTools.getPoint(pcp.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition)); + Point3d p1 = ControlPointTools.getRealPosition(pcp, PositionType.NEXT); + Point3d p2 = ControlPointTools.getRealPosition(pcp, PositionType.PREVIOUS); + Vector3d dir1 = ControlPointTools.getPathLegDirection(pcp, Direction.NEXT); + Vector3d dir2 = ControlPointTools.getPathLegDirection(pcp, Direction.PREVIOUS); + c.points.add(center); + c.points.add(p1); + c.points.add(p2); + c.dirs.add(dir1); + c.dirs.add(dir2); + return (T) c; + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/animations/PipeAnimationController.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/animations/PipeAnimationController.java new file mode 100644 index 00000000..0524171f --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/animations/PipeAnimationController.java @@ -0,0 +1,141 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.animations; + +import java.net.URL; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.runtime.FileLocator; +import org.eclipse.core.runtime.Path; +import org.simantics.db.Graph; +import org.simantics.layer0.utils.IEntity; +import org.simantics.proconf.g3d.animation.Animatable; +import org.simantics.proconf.g3d.animation.AnimationController; +import org.simantics.proconf.g3d.base.JmeRenderingComponent; + +import com.jme.bounding.BoundingBox; +import com.jme.image.Texture; +import com.jme.intersection.PickResults; +import com.jme.math.Ray; +import com.jme.renderer.Renderer; +import com.jme.scene.Node; +import com.jme.scene.state.AlphaState; +import com.jme.scene.state.TextureState; +import com.jme.scene.state.ZBufferState; +import com.jme.util.TextureManager; +import com.jmex.effects.particles.ParticleGeometry; + +import fi.vtt.simantics.processeditor.Activator; +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.stubs.PipeRun; +import fi.vtt.simantics.processeditor.stubs.VariableLengthInlineComponent; + + +public class PipeAnimationController implements AnimationController { + private List pipeAnimations = new ArrayList(); + + List animatables = new ArrayList(); + + private double d = Math.random(); + private double delta = 0.01; + + AlphaState as1; + TextureState ts; + Node particleNode = new Node() { + private static final long serialVersionUID = 7477121374264124684L; + + // Without this picking code tries to pick particles which doesn't work (Causes class cast exception) + public void findPick(Ray toTest, PickResults results) { + return; + } + }; + + public PipeAnimationController(JmeRenderingComponent component, PipeRun pipeline) { + as1 = component.getDisplaySystem().getRenderer().createAlphaState(); + as1.setBlendEnabled(true); + as1.setSrcFunction(AlphaState.SB_SRC_ALPHA); + as1.setDstFunction(AlphaState.DB_ONE); + //as1.setDstFunction(AlphaState.DB_ONE_MINUS_SRC_ALPHA); + as1.setTestEnabled(true); + as1.setTestFunction(AlphaState.TF_GREATER); + as1.setEnabled(true); + + TextureState ts = component.getDisplaySystem().getRenderer().createTextureState(); + //URL url = FileLocator.find(com.jme.eclipse.Activator.getDefault().getBundle(),new Path("data/textures/flaresmall.jpg"),null); + URL url = FileLocator.find(Activator.getDefault().getBundle(),new Path("icons/bubble.png"),null); + + ts.setTexture( + TextureManager.loadTexture(url, + Texture.MM_LINEAR_LINEAR, + Texture.FM_LINEAR)); + ts.setEnabled(true); + + ZBufferState zs = component.getDisplaySystem().getRenderer().createZBufferState(); + zs.setFunction(ZBufferState.CF_LEQUAL); + zs.setWritable(false); + //zs.setFunction(ZBufferState.CF_ALWAYS); + particleNode.setRenderState(as1); + particleNode.setRenderState(ts); + particleNode.setRenderState(zs); + particleNode.setRenderQueueMode(Renderer.QUEUE_TRANSPARENT); + component.getShadowRoot().attachChild(particleNode); + createAnimations(pipeline); + } + + public void addAnimatable(Animatable animatable) { + animatables.add((PipeFlowAnimation)animatable); + + } + + public void setAnimatable(Animatable animatable) { + animatables.clear(); + animatables.add((PipeFlowAnimation)animatable); + + } + + + public void updateAnimation(Graph g, double frameTime) { + d += delta; + if (d > 1.0) { + d = 1.0; + delta = -delta; + } else if (d < 0.0) { + delta = -delta; + d = 0.0; + } + for (Animatable a : animatables) + a.animate(d,frameTime); + } + + public void dispose() { + for (ParticleGeometry p : pipeAnimations) + p.removeFromParent(); + pipeAnimations.clear(); + + } + + private void createAnimations(PipeRun pipeline) { + List straights = new ArrayList(); + for (IEntity t : pipeline.getChild()) { + if (t.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent)) + straights.add(t); + } + + for (IEntity r : straights) { + animatables.add(new PipeFlowAnimation(pipeAnimations, particleNode, new VariableLengthInlineComponent(r),false)); + } + particleNode.setModelBound(new BoundingBox()); + particleNode.updateModelBound(); + particleNode.updateRenderState(); + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/animations/PipeFlowAnimation.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/animations/PipeFlowAnimation.java new file mode 100644 index 00000000..d86358da --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/animations/PipeFlowAnimation.java @@ -0,0 +1,144 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.animations; + +import java.util.List; + +import javax.vecmath.Point3d; +import javax.vecmath.Vector3d; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.proconf.g3d.animation.Animatable; +import org.simantics.proconf.g3d.base.G3DTools; +import org.simantics.proconf.g3d.base.VecmathJmeTools; + +import com.jme.renderer.ColorRGBA; +import com.jme.scene.Node; +import com.jmex.effects.particles.ParticleFactory; +import com.jmex.effects.particles.ParticleGeometry; + + +import fi.vtt.simantics.processeditor.common.ControlPointTools; +import fi.vtt.simantics.processeditor.common.PipingTools2; +import fi.vtt.simantics.processeditor.stubs.PipeControlPoint; +import fi.vtt.simantics.processeditor.stubs.VariableLengthInlineComponent; + + +public class PipeFlowAnimation implements Animatable{ + + ParticleGeometry particle; + float length; + int numParticles; + + public PipeFlowAnimation(List pipeAnimations, Node particleNode, VariableLengthInlineComponent s, boolean reversed) { + PipeControlPoint pcp = s.getControlPoint(); + + Point3d p1 = new Point3d(); + Point3d p2 = new Point3d(); + + ControlPointTools.getInlineControlPointEnds(pcp, p2, p1); + + if (reversed) { + Point3d t = p1; + p1 = p2; + p2 = t; + } + + + Vector3d dir = new Vector3d(p2); + dir.sub(p1); + length = (float)dir.length(); + //if (length < 0.1f) + // return; + //continue; + // with longer pipes particles will travel too far so the length of the pipe must be scaled + length *= 0.83f; + float vel = 0.1f; + //float size = (float)s.getPipeRadiusValue() + 0.1f; + //size *= 2.f; + float size = (float)s.getPipeDiameter()[0]; + //size *= 1.2f; + float life = length/vel; + + //int releaseRate = 40; + //int numParticles = (int)(releaseRate * life / 100.f);//(int)(releaseRate * life / 500.f); + + numParticles = (int)(length * 2.0); + int releaseRate = (int)((numParticles * 500.0) / life); + + if (numParticles < 2) + numParticles = 2; + + particle = ParticleFactory.buildParticles("Animation of " + s.getResource().getResourceId(),numParticles, ParticleGeometry.PT_QUAD);//new ParticleMesh("Animation of " + r.getId(),40); + particle.setEmissionDirection(VecmathJmeTools.get(dir).normalize()); + particle.setLocalTranslation(VecmathJmeTools.get(p1)); + particle.setEmitType(ParticleGeometry.ET_POINT); + particle.setInitialVelocity(vel); + particle.setMinimumAngle(0.f); + particle.setMaximumAngle(0.f); + particle.setReleaseRate(releaseRate); + particle.getParticleController().setReleaseVariance(0.f); + particle.getParticleController().setControlFlow(true); + particle.setStartColor(new ColorRGBA(1.f,1.f,0.f,1.f)); + particle.setEndColor(new ColorRGBA(1.f,1.f,0.f,1.f)); + particle.setStartSize(size); + particle.setEndSize(size); + setFlow(vel); + particle.getParticleController().setSpeed(vel); + particle.warmUp(60); + pipeAnimations.add(particle); + particleNode.attachChild(particle); + } + + ParticleGeometry getParticleGeometry() { + return particle; + } + + private void setFlow(float vel) { + float life; + if (vel > 0.f) + life = length/vel; + else + life = 0.f; + particle.setInitialVelocity(vel); + particle.setMaximumLifeTime(life); + particle.setMinimumLifeTime(life); + particle.getParticleController().setSpeed(vel); + + } + + private void setReleaserate(float vel) { + float life; + if (vel > 0.f) + life = length/vel; + else + life = 0.f; + particle.setInitialVelocity(vel); + particle.setMaximumLifeTime(life); + particle.setMinimumLifeTime(life); + particle.setReleaseRate((int)((numParticles * 500.0) / life)); + } + + public void animate(double delta,double frameRate) { + //setFlow(0.1f*(float)delta); + setReleaserate(0.05f*(float)delta); + } + + public boolean setAnimation(Graph graph, Resource animation) { + return false; + } + + public boolean setRandomAnimation(Graph graph) { + return false; + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/animations/ResourcePipeAnimationController.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/animations/ResourcePipeAnimationController.java new file mode 100644 index 00000000..43505000 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/animations/ResourcePipeAnimationController.java @@ -0,0 +1,72 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.animations; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.proconf.g3d.base.JmeRenderingComponent; + +import com.jme.renderer.ColorRGBA; + +import fi.vtt.simantics.processeditor.stubs.PipeRun; + +// TODO : this class won't work with valueSets +public class ResourcePipeAnimationController extends PipeAnimationController { + Resource color; + Resource velocity; + + ColorRGBA minColor = new ColorRGBA(0.f,0.f,1.f,1.f); + ColorRGBA maxColor = new ColorRGBA(1.f,0.f,0.f,1.f); + ColorRGBA currentColor = new ColorRGBA(1.f,1.f,1.f,1.f); + + double colorMin; + double colorMax; + double iColorRange; + + double velMin; + double velMax; + double iVelRange; + public ResourcePipeAnimationController(JmeRenderingComponent component, PipeRun pipeline, Resource color,double colorMin, double colorMax, Resource velocity, double velMin, double velMax) { + super(component, pipeline); + this.color = color; + this.velocity = velocity; + + this.colorMin = colorMin; + this.colorMax = colorMax; + this.iColorRange = 1.0/(colorMax-colorMin); + this.velMin = velMin; + this.velMax = velMax; + this.iVelRange = 1.0/(velMax-velMin); + } + + private double getVelocity(Graph graph) { + return graph.getScalarDouble(velocity); + //velocity.getDoubleScalarValue(); + } + + private double getColor(Graph graph) { + return graph.getScalarDouble(color); + } + public void updateAnimation(Graph g,double frameTime) { + double d = (getVelocity(g)-velMin)*iVelRange; + float f = (float)((getColor(g)-colorMin)*iColorRange); + currentColor.interpolate(minColor, maxColor, f); + for (PipeFlowAnimation a : animatables) { + a.animate(d,frameTime); + //a.getParticleGeometry().setDefaultColor(currentColor); + a.getParticleGeometry().setStartColor(currentColor); + a.getParticleGeometry().setEndColor(currentColor); + } + } + + + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/ControlPointTools.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/ControlPointTools.java new file mode 100644 index 00000000..077ea704 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/ControlPointTools.java @@ -0,0 +1,1198 @@ +package fi.vtt.simantics.processeditor.common; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Stack; + +import javax.vecmath.AxisAngle4d; +import javax.vecmath.Matrix3d; +import javax.vecmath.Point3d; +import javax.vecmath.Quat4d; +import javax.vecmath.Tuple3d; +import javax.vecmath.Vector3d; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.proconf.g3d.base.G3DTools; +import org.simantics.proconf.g3d.base.MathTools; +import org.simantics.proconf.g3d.base.TransformationTools; +import org.simantics.utils.ErrorLogger; +import org.simantics.utils.datastructures.Pair; + +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.actions.PositionType; +import fi.vtt.simantics.processeditor.common.PipingTools2.Direction; +import fi.vtt.simantics.processeditor.stubs.PipeControlPoint; +import fi.vtt.simantics.processeditor.stubs.PipeRun; + +public class ControlPointTools { + + private static boolean DEBUG = false; + + private static TransformationTools tt; + + public static void initialize() { + tt = new TransformationTools(ProcessResource.plant3Dresource.HasSubPoint,ProcessResource.plant3Dresource.SubPointOf) { + @Override + public IEntity getParent(IEntity node) { + IEntity parent = super.getParent(node); + if (parent == null) { + parent = node.getAtMostOneRelatedObject(ProcessResource.plant3Dresource.ControlPointOf); + if (parent != null) + parent = parent.getAtMostOneRelatedObject(ProcessResource.g3dResource.HasParent); + else + parent = node.getAtMostOneRelatedObject(ProcessResource.g3dResource.HasParent); + + } + return parent; + } + }; + } + + public static void deinitialize() { + tt = null; + } + + /** + * Adds new control point between given control points. + * New pcp must be already part of the same piperun as previous CP and nextCP + * + * SizeChangeControlPoints cannot be inserted with this method, since it does link two different piperuns to each other + * + * @param newCP + * @param previousCP + * @param nextCP + */ + public static void insertControlPoint(IEntity newCP, IEntity previousCP, IEntity nextCP) { + // inserting an offsetpoint is error, + assert(!newCP.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)); + // size change control point cannot be inserted this way, because it ends PipeRun + assert(!newCP.isInstanceOf(ProcessResource.plant3Dresource.SizeChangeControlPoint)); + + IEntity piperun = previousCP.getSingleRelatedObject(ProcessResource.plant3Dresource.ControlPointOfPipeRun); + // and just to make sure that control point structure is not corrupted + assert(piperun.equals(nextCP.getSingleRelatedObject(ProcessResource.plant3Dresource.ControlPointOfPipeRun))); + assert(piperun.equals(newCP.getSingleRelatedObject(ProcessResource.plant3Dresource.ControlPointOfPipeRun))); + + // insert new BranchControlPoint between straight's control points + IEntity previousNext = previousCP.getAtMostOneRelatedObject(ProcessResource.plant3Dresource.HasNext); + IEntity previousPrevious = previousCP.getAtMostOneRelatedObject(ProcessResource.plant3Dresource.HasPrevious); + + IEntity offsetCP = null; + + if (newCP.isInstanceOf(ProcessResource.plant3Dresource.OffsettingPoint)) { + offsetCP = newCP.getSingleRelatedObject(ProcessResource.plant3Dresource.HasSubPoint); + } + + if (previousNext != null && previousNext.equals(nextCP)) { + assert(!previousCP.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)); + assert(!nextCP.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)); + + setStatement(previousCP, ProcessResource.plant3Dresource.HasNext, newCP); + setStatement(newCP, ProcessResource.plant3Dresource.HasPrevious, previousCP); + + if (previousCP.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)) { + IEntity sccp = previousCP.getSingleRelatedObject(ProcessResource.plant3Dresource.SubPointOf); + setStatement(sccp, ProcessResource.plant3Dresource.HasNext, newCP); + } + + setStatement(newCP, ProcessResource.plant3Dresource.HasNext, nextCP); + + if (offsetCP == null) { + setStatement(nextCP, ProcessResource.plant3Dresource.HasPrevious, newCP); + } else { + setStatement(nextCP, ProcessResource.plant3Dresource.HasPrevious, offsetCP); + setStatement(offsetCP, ProcessResource.plant3Dresource.HasNext, nextCP); + setStatement(offsetCP, ProcessResource.plant3Dresource.HasPrevious, previousCP); + } + + if (nextCP.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)) { + IEntity ocp = nextCP.getSingleRelatedObject(ProcessResource.plant3Dresource.HasSubPoint); + setStatement(ocp, ProcessResource.plant3Dresource.HasPrevious, newCP); + } + + } else if (previousPrevious != null && previousPrevious.equals(nextCP)) { + // control point were given in reverse order + assert(!nextCP.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)); + assert(!previousCP.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)); + + setStatement(newCP, ProcessResource.plant3Dresource.HasNext, previousCP); + if (offsetCP == null) { + setStatement(previousCP, ProcessResource.plant3Dresource.HasPrevious, newCP); + } else { + setStatement(previousCP, ProcessResource.plant3Dresource.HasPrevious, offsetCP); + setStatement(offsetCP, ProcessResource.plant3Dresource.HasNext, previousCP); + setStatement(offsetCP, ProcessResource.plant3Dresource.HasPrevious, nextCP); + } + + if (previousCP.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)) { + IEntity ocp = previousCP.getSingleRelatedObject(ProcessResource.plant3Dresource.HasSubPoint); + setStatement(ocp, ProcessResource.plant3Dresource.HasPrevious, newCP); + } + + setStatement(newCP, ProcessResource.plant3Dresource.HasPrevious, nextCP); + setStatement(nextCP, ProcessResource.plant3Dresource.HasNext, newCP); + if (nextCP.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)) { + IEntity sccp = nextCP.getSingleRelatedObject(ProcessResource.plant3Dresource.SubPointOf); + setStatement(sccp, ProcessResource.plant3Dresource.HasNext, newCP); + } + } else { + ErrorLogger.defaultLogError( + "Route pipe : could not find connection between straight pipe's control points", null); + } + + } + + /** + * Adds new control point attaching it to given control point. + * If the new control point is SizeChangeControlPoint, it must have its offset point set. + * + * @param newCP + * @param pcp + * @param direction + */ + public static void insertControlPoint(IEntity newCP, IEntity pcp, Direction direction) { + assert(!newCP.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)); + if (direction == Direction.NEXT) { + // if direction is next, user must have given OffsetPoint + assert(!pcp.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)); + // basic next/prev links + pcp.removeRelatedStatements(ProcessResource.plant3Dresource.HasNext); + pcp.addStatement(ProcessResource.plant3Dresource.HasNext, newCP); + newCP.removeRelatedStatements(ProcessResource.plant3Dresource.HasPrevious); + newCP.addStatement(ProcessResource.plant3Dresource.HasPrevious, pcp); + // and last take care of sizechange / offset points + if (pcp.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)) { + IEntity sccp = pcp.getSingleRelatedObject(ProcessResource.plant3Dresource.SubPointOf); + sccp.removeRelatedStatements(ProcessResource.plant3Dresource.HasNext); + sccp.addStatement(ProcessResource.plant3Dresource.HasNext, newCP); + } + if (newCP.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)) { + IEntity ocp = newCP.getSingleRelatedObject(ProcessResource.plant3Dresource.HasSubPoint); + ocp.removeRelatedStatements(ProcessResource.plant3Dresource.HasPrevious); + ocp.addStatement(ProcessResource.plant3Dresource.HasPrevious, pcp); + } + } else { + // if direction is previous, user must have given sizechange + assert(!pcp.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)); + // previous direction is more complicated, since if newCP is SizeChangeControlPoint, + // we must link pcp to newCP's OffsetPoint + IEntity nocp = null; + if (newCP.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)) { + nocp = newCP.getSingleRelatedObject(ProcessResource.plant3Dresource.HasSubPoint); + nocp.removeRelatedStatements(ProcessResource.plant3Dresource.HasNext); + nocp.addStatement(ProcessResource.plant3Dresource.HasNext, pcp); + } + pcp.removeRelatedStatements(ProcessResource.plant3Dresource.HasPrevious); + if (nocp == null) + pcp.addStatement(ProcessResource.plant3Dresource.HasPrevious, newCP); + else + pcp.addStatement(ProcessResource.plant3Dresource.HasPrevious, nocp); + + newCP.removeRelatedStatements(ProcessResource.plant3Dresource.HasNext); + newCP.addStatement(ProcessResource.plant3Dresource.HasNext, pcp); + if (pcp.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)) { + IEntity ocp = pcp.getSingleRelatedObject(ProcessResource.plant3Dresource.HasSubPoint); + ocp.removeRelatedStatements(ProcessResource.plant3Dresource.HasPrevious); + if (nocp == null) + ocp.addStatement(ProcessResource.plant3Dresource.HasPrevious, newCP); + else + ocp.addStatement(ProcessResource.plant3Dresource.HasPrevious, nocp); + } + + } + } + + /** + * Returns path legs direction + * @param pcp + * @param direction + * @return + */ + public static Vector3d getPathLegDirection(IEntity pcp,Direction direction) { + IEntity previous = pcp.getAtMostOneRelatedObject(ProcessResource.plant3Dresource.HasPrevious); + IEntity next = pcp.getAtMostOneRelatedObject(ProcessResource.plant3Dresource.HasNext); + if (direction == Direction.NEXT) { + if (next != null) { + if (pcp.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)) + pcp = pcp.getSingleRelatedObject(ProcessResource.plant3Dresource.HasSubPoint); + Point3d p1 = G3DTools.getPoint(pcp.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition)); + Point3d p2 = G3DTools.getPoint(next.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition)); + Vector3d v = new Vector3d(); + v.sub(p2, p1); + return v; + } else { + if (pcp.isInstanceOf(ProcessResource.plant3Dresource.VariableAngleTurnControlPoint)) + throw new RuntimeException("Cannot calculate path leg direction for unconnected variable angle control point " + pcp.getResource()); + if (previous == null) { + if (!pcp.isInstanceOf(ProcessResource.plant3Dresource.DirectedControlPoint)) + throw new RuntimeException("Cannot calculate path leg direction for unconnected control point " + pcp.getResource()); + else + return getDirectedControlPointDirection(pcp); + } else { + if (pcp.isInstanceOf(ProcessResource.plant3Dresource.InlineControlPoint)) { + Point3d p1 = G3DTools.getPoint(previous.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition)); + Point3d p2 = G3DTools.getPoint(pcp.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition)); + Vector3d v = new Vector3d(); + v.sub(p2, p1); + return v; + } + throw new RuntimeException("Missing implementation"); + } + } + } else { + if (previous != null) { + if (pcp.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)) + pcp = pcp.getSingleRelatedObject(ProcessResource.plant3Dresource.SubPointOf); + Point3d p1 = G3DTools.getPoint(pcp.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition)); + Point3d p2 = G3DTools.getPoint(previous.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition)); + Vector3d v = new Vector3d(); + v.sub(p2, p1); + return v; + } else { + if (pcp.isInstanceOf(ProcessResource.plant3Dresource.VariableAngleTurnControlPoint)) + throw new RuntimeException("Cannot calculate path leg direction for unconnected variable angle control point " + pcp.getResource()); + if (next == null) { + if (!pcp.isInstanceOf(ProcessResource.plant3Dresource.DirectedControlPoint)) + throw new RuntimeException("Cannot calculate path leg direction for unconnected control point " + pcp.getResource()); + else { + Vector3d v = getDirectedControlPointDirection(pcp); + v.negate(); + return v; + } + } else { + if (pcp.isInstanceOf(ProcessResource.plant3Dresource.InlineControlPoint)) { + Point3d p1 = G3DTools.getPoint(next.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition)); + Point3d p2 = G3DTools.getPoint(pcp.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition)); + Vector3d v = new Vector3d(); + v.sub(p2, p1); + return v; + } + throw new RuntimeException("Missing implementation"); + } + } + } + + } + + /** + * Return positions (world) of an InlineComponents ends + * @param pcp + * @param p1 + * @param p2 + */ + public static void getInlineControlPointEnds(IEntity pcp, Point3d p1, Point3d p2) { + assert (pcp.isInstanceOf(ProcessResource.plant3Dresource.InlineControlPoint)); + + Point3d pos = G3DTools.getPoint(pcp.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition)); + Vector3d dir = ControlPointTools.getPathLegDirection(pcp, Direction.NEXT); + dir.normalize(); + double length = pcp.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength); + dir.scale(length * 0.5); + p1.set(pos); + p2.set(pos); + p1.add(dir); + p2.sub(dir); + } + + /** + * Return positions (world) of an InlineComponents ends + * @param pcp + * @param p1 + * @param p2 + */ + public static void getInlineControlPointEnds(IEntity pcp, Point3d p1, Point3d p2, Vector3d dir) { + assert (pcp.isInstanceOf(ProcessResource.plant3Dresource.InlineControlPoint)); + + Point3d pos = G3DTools.getPoint(pcp.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition)); + dir.set(ControlPointTools.getPathLegDirection(pcp, Direction.NEXT)); + double length = pcp.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength); + Vector3d d = new Vector3d(dir); + d.scale(length * 0.5); + p1.set(pos); + p2.set(pos); + p1.add(d); + p2.sub(d); + } + + /** + * Return positions (world) of an InlineComponents ends + * @param pcp + * @param p1 + * @param p2 + */ + public static void getInlineControlPointEnds(IEntity pcp, Point3d center, Point3d p1, Point3d p2, Vector3d dir) { + assert (pcp.isInstanceOf(ProcessResource.plant3Dresource.InlineControlPoint)); + + Point3d pos = G3DTools.getPoint(pcp.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition)); + center.set(pos); + dir.set(ControlPointTools.getPathLegDirection(pcp, Direction.NEXT)); + double length = pcp.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength); + Vector3d d = new Vector3d(dir); + d.scale(length * 0.5); + p1.set(pos); + p2.set(pos); + p1.add(d); + p2.sub(d); + } + + public static double getInlineLength(IEntity pcp) { + double l2 = 0.0; + if (pcp.isInstanceOf(ProcessResource.plant3Dresource.TurnControlPoint)) { + l2 += pcp.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength); + } else if (pcp.isInstanceOf(ProcessResource.plant3Dresource.InlineControlPoint)) { + l2 += pcp.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength) * 0.5; + } + return l2; + } + + /** + * Returns position (world) of a single port + * @param pcp + * @param type + * @return + */ + public static Point3d getRealPosition(IEntity pcp, PositionType type) { + PipeControlPoint p= new PipeControlPoint(pcp); + Point3d pos = G3DTools.getPoint(p.getWorldPosition()); + switch (type) { + case NEXT: { + Vector3d dir = ControlPointTools.getPathLegDirection(pcp,Direction.NEXT); + double length = getInlineLength(pcp); + dir.normalize(); + dir.scale(length); + pos.add(dir); + break; + } + case PREVIOUS: { + Vector3d dir = ControlPointTools.getPathLegDirection(pcp,Direction.PREVIOUS); + double length = getInlineLength(pcp); + 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 static void getInlineMovement(PipeControlPoint pcp, Point3d start, Point3d end) { + // FIXME : check type of neighbor components and allow movement on top of variable length components, + // ffind proper range for movement (pcp's position is not) + PipeControlPoint prev = pcp.getPrevious().getPrevious(); + PipeControlPoint next = pcp.getNext().getNext(); + start.set(G3DTools.getPoint(prev.getWorldPosition())); + end.set(G3DTools.getPoint(next.getWorldPosition())); + } + + public static AxisAngle4d getControlPointLocalRotation(IEntity pcp, double angle) { + Quat4d q1 = getControlPointLocalOrientationQuat(pcp, angle); + AxisAngle4d aa= new AxisAngle4d(); + aa.set(q1); + return aa; + } + + public static AxisAngle4d getControlPointWorldRotation(IEntity pcp, double angle) { + Quat4d q1 = getControlPointWorldOrientationQuat(pcp, angle); + AxisAngle4d aa= new AxisAngle4d(); + aa.set(q1); + return aa; + } + + + public static Quat4d getControlPointLocalOrientationQuat(IEntity pcp, double angle) { + return getControlPointLocalOrientationQuat(pcp, angle, false); + } + + public static Quat4d getControlPointWorldOrientationQuat(IEntity pcp, double angle) { + return getControlPointWorldOrientationQuat(pcp, angle, false); + } + + public static Quat4d getControlPointLocalOrientationQuat(IEntity cp, double angle, boolean offset) { + PipeControlPoint pcp = new PipeControlPoint(cp); + PipeControlPoint next; + // if pcp is size change control point with offset, next control point is not in line with previous and pcp control point (it's offsetted) + // else it's more numerically stable to use next control point + if (offset) + next = pcp; + else + next = pcp.getNext(); + + PipeControlPoint prev = pcp.getPrevious(); + assert (next != null || prev != null); + if (prev == null) + prev = pcp; + else if (next == null) + next = pcp; + // TODO : check correct type + if (pcp.isInstanceOf(ProcessResource.plant3Dresource.PathLegEndControlPoint) && pcp.getPrevious() == null) { + PipeControlPoint temp = next; + next = prev; + prev = temp; + } + Vector3d current = new Vector3d(G3DTools.getPoint(next.getLocalPosition())); + current.sub(G3DTools.getPoint(prev.getLocalPosition())); + current.normalize(); + return getControlPointOrientationQuat(current, angle); + } + + public static Quat4d getControlPointWorldOrientationQuat(IEntity cp, double angle, boolean offset) { + PipeControlPoint pcp = new PipeControlPoint(cp); + PipeControlPoint next; + // if pcp is size change control point with offset, next control point is not in line with previous and pcp control point (it's offsetted) + // else it's more numerically stable to use next control point + if (offset) + next = pcp; + else + next = pcp.getNext(); + + PipeControlPoint prev = pcp.getPrevious(); + assert (next != null || prev != null); + if (prev == null) + prev = pcp; + else if (next == null) + next = pcp; + // TODO : check correct type + if (pcp.isInstanceOf(ProcessResource.plant3Dresource.PathLegEndControlPoint) && pcp.getPrevious() == null) { + PipeControlPoint temp = next; + next = prev; + prev = temp; + } + Vector3d current = new Vector3d(G3DTools.getPoint(next.getWorldPosition())); + current.sub(G3DTools.getPoint(prev.getWorldPosition())); + current.normalize(); + return getControlPointOrientationQuat(current, angle); + } + + public static Quat4d getControlPointOrientationQuat(Vector3d dir, double angle) { + + + final Vector3d front = new Vector3d(1.0,0.0,0.0); + + Quat4d q1 = new Quat4d(); + + 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); + } + + 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 static PipeControlPoint findPreviousEnd(PipeControlPoint tcp) { + // TODO : optimize (we do not need the list here) + ArrayList t = new ArrayList(); + return findPreviousEnd(tcp, t); + } + + public static PipeControlPoint findNextEnd(PipeControlPoint tcp) { + // TODO : optimize (we do not need the list here) + ArrayList t = new ArrayList(); + return findNextEnd(tcp, t); + } + + /** + * Returns pipe leg's end using "nextControlPoint" relation and collects control point in the given list. + * @param tcp + * @param nextList + * @return + */ + public static PipeControlPoint findNextEnd(PipeControlPoint tcp, ArrayList nextList) { + if (DEBUG) System.out.print("PipingTools.findNextEnd " + tcp.getResource()); + while (true) { + PipeControlPoint pcp = null; + PipeControlPoint p = null; + if (nextList.size() == 0) + p = tcp; + + 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.isInstanceOf(ProcessResource.plant3Dresource.PathLegEndControlPoint)) { + if (DEBUG) System.out.println(" " + pcp.getResource()); + return pcp; + } else { + nextList.add(pcp); + if (DEBUG) System.out.print(" " + pcp.getResource()); + } + } + } + + + + /** + * Returns pipe leg's end using "previousControlPoint" relation and collects control point in the given list. + * @param tcp + * @param prevList + * @return + */ + public static PipeControlPoint findPreviousEnd(PipeControlPoint tcp, ArrayList prevList) { + if (DEBUG) System.out.print("PipingTools.findPreviousEnd " + tcp.getResource()); + while (true) { + PipeControlPoint pcp = null; + PipeControlPoint p = null; + if (prevList.size() == 0) + p = tcp; + + 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.isInstanceOf(ProcessResource.plant3Dresource.PathLegEndControlPoint)) { + if (DEBUG) System.out.println(" " + pcp.getResource()); + return pcp; + } else { + prevList.add(pcp); + if (DEBUG) System.out.print(" " + pcp.getResource()); + } + } + } + + public static PipeRun getPipeRun(PipeControlPoint pcp) { + return pcp.getControlPointOfPipeRun(); + } + + @Deprecated + public static Vector3d getSizeChangeOffsetVector(PipeControlPoint sccp) { + Quat4d q = getControlPointWorldOrientationQuat(sccp, sccp.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasRotationAngle),true); + return getSizeChangeOffsetVector(sccp,q); + } + + public static Vector3d getSizeChangeOffsetVector(PipeControlPoint sccp, Vector3d dir) { + Quat4d q = getControlPointOrientationQuat(dir, sccp.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasRotationAngle)); + return getSizeChangeOffsetVector(sccp,q); + } + + public static Vector3d getSizeChangeOffsetVector(PipeControlPoint sccp, Quat4d q) { + Vector3d v = new Vector3d(0.0,0.0,sccp.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasOffset)); + Vector3d offset = new Vector3d(); + MathTools.rotate(q, v, offset); + return offset; + } + + public static Vector3d getDirectedControlPointDirection(IEntity dcp) { + assert(dcp.isInstanceOf(ProcessResource.plant3Dresource.DirectedControlPoint)); + AxisAngle4d worldR = G3DTools.getOrientation(dcp.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldOrientation)); + Quat4d q = new Quat4d(); + q.set(worldR); + Vector3d dir = new Vector3d(); + MathTools.rotate(q, new Vector3d(1.0, 0.0, 0.0), dir); + dir.normalize(); + return dir; + } + + public static Vector3d getNozzleDirection(IEntity rotation) { + AxisAngle4d worldR = G3DTools.getOrientation(rotation); + Quat4d q = new Quat4d(); + q.set(worldR); + Vector3d dir = new Vector3d(); + MathTools.rotate(q, new Vector3d(1.0, 0.0, 0.0), dir); + return dir; + } + + public static Vector3d getNozzleDirection(PipeControlPoint dcp) { + return getNozzleDirection(dcp.getWorldOrientation()); + } + + public static void removeControlPoint(PipeControlPoint removed) { + if (DEBUG) System.out.println("PipingTools.removeControlPoint() controlpoint " + removed.getResource());//FIXME : offset + size change control points ! + + // this code is not valid anymore. + + // different removing cases: + // + // 1. Point is SizeChangeControlPoint (this is currently ok) + // * remove offset point and component + // * do NOT link components together + // + // 2. Point is VariableLength + // * check if its a branch (TODO : ontology support?) + // * if so, also branch point in the other piperun may have to be removed + // (we cannot move other components next to branch) + // * if not, components next to removed one are moved next to each other + // 3. Other + // * check if there is VariableLength on both sides, + // * if so, those must be unified to a single Variable Length component. + // * if not, components must be moved next to each other + // + // a) If removed Control Point is next to Nozzle and after the point is removed nozzle is not connected to anything + // * nozzle's link to piperun's specs must be removed + // + + + if (removed.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)|| + removed.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)) { + // sccp & ocp connect two pipeRuns to each other; when thoes are remove, pipeRuns are not connected to each other anymore. + removeDualPoint(removed); + return; + } else { + PipeControlPoint prev = removed.getPrevious(); + PipeControlPoint next = removed.getNext(); + PipeRun pipeRun = getPipeRun(removed); + if (pipeRun == null) + return; + if (next == null && prev == null) { + if (removed.isInstanceOf(ProcessResource.plant3Dresource.NozzleControlPoint)) { + // Nozzle's control point does not need to be removed, only unlinked + // TODO : what about component ports? + PipingTools2.unlinkNozzleAndPiperun(removed.getSingleRelatedObject(ProcessResource.plant3Dresource.ControlPointOf), ControlPointTools.getPipeRun(removed)); + return; + } + } else { + + if (next != null && prev != null) { + boolean link = true; + if (next.isInstanceOf(ProcessResource.plant3Dresource.BranchEndControlPoint)){ + link = false; + next.removeRelatedStatements(ProcessResource.plant3Dresource.HasPrevious); + removed.removeRelatedStatements(ProcessResource.plant3Dresource.HasNext); + removeControlPoint(next); + } + if (prev.isInstanceOf(ProcessResource.plant3Dresource.BranchEndControlPoint)) { + link = false; + prev.removeRelatedStatements(ProcessResource.plant3Dresource.HasNext); + removed.removeRelatedStatements(ProcessResource.plant3Dresource.HasPrevious); + removeControlPoint(prev); + } + if (link && prev.isInstanceOf(ProcessResource.plant3Dresource.DirectedControlPoint)&& + next.isInstanceOf(ProcessResource.plant3Dresource.DirectedControlPoint)) { + link = false; + } + if (next.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)) { + PipeControlPoint sccp = next; + PipeControlPoint ocp = sccp.getSubPoint().iterator().next(); + if (ocp == null) { + ErrorLogger.defaultLogError("Removing PipeControlPoint " + removed.getResource()+ " structure damaged, no offset control point",null); + return; + } + if (link) { + sccp.setPrevious(prev); + ocp.setPrevious(prev); + } else { + sccp.removeRelatedStatements(ProcessResource.plant3Dresource.HasPrevious); + ocp.removeRelatedStatements(ProcessResource.plant3Dresource.HasPrevious); + + } + removed.removeRelatedStatements(ProcessResource.plant3Dresource.HasNext); + } else if (next.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)) { + ErrorLogger.defaultLogError("Removing PipeControlPoint " + removed.getResource()+ " structure damaged, next control point is offset control point",null); + return; + } else if (next.getPrevious().getResource().equals(removed.getResource())) { + if (link) { + next.setPrevious(prev); + } else { + next.removeRelatedStatements(ProcessResource.plant3Dresource.HasPrevious); + } + removed.removeRelatedStatements(ProcessResource.plant3Dresource.HasNext); + } else { + ErrorLogger.defaultLogError("Removing PipeControlPoint "+ removed.getResource()+ " structure damaged", null); + return; + } + if (prev.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)) { + ErrorLogger.defaultLogError("Removing PipeControlPoint " + removed.getResource() + " structure damaged, previous control point is size change control point", null); + return; + } else if (prev.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)) { + PipeControlPoint ocp = prev; + PipeControlPoint sccp = ocp.getSubPointOf(); + if (sccp == null) { + ErrorLogger.defaultLogError("Removing PipeControlPoint " + removed.getResource() + " structure damaged, no size change control point",null); + return; + } + if (link) { + ocp.setNext(next); + sccp.setNext(next); + } else { + ocp.removeRelatedStatements(ProcessResource.plant3Dresource.HasNext); + sccp.removeRelatedStatements(ProcessResource.plant3Dresource.HasNext); + } + removed.removeRelatedStatements(ProcessResource.plant3Dresource.HasPrevious); + } else if (prev.getNext().getResource().equals(removed.getResource())) { + if (link) + prev.setNext(next); + else + prev.removeRelatedStatements(ProcessResource.plant3Dresource.HasNext); + removed.removeRelatedStatements(ProcessResource.plant3Dresource.HasPrevious); + } else { + ErrorLogger.defaultLogError("Removing PipeControlPoint " + removed.getResource() + " structure damaged", null); + return; + } + if (link) { + if (next.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthControlPoint) && + prev.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthControlPoint)) { + // we have to join them into single variable length component. + removeControlPoint(prev); + } + } + + + } else if (next != null) { + if (next.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)) { + PipeControlPoint sccp = next; + PipeControlPoint ocp = sccp.getSubPoint().iterator().next(); + if (ocp == null) { + ErrorLogger.defaultLogError("Removing PipeControlPoint "+ removed.getResource()+ " structure damaged, no offset control point",null); + return; + } + next.removeRelatedStatements(ProcessResource.plant3Dresource.HasPrevious); + ocp.removeRelatedStatements(ProcessResource.plant3Dresource.HasPrevious); + } else if (next.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)) { + ErrorLogger.defaultLogError("Removing PipeControlPoint " + removed.getResource() + " structure damaged, next control point is offset control point", null); + return; + } else if (next.getPrevious().getResource().equals(removed.getResource())) { + next.removeRelatedStatements(ProcessResource.plant3Dresource.HasPrevious); + } else { + ErrorLogger.defaultLogError("Removing PipeControlPoint " + removed.getResource() + " structure damaged", null); + return; + } + removed.removeRelatedStatements(ProcessResource.plant3Dresource.HasNext); + } else { //(prev != null) + if (prev.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)) { + ErrorLogger.defaultLogError("Removing PipeControlPoint " + removed.getResource() + " structure damaged, previous control point is size change control point", null); + return; + } else if (prev.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)) { + PipeControlPoint ocp = prev; + PipeControlPoint sccp = ocp.getSubPointOf(); + if (sccp == null) { + ErrorLogger.defaultLogError("Removing PipeControlPoint " + removed.getResource() + " structure damaged, no size change control point", null); + return; + } + prev.removeRelatedStatements(ProcessResource.plant3Dresource.HasNext); + sccp.removeRelatedStatements(ProcessResource.plant3Dresource.HasNext); + } else if (prev.getNext().getResource().equals(removed.getResource())) { + prev.removeRelatedStatements(ProcessResource.plant3Dresource.HasNext); + } else { + ErrorLogger.defaultLogError("Removing PipeControlPoint "+ removed.getResource() + " structure damaged", null); + return; + } + removed.removeRelatedStatements(ProcessResource.plant3Dresource.HasPrevious); + } + + } + if (removed.getSubPoint().size() > 0 ) { + removeSubPoints(removed); + } else if (removed.getSubPointOf() != null) { + removeParentPoint(removed); + } + + removeComponents(removed); + + pipeRun.removeStatement(ProcessResource.plant3Dresource.HasControlPoints, removed); + if (pipeRun.getChild().size() == 0) { + PipingTools2.removePipeRun(pipeRun); + } + else if (pipeRun.getControlPoints().size() == 1) { + removeControlPoint(pipeRun.getControlPoints().iterator().next()); + } + } + + } + + private static void removeDualPoint(PipeControlPoint removed) { + PipeControlPoint prev = removed.getPrevious(); + PipeControlPoint next = removed.getNext(); + if (prev != null) { + prev.removeRelatedStatements(ProcessResource.plant3Dresource.HasNext); + } + if (next != null) + next.removeRelatedStatements(ProcessResource.plant3Dresource.HasPrevious); + PipeControlPoint ocp; + PipeControlPoint sccp; + // get sccp / ocp pair + if (removed.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)) { + sccp = removed; + ocp = sccp.getSubPoint().iterator().next(); + + } else { + ocp = removed; + sccp = ocp.getSubPointOf(); + } + PipeRun p1 = getPipeRun(ocp); + PipeRun p2 = getPipeRun(sccp); + + // removes all components connected to control point + + removeComponents(ocp); + + removeComponents(sccp); + + // remove control points from pipeRuns + p1.removeStatement(ProcessResource.plant3Dresource.HasControlPoints, ocp); + p2.removeStatement(ProcessResource.plant3Dresource.HasControlPoints, sccp); + + // remove links to other control points + ocp.removeRelatedStatements(ProcessResource.plant3Dresource.HasNext); + sccp.removeRelatedStatements(ProcessResource.plant3Dresource.HasNext); + ocp.removeRelatedStatements(ProcessResource.plant3Dresource.HasPrevious); + sccp.removeRelatedStatements(ProcessResource.plant3Dresource.HasPrevious); + + // if pipeRuns contains no other components(control points), they can be removed too. + if (p1.getControlPoints().size() == 0) { + PipingTools2.removePipeRun(p1); + } else if (p1.getControlPoints().size() == 1) { + removeControlPoint(p1.getControlPoints().iterator().next()); + } + if (p2.getControlPoints().size() == 0) { + PipingTools2.removePipeRun(p2); + } else if (p2.getControlPoints().size() == 1) { + removeControlPoint(p2.getControlPoints().iterator().next()); + } + } + + /** + * Removes sub points of a point + * @param removed + * @throws TransactionException + */ + private static void removeSubPoints(PipeControlPoint removed) { + // if control point is branch control point, all branch of points must be removed too + Collection points = removed.getSubPoint(); + + for (PipeControlPoint p : points) { + removed.removeStatement(ProcessResource.plant3Dresource.HasSubPoint, p); + removeControlPoint(p); + } + } + + /** + * Removed point is a subpoint of something, + * @param removed + */ + private static void removeParentPoint(PipeControlPoint removed) { + throw new RuntimeException("Subpoints cannot be removed"); + + // if control point is branch it has to be removed from branch control point +// BranchEndControlPoint ecp = BranchEndControlPointFactory.create(removed); +// BranchControlPoint bcp = null; +// if (ecp.getBranchOfPointSet().size() == 1) { +// bcp = ecp.getBranchOfPointSet().iterator().next(); +// } +// if (bcp != null) { +// bcp.getBranchPointSet().remove(ecp); +// if (bcp.getBranchPointSet().size() == 0) { +// // branch control point is not used and can be removed +// removeControlPoint(bcp); +// } +// } + } + + + private static void removeComponents(PipeControlPoint pcp) { + IEntity component = pcp.getControlPointOf(); + if (component != null) { + PipeRun p1 = getPipeRun(pcp); + p1.removeStatement(ProcessResource.g3dResource.HasChild, component); + component.removeRelatedStatements(ProcessResource.plant3Dresource.HasControlPoint); + } + } + + private static void setStatement(IEntity subject, Resource relation, IEntity object) { + subject.removeRelatedStatements(relation); + subject.addStatement(relation, object); + } + + + public static void setWorldPosition(IEntity pcp, Tuple3d position) { + IEntity wp = pcp.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition); + G3DTools.setTuple3(wp, position); + tt.propagateWorldTransformChange(tt.getParent(pcp), pcp); + + } + + public static void setLocalPosition(IEntity pcp, Tuple3d position) { + G3DTools.setTuple3(pcp.getSingleRelatedObject(ProcessResource.g3dResource.HasLocalPosition), position); + tt.propagateLocalTransformChange(tt.getParent(pcp), pcp); + } + + public static void setWorldOrientation(IEntity node, AxisAngle4d orientation) { + G3DTools.setOrientation(node.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldOrientation), orientation); + tt.propagateWorldTransformChange(tt.getParent(node), node); + + } + + public static void setLocalOrientation(IEntity node, AxisAngle4d orientation) { + G3DTools.setOrientation(node.getSingleRelatedObject(ProcessResource.g3dResource.HasLocalOrientation), orientation); + tt.propagateLocalTransformChange(tt.getParent(node), node); + } + + private static boolean updatePosition(IEntity pcp) { + return tt.transformationUpdate(pcp); + + + // TODO : orientation is also needed, current code handles only position + // TODO : reuse the code in G3DTools! + /* + IEntity worldPosition = pcp.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition); + IEntity localPosition = pcp.getSingleRelatedObject(ProcessResource.g3dResource.HasLocalPosition); + + + Tuple3d worldP = G3DTools.getPoint(worldPosition); + Tuple3d localP = G3DTools.getPoint(localPosition); + + if (localP == null || worldP == null) + return false; + if (!isValid(worldP) && !isValid(localP)) + return false; + + Tuple3d cachedWorldP = (Tuple3d) getProperty(worldPosition.getResource()); + Tuple3d cachedLocalP = (Tuple3d) getProperty(localPosition.getResource()); + + if (DEBUG) System.out.println("PipeControlPoint changed " + worldP + " " + cachedWorldP + " " + localP + " " + cachedLocalP); + boolean changed = false; + + IEntity parent = pcp.getSingleRelatedObject(ProcessResource.plant3Dresource.ControlPointOf); + + if (parent == null) { + if (DEBUG) System.out.println("PipeControlPoint changed, no parent node"); + return false; + } + + if (cachedLocalP == null) { + storeProperty(localPosition.getResource(), localP); + Tuple3d p = G3DTools.getWorldFromLocal(parent, new Point3d(localP)); + storeProperty(worldPosition.getResource(), p); + G3DTools.setTuple3(worldPosition, p); + if (DEBUG) System.out.println("PipeControlPoint changed local " + worldP + " " + p); + changed = true; + } else { + if (TransformationTools.changed(cachedLocalP, localP)) { + storeProperty(localPosition.getResource(), localP); + Tuple3d p = G3DTools.getWorldFromLocal(parent, new Point3d(localP)); + storeProperty(worldPosition.getResource(), p); + G3DTools.setTuple3(worldPosition, p); + if (DEBUG) System.out.println("PipeControlPoint changed local " + worldP + " " + localP); + changed = true; + } + if (cachedWorldP == null) { + storeProperty(worldPosition.getResource(), worldP); + Tuple3d p = G3DTools.getLocalFromWorld(parent, new Point3d(worldP)); + G3DTools.setTuple3(localPosition, p); + storeProperty(localPosition.getResource(), p); + if (DEBUG) System.out.println("PipeControlPoint changed world " + worldP + " " + p); + changed = true; + } else { + if (TransformationTools.changed(cachedWorldP, worldP)) { + storeProperty(worldPosition.getResource(), worldP); + Tuple3d p = G3DTools.getLocalFromWorld(parent, new Point3d(worldP)); + G3DTools.setTuple3(localPosition, p); + storeProperty(localPosition.getResource(), p); + if (DEBUG) System.out.println("PipeControlPoint changed world " + worldP + " " + p); + changed = true; + } + } + } + return changed; + //*/ + } + + static boolean isControlPointChanged(PipeControlPoint node) { + long id = node.getResource().getResourceId(); + boolean changed = updatePosition(node); + //if (!changed) { + if (node.isInstanceOf(ProcessResource.plant3Dresource.PathLegEndControlPoint)) { + if (node.isInstanceOf(ProcessResource.plant3Dresource.TurnControlPoint)) { + Pair connected = (Pair)getProperty(node.getResource().getResourceId()); + PipeControlPoint next = node.getNext(); + PipeControlPoint prev = node.getPrevious(); + if ((next != null && prev != null) && ( + connected == null || + (connected.first == null && prev != null) || + (connected.second == null && next != null) || + !connected.first.equals(prev.getResource().getResourceId()) || + !connected.second.equals(next.getResource().getResourceId()))) { + storeProperty(id, new Pair(prev.getResource().getResourceId(),next.getResource().getResourceId())); + changed = true; + } + if (node.isInstanceOf(ProcessResource.plant3Dresource.VariableAngleTurnControlPoint)) { + double r = node.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasTurnRadius); + Double d = (Double)getProperty(id + ":turnradius"); + if (d == null || TransformationTools.changed(r, d)) { + storeProperty(id + ":turnradius", r); + changed = true; + } + } + } + else if (node.isInstanceOf(ProcessResource.plant3Dresource.DirectedControlPoint)) { + Vector3d dir = ControlPointTools.getDirectedControlPointDirection(node); + Vector3d old = (Vector3d)getProperty(id + ":direction"); + if (old == null || TransformationTools.changed(dir, old)) { + storeProperty(id + ":direction", dir); + changed = true; + } + } + } else { // InlineControlPoint + if (node.isInstanceOf(ProcessResource.plant3Dresource.FixedLengthControlPoint)) { + double length = node.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength); + Double d = (Double)getProperty(id + ":length"); + if (d == null) + changed = true; + else + changed = changed || TransformationTools.changed(length, d); + + if (changed) { + storeProperty(id + ":length", length); + return true; + } + } else + if (node.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)) { + + double angle = node.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasRotationAngle); + Double d = (Double)getProperty(id + ":rotationangle"); + if (d == null) + changed = true; + else + changed = changed || TransformationTools.changed(angle, d); + if (changed) { + storeProperty(id + ":rotationangle", angle); + return true; + } + Collection subpoints = node.getSubPoint(); + if (subpoints.size() != 1) + throw new RuntimeException("Current implementation assumes that size change components are dual conmnected"); + PipeControlPoint ocp = subpoints.iterator().next(); + if (node.isInstanceOf(ProcessResource.plant3Dresource.OffsettingPoint)) { + double offset = ocp.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasOffset); + d = (Double)getProperty(id +":offset"); + if (d == null) + changed = true; + else + changed = TransformationTools.changed(offset, d); + if (changed) { + storeProperty(id+":offset", offset); + return true; + } + } +// } else if (node instanceof OffsetControlPoint) { +// OffsetControlPoint ocp = (OffsetControlPoint)node; +// //ocp. +// } else if (node instanceof BranchControlPoint) { +// BranchControlPoint bcp = (BranchControlPoint)node; +// int size = bcp.getBranchPointSet().size(); +// Integer i = (Integer)getProperty(bcp.getResource().getId()); +// if (i == null) +// changed =true; +// else +// changed = changed || i != size; +// if (changed) { +// storeProperty(bcp.getResource().getId(), size); +// return true; +// } + } + } + //} + + return changed; + } + + private static boolean isValid(Tuple3d v) { + if (Double.isInfinite(v.x) || + Double.isNaN(v.x) || + Double.isInfinite(v.y) || + Double.isNaN(v.y) || + Double.isInfinite(v.z) || + Double.isNaN(v.z)) + return false; + return true; + } + + private static HashMap properties = new HashMap(); + + public static Object getProperty(Object key) { + return properties.get(key); + } + + public static void storeProperty(Object key, Object value) { + properties.put(key, value); + } + + /** + * Loads positions of controlpoint to rule cache + * + * TODO : this caches only transformation information : other info must be cached too + * + * @param root resource of the modeled plant + */ + public static void reloadCache(Graph graph, Resource root) { + + Stack stack = new Stack(); + stack.add(EntityFactory.create(graph,root)); + while (!stack.isEmpty()) { + IEntity current = stack.pop(); + IEntity pcp = current.getAtMostOneRelatedObject(ProcessResource.plant3Dresource.HasControlPoint); + if (pcp == null) { + stack.addAll(current.getRelatedObjects(ProcessResource.g3dResource.HasChild)); + } else { + if (DEBUG) System.out.println("Cached pcp " + pcp.getResource()); + IEntity localPos = pcp.getSingleRelatedObject(ProcessResource.g3dResource.HasLocalPosition); + IEntity worldPos = pcp.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition); + + tt.storeProperty(localPos.getResource(),G3DTools.getPoint(localPos)); + tt.storeProperty(worldPos.getResource(),G3DTools.getPoint(worldPos)); + + IEntity localOr = pcp.getAtMostOneRelatedObject(ProcessResource.g3dResource.HasLocalOrientation); + IEntity worldOr = pcp.getAtMostOneRelatedObject(ProcessResource.g3dResource.HasWorldOrientation); + + if (worldOr != null) { + tt.storeProperty(localOr.getResource(),G3DTools.getOrientation(localOr)); + tt.storeProperty(worldOr.getResource(),G3DTools.getOrientation(worldOr)); + } + + stack.addAll(pcp.getRelatedObjects(ProcessResource.plant3Dresource.HasSubPoint)); + } + } + + } +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/PathUtils.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/PathUtils.java new file mode 100644 index 00000000..9ddaf040 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/PathUtils.java @@ -0,0 +1,145 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.common; + +import java.util.ArrayList; +import java.util.Collection; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.layer0.utils.viewpoints.TraversalPath; +import org.simantics.proconf.browsing.GraphExplorer; +import org.simantics.utils.datastructures.Pair; + + + + + +public class PathUtils { + + public static void createPath(java.util.List samplePath, TraversalPath path, Resource sampleInstance, Resource sampleSource, GraphExplorer oe) { +// while (tNode != null) { +// long[] path = tNode.getPath(); +// for (int i = 0; i < path.length; i++) { +// samplePath.add(i, path[i]); +// } +// samplePath.add(path.length,tNode.getCoreId()); +// tNode = oe.getTreeParent(tNode); +// } + while (path != null) { + Resource predicate = path.getPredicate(); + Resource obj = path.getResource(); + if (predicate != null) { + samplePath.add(0,predicate); + path = path.getTail(); + } else { + // there is no relation and so this has to be root + path = null; + } + samplePath.add(1,obj); + + } + + if (!sampleInstance.equals(samplePath.get(0)) || !sampleSource.equals(samplePath.get(samplePath.size()-1))) { + String s = ""; + for (int i = 0; i < samplePath.size(); i++) { + s += samplePath.get(i) + " "; + } + throw new RuntimeException("Path from " + sampleInstance + " to " + + sampleSource + " is broken: " + s); + } + +// String s = ""; +// for (int i = 0; i < samplePath.size(); i++) { +// s += samplePath.get(i) + " "; +// } +// System.out.println("Path from " + sampleInstance + " to " + sampleSource + " is: " + s); + samplePath.remove(0); + } + + + + /** + * Finds similar path in cloned resource + * TODO : this isn't correct way to do this; + * Rigth way would be finding mapping between two clones + * and then find the similar resource + * (Viewpoint used to create clone is required) + * + * @param path + * @param begin + * @return + */ + public static IEntity findSimilar(java.util.List path, IEntity begin) { + if (path.size() == 0) + return begin; + if (path.size() == 1) + return null; + Graph g = begin.getGraph(); + java.util.List tPath = new ArrayList(); + tPath.addAll(path); + + Resource p = tPath.get(0); // predicate (relation) + Resource o = tPath.get(1); // object + tPath.remove(0); + tPath.remove(0); + + IEntity predicate = EntityFactory.create(g, p); + + + Collection possibleObjects = begin.getRelatedObjects(predicate); + if (possibleObjects.size() == 0) + return null; + if (possibleObjects.size() == 1) + return findSimilar(tPath, possibleObjects.iterator().next()); + else { + IEntity object = EntityFactory.create(g, o); + Collection objectTypes = object.getTypes(); + java.util.List> list = new ArrayList>(); + for (IEntity possible : possibleObjects) { + boolean matchTypes = true; + for (IEntity type : objectTypes) { + if(!possible.isInstanceOf(type)) { + matchTypes = false; + break; + } + + } + if (matchTypes) { + IEntity r = findSimilar(tPath,possible); + if (r != null) + list.add(new Pair(possible,r)); + //return r; + } + } + if (list.size() == 0) + return null; + if (list.size() == 1) + return list.get(0).second; + else { + // uses names of objects to detect similarities + String name = object.getName(); + if (name != null) { + for (Pair possible : list) { + String otherName = possible.first.getName(); + //System.out.println(name + " : " + otherName); + if (otherName != null && name.compareTo(otherName) == 0) + return possible.second; + } + } + } + } + + return null; + } +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/PipeComponentProvider.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/PipeComponentProvider.java new file mode 100644 index 00000000..a59e0f81 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/PipeComponentProvider.java @@ -0,0 +1,531 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.common; + +import java.nio.FloatBuffer; +import java.nio.IntBuffer; + +import javax.vecmath.AxisAngle4d; +import javax.vecmath.Point3d; +import javax.vecmath.Quat4d; +import javax.vecmath.Vector3d; + +import org.simantics.layer0.utils.IEntity; +import org.simantics.proconf.g3d.base.G3DTools; +import org.simantics.proconf.g3d.base.GeometryProvider; +import org.simantics.proconf.g3d.base.MathTools; +import org.simantics.utils.ErrorLogger; + +import com.jme.scene.Geometry; +import com.jme.scene.Line; +import com.jme.scene.TriMesh; +import com.jme.util.geom.BufferUtils; + +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.stubs.PipeControlPoint; +import fi.vtt.simantics.processeditor.stubs.PipelineComponent; +import fi.vtt.simantics.processeditor.stubs.TurnControlPoint; + + +/** + * Geometry provider for pipe components. + * TODO : split into three providers (one for each type) to faster access (ShapeNodes can cache geometry provider) + * + * @author Marko Luukkainen + * + */ +public class PipeComponentProvider implements GeometryProvider { + + + //private static double ELBOW_RING_ANGLE = 12.0/ Math.PI; + //private static int RING_SEGMENTS = 8; + + private static double ELBOW_RING_ANGLE = 24.0/ Math.PI; + private static int RING_SEGMENTS = 16; + + public boolean canHandle(IEntity instance) { + if (instance.isInstanceOf(ProcessResource.plant3Dresource.Elbow)) + return true; + if (instance.isInstanceOf(ProcessResource.plant3Dresource.Straight)) + return true; + if (instance.isInstanceOf(ProcessResource.plant3Dresource.Reducer)) + return true; + return false; + } + + + public Geometry[] getGeometryFromResource(IEntity instance, boolean transform) { + if (instance.isInstanceOf(ProcessResource.plant3Dresource.Elbow)) { + Geometry[] g = new Geometry[]{new TriMesh(),new Line()}; + if( getElbowGeometry(instance,g)) { + return g; + } + return null; + } + + if (instance.isInstanceOf(ProcessResource.plant3Dresource.Straight)) { + Geometry[] g = new Geometry[]{new TriMesh(),new Line()}; + if( getStraightGeometry(instance,g)) { + return g; + } + return null; + } + if (instance.isInstanceOf(ProcessResource.plant3Dresource.Reducer)) { + Geometry[] g = new Geometry[]{new TriMesh(),new Line()}; + if (getReducerGeometry(instance,g)) { + return g; + } + return null; + } + return null; + } + + public boolean reconstructGeometry(IEntity instance, boolean transform, Geometry[] geometry) { + if (instance.isInstanceOf(ProcessResource.plant3Dresource.Elbow)) + return getElbowGeometry(instance,geometry); + if (instance.isInstanceOf(ProcessResource.plant3Dresource.Straight)) + return getStraightGeometry(instance,geometry); + if (instance.isInstanceOf(ProcessResource.plant3Dresource.Reducer)) + return getReducerGeometry(instance,geometry); + + return false; + } + + public boolean getElbowGeometry(IEntity instance, Geometry[] geometry) { + PipelineComponent elbow = new PipelineComponent(instance); + PipeControlPoint pcp = elbow.getControlPoint(); + if (pcp == null) { + ErrorLogger.defaultLogError("Elbow " + instance + " has no control point", null); + return false; + } + TurnControlPoint tcp = new TurnControlPoint(pcp); + // double turnAngleValue = tcp.getTurnAngleValue(); + + double pipeRadius = elbow.getPipeDiameter()[0]*0.5; + double elbowRadius = elbow.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasTurnRadius); + double R = tcp.getLength()[0]; //getComponentOffset(); + double turnAngle = tcp.getTurnAngle()[0]; + + PipeControlPoint startControlPoint = tcp.getPrevious(); + PipeControlPoint endControlPoint = tcp.getNext(); + if (startControlPoint == null || endControlPoint == null) + return false; + + //Point3d start = getLocalPoint(pipeline,startControlPoint); + //Point3d middle = getLocalPoint(pipeline,tcp); + //Point3d end = getLocalPoint(pipeline,endControlPoint); + + Point3d start = G3DTools.getPoint(startControlPoint.getWorldPosition()); + Point3d middle = G3DTools.getPoint(tcp.getWorldPosition()); + Point3d end = G3DTools.getPoint(endControlPoint.getWorldPosition()); + + Vector3d dir1 = new Vector3d(middle); + dir1.sub(start); + Vector3d dir2 = new Vector3d(end); + dir2.sub(middle); + + Vector3d n = new Vector3d(dir1); + n.normalize(); + Vector3d offset = new Vector3d(n); + + offset.scale(R); + Vector3d startPipe = new Vector3d(middle); + startPipe.sub(offset); + // normal of the plane + Vector3d normal = new Vector3d(); + normal.cross(dir1, dir2); + Vector3d elbowCenter = new Vector3d(); + elbowCenter.cross(normal, dir1); + elbowCenter.normalize(); + elbowCenter.scale(elbowRadius); + elbowCenter.add(startPipe); + + elbowCenter.sub(middle); + + // creates sweep shape by rotating a circle + // several values must be checked if they are infinite (OCC crashes if they are) + if (turnAngle > 0.001 && normal.lengthSquared() > 0.0 && !(Double.isInfinite(turnAngle)) && isValid(n) && isValid(startPipe)) { +// System.out.println(startPipe + " " + middle + " " + n + " " + elbowCenter + " " + normal + " " + turnAngle); +// gp_Circ circ = new gp_Circ(new double[] { startPipe.x - middle.x, startPipe.y - middle.y, +// startPipe.z - middle.z, n.x, n.y, n.z }, pipeRadius); +// TopoDS_Edge ed = (TopoDS_Edge) new BRepBuilderAPI_MakeEdge(circ).shape(); +// TopoDS_Wire w = (TopoDS_Wire) new BRepBuilderAPI_MakeWire(ed).shape(); +// TopoDS_Face F = (TopoDS_Face) new BRepBuilderAPI_MakeFace(w).shape(); +// TopoDS_Shape S4 = new BRepPrimAPI_MakeRevol(F, new double[] { elbowCenter.x, elbowCenter.y, elbowCenter.z, +// normal.x, normal.y, normal.z }, turnAngle).shape(); +// +// try { +// return OccTriangulator.getGeometry(S4, true); +// +// } catch (Exception e) { +// e.printStackTrace(); +// return null; +// } + elbow(pipeRadius,elbowRadius,n,normal,turnAngle,elbowCenter,geometry); + return true; + } + return false; + + } + + public void elbow(double radius, double turnRadius, Vector3d sn, Vector3d rn, double angle, Vector3d p, Geometry[] geometry) { + Vector3d t = new Vector3d(); + t.cross(sn,rn); + t.normalize(); + t.scale(turnRadius); + Vector3d vs[][] = calcCirc(RING_SEGMENTS, 0.0, 0.0, 0.0, sn.x, sn.y, sn.z, radius); + int rings = (int)Math.ceil(angle * ELBOW_RING_ANGLE * Math.sqrt(turnRadius)); + if (rings < 2) + rings = 2; + FloatBuffer v = BufferUtils.createFloatBuffer(vs[0].length * rings * 3); + FloatBuffer n = BufferUtils.createFloatBuffer(vs[0].length * rings * 3); + Quat4d q = new Quat4d(); + AxisAngle4d aa = new AxisAngle4d(); + Vector3d pos = new Vector3d(); + Vector3d t2 = new Vector3d(); + + aa.x = rn.x; + aa.y = rn.y; + aa.z = rn.z; + for (int i = 0; i < rings; i++) { + double a = (double)i/(double)(rings-1) * angle; + aa.angle = a; + q.set(aa); + MathTools.rotate(q, t, pos); + for (int j = 0; j < vs[0].length; j++) { + MathTools.rotate(q, vs[0][j], t2); + t2.add(pos); + t2.add(p); + v.put((float)t2.x); + v.put((float)t2.y); + v.put((float)t2.z); + MathTools.rotate(q, vs[1][j], t2); + n.put((float)t2.x); + n.put((float)t2.y); + n.put((float)t2.z); + } + } + int indexCount = indexCount(RING_SEGMENTS, rings); + int edgeIndexCount = edgeIndexCount(RING_SEGMENTS, rings); + IntBuffer i = BufferUtils.createIntBuffer(indexCount); + IntBuffer ei = BufferUtils.createIntBuffer(edgeIndexCount); + createIndices(i, RING_SEGMENTS, rings); + createEdgeIndices(ei, RING_SEGMENTS, rings); + TriMesh m = (TriMesh)geometry[0];//new TriMesh(); + Line l = (Line)geometry[1];//new Line(); + m.reconstruct(v, n, null, null,i); + l.reconstruct(v, null, null, null,ei); + //return new Geometry[]{m,l}; + } + + public boolean getStraightGeometry(IEntity instance, Geometry[] geometry) { + //Straight straight = new Straight(instance); + PipelineComponent straight = new PipelineComponent(instance); + double pipeRadius = straight.getPipeDiameter()[0] * 0.5; + //PipeRun pipeline = (PipeRun)PipingTools2.getPipeRun(straight.toPipelineComponent());//parent.getGraphicsNode(); + //double pipeRadius = pipeline.getPipeDiameter()[0] * 0.5; + + +// PipeControlPoint startControlPoint = (PipeControlPoint)StubFactory.getStubForResource(this.getClass().getClassLoader(),straight.getHasPreviousControlPoint().getResource()); +// PipeControlPoint endControlPoint = (PipeControlPoint)StubFactory.getStubForResource(this.getClass().getClassLoader(),straight.getHasNextControlPoint().getResource()); + + // start and end position of the pipe + // positions may be linked to other components, like nozzles + // and then their coordinates are in component's local coordinates + // which must be transformed into pipeline's local coordinates + + Point3d startPipe = new Point3d();//getLocalPoint(pipeline,startControlPoint); + + + Point3d endPipe = new Point3d(); //getLocalPoint(pipeline, endControlPoint); + + + + + PipingTools2.getInlineComponentEnds(straight, startPipe, endPipe); + boolean b = createStraightGeometry(startPipe, endPipe, pipeRadius, geometry); + if (!b) + ErrorLogger.getDefault().logWarning("Straight pipe " + instance + " is too short", null); + return b; + } + + public static boolean createStraightGeometry(Point3d startPipe, Point3d endPipe, double pipeRadius, Geometry geometry[]) { + Vector3d dir = new Vector3d(endPipe); + dir.sub(startPipe); + + double h = dir.length(); +// several values must be checked if they are infinite (OCC crashes if they are) + if (h > 0.001 && h < 10000.0 && pipeRadius > 0.01) { + + dir.normalize(); + + Vector3d[][] v1 = calcCirc(RING_SEGMENTS, startPipe.x, startPipe.y, startPipe.z, dir.x, dir.y, dir.z, pipeRadius); + Vector3d[][] v2 = calcCirc(RING_SEGMENTS, endPipe.x, endPipe.y, endPipe.z, dir.x, dir.y, dir.z, pipeRadius); + TriMesh m = (TriMesh)geometry[0];//new TriMesh(); + Line l = null; + if (geometry.length>1) + l = (Line)geometry[1];//new Line(); + FloatBuffer v = BufferUtils.createFloatBuffer(v1[0].length * 2 * 3); + FloatBuffer n = BufferUtils.createFloatBuffer(v1[0].length * 2 * 3 ); + for (int i = 0; i < v1[0].length; i++) { + v.put((float)v1[0][i].x); + v.put((float)v1[0][i].y); + v.put((float)v1[0][i].z); + n.put((float)v1[1][i].x); + n.put((float)v1[1][i].y); + n.put((float)v1[1][i].z); + } + for (int i = 0; i < v2[0].length; i++) { + v.put((float)v2[0][i].x); + v.put((float)v2[0][i].y); + v.put((float)v2[0][i].z); + n.put((float)v2[1][i].x); + n.put((float)v2[1][i].y); + n.put((float)v2[1][i].z); + } + + IntBuffer i = BufferUtils.createIntBuffer(indexCount(RING_SEGMENTS, 2)); + createIndices(i, RING_SEGMENTS, 2); + m.reconstruct(v, n, null, null,i); + if (l != null) { + IntBuffer ei = BufferUtils.createIntBuffer(edgeIndexCount(RING_SEGMENTS, 2)); + createEdgeIndices(ei, RING_SEGMENTS, 2); + l.reconstruct(v, null, null, null,ei); + } + return true; + } + return false; + } + + public static void createStraightEdges(Line l, Point3d startPipe, Point3d endPipe, double pipeRadius) { + Vector3d dir = new Vector3d(endPipe); + dir.sub(startPipe); + dir.normalize(); + Vector3d[][] v1 = calcCirc(8, startPipe.x, startPipe.y, startPipe.z, dir.x, dir.y, dir.z, pipeRadius); + Vector3d[][] v2 = calcCirc(8, endPipe.x, endPipe.y, endPipe.z, dir.x, dir.y, dir.z, pipeRadius); + FloatBuffer v = BufferUtils.createFloatBuffer(v1[0].length * 2 * 3); + FloatBuffer n = BufferUtils.createFloatBuffer(v1[0].length * 2 * 3 ); + for (int i = 0; i < v1[0].length; i++) { + v.put((float)v1[0][i].x); + v.put((float)v1[0][i].y); + v.put((float)v1[0][i].z); + n.put((float)v1[1][i].x); + n.put((float)v1[1][i].y); + n.put((float)v1[1][i].z); + } + for (int i = 0; i < v2[0].length; i++) { + v.put((float)v2[0][i].x); + v.put((float)v2[0][i].y); + v.put((float)v2[0][i].z); + n.put((float)v2[1][i].x); + n.put((float)v2[1][i].y); + n.put((float)v2[1][i].z); + } + + + IntBuffer ei = BufferUtils.createIntBuffer(edgeIndexCount(8, 2)); + createEdgeIndices(ei, 8, 2); + l.reconstruct(v, null, null, null,ei); + } + + public boolean getReducerGeometry(IEntity instance,Geometry[] geometry) { + //Reducer reducer = new Reducer(instance); + PipelineComponent reducer = new PipelineComponent(instance); + PipeControlPoint pcp = reducer.getControlPoint(); + PipeControlPoint pcp2 = pcp.getSubPoint().iterator().next(); + //PipeControlPoint pcp = reducer.getHasControlPoint(); + //PipeControlPoint prev = pcp.getPreviousPoint(); + //assert (prev != null); + //Point3d prevPoint = GraphicsNodeTools.getPoint(prev.getLocalPosition()); + //Point3d point = GraphicsNodeTools.getPoint(pcp.getLocalPosition()); + //Vector3d dir = new Vector3d(point); + //dir.sub(prevPoint); + //dir.normalize(); + double h = reducer.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength); + double r1 = pcp.getPipeDiameter()[0] * 0.5;//reducer.getBottomRadius(); + double r2 = pcp2.getPipeDiameter()[0] * 0.5;//reducer.getTopRadiusValue(); + + if (h > 0.001 && r1 > 0.001 && r2 > 0.001 ) { +// TopoDS_Shape S4 = getShape(h,r1,r2, instance.isInstanceOf(GlobalIdMap.get(PSK3DModelingOntologyMapping.ECCENTRIC_REDUCER))); +// +// +// try { +// return OccTriangulator.getGeometry(S4, true); +// +// } catch (Exception e) { +// e.printStackTrace(); +// return null; +// } + Vector3d[][] v1 = calcCirc(RING_SEGMENTS, -h * 0.5, 0.0, 0.0, 1.0, 0.0, 0.0, r1); + Vector3d[][] v2 = calcCirc(RING_SEGMENTS, h * 0.5, 0.0, instance.isInstanceOf(ProcessResource.plant3Dresource.EccentricReducer) ? (r1 - r2) : 0.0, 1.0, 0.0, 0.0, r2); + TriMesh m = (TriMesh)geometry[0];//new TriMesh(); + Line l = (Line)geometry[1];//new Line(); + FloatBuffer v = BufferUtils.createFloatBuffer(v1[0].length * 2 * 3); + FloatBuffer n = BufferUtils.createFloatBuffer(v1[0].length * 2 * 3 ); + for (int i = 0; i < v1[0].length; i++) { + v.put((float)v1[0][i].x); + v.put((float)v1[0][i].y); + v.put((float)v1[0][i].z); + n.put((float)v1[1][i].x); + n.put((float)v1[1][i].y); + n.put((float)v1[1][i].z); + } + for (int i = 0; i < v2[0].length; i++) { + v.put((float)v2[0][i].x); + v.put((float)v2[0][i].y); + v.put((float)v2[0][i].z); + n.put((float)v2[1][i].x); + n.put((float)v2[1][i].y); + n.put((float)v2[1][i].z); + } + + IntBuffer i = BufferUtils.createIntBuffer(indexCount(RING_SEGMENTS, 2)); + IntBuffer ei = BufferUtils.createIntBuffer(edgeIndexCount(RING_SEGMENTS, 2)); + createIndices(i, RING_SEGMENTS, 2); + createEdgeIndices(ei, RING_SEGMENTS, 2); + m.reconstruct(v, n, null, null,i); + l.reconstruct(v, null, null, null,ei); + //return new Geometry[]{m,l}; + return true; + + } + return false; + + } + +// protected TopoDS_Shape getShape(double h, double r1, double r2, boolean eccentric) { +// TopoDS_Shape S4 = null; +// +// gp_Circ circ1 = new gp_Circ(new double[] { -h * 0.5, 0.0, 0.0, 1.0, 0.0, 0.0 }, r1); +// TopoDS_Edge ed1 = (TopoDS_Edge) new BRepBuilderAPI_MakeEdge(circ1) +// .shape(); +// TopoDS_Wire w1 = (TopoDS_Wire) new BRepBuilderAPI_MakeWire(ed1).shape(); +// gp_Circ circ2 = new gp_Circ(new double[] { h * 0.5, 0.0, eccentric ? r1 - r2 : 0.0, 1.0, 0.0, 0.0 }, r2); +// TopoDS_Edge ed2 = (TopoDS_Edge) new BRepBuilderAPI_MakeEdge(circ2) +// .shape(); +// TopoDS_Wire w2 = (TopoDS_Wire) new BRepBuilderAPI_MakeWire(ed2).shape(); +//// BRepOffsetAPI_ThruSections generatorb = new BRepOffsetAPI_ThruSections( +//// true, false); +// BRepOffsetAPI_ThruSections generatorb = new BRepOffsetAPI_ThruSections(true, true); +// generatorb.addWire(w1); +// generatorb.addWire(w2); +// generatorb.build(); +// S4 = generatorb.shape(); +// return S4; +// } + + private boolean isValid(Vector3d v) { + if (Double.isInfinite(v.x) || + Double.isNaN(v.x) || + Double.isInfinite(v.y) || + Double.isNaN(v.y) || + Double.isInfinite(v.z) || + Double.isNaN(v.z)) + return false; + return true; + } + + private static Vector3d[][] calcCirc(int segmentCount,double x, double y, double z, double dx, double dy, double dz, double r) { + Vector3d res[][] = new Vector3d[2][segmentCount + 1]; + Vector3d t = new Vector3d(); + if (Math.abs(dy) + Math.abs(dz) < 0.001) { + t.y = 1.0; + } else { + t.x = 1.0; + } + Vector3d d = new Vector3d(dx,dy,dz); + Vector3d a = new Vector3d(); + a.cross(t, d); + a.normalize(); + a.scale(r); + Quat4d q = new Quat4d(); + AxisAngle4d aa = new AxisAngle4d(); + aa.x = dx; + aa.y = dy; + aa.z = dz; + for (int i = 0; i <= segmentCount; i++) { + aa.angle = (double)i / (double) segmentCount * Math.PI * 2.0; + q.set(aa); + res[0][i] = new Vector3d(); + res[1][i] = new Vector3d(); + MathTools.rotate(q, a, res[0][i]); + res[1][i].normalize(res[0][i]); + //res[1][i].negate(); + res[0][i].x += x; + res[0][i].y += y; + res[0][i].z += z; + } + return res; + + } + + private static int indexCount(int segmentCount, int ringCount) { + return 6 * segmentCount * (ringCount - 1); + } + + private static void createIndices(IntBuffer buf, int segmentCount, int ringCount) { + int s = segmentCount + 1; + for (int ring = 0; ring < ringCount - 1; ring++) { + for (int segment = 0; segment < segmentCount; segment++) { + int index = ring * s + segment; + buf.put(index); + buf.put(index + 1); + buf.put(index + s); + buf.put(index + s + 1); + buf.put(index + s); + buf.put(index + 1); + } + } + } + + private static int edgeIndexCount(int segmentCount, int ringCount) { + if (ringCount > 1) { + return segmentCount * 4 + ringCount * 4 * (segmentCount / 4); + } else { + return ringCount * segmentCount * 2; + } + } + + private static void createEdgeIndices(IntBuffer buf, int segmentCount, int ringCount) { + int s = segmentCount + 1; + if (ringCount > 1) { + int ring = 0; + for (int segment = 0; segment < segmentCount; segment++) { + int index = ring * s + segment; + buf.put(index); + buf.put(index + 1); + } + ring = ringCount - 1; + for (int segment = 0; segment < segmentCount; segment++) { + int index = ring * s + segment; + buf.put(index); + buf.put(index + 1); + } + int space = segmentCount / 4; + for (ring = 0; ring < ringCount - 1; ring++) { + for (int segment = 0; segment < segmentCount; segment+=space) { + int index = ring * s + segment; + buf.put(index); + buf.put(index + s); + } + } + } else { + int ring = 0; + for (int segment = 0; segment < segmentCount; segment++) { + int index = ring * s + segment; + buf.put(index); + buf.put(index + 1); + } + } + buf.limit(buf.position()); + + } +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/PipingRules.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/PipingRules.java new file mode 100644 index 00000000..d7e1619e --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/PipingRules.java @@ -0,0 +1,1134 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.common; + +import java.util.ArrayList; +import java.util.Collection; + +import javax.vecmath.AxisAngle4d; +import javax.vecmath.Point3d; +import javax.vecmath.Vector3d; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.proconf.g3d.base.G3DTools; +import org.simantics.proconf.g3d.base.MathTools; +import org.simantics.utils.ErrorLogger; + +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.stubs.PipeControlPoint; +import fi.vtt.simantics.processeditor.stubs.PipeRun; +import fi.vtt.simantics.processeditor.stubs.PipelineComponent; + +/** + * Rules that update pipeline. + * TODO : optimize, remove stubs + * + * FIXME : transformations + * + * TODO : FixedAngleTurnComponents are handled like VariableAngleTurnComponents + * + * + * @author Marko Luukkainen + * + */ +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 enum PathLegUpdateType {NONE,PREV,NEXT,PREV_S,NEXT_S}; + + /** + * Rule + * + * @param resources + * @param pp + * @throws TransactionException + */ + public static void pipeControlPointPositionUpdate(Graph g, Resource pp) { + + PipeControlPoint pcp = new PipeControlPoint(g,pp); + if (DEBUG) System.out.println("PipeControlPoint changed " + pp); + + boolean changed = ControlPointTools.isControlPointChanged(pcp); + + + if (changed) { + if (pcp.isInstanceOf(ProcessResource.plant3Dresource.PathLegEndControlPoint)) { + updatePathLegEndControlPoint(pcp); + } else { + updateInlineControlPoint(pcp); + } + } + + } + + + + 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) { + if (DEBUG) System.out.println("PipingTools.updateRunEndControlPoint() " + pcp.getResource()); + 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) { + if (DEBUG) System.out.println("PipingTools.updateInlineControlPoint() " + pcp.getResource()); + PipeControlPoint start = ControlPointTools.findPreviousEnd(pcp); + updatePathLegNext(start,pcp,PathLegUpdateType.NONE); + } + + private static PipeControlPoint insertElbow(PipeControlPoint pcp1 , PipeControlPoint pcp2, Point3d pos) { + if (DEBUG) System.out.println("PipingRules.insertElbow() " + pcp1.getResource() + " " + pcp2.getResource()+ " " + pos); + PipelineComponent elbow = PipingTools2.instantiatePipelineComponent(pcp1.getGraph(), ControlPointTools.getPipeRun(pcp1).getResource(), ProcessResource.plant3Dresource.Elbow); + PipeControlPoint pcp = elbow.getControlPoint(); + + ControlPointTools.insertControlPoint(pcp, pcp1,pcp2); + + ControlPointTools.setWorldPosition(pcp, pos); + + return pcp; + } + + private static void updatePathLegNext(PipeControlPoint start, PipeControlPoint updated, PathLegUpdateType lengthChange){ + ArrayList list = new ArrayList(); + PipeControlPoint end = ControlPointTools.findNextEnd(start,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 list, PipeControlPoint end, PipeControlPoint updated, PathLegUpdateType lengthChange) { + updatePathLeg(start,list,end,false,0,new ArrayList(),updated, lengthChange); + } + + private static class UpdateStruct2 { + public PipeControlPoint start; + public Point3d startPoint; + public ArrayList list; + public PipeControlPoint end; + public Point3d endPoint; + public Vector3d dir; + public Vector3d offset; + public boolean hasOffsets; + public int iter; + public boolean reversed; + public ArrayList toRemove; + public PipeControlPoint updated; + public UpdateStruct2(PipeControlPoint start, Point3d startPoint, ArrayList list, PipeControlPoint end, Point3d endPoint, Vector3d dir, Vector3d offset, boolean hasOffsets, int iter, boolean reversed, ArrayList toRemove, PipeControlPoint updated) { + super(); + 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; + } + + public String toString() { + return start.getResource() + " " + end.getResource() + " " + dir + " " + hasOffsets + " " + offset + " " + iter + " " + toRemove.size(); + } + + } + + private static boolean calculateOffset(Point3d startPoint, Point3d endPoint, ArrayList list, Vector3d dir, Vector3d offset) { + boolean hasOffsets = false; + dir.set(startPoint); + dir.sub(endPoint); + dir.normalize(); + offset.set(0.0,0.0,0.0); + for (PipeControlPoint icp : list) { + if (icp.isInstanceOf(ProcessResource.plant3Dresource.OffsettingPoint)) { + hasOffsets = true; + offset.add(ControlPointTools.getSizeChangeOffsetVector(icp,dir)); + } + else if (icp.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)) + ErrorLogger.defaultLogError("Updating pipe run, found offset controlpoint " + icp.getResource(), 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 list, PipeControlPoint end, boolean reversed, int iter, ArrayList toRemove, PipeControlPoint updated, PathLegUpdateType lengthChange) { + // FIXME: direction is calculated wrong way! + boolean hasOffsets = false; + Vector3d offset = new Vector3d(); + Point3d startPoint = G3DTools.getPoint(start.getWorldPosition()); + Point3d endPoint = G3DTools.getPoint(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){ + int directed = 0; + if (u.start.isInstanceOf(ProcessResource.plant3Dresource.DirectedControlPoint)) + directed ++; + if (u.end.isInstanceOf(ProcessResource.plant3Dresource.DirectedControlPoint)) + 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) { + if (DEBUG) System.out.println("PipingRules.updateFreePipeRun " + u + " " + lengthChange); + checkExpandPathLeg(u, lengthChange); + } + + private static void updateInlineControlPoints(UpdateStruct2 u, boolean checkSizes) { + if (DEBUG) System.out.println("PipingTools.updateInlineControlPoints() " + u); + + if (!u.hasOffsets) { + // FIXME : cache positions + if (!checkSizes) { + for (PipeControlPoint icp : u.list) { + updateInlineControlPoint(icp, u.startPoint, u.endPoint,u.dir); + } + return; + } + + ArrayList pathLegPoints = new ArrayList(); + 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; + Point3d prevPos; + prev = pathLegPoints.get(i-1); + prevPos = G3DTools.getPoint(prev.getWorldPosition()); + Point3d currentPos = G3DTools.getPoint(icp.getWorldPosition()); + + if (icp.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthControlPoint)) { + if (i != pathLegPoints.size() - 1) { + PipeControlPoint next; + Point3d nextPos; + next = pathLegPoints.get(i + 1); + nextPos = G3DTools.getPoint(next.getWorldPosition()); + Vector3d dir = new Vector3d(nextPos); + dir.sub(prevPos); + double l = dir.lengthSquared(); // distance between control points (square) + double l2prev = ControlPointTools.getInlineLength(prev); // distance taken by components + double l2next = ControlPointTools.getInlineLength(next); + 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); + ControlPointTools.setWorldPosition(icp,dir); + icp.setRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength, length); + } else { + //components leave no space to the component and it must be removed + ControlPointTools.removeControlPoint(icp); + } + + } 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.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength); + Vector3d dir = new Vector3d(); + dir.sub(currentPos,prevPos); + 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 = ControlPointTools.getInlineLength(prev); + Point3d beginPos = new Point3d(dir); + beginPos.scale(offset); + beginPos.add(prevPos); //this is the connected end of the component + + double l = beginPos.distance(endPos); + + dir.scale(l*0.5); + beginPos.add(dir); //center position + + if (DEBUG) System.out.println("PipingRules.updateInlineControlPoints() setting variable length to " + l); + icp.setRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength, l); + + ControlPointTools.setWorldPosition(icp, beginPos); + } + i++; + + } else if (!prev.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthControlPoint)){ + // 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 = ControlPointTools.getInlineLength(prev); + double l2next = ControlPointTools.getInlineLength(icp); + double l2 = l2prev + l2next; + double l2s = l2 * l2; + if (l > l2s) { + PipelineComponent component = PipingTools2.instantiatePipelineComponent(prev.getGraph(), ControlPointTools.getPipeRun(prev).getResource(), ProcessResource.plant3Dresource.Straight); + PipeControlPoint scp = component.getControlPoint(); + ControlPointTools.insertControlPoint(scp, prev, icp); + + 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); + ControlPointTools.setWorldPosition(scp, dir); + scp.setRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength, length); + } + } + } + } 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.isInstanceOf(ProcessResource.plant3Dresource.OffsettingPoint)) { + // TODO : offset vector is already calculated and should be + // cached + u.offset = ControlPointTools.getSizeChangeOffsetVector(icp, u.dir); + updateOffsetPoint( icp, u.offset); + u.startPoint.add(u.offset); + u.endPoint.add(u.offset); + } + } + } + } + + + + private static void ppNoOffset(UpdateStruct2 u) { + 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.isInstanceOf(ProcessResource.plant3Dresource.OffsettingPoint)) { + offset.add(ControlPointTools.getSizeChangeOffsetVector(icp,u.dir)); + } + else if (icp.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)) + ErrorLogger.defaultLogError("Updating pipe run, found offset controlpoint " + icp.getResource(), new Exception("ASSERT!")); + } + } + u.offset = offset; + checkExpandPathLeg(u,PathLegUpdateType.NONE); + } + + private static void ppNoDir(PipeControlPoint start, Point3d startPoint,ArrayList list, PipeControlPoint end,Point3d endPoint, boolean hasOffsets,int iter,boolean reversed, ArrayList toRemove, PipeControlPoint updated) { + if (DEBUG)System.out.println("PipingRules.ppNoDir() " + start.getResource() + " " + end.getResource() + " " + 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) { + 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,false,false); + int type = checkTurns(u,lengthChange); + if (type == REMOVE_NONE) { + processPathLeg(u,false,true); + } else { + expandPathLeg(u, type); + } + } else { + processPathLeg(u,false,true); + } + } + + private static void updateDirectedPathLeg(UpdateStruct2 u, PathLegUpdateType lengthChange) { + if (DEBUG)System.out.println("PipingRules.updateDirectedPipeRun() " + u + " " + lengthChange); + PipeControlPoint dcp; + PipeControlPoint other; + boolean canMoveOther = false; + boolean dcpStart = false; + Point3d position; + if (u.start.isInstanceOf(ProcessResource.plant3Dresource.DirectedControlPoint)) { + dcp = u.start; + other = u.end; + position = u.startPoint; + dcpStart = true; + if (!u.reversed) + canMoveOther = true; + } else { + dcp = u.end; + other = u.start; + position = u.endPoint; + if (u.reversed) + canMoveOther = true; + } + + Vector3d directedDirection = ControlPointTools.getDirectedControlPointDirection(dcp); + 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.001); + if (aligned) { + checkExpandPathLeg(u,lengthChange); + } 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.isInstanceOf(ProcessResource.plant3Dresource.VariableAngleTurnControlPoint)) { + + // 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.getResource() + " to " + closest); + ControlPointTools.setWorldPosition(other, closest); + if (dcpStart) { + ppNoOffset(new UpdateStruct2(u.start, u.startPoint, u.list, u.end, new Point3d(closest), directedDirection,null, u.hasOffsets, u.iter, u.reversed, u.toRemove,u.updated)); + if (u.end.getNext() != null) + updatePathLegNext(u.end,u.updated,PathLegUpdateType.NEXT); + } else { + ppNoOffset(new UpdateStruct2(u.start, new Point3d(closest), u.list, u.end, u.endPoint, directedDirection,null, u.hasOffsets, u.iter, u.reversed, u.toRemove,u.updated)); + if (u.start.getPrevious() != null) + updatePathLegPrev(u.start,u.updated,PathLegUpdateType.PREV); + } + } else { + // TODO : calculate needed space from next run end. + insertElbowUpdate(u, dcp, nextToMoved, dcpStart, position, directedDirection); + } + } else if (other.isInstanceOf(ProcessResource.plant3Dresource.UndirectedControlPoint) && + other.getSubPointOf() != null) { + // FIXME : this code was for updating branches + Vector3d bintersect = new Vector3d(); + PipeControlPoint bcp = other.getSubPointOf(); + if (bcp != null && canMoveOther) { + Point3d bstart = new Point3d(); + Point3d bend = new Point3d(); + Vector3d bdir = new Vector3d(); + ControlPointTools.getInlineControlPointEnds(bcp, bstart, bend, bdir); + Vector3d nintersect = new Vector3d(); + + MathTools.intersectStraightStraight(position, directedDirection, bstart, + 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.getResource() + " to " + bintersect); + // is required branch position is in possible range + ControlPointTools.setWorldPosition(bcp, bintersect); + if (dcpStart) { + checkExpandPathLeg(new UpdateStruct2(u.start, u.startPoint, u.list, u.end, new Point3d(bintersect),directedDirection, u.offset, u.hasOffsets, u.iter, u.reversed, u.toRemove,u.updated),lengthChange); + } else { + checkExpandPathLeg(new UpdateStruct2(u.start, new Point3d(bintersect), u.list, u.end, u.endPoint,directedDirection, u.offset, u.hasOffsets, u.iter, u.reversed, u.toRemove,u.updated),lengthChange); + } + } else { + // branch cannot be moved into right position, new turn + // / elbow must be inserted + insertElbowUpdate(u , dcp, nextToMoved, dcpStart, position, directedDirection); + } + + } else { // assume that control point cannot be moved, but can be rotated + insertElbowUpdate(u, dcp, nextToMoved, dcpStart, position, directedDirection); + } + } + } + } + + + + private static void updateDualDirectedPathLeg(UpdateStruct2 u, PathLegUpdateType lengthChange) { + if (DEBUG) System.out.println("PipingRules.updateDualDirectedPipeRun() " + u + " " + lengthChange); + + PipeControlPoint dcp1 = u.start; + PipeControlPoint dcp2 = u.end; + Point3d position1 = u.startPoint; + Point3d position2 = u.endPoint; + Point3d position1offset = new Point3d(position1); + position1offset.sub(u.offset); + Point3d position2offset = new Point3d(position2); + position2offset.add(u.offset); + Vector3d dir1 = ControlPointTools.getDirectedControlPointDirection(dcp1); + Vector3d dir2 = ControlPointTools.getDirectedControlPointDirection(dcp2); + 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 { + 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; + } + + PipeRun pipeline = ControlPointTools.getPipeRun(dcp1); + PipelineComponent elbow1 = PipingTools2.instantiatePipelineComponent(u.start.getGraph(), pipeline.getResource(), ProcessResource.plant3Dresource.Elbow); + PipelineComponent elbow2 = PipingTools2.instantiatePipelineComponent(u.start.getGraph(), pipeline.getResource(), ProcessResource.plant3Dresource.Elbow); + + PipeControlPoint tcp1 = elbow1.getControlPoint(); + PipeControlPoint tcp2 = elbow2.getControlPoint(); + + // Straight s1 = getStraight(dcp, next); + ControlPointTools.insertControlPoint(tcp1, dcp, next); + // s1 = getStraight(tcp1, next); + ControlPointTools.insertControlPoint(tcp2, tcp1, next); + p1 = G3DTools.getVector(dcp.getLocalPosition()); + 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); + + ControlPointTools.setWorldPosition(tcp1, p1); + ControlPointTools.setWorldPosition(tcp2, p2); + + if (DEBUG) System.out.println("PipingRules.updateDualDirectedPipeRun() created two turns " + tcp1.getResource() + " " + tcp2.getResource()); + + if (!u.reversed) { + Vector3d dd = new Vector3d(p2); + dd.sub(p1); + dir2.negate(); + processPathLeg(new UpdateStruct2(u.start, u.startPoint,new ArrayList(), tcp1, new Point3d(p1),dir1, new Vector3d(), false, 0, false,new ArrayList(), u.updated)); + processPathLeg(new UpdateStruct2(tcp1,new Point3d(p1), new ArrayList(),tcp2, new Point3d(p2), dd,new Vector3d(), false, 0, false,new ArrayList(), u.updated)); + // offset is recalculated + processPathLegNoOffset(new UpdateStruct2(tcp2, new Point3d(p2), u.list,u.end, u.endPoint, dir2, null, u.hasOffsets,u.iter, u.reversed, u.toRemove, u.updated)); + } else { + Vector3d dd = new Vector3d(p1); + dd.sub(p2); + dir2.negate(); + processPathLeg(new UpdateStruct2(tcp1,new Point3d(p1), new ArrayList(),u.end, u.endPoint, dir2, new Vector3d(), false, 0,false, new ArrayList(), u.updated)); + processPathLeg(new UpdateStruct2(tcp2,new Point3d(p2), new ArrayList(),tcp1, new Point3d(p1), dd,new Vector3d(), false, 0, false,new ArrayList(), u.updated)); + // offset is recalculated + processPathLegNoOffset(new UpdateStruct2(u.start, u.startPoint,u.list, tcp2, new Point3d(p2),dir1, null, u.hasOffsets, u.iter, u.reversed,u.toRemove, u.updated)); + } + } + } + } + + private static void insertElbowUpdate(UpdateStruct2 u, PipeControlPoint dcp, PipeControlPoint next, boolean dcpStart, Point3d position, Vector3d directedDirection) { + + Vector3d closest = new Vector3d(position); + closest.add(directedDirection); + PipeControlPoint tcp = insertElbow(dcp, next, new Point3d(closest)); + + if (DEBUG) System.out.println("PipingRules.updateDirectedPipeRun() inserted " + tcp.getResource()); + + if (dcpStart) { + // update pipe run from new turn to other end + ppNoDir(tcp, new Point3d(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(), tcp, new Point3d(closest), directedDirection, new Vector3d(), false, 0, false, new ArrayList(),u.updated)); + } else { + // update pipe run from other end to new turn + ppNoDir(u.start, u.startPoint, u.list, tcp, new Point3d(closest), u.hasOffsets, u.iter, u.reversed, u.toRemove,u.updated); + // update pipe run from new turn to directed + processPathLeg(new UpdateStruct2(tcp, new Point3d(closest), new ArrayList(), u.end, u.endPoint, directedDirection, new Vector3d(), false, 0, false, new ArrayList(),u.updated)); + } + } + + /** + * Checks if turns can be removed (turn angle near zero) + */ + private static int checkTurns(UpdateStruct2 u, PathLegUpdateType lengthChange) { + if (DEBUG) + System.out.println("PipingRules.checkTurns() " + u.start.getResource() + + " " + u.end.getResource()); + boolean startRemoved = false; + boolean endRemoved = false; + if (u.start.isInstanceOf(ProcessResource.plant3Dresource.VariableAngleTurnControlPoint)) { + // 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 { + Point3d ep = new Point3d(u.endPoint); + ep.add(u.offset); + a = updateTurnControlPointTurn( u.start,u.startPoint, G3DTools.getPoint(startPrev.getLocalPosition()), ep); + + } + if (a < MIN_TURN_ANGLE) + 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.isInstanceOf(ProcessResource.plant3Dresource.VariableAngleTurnControlPoint)) { + + PipeControlPoint endNext = u.end.getNext(); + if (endNext != null) { + double a; + if (!u.hasOffsets) { + a = updateTurnControlPointTurn(u.end,u.start, endNext); + } else { + Point3d sp = new Point3d(u.startPoint); + sp.sub(u.offset); + a = updateTurnControlPointTurn(u.end, u.endPoint, sp, G3DTools.getPoint(endNext.getLocalPosition())); + } + if (a < MIN_TURN_ANGLE) + 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) { + if (DEBUG) System.out.println("PipingRules.expandPipeline " + u.start.getResource() + " " + u.end.getResource()); + ArrayList newList = new ArrayList (); + 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 = ControlPointTools.findPreviousEnd(u.start); + u.startPoint = G3DTools.getPoint(u.start.getLocalPosition()); + ControlPointTools.findNextEnd(u.start,newList); + newList.addAll(u.list); + u.list = newList; + break; + case REMOVE_END : + u.toRemove.add(new ExpandIterInfo(u.end,REMOVE_END)); + u.end = ControlPointTools.findNextEnd(u.end,newList); + u.endPoint = G3DTools.getPoint(u.end.getLocalPosition()); + u.list.addAll(newList); + break; + case REMOVE_BOTH : + u.toRemove.add(new ExpandIterInfo(u.start,u.end)); + u.start = ControlPointTools.findPreviousEnd(u.start); + u.startPoint = G3DTools.getPoint(u.start.getLocalPosition()); + ControlPointTools.findNextEnd(u.start,newList); + newList.addAll(u.list); + u.list = newList; + newList = new ArrayList (); + u.end = ControlPointTools.findNextEnd(u.end,newList); + u.endPoint = G3DTools.getPoint(u.end.getLocalPosition()); + 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.isInstanceOf(ProcessResource.plant3Dresource.OffsettingPoint)) { + u.offset.add(ControlPointTools.getSizeChangeOffsetVector(icp,u.dir)); + } + else if (icp.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)) + ErrorLogger.defaultLogError("Updating pipe run, found offset controlpoint " + icp.getResource(), new Exception("ASSERT!")); + } + } + if (DEBUG) System.out.println("PipingRules.expandPipeline expanded " + u.start.getResource() + " " + u.end.getResource()); + u.iter++; + updatePathLeg(u,PathLegUpdateType.NONE); + } + + /** + * reverts one iteration of turn removing back) + */ + private static void backIter(UpdateStruct2 u) { + + if (DEBUG) System.out.println("PipingRules.backIter" + u.start.getResource() + " " + u.end.getResource()); + 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().getResource().equals(info.getStart().getResource())) + 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().getResource().equals(info.getEnd().getResource())) + 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.isInstanceOf(ProcessResource.plant3Dresource.OffsettingPoint)) { + u.offset.add(ControlPointTools.getSizeChangeOffsetVector(icp,u.dir)); + } + else if (icp.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)) + ErrorLogger.defaultLogError("Updating pipe run, found offset controlpoint " + icp.getResource(), new Exception("ASSERT!")); + } + } + processPathLeg(u); + + } + + /** + * Processes pipe run (removes necessary turns and updates run ends) + */ + // private static void processPathLeg(PipeControlPoint start, Point3d startPoint,ArrayList list, PipeControlPoint end,Point3d endPoint, Vector3d dir,Vector3d offset, boolean hasOffsets,int iter, boolean reversed, ArrayList toRemove) throws TransactionException { + + private static void processPathLeg(UpdateStruct2 u) { + if (DEBUG) System.out.println("PipingRules.processPathLeg " + u.start.getResource() + " " + u.end.getResource()); + processPathLeg(u, true, true); + } + + + private static void processPathLeg(UpdateStruct2 u, boolean updateEnds, boolean updateInline) { + if (DEBUG) System.out.println("PipingRules.processPathLeg " + u.start.getResource() + " " + u.end.getResource()); + if (u.toRemove.size() > 0) { + for (ExpandIterInfo info : u.toRemove) { + if (info.getStart() != null) { + ControlPointTools.removeControlPoint(info.getStart()); + } + if (info.getEnd() != null) { + ControlPointTools.removeControlPoint(info.getEnd()); + } + } + // ControlPointTools.removeControlPoint may remove mo0re than one CP; + // we must populate inline CP list again. + u.list.clear(); + ControlPointTools.findNextEnd(u.start, 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.isInstanceOf(ProcessResource.plant3Dresource.TurnControlPoint)) { + updateTurnControlPointTurn(u.start, u.start.getPrevious(), u.start.getNext()); + updatePathLegPrev(u.start, u.start, PathLegUpdateType.NONE); + } else if (u.start.isInstanceOf(ProcessResource.plant3Dresource.EndComponentControlPoint)) { + updateEndComponentControlPoint(u.start, u.startPoint, u.endPoint); + } + if (u.end.isInstanceOf(ProcessResource.plant3Dresource.TurnControlPoint)) { + updateTurnControlPointTurn( u.end, u.end.getPrevious(), u.end.getNext()); + updatePathLegNext(u.end, u.end, PathLegUpdateType.NONE); + } else if (u.end.isInstanceOf(ProcessResource.plant3Dresource.EndComponentControlPoint)) { + updateEndComponentControlPoint(u.end, u.startPoint, u.endPoint); + } + + } else { + if (u.start.isInstanceOf(ProcessResource.plant3Dresource.EndComponentControlPoint)) { + updateEndComponentControlPoint(u.start, u.startPoint, u.endPoint); + } + if (u.end.isInstanceOf(ProcessResource.plant3Dresource.EndComponentControlPoint)) { + 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 list, PipeControlPoint end,Point3d endPoint, Vector3d dir, boolean hasOffsets,int iter, boolean reversed, ArrayList toRemove) throws TransactionException { + private static void processPathLegNoOffset(UpdateStruct2 u) { + if (DEBUG) System.out.println("PipingRules.processPathLeg " + u.start.getResource() + " " + u.end.getResource()); + Vector3d offset = new Vector3d(); + if (u.hasOffsets) { + u.dir.normalize(); + for (PipeControlPoint icp : u.list) { + if (icp.isInstanceOf(ProcessResource.plant3Dresource.OffsetComponent)) { + offset.add(ControlPointTools.getSizeChangeOffsetVector(icp,u.dir)); + } else if (icp.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)) { + ErrorLogger.defaultLogError("Updating pipe run, found offset controlpoint " + icp.getResource(), new Exception("ASSERT!")); + } + } + } + processPathLeg(u); + } + + private static void updateOffsetPoint(PipeControlPoint sccp, Vector3d offset) { + Point3d world = G3DTools.getPoint(sccp.getWorldPosition()); + world.add(offset); + PipeControlPoint ocp = sccp.getSubPoint().iterator().next(); + ControlPointTools.setWorldPosition(ocp, world); + } + + private static void updatePathLegPrev(PipeControlPoint start, PipeControlPoint updated, PathLegUpdateType lengthChange) { + ArrayList list = new ArrayList(); + PipeControlPoint end = ControlPointTools.findPreviousEnd(start,list); + updatePathLegPrev(start, list, end,updated,lengthChange); + } + + private static void updatePathLegPrev(PipeControlPoint start, ArrayList list, PipeControlPoint end, PipeControlPoint updated, PathLegUpdateType lengthChange) { + // reverses the list + ArrayList nextList = new ArrayList(); + for (PipeControlPoint icp : list) { + if (icp.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)) { + nextList.add(0, icp.getSubPointOf()); + } else { + nextList.add(0,icp); + } + + } + updatePathLeg(end, nextList, start, true,0,new ArrayList(),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, Point3d nextPoint, Point3d prevPoint, Vector3d dir) { + if (DEBUG) System.out.println("PipingRules.updateInlineControlPoint() " + icp.getResource()); + + Point3d inlinePoint = G3DTools.getPoint(icp.getLocalPosition()); + if (DEBUG) System.out.print("InlineControlPoint update "+icp.getResource() + " " + inlinePoint + " " + prevPoint + " " + nextPoint); + Vector3d newInlinePoint = null; + boolean branchUpdate = false; + PipeControlPoint becp = null; + for (PipeControlPoint pcp : icp.getSubPoint()) + if (pcp.isInstanceOf(ProcessResource.plant3Dresource.UndirectedControlPoint)) { + 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 = ControlPointTools.findNextEnd(becp); + } else if (becp.getPrevious() != null) { + p = ControlPointTools.findPreviousEnd(becp); + } + if (p == null) { + newInlinePoint = MathTools.closestPointOnEdge(new Vector3d(inlinePoint), new Vector3d(nextPoint), new Vector3d(prevPoint)); + } else { + Point3d branchLegEnd = G3DTools.getPoint(p.getLocalPosition()); + 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); + + ControlPointTools.setWorldPosition(icp, 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, Point3d start, Point3d end) { + if (DEBUG) System.out.println("PipingRules.updateEndComponentControlPoint() " + ecp.getResource()); +// 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); + + 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; + Double angleO = pcp.getAtMostOneRelatedScalarDouble(ProcessResource.plant3Dresource.HasRotationAngle); + double angle = 0.0; + if (angleO != null) + angle = angleO; + + AxisAngle4d aa = ControlPointTools.getControlPointWorldRotation(pcp, angle); + ControlPointTools.setWorldOrientation(pcp,aa); + + } + + /** + * Updates all branches when branch's position has been changed + * @param bcp + */ + private static void updateBranchControlPointBranches(PipeControlPoint bcp) { + if (DEBUG) System.out.println("PipingRules.updateBranchControlPointBranches() " + bcp.getResource()); + Collection 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.getResource()); + if (next == null || prev == null) + return Math.PI; // FIXME : argh + Point3d middlePoint = G3DTools.getPoint(tcp.getWorldPosition()); + Point3d nextPoint = G3DTools.getPoint(next.getWorldPosition()); + Point3d prevPoint = G3DTools.getPoint(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, Point3d middlePoint, Point3d prevPoint, Point3d 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.getResource() + " " + 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; + + double elbowRadius = tcp.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasTurnRadius); + double R = elbowRadius / Math.tan(angle * 0.5); + Vector3d turnAxis = new Vector3d(); + turnAxis.cross(dir1, dir2); + turnAxis.normalize(); + tcp.setRelatedScalarDouble(ProcessResource.plant3Dresource.HasTurnAngle,turnAngle); + tcp.setRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength, R);//setComponentOffsetValue(R); + G3DTools.setTuple3(tcp.getSingleRelatedObject(ProcessResource.plant3Dresource.HasTurnAxis), turnAxis); + if (DEBUG) System.out.println("PipingTools.updateTurnControlPointTurn " + dir1 + " " + dir2 + " " + turnAngle + " " + turnAxis); + return turnAngle; + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/PipingTools.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/PipingTools.java new file mode 100644 index 00000000..7ae038d2 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/PipingTools.java @@ -0,0 +1,225 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.common; + + +public class PipingTools { +// private static final boolean DEBUG = true; +// +// +// +// /** +// * Splits straigth by inserting new controlpoint between straight ends. +// * @param straight +// * @param newPcp +// * @throws TransactionException +// */ +//// public static void insertControlPoint(Straight straight, PipeControlPoint newPcp) throws TransactionException { +//// if (straight == null || newPcp == null) { +//// ErrorLogger.defaultLogError("Routing pipe, cannot make branch: straight or control point is null", null); +//// return; +//// } +//// PipeControlPoint scp = straight.getHasControlPoint(); +//// PipeControlPoint straightStart = (PipeControlPoint)StubFactory.getStubForResource(straight.getClass().getClassLoader(),scp.getPreviousPoint().getResource()); +//// PipeControlPoint straightEnd = (PipeControlPoint)StubFactory.getStubForResource(straight.getClass().getClassLoader(),scp.getNext().getResource()); +//// if (DEBUG) System.out.println("PipingTools inserting control point between " + straightStart.getResource() + " " + straightEnd.getResource() + " straight " + straight.getResource()); +//// +//// // remove the straight pipe +//// PipeControlPoint temp = PipeControlPointFactory.instantiate(newPcp.getGraph()); +//// //straight.setHasNextControlPoint(temp); +//// //straight.setHasPreviousControlPoint(temp); +//// straight.setHasControlPoint(temp); +//// +//// PipeRun pipeRun = getPipeRun(straight); +//// if (pipeRun != null) { +//// pipeRun.getHasSubnodesSet().remove(straight.getResource()); +//// } +//// insertControlPoint(pipeRun, newPcp, straightStart, straightEnd); +//// +//// } +// +// +// +// +// +// +// +// +// public static void getStraightPipeEnds(Straight straight, Point3d end1, Point3d end2) { +// getStraightPipeEnds(getPipeRun(straight), straight, end1, end2); +// } +// +// public static void getStraightPipeEnds(PipeRun pipeRun,Straight straight, Point3d end1, Point3d end2) { +// if (DEBUG) System.out.println("PipingTools.getStraightPipeEnds() " + straight.getResource()); +// PipeControlPoint scp = straight.getHasControlPoint(); +// PipeControlPoint startControlPoint = (PipeControlPoint)StubFactory.getStubForResource(straight.getClass().getClassLoader(),scp.getPrevious().getResource()); +// PipeControlPoint endControlPoint = (PipeControlPoint)StubFactory.getStubForResource(straight.getClass().getClassLoader(),scp.getNext().getResource()); +// if (startControlPoint == null || endControlPoint == null) { +// ErrorLogger.defaultLogError("Pipe ends null", new NullPointerException()); +// } +// // start and end position of the pipe +// // positions may be linked to other components, like nozzles +// // and then their coordinates are in component's local coordinates +// // which must be transformed into pipeRun's local coordinates +// +// //Point3d startPipe = getLocalPoint(pipeRun,startControlPoint); +// +// +// //Point3d endPipe = getLocalPoint(pipeRun, endControlPoint); +// Point3d startPipe = G3DTools.getPoint(startControlPoint.getLocalPosition()); +// Point3d endPipe = G3DTools.getPoint(endControlPoint.getLocalPosition()); +// if (startPipe == null || endPipe == null) { +// end1.x = Double.NaN; +// end1.y = Double.NaN; +// end1.z = Double.NaN; +// end2.x = Double.NaN; +// end2.y = Double.NaN; +// end2.z = Double.NaN; +// if (DEBUG) System.out.println("no positions"); +// return; +// } +// +// Vector3d dir = new Vector3d(endPipe); +// dir.sub(startPipe); +// +// +// if (startControlPoint instanceof TurnControlPoint) { +// TurnControlPoint t = (TurnControlPoint)startControlPoint; +// double R = t.getComponentOffsetValue(); +// Vector3d n = new Vector3d(dir); +// n.normalize(); +// n.scale(R); +// startPipe.add(n); +// } else if (startControlPoint instanceof InlineControlPoint && !(startControlPoint instanceof BranchControlPoint)) { +// InlineControlPoint t = (InlineControlPoint)startControlPoint; +// double R = t.getNextComponentOffsetValue(); +// Vector3d n = new Vector3d(dir); +// n.normalize(); +// n.scale(R); +// startPipe.add(n); +// } +// +// if (endControlPoint instanceof TurnControlPoint) { +// TurnControlPoint t = (TurnControlPoint)endControlPoint; +// double R = t.getComponentOffsetValue(); +// Vector3d n = new Vector3d(dir); +// n.normalize(); +// n.scale(R); +// endPipe.sub(n); +// } else if (endControlPoint instanceof InlineControlPoint && !(endControlPoint instanceof BranchControlPoint)) { +// InlineControlPoint t = (InlineControlPoint)endControlPoint; +// double R = t.getPreviousComponentOffsetValue(); +// Vector3d n = new Vector3d(dir); +// n.normalize(); +// n.scale(R); +// endPipe.sub(n); +// } +// +// end1.x = startPipe.x; +// end1.y = startPipe.y; +// end1.z = startPipe.z; +// +// end2.x = endPipe.x; +// end2.y = endPipe.y; +// end2.z = endPipe.z; +// +// } +// +// /** +// * Finds direction and ends where inline component, reducer or branch can be moved. +// * @param icp +// * @param s +// * @param e +// * @param d +// */ +// public static void getInlineEnds(InlineControlPoint icp, Vector3d s, Vector3d e, Vector3d d) { +// +// PipeControlPoint next = (PipeControlPoint)StubFactory.getStubForResource(icp.getClass().getClassLoader(), icp.getNext().getResource()); +// PipeControlPoint prev = (PipeControlPoint)StubFactory.getStubForResource(icp.getClass().getClassLoader(), icp.getPrevious().getResource()); +// Vector3d start = G3DTools.getVector(prev.getLocalPosition()); +// Vector3d end = G3DTools.getVector(next.getLocalPosition()); +// if (icp.getResource().isInstanceOf(GlobalIdMap.get(PSK3DModelingOntologyMapping.SIZE_CHANGE_CONTROL_POINT))) { +// SizeChangeControlPoint sccp = SizeChangeControlPointFactory.create(icp.getResource()); +// Vector3d tDir = new Vector3d(G3DTools.getVector(sccp.getLocalPosition())); +// Vector3d offset = getSizeChangeOffsetVector(sccp, tDir); +// end.sub(offset); +// } +// Vector3d dir = new Vector3d(end); +// dir.sub(start); +// Vector3d n = new Vector3d(dir); +// n.normalize(); +// +// double offset = icp.getNextComponentOffsetValue(); +// if (next instanceof InlineControlPoint) { +// InlineControlPoint ip = (InlineControlPoint) next; +// offset += ip.getPreviousComponentOffsetValue(); +// } +// else if (next instanceof TurnControlPoint) { +// TurnControlPoint tcp = (TurnControlPoint)next; +// offset += tcp.getComponentOffsetValue(); +// } +// Vector3d t = new Vector3d(n); +// t.scale(offset); +// end.sub(t); +// +// offset = icp.getPreviousComponentOffsetValue(); +// if (prev instanceof InlineControlPoint) { +// InlineControlPoint ip = (InlineControlPoint) prev; +// offset += ip.getPreviousComponentOffsetValue(); +// } +// else if (prev instanceof TurnControlPoint) { +// TurnControlPoint tcp = (TurnControlPoint)prev; +// offset += tcp.getComponentOffsetValue(); +// } +// t = new Vector3d(n); +// t.scale(offset); +// start.add(t); +// +// dir= new Vector3d(end); +// dir.sub(start); +// +// s.x = start.x; +// s.y = start.y; +// s.z = start.z; +// +// e.x = end.x; +// e.y = end.y; +// e.z = end.z; +// +// d.x = dir.x; +// d.y = dir.y; +// d.z = dir.z; +// +// System.out.println("PipingTools.getInlineEnds() " + s + " " + e + " " + d); +// } +// +// +// public static void setSame(fi.vtt.simantics.layer0.stubs.Double d1, fi.vtt.simantics.layer0.stubs.Double d2) { +// d1.getResource().createRelation(d2.getResource(), GlobalIdMap.get(PSK3DModelingOntologyMapping.IS_SAME_VALUE)); +// } +// +// public static void setHalf(fi.vtt.simantics.layer0.stubs.Double d1, fi.vtt.simantics.layer0.stubs.Double d2) { +// d1.getResource().createRelation(d2.getResource(), GlobalIdMap.get(PSK3DModelingOntologyMapping.IS_HALF_OF_THE_VALUE)); +// } +// +// +// + +// +// +// +// +// +// +// +// + +} \ No newline at end of file diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/PipingTools2.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/PipingTools2.java new file mode 100644 index 00000000..4baf3089 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/PipingTools2.java @@ -0,0 +1,668 @@ +package fi.vtt.simantics.processeditor.common; + +import java.util.Collection; + +import javax.vecmath.Point3d; +import javax.vecmath.Vector3d; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.layer0.utils.Statement; +import org.simantics.layer0.utils.instantiation.Instance; +import org.simantics.layer0.utils.instantiation.InstanceFactory; +import org.simantics.proconf.g3d.base.G3DTools; +import org.simantics.proconf.g3d.stubs.G3DNode; + +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.actions.PositionType; +import fi.vtt.simantics.processeditor.stubs.Equipment; +import fi.vtt.simantics.processeditor.stubs.InlineComponent; +import fi.vtt.simantics.processeditor.stubs.Nozzle; +import fi.vtt.simantics.processeditor.stubs.PipeControlPoint; +import fi.vtt.simantics.processeditor.stubs.PipeRun; +import fi.vtt.simantics.processeditor.stubs.PipelineComponent; + +public class PipingTools2 { + private static final boolean DEBUG = false; + public enum Direction{NEXT,PREVIOUS}; + + + + /** + * Reverses a piperun by swapping all previous/next connections + * @param pipeRun + */ + public static void reversePipeRun(IEntity pipeRun) { +// //FIXME : reducers / size-change / offset-control points +// RelationTypeSet cps = pipeRun.getHasControlPointSet(); +// if (cps.size() == 0) +// return; +// List list = new ArrayList(); +// PipeControlPoint pcp = cps.iterator().next(); +// list.add(pcp); +// PipeControlPoint temp = pcp.getPrevious(); +// while (temp != null) { +// list.add(0,temp); +// temp = temp.getPrevious(); +// } +// temp = pcp.getNext(); +// while (temp != null) { +// list.add(temp); +// temp = temp.getNext(); +// } +// // now list contains control points in sorted order. +// // switch order +// for (int i = 0; i < list.size() - 1; i++) { +// PipeControlPoint pcp1 = list.get(i); +// PipeControlPoint pcp2 = list.get(i+1); +// pcp1.setPrevious(pcp2); +// pcp2.setNext(pcp1); +// +// } +// // fix ends +// list.get(0).setNext(null); +// list.get(list.size() - 1).setPrevious(null); + + } + + public static IEntity getPipeRun(IEntity component) { + assert(component.isInstanceOf(ProcessResource.plant3Dresource.PipelineComponent)); + return component.getSingleRelatedObject(ProcessResource.g3dResource.HasParent); + } + + /** + * Returns Nozzle of a directed control point + * @param dcp + * @return + */ + public static Nozzle getNozzle(PipeControlPoint dcp) { + assert (dcp.isInstanceOf(ProcessResource.plant3Dresource.DirectedControlPoint)); + IEntity e = dcp.getControlPointOf(); + if (e == null) + return null; + assert (e.isInstanceOf(ProcessResource.plant3Dresource.Nozzle)); + return new Nozzle(e); + } + + /** + * Instantiates new pipeline component and all necessary control points for it. + * @param graph + * @param typeResource + * @return + */ + public static PipelineComponent instantiatePipelineComponent(Graph graph, Resource pipeRunResource, Resource typeResource) { + IEntity pipeRun = EntityFactory.create(graph,pipeRunResource); + Instance ins = InstanceFactory.getInstanceOfType(graph, typeResource); + Resource instance = ins.instantiate(graph); + PipelineComponent component = new PipelineComponent(graph,instance); + G3DTools.resetTransformation(component); + // copy control point + Collection pcps = graph.getObjects(typeResource, ProcessResource.plant3Dresource.HasControlPoint); + assert(pcps.size() == 1); + Collection types = graph.getObjects(pcps.iterator().next(), ProcessResource.builtins.InstanceOf); + PipeControlPoint componentPCP = new PipeControlPoint(graph,InstanceFactory.instantiate(graph, types)); + component.addStatement(ProcessResource.plant3Dresource.HasControlPoint, componentPCP); + pipeRun.addStatement(ProcessResource.g3dResource.HasChild, component); + pipeRun.addStatement(ProcessResource.plant3Dresource.HasControlPoints, componentPCP); + component.setPipeDiameter(pipeRun.getSingleRelatedObject(ProcessResource.plant3Dresource.HasPipeDiameter)); + if (component.isInstanceOf(ProcessResource.plant3Dresource.VariableAngleTurnComponent)) { + setStatement(component, ProcessResource.plant3Dresource.HasTurnRadius, pipeRun.getSingleRelatedObject(ProcessResource.plant3Dresource.HasTurnRadius)); + setStatement(componentPCP, ProcessResource.plant3Dresource.HasTurnRadius, pipeRun.getSingleRelatedObject(ProcessResource.plant3Dresource.HasTurnRadius)); + setStatement(component, ProcessResource.plant3Dresource.HasTurnAngle, componentPCP.getSingleRelatedObject(ProcessResource.plant3Dresource.HasTurnAngle)); + setStatement(component, ProcessResource.plant3Dresource.HasTurnAxis, componentPCP.getSingleRelatedObject(ProcessResource.plant3Dresource.HasTurnAxis)); + } + if (component.getAtMostOneRelatedObject(ProcessResource.plant3Dresource.HasLength) != null) { + setStatement(componentPCP, ProcessResource.plant3Dresource.HasLength, component.getSingleRelatedObject(ProcessResource.plant3Dresource.HasLength)); + } + componentPCP.setLocalOrientation(component.getLocalOrientation()); + componentPCP.setWorldOrientation(component.getWorldOrientation()); + + componentPCP.setLocalPosition(component.getLocalPosition()); + componentPCP.setWorldPosition(component.getWorldPosition()); + + setStatement(componentPCP, ProcessResource.plant3Dresource.HasPipeDiameter, pipeRun.getSingleRelatedObject(ProcessResource.plant3Dresource.HasPipeDiameter)); + setStatement(component, ProcessResource.plant3Dresource.HasPipeDiameter, pipeRun.getSingleRelatedObject(ProcessResource.plant3Dresource.HasPipeDiameter)); + + // TODO : instantiate subpoints + + + return component; + } + + public static Nozzle instantiateNozzle(Graph graph, Resource typeResource) { + Instance ins = InstanceFactory.getInstanceOfType(graph, typeResource); + Resource instance = ins.instantiate(graph); + Nozzle n = new Nozzle(graph,instance); + G3DTools.resetTransformation(n); + + // copy control point + Collection pcps = graph.getObjects(typeResource, ProcessResource.plant3Dresource.HasControlPoint); + assert(pcps.size() == 1); + Collection types = graph.getObjects(pcps.iterator().next(), ProcessResource.builtins.InstanceOf); + PipeControlPoint nozzlePCP = new PipeControlPoint(graph,InstanceFactory.instantiate(graph, types)); + n.addStatement(ProcessResource.plant3Dresource.HasControlPoint, nozzlePCP); + nozzlePCP.setLocalOrientation(n.getLocalOrientation()); + nozzlePCP.setWorldOrientation(n.getWorldOrientation()); + nozzlePCP.setLocalPosition(n.getLocalPosition()); + nozzlePCP.setWorldPosition(n.getWorldPosition()); + setStatement(nozzlePCP, ProcessResource.plant3Dresource.HasPipeDiameter, n.getSingleRelatedObject(ProcessResource.plant3Dresource.HasPipeDiameter)); + nozzlePCP.setPipeDiameter(0.2); + return n; + } + + public static Equipment instantiateEquipment(Graph graph, Resource typeResource) { + Instance ins = InstanceFactory.getInstanceOfType(graph, typeResource); + Resource instance = ins.instantiate(graph); + Equipment equipment = new Equipment(graph, instance); + G3DTools.resetTransformation(equipment); + + IEntity type = EntityFactory.create(graph, typeResource); + IEntity geometricModel = type.getSingleRelatedObject(ProcessResource.plant3Dresource.HasGraphics); + + Collection sizingProperties = geometricModel.getRelatedObjects(ProcessResource.g3dResource.HasSizingParameter); + Collection equipmentProperties = equipment.getRelatedStatements(ProcessResource.builtins.HasProperty); + + for (IEntity e : sizingProperties) { + String name = e.getName(); + String pName = "Has " + name; + boolean found = false; + for (Statement s : equipmentProperties) { + IEntity predicate = s.getPredicate(); + String predicateName = predicate.getName(); + if (predicateName.equals(pName)) { + found = true; + break; + } + } + if(!found) { + IEntity rel = getOrCreateRel(graph,name); + equipment.setRelatedScalarDouble(rel, 1.0); + } + } + + // TODO : create nozzles if needed + + return equipment; + } + + private static IEntity getOrCreateRel(Graph graph, String name) { + IEntity rel = null; + try { + Resource relr = graph.getResourceByURI("http://www.vtt.fi/Simantics/Plant3D/1.0/Relations#Has" + name); + rel = EntityFactory.create(graph,relr); + } catch (Exception e) { + Resource relLib = null; + try { + relLib = graph.getResourceByURI("http://www.vtt.fi/Simantics/Plant3D/1.0#Relations"); + } catch (Exception e2) { + + } + Resource relr = graph.newResource(); + rel = EntityFactory.create(graph, relr); + rel.addStatement(ProcessResource.builtins.SubrelationOf, ProcessResource.g3dResource.HasNonTransformation); + rel.setName("Has " + name); + Resource irelr = graph.newResource(); + graph.addStatement(relr,ProcessResource.builtins.InverseOf,irelr); + graph.addStatement(relLib, ProcessResource.builtins.ConsistsOf, relr); + } + return rel; + } + + public static IEntity getLibraryComponentType(IEntity component) { + assert(component.isInstanceOf(ProcessResource.plant3Dresource.LibraryComponent)); + // IEntity.getTypes() returns all types, but we want the closest type. + Collection types = component.getRelatedObjects(ProcessResource.builtins.InstanceOf);//component.getTypes(); + IEntity type = null; + for (IEntity t : types) { + if (t.isInheritedFrom(ProcessResource.plant3Dresource.LibraryComponent)) { + if (type == null) + type = t; + else + throw new RuntimeException("Cannot find proper type for library component " + component.getResource() ); + } + } + return type; + } + + /** + * Splits existing VariableLengthComponent with another component. + * Result is two VariableLengthComponents and inserted component between them. + * + * Note : world position of newComponent must be set before this method may be called. + * + * @param newComponent + * @param splittingComponent + */ + public static void splitVariableLengthComponent(IEntity newComponent, IEntity splittingComponent) { + assert(splittingComponent.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent)); + assert(newComponent.isInstanceOf(ProcessResource.plant3Dresource.PipelineComponent)); + assert(!newComponent.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent)); + IEntity newCP = newComponent.getSingleRelatedObject(ProcessResource.plant3Dresource.HasControlPoint); + IEntity splittingCP = splittingComponent.getSingleRelatedObject(ProcessResource.plant3Dresource.HasControlPoint); + IEntity nextCP = splittingCP.getAtMostOneRelatedObject(ProcessResource.plant3Dresource.HasNext); + IEntity prevCP = splittingCP.getAtMostOneRelatedObject(ProcessResource.plant3Dresource.HasPrevious); + + /* 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.getResource() + " is not connected to anything."); + } + + Point3d next = ControlPointTools.getRealPosition(splittingCP, PositionType.NEXT); + Point3d prev = ControlPointTools.getRealPosition(splittingCP, PositionType.PREVIOUS); + Point3d comp = G3DTools.getPoint(newComponent.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition)); + double length = newComponent.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength); + Vector3d dir = new Vector3d(next); + dir.sub(prev); + dir.normalize(); + dir.scale(length * 0.5); + Point3d vn = new Point3d(comp); + Point3d vp = new Point3d(comp); + 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); + + IEntity type = getLibraryComponentType(splittingComponent); + + IEntity newVariableLengthComponent = instantiatePipelineComponent(splittingComponent.getGraph(), getPipeRun(splittingComponent).getResource(), type.getResource()); + IEntity newVariableLengthCP = newVariableLengthComponent.getSingleRelatedObject(ProcessResource.plant3Dresource.HasControlPoint); + if (nextCP == null) { + ControlPointTools.insertControlPoint(newCP, splittingCP,Direction.NEXT); + ControlPointTools.insertControlPoint(newVariableLengthCP, newCP,Direction.NEXT); + ControlPointTools.setWorldPosition(splittingCP, vp); + splittingCP.setRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength, lp); + ControlPointTools.setWorldPosition(newVariableLengthCP, vn); + newVariableLengthComponent.setRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength, ln); + } else if (prevCP == null) { + ControlPointTools.insertControlPoint(newCP, splittingCP,Direction.PREVIOUS); + ControlPointTools.insertControlPoint(newVariableLengthCP, newCP,Direction.PREVIOUS); + ControlPointTools.setWorldPosition(splittingCP, vn); + splittingCP.setRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength, ln); + ControlPointTools.setWorldPosition(newVariableLengthCP, vp); + newVariableLengthComponent.setRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength, lp); + } else { + ControlPointTools.insertControlPoint(newCP,splittingCP,nextCP); + ControlPointTools.insertControlPoint(newVariableLengthCP, newCP,nextCP); + ControlPointTools.setWorldPosition(splittingCP, vp); + splittingCP.setRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength, lp); + ControlPointTools.setWorldPosition(newVariableLengthCP, vn); + newVariableLengthComponent.setRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength, ln); + } + + } + + /** + * Attaches newComponent into connectedComponent's connectedControlPoint + * @param newComponent + * @param connectedComponent + * @param connectedControlPoint + */ + public static void insertComponent(IEntity newComponent, IEntity connectedComponent, IEntity connectedControlPoint, Direction direction) { + assert (newComponent.isInstanceOf(ProcessResource.plant3Dresource.PipelineComponent)); + assert (connectedComponent.isInstanceOf(ProcessResource.plant3Dresource.PipelineComponent)); + // TODO : piperun check is more complicated, since newComponent and connectedComponent may be SizeChangeComponents + //assert (getPipeRun(connectedComponent).equals(getPipeRun(newComponent))); + + // new control point and its subpoint + IEntity newControlPoint = newComponent.getSingleRelatedObject(ProcessResource.plant3Dresource.HasControlPoint); + ControlPointTools.insertControlPoint(newControlPoint, connectedControlPoint, direction); +// IEntity newSubPoint = null; +// if (newControlPoint.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)) +// newSubPoint = newControlPoint.getSingleRelatedObject(ProcessResource.plant3Dresource.HasSubPoint); +// +// // connected components parent or subpoint +// IEntity connectedSubPoint = null; +// IEntity connectedParentPoint = null; +// if (connectedControlPoint.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)) +// connectedSubPoint = connectedControlPoint.getSingleRelatedObject(ProcessResource.plant3Dresource.HasSubPoint); +// else if (connectedControlPoint.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)) +// connectedParentPoint = connectedControlPoint.getSingleRelatedObject(ProcessResource.plant3Dresource.SubPointOf); +// +// if (direction == Direction.NEXT) { +// assert (connectedSubPoint == null); // if direction is next, connection done to subpoint +// setStatement(connectedControlPoint, ProcessResource.plant3Dresource.HasNext, newControlPoint); +// if (connectedParentPoint != null) +// setStatement(connectedParentPoint, ProcessResource.plant3Dresource.HasNext, newControlPoint); +// setStatement(newControlPoint, ProcessResource.plant3Dresource.HasPrevious, connectedControlPoint); +// if (newSubPoint != null) +// setStatement(newSubPoint, ProcessResource.plant3Dresource.HasPrevious, connectedControlPoint); +// +// } else { +// assert (connectedParentPoint == null); // if direction is prev, connection done to parentpoint +// if (newSubPoint != null) { +// +// } +// } + + /* + private void insertEndComponent() { + activated = false; + Graph coreTC = parent.getGraph(); + + if (replace == null) + checkForEndInsertion(); + if (replace == null) { + ErrorLogger.defaultLogError("Cannot insert end component",null); + end(); + return; + } + G3DNode p = straight.getHasParent(); + if (p == null) { + ErrorLogger.defaultLogError("Straight pipe has no parent", new Exception("ASSERT!")); + + } else { + Pipeline pipeline = PipelineFactory.create(p); + coreTC.startTransaction(this); + try { + Vector3d startPoint = GraphicsNodeTools.getVector(replace.getLocalPosition()); + EndComponentControlPoint ecp = EndComponentControlPointFactory.instantiate(coreTC); + coreTC.commitChanges(CommitMessage.CHANGE_MESSAGE); + pipeline.getHasControlPointSet().remove(replace); + // create dummy node + //PipeControlPoint pcp = PipeControlPointFactory.instantiate(coreTC); + replace.setNextPoint(null); + replace.setPreviousPoint(null); + pipeline.getHasControlPointSet().add(ecp); + if (next) { + straight.getHasControlPoint().getPreviousPoint().setNextPoint(ecp); + straight.getHasControlPoint().setNextPoint(ecp); + ecp.setPreviousPoint(straight.getHasControlPoint().getPreviousPoint()); + //ecp.setNextPoint(null); + } else { + straight.getHasControlPoint().getNextPoint().setPreviousPoint(ecp); + straight.getHasControlPoint().setPreviousPoint(ecp); + ecp.setNextPoint(straight.getHasControlPoint().getNextPoint()); + //ecp.setPreviousPoint(null); + } + G3DTools.setTranslation(ecp.getLocalPosition(), startPoint); + // FIXME : component should specify how much space it needs + createAndLink(coreTC, pipeline, ecp); + coreTC.commitChanges(CommitMessage.CHANGE_MESSAGE); + coreTC.commitTransaction(CommitMessage.TRANSACTION_MESSAGE); + } catch (TransactionException e) { + ErrorLogger.defaultLogError("Cannot insert component", e); + coreTC.cancelTransaction(); + } + } + + end(); + } + + private void insertComponent(Point3d startPoint) { + activated = false; + Graph coreTC = parent.getGraph(); + G3DNode p = straight.getHasParent(); + if (p == null) { + ErrorLogger.defaultLogError("Straight pipe has no parent", new Exception("ASSERT!")); + + } else { + Pipeline pipeline = PipelineFactory.create(p); + coreTC.startTransaction(this); + try { + InlineComponentControlPoint icp = InlineComponentControlPointFactory.instantiate(coreTC); + coreTC.commitChanges(CommitMessage.CHANGE_MESSAGE); + PipeControlPoint scp = straight.getHasControlPoint(); + // it shouldn't matter whitch control point to use, next or previous. + PipingTools.insertControlPoint(pipeline, icp, scp, scp.getNextPoint()); + //PipingTools.insertControlPoint(straight, icp); + pipeline.getHasControlPointSet().add(icp); + G3DTools.setTranslation(icp.getLocalPosition(), startPoint); + // FIXME : component should specify how much space it needs + icp.setNextComponentOffsetValue(pipeline.getPipeRadiusValue()); + icp.setPreviousComponentOffsetValue(pipeline.getPipeRadiusValue()); + PipingTools.setSame(pipeline.getPipeRadius(), icp.getNextComponentOffset()); + PipingTools.setSame(pipeline.getPipeRadius(), icp.getPreviousComponentOffset()); + createAndLink(coreTC, pipeline, icp); + coreTC.commitChanges(CommitMessage.CHANGE_MESSAGE); + coreTC.commitTransaction(CommitMessage.TRANSACTION_MESSAGE); + } catch (TransactionException e) { + ErrorLogger.defaultLogError("Cannot insert component", e); + coreTC.cancelTransaction(); + } + } + + line.removeFromParent(); + + end(); + + } + + + private void createAndLink(Graph coreTC, Pipeline pipeline, PipeControlPoint icp) throws TransactionException { + PipelineComponent component = PipelineComponentFactory.create(OntologyUtils.instantiate(typeResource)); + coreTC.commitChanges(CommitMessage.CHANGE_MESSAGE); + component.setHasControlPoint(icp); + component.setLocalPosition(icp.getLocalPosition()); + pipeline.getHasSubnodesSet().add(component); + component.setPipeRadius(pipeline.getPipeRadius()); + component.setHasGraphics(GraphicsModelFactory.create(modelResource)); + + } + */ + + /* + old insert reducer code + + Pipeline pipeline = PipingTools.getPipeline(straight); + // pcp is Turn Control Point and we'll have to change it's type to Size Change Control Point + // First we'll remove its unnecessary properties and elbow connected to it, + RelationTypeSet pipeComponents = pcp.getControlPointOfSet(); + Resource elbowResource = null; + for (Entity e : pipeComponents) { + if (e.getResource().isInstanceOf(GlobalIdMap.get(PSK3DModelingOntologyMapping.ELBOW))) { + elbowResource = e.getResource(); + } + } + if (elbowResource != null) { + pipeComponents.remove(elbowResource); + pipeline.getHasSubnodesSet().remove(elbowResource); + } + RelationSet rs = pcp.getResource().getRelatedResourcesWithRelationIds(GlobalIdMap.get(PSK3DModelingOntologyMapping.HAS_TURN_ANGLE)); + RelationReference rr = rs.getRelations()[0]; + pcp.getResource().removeRelationById(rr.getObjectId(),rr.getRelationId()); + rs = pcp.getResource().getRelatedResourcesWithRelationIds(GlobalIdMap.get(PSK3DModelingOntologyMapping.HAS_COMPONENT_OFFSET)); + rr = rs.getRelations()[0]; + pcp.getResource().removeRelationById(rr.getObjectId(),rr.getRelationId()); + rs = pcp.getResource().getRelatedResourcesWithRelationIds(GlobalIdMap.get(Builtins.InstanceOf)); + rr = rs.getRelations()[0]; + //pcp.getResource().removeRelationById(type[0], GlobalIdMap.get(Builtins.InstanceOf)); + pcp.getResource().removeRelationById(rr.getObjectId(),rr.getRelationId()); + Resource sccpType = graph.getResource(PSK3DModelingOntologyMapping.SIZE_CHANGE_CONTROL_POINT); + pcp.createRelation(sccpType, graph.getResource(Builtins.InstanceOf)); + + graph.commitChanges(CommitMessage.CHANGE_MESSAGE); + + Reducer reducer = null; + Pipeline newPipeline = PipelineFactory.instantiate(graph); + OffsetControlPoint offsetControlPoint = OffsetControlPointFactory.instantiate(graph); + if (i == 0) { + reducer = ConcentricReducerFactory.instantiate(graph); + } else { + reducer = EccentricReducerFactory.instantiate(graph); + } + graph.commitChanges(CommitMessage.CHANGE_MESSAGE); + SizeChangeControlPoint sccp = SizeChangeControlPointFactory.create(pcp.getResource()); + + + // FIXME : lenght, pipe radius and turn angle from specs + let the user choose spec for new pipeline + double reducerLength = 0.3; + reducer.setLengthValue(reducerLength); + double newPipeRadius = pipelineDialog.getPipeRadius(); + double newPipeTurnRadius = pipelineDialog.getTurnRadius(); + + reducer.setLocalPosition(sccp.getLocalPosition()); + reducer.setWorldPosition(sccp.getWorldPosition()); + + reducer.setBottomRadiusValue(pipeline.getPipeRadiusValue()); + + reducer.setPipeRadius(pipeline.getPipeRadius()); + reducer.setTopRadiusValue(newPipeRadius); + newPipeline.setPipeRadiusValue(newPipeRadius); + newPipeline.setTurnRadiusValue(newPipeTurnRadius); + + // reducer is adjuste by pipelines' radiis + PipingTools.setSame(pipeline.getPipeRadius(), reducer.getBottomRadius()); + PipingTools.setSame(newPipeline.getPipeRadius(), reducer.getTopRadius()); + + //newPipeline.getHasControlPointSet().add(pcp); + sccp.setHasOffsetPoint(offsetControlPoint); + offsetControlPoint.setOffsetPointOf(sccp); + + reducer.setHasControlPoint(sccp); + graph.commitChanges(CommitMessage.CHANGE_MESSAGE); + + sccp.setNextComponentOffsetValue(reducerLength*0.5); + sccp.setPreviousComponentOffsetValue(reducerLength*0.5); + + // offsets are calculated from reducers length + PipingTools.setHalf(reducer.getLength(), sccp.getNextComponentOffset()); + PipingTools.setHalf(reducer.getLength(), sccp.getPreviousComponentOffset()); + + // linking sccp and ocp offsets + offsetControlPoint.setNextComponentOffset(sccp.getNextComponentOffset()); + offsetControlPoint.setPreviousComponentOffset(sccp.getPreviousComponentOffset()); + + + offsetControlPoint.setPreviousPoint(sccp.getPreviousPoint()); + offsetControlPoint.setNextPoint(sccp.getNextPoint()); + if (i == 1) { + // FIXME : link offset value + sccp.setOffsetValue(reducer.getBottomRadiusValue() - reducer.getTopRadiusValue()); + sccp.setAngle(((EccentricReducer)reducer).getAngle()); + Vector3d v = PipingTools.getSizeChangeOffsetVector(sccp); + Point3d local = GraphicsNodeTools.getTranslation(sccp.getLocalPosition()); + local.add(v); + //Point3d World = GraphicsNodeTools.getTranslation(sccp.getLocalPosition()); + GraphicsNodeTools.setTranslation(offsetControlPoint.getLocalPosition(), local); + } else { + // FIXME : is it possible that pipelines are in different coordinate systems + offsetControlPoint.setLocalPosition(sccp.getLocalPosition()); + offsetControlPoint.setWorldPosition(sccp.getWorldPosition()); + } + ((TestProcessEditor)parent).getPlant().getHasSubnodesSet().add(newPipeline); + pipeline.getHasSubnodesSet().add(reducer); + newPipeline.getHasControlPointSet().add(offsetControlPoint); + graph.commitChanges(CommitMessage.CHANGE_MESSAGE); + + graph.commitTransaction(CommitMessage.TRANSACTION_MESSAGE); + + */ + + + + } + + /** + * Returns direction of a nozzle + * @param nozzle + * @return + */ + public static Vector3d getNozzleDirection(IEntity nozzle) { + return ControlPointTools.getNozzleDirection(nozzle.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldOrientation)); + } + + /** + * Returns true if a nozzle is not connected to a pipe + * @param nozzle + * @return + */ + public static boolean isFreeNozzle(IEntity nozzle) { + assert (nozzle.isInstanceOf(ProcessResource.plant3Dresource.Nozzle)); + IEntity pcp = nozzle.getSingleRelatedObject(ProcessResource.plant3Dresource.HasControlPoint); + IEntity next = pcp.getAtMostOneRelatedObject(ProcessResource.plant3Dresource.HasNext); + IEntity previous = pcp.getAtMostOneRelatedObject(ProcessResource.plant3Dresource.HasPrevious); + if (next == null && previous == null) { + assert (pcp.getAtMostOneRelatedObject(ProcessResource.plant3Dresource.ControlPointOfPipeRun) == null); + return true; + } + assert (pcp.getAtMostOneRelatedObject(ProcessResource.plant3Dresource.ControlPointOfPipeRun) != null); + return false; + } + + public static void getInlineComponentEnds(IEntity inlineComponent, Point3d p1, Point3d p2) { + assert(inlineComponent.isInstanceOf(ProcessResource.plant3Dresource.InlineComponent)); + ControlPointTools.getInlineControlPointEnds(inlineComponent.getSingleRelatedObject(ProcessResource.plant3Dresource.HasControlPoint), p1, p2); + } + + public static void getInlineComponentEnds(IEntity inlineComponent, Point3d p1, Point3d p2, Vector3d dir) { + assert(inlineComponent.isInstanceOf(ProcessResource.plant3Dresource.InlineComponent)); + ControlPointTools.getInlineControlPointEnds(inlineComponent.getSingleRelatedObject(ProcessResource.plant3Dresource.HasControlPoint), p1, p2,dir); + } + + public static void getInlineComponentEnds(IEntity inlineComponent, Point3d center, Point3d p1, Point3d p2, Vector3d dir) { + assert(inlineComponent.isInstanceOf(ProcessResource.plant3Dresource.InlineComponent)); + ControlPointTools.getInlineControlPointEnds(inlineComponent.getSingleRelatedObject(ProcessResource.plant3Dresource.HasControlPoint), center, p1, p2,dir); + } + + public static void removePipeRun(PipeRun pipeRun) { + if (DEBUG) System.out.println("PipingTools.removePipeRun() " + pipeRun.getResource()); + G3DNode parent = pipeRun.getParent(); + if (parent != null) + parent.getChild().remove(pipeRun); + + } + /** + * Liks piperun's specs to nozzle's specs + * @param nozzle + * @param piperun + */ + public static void linkNozzleAndPipeRun(IEntity nozzle, IEntity piperun) { + assert(nozzle.isInstanceOf(ProcessResource.plant3Dresource.Nozzle)); + assert(piperun.isInstanceOf(ProcessResource.plant3Dresource.PipeRun)); + IEntity diam = piperun.getSingleRelatedObject(ProcessResource.plant3Dresource.HasPipeDiameter); + + piperun.addStatement(ProcessResource.plant3Dresource.HasControlPoints, nozzle.getSingleRelatedObject(ProcessResource.plant3Dresource.HasControlPoint)); + setStatement(nozzle, ProcessResource.plant3Dresource.HasPipeDiameter, diam); + } + + /** + * Unlinks piperun's specs from nozzle's specs. + * @param nozzle + * @param piperun + */ + public static void unlinkNozzleAndPiperun(IEntity nozzle, IEntity piperun) { + assert(nozzle.isInstanceOf(ProcessResource.plant3Dresource.Nozzle)); + assert(piperun.isInstanceOf(ProcessResource.plant3Dresource.PipeRun)); + + piperun.removeStatement(ProcessResource.plant3Dresource.HasControlPoints, nozzle.getSingleRelatedObject(ProcessResource.plant3Dresource.HasControlPoint)); + // get current diameter + double diam = nozzle.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasPipeDiameter); + // remove link to shared diameter resource + nozzle.removeRelatedStatements(ProcessResource.plant3Dresource.HasPipeDiameter); + // create new reource for diameter + nozzle.setRelatedScalarDouble(ProcessResource.plant3Dresource.HasPipeDiameter, diam); + } + + private static void setStatement(IEntity subject, Resource relation, IEntity object) { + subject.removeRelatedStatements(relation); + subject.addStatement(relation, object); + } + + public static void getInlineMovement(InlineComponent ic, Point3d start, Point3d end) { + PipeControlPoint pcp = ic.getControlPoint(); + ControlPointTools.getInlineMovement(pcp, start, end); + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/ConfigureAnimationDialog.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/ConfigureAnimationDialog.java new file mode 100644 index 00000000..de5e5aa2 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/ConfigureAnimationDialog.java @@ -0,0 +1,478 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.dialogs; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.Map.Entry; + +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.List; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Resource; +import org.simantics.db.Session; +import org.simantics.g2d.stubs.anim.Animation; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.layer0.utils.viewpoints.TraversalPath; +import org.simantics.proconf.browsing.GraphExplorer; +import org.simantics.proconf.g3d.animation.Animatable; +import org.simantics.proconf.g3d.animation.AnimationSystem; +import org.simantics.proconf.g3d.animation.ResourceAnimationController; +import org.simantics.proconf.g3d.animation.ScaledResourceAnimationController; +import org.simantics.proconf.g3d.base.ScenegraphAdapter; +import org.simantics.proconf.g3d.scenegraph.IGraphicsNode; +import org.simantics.proconf.g3d.stubs.G3DModel; +import org.simantics.proconf.g3d.tools.OEPathSelectionListener; +import org.simantics.utils.ErrorLogger; + +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.common.PathUtils; + +public class ConfigureAnimationDialog extends Dialog { + Session session; + List typeList; + List animationList; + java.util.List nodes; + Set models; + + private Composite oeLabelComposite; + //private Control viewpointControl; + private Composite oeComposite; + private GraphExplorer oe; + private Map instanceModelMap = new HashMap(); + private ScenegraphAdapter adapter; + + private Button applyAnimationButton; + + Resource selectedType; + Resource sampleInstance; + Resource sampleSource; + java.util.List samplePath; + AnimationSystem animationSystem; + + Button scaleButton; + Text minText; + Text maxText; + + public ConfigureAnimationDialog(Shell parentShell, Session session, java.util.List nodes, ScenegraphAdapter adapter, AnimationSystem animationSystem) { + super(parentShell); + this.session = session; + this.nodes = nodes; + models = new HashSet(); + session.syncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + for (Resource n : ConfigureAnimationDialog.this.nodes) { + IEntity t = EntityFactory.create(g,n); + Collection r = t.getRelatedObjects(ProcessResource.plant3Dresource.HasGraphics); + if (r.size() == 1) { + IEntity model = r.iterator().next(); + if (model.isInstanceOf(ProcessResource.g3dResource.G3DModel)) { + models.add(model.getResource()); + instanceModelMap.put(n, model.getResource()); + } else { + throw new RuntimeException("Expected G3DModel, got something else " + model); + } + } else { + ErrorLogger.getDefault().logWarning("Got node without a model", null); + } + } + return GraphRequestStatus.transactionComplete(); + } + }); + + this.adapter = adapter; + this.animationSystem = animationSystem; + int shellStyle = getShellStyle(); + setShellStyle(shellStyle | SWT.MAX | SWT.RESIZE); + } + + @Override + protected void configureShell(Shell newShell) { + super.configureShell(newShell); + newShell.setText("Configure animations"); + + } + + protected Control createDialogArea(Composite parent) { + Composite composite = (Composite) super.createDialogArea(parent); + GridLayout layout = new GridLayout(4,true); + 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); + + Label label = new Label(composite, SWT.WRAP); + label.setText("Types"); +// GridData data = new GridData(GridData.GRAB_HORIZONTAL +// | GridData.GRAB_VERTICAL | GridData.HORIZONTAL_ALIGN_FILL +// | GridData.VERTICAL_ALIGN_BEGINNING); + GridData data = new GridData(GridData.CENTER,GridData.FILL,true,false,1,1); + data.widthHint = convertHorizontalDLUsToPixels(IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH); + label.setLayoutData(data); + label.setFont(parent.getFont()); + + label = new Label(composite, SWT.WRAP); + label.setText("Models"); + label.setLayoutData(data); + label.setFont(parent.getFont()); + + label = new Label(composite, SWT.WRAP); + label.setText("Animations"); + label.setLayoutData(data); + label.setFont(parent.getFont()); + + oeLabelComposite = new Composite(composite,SWT.NONE); + data = new GridData(GridData.CENTER,GridData.FILL,true,false,1,1); + data.widthHint = convertHorizontalDLUsToPixels(IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH); + + oeLabelComposite.setLayoutData(data); + oeLabelComposite.setLayout(new FillLayout(SWT.HORIZONTAL)); + //label = new Label(composite, SWT.WRAP); + label = new Label(oeLabelComposite, SWT.WRAP); + label.setText("Animation source"); +// label.setLayoutData(data); + label.setFont(parent.getFont()); + + typeList = new List(composite, SWT.BORDER | SWT.SINGLE | SWT.READ_ONLY | SWT.V_SCROLL); + typeList.setLayoutData(new GridData(GridData.GRAB_VERTICAL | GridData.VERTICAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL)); +// modelList = new List(composite, SWT.BORDER | SWT.SINGLE | SWT.READ_ONLY | SWT.V_SCROLL); +// modelList.setLayoutData(new GridData(GridData.GRAB_VERTICAL | GridData.VERTICAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL)); + animationList = new List(composite, SWT.BORDER | SWT.SINGLE | SWT.READ_ONLY | SWT.V_SCROLL); + animationList.setLayoutData(new GridData(GridData.GRAB_VERTICAL | GridData.VERTICAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL)); + oeComposite = new Composite(composite,SWT.BORDER); + oeComposite.setLayoutData(new GridData(GridData.GRAB_VERTICAL | GridData.VERTICAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL)); + layout = new GridLayout(); + layout.marginWidth = 0; + layout.marginHeight = 0; + oeComposite.setLayout(layout); + + session.asyncRead(new GraphRequestAdapter() { + TreeMap sorter; + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + Collection types = getTypes(g,nodes); + + sorter = new TreeMap(); + for (Resource type : types) { + IEntity t = EntityFactory.create(g,type); + if (t.getRelatedObjects(ProcessResource.plant3Dresource.HasGraphics).size() > 0) { + String key = t.getName(); + if (key.equals("")) key = "ERROR (" + type.getResourceId() + ")"; + sorter.put(key, type); + } + } + + + + return GraphRequestStatus.transactionComplete(); + } + + @Override + public void requestCompleted(GraphRequestStatus status) { + getShell().getDisplay().asyncExec(new Runnable(){ + @Override + public void run() { + for (Entry e : sorter.entrySet()) { + typeList.add(e.getKey()); + typeList.setData(e.getKey(), e.getValue()); + } + } + }); + } + }); + + typeList.addSelectionListener(new SelectionListener() { + public void widgetSelected(SelectionEvent e) { + session.asyncRead(new GraphRequestAdapter(){ + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + String key = typeList.getItem(typeList.getSelectionIndex()); + selectType(EntityFactory.create(g,(Resource) typeList.getData(key))); + return GraphRequestStatus.transactionComplete(); + } + }); + + } + public void widgetDefaultSelected(SelectionEvent e) { + } + }); + +// modelList.addSelectionListener(new SelectionListener() { +// public void widgetSelected(SelectionEvent e) { +// if (modelList.getSelectionIndex() < 0 || modelList.getSelectionIndex() >= modelList.getItemCount()) +// return; +// String key = modelList.getItem(modelList.getSelectionIndex()); +// selectModel((GraphicsModel) modelList.getData(key)); +// } +// public void widgetDefaultSelected(SelectionEvent e) { +// } +// }); + + Composite buttonComposite = new Composite(composite,SWT.NONE); + buttonComposite.setLayoutData(new GridData(GridData.END,GridData.FILL,true,false,4,1)); + buttonComposite.setLayout(new FillLayout(SWT.HORIZONTAL)); + scaleButton = new Button(buttonComposite,SWT.CHECK); + scaleButton.setText("Scaling"); + scaleButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + if (scaleButton.getSelection()) { + minText.setEnabled(true); + maxText.setEnabled(true); + } else { + minText.setEnabled(false); + maxText.setEnabled(false); + } + } + }); + minText = new Text(buttonComposite,SWT.SINGLE|SWT.BORDER); + minText.setText("0.0"); + + maxText = new Text(buttonComposite,SWT.SINGLE|SWT.BORDER); + maxText.setText("1.0"); + + minText.setEnabled(false); + maxText.setEnabled(false); + + applyAnimationButton = new Button(buttonComposite,SWT.PUSH); + applyAnimationButton.setText("Apply animation"); + applyAnimationButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + session.asyncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + applyAnimation(g); + return GraphRequestStatus.transactionComplete(); + } + }); + + } + }); + return composite; + } + + /** + * Updates type selection: + * Finds all GraphicsModels that are connected to instances of selected type with HasGraphics-relation + * and lists them in modelList. + * + * @param resource + */ + private void selectType(IEntity resource) { + Graph g = resource.getGraph(); + selectedType = resource.getResource(); + //modelList.removeAll(); + animationList.removeAll(); + + Collection model = resource.getRelatedObjects(ProcessResource.plant3Dresource.HasGraphics); + if (model.size() != 1) + throw new RuntimeException("Type " + resource + " does not have a model"); + + if (oe != null) { + oe.dispose(); + } + sampleInstance = null; + sampleSource = null; + for (Resource n : nodes) { + IEntity t = EntityFactory.create(g,n); + if (t.isInstanceOf(resource.getResource())) { + sampleInstance = n; + break; + } + } + if (sampleInstance != null) { +// oe = new OntologyExplorer("Animation Source",this.getShell(), new OntologyEditorInput(sampleInstance.getId())); +// if(viewpointControl != null && !viewpointControl.isDisposed()) { +// viewpointControl.dispose(); +// } +// viewpointControl = oe.getControl(oeLabelComposite, 1, OntologyExplorer.ViewpointSelector, SWT.NONE); +// Control c = oe.getControl(oeComposite, 1, OntologyExplorer.OntologyTree, SWT.SINGLE); +// c.setLayoutData(new GridData(GridData.FILL_BOTH)); +// oe.init(null, ViewpointUtils.getModelledHandler(oe.getGraph(), Builtins.DefaultViewpointId), null, ViewLabelProviderDecorationSettings.DEFAULT, new MenuAboutToShowAction(), new NullAdditionAction(), false); +// //oeComposite.layout(true, true); +// oe.setSelectionScheme(new SourceSelectionScheme(oe)); +// //oeLabelComposite.layout(true, true); +// oeComposite.getParent().getParent().layout(true,true); + + oe = new GraphExplorer(oeComposite,SWT.SINGLE); + oe.getTree().setLayoutData(new GridData(GridData.FILL_BOTH)); + oe.getViewer().addPostSelectionChangedListener(new OEPathSelectionListener(){ + @Override + protected void pathSelectionUpdated(java.util.List paths) { + if (paths.size() == 0) { + //selectSource(null); + } else { + final TraversalPath path = paths.iterator().next(); + session.asyncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + selectSource(g,path); + return GraphRequestStatus.transactionComplete(); + } + }); + + } + } + }); + } + +// modelList.redraw(); +// animationList.redraw(); + selectModel(new G3DModel(model.iterator().next())); + } + + /** + * Selects model and shows model's animations in animationList + * @param model + */ + private void selectModel(G3DModel model) { + animationList.removeAll(); + + TreeMap sorter = new TreeMap(); + + Collection animations = model.getAnimation(); + for (Animation a : animations) { + String key = a.getName(); + if (key.equals("")) key = "ERROR (" + a.getResource().getResourceId() + ")"; + sorter.put(key, a); + } + + final TreeMap fa = sorter; + + getShell().getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + for (Entry e : fa.entrySet()) { + animationList.add(e.getKey()); + animationList.setData(e.getKey(), e.getValue()); + } + animationList.redraw(); + + } + }); + + } + + private void selectSource(Graph graph,TraversalPath path) { + //System.out.println(sampleInstance + " " + resource); + + if (path == null) { + sampleSource = null; + return; + } + IEntity t = EntityFactory.create(graph,path.getResource()); + if (!t.isInstanceOf(ProcessResource.builtins.Double)) { + sampleSource = null; + } else { + sampleSource = path.getResource(); + samplePath = new ArrayList(); + PathUtils.createPath(samplePath, path ,sampleInstance,sampleSource,oe); + } + } + + + + private void applyAnimation(Graph graph) { + int animationIndex = animationList.getSelectionIndex(); + if (sampleInstance == null || sampleSource == null || samplePath == null || animationIndex == -1) { + throw new RuntimeException("Missing required selections"); + //return; + } + + java.util.List instances = new ArrayList(); + java.util.List sources = new ArrayList(); + browseOthers(graph,instances, sources); + instances.add(sampleInstance); + sources.add(sampleSource); + + for (int i = 0; i < instances.size(); i++) { + IGraphicsNode n = adapter.getNode(instances.get(i)); + if (!(n instanceof Animatable)) { + //throw new RuntimeException("Node is not animatable"); + continue; + } + + Animatable animatable = (Animatable) n; + Animation a = (Animation) animationList.getData(animationList.getItem(animationIndex)); + if (!animatable.setAnimation(graph,a.getResource())) { + //throw new RuntimeException("Cannot set animation"); + continue; + } + ResourceAnimationController c; + if (scaleButton.getSelection()) { + c = new ScaledResourceAnimationController(sources.get(i),Double.parseDouble(minText.getText()),Double.parseDouble(maxText.getText())); + } else { + c = new ResourceAnimationController(sources.get(i)); + } + c.addAnimatable(animatable); + animationSystem.add(c); + } + + } + + private void browseOthers(Graph g, java.util.List instances,java.util.List sources) { + java.util.List possibleInstances = new ArrayList(); + for (Resource n : nodes) { + IEntity t = EntityFactory.create(g,n); + if (t.isInstanceOf(selectedType) && !n.equals(sampleInstance)) { + possibleInstances.add(n.getResource()); + } + } + + for (Resource instance : possibleInstances) { + IEntity source = PathUtils.findSimilar(samplePath,EntityFactory.create(g,instance)); + if (source != null) { + instances.add(instance); + sources.add(source.getResource()); + } else { + ErrorLogger.getDefault().logWarning("Cannot find animation source for " + instance, null); + } + } + } + + + private Collection getTypes(Graph g, java.util.List instances) { + Set types = new HashSet(); + for (Resource r : instances) { + IEntity t = EntityFactory.create(g,r); + Collection tTypes = t.getTypes(); + for (IEntity type : tTypes) + types.add(type.getResource()); + } + return types; + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/ConfigureMonitorDialog.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/ConfigureMonitorDialog.java new file mode 100644 index 00000000..a771976c --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/ConfigureMonitorDialog.java @@ -0,0 +1,309 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.dialogs; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; +import java.util.TreeMap; +import java.util.Map.Entry; + +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.List; +import org.eclipse.swt.widgets.Shell; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Resource; +import org.simantics.db.Session; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.layer0.utils.viewpoints.TraversalPath; +import org.simantics.proconf.browsing.GraphExplorer; +import org.simantics.proconf.g3d.stubs.G3DModel; +import org.simantics.proconf.g3d.tools.OEPathSelectionListener; + +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.common.PathUtils; +import fi.vtt.simantics.processeditor.monitors.PathContainer; + +public class ConfigureMonitorDialog extends Dialog { + Session session; + List typeList; + java.util.List nodes; + + + private Composite oeLabelComposite; + //private Control viewpointControl; + private Composite oeComposite; + private GraphExplorer oe; + + private Button applyAnimationButton; + + Resource selectedType; + Resource sampleInstance; + java.util.List sampleSource; + java.util.List> samplePath; + + + public ConfigureMonitorDialog(Shell parentShell, Session session, java.util.List nodes) { + super(parentShell); + this.nodes = nodes; + this.session = session; + int shellStyle = getShellStyle(); + setShellStyle(shellStyle | SWT.MAX | SWT.RESIZE); + } + + @Override + protected void configureShell(Shell newShell) { + super.configureShell(newShell); + newShell.setText("Configure monitors"); + + } + + protected Control createDialogArea(Composite parent) { + Composite composite = (Composite) super.createDialogArea(parent); + GridLayout layout = new GridLayout(2,true); + 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); + + Label label = new Label(composite, SWT.WRAP); + label.setText("Types"); + GridData data = new GridData(GridData.CENTER,GridData.FILL,true,false,1,1); + data.widthHint = convertHorizontalDLUsToPixels(IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH); + label.setLayoutData(data); + label.setFont(parent.getFont()); + + oeLabelComposite = new Composite(composite,SWT.NONE); + oeLabelComposite.setLayoutData(data); + oeLabelComposite.setLayout(new FillLayout(SWT.HORIZONTAL)); + //label = new Label(composite, SWT.WRAP); + label = new Label(oeLabelComposite, SWT.WRAP); + label.setText("Monitor source"); +// label.setLayoutData(data); + label.setFont(parent.getFont()); + + typeList = new List(composite, SWT.BORDER | SWT.SINGLE | SWT.READ_ONLY | SWT.V_SCROLL); + typeList.setLayoutData(new GridData(GridData.GRAB_VERTICAL | GridData.VERTICAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL)); + + oeComposite = new Composite(composite,SWT.BORDER); + oeComposite.setLayoutData(new GridData(GridData.GRAB_VERTICAL | GridData.VERTICAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL)); + layout = new GridLayout(); + layout.marginWidth = 0; + layout.marginHeight = 0; + oeComposite.setLayout(layout); + session.asyncRead(new GraphRequestAdapter() { + TreeMap sorter; + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + Collection types = getTypes(g,nodes); + + sorter = new TreeMap(); + for (Resource type : types) { + IEntity t = EntityFactory.create(g, type); + String key = t.getName(); + if (key.equals("")) key = "ERROR (" + type.getResourceId() + ")"; + sorter.put(key, type); + } + + + return GraphRequestStatus.transactionComplete(); + } + + @Override + public void requestCompleted(GraphRequestStatus status) { + getShell().getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + for (Entry e : sorter.entrySet()) { + typeList.add(e.getKey()); + typeList.setData(e.getKey(), e.getValue()); + } + } + }); + } + }); + + typeList.addSelectionListener(new SelectionListener() { + public void widgetSelected(SelectionEvent e) { + session.asyncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + String key = typeList.getItem(typeList.getSelectionIndex()); + selectType(EntityFactory.create(g,(Resource) typeList.getData(key))); + return GraphRequestStatus.transactionComplete(); + } + }); + + } + public void widgetDefaultSelected(SelectionEvent e) { + } + }); + + + + Composite buttonComposite = new Composite(composite,SWT.NONE); + buttonComposite.setLayoutData(new GridData(GridData.END,GridData.FILL,true,false,4,1)); + buttonComposite.setLayout(new FillLayout(SWT.HORIZONTAL)); + + + applyAnimationButton = new Button(buttonComposite,SWT.PUSH); + applyAnimationButton.setText("Apply monitor configuration"); + applyAnimationButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + applyAnimation(); + } + }); + return composite; + } + + /** + * Updates type selection: + * Finds all GraphicsModels that are connected to instances of selected type with HasGraphics-relation + * and lists them in modelList. + * + * @param resource + */ + private void selectType(IEntity resource) { + selectedType = resource.getResource(); + + TreeMap sorter = new TreeMap(); + + Collection models = resource.getRelatedObjects(ProcessResource.plant3Dresource.HasGraphics); + for (IEntity model : models) { + + String key = model.getName(); + if (key.equals("")) key = "ERROR (" + model.getResource().getResourceId() + ")"; + sorter.put(key, new G3DModel(model)); + } + + if (oe != null) { + oe.dispose(); + } + sampleInstance = null; + sampleSource = null; + for (Resource n : nodes) { + IEntity t = EntityFactory.create(resource.getGraph(),n); + if (t.isInstanceOf(resource.getResource())) { + sampleInstance = n; + break; + } + } + if (sampleInstance != null) { +// oe = new OntologyExplorer("Animation Source",this.getShell(), new OntologyEditorInput(sampleInstance.getId())); +// if(viewpointControl != null && !viewpointControl.isDisposed()) { +// viewpointControl.dispose(); +// } +// viewpointControl = oe.getControl(oeLabelComposite, 1, OntologyExplorer.ViewpointSelector, SWT.NONE); +// Control c = oe.getControl(oeComposite, 1, OntologyExplorer.OntologyTree, SWT.MULTI); +// c.setLayoutData(new GridData(GridData.FILL_BOTH)); +// oe.init(null, ViewpointUtils.getModelledHandler(oe.getGraph(), Builtins.DefaultViewpointId), null, ViewLabelProviderDecorationSettings.DEFAULT, new MenuAboutToShowAction(), new NullAdditionAction(), false); +// oe.setSelectionScheme(new SourceSelectionScheme(oe)); +// oeComposite.getParent().layout(true,true); + oe = new GraphExplorer(oeComposite,SWT.MULTI); + oe.getTree().setLayoutData(new GridData(GridData.FILL_BOTH)); + oe.getViewer().addPostSelectionChangedListener(new OEPathSelectionListener(){ + @Override + protected void pathSelectionUpdated(java.util.List paths) { + if (paths.size() == 0) { + //selectSource(null); + } else { + final java.util.List ps = paths; + session.asyncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + selectSource(g,ps); + return GraphRequestStatus.transactionComplete(); + } + }); + + } + + } + }); + } + + } + + + + private void selectSource(Graph graph, java.util.List resources) { + if (resources == null) { + sampleSource = null; + } + for (TraversalPath p : resources) { + IEntity t = EntityFactory.create(graph, p.getResource()); + if (!t.isInstanceOf(ProcessResource.builtins.Double)) { + sampleSource = null; + return; + } + } + sampleSource = new ArrayList(); + for (TraversalPath p : resources) + sampleSource.add(p.getResource()); + + samplePath = new ArrayList>(); + for (int i = 0; i < sampleSource.size(); i++) { + TraversalPath tpath = resources.get(i); + java.util.List path = new ArrayList(); + PathUtils.createPath(path, tpath,sampleInstance,sampleSource.get(i),oe); + samplePath.add(path); + } + + } + + private void applyAnimation() { + + if (sampleInstance == null || sampleSource == null || samplePath == null ) { + throw new RuntimeException("Missing required selections"); + //return; + } + + PathContainer.getInstance().clearPaths(selectedType); + for (java.util.List s : samplePath) { + PathContainer.getInstance().addPath(selectedType, s); + } + } + + + + + + private Collection getTypes(Graph g, java.util.List instances) { + Set types = new HashSet(); + for (Resource r : instances) { + IEntity t = EntityFactory.create(g,r); + Collection tTypes = t.getTypes(); + for (IEntity type : tTypes) + types.add(type.getResource()); + } + return types; + } + + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/ConfigurePipelineAnimationDialog.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/ConfigurePipelineAnimationDialog.java new file mode 100644 index 00000000..2735a69c --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/ConfigurePipelineAnimationDialog.java @@ -0,0 +1,315 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.dialogs; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Resource; +import org.simantics.db.Session; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.layer0.utils.viewpoints.TraversalPath; +import org.simantics.proconf.browsing.GraphExplorer; +import org.simantics.proconf.g3d.animation.AnimationSystem; +import org.simantics.proconf.g3d.base.JmeRenderingComponent; +import org.simantics.proconf.g3d.tools.OEPathSelectionListener; +import org.simantics.utils.ErrorLogger; + +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.animations.ResourcePipeAnimationController; +import fi.vtt.simantics.processeditor.common.PathUtils; +import fi.vtt.simantics.processeditor.stubs.PipeRun; + + +public class ConfigurePipelineAnimationDialog extends Dialog { + Session session; + java.util.List nodes; + + //private Control viewpointControl1; + private GraphExplorer oe1; + + + //private Control viewpointControl2; + private GraphExplorer oe2; + + JmeRenderingComponent component; + + private Button applyAnimationButton; + + Resource sampleInstance; + Resource sampleSource1; + Resource sampleSource2; + java.util.List samplePath1; + java.util.List samplePath2; + AnimationSystem animationSystem; + + Button scaleButton1; + Text minText1; + Text maxText1; + + Button scaleButton2; + Text minText2; + Text maxText2; + + public ConfigurePipelineAnimationDialog(Shell parentShell, Session session,java.util.List nodes, JmeRenderingComponent component, AnimationSystem animationSystem) { + super(parentShell); + this.session = session; + this.nodes = nodes; + this.component = component; + this.animationSystem = animationSystem; + int shellStyle = getShellStyle(); + setShellStyle(shellStyle | SWT.MAX | SWT.RESIZE); + } + + @Override + protected void configureShell(Shell newShell) { + super.configureShell(newShell); + newShell.setText("Configure pipeline animations"); + + } + + protected Control createDialogArea(Composite parent) { + Composite composite = (Composite) super.createDialogArea(parent); + GridLayout layout = new GridLayout(2,true); + 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); + + Label label = new Label(composite, SWT.WRAP); + label.setText("Color Change"); + GridData data = new GridData(GridData.CENTER,GridData.FILL,true,false,1,1); + data.widthHint = convertHorizontalDLUsToPixels(IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH); + label.setLayoutData(data); + label.setFont(parent.getFont()); + + label = new Label(composite, SWT.WRAP); + label.setText("Particle velocity"); + label.setLayoutData(data); + label.setFont(parent.getFont()); + + sampleInstance = nodes.get(0).getResource(); + +// oe1 = new OntologyExplorer("Animation Source",this.getShell(), new OntologyEditorInput(sampleInstance.getId())); +// viewpointControl1 = oe1.getControl(composite, 1, OntologyExplorer.ViewpointSelector, SWT.NONE); +// +// oe2 = new OntologyExplorer("Animation Source",this.getShell(), new OntologyEditorInput(sampleInstance.getId())); +// viewpointControl2 = oe2.getControl(composite, 1, OntologyExplorer.ViewpointSelector, SWT.NONE); +// +// Control c = oe1.getControl(composite, 1, OntologyExplorer.OntologyTree, SWT.SINGLE|SWT.BORDER); +// c.setLayoutData(new GridData(GridData.FILL_BOTH)); +// +// c = oe2.getControl(composite, 1, OntologyExplorer.OntologyTree, SWT.SINGLE|SWT.BORDER); +// c.setLayoutData(new GridData(GridData.FILL_BOTH)); +// +// oe1.init(null, ViewpointUtils.getModelledHandler(oe1.getGraph(), Builtins.DefaultViewpointId), null, ViewLabelProviderDecorationSettings.DEFAULT, new MenuAboutToShowAction(), new NullAdditionAction(), false); +// oe1.setSelectionScheme(new SourceSelectionScheme(oe1)); +// +// oe2.init(null, ViewpointUtils.getModelledHandler(oe1.getGraph(), Builtins.DefaultViewpointId), null, ViewLabelProviderDecorationSettings.DEFAULT, new MenuAboutToShowAction(), new NullAdditionAction(), false); +// oe2.setSelectionScheme(new SourceSelectionScheme(oe2)); + + oe1 = new GraphExplorer(composite,SWT.SINGLE); + oe1.getTree().setLayoutData(new GridData(GridData.FILL_BOTH)); + + oe2 = new GraphExplorer(composite,SWT.SINGLE); + oe2.getTree().setLayoutData(new GridData(GridData.FILL_BOTH)); + + oe1.getViewer().addPostSelectionChangedListener(new OEPathListener(oe1)); + oe2.getViewer().addPostSelectionChangedListener(new OEPathListener(oe2)); + + + Composite buttonComposite = new Composite(composite,SWT.NONE); + buttonComposite.setLayoutData(new GridData(GridData.END,GridData.FILL,true,false,1,1)); + buttonComposite.setLayout(new FillLayout(SWT.HORIZONTAL)); + + scaleButton1 = new Button(buttonComposite,SWT.CHECK); + scaleButton1.setText("Scaling"); + scaleButton1.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + if (scaleButton1.getSelection()) { + minText1.setEnabled(true); + maxText1.setEnabled(true); + } else { + minText1.setEnabled(false); + maxText1.setEnabled(false); + } + } + }); + minText1 = new Text(buttonComposite,SWT.SINGLE|SWT.BORDER); + minText1.setText("0.0"); + + maxText1 = new Text(buttonComposite,SWT.SINGLE|SWT.BORDER); + maxText1.setText("1.0"); + + minText1.setEnabled(false); + maxText1.setEnabled(false); + + buttonComposite = new Composite(composite,SWT.NONE); + buttonComposite.setLayoutData(new GridData(GridData.END,GridData.FILL,true,false,1,1)); + buttonComposite.setLayout(new FillLayout(SWT.HORIZONTAL)); + + scaleButton2 = new Button(buttonComposite,SWT.CHECK); + scaleButton2.setText("Scaling"); + scaleButton2.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + if (scaleButton2.getSelection()) { + minText2.setEnabled(true); + maxText2.setEnabled(true); + } else { + minText2.setEnabled(false); + maxText2.setEnabled(false); + } + } + }); + minText2 = new Text(buttonComposite,SWT.SINGLE|SWT.BORDER); + minText2.setText("0.0"); + + maxText2 = new Text(buttonComposite,SWT.SINGLE|SWT.BORDER); + maxText2.setText("1.0"); + + minText2.setEnabled(false); + maxText2.setEnabled(false); + + + applyAnimationButton = new Button(composite,SWT.PUSH); + applyAnimationButton.setText("Apply animation"); + applyAnimationButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + session.syncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + applyAnimation(g); + return GraphRequestStatus.transactionComplete(); + } + }); + + } + }); + applyAnimationButton.setLayoutData(new GridData(GridData.END,GridData.FILL,true,false,2,1)); + return composite; + } + + private class OEPathListener extends OEPathSelectionListener { + GraphExplorer oe; + + public OEPathListener(GraphExplorer oe) { + this.oe = oe; + } + + protected void pathSelectionUpdated(List paths) { + if (paths.size() == 0) { + //selectSource(null); + } else { + selectSource(oe,paths.get(0)); + } + } + } + + private void selectSource(GraphExplorer oe,TraversalPath path) { + Graph graph = null; + IEntity t = EntityFactory.create(graph,path.getResource()); + if (!t.isInstanceOf(ProcessResource.builtins.Double)) + return; + if (oe == oe1) { + sampleSource1 = path.getResource(); + samplePath1 = new ArrayList(); + PathUtils.createPath(samplePath1, path,sampleInstance,sampleSource1,oe); + } else if (oe == oe2) { + sampleSource2 = path.getResource(); + samplePath2 = new ArrayList(); + PathUtils.createPath(samplePath2, path,sampleInstance,sampleSource2,oe); + } + } + + + + + private void applyAnimation(Graph graph) { + if (sampleInstance == null || sampleSource1 == null || sampleSource2 == null || samplePath1 == null|| samplePath2 == null) { + throw new RuntimeException("Missing required selections"); + //return; + } + java.util.List instances1 = new ArrayList(); + java.util.List instances2 = new ArrayList(); + java.util.List sources1 = new ArrayList(); + java.util.List sources2 = new ArrayList(); + browseOthers(instances1, sources1,samplePath1); + browseOthers(instances2, sources2,samplePath2); + instances1.add(sampleInstance); + instances2.add(sampleInstance); // instances1 == instances2 + sources1.add(sampleSource1); + sources2.add(sampleSource2); + + for (int i = 0; i < instances1.size(); i++) { + + double cMin = 0.0; + double cMax = 1.0; + double vMin = 0.0; + double vMax = 0.0; + + if (scaleButton1.getSelection()) { + cMin = Double.parseDouble(minText1.getText()); + cMax = Double.parseDouble(maxText1.getText()); + } + if (scaleButton2.getSelection()) { + vMin = Double.parseDouble(minText2.getText()); + vMax = Double.parseDouble(maxText2.getText()); + } + ResourcePipeAnimationController c = new ResourcePipeAnimationController(component, new PipeRun(graph,instances1.get(i)),sources1.get(i),cMin,cMax,sources2.get(i),vMin,vMax); + + animationSystem.add(c); + } + + } + + private void browseOthers(java.util.List instances,java.util.List sources,java.util.List samplePath) { + Graph graph = null; + java.util.List possibleInstances = new ArrayList(); + for (Resource n : nodes) { + possibleInstances.add(n); + } + + for (Resource instance : possibleInstances) { + IEntity source = PathUtils.findSimilar(samplePath,EntityFactory.create(graph,instance)); + if (source != null) { + instances.add(instance); + sources.add(source.getResource()); + } else { + ErrorLogger.getDefault().logWarning("Cannot find animation source for " + instance, null); + } + } + } + + + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/EquipmentDialog.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/EquipmentDialog.java new file mode 100644 index 00000000..cf194301 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/EquipmentDialog.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.dialogs; + +import org.eclipse.swt.widgets.Shell; +import org.simantics.db.Session; + + +import fi.vtt.simantics.processeditor.ProcessResource; + +public class EquipmentDialog extends LibraryComponentDialog { + + + public EquipmentDialog(Shell parentShell, String dialogTitle, Session session) { + super(parentShell,session,ProcessResource.plant3Dresource.Equipment,dialogTitle); + + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/LibraryComponentDialog.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/LibraryComponentDialog.java new file mode 100644 index 00000000..6909fb63 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/LibraryComponentDialog.java @@ -0,0 +1,195 @@ +package fi.vtt.simantics.processeditor.dialogs; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Stack; + +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.List; +import org.eclipse.swt.widgets.Shell; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Resource; +import org.simantics.db.Session; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.proconf.ui.ProConfUI; +import org.simantics.utils.ErrorLogger; + +import fi.vtt.simantics.processeditor.ProcessResource; + +public class LibraryComponentDialog extends Dialog{ + + private List typeList; + private Resource selectedType = null; + private Session session; + private String title; + + private Resource primaryType; + private Collection requiredTypes = new ArrayList(); + private Collection filteredTypes = new ArrayList(); + + public LibraryComponentDialog(Shell shell, Session session, Resource primaryType, String title) { + super(shell); + assert(title != null); + this.session = session; + this.title = title; + this.primaryType = primaryType; + } + + + protected void setFilter(Collection filter) { + this.filteredTypes = filter; + } + + protected void setRequired(Collection required) { + this.requiredTypes = required; + } + + + @Override + protected void configureShell(Shell newShell) { + + super.configureShell(newShell); + newShell.setText(title); + } + + public Resource getComboValue() { + return selectedType; + } + + protected Control createDialogArea(Composite parent) { + Composite composite = (Composite) super.createDialogArea(parent); + + Label label = new Label(composite, SWT.WRAP); + label.setText("Select Component"); + GridData data = new GridData(GridData.GRAB_HORIZONTAL + | GridData.GRAB_VERTICAL | GridData.HORIZONTAL_ALIGN_FILL + | GridData.VERTICAL_ALIGN_CENTER); + data.widthHint = convertHorizontalDLUsToPixels(IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH); + label.setLayoutData(data); + label.setFont(parent.getFont()); + // TODO : list populating is done in random order; change to alphabetic + typeList = new List(composite, SWT.BORDER | SWT.SINGLE | SWT.READ_ONLY | SWT.V_SCROLL); + typeList.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL)); + + typeList.addSelectionListener(new SelectionListener() { + public void widgetSelected(SelectionEvent e) { + String key = typeList.getItem(typeList.getSelectionIndex()); + selectedType = (Resource) typeList.getData(key); + } + public void widgetDefaultSelected(SelectionEvent e) { + } + }); + getShell().setText(title + " loading..."); + session.asyncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + loadComponents(g); + return GraphRequestStatus.transactionComplete(); + } + + @Override + public void requestCompleted(GraphRequestStatus status) { + getDialogArea().getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + getShell().setText(title); + if (selectedType == null) { + typeList.select(0); + selectedType = (Resource)typeList.getData(typeList.getItem(0)); + } + } + + }); + } + }); + + GridData data2 = new GridData(GridData.GRAB_HORIZONTAL + | GridData.GRAB_VERTICAL | GridData.HORIZONTAL_ALIGN_FILL + | GridData.VERTICAL_ALIGN_FILL); + data2.widthHint = convertHorizontalDLUsToPixels(IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH); + data2.heightHint = 200; + typeList.setLayoutData(data2); + typeList.setFont(parent.getFont()); + + typeList.showSelection(); + + applyDialogFont(composite); + return composite; + } + + private void loadComponents(Graph g) { + Resource projectResource = ProConfUI.getProject().getResource(); + Stack handling = new Stack(); + handling.push(projectResource); + while (!handling.isEmpty()) { + final Resource node = handling.pop(); + if (g.isInstanceOf(node,primaryType)) { + IEntity equipment = EntityFactory.create(g, node); + Collection graphics = equipment + .getRelatedObjects(ProcessResource.plant3Dresource.HasGraphics); + if (graphics.size() != 1) { + ErrorLogger.defaultLogError("Equipment " + + equipment.getName() + " has " + graphics.size() + + " + graphical representation!", null); + } else { + boolean add = true; + for (Resource r : requiredTypes) { + if (!equipment.isInstanceOf(r)) { + add = false; + break; + } + } + if (add) { + for (Resource r : filteredTypes) { + if (equipment.isInstanceOf(r)) { + add = false; + break; + } + } + } + if (add) { + final String name = equipment.getName(); + getDialogArea().getDisplay().asyncExec(new Runnable() { + public void run() { + // List won't work with two ore more same names. + if (typeList.getData(name)!= null) { + String n = new String(name); + int i = 1; + while (true) { + n = name +"("+i+")"; + if (typeList.getData(n)== null) { + typeList.add(n); + typeList.setData(n, node); + break; + } + } + } else { + typeList.add(name); + typeList.setData(name, node); + } + } + }); + } + } + } else { + handling.addAll(g.getObjects(node, + ProcessResource.builtins.ConsistsOf)); + } + + } + + } + + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/NozzleDialog.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/NozzleDialog.java new file mode 100644 index 00000000..282c9ce6 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/NozzleDialog.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.dialogs; + +import org.eclipse.swt.widgets.Shell; +import org.simantics.db.Session; + + +import fi.vtt.simantics.processeditor.ProcessResource; + +public class NozzleDialog extends LibraryComponentDialog { + + + public NozzleDialog(Shell parentShell, String dialogTitle, Session session) { + super(parentShell,session,ProcessResource.plant3Dresource.Nozzle,dialogTitle); + + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/PipelineComponentDialog.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/PipelineComponentDialog.java new file mode 100644 index 00000000..a7510b4d --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/PipelineComponentDialog.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.dialogs; + +import java.util.Collection; + +import org.eclipse.swt.widgets.Shell; +import org.simantics.db.Resource; +import org.simantics.db.Session; + + + +import fi.vtt.simantics.processeditor.ProcessResource; + +public class PipelineComponentDialog extends LibraryComponentDialog{ + + + public PipelineComponentDialog(Shell parentShell, Collection requiredTypes, Collection filteredTypes, Session session) { + super(parentShell,session,ProcessResource.plant3Dresource.PipelineComponent,"Select Component"); + if (requiredTypes != null) + setRequired(requiredTypes); + if (filteredTypes != null) + setFilter(filteredTypes); + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/PipelineDialog.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/PipelineDialog.java new file mode 100644 index 00000000..5cf1ea40 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/PipelineDialog.java @@ -0,0 +1,132 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.dialogs; + +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.KeyEvent; +import org.eclipse.swt.events.KeyListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; + +public class PipelineDialog extends Dialog implements KeyListener{ + Text pipeRadiusText; + Text turnRadiusText; + + double pipeDiameter = 0.0; + double turnRadius = 0.0; + + public PipelineDialog(Shell parentShell) { + super(parentShell); + } + + public PipelineDialog(Shell parentShell, double pipeRadius, double turnRadius) { + super(parentShell); + this.pipeDiameter = pipeRadius; + this.turnRadius = turnRadius; + } + + + @Override + protected void configureShell(Shell newShell) { + super.configureShell(newShell); + newShell.setText("Configure new pipeline"); + } + + @Override + protected Control createDialogArea(Composite parent) { + Composite composite = (Composite) super.createDialogArea(parent); + Label label = new Label(composite, SWT.WRAP); + label.setText("Input pipeline specifications"); + GridData data = new GridData(GridData.GRAB_HORIZONTAL + | GridData.GRAB_VERTICAL | GridData.HORIZONTAL_ALIGN_FILL + | GridData.VERTICAL_ALIGN_CENTER); + + data.widthHint = convertHorizontalDLUsToPixels(IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH); + label.setLayoutData(data); + label.setFont(parent.getFont()); + label = new Label(composite, SWT.WRAP); + label.setText("Pipe diameter"); + label.setLayoutData(data); + label.setFont(parent.getFont()); + pipeRadiusText = new Text(composite,SWT.BORDER); + pipeRadiusText.setLayoutData(data); + label = new Label(composite, SWT.WRAP); + label.setText("Pipe elbow/turn radius"); + label.setLayoutData(data); + label.setFont(parent.getFont()); + turnRadiusText = new Text(composite,SWT.BORDER); + turnRadiusText.setLayoutData(data); + + pipeRadiusText.addKeyListener(this); + turnRadiusText.addKeyListener(this); + if (pipeDiameter > 0.0 && turnRadius > 0.0) { + pipeRadiusText.setText(Double.toString(pipeDiameter)); + turnRadiusText.setText(Double.toString(turnRadius)); + } + + + return composite; + } + + @Override + public int open() { + return super.open(); + } + + + + + public void keyPressed(KeyEvent e) { + + + } + + public void keyReleased(KeyEvent e) { + boolean ok = true; + try { + pipeDiameter = Double.parseDouble(pipeRadiusText.getText()); + turnRadius = Double.parseDouble(turnRadiusText.getText()); + if (pipeDiameter <= 0.0) + ok = false; + if (turnRadius <= 0.0) + ok = false; + + } catch (NumberFormatException err) { + ok = false; + } + if (ok) { + this.getButton(IDialogConstants.OK_ID).setEnabled(true); + } else { + this.getButton(IDialogConstants.OK_ID).setEnabled(false); + } + } + + + public double getPipeDiameter() { + return pipeDiameter; + } + + + public double getTurnRadius() { + return turnRadius; + } + + + + + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/gizmo/PositionSelectionGizmo.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/gizmo/PositionSelectionGizmo.java new file mode 100644 index 00000000..62d36858 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/gizmo/PositionSelectionGizmo.java @@ -0,0 +1,177 @@ +package fi.vtt.simantics.processeditor.gizmo; + +import java.net.URL; +import java.util.ArrayList; +import java.util.List; + +import javax.vecmath.Point3d; + +import org.eclipse.core.runtime.FileLocator; +import org.eclipse.core.runtime.Path; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.base.VecmathJmeTools; +import org.simantics.proconf.g3d.gizmo.Gizmo; +import org.simantics.utils.datastructures.Pair; + +import com.jme.bounding.BoundingSphere; +import com.jme.image.Image; +import com.jme.image.Texture; +import com.jme.math.Vector3f; +import com.jme.renderer.Renderer; +import com.jme.scene.BillboardNode; +import com.jme.scene.Node; +import com.jme.scene.shape.Quad; +import com.jme.scene.state.AlphaState; +import com.jme.scene.state.LightState; +import com.jme.scene.state.TextureState; +import com.jme.scene.state.ZBufferState; +import com.jme.util.TextureManager; + +import fi.vtt.simantics.processeditor.Activator; +import fi.vtt.simantics.processeditor.actions.PositionType; + +/** + * Gizmo that allows user to selected insertion point of a component + * TODO : for splits we want use line between component ends to + * position the button, instead of its center point. + * + * @author Marko Luukkainen + * + */ +public class PositionSelectionGizmo implements Gizmo { + + private static String PICK_PREFIX = "insert"; + private static String SPLIT_TEXTURE = "icons/middle.png"; + private static String END_TEXTURE = "icons/plus.png"; + private static String PORT_TEXTURE = END_TEXTURE; + + private ThreeDimensionalEditorBase parent; + + private boolean changed = false; + private int selected = -1; + private boolean useDistanceResize = true; + + private List nodes; + private List alphaStates; + private Node rootNode; + + public PositionSelectionGizmo(ThreeDimensionalEditorBase parent, List> positions) { + this.parent = parent; + rootNode = new Node(); + rootNode.setCullMode(Node.CULL_NEVER); + rootNode.setRenderQueueMode(Renderer.QUEUE_TRANSPARENT); + rootNode.setLightCombineMode(LightState.OFF); + int i = 0; + nodes = new ArrayList(); + alphaStates = new ArrayList(); + // create a button (billboard) for each insertion position + + ZBufferState zs = parent.getRenderingComponent().getDisplaySystem().getRenderer().createZBufferState(); + zs.setFunction(ZBufferState.CF_ALWAYS); + + for (Pair p : positions) { + BillboardNode node = new BillboardNode(""); + nodes.add(node); + Quad quad = new Quad(PICK_PREFIX + i,1.f,1.f); + + TextureState ts = parent.getRenderingComponent().getDisplaySystem().getRenderer().createTextureState(); + String filename = ""; + switch (p.second) { + case NEXT: + case PREVIOUS: + filename = END_TEXTURE; + break; + case SPLIT: + filename = SPLIT_TEXTURE; + break; + case PORT: + filename = PORT_TEXTURE; + } + URL url = FileLocator.find(Activator.getDefault().getBundle(), new Path(filename),null); + Image image = TextureManager.loadImage(url, true); + Texture texture = new Texture(); + texture.setImage(image); + texture.setFilter(Texture.FM_LINEAR); + ts.setTexture(texture); + quad.setRenderState(ts); + + AlphaState as = parent.getRenderingComponent().getDisplaySystem().getRenderer().createAlphaState(); + as.setSrcFunction(AlphaState.SB_SRC_ALPHA); + as.setDstFunction(AlphaState.DB_ONE_MINUS_SRC_ALPHA); + as.setBlendEnabled(true); + alphaStates.add(as); + quad.setRenderState(as); + quad.setRenderState(zs); + + node.attachChild(quad); + node.setLocalTranslation(VecmathJmeTools.get(p.first)); + quad.setModelBound(new BoundingSphere(0.5f,new Vector3f())); + quad.updateModelBound(); + rootNode.attachChild(node); + + i++; + } + } + + + @Override + public Node getNode() { + return rootNode; + } + + @Override + public String getPickPrefix() { + return PICK_PREFIX; + } + + @Override + public boolean isChanged() { + return changed; + } + + @Override + public void setChanged(boolean b) { + changed = b; + } + + @Override + public void setSelected(String name) { + if (name == null) { + setSelected(-1); + return; + } + assert(name.startsWith(PICK_PREFIX)); + setSelected(Integer.parseInt(name.substring(PICK_PREFIX.length()))); + } + + private void setSelected(int i) { + if (selected == i) + return; + if (selected != -1) { + alphaStates.get(selected).setDstFunction(AlphaState.DB_ONE_MINUS_SRC_ALPHA); + nodes.get(selected).getChild(0).setRenderState(alphaStates.get(selected)); + } + selected = i; + if (selected != -1) { + alphaStates.get(selected).setDstFunction(AlphaState.DB_ONE); + nodes.get(selected).getChild(0).setRenderState(alphaStates.get(selected)); + } + parent.setViewChanged(true); + } + + public int getSelected() { + return selected; + } + + public void update() { + if (useDistanceResize) { + Vector3f v = VecmathJmeTools.get(parent.getCamera().getCameraPos()); + for (BillboardNode n : nodes) { + float length = v.subtract(n.getWorldTranslation()).length(); + n.setLocalScale(length * 0.06f); + } + } + } + + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/EquipmentEditorAdapter.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/EquipmentEditorAdapter.java new file mode 100644 index 00000000..6339ca45 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/EquipmentEditorAdapter.java @@ -0,0 +1,40 @@ +package fi.vtt.simantics.processeditor.handlers; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.proconf.ui.workbench.ResourceEditorInput; +import org.simantics.proconf.ui.workbench.editor.SimpleEditorAdapter; +import org.simantics.utils.ui.BundleUtils; +import org.simantics.utils.ui.workbench.WorkbenchUtils; + +import fi.vtt.simantics.processeditor.Activator; +import fi.vtt.simantics.processeditor.ProcessResource; + +/** + * EditorAdapter for EquipmentEditor + * + * @author Marko Luukkainen + * + */ +public class EquipmentEditorAdapter extends SimpleEditorAdapter { + public EquipmentEditorAdapter() { + super("Equipment Editor", + BundleUtils.getImageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/tank.png"), + null,null,null); + } + + @Override + public boolean canHandle(Graph g, Resource r) { + if(ProcessResource.plant3Dresource == null) return false; + if(ProcessResource.plant3Dresource.Plant == null) return false; + if(!g.isInstanceOf(r, ProcessResource.plant3Dresource.Equipment)) return false; + return true; + } + + + @Override + public void openEditor(Resource r) throws Exception { + WorkbenchUtils.openEditor("org.simantics.proconf.processeditor.equipmenteditor", new ResourceEditorInput("org.simantics.proconf.processeditor.equipmenteditor",r)); + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/NewComponentHandler.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/NewComponentHandler.java new file mode 100644 index 00000000..7cb2be98 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/NewComponentHandler.java @@ -0,0 +1,290 @@ +package fi.vtt.simantics.processeditor.handlers; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.handlers.HandlerUtil; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Resource; +import org.simantics.layer0.stubs.Library; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.layer0.utils.instantiation.InstanceFactory; +import org.simantics.proconf.ui.ProConfUI; +import org.simantics.proconf.ui.utils.ResourceAdaptionUtils; + +import fi.vtt.simantics.processeditor.ProcessResource; + + +/** + * Handler that creates new pipeline components. + * + * @author Marko Luukkainen + * + */ +public class NewComponentHandler extends AbstractHandler { + + private Map nameMap; + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + ISelection s = HandlerUtil.getCurrentSelectionChecked(event); + IStructuredSelection ss = (IStructuredSelection) s; + if (ss.size() != 1) + return null; + final Resource lib = ResourceAdaptionUtils.toSingleResource(ss); + + + + if (nameMap == null) { + ProConfUI.getSession().syncRead(new GraphRequestAdapter(){ + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + nameMap = new HashMap(); + for (Resource r : getComponentTypes()) { + IEntity e = EntityFactory.create(g,r); + nameMap.put(r, e.getName()); + for (Resource r2 : getComponentOptions(r)) { + IEntity e2 = EntityFactory.create(g,r2); + nameMap.put(r2, e2.getName()); + } + } + return GraphRequestStatus.transactionComplete(); + } + }); + } + + ComponentTypeDialog dialog = new ComponentTypeDialog(Display.getDefault().getActiveShell()); + if (dialog.open() == ComponentTypeDialog.CANCEL) + return null; + final List types = dialog.getSelection(); + final String name = dialog.getName(); + + if (types.size() == 0 || name == null || name.length() == 0) + return null; + + ProConfUI.getSession().asyncWrite(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + // instantiate component + IEntity instance = EntityFactory.create(g, InstanceFactory.instantiate(g, types)); + Library l = new Library(g, lib); + l.addStatement(g.getBuiltins().ConsistsOf, instance); + instance.setName(name); + + // TODO : is this correct (instance & inherits) + for (Resource type : types) { + instance.addStatement(ProcessResource.builtins.Inherits, type); + } + + // instantiate control point(s) + List cpTypes = getControlPointTypes(types); + boolean isDual = (cpTypes.contains(ProcessResource.plant3Dresource.SizeChangeControlPoint) || + cpTypes.contains(ProcessResource.plant3Dresource.OffsettingPoint)); + IEntity cp = EntityFactory.create(g, InstanceFactory.instantiate(g, cpTypes)); + instance.addStatement(ProcessResource.plant3Dresource.HasControlPoint, cp); + if (isDual) { + IEntity subCP = EntityFactory.create(g, InstanceFactory.instantiate(g, ProcessResource.plant3Dresource.DualSubControlPoint)); + cp.addStatement(ProcessResource.plant3Dresource.HasSubPoint, subCP); + } + // instantiate model + Resource modelType = g.getResourceByURI("http://www.vtt.fi/Simantics/CSG/1.0/Types#CSGModel"); + IEntity model = EntityFactory.create(g, InstanceFactory.instantiate(g, modelType)); + instance.addStatement(ProcessResource.plant3Dresource.HasGraphics, model); + + return GraphRequestStatus.transactionComplete(); + } + }); + + + return null; + } + + /** + * Returns all possible types for a pipeline component + * @return + */ + private List getComponentTypes() { + List list = new ArrayList(); + list.add(ProcessResource.plant3Dresource.FixedLengthInlineComponent); + list.add(ProcessResource.plant3Dresource.VariableLengthInlineComponent); + list.add(ProcessResource.plant3Dresource.VariableAngleTurnComponent); + list.add(ProcessResource.plant3Dresource.FixedAngleTurnComponent); + list.add(ProcessResource.plant3Dresource.EndComponent); + list.add(ProcessResource.plant3Dresource.Nozzle); + + return list; + } + + /** + * Returns optional types for a component type + * @param type + * @return + */ + private List getComponentOptions(Resource type) { + List list = new ArrayList(); + if (type.equals(ProcessResource.plant3Dresource.FixedLengthInlineComponent)) { + list.add(ProcessResource.plant3Dresource.SizeChangeComponent); + list.add(ProcessResource.plant3Dresource.OffsetComponent); + } + return list; + } + + /** + * Returns control point type(s) for given control point type. + * + * @param types + * @return + */ + private List getControlPointTypes(List types) { + Resource primaryType = types.get(0); + List cpTypes = new ArrayList(); + if (primaryType == ProcessResource.plant3Dresource.FixedLengthInlineComponent) { + if (types.size() == 1) { + cpTypes.add(ProcessResource.plant3Dresource.FixedLengthControlPoint); + } else { + if (types.contains(ProcessResource.plant3Dresource.SizeChangeComponent)) { + cpTypes.add(ProcessResource.plant3Dresource.SizeChangeControlPoint); + } + if (types.contains(ProcessResource.plant3Dresource.OffsetComponent)) { + cpTypes.add(ProcessResource.plant3Dresource.OffsettingPoint); + } + if (cpTypes.size() == 0) { + throw new RuntimeException("Cannot find control point type for " + primaryType); + } + } + + } else if (primaryType == ProcessResource.plant3Dresource.VariableLengthInlineComponent) { + cpTypes.add(ProcessResource.plant3Dresource.VariableLengthControlPoint); + } else if (primaryType == ProcessResource.plant3Dresource.FixedAngleTurnComponent) { + cpTypes.add(ProcessResource.plant3Dresource.FixedAngleTurnControlPoint); + } else if (primaryType == ProcessResource.plant3Dresource.VariableAngleTurnComponent) { + cpTypes.add(ProcessResource.plant3Dresource.VariableAngleTurnControlPoint); + } else if (primaryType == ProcessResource.plant3Dresource.EndComponent) { + cpTypes.add(ProcessResource.plant3Dresource.EndComponentControlPoint); + } else if (primaryType == ProcessResource.plant3Dresource.Nozzle) { + cpTypes.add(ProcessResource.plant3Dresource.NozzleControlPoint); + } else { + throw new RuntimeException("Cannot find control point type for " + primaryType); + } + + return cpTypes; + } + + + private class ComponentTypeDialog extends Dialog { + + List selected = new ArrayList(); + String name; + + public ComponentTypeDialog(Shell shell) { + super(shell); + } + + @Override + protected Control createDialogArea(Composite parent) { + Composite composite = (Composite) super.createDialogArea(parent); + Label label = new Label(composite,SWT.NONE); + label.setText("Name:"); + Text text = new Text(composite,SWT.SINGLE|SWT.BORDER); + text.addModifyListener(new ModifyListener() { + @Override + public void modifyText(ModifyEvent e) { + name = ((Text)e.widget).getText(); + } + }); + GridData data = new GridData(); + data.grabExcessHorizontalSpace = true; + data.horizontalAlignment = SWT.FILL; + text.setLayoutData(data); + label = new Label(composite,SWT.NONE); + label.setText("Type:"); + for (Resource r : getComponentTypes()) { + final Button b = new Button(composite,SWT.RADIO); + b.setText(nameMap.get(r)); + b.setData(r); + b.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + Button button = (Button)e.widget; + Resource res = (Resource)button.getData(); + if (button.getSelection()) { + selected.add(0,res); + } else { + selected.remove(res); + } + } + }); + data = new GridData(); + b.setLayoutData(data); + for (Resource r2 : getComponentOptions(r)) { + final Button b2 = new Button(composite,SWT.CHECK); + b2.setText(nameMap.get(r2)); + b2.setData(r2); + b.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + b2.setEnabled(b.getSelection()); + Resource res = (Resource)b2.getData(); + if (!b.getSelection()) { + selected.remove(res); + } else if (b2.getSelection()) { + selected.add(res); + } + } + }); + b2.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + Button button = (Button)e.widget; + Resource res = (Resource)button.getData(); + if (button.getSelection()) { + selected.add(res); + } else { + selected.remove(res); + } + } + }); + b2.setEnabled(false); + data = new GridData(); + data.horizontalIndent = convertWidthInCharsToPixels(2); + b2.setLayoutData(data); + } + } + + return composite; + } + + List getSelection() { + return selected; + } + + public String getName() { + return name; + } + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/NewEquipmentHandler.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/NewEquipmentHandler.java new file mode 100644 index 00000000..49eb77ef --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/NewEquipmentHandler.java @@ -0,0 +1,110 @@ +package fi.vtt.simantics.processeditor.handlers; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.handlers.HandlerUtil; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Resource; +import org.simantics.layer0.stubs.Library; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.layer0.utils.instantiation.InstanceFactory; +import org.simantics.proconf.ui.ProConfUI; +import org.simantics.proconf.ui.utils.ResourceAdaptionUtils; + +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.stubs.Equipment; + +/** + * Creates new equipment + * + * @author Marko Luukkainen + * + */ +public class NewEquipmentHandler extends AbstractHandler { + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + ISelection s = HandlerUtil.getCurrentSelectionChecked(event); + IStructuredSelection ss = (IStructuredSelection) s; + if (ss.size() != 1) + return null; + final Resource lib = ResourceAdaptionUtils.toSingleResource(ss); + + EquipmentDialog dialog = new EquipmentDialog(Display.getDefault().getActiveShell()); + if (dialog.open() == EquipmentDialog.CANCEL) + return null; + final String name = dialog.getName(); + if (name == null || name.length() == 0) + return null; + ProConfUI.getSession().asyncWrite(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + Equipment equipment = Equipment.createDefault(g); + Library l = new Library(g, lib); + l.addStatement(g.getBuiltins().ConsistsOf, equipment); + + // TODO : is this correct (instance & inherits) + equipment.addStatement(ProcessResource.builtins.Inherits, ProcessResource.plant3Dresource.Equipment); + + Resource modelType = g.getResourceByURI("http://www.vtt.fi/Simantics/CSG/1.0/Types#CSGModel"); + IEntity model = EntityFactory.create(g, InstanceFactory.instantiate(g, modelType)); + equipment.addStatement(ProcessResource.plant3Dresource.HasGraphics, model); + equipment.setName(name); + return GraphRequestStatus.transactionComplete(); + } + }); + + + return null; + } + + private class EquipmentDialog extends Dialog { + + private String name; + + public EquipmentDialog(Shell shell) { + super(shell); + } + + @Override + protected Control createDialogArea(Composite parent) { + Composite composite = (Composite) super.createDialogArea(parent); + Label label = new Label(composite,SWT.NONE); + label.setText("Name:"); + Text text = new Text(composite,SWT.SINGLE|SWT.BORDER); + text.addModifyListener(new ModifyListener() { + @Override + public void modifyText(ModifyEvent e) { + name = ((Text)e.widget).getText(); + } + }); + GridData data = new GridData(); + data.grabExcessHorizontalSpace = true; + data.horizontalAlignment = SWT.FILL; + text.setLayoutData(data); + return composite; + } + + public String getName() { + return name; + } + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/NewPlantHandler.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/NewPlantHandler.java new file mode 100644 index 00000000..45f54cf5 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/NewPlantHandler.java @@ -0,0 +1,95 @@ +package fi.vtt.simantics.processeditor.handlers; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.handlers.HandlerUtil; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Resource; +import org.simantics.layer0.stubs.Library; +import org.simantics.proconf.ui.ProConfUI; +import org.simantics.proconf.ui.utils.ResourceAdaptionUtils; + +import fi.vtt.simantics.processeditor.stubs.Plant; + +public class NewPlantHandler extends AbstractHandler { + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + ISelection s = HandlerUtil.getCurrentSelectionChecked(event); + IStructuredSelection ss = (IStructuredSelection) s; + if (ss.size() != 1) + return null; + final Resource lib = ResourceAdaptionUtils.toSingleResource(ss); + + PlantDialog dialog = new PlantDialog(Display.getDefault().getActiveShell()); + if (dialog.open() == PlantDialog.CANCEL) + return null; + final String name = dialog.getName(); + if (name == null || name.length() == 0) + return null; + + ProConfUI.getSession().asyncWrite(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + Plant model = Plant.createDefault(g); + model.setName(name); + Library l = new Library(g, lib); + l.addStatement(g.getBuiltins().ConsistsOf, model); + + return GraphRequestStatus.transactionComplete(); + } + }); + + + return null; + } + + private class PlantDialog extends Dialog { + + private String name; + + public PlantDialog(Shell shell) { + super(shell); + } + + @Override + protected Control createDialogArea(Composite parent) { + Composite composite = (Composite) super.createDialogArea(parent); + Label label = new Label(composite,SWT.NONE); + label.setText("Name:"); + Text text = new Text(composite,SWT.SINGLE|SWT.BORDER); + text.addModifyListener(new ModifyListener() { + @Override + public void modifyText(ModifyEvent e) { + name = ((Text)e.widget).getText(); + } + }); + GridData data = new GridData(); + data.grabExcessHorizontalSpace = true; + data.horizontalAlignment = SWT.FILL; + text.setLayoutData(data); + return composite; + } + + public String getName() { + return name; + } + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/PipelineComponentEditorAdapter.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/PipelineComponentEditorAdapter.java new file mode 100644 index 00000000..2523fa1e --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/PipelineComponentEditorAdapter.java @@ -0,0 +1,45 @@ +package fi.vtt.simantics.processeditor.handlers; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.proconf.ui.workbench.ResourceEditorInput; +import org.simantics.proconf.ui.workbench.editor.SimpleEditorAdapter; +import org.simantics.utils.ui.BundleUtils; +import org.simantics.utils.ui.workbench.WorkbenchUtils; + +import fi.vtt.simantics.processeditor.Activator; +import fi.vtt.simantics.processeditor.ProcessResource; + +/** + * EditorAdapter for PipeLineComponentEditor + * + * @author Marko Luukkainen + * + */ +public class PipelineComponentEditorAdapter extends SimpleEditorAdapter { + public PipelineComponentEditorAdapter() { + super("Component Editor", + BundleUtils.getImageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/Component.png"), + null,null,null); + } + + @Override + public boolean canHandle(Graph g, Resource r) { + if(ProcessResource.plant3Dresource == null) return false; + if(ProcessResource.plant3Dresource.Plant == null) return false; + if(!g.isInstanceOf(r, ProcessResource.plant3Dresource.PipelineComponent)) { + if (g.isInstanceOf(r, ProcessResource.plant3Dresource.Nozzle)) + return true; + return false; + } + if(g.isInstanceOf(r, ProcessResource.plant3Dresource.CodedComponent)) return false; + return true; + } + + + @Override + public void openEditor(Resource r) throws Exception { + WorkbenchUtils.openEditor("org.simantics.proconf.processeditor.componenteditor", new ResourceEditorInput("org.simantics.proconf.processeditor.componenteditor",r)); + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/Plant3DEditorAdapter.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/Plant3DEditorAdapter.java new file mode 100644 index 00000000..93edd948 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/Plant3DEditorAdapter.java @@ -0,0 +1,34 @@ +package fi.vtt.simantics.processeditor.handlers; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.proconf.ui.workbench.ResourceEditorInput; +import org.simantics.proconf.ui.workbench.editor.SimpleEditorAdapter; +import org.simantics.utils.ui.BundleUtils; +import org.simantics.utils.ui.workbench.WorkbenchUtils; + +import fi.vtt.simantics.processeditor.Activator; +import fi.vtt.simantics.processeditor.ProcessResource; + +public class Plant3DEditorAdapter extends SimpleEditorAdapter { + public Plant3DEditorAdapter() { + super("PlantEditor", + BundleUtils.getImageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/factory.png"), + null,null,null); + } + + @Override + public boolean canHandle(Graph g, Resource r) { + if(ProcessResource.plant3Dresource == null) return false; + if(ProcessResource.plant3Dresource.Plant == null) return false; + return g.isInstanceOf(r, ProcessResource.plant3Dresource.Plant); + } + + + @Override + public void openEditor(Resource r) throws Exception { + WorkbenchUtils.openEditor("org.simantics.proconf.processeditor.planteditor", new ResourceEditorInput("org.simantics.proconf.processeditor.planteditor",r)); + + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/Plant3DProjectAdapter.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/Plant3DProjectAdapter.java new file mode 100644 index 00000000..305b6362 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/Plant3DProjectAdapter.java @@ -0,0 +1,14 @@ +package fi.vtt.simantics.processeditor.handlers; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.db.adaption.AdaptionException; +import org.simantics.db.adaption.ResourceAdapter; + +public class Plant3DProjectAdapter implements ResourceAdapter { + @SuppressWarnings("unchecked") + @Override + public T adapt(Graph graph, Resource resource, Resource mia) throws AdaptionException { + return (T) new Plant3DProjectType(graph,resource); + } +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/Plant3DProjectType.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/Plant3DProjectType.java new file mode 100644 index 00000000..f1121176 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/Plant3DProjectType.java @@ -0,0 +1,53 @@ +package fi.vtt.simantics.processeditor.handlers; + +import java.util.ArrayList; +import java.util.Collection; + +import org.simantics.db.Builtins; +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.layer0.utils.direct.GraphUtils; +import org.simantics.proconf.ui.projects.IProject; +import org.simantics.proconf.ui.projects.ProjectType; + +public class Plant3DProjectType extends ProjectType{ + + public Plant3DProjectType(Graph graph, Resource projectTypeResource) { + super(graph, projectTypeResource); + } + + @Override + public Resource createProject(Graph g, String name) throws Exception { + Resource project = super.createProject(g, name); + Builtins b = g.getBuiltins(); + { // Plants + Resource modelLibrary = g.newResource(); + g.addStatement(modelLibrary, b.InstanceOf, b.ModelLibrary); + GraphUtils.addRelatedScalarString(g, modelLibrary, b.HasName, "Plants"); + g.addStatement(project, b.ConsistsOf, modelLibrary); + } + { // Equipment + Resource modelLibrary = g.newResource(); + g.addStatement(modelLibrary, b.InstanceOf, b.ModelLibrary); + GraphUtils.addRelatedScalarString(g, modelLibrary, b.HasName, "Equipment"); + g.addStatement(project, b.ConsistsOf, modelLibrary); + } + return project; + + } + + @Override + public IProject loadProject(Graph g, Resource r) { + + IProject project = super.loadProject(g, r); + project.set(DefaultPerspective, "org.simantics.proconf.processeditor.plantmodelling"); + Collection perspectives = new ArrayList(); + perspectives.add("org.simantics.proconf.processeditor.plantmodelling"); + project.set(Perspectives, perspectives); + + return project; + } + + + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/BillboardMonitor.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/BillboardMonitor.java new file mode 100644 index 00000000..d35d62c1 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/BillboardMonitor.java @@ -0,0 +1,216 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.monitors; + +import java.awt.Color; +import java.util.ArrayList; + +import javax.vecmath.Point3d; +import javax.vecmath.Vector3d; + +import org.simantics.db.Graph; +import org.simantics.proconf.g3d.base.G3DTools; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.base.VecmathJmeTools; +import org.simantics.proconf.g3d.scenegraph.IGraphicsNode; +import org.simantics.proconf.g3d.stubs.G3DNode; + +import com.jme.image.Texture; +import com.jme.math.Vector3f; +import com.jme.renderer.ColorRGBA; +import com.jme.renderer.Renderer; +import com.jme.scene.BillboardNode; +import com.jme.scene.Node; +import com.jme.scene.shape.Quad; +import com.jme.scene.state.AlphaState; +import com.jme.scene.state.MaterialState; +import com.jme.scene.state.RenderState; +import com.jme.scene.state.TextureState; +import com.jme.scene.state.ZBufferState; +import com.jmex.awt.swingui.ImageGraphics; + + +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.stubs.InlineComponent; + + + +/** + * A monitor that uses billboard to show it's information. + * + * @author Marko Luukkainen + * + */ +//TODO : should it be variable length / fixed length inline component instead of Straight + +public class BillboardMonitor implements Monitor{ + private enum Type{POSITION,PIPE}; + private Type type; + private ThreeDimensionalEditorBase editor; + private BillboardNode monitorNode = null; + private int monitorSize = 128; + private ImageGraphics graphics = ImageGraphics.createInstance(monitorSize, monitorSize, 0); + private Node currentParent = null; + private IGraphicsNode node = null; + private boolean useDistanceResize = true; + + Point3d start; + Point3d end; + Point3d middle; + + private MonitorTextProvider provider = new ObjectPropertyProvider(); + + + public BillboardMonitor(ThreeDimensionalEditorBase editor) { + this.editor = editor; + monitorNode = new BillboardNode(""); + monitorNode.setRenderQueueMode(Renderer.QUEUE_TRANSPARENT); + ZBufferState zs = editor.getRenderingComponent() + .getDisplaySystem().getRenderer().createZBufferState(); + zs.setEnabled(true); + zs.setFunction(ZBufferState.CF_ALWAYS); + monitorNode.setRenderState(zs); + Quad quad = new Quad(""); + quad.initialize(3.f, 3.f); + monitorNode.attachChild(quad); + // SWTImageGraphics graphics = + // SWTImageGraphics.createInstance(64,64, 0); + + graphics.clearRect(0, 0, monitorSize, monitorSize); + + // graphics.setFont(new Font("Arial",Font.PLAIN,30)); + // graphics.setColor(Display.getDefault().getSystemColor(SWT.COLOR_GREEN)); + graphics.setColor(new Color(0, 255, 0, 255)); + graphics.drawString("Monitor", 0, 32); + + TextureState ts = editor.getRenderingComponent().getDisplaySystem().getRenderer().createTextureState(); + Texture texture = new Texture(); + texture.setApply(Texture.AM_MODULATE); + // texture.setBlendColor(new ColorRGBA(1, 1, 1, 1)); + texture.setFilter(Texture.MM_LINEAR); + texture.setMipmapState(Texture.FM_LINEAR); + texture.setImage(graphics.getImage()); + graphics.update(); + AlphaState as = editor.getRenderingComponent().getDisplaySystem() + .getRenderer().createAlphaState(); + as.setBlendEnabled(true); + as.setSrcFunction(AlphaState.SB_SRC_ALPHA); + as.setDstFunction(AlphaState.DB_ONE_MINUS_SRC_ALPHA); + as.setTestEnabled(true); + as.setTestFunction(AlphaState.TF_GREATER); + ts.setTexture(texture); + MaterialState ms = editor.getRenderingComponent().getDisplaySystem().getRenderer().createMaterialState(); + ms.setEmissive(new ColorRGBA(1.f, 1.f, 1.f, 0.f)); + monitorNode.setRenderState(ts); + monitorNode.setRenderState(as); + monitorNode.setRenderState(ms); + graphics.drawLine(0, 33, monitorSize-1, 33); + graphics.update(); + } + + public boolean acceptNode(Graph graph, IGraphicsNode node) { + Node selectedParent = node.getGroup(); + if (currentParent == null || !selectedParent.equals(currentParent)) { + if (node.getG3DNode(graph).getLocalPosition() != null) { + return true; + } else if (node.getG3DNode(graph).isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent)) { + + return true; + } + } + + return false; + } + + public void setNode(Graph graph, IGraphicsNode node) { + G3DNode n = node.getG3DNode(graph); + if (n.getLocalPosition() != null) { + type = Type.POSITION; + monitorNode.setLocalTranslation(new Vector3f(0.f,0.f,0.f)); + } else if (n.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent)) { + type = Type.PIPE; + InlineComponent ic = new InlineComponent(n); + start = G3DTools.getPoint(ic.getControlPoint().getPrevious().getLocalPosition()); + end = G3DTools.getPoint(ic.getControlPoint().getNext().getLocalPosition()); + Vector3d dir = new Vector3d(end); + dir.sub(start); + dir.scale(0.5); + middle = new Point3d(start); + middle.add(dir); + monitorNode.setLocalTranslation(VecmathJmeTools.get(middle)); + } else { + return; + } + Node selectedParent = node.getGroup(); + this.node = node; + currentParent = selectedParent; + monitorNode.removeFromParent(); + currentParent.attachChild(monitorNode); + + provider.setSource(n); + update(graph); + } + + public IGraphicsNode getNode() { + return node; + } + + public void update() { + if (useDistanceResize) { + Vector3f v = VecmathJmeTools.get(editor.getCamera().getCameraPos()); + v.subtractLocal(monitorNode.getWorldTranslation()); + float length = v.length(); + monitorNode.setLocalScale(length * 0.06f); + } + } + + + public void update(Graph graph) { + ArrayList titles = provider.getTexts(graph); + graphics.clearRect(0, 0, monitorSize, monitorSize); + int y = 16; + for (String s : titles) { + graphics.drawString(s, 0, y); + y += 16; + } + + TextureState ts = (TextureState) monitorNode + .getRenderState(RenderState.RS_TEXTURE); + ts.deleteAll(); // FIXME : texture won't be updated without this + graphics.update(); + update(); + } + + public void remove() { + monitorNode.removeFromParent(); + node = null; + } + + /** + * if true, monitors size is independent of distance to camera. Else monitor's size changes when camera is moved. + * @return + */ + public boolean isUseDistanceResize() { + return useDistanceResize; + } + + public void setUseDistanceResize(boolean useDistanceResize) { + this.useDistanceResize = useDistanceResize; + if (!useDistanceResize) { + monitorNode.setLocalScale(1.f); + } + } + + public void setTextProvider(MonitorTextProvider provider) { + this.provider = provider; + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/Monitor.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/Monitor.java new file mode 100644 index 00000000..d748b175 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/Monitor.java @@ -0,0 +1,62 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.monitors; + +import org.simantics.db.Graph; +import org.simantics.proconf.g3d.scenegraph.IGraphicsNode; + + + + +/** + * Interface for monitors (Textual display of objects properties) + * + * @author Marko Luukkainen + * + */ +public interface Monitor { + + /** + * Returns true if monitor can be attached to node + * @param node + * @return + */ + public boolean acceptNode(Graph graph,IGraphicsNode node); + + /** + * Returns the scene-graph node where monitor is attached + * @return + */ + public IGraphicsNode getNode(); + + /** + * Sets monitored node + * @param node + */ + public void setNode(Graph graph,IGraphicsNode node); + + /** + * Updates monitor's texts + * + */ + public void update(); + + public void update(Graph graph); + + /** + * Removes the monitor. + */ + public void remove(); + + + public void setTextProvider(MonitorTextProvider provider); + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/MonitorTextProvider.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/MonitorTextProvider.java new file mode 100644 index 00000000..08b3b02b --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/MonitorTextProvider.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.monitors; + +import java.util.ArrayList; + +import org.simantics.db.Graph; +import org.simantics.layer0.utils.IEntity; + + + +public interface MonitorTextProvider { + public void setSource(IEntity instance); + public ArrayList getTexts(Graph graph); +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/ObjectPropertyProvider.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/ObjectPropertyProvider.java new file mode 100644 index 00000000..f0945609 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/ObjectPropertyProvider.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.monitors; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.layer0.utils.ResourceDebugUtils; + + +import fi.vtt.simantics.processeditor.ProcessResource; + + +public class ObjectPropertyProvider implements MonitorTextProvider { + + private Resource instance; + private Resource properties[]; + String name; + + public void setSource(IEntity instance) { + this.instance = instance.getResource(); + Collection props = instance.getRelatedObjects(ProcessResource.builtins.HasProperty); + List res = new ArrayList(); + for (IEntity t : props) + res.add(t.getResource()); + properties = new Resource[res.size()]; + properties = res.toArray(properties); + name = ResourceDebugUtils.getReadableNameForEntity(instance); + } + + public ArrayList getTexts(Graph graph) { + ArrayList titles = new ArrayList(); + if (instance == null) + return titles; + IEntity thing = EntityFactory.create(graph,instance); + name = ResourceDebugUtils.getReadableNameForEntity(thing); + titles.add(name); + + for (Resource p : properties) { + thing = EntityFactory.create(graph,p); + //if (p.isInstanceOf(Builtins.Double)) { + //typeResources = p.getRelatedResources(Builtins.InstanceOf); + //name = PropertyUtils.getScalarStringProperty(typeResources[0],Builtins.HasName); + name = ResourceDebugUtils.getReadableNameForEntity(thing); + titles.add(name); + //} + } + return titles; + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/PathContainer.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/PathContainer.java new file mode 100644 index 00000000..4c2aab7e --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/PathContainer.java @@ -0,0 +1,61 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.monitors; + +import java.util.Collection; +import java.util.List; + +import org.simantics.db.Resource; +import org.simantics.layer0.utils.IEntity; +import org.simantics.utils.datastructures.MapList; + + +/** + * Container for Paths + * FIXME : singleton + * TODO : removing paths + * TODO : prevent adding same path multiple times + * + * + * @author Marko Luukkainen + * + */ +public class PathContainer { + + private static PathContainer instance = new PathContainer(); + + MapList> paths; + + private PathContainer() { + paths = new MapList>(); + } + + public List> getPaths(IEntity instance) { + Collection types = instance.getTypes(); + if (types.size() != 1) + throw new UnsupportedOperationException("Multi-instances not supported!"); + Resource type = types.iterator().next().getResource(); + return paths.getValues(type); + } + + public void addPath(Resource type, List path) { + paths.add(type, path); + } + + public void clearPaths(Resource type) { + paths.remove(type); + } + + public static PathContainer getInstance() { + return instance; + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/ResourcePathPropertyProvider.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/ResourcePathPropertyProvider.java new file mode 100644 index 00000000..75812333 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/ResourcePathPropertyProvider.java @@ -0,0 +1,87 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.monitors; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.layer0.utils.ResourceDebugUtils; + +import fi.vtt.simantics.processeditor.common.PathUtils; + + +public class ResourcePathPropertyProvider implements MonitorTextProvider { + + private Resource instance; + private List properties = new ArrayList(); + private List names = new ArrayList(); + private List units = new ArrayList(); + String name; + + private MonitorTextProvider provider = new ObjectPropertyProvider(); + + public void setSource(IEntity instance) { + this.instance = instance.getResource(); + properties.clear(); + names.clear(); + //units.clear(); + List> paths = PathContainer.getInstance().getPaths(instance); + if (paths != null) { + for (List path : paths) { + IEntity source = PathUtils.findSimilar(path, instance); + if (source != null) + properties.add(source.getResource()); + } + } + Collection types = instance.getTypes(); + name = ResourceDebugUtils.getReadableNameForEntity(types.iterator().next()); + for (Resource p : properties) { + names.add(ResourceDebugUtils.getReadableNameForEntity(EntityFactory.create(instance.getGraph(),p))); +// if (p.isInstanceOf(Builtins.Double)) { +// typeResources = p.getRelatedResources(Builtins.InstanceOf); +// String name = PropertyUtils.getScalarStringProperty(typeResources[0],Builtins.HasName); +// Property property = new Property(p); +// String abbr = property.getUnitAbbreviation(); +// names.add(name); +// if (abbr != null) +// units.add(abbr); +// else +// units.add(""); +// //titles.add(name + " " + PropertyUtils.getDoubleValue(p)[0] + " " + abbr); +// } + } + provider.setSource(instance); + } + + public ArrayList getTexts(Graph graph) { + if (properties.size() == 0) + return provider.getTexts(graph); + ArrayList titles = new ArrayList(); + if (instance == null) + return titles; + + titles.add(name); + for (int i = 0; i < properties.size(); i++) { + //titles.add(names.get(i) + " " + Double.toString(PropertyUtils.getDoubleValue(properties.get(i))[0]) + " " + units.get(i)); + // FIXME : check value + titles.add(names.get(i) + " " + EntityFactory.create(graph,properties.get(i)).toProperty().getValue()); + } + + return titles; + } + + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/TextMonitor.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/TextMonitor.java new file mode 100644 index 00000000..41c60a6b --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/TextMonitor.java @@ -0,0 +1,272 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.monitors; + +import java.net.URL; +import java.util.ArrayList; + +import javax.vecmath.Point3d; +import javax.vecmath.Vector3d; + +import org.eclipse.core.runtime.FileLocator; +import org.eclipse.core.runtime.Path; +import org.eclipse.swt.graphics.Rectangle; +import org.simantics.db.Graph; +import org.simantics.proconf.g3d.base.G3DTools; +import org.simantics.proconf.g3d.base.MathTools; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.base.VecmathJmeTools; +import org.simantics.proconf.g3d.scenegraph.IGraphicsNode; +import org.simantics.proconf.g3d.stubs.G3DNode; + +import com.jme.image.Texture; +import com.jme.math.Vector2f; +import com.jme.math.Vector3f; +import com.jme.renderer.ColorRGBA; +import com.jme.renderer.Renderer; +import com.jme.scene.Node; +import com.jme.scene.Text; +import com.jme.scene.shape.Quad; +import com.jme.scene.state.AlphaState; +import com.jme.scene.state.MaterialState; +import com.jme.scene.state.RenderState; +import com.jme.scene.state.TextureState; +import com.jme.util.TextureManager; + +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.stubs.InlineComponent; + +/** + * A monitor implemetation that uses JME's text component to show it's information. + * + * @author Marko Luukkainen + * + */ +public class TextMonitor implements Monitor { + private enum Type{POSITION,PIPE}; + private Type type; + + public static String fontLocation = "data/textures/tahoma512.png"; + + + private ThreeDimensionalEditorBase editor; + private ArrayList texts = new ArrayList(); + private Node monitorNode = new Node(""); + Node textNode; + private IGraphicsNode node = null; + + Point3d start; + Point3d end; + Point3d middle; + + float width = 0.f; + float height = 0.f; + float textHeight = 0.f; + + Quad background; + + private MonitorTextProvider provider = new ObjectPropertyProvider(); + + public TextMonitor(ThreeDimensionalEditorBase editor) { + this.editor = editor; + textNode = new Node(""); + + + + AlphaState as1 = editor.getRenderingComponent().getDisplaySystem().getRenderer().createAlphaState(); + as1.setBlendEnabled(true); + as1.setSrcFunction(AlphaState.SB_SRC_ALPHA); + as1.setDstFunction(AlphaState.DB_ONE_MINUS_SRC_ALPHA); + as1.setTestEnabled(true); + as1.setTestFunction(AlphaState.TF_GREATER); + as1.setEnabled(true); + + MaterialState ms = editor.getRenderingComponent().getDisplaySystem().getRenderer().createMaterialState(); + ms.setEmissive(new ColorRGBA(0.f,1.f,0.f,0.f)); + + TextureState font = editor.getRenderingComponent().getDisplaySystem().getRenderer().createTextureState(); + /** The texture is loaded from fontLocation */ + font.setTexture(loadFontTexture()); + font.setEnabled(true); + textNode.setRenderState(font); + textNode.setRenderState(as1); + textNode.setRenderState(ms); + background = new Quad("",100.f,100.f); + + MaterialState ms2 = editor.getRenderingComponent().getDisplaySystem().getRenderer().createMaterialState(); + ms2.setEmissive(new ColorRGBA(0.f,0.f,0.f,0.8f)); + ms2.setDiffuse(new ColorRGBA(0.f,0.f,0.f,0.8f)); + + AlphaState as2 = editor.getRenderingComponent().getDisplaySystem().getRenderer().createAlphaState(); + as2.setBlendEnabled(true); + as2.setSrcFunction(AlphaState.SB_SRC_ALPHA); + as2.setDstFunction(AlphaState.DB_ONE_MINUS_SRC_ALPHA); + as2.setTestEnabled(true); + as2.setTestFunction(AlphaState.TF_GREATER); + as2.setEnabled(true); + monitorNode.setRenderState(ms2); + monitorNode.setRenderState(as2); + + background.setRenderQueueMode(Renderer.QUEUE_ORTHO); + textNode.setRenderQueueMode(Renderer.QUEUE_ORTHO); + + monitorNode.attachChild(background); + monitorNode.attachChild(textNode); + // editor.getRenderingComponent().getOrthoNode().attachChild(monitorNode); + + + } + + public boolean acceptNode(Graph graph,IGraphicsNode node) { + G3DNode n = node.getG3DNode(graph); + if (this.node == null || !node.equals(this.node)) { + if (n.getLocalPosition() != null) { + return true; + } else if (n.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent)) { + return true; + } + } + + return false; + + } + + public void setNode(Graph graph, IGraphicsNode node) { + G3DNode n = node.getG3DNode(graph); + if (n.getLocalPosition() != null) { + type = Type.POSITION; + } else if (n.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent)) { + type = Type.PIPE; + InlineComponent ic = new InlineComponent(n); + start = G3DTools.getPoint(ic.getControlPoint().getPrevious().getWorldPosition()); + end = G3DTools.getPoint(ic.getControlPoint().getNext().getWorldPosition()); + Vector3d dir = new Vector3d(end); + dir.sub(start); + dir.scale(0.5); + middle = new Point3d(start); + middle.add(dir); + } else { + return; + } + + this.node = node; + provider.setSource(n); + ArrayList titles = provider.getTexts(graph); + + for (int i = titles.size() - 1; i < texts.size(); i++) { + texts.get(i).removeFromParent(); + } + while (texts.size() < titles.size()) { + Text text = new Text("", ""); + texts.add(text); + textNode.attachChild(text); + } + width = 0.f; + height = 0.f; + for (int i = 0; i < titles.size(); i++) { + Text text = texts.get(i); + text.print(titles.get(i)); + width = Math.max(width,text.getWidth()); + textHeight = text.getHeight(); + height += textHeight; + textNode.attachChild(text); + } + background.resize(width+20.f, height+10.f); + if (monitorNode.getParent() == null) + editor.getScenegraphAdapter().getRoot().attachChild(monitorNode); + + } + + private void updateText(Graph graph) { + ArrayList titles = provider.getTexts(graph); + float newWidth = 0.f; + for (int i = 0; i < titles.size(); i++) { + Text text = texts.get(i); + text.print(titles.get(i)); + newWidth = Math.max(newWidth,text.getWidth()); + } + if (newWidth != width) { + width = newWidth; + background.resize(width+20.f, height+10.f); + } + + } + + public void update() { + if (node == null) + return; + Vector2f v; + + if (type == Type.POSITION) { + v = editor.getScreenCoord(VecmathJmeTools.getD(node.getGroup().getWorldTranslation())); + } else { + float mx = editor.getRenderingComponent().getDisplaySystem().getWidth(); + float my = editor.getRenderingComponent().getDisplaySystem().getHeight(); + Vector2f s = editor.getScreenCoord(start); + Vector2f e = editor.getScreenCoord(end); + Vector2f rs = new Vector2f(); + Vector2f re = new Vector2f(); + boolean in = MathTools.clipLineRectangle(s, e, new Vector2f(0.f,0.f), new Vector2f(mx,my), rs, re); + if (in) { + re.subtractLocal(rs); + re.multLocal(0.5f); + rs.addLocal(re); + v = rs; + } else { + // just a hack to move monitor out of the view + v = new Vector2f (mx+width,my+height); + } + + + } + background.setLocalTranslation(new Vector3f(v.x,v.y,0.f)); + float y = v.y + (height * 0.5f) - textHeight; + v.x -= width * 0.5f; + + for (Text text : texts) { + text.setLocalTranslation(new Vector3f(v.x,y,0.f)); + y -= textHeight; + } + + + + } + + @Override + public void update(Graph graph) { + updateText(graph); + update(); + } + + public IGraphicsNode getNode() { + return node; + } + + public void remove() { + monitorNode.removeFromParent(); + node = null; + } + + protected Texture loadFontTexture() { + URL url = FileLocator.find(com.jme.eclipse.Activator.getDefault().getBundle(),new Path(fontLocation),null); + return TextureManager.loadTexture(url, Texture.MM_LINEAR, + Texture.FM_LINEAR); + } + + public void setTextProvider(MonitorTextProvider provider) { + this.provider = provider; + } + + + + + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/perspectives/Plant3DModellingPerspective.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/perspectives/Plant3DModellingPerspective.java new file mode 100644 index 00000000..f7cceaa6 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/perspectives/Plant3DModellingPerspective.java @@ -0,0 +1,13 @@ +package fi.vtt.simantics.processeditor.perspectives; + +import org.eclipse.ui.IPageLayout; +import org.eclipse.ui.IPerspectiveFactory; + +public class Plant3DModellingPerspective implements IPerspectiveFactory{ + + @Override + public void createInitialLayout(IPageLayout layout) { + + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/perspectives/ViewpointGenerator.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/perspectives/ViewpointGenerator.java new file mode 100644 index 00000000..03c7a5c2 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/perspectives/ViewpointGenerator.java @@ -0,0 +1,108 @@ +package fi.vtt.simantics.processeditor.perspectives; + +import java.util.Collection; + +import org.simantics.db.Builtins; +import org.simantics.layer0.utils.IEntity; +import org.simantics.layer0.utils.Statement; +import org.simantics.layer0.utils.viewpoints.AcceptDecision; +import org.simantics.layer0.utils.viewpoints.AcceptRule; +import org.simantics.layer0.utils.viewpoints.PlainStateFactory; +import org.simantics.layer0.utils.viewpoints.ResourceViewpoint; +import org.simantics.layer0.utils.viewpoints.State; +import org.simantics.layer0.utils.viewpoints.StateFactory; +import org.simantics.layer0.utils.viewpoints.TraversalDecision; +import org.simantics.layer0.utils.viewpoints.TraversalRule; +import org.simantics.layer0.utils.viewpoints.rules.AcceptAllResourceAcceptRule; + +import fi.vtt.simantics.processeditor.ProcessResource; + +public class ViewpointGenerator { + public static ResourceViewpoint createViewpoint() { + StateFactory f = new PlainStateFactory(); + final State rootState = f.newState(); + final State projectState = f.newState(); + final State libraryState = f.newState(); + + return new ResourceViewpoint(new TraversalRule() { + @Override + public TraversalDecision makeTraversalDecision(State state, Statement statement) { + Builtins b = statement.getGraph().getBuiltins(); + if (state.equals(rootState)) { + if (statement.getObject().isInstanceOf(b.Ontology)) + return TraversalDecision.stopTraversal; + if(!statement.getPredicate().equals(b.ConsistsOf)) + return TraversalDecision.stopTraversal; + return TraversalDecision.continueTraversal(projectState); + } else if (state.equals(projectState)) { + if(!statement.getPredicate().equals(b.ConsistsOf)) + return TraversalDecision.stopTraversal; + return TraversalDecision.continueTraversal(libraryState); + } else if (state.equals(libraryState)) { + if(!statement.getPredicate().equals(b.ConsistsOf)) + return TraversalDecision.stopTraversal; + return TraversalDecision.continueTraversal(libraryState); + } + return TraversalDecision.stopTraversal; + } + + @Override + public boolean areAllStatesRelevant() { + return true; + } + + @Override + public Collection relevantStates() { + return null; + } + }, new AcceptRule() { + @Override + public AcceptDecision makeAcceptDecision(State state, IEntity obj) { + Builtins b = obj.getGraph().getBuiltins(); + //NOSEResource nr = NOSEResource.getInstance(obj.getGraph()); + if(obj.isInstanceOf(b.Project)) return AcceptDecision.REJECT; + else if (obj.isInstanceOf(b.Ontology)) return AcceptDecision.REJECT; + else return AcceptDecision.ACCEPT; + } + + @Override + public boolean areAllStatesRelevant() { + return true; + } + + @Override + public Collection relevantStates() { + return null; + } + }, rootState); + } + + public static ResourceViewpoint createObjectStructureViewpoint() { + StateFactory f = new PlainStateFactory(); + final State rootState = f.newState(); + + return new ResourceViewpoint(new TraversalRule() { + @Override + public TraversalDecision makeTraversalDecision(State state, + Statement statement) { + if (state.equals(rootState)) { + if (!statement.getPredicate().isSubrelationOf( + ProcessResource.g3dResource.HasChild)) + return TraversalDecision.stopTraversal; + return TraversalDecision.continueTraversal(rootState); + } + return TraversalDecision.stopTraversal; + } + + @Override + public boolean areAllStatesRelevant() { + return true; + } + + @Override + public Collection relevantStates() { + return null; + } + }, new AcceptAllResourceAcceptRule(), rootState); + } +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/scenegraph/NonVisibleNode.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/scenegraph/NonVisibleNode.java new file mode 100644 index 00000000..240dd866 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/scenegraph/NonVisibleNode.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.scenegraph; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.proconf.g3d.scenegraph.IGraphicsNode; +import org.simantics.proconf.g3d.scenegraph.NonTransformableNode; + +import fi.vtt.simantics.processeditor.ProcessResource; + +public class NonVisibleNode extends NonTransformableNode { + + public NonVisibleNode(IGraphicsNode parent, Graph graph, Resource resource) { + super(parent,resource); + if (!getG3DNode(graph).isInstanceOf(ProcessResource.plant3Dresource.NonVisibleComponent)) + throw new RuntimeException("Resource must be instance of NonVisibleComponent"); + + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/scenegraph/PipeComponentNode.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/scenegraph/PipeComponentNode.java new file mode 100644 index 00000000..2c204a27 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/scenegraph/PipeComponentNode.java @@ -0,0 +1,107 @@ +package fi.vtt.simantics.processeditor.scenegraph; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import javax.vecmath.AxisAngle4d; +import javax.vecmath.Quat4d; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.scenegraph.IGraphicsNode; +import org.simantics.proconf.g3d.scenegraph.ShapeNode; + +import com.jme.math.Quaternion; +import com.jme.renderer.ColorRGBA; +import com.jme.scene.Geometry; +import com.jme.scene.state.MaterialState; +import com.jme.scene.state.RenderState; + +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.common.ControlPointTools; +import fi.vtt.simantics.processeditor.common.PipingTools; +import fi.vtt.simantics.processeditor.stubs.CodedComponent; +import fi.vtt.simantics.processeditor.stubs.PipeControlPoint; +import fi.vtt.simantics.processeditor.stubs.Plant3DResource; +import fi.vtt.simantics.processeditor.stubs.SizeChangeControlPoint; + + +/** + * This is for hard-coded geometries + * TODO : we need an extension point for geometries, + * so that other code-based geometries can be supported + * + * + * @author Marko Luukkainen + * + */ +public class PipeComponentNode extends ShapeNode { + + enum Type{ELBOW,STRAIGHT,REDUCER}; + + Type type; + Resource controlPoint; + + + public PipeComponentNode(ThreeDimensionalEditorBase editor, IGraphicsNode parent, Graph graph, Resource resource) { + super(editor, parent, graph, resource); + CodedComponent component = new CodedComponent(graph,resource); + PipeControlPoint cp = component.getControlPoint(); + Plant3DResource p3r = ProcessResource.plant3Dresource; + controlPoint = cp.getResource(); + + if (component.isInstanceOf(p3r.Elbow)) { + type = Type.ELBOW; + } else if (component.isInstanceOf(p3r.Straight)) { + type = Type.STRAIGHT; + } else if (component.isInstanceOf(p3r.Elbow)) { + type = Type.REDUCER; + } + + + } + + @Override + public Collection getMaterial() { + MaterialState ms = null; + ms = editor.getRenderingComponent().getDisplaySystem().getRenderer().createMaterialState(); + ms.setEmissive(new ColorRGBA(0.f,0.f,0.f,0.f)); + ms.setSpecular(new ColorRGBA(1.f,1.f,1.f,1.f)); + ms.setEnabled(true); + ms.setShininess(128.f); + if (type == Type.ELBOW) { + ms.setDiffuse(new ColorRGBA(0.5f,0.5f,0.5f,0.f)); + ms.setAmbient(new ColorRGBA(0.5f,0.5f,0.5f,0.f)); + } else if (type == Type.STRAIGHT) { + ms.setDiffuse(new ColorRGBA(0.75f,0.75f,0.75f,0.f)); + ms.setAmbient(new ColorRGBA(0.75f,0.75f,0.75f,0.f)); + } else { + ms.setDiffuse(new ColorRGBA(0.6f,0.6f,0.6f,0.f)); + ms.setAmbient(new ColorRGBA(0.6f,0.6f,0.6f,0.f)); + } + List states = new ArrayList(); + states.add(ms); + return states; + } + + + @Override + public void updateTransform(Graph graph) { + if (type == Type.REDUCER) { + SizeChangeControlPoint sccp = new SizeChangeControlPoint(graph, controlPoint); + Quat4d q = ControlPointTools.getControlPointLocalOrientationQuat(sccp, sccp.getRotationAngle()[0], true); + update(q); + } + if (type != Type.STRAIGHT) { + super.updateTransform(graph); + } else { + transform.setLocalTranslation(0.f,0.f,0.f); + transform.setLocalRotation(new Quaternion()); + } + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/scenegraph/PipeRunNode.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/scenegraph/PipeRunNode.java new file mode 100644 index 00000000..b03a36fb --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/scenegraph/PipeRunNode.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.scenegraph; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.proconf.g3d.scenegraph.IGraphicsNode; +import org.simantics.proconf.g3d.scenegraph.NonTransformableNode; + +import fi.vtt.simantics.processeditor.ProcessResource; + +public class PipeRunNode extends NonTransformableNode { + + public PipeRunNode(IGraphicsNode parent, Graph graph, Resource resource) { + super(parent,resource); + if (!getG3DNode(graph).isInstanceOf(ProcessResource.plant3Dresource.PipeRun)) + throw new RuntimeException("Resource must be instance of Pipeline"); + + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/scenegraph/PipelineComponentNode.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/scenegraph/PipelineComponentNode.java new file mode 100644 index 00000000..07f20eb1 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/scenegraph/PipelineComponentNode.java @@ -0,0 +1,87 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.scenegraph; + +import javax.vecmath.AxisAngle4d; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.scenegraph.IGraphicsNode; +import org.simantics.proconf.g3d.scenegraph.ParameterizedModelNode; + +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.common.ControlPointTools; +import fi.vtt.simantics.processeditor.stubs.PipeControlPoint; +import fi.vtt.simantics.processeditor.stubs.PipelineComponent; + + + +public class PipelineComponentNode extends ParameterizedModelNode { + + boolean updating = false; + + public PipelineComponentNode(ThreeDimensionalEditorBase editor, IGraphicsNode parent, Graph graph, Resource resource) { + super(editor,parent,graph, resource, ProcessResource.plant3Dresource.HasGraphics); + PipelineComponent component = new PipelineComponent(graph, resource); + if(!component.isInstanceOf(ProcessResource.plant3Dresource.PipelineComponent)) + throw new RuntimeException("Resource must be instance of Inline Component " + resource); + if (!(parent instanceof PipeRunNode)) + throw new RuntimeException("Parent must be instance of PipelineNode " + parent.getResource() + " " + resource); + + //PipeControlPoint pcp = component.getControlPoint(); +// monitor = new StructuralChangeMonitor( +// new StructuralChangeListener[] { this }, pcp.getResource(), GlobalIdMap +// .get(Layer0Mapping.HAS_PROPERTY)); + updateTransform(graph); + } + +// public void handleUpdate(StructuralChangeMonitor monitor, GraphChangeEvent event) { +// if (updating) +// return; +// if (event.getParameter() instanceof InlineComponentNode) +// return; +// if (event.getTransactionId() == null) +// return; +// if (event.getParameter() instanceof AbstractGraphicsNode) +// return; +// +// updating = true; +// updateTransform(); +// updating = false; +// } + + public void updateTransform(Graph graph) { + super.updateTransform(graph); + /* + PipelineComponent component = new PipelineComponent(graph,shapeResource); + + PipeControlPoint pcp = component.getControlPoint(); + Double angle = component.getAtMostOneRelatedScalarDouble(ProcessResource.plant3Dresource.HasRotationAngle); + double componentAngle = 0.0; + if (angle != null) + componentAngle = angle; + + AxisAngle4d aa = ControlPointTools.getControlPointRotation(pcp, componentAngle); + update(aa); + */ + } + + + public void dispose() { + //monitor.dispose(); + super.dispose(); + } + + + + +} \ No newline at end of file diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/tools/ControlPointContribution.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/tools/ControlPointContribution.java new file mode 100644 index 00000000..2f3dba8a --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/tools/ControlPointContribution.java @@ -0,0 +1,431 @@ +package fi.vtt.simantics.processeditor.tools; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import javax.vecmath.AxisAngle4d; +import javax.vecmath.Point3d; +import javax.vecmath.Quat4d; +import javax.vecmath.Vector3d; + +import org.eclipse.core.runtime.FileLocator; +import org.eclipse.core.runtime.Path; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.IToolBarManager; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.layout.FormAttachment; +import org.eclipse.swt.layout.FormData; +import org.eclipse.swt.layout.FormLayout; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Resource; +import org.simantics.proconf.g3d.actions.ContextAction; +import org.simantics.proconf.g3d.base.EditorContribution; +import org.simantics.proconf.g3d.base.G3DTools; +import org.simantics.proconf.g3d.base.MathTools; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.base.VecmathJmeTools; +import org.simantics.proconf.g3d.common.StructuredResourceSelection; +import org.simantics.utils.ErrorLogger; + +import com.jme.renderer.ColorRGBA; +import com.jme.scene.Geometry; +import com.jme.scene.Node; +import com.jme.scene.Spatial; +import com.jme.scene.TriMesh; +import com.jme.scene.shape.Sphere; +import com.jme.scene.state.MaterialState; +import com.jme.util.export.Savable; +import com.jme.util.export.binary.BinaryImporter; +import com.jmex.model.converters.ObjToJme; + +import fi.vtt.simantics.processeditor.Activator; +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.common.PipeComponentProvider; +import fi.vtt.simantics.processeditor.stubs.DirectedControlPoint; +import fi.vtt.simantics.processeditor.stubs.PipeControlPoint; + +public class ControlPointContribution implements EditorContribution { + private List actions = new ArrayList(); + private ThreeDimensionalEditorBase parent; + private Resource componentResource; + private Resource controlPointResource; + + private Composite sideComposite; + + private double radius = 0.2; + private double radius2 = 0.1; + private double angle = Math.PI / 4.0; + + public ControlPointContribution(ThreeDimensionalEditorBase parent) { + this.parent = parent; + } + + @Override + public void createControl(Composite parent) { + FormLayout flayout = new FormLayout(); + parent.setLayout(flayout); + sideComposite = new Composite(parent,SWT.BORDER); + FormData data = new FormData(); + data.top = new FormAttachment(0, 0); + data.left = new FormAttachment(0, 0); + data.right = new FormAttachment(sideComposite, 0, SWT.LEFT); + data.bottom = new FormAttachment(100,0); + this.parent.getRenderingComposite().setLayoutData(data); + GridLayout layout = new GridLayout(1,false); + layout.marginHeight = 1; + layout.marginWidth = 1; + sideComposite.setLayout(layout); + data = new FormData(); + data.top = new FormAttachment(0, 0); + data.bottom = new FormAttachment(100,0); + data.right = new FormAttachment(100,0); + sideComposite.setLayoutData(data); + + Button showCPButton = new Button(sideComposite,SWT.TOGGLE); + showCPButton.setText("Show CtrlPts"); + showCPButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + Button b = (Button)e.widget; + showControlPoints(b.getSelection()); + } + }); + + Button addCPButton = new Button(sideComposite,SWT.PUSH); + addCPButton.setText("Add CtrlPt"); + addCPButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + addControlPoint(); + } + }); + + Button removeCPButton = new Button(sideComposite,SWT.PUSH); + removeCPButton.setText("Remove CtrlPt"); + removeCPButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + + } + }); + + Button showPipesButton = new Button(sideComposite,SWT.TOGGLE); + showPipesButton.setText("Pipes"); + showPipesButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + Button b = (Button)e.widget; + showPipes(b.getSelection()); + } + }); + + + } + + @Override + public void disposeControl() { + sideComposite.dispose(); + } + + @Override + public void fillContextMenu(Graph graph, IMenuManager manager, + StructuredResourceSelection selection) { + + } + + @Override + public void fillLocalPullDown(IMenuManager manager) { + + } + + @Override + public void fillLocalToolBar(IToolBarManager manager) { + + } + + @Override + public Collection getActions() { + return actions; + } + + @Override + public String getName() { + return "Control Points"; + } + + List pipes = new ArrayList(); + List controlPoints = new ArrayList(); + + private void showPipes(boolean show) { + if (show) { + if (!pipes.isEmpty()) { + for (Node n : pipes) { + n.removeFromParent(); + n.dispose(); + } + pipes.clear(); + } + parent.getSession().asyncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + PipeControlPoint pcp = new PipeControlPoint(g,controlPointResource); + if (pcp.isInstanceOf(ProcessResource.plant3Dresource.EndComponentControlPoint)) { + Node n = new Node(); + TriMesh mesh = new TriMesh(); + Point3d p1 = new Point3d(-10.0,0.0,0.0); + Point3d p2 = new Point3d( 0.0,0.0,0.0); + PipeComponentProvider.createStraightGeometry(p1, p2, radius, new Geometry[]{mesh}); + n.attachChild(mesh); + parent.getRenderingComponent().getShadowRoot().attachChild(n); + pipes.add(n); + + } else if (pcp.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)) { + + double length = 0.5; + Double d = pcp.getAtMostOneRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength); + if (d != null) + length = d; + + double offset = 0.0; + d = pcp.getAtMostOneRelatedScalarDouble(ProcessResource.plant3Dresource.HasOffset); + if (d != null) + offset = d; + + double r = radius; + if (pcp.isInstanceOf(ProcessResource.plant3Dresource.SizeChangeControlPoint)) { + r = radius2; + } + + Node n = new Node(); + TriMesh mesh = new TriMesh(); + Point3d p1 = new Point3d(-10.0,0.0,0.0); + Point3d p2 = new Point3d( -length*0.5,0.0,0.0); + + PipeComponentProvider.createStraightGeometry(p1, p2, radius, new Geometry[]{mesh}); + n.attachChild(mesh); + parent.getRenderingComponent().getShadowRoot().attachChild(n); + pipes.add(n); + + n = new Node(); + mesh = new TriMesh(); + p1 = new Point3d(10.0,offset,0.0); + p2 = new Point3d(length*0.5,offset,0.0); + + PipeComponentProvider.createStraightGeometry(p1, p2, r, new Geometry[]{mesh}); + n.attachChild(mesh); + parent.getRenderingComponent().getShadowRoot().attachChild(n); + pipes.add(n); + + } else if (pcp.isInstanceOf(ProcessResource.plant3Dresource.InlineControlPoint)) { + double length = 0.5; + Double d = pcp.getAtMostOneRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength); + if (d != null) + length = d; + + Node n = new Node(); + TriMesh mesh = new TriMesh(); + Point3d p1 = new Point3d(-10.0,0.0,0.0); + Point3d p2 = new Point3d( -length*0.5,0.0,0.0); + + PipeComponentProvider.createStraightGeometry(p1, p2, radius, new Geometry[]{mesh}); + n.attachChild(mesh); + parent.getRenderingComponent().getShadowRoot().attachChild(n); + pipes.add(n); + + n = new Node(); + mesh = new TriMesh(); + p1 = new Point3d(10.0,0.0,0.0); + p2 = new Point3d(length*0.5,0.0,0.0); + + PipeComponentProvider.createStraightGeometry(p1, p2, radius, new Geometry[]{mesh}); + n.attachChild(mesh); + parent.getRenderingComponent().getShadowRoot().attachChild(n); + pipes.add(n); + } else if (pcp.isInstanceOf(ProcessResource.plant3Dresource.TurnControlPoint)) { + double length = 0.5; + Double d = pcp.getAtMostOneRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength); + if (d != null) + length = d; + + Node n = new Node(); + TriMesh mesh = new TriMesh(); + Point3d p1 = new Point3d(-10.0,0.0,0.0); + Point3d p2 = new Point3d( -length*0.5,0.0,0.0); + + PipeComponentProvider.createStraightGeometry(p1, p2, radius, new Geometry[]{mesh}); + n.attachChild(mesh); + parent.getRenderingComponent().getShadowRoot().attachChild(n); + pipes.add(n); + + n = new Node(); + mesh = new TriMesh(); + p1 = new Point3d(10.0,0.0,0.0); + p2 = new Point3d(length*0.5,0.0,0.0); + Quat4d q = new Quat4d(); + q.set(new AxisAngle4d(0.0,1.0,0.0,angle)); + MathTools.rotate(q, p1, p1); + MathTools.rotate(q, p2, p2); + + PipeComponentProvider.createStraightGeometry(p1, p2, radius, new Geometry[]{mesh}); + n.attachChild(mesh); + parent.getRenderingComponent().getShadowRoot().attachChild(n); + pipes.add(n); + } else if (pcp.isInstanceOf(ProcessResource.plant3Dresource.DirectedControlPoint)) { + Node n = new Node(); + TriMesh mesh = new TriMesh(); + Point3d p1 = new Point3d(10.0,0.0,0.0); + Point3d p2 = new Point3d( 0.0,0.0,0.0); + PipeComponentProvider.createStraightGeometry(p1, p2, radius, new Geometry[]{mesh}); + n.attachChild(mesh); + parent.getRenderingComponent().getShadowRoot().attachChild(n); + pipes.add(n); + } + + if(!pcp.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)) { + Collection subPoints = pcp.getSubPoint(); + + } + + parent.setViewChanged(true); + return GraphRequestStatus.transactionComplete(); + } + }); + } else { + if (!pipes.isEmpty()) { + for (Node n : pipes) { + n.removeFromParent(); + n.dispose(); + } + pipes.clear(); + parent.setViewChanged(true); + } + } + } + + private void showControlPoints(boolean show) { + if (show) { + if (!controlPoints.isEmpty()) { + for (Node n : controlPoints) { + n.removeFromParent(); + n.dispose(); + } + + } + parent.getSession().asyncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + + PipeControlPoint pcp = new PipeControlPoint(g,controlPointResource); + Vector3d p = G3DTools.getVector(pcp.getWorldPosition()); + Node n = new Node(); + Spatial sphere = new Sphere("",5,8,0.1f); + n.attachChild(sphere); + n.setLocalTranslation(VecmathJmeTools.get(p)); + MaterialState ms = parent.getRenderingComponent().getDisplaySystem().getRenderer().createMaterialState(); + ms.setDiffuse(new ColorRGBA(1.f,0.f,0.f,0.f)); + sphere.setRenderState(ms); + sphere.setName(Long.toString(pcp.getResource().getResourceId())); + parent.getRenderingComponent().getNoShadowRoot().attachChild(n); + controlPoints.add(n); + Collection subPoints = pcp.getSubPoint(); + ms = parent.getRenderingComponent().getDisplaySystem().getRenderer().createMaterialState(); + ms.setDiffuse(new ColorRGBA(0.f,1.f,0.f,0.f)); + for (PipeControlPoint cp : subPoints) { + p = G3DTools.getVector(cp.getWorldPosition()); + n = new Node(); + if (cp.isInstanceOf(ProcessResource.plant3Dresource.DirectedControlPoint)) { + sphere = getDCPMesh(); + if (sphere == null) + sphere = new Sphere("",5,8,0.1f); + } else { + sphere = new Sphere("",5,8,0.1f); + } + sphere.setName(Long.toString(cp.getResource().getResourceId())); + n.attachChild(sphere); + n.setLocalTranslation(VecmathJmeTools.get(p)); + sphere.setRenderState(ms); + parent.getRenderingComponent().getNoShadowRoot().attachChild(n); + controlPoints.add(n); + } + parent.setViewChanged(true); + return GraphRequestStatus.transactionComplete(); + } + }); + } else { + if (!controlPoints.isEmpty()) { + for (Node n : controlPoints) { + n.removeFromParent(); + n.dispose(); + } + parent.setViewChanged(true); + } + } + } + + @Override + public void initialize(Graph graph) { + Resource modelResource = parent.getInputResource(); + Resource inverse = graph.getInverse(ProcessResource.plant3Dresource.HasGraphics); + Collection equipment = graph.getObjects(modelResource, inverse); + if (equipment.size() != 1) + throw new RuntimeException("Cannot find component for model " + modelResource); + componentResource = equipment.iterator().next(); + Collection pcp = graph.getObjects(componentResource, ProcessResource.plant3Dresource.HasControlPoint); + if (pcp.size() != 1) + throw new RuntimeException("Cannot find control point for component " + componentResource); + controlPointResource = pcp.iterator().next(); + } + + @Override + public void dispose() { + + } + + @Override + public void run() { + + } + + private void addControlPoint() { + parent.getSession().asyncWrite(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + DirectedControlPoint dcp = DirectedControlPoint.createDefault(g); + PipeControlPoint pcp = new PipeControlPoint(g,controlPointResource); + pcp.addStatement(ProcessResource.plant3Dresource.HasSubPoint, dcp); + return GraphRequestStatus.transactionComplete(); + } + }); + } + + private Spatial getDCPMesh() { + try { + ObjToJme converter=new ObjToJme(); + String file = "data/dcp.obj"; + URL objFile=FileLocator.find(Activator.getDefault().getBundle(),new Path(file),null); + converter.setProperty("mtllib",objFile); + ByteArrayOutputStream BO=new ByteArrayOutputStream(); + //System.out.println("Starting to convert .obj to .jme"); + converter.convert(objFile.openStream(),BO); + + Savable s = BinaryImporter.getInstance().load(new ByteArrayInputStream(BO.toByteArray())); + return (Spatial)s; + } catch (Exception e) { + ErrorLogger.defaultLogError(e); + return null; + } + } + + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/tools/NozzleContribution.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/tools/NozzleContribution.java new file mode 100644 index 00000000..91f65baa --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/tools/NozzleContribution.java @@ -0,0 +1,129 @@ +package fi.vtt.simantics.processeditor.tools; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IContributionItem; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.IToolBarManager; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.layout.FormAttachment; +import org.eclipse.swt.layout.FormData; +import org.eclipse.swt.layout.FormLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Text; +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.proconf.g3d.actions.ContextAction; +import org.simantics.proconf.g3d.base.EditorContribution; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.common.StructuredResourceSelection; + +import fi.vtt.simantics.processeditor.ProcessResource; + +public class NozzleContribution implements EditorContribution { + private List actions = new ArrayList(); + private ThreeDimensionalEditorBase parent; + private Resource equipmentResource; + private Composite sideComposite; + + public NozzleContribution(ThreeDimensionalEditorBase parent) { + this.parent = parent; + } + + @Override + public void createControl(Composite parent) { + FormLayout flayout = new FormLayout(); + parent.setLayout(flayout); + sideComposite = new Composite(parent,SWT.BORDER); + FormData data = new FormData(); + data.top = new FormAttachment(0, 0); + data.left = new FormAttachment(0, 0); + data.right = new FormAttachment(sideComposite, 0, SWT.LEFT); + data.bottom = new FormAttachment(100,0); + this.parent.getRenderingComposite().setLayoutData(data); + sideComposite.setLayout(new FillLayout(SWT.VERTICAL)); + data = new FormData(); + data.top = new FormAttachment(0, 0); + data.bottom = new FormAttachment(100,0); + data.right = new FormAttachment(100,0); + sideComposite.setLayoutData(data); + showNozzles(true); + + Button addButton = new Button(sideComposite,SWT.PUSH); + addButton.setText("Add Nozzle"); + Label label = new Label(sideComposite,SWT.NONE); + label.setText("Restrictions:"); + Button minButton = new Button(sideComposite,SWT.CHECK); + minButton.setText("Min"); + Text minText = new Text(sideComposite,SWT.SINGLE | SWT.BORDER); + Button maxButton = new Button(sideComposite,SWT.CHECK); + maxButton.setText("Max"); + Text maxText = new Text(sideComposite,SWT.SINGLE | SWT.BORDER); + minText.setToolTipText("Enter minimum number of nozzles"); + maxText.setToolTipText("Enter maximum number of nozzles"); + + } + + @Override + public void disposeControl() { + sideComposite.dispose(); + + } + @Override + public void fillContextMenu(Graph graph, IMenuManager manager, + StructuredResourceSelection selection) { + + } + + @Override + public void fillLocalPullDown(IMenuManager manager) { + + } + + @Override + public void fillLocalToolBar(IToolBarManager manager) { + + } + + @Override + public Collection getActions() { + return actions; + } + + @Override + public String getName() { + return "Nozzles"; + } + + private void showNozzles(boolean show) { + + } + + @Override + public void initialize(Graph graph) { + Resource modelResource = parent.getInputResource(); + Resource inverse = graph.getInverse(ProcessResource.plant3Dresource.HasGraphics); + Collection equipment = graph.getObjects(modelResource, inverse); + if (equipment.size() != 1) + throw new RuntimeException("Cannot find equipment"); + equipmentResource = equipment.iterator().next(); + } + + @Override + public void dispose() { + showNozzles(false); + } + + @Override + public void run() { + + } + + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/tools/PlantEditContribution.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/tools/PlantEditContribution.java new file mode 100644 index 00000000..e411131b --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/tools/PlantEditContribution.java @@ -0,0 +1,330 @@ +package fi.vtt.simantics.processeditor.tools; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.IToolBarManager; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.FormAttachment; +import org.eclipse.swt.layout.FormData; +import org.eclipse.swt.layout.FormLayout; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Text; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Resource; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.proconf.g3d.actions.ContextAction; +import org.simantics.proconf.g3d.actions.FocusAction; +import org.simantics.proconf.g3d.actions.RemoveAction; +import org.simantics.proconf.g3d.actions.RotateAction; +import org.simantics.proconf.g3d.actions.TranslateAction; +import org.simantics.proconf.g3d.base.EditorContribution; +import org.simantics.proconf.g3d.common.StructuredResourceSelection; +import org.simantics.utils.ui.jface.MenuTools; + +import com.jme.intersection.CollisionData; +import com.jme.intersection.CollisionResults; +import com.jme.intersection.TriangleCollisionResults; +import com.jme.scene.Geometry; +import com.jme.scene.Node; +import com.jme.scene.Spatial; + +import fi.vtt.simantics.processeditor.Activator; +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.actions.InsertComponentAction; +import fi.vtt.simantics.processeditor.actions.InsertEquipmentAction; +import fi.vtt.simantics.processeditor.actions.InsertNozzleAction; +import fi.vtt.simantics.processeditor.actions.ReversePipelineAction; +import fi.vtt.simantics.processeditor.actions.RoutePipeAction; +import fi.vtt.simantics.processeditor.actions.TranslateElbowAction; +import fi.vtt.simantics.processeditor.actions.TranslateInlineComponentAction; +import fi.vtt.simantics.processeditor.actions.TranslateStraightAction; +import fi.vtt.simantics.processeditor.common.ControlPointTools; +import fi.vtt.simantics.processeditor.stubs.InlineComponent; +import fi.vtt.simantics.processeditor.stubs.PipeControlPoint; +import fi.vtt.simantics.processeditor.views.ProcessEditor; + +public class PlantEditContribution implements EditorContribution { + private List actions = new ArrayList(); + private ProcessEditor parent; + private Composite infoComposite; + private Text infoText; + + private Action checkInterferencesAction = null; + + public PlantEditContribution(ProcessEditor parent) { + this.parent = parent; + } + + @Override + public void createControl(Composite parent) { + FormLayout flayout = new FormLayout(); + parent.setLayout(flayout); + infoComposite = new Composite(parent, SWT.BORDER); + FormData data = new FormData(); + data.top = new FormAttachment(0, 0); + data.left = new FormAttachment(0, 0); + data.right = new FormAttachment(100, 0); + data.bottom = new FormAttachment(infoComposite, 0, SWT.TOP); + this.parent.getRenderingComposite().setLayoutData(data); + data = new FormData(); + data.left = new FormAttachment(0, 0); + data.right = new FormAttachment(100, 0); + data.bottom = new FormAttachment(100, 0); + data.height = 18; + infoComposite.setLayoutData(data); + GridLayout layout = new GridLayout(1,false); + layout.marginWidth = 1; + layout.marginHeight = 1; + infoComposite.setLayout(layout); + infoText = new Text(infoComposite, SWT.NONE); + GridData gdata = new GridData(); + gdata.grabExcessHorizontalSpace = true; + gdata.horizontalAlignment = SWT.FILL; + infoText.setLayoutData(gdata); + + } + + @Override + public void disposeControl() { + infoComposite.dispose(); + + } + + @Override + public void dispose() { + + } + + + + @Override + public void fillContextMenu(Graph graph, IMenuManager manager, + StructuredResourceSelection selection) { + + } + + @Override + public void fillLocalPullDown(IMenuManager manager) { + MenuTools.getOrCreate(parent.getMenuID(),"Advanced", manager).add(checkInterferencesAction); + + } + + @Override + public void fillLocalToolBar(IToolBarManager manager) { + + } + + @Override + public Collection getActions() { + return actions; + } + + @Override + public String getName() { + return "Plant Editing"; + } + + @Override + public void initialize(Graph graph) { + actions.add(new TranslateAction(parent){ + @Override + public boolean usable(Graph graph,List resources) { + if (super.usable(graph, resources)) { + for (Resource r : resources) { + // FIXME : use new ontology : + // 1. lose ends works like end components (just what this code does, but type checks are not correct) + // 2. connected components are moved inline. (TranslateInlineAction) + IEntity t = EntityFactory.create(graph, r); + if (t.isInstanceOf(ProcessResource.plant3Dresource.InlineComponent)) { + InlineComponent component = new InlineComponent(t); + PipeControlPoint pcp = component.getControlPoint(); + if (pcp.getNext() != null && pcp.getPrevious() != null) + return false; + } + } + return true; + } + return false; + } + + @Override + public void setInfoText(String text) { + infoText.setText(text); + } + }); + actions.add(new TranslateInlineComponentAction(parent) { + @Override + public void setInfoText(String text) { + infoText.setText(text); + } + }); + actions.add(new TranslateStraightAction(parent) { + @Override + public void setInfoText(String text) { + infoText.setText(text); + } + }); + actions.add(new TranslateElbowAction(parent) { + @Override + public void setInfoText(String text) { + infoText.setText(text); + } + }); + actions.add(new RotateAction(parent){ + @Override + public boolean usable(Graph graph,List resources) { + if (super.usable(graph,resources)) { + for (Resource r : resources) { + IEntity t = EntityFactory.create(graph,r); + // FIXME : use new ontology + // TODO : create rotate action that can rotate inline components + // TODO : ontology change: pipes and similar components cannot be rotated, since there is no point to do that. + if (t.isInstanceOf(ProcessResource.plant3Dresource.InlineComponent)) { + return false; + } + } + return true; + } + + return false; + } + + @Override + public void setInfoText(String text) { + infoText.setText(text); + } + }); + actions.add(new RemoveAction(parent) { + @Override + public GraphRequestStatus doChanges(Graph graph) { + Iterator i = parent.getSelectionAdapter().getCurrentSelection().iterator(); + while (i.hasNext()) { + Resource s = i.next(); + IEntity r = EntityFactory.create(graph, s); + if (r.isInstanceOf(ProcessResource.g3dResource.G3DNode)) { + Collection parentNode= r.getRelatedObjects(ProcessResource.g3dResource.HasParent); + if (parentNode.size() == 1) { + Collection rs = r.getRelatedObjects(ProcessResource.plant3Dresource.HasControlPoint); + for (IEntity cp : rs) { + ControlPointTools.removeControlPoint(new PipeControlPoint(cp)); + } + r.removeRelatedStatements(ProcessResource.g3dResource.HasParent); + } else { + if (parentNode.size() == 0) { + parent.showMessage("Object has no parent, don't know what to do!"); + } else { + parent.showMessage("Object has more than one parent, don't know what to do!"); + } + } + } + + } + //parent.getSelectionAdapter().setSelection(new StructuredResourceSelection()); + return GraphRequestStatus.transactionComplete(); + } + }); + actions.add(new FocusAction(parent)); + actions.add(new RoutePipeAction(parent){ + @Override + public void setInfoText(String text) { + infoText.setText(text); + } + }); + actions.add(new InsertComponentAction(parent)); + actions.add(new InsertEquipmentAction(parent)); + actions.add(new InsertNozzleAction(parent)); + actions.add(new ReversePipelineAction(parent)); + + checkInterferencesAction = new Action() { + public void run() { + CollisionResults results = new TriangleCollisionResults(); + //getRenderingComponent().getNormalRoot().calculateCollisions(getRenderingComponent().getNormalRoot(), results); + collide(parent.getRenderingComponent().getShadowRoot(),parent.getRenderingComponent().getShadowRoot(),results); + results = filterResults(results); + for (int i = 0; i < results.getNumber(); i++) { + CollisionData data = results.getCollisionData(i); + Geometry s = data.getSourceMesh(); + Geometry t = data.getTargetMesh(); + MessageDialog dialog = new MessageDialog(parent.getRenderingComposite().getShell(),"Interference " + i + " / " + results.getNumber(), null, "Interference between " + s + " and " + t,MessageDialog.WARNING,new String[]{"Next","Cancel"},0); + try { + Resource sid = parent.getScenegraphAdapter().getNodeResource(s.getName()); + Resource tid = parent.getScenegraphAdapter().getNodeResource(t.getName()); + + StructuredResourceSelection sel = new StructuredResourceSelection(); + if (sid == tid) { + sel.add(sid); + } else { + sel.add(sid); + sel.add(tid); + } + parent.getSelectionAdapter().setSelection(sel); + } catch(NumberFormatException e) { + + } + if (dialog.open() == 1) + break; + } + } + + private void collide(Spatial s, Spatial p, CollisionResults r) { + s.calculateCollisions(p, r); + if (s instanceof Node) { + Node n = (Node)s; + for (Spatial t : n.getChildren()) + collide(t,p,r); + } + } + + private CollisionResults filterResults(CollisionResults results) { + CollisionResults r = new TriangleCollisionResults(); + for (int i = 0; i < results.getNumber(); i++) { + CollisionData d = results.getCollisionData(i); + if (d.getSourceMesh() == d.getTargetMesh()) + continue; + boolean found = false; + for (int j = 0; j < r.getNumber(); j++) { + CollisionData d2 = r.getCollisionData(j); + if (d2.getSourceMesh() == d.getSourceMesh() && + d2.getTargetMesh() == d.getTargetMesh()) { + found = true; + break; + } + if (d2.getSourceMesh() == d.getTargetMesh() && + d2.getTargetMesh() == d.getSourceMesh()) { + found = true; + break; + } + } + if (!found) { + if (d.getSourceTris().size() == 0) + continue; + if (d.getTargetTris().size() == 0) + continue; + r.addCollisionData(d); + } + } + return r; + } + + }; + checkInterferencesAction.setText("Interferences"); + checkInterferencesAction.setImageDescriptor(Activator.imageDescriptorFromPlugin("fi.vtt.proconf.ode", "icons/silk/delete.png")); + + } + + @Override + public void run() { + + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/tools/PlantVisualizationContribution.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/tools/PlantVisualizationContribution.java new file mode 100644 index 00000000..42b93f0a --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/tools/PlantVisualizationContribution.java @@ -0,0 +1,376 @@ +package fi.vtt.simantics.processeditor.tools; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Stack; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.IToolBarManager; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.widgets.Composite; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Resource; +import org.simantics.proconf.g3d.actions.ContextAction; +import org.simantics.proconf.g3d.actions.FocusAction; +import org.simantics.proconf.g3d.animation.Animatable; +import org.simantics.proconf.g3d.animation.AnimationController; +import org.simantics.proconf.g3d.animation.AnimationSystem; +import org.simantics.proconf.g3d.animation.TestAnimationController; +import org.simantics.proconf.g3d.animation.ui.AnimationControlCreator; +import org.simantics.proconf.g3d.base.EditorContribution; +import org.simantics.proconf.g3d.common.StructuredResourceSelection; +import org.simantics.proconf.g3d.scenegraph.IGraphicsNode; +import org.simantics.proconf.g3d.stubs.G3DNode; +import org.simantics.utils.ui.jface.MenuTools; + +import fi.vtt.simantics.processeditor.Activator; +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.animations.PipeAnimationController; +import fi.vtt.simantics.processeditor.dialogs.ConfigureAnimationDialog; +import fi.vtt.simantics.processeditor.dialogs.ConfigureMonitorDialog; +import fi.vtt.simantics.processeditor.dialogs.ConfigurePipelineAnimationDialog; +import fi.vtt.simantics.processeditor.monitors.Monitor; +import fi.vtt.simantics.processeditor.monitors.ResourcePathPropertyProvider; +import fi.vtt.simantics.processeditor.monitors.TextMonitor; +import fi.vtt.simantics.processeditor.stubs.PipeRun; +import fi.vtt.simantics.processeditor.views.ProcessEditor; + +public class PlantVisualizationContribution implements EditorContribution { + private List actions = new ArrayList(); + private ProcessEditor parent; + + private AnimationSystem animationSystem = null; + private Action animatePipesAction = null; + private Action animateAction = null; + private Action showMonitorsAction = null; + private Action configureAnimationAction = null; + private Action configurePipelineAnimationAction = null; + private Action configureMonitorAction = null; + + private Monitor monitor; + + public PlantVisualizationContribution(ProcessEditor parent) { + this.parent = parent; + } + + @Override + public void createControl(Composite parent) { + parent.setLayout(new FillLayout()); + this.parent.getRenderingComposite().setLayoutData(null); + } + + @Override + public void disposeControl() { + + } + + @Override + public void dispose() { + + } + + @Override + public void fillContextMenu(Graph graph, IMenuManager manager, + StructuredResourceSelection selection) { + + } + + @Override + public void fillLocalPullDown(IMenuManager menuManager) { + MenuTools.getOrCreate(parent.getMenuID(),"Monitors", menuManager).add(showMonitorsAction); + MenuTools.getOrCreate(parent.getMenuID(),"Monitors", menuManager).add(configureMonitorAction); + IMenuManager animationMenu = MenuTools.getOrCreate(parent.getMenuID(),"Animations",menuManager); + animationMenu.add(configureAnimationAction); + animationMenu.add(configurePipelineAnimationAction); + MenuTools.getOrCreate(parent.getMenuID(),"Test", animationMenu).add(animateAction); + MenuTools.getOrCreate(parent.getMenuID(),"Test", animationMenu).add(animatePipesAction); + + } + +// @Override +// public void fillMainMenu(List list) { +// MenuTools.getOrCreate("Monitors", list).add(showMonitorsAction); +// MenuTools.getOrCreate("Monitors", list).add(configureMonitorAction); +// IMenuManager animationMenu = MenuTools.getOrCreate("Animations",list); +// animationMenu.add(configureAnimationAction); +// animationMenu.add(configurePipelineAnimationAction); +// MenuTools.getOrCreate("Test", animationMenu).add(animateAction); +// MenuTools.getOrCreate("Test", animationMenu).add(animatePipesAction); +// +// } + + @Override + public void fillLocalToolBar(IToolBarManager manager) { + AnimationControlCreator c = new AnimationControlCreator(getAnimationSystem()); + manager.add(c.createStopAction()); + manager.add(c.createPauseAction()); + manager.add(c.createPlayAction()); + manager.add(showMonitorsAction); + } + + @Override + public Collection getActions() { + return actions; + } + + @Override + public String getName() { + return "Plant Visualization"; + } + + @Override + public void run() { + parent.getSession().syncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + getAnimationSystem().run(g,0.01); + updateMonitor(g); + return GraphRequestStatus.transactionComplete(); + } + }); + + + } + + @Override + public void initialize(Graph graph) { + animateAction = new Action("", Action.AS_CHECK_BOX) { + public void run() { + if (this.isChecked()) { + parent.getSession().asyncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) + throws Exception { + AnimationController c = new TestAnimationController(); + Collection nodes = parent.getScenegraphAdapter().getNodes(); + for (IGraphicsNode node : nodes) { + if (node instanceof Animatable) { + Animatable a = (Animatable) node; + if (a.setRandomAnimation(g)) + c.addAnimatable(a); + } + } + animationSystem.add(c); + return GraphRequestStatus.transactionComplete(); + } + }); + +// showMessage("Activated " + animatables.size() +// + " animations"); + } else { + animationSystem.stop(); + } + } + }; + + animateAction.setText("Random animations"); + + animatePipesAction = new AnimatePipesAction("Pipe animations"); + + showMonitorsAction = new Action("Interactive Monitor", Action.AS_CHECK_BOX) { + public void run() { + showMonitors(this.isChecked()); + } + }; + showMonitorsAction.setImageDescriptor(Activator.imageDescriptorFromPlugin("fi.vtt.proconf.ode", "icons/silk/monitor.png")); + + + + configureAnimationAction = new Action() { + + public void run() { + parent.getSession().syncRead(new GraphRequestAdapter(){ + List list = new ArrayList(); + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + Stack stack = new Stack(); + stack.add(parent.getPlant(g).toG3DNode()); + while (!stack.isEmpty()) { + G3DNode n = stack.pop(); + list.add(n.getResource()); + for (G3DNode no : n.getChild()) + stack.push(no); + } + + if (list.size() == 0) + return GraphRequestStatus.transactionComplete(); + + ConfigureAnimationDialog dialog = new ConfigureAnimationDialog(parent.getRenderingComposite().getShell(),parent.getSession(),list,parent.getScenegraphAdapter(),getAnimationSystem()); + dialog.open(); + return GraphRequestStatus.transactionComplete(); + } + + }); + + } + + + }; + configureAnimationAction.setText("Configure animations"); + configureAnimationAction.setImageDescriptor(Activator.imageDescriptorFromPlugin("fi.vtt.proconf.ode", "icons/silk/film_edit.png")); + + configurePipelineAnimationAction = new Action() { + + public void run() { + parent.getSession().syncRead(new GraphRequestAdapter(){ + List list = new ArrayList(); + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + Stack stack = new Stack(); + stack.add(parent.getPlant(g).toG3DNode()); + while (!stack.isEmpty()) { + G3DNode n = stack.pop(); + if (n.isInstanceOf(ProcessResource.plant3Dresource.PipeRun)) + list.add(n.getResource()); + else //piperun will not contain other piperuns + for (G3DNode no : n.getChild()) + stack.push(no); + } + + if (list.size() == 0) + return GraphRequestStatus.transactionComplete(); + + ConfigurePipelineAnimationDialog dialog = new ConfigurePipelineAnimationDialog(parent.getRenderingComposite().getShell(),parent.getSession(),list,parent.getRenderingComponent(),getAnimationSystem()); + dialog.open(); + return GraphRequestStatus.transactionComplete(); + } + + }); + + } + + + }; + configurePipelineAnimationAction.setText("Configure pipeline animations"); + configurePipelineAnimationAction.setImageDescriptor(Activator.imageDescriptorFromPlugin("fi.vtt.proconf.ode", "icons/silk/film_edit.png")); + configureMonitorAction = new Action() { + + public void run() { + parent.getSession().syncRead(new GraphRequestAdapter(){ + List list = new ArrayList(); + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + Stack stack = new Stack(); + stack.add(parent.getPlant(g).toG3DNode()); + while (!stack.isEmpty()) { + G3DNode n = stack.pop(); + list.add(n.getResource()); + for (G3DNode no : n.getChild()) + stack.push(no); + } + + if (list.size() == 0) + return GraphRequestStatus.transactionComplete(); + + ConfigureMonitorDialog dialog = new ConfigureMonitorDialog(parent.getRenderingComposite().getShell(),parent.getSession(),list); + dialog.open(); + return GraphRequestStatus.transactionComplete(); + } + + }); + + } + }; + configureMonitorAction.setText("Configure monitor"); + configureMonitorAction.setImageDescriptor(Activator.imageDescriptorFromPlugin("fi.vtt.proconf.ode", "icons/silk/monitor_edit.png")); + + actions.add(new FocusAction(parent)); + } + + private AnimationSystem getAnimationSystem() { + if (animationSystem == null) { + animationSystem = new AnimationSystem(parent.getScenegraphAdapter()); + } + return animationSystem; + } + + protected void updateMonitor(Graph graph) { + if (showMonitorsAction.isChecked()) { + + List nodes = parent.getSelectionAdapter().getInteractiveSelectedObjects(); + if (nodes.size() > 0) { + IGraphicsNode selected = nodes.get(0); + if (monitor.acceptNode(graph,selected)) + monitor.setNode(graph,selected); + } + monitor.update(); + } + } + + protected Monitor createMonitor() { + Monitor m = new TextMonitor(parent); + m.setTextProvider(new ResourcePathPropertyProvider()); + return m; + } + + private void showMonitors(boolean show) { + if (show) { + if (monitor == null) { + monitor = createMonitor(); + } + final List nodes = parent.getSelectionAdapter().getInteractiveSelectedObjects(); + if (nodes.size() > 0) { + parent.getSession().asyncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + monitor.setNode(g,nodes.get(0)); + return GraphRequestStatus.transactionComplete(); + } + }); + + } + + } else if (!show && monitor != null) { + monitor.remove(); + parent.setViewChanged(true); + } + } + + private class AnimatePipesAction extends Action { + + public AnimatePipesAction(String text) { + super(text, Action.AS_CHECK_BOX); + + } + + public void run() { + if (this.isChecked()) { + parent.getSession().syncRead(new GraphRequestAdapter() { + List list = new ArrayList(); + + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + Stack stack = new Stack(); + stack.add(parent.getPlant(g).toG3DNode()); + while (!stack.isEmpty()) { + G3DNode n = stack.pop(); + if (n.isInstanceOf(ProcessResource.plant3Dresource.PipeRun)) + list.add(new PipeRun(n)); + else + //piperun will not contain other piperuns + for (G3DNode no : n.getChild()) + stack.push(no); + } + + for (PipeRun n : list) { + PipeAnimationController c = new PipeAnimationController(parent.getRenderingComponent(), n); + //animationSystem.add(c); + getAnimationSystem().add(c); + } + return GraphRequestStatus.transactionComplete(); + } + + }); + + } else { + //stopAnimations(); + getAnimationSystem().stop(); + } + } + + } +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/EquipmentEditorPart.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/EquipmentEditorPart.java new file mode 100644 index 00000000..07283dac --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/EquipmentEditorPart.java @@ -0,0 +1,46 @@ +package fi.vtt.simantics.processeditor.views; + +import java.util.Collection; + +import org.eclipse.swt.widgets.Display; +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.db.management.ISessionContext; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorPart; +import org.simantics.proconf.g3d.shapeeditor.views.ShapeEditorBase; + +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.tools.NozzleContribution; + +public class EquipmentEditorPart extends ThreeDimensionalEditorPart { + + @Override + protected ThreeDimensionalEditorBase createEditor(ISessionContext session) { + ShapeEditorBase base = new ShapeEditorBase(session); + base.addEditorContribution(new NozzleContribution(base)); + return base; + } + + @Override + public void reload(Graph g) { + Resource inputResource = getInputResource(); + Collection model = g.getObjects(inputResource, ProcessResource.plant3Dresource.HasGraphics); + if (model.size() != 1) + throw new RuntimeException("Cannot find model for equipment " + inputResource); + Resource modelResource = model.iterator().next(); + if (modelResource != null) { + editor.reload(g,modelResource); + } else { + + Display d = getSite().getShell().getDisplay(); + d.asyncExec(new Runnable() { + public void run() { + editor.showMessage("Failed to load model."); + getSite().getPage().closeEditor(EquipmentEditorPart.this,false); + } + }); + } + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/PipelineComponentEditorPart.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/PipelineComponentEditorPart.java new file mode 100644 index 00000000..e94d7d57 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/PipelineComponentEditorPart.java @@ -0,0 +1,46 @@ +package fi.vtt.simantics.processeditor.views; + +import java.util.Collection; + +import org.eclipse.swt.widgets.Display; +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.db.management.ISessionContext; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorPart; +import org.simantics.proconf.g3d.shapeeditor.views.ShapeEditorBase; + +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.tools.ControlPointContribution; + +public class PipelineComponentEditorPart extends ThreeDimensionalEditorPart { + + @Override + protected ThreeDimensionalEditorBase createEditor(ISessionContext session) { + ShapeEditorBase base = new ShapeEditorBase(session); + base.addEditorContribution(new ControlPointContribution(base)); + return base; + } + + @Override + public void reload(Graph g) { + Resource inputResource = getInputResource(); + Collection model = g.getObjects(inputResource, ProcessResource.plant3Dresource.HasGraphics); + if (model.size() != 1) + throw new RuntimeException("Cannot find model for pipeline component " + inputResource); + Resource modelResource = model.iterator().next(); + if (modelResource != null) { + editor.reload(g,modelResource); + } else { + + Display d = getSite().getShell().getDisplay(); + d.asyncExec(new Runnable() { + public void run() { + editor.showMessage("Failed to load model."); + getSite().getPage().closeEditor(PipelineComponentEditorPart.this,false); + } + }); + } + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/PlantStructureOutlinePage.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/PlantStructureOutlinePage.java new file mode 100644 index 00000000..0c7a356f --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/PlantStructureOutlinePage.java @@ -0,0 +1,27 @@ +package fi.vtt.simantics.processeditor.views; + +import org.eclipse.swt.widgets.Composite; +import org.simantics.db.Resource; +import org.simantics.db.management.ISessionContext; +import org.simantics.layer0.utils.viewpoints.ResourceViewpoint; +import org.simantics.proconf.browsing.views.GraphExplorerOutlinePage; + +import fi.vtt.simantics.processeditor.perspectives.ViewpointGenerator; + +public class PlantStructureOutlinePage extends GraphExplorerOutlinePage { + + + public PlantStructureOutlinePage(ISessionContext sessionContext, Resource inputResource) { + super(sessionContext, inputResource); + } + + @Override + public void createControl(Composite parent) { + super.createControl(parent); + } + + @Override + public ResourceViewpoint getViewPoint(ISessionContext sessionContext) { + return ViewpointGenerator.createObjectStructureViewpoint(); + } +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/PlantStructureView.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/PlantStructureView.java new file mode 100644 index 00000000..6685e36c --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/PlantStructureView.java @@ -0,0 +1,22 @@ +package fi.vtt.simantics.processeditor.views; + +import org.eclipse.swt.widgets.Composite; +import org.simantics.db.management.ISessionContext; +import org.simantics.layer0.utils.viewpoints.ResourceViewpoint; +import org.simantics.proconf.browsing.GraphExplorer; +import org.simantics.proconf.browsing.views.GraphExplorerView; + +import fi.vtt.simantics.processeditor.perspectives.ViewpointGenerator; + +public class PlantStructureView extends GraphExplorerView { + + @Override + protected GraphExplorer createExplorer(Composite parent) { + return super.createExplorer(parent); + } + + @Override + protected ResourceViewpoint getViewpoint(ISessionContext context) { + return ViewpointGenerator.createViewpoint(); + } +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/ProcessEditor.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/ProcessEditor.java new file mode 100644 index 00000000..5aae5881 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/ProcessEditor.java @@ -0,0 +1,704 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.views; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.KeyEvent; +import org.eclipse.swt.events.KeyListener; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.views.contentoutline.IContentOutlinePage; +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.db.Session; +import org.simantics.db.management.ISessionContext; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.layer0.utils.Property; +import org.simantics.proconf.g3d.base.JmeRenderingComponent; +import org.simantics.proconf.g3d.base.ScenegraphAdapter; +import org.simantics.proconf.g3d.base.ScenegraphAdapterImpl; +import org.simantics.proconf.g3d.base.SelectionAdapter; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.common.StructuredResourceSelection; +import org.simantics.proconf.g3d.scenegraph.IGeometryNode; +import org.simantics.proconf.g3d.scenegraph.IGraphicsNode; +import org.simantics.proconf.g3d.scenegraph.ISelectableNode; +import org.simantics.proconf.g3d.scenegraph.ParameterizedModelNode; +import org.simantics.proconf.g3d.shapes.FloorShape; +import org.simantics.proconf.g3d.stubs.G3DNode; +import org.simantics.utils.ErrorLogger; +import org.simantics.utils.ui.jface.MenuTools; + +import com.jme.math.Vector3f; +import com.jme.scene.Geometry; + +import fi.vtt.simantics.processeditor.Activator; +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.actions.InsertComponentAction; +import fi.vtt.simantics.processeditor.actions.InsertEquipmentAction; +import fi.vtt.simantics.processeditor.actions.InsertNozzleAction; +import fi.vtt.simantics.processeditor.actions.RoutePipeAction; +import fi.vtt.simantics.processeditor.common.ControlPointTools; +import fi.vtt.simantics.processeditor.common.PipingRules; +import fi.vtt.simantics.processeditor.scenegraph.NonVisibleNode; +import fi.vtt.simantics.processeditor.scenegraph.PipelineComponentNode; +import fi.vtt.simantics.processeditor.scenegraph.PipeComponentNode; +import fi.vtt.simantics.processeditor.scenegraph.PipeRunNode; +import fi.vtt.simantics.processeditor.stubs.PipeControlPoint; +import fi.vtt.simantics.processeditor.stubs.PipeRun; +import fi.vtt.simantics.processeditor.stubs.Plant; +import fi.vtt.simantics.processeditor.stubs.Plant3DResource; +import fi.vtt.simantics.processeditor.tools.PlantEditContribution; +import fi.vtt.simantics.processeditor.tools.PlantVisualizationContribution; + +public class ProcessEditor extends ThreeDimensionalEditorBase { + + private Resource plantResource = null; + + //private List animationControllers = new ArrayList(); + + private Action configureFloorAction = null; + + private Geometry floorShape = null; + + public ProcessEditor(ISessionContext session) { + super(session); + addEditorContribution(new PlantEditContribution(this)); + addEditorContribution(new PlantVisualizationContribution(this)); + } + + public ProcessEditor(ISessionContext session,JmeRenderingComponent component) { + super(session,component); + addEditorContribution(new PlantEditContribution(this)); + addEditorContribution(new PlantVisualizationContribution(this)); + } + + @Override + protected ScenegraphAdapter createScenegraphAdapter() { + return new ProcessEditorAdapter(session,getRenderingComponent()); + } + + @Override + public void createControl(Graph graph,Composite parent) { + super.createControl(graph,parent); + + floorShape = FloorShape.getShape(getRenderingComponent().getDisplaySystem().getRenderer(), 100.f,0.2f); + getRenderingComponent().getNoCastRoot().attachChild(floorShape); + floorShape.setLocalTranslation(new Vector3f(0.f,-0.01f,0.f)); + } + + @Override + protected void makeActions(Graph graph) { + super.makeActions(graph); + + //actions.add(new ShowTrendsAction(this)); + + configureFloorAction = new Action() { + public void run() { + FloorConfigureDialog dialog = new FloorConfigureDialog(ProcessEditor.this.parent.getShell()); + if (dialog.open() == FloorConfigureDialog.CANCEL) + return; + if (dialog.isFloorEnabled()) { + if (floorShape.getParent() == null) + getRenderingComponent().getNoCastRoot().attachChild(floorShape); + } else { + floorShape.removeFromParent(); + } + floorShape.setLocalTranslation(new Vector3f(0.f,(float)dialog.getFloorHeight(),0.f)); + + } + }; + configureFloorAction.setText("Configure floor"); + configureFloorAction.setImageDescriptor(Activator.imageDescriptorFromPlugin("fi.vtt.proconf.ode", "icons/silk/shape_align_bottom.png")); + +// ContextActionFactory extended[] = ContextActionRegistry.getActions("fi.vtt.proconf.shapeeditor.processeditorview"); +// for (ContextActionFactory c : extended) { +// actions.add(c.createAction(this)); +// } + } + +// protected void stopAnimations() { +// animationSystem.stop(); +// } + + protected void fillLocalPullDown() { + super.fillLocalPullDown(); + MenuTools.getOrCreate(getMenuID(),"Advanced", menuManager).add(configureFloorAction); + } + + protected class ProcessEditorAdapter extends ScenegraphAdapterImpl { + + public ProcessEditorAdapter(Session session, JmeRenderingComponent component) { + super(session, component); + } + + private class NormalScengraphQuery extends ScenegraphQuery { + + public NormalScengraphQuery(Resource node) { + super(node); + } + + + @Override + public void shapeAdded(Graph graph, IGraphicsNode node) { + // FIXME : this won't work like in previous ProConf + } + } + + private Map pipeRunQueries = new HashMap(); + + protected ScenegraphQuery newSubnodeListener(G3DNode node) { + if (node.isInstanceOf(ProcessResource.plant3Dresource.PipeRun)) { + PipeRunControlPointQuery query = new PipeRunControlPointQuery(node.getResource()); + pipeRunQueries.put(node.getResource(), query); + node.getGraph().performQuery(query); +// return new SubnodeListener(node) { +// @Override +// public void shapeAdded(IGraphicsNode node) { +// if (node instanceof IGeometryNode) { +// updateGeometry((IGeometryNode)node); +// +// } +// node.setVisible(true); +// } +// }; + } + return new NormalScengraphQuery(node.getResource()); + + } + + @Override + protected NodePropertyQuery newRootPropertyListener(G3DNode root) { + // currently Plant does not have any properties. + return null; + } + + private class TransformationQuery extends NodeTransformationQuery { + + public TransformationQuery(Resource res) { + super(res); + } + + @Override + public void shapeUpdated(Graph graph, IGraphicsNode shape) { + //if (shape instanceof IGeometryNode) { + // updateGeometry((IGeometryNode)shape); + //} else { + shape.updateTransform(graph); + //} + } + } + + @Override + protected NodeTransformationQuery newTransformationListener(G3DNode root) { + return new TransformationQuery(root.getResource()); + } + + private class NormalNodePropertyQuery extends org.simantics.proconf.g3d.base.ScenegraphAdapterImpl.NodePropertyQuery { + + public NormalNodePropertyQuery(Resource resource) { + super(resource); + } + + @Override + public void shapeUpdated(Graph graph,IGraphicsNode shape) { + if (shape instanceof IGeometryNode) { + updateGeometry((IGeometryNode)shape); + } else { + shape.updateTransform(graph); + } + } + } + @Override + protected NodePropertyQuery newPropertyListener(G3DNode node) { + return new NormalNodePropertyQuery(node.getResource()); + } + + @Override + protected IGraphicsNode instantiateNode(IGraphicsNode parent, + G3DNode node) { + Plant3DResource p3r = ProcessResource.plant3Dresource; + IGraphicsNode newNode = null; + try { + if (node.isInstanceOf(p3r.Equipment)) { + newNode = new ParameterizedModelNode( + ProcessEditor.this, parent, node.getGraph(), + node.getResource(), p3r.HasGraphics); + } else if (node.isInstanceOf(p3r.PipeRun)) { + newNode = new PipeRunNode(parent, node.getGraph(), node.getResource()); + } else if (node.isInstanceOf(p3r.Nozzle)) { + newNode = new ParameterizedModelNode( + ProcessEditor.this, parent, node.getGraph(), + node.getResource(), p3r.HasGraphics); + // CodedComponent must be handled first since it uses + // hard-coded geometries + // TODO : is this really necessary, or could we unify + // PipeComponentNode, InlineComponentNode,... + } else if (node.isInstanceOf(p3r.CodedComponent)) { + newNode = new PipeComponentNode(ProcessEditor.this, + parent, node.getGraph(), node.getResource()); + } else if (node.isInstanceOf(p3r.NonVisibleComponent)) { + newNode = new NonVisibleNode(parent, node.getGraph(), node.getResource()); + } else if (node.isInstanceOf(p3r.PipelineComponent)) { + newNode = new PipelineComponentNode(ProcessEditor.this, + parent, node.getGraph(), node.getResource()); + } + + // } else if (node instanceof Shape) // Markers (ar/mobile) + // needed this + // newNode = new ShapeNode(TestProcessEditor.this,parent,node); + if (newNode != null) { + if (newNode instanceof ISelectableNode) + ((ISelectableNode) newNode).setVisible(true); + if (newNode instanceof IGeometryNode) { + updateGeometry((IGeometryNode) newNode); + } + return newNode; + } + } catch (Exception e) { + ErrorLogger.defaultLogError("Cannot handle node " + node.getResource(), e); + return null; + } + ErrorLogger.defaultLogError("Cannot handle node " + node.getResource(), null); + return null; + + } + + /** + * This is used to create elbows and straight pipes to pipeline TODO : + * this should be done with rule-engine! + * + * + * @author Marko Luukkainen + * + */ + protected class PipeRunControlPointQuery extends NodeQuery { + private List removed = new ArrayList(); + private List added = new ArrayList(); + + public PipeRunControlPointQuery(Resource r) { + super(r); + if (DEBUG) System.out.println("Created PipeRunControlPointQuery for " + r); + + } + + @Override + protected Object compute2(Graph graph) { + PipeRun run = new PipeRun(graph, nodeResource); + Collection cps = run + .getRelatedObjects(ProcessResource.plant3Dresource.HasControlPoints); + List res = new ArrayList(); + for (IEntity t : cps) + res.add(t.getResource()); + return res; + } + + @Override + public boolean updated(Graph graph, Object oldResult, + Object newResult) { + + removed.clear(); + added.clear(); + + List oldCps = (List) oldResult; + List newCps = (List) newResult; + if (oldCps == null) + oldCps = new ArrayList(); + + for (Resource r : oldCps) { + if (!newCps.contains(r)) + removed.add(r); + } + + for (Resource r : newCps) { + if (!oldCps.contains(r)) + added.add(r); + } + for (Resource r : removed) + removeControlPoint(graph, r); + for (Resource r : added) { + addControlPoint(graph, r); + // ControlPointTools.addControlPoint(new + // PipeRun(graph,pipeRun), new PipeControlPoint(graph, r)); + } + + return (added.size() > 0 || removed.size() > 0); + } + + @Override + public void dispose() { + super.dispose(); + for (ControlPointPropertyQuery q : controlPointPropertyQueries.values()) + q.dispose(); + controlPointPropertyQueries.clear(); + } + + private Map controlPointPropertyQueries = new HashMap(); + + private void addControlPoint(Graph graph, Resource resource) { + ControlPointPropertyQuery query = new ControlPointPropertyQuery(resource); + graph.performQuery(query); + controlPointPropertyQueries.put(resource,query); + } + + private void removeControlPoint(Graph graph, Resource resource) { + ControlPointPropertyQuery query = controlPointPropertyQueries.remove(resource); + query.dispose(); + ControlPointTools.removeControlPoint(new PipeControlPoint( + graph, resource)); + } + + } + + protected class ControlPointPropertyQuery extends NodeQuery { + boolean initialized = false; + + public ControlPointPropertyQuery(Resource r) { + super(r); + if (DEBUG) System.out.println("Created ControlPointPropertyQuery for " + r); + } + + @Override + public List compute2(Graph g) { + IEntity t = EntityFactory.create(g,nodeResource); + + Collection properties = t.getRelatedProperties(ProcessResource.builtins.HasProperty); + List propertyValues = new ArrayList(); + p(properties,propertyValues); + + return propertyValues; + } + + private void p(Collection properties, List propertyValues) { + for (Property p : properties) { + Collection subProperties = p.getRelatedProperties(p.getGraph().getBuiltins().HasProperty); + if (subProperties.size() != 0) { + p(subProperties,propertyValues); + } + if (p.hasValue()){ + propertyValues.add(p.getValue()); + } + } + } + + @Override + public boolean updated(Graph graph, Object oldResult, Object newResult) { + PipingRules.pipeControlPointPositionUpdate(graph, this.nodeResource); + if (initialized) { + //PipingRules.pipeControlPointPositionUpdate(graph, this.nodeResource); + } else { + initialized = true; + } + return true; + } + } + + @Override + protected void removeNode(Resource parent, Resource r) { + super.removeNode(parent, r); + PipeRunControlPointQuery q = pipeRunQueries.get(r); + if (q != null) + q.dispose(); + } + + @Override + public void dispose() { + super.dispose(); + } + } + + @Override + protected void pageSelectionChanged(IWorkbenchPart part, ISelection selection) { + if (!(selection instanceof StructuredResourceSelection)) { + return; + } + + StructuredResourceSelection s = (StructuredResourceSelection) selection; + selectionAdapter.setCurrentSelection(s); + viewChanged = true; + + //if (s.getRootSelection() == null) { + if (!(part instanceof ProcessEditor)) { + //System.out.println("ShapeEditorView.pageSelectionChanged() no root selection"); + ((ProcessEditorSelectionAdapter)selectionAdapter).setEditorSelection(true); + return; + } + //if (!s.getRootSelection().getResource().getId().equals(plant.getResource().getId())) { + ProcessEditor sender = (ProcessEditor)part; + if (!sender.getPlantResource().equals(plantResource)) { +// System.out.println("ShapeEditorView.pageSelectionChanged() not right group " +// + s.getRootSelection().getResource().getId() + " != " + model.getResource().getId()); + selectionAdapter.setCurrentSelection(new StructuredResourceSelection()); + ((ProcessEditorSelectionAdapter)selectionAdapter).setEditorSelection(false); + return; + } + selectionAdapter.setEditorSelection(); + + } + + @Override + protected void reloadFrom(IEntity thing) { + if (plantResource != null) { + throw new UnsupportedOperationException("Reloading instantiated viewer not supported"); + } + if (thing.isInstanceOf(ProcessResource.plant3Dresource.Plant)) { + plantResource = thing.getResource(); + G3DNode plant = new G3DNode(thing); + adapter.setRootNode(plant); + //adapter.addOutbound(plant); + ControlPointTools.reloadCache(thing.getGraph(),plant.getResource()); + } else { + throw new IllegalArgumentException("Resource is not a plant"); + } + } + + public Resource getPlantResource() { + return plantResource; + } + + public Plant getPlant(Graph g) { + return new Plant(g, plantResource); + } + + @Override + protected SelectionAdapter createSelectionAdapter() { + return new ProcessEditorSelectionAdapter(adapter); + } + + protected class ProcessEditorSelectionAdapter extends SelectionAdapter { + + + public ProcessEditorSelectionAdapter(ScenegraphAdapter adapter) { + super(adapter); + // TODO Auto-generated constructor stub + } + + @Override + protected StructuredResourceSelection filterSelection(ISelection s) { + if (!(s instanceof StructuredResourceSelection)) + return new StructuredResourceSelection(); + return (StructuredResourceSelection)s; + } + + @Override + public void setEditorSelection() { + List sel = getSelectedObjects(); + for (IGraphicsNode o : adapter.getNodes()) + if (o instanceof ISelectableNode) { + if (sel.contains(o)) { + ((ISelectableNode)o).setSelected(true); + } else { + ((ISelectableNode)o).setSelected(false); + } + } + List selected = getSelectedResources(); + // TODO : don't know why this code is here, but it seems unnecessary +// for (Resource r : selected) { +// if (!adapter.hasNode(r)) { +// // instantiating a new resource : usin this editor's tc +// Resource resource = graph.getResource(r.getId()); +// adapter.addInbound(resource).setSelected(true); +// +// } +// } + + } + + public void setEditorSelection(boolean addShapes) { + + List sel = getSelectedObjects(); + for (IGraphicsNode o : adapter.getNodes()) + if (o instanceof ISelectableNode) { + if (sel.contains(o)) { + ((ISelectableNode)o).setSelected(true); + } else { + ((ISelectableNode)o).setSelected(false); + } + } + if (addShapes) { + // TODO : don't know why this code is here, but it seems unnecessary +// List selected = getSelectedResources(); +// for (Resource r : selected) { +// if (!adapter.hasNode(r)) { +// if (r.isInstanceOf(GlobalIdMap.get(PSK3DModelingOntologyMapping.EQUIPMENT))) { +// Resource group = GraphicsNodeTools.getModelFromResource(r); +// if (group != null && group.getId() == plant.getResource().getId()) { +//// instantiating a new resource : usin this editor's tc +// Resource resource = graph.getResource(r.getId()); +// adapter.addInbound(resource).setSelected(true); +// } +// +// } +// } +// } + } + } + + @Override + protected void setEditorHighlightSelection() { + List sel = getInteractiveSelectedObjects(); + for (IGraphicsNode o : adapter.getNodes()) + if (o instanceof ISelectableNode) { + if (sel.contains(o)) { + ((ISelectableNode)o).setHighlighted(true); + } else { + ((ISelectableNode)o).setHighlighted(false); + } + } + } + } + + private class FloorConfigureDialog extends Dialog implements KeyListener,SelectionListener { + + private boolean floorEnabled = true; + private double floorHeight = 0.0; + + private Text floorHeightText = null; + private Button floorEnabledButton = null; + + public FloorConfigureDialog(Shell shell) { + super(shell); + } + + @Override + protected Control createDialogArea(Composite parent) { + Composite composite = (Composite) super.createDialogArea(parent); + Label label = new Label(composite, SWT.WRAP); + label.setText("Configure floor"); + GridData data = new GridData(GridData.GRAB_HORIZONTAL + | GridData.GRAB_VERTICAL | GridData.HORIZONTAL_ALIGN_FILL + | GridData.VERTICAL_ALIGN_CENTER); + + data.widthHint = convertHorizontalDLUsToPixels(IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH); + label.setLayoutData(data); + label.setFont(parent.getFont()); + floorEnabledButton = new Button(composite,SWT.CHECK); + floorEnabledButton.setText("Enabled"); + label = new Label(composite, SWT.WRAP); + label.setText("Height"); + label.setLayoutData(data); + label.setFont(parent.getFont()); + floorHeightText = new Text(composite,SWT.NONE); + + + floorHeightText.addKeyListener(this); + floorEnabledButton.addSelectionListener(this); + floorEnabledButton.setSelection(floorEnabled); + floorHeightText.setText(Double.toString(floorHeight)); + + return composite; + } + + @Override + protected void configureShell(Shell newShell) { + super.configureShell(newShell); + newShell.setText("Configure floor"); + } + + public void keyPressed(KeyEvent e) { + + } + + public void keyReleased(KeyEvent e) { + boolean ok = true; + try { + floorHeight = Double.parseDouble(floorHeightText.getText()); + } catch (NumberFormatException err) { + ok = false; + } + if (ok) { + this.getButton(IDialogConstants.OK_ID).setEnabled(true); + } else { + this.getButton(IDialogConstants.OK_ID).setEnabled(false); + } + } + + public void widgetDefaultSelected(SelectionEvent e) { + + } + + public void widgetSelected(SelectionEvent e) { + floorEnabled = floorEnabledButton.getSelection(); + } + + public boolean isFloorEnabled() { + return floorEnabled; + } + + public double getFloorHeight() { + return floorHeight; + } + + } + + @Override + protected void hookDragAndDrop() { + super.hookDragAndDrop(); + dropTarget.addDropListener(new InsertEquipmentAction(this)); + dropTarget.addDropListener(new InsertNozzleAction(this)); + dropTarget.addDropListener(new InsertComponentAction(this)); + dropTarget.addDropListener(new RoutePipeAction(this)); + } + + @Override + public Object getAdapter(Class adapter) { + if (adapter == IContentOutlinePage.class) { + if (getPlantResource() == null) + return null; + final PlantStructureOutlinePage page = new PlantStructureOutlinePage(sessionContext,getPlantResource()); + + getSelectionAdapter().addSelectionChangedListener(new ISelectionChangedListener() { + @Override + public void selectionChanged(SelectionChangedEvent event) { + page.setSelection(event.getSelection()); + + } + }); + parent.getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + page.addSelectionChangedListener(new ISelectionChangedListener() { + @Override + public void selectionChanged(SelectionChangedEvent event) { + selectionAdapter.setSelection(SelectionAdapter.transformSelection(event.getSelection())); + } + }); + } + }); + + + + return page; + } + return null; + } +} \ No newline at end of file diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/ProcessEditorPart.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/ProcessEditorPart.java new file mode 100644 index 00000000..a83f40b5 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/ProcessEditorPart.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.views; + +import org.simantics.db.management.ISessionContext; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorPart; + + +public class ProcessEditorPart extends ThreeDimensionalEditorPart { + + @Override + protected ThreeDimensionalEditorBase createEditor(ISessionContext session) { + return new ProcessEditor(session); + } + +}