]> gerrit.simantics Code Review - simantics/3d.git/blob - org.simantics.proconf.processeditor/src/org/simantics/processeditor/actions/RoutePipeAction.java
7089ca25a8590031813a6375cf77a436b6dc893a
[simantics/3d.git] / org.simantics.proconf.processeditor / src / org / simantics / processeditor / actions / RoutePipeAction.java
1 /*******************************************************************************\r
2  * Copyright (c) 2007 VTT Technical Research Centre of Finland and others.\r
3  * All rights reserved. This program and the accompanying materials\r
4  * are made available under the terms of the Eclipse Public License v1.0\r
5  * which accompanies this distribution, and is available at\r
6  * http://www.eclipse.org/legal/epl-v10.html\r
7  *\r
8  * Contributors:\r
9  *     VTT Technical Research Centre of Finland - initial API and implementation\r
10  *******************************************************************************/\r
11 package org.simantics.processeditor.actions;\r
12 \r
13 import java.awt.event.KeyEvent;\r
14 import java.awt.event.MouseEvent;\r
15 import java.math.BigDecimal;\r
16 import java.util.ArrayList;\r
17 import java.util.List;\r
18 \r
19 import javax.vecmath.Point3d;\r
20 import javax.vecmath.Vector3d;\r
21 \r
22 import org.eclipse.jface.action.Action;\r
23 import org.eclipse.jface.action.IToolBarManager;\r
24 import org.eclipse.jface.resource.ImageDescriptor;\r
25 import org.simantics.db.Graph;\r
26 import org.simantics.db.GraphRequestAdapter;\r
27 import org.simantics.db.GraphRequestStatus;\r
28 import org.simantics.db.GraphRequestWithResult;\r
29 import org.simantics.db.Resource;\r
30 import org.simantics.layer0.utils.EntityFactory;\r
31 import org.simantics.layer0.utils.IEntity;\r
32 import org.simantics.processeditor.Activator;\r
33 import org.simantics.processeditor.ProcessResource;\r
34 import org.simantics.processeditor.common.ControlPointTools;\r
35 import org.simantics.processeditor.common.PipeComponentProvider;\r
36 import org.simantics.processeditor.common.PipingTools2;\r
37 import org.simantics.processeditor.common.PipingTools2.Direction;\r
38 import org.simantics.processeditor.dialogs.PipelineDialog;\r
39 import org.simantics.processeditor.gizmo.PositionSelectionGizmo;\r
40 import org.simantics.processeditor.stubs.BranchEndControlPoint;\r
41 import org.simantics.processeditor.stubs.PipeControlPoint;\r
42 import org.simantics.processeditor.stubs.PipeRun;\r
43 import org.simantics.processeditor.stubs.PipelineComponent;\r
44 import org.simantics.processeditor.stubs.VariableLengthInlineComponent;\r
45 import org.simantics.processeditor.views.ProcessEditor;\r
46 import org.simantics.proconf.g3d.actions.InteractiveAction;\r
47 import org.simantics.proconf.g3d.base.ConstraintDetector;\r
48 import org.simantics.proconf.g3d.base.G3DAPI;\r
49 import org.simantics.proconf.g3d.base.G3DTools;\r
50 import org.simantics.proconf.g3d.base.MathTools;\r
51 import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase;\r
52 import org.simantics.proconf.g3d.common.StructuredResourceSelection;\r
53 import org.simantics.proconf.g3d.dnd.DropListener;\r
54 import org.simantics.proconf.g3d.scenegraph.IGraphicsNode;\r
55 import org.simantics.utils.datastructures.Pair;\r
56 \r
57 import com.jme.renderer.ColorRGBA;\r
58 import com.jme.scene.Geometry;\r
59 import com.jme.scene.Line;\r
60 import com.jme.scene.state.MaterialState;\r
61 \r
62 \r
63 /**\r
64  * Action for Routing Pipes\r
65  * \r
66  * FIXME : does several thing that should be done by PipingTools.\r
67  * TODO : instead of using lines to show route of pipe, generate pipe and change it real-time\r
68  * \r
69  * @author MLMARKO\r
70  *\r
71  */\r
72 public class RoutePipeAction extends InteractiveAction implements DropListener, SplitPointListener {\r
73         \r
74         \r
75         private static final ImageDescriptor X_AXIS_ICON = Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/x-axis.png");\r
76         private static final ImageDescriptor Y_AXIS_ICON = Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/y-axis.png");\r
77         private static final ImageDescriptor Z_AXIS_ICON = Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/z-axis.png");\r
78         private static final ImageDescriptor X_PLANE_ICON = Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/x-plane.png");\r
79         private static final ImageDescriptor Y_PLANE_ICON = Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/y-plane.png");\r
80         private static final ImageDescriptor Z_PLANE_ICON = Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/z-plane.png");\r
81     \r
82         private static final ImageDescriptor CAMERA_ICON = Activator.imageDescriptorFromPlugin("org.simantics.proconf.g3d", "icons/eye.png");\r
83     \r
84         \r
85         private Action xAxisAction;\r
86         private Action yAxisAction;\r
87         private Action zAxisAction;\r
88         private Action xPlaneAction;\r
89         private Action yPlaneAction;\r
90         private Action zPlaneAction;\r
91         \r
92         private Action cameraAction;\r
93         \r
94     ConstraintDetector detector = null;\r
95     \r
96     public RoutePipeAction(ThreeDimensionalEditorBase parent) {\r
97         super(parent);\r
98         detector = new ConstraintDetector(parent);\r
99         xAxisAction = new Action("X",Action.AS_RADIO_BUTTON) {\r
100                 public void run() {\r
101                         if (lock == LockType.X)\r
102                                 setLockType(LockType.NONE,false);\r
103                         else\r
104                                 setLockType(LockType.X,false);\r
105                 }\r
106         };\r
107         xAxisAction.setImageDescriptor(X_AXIS_ICON);\r
108         xAxisAction.setToolTipText("Lock X-Axis");\r
109         yAxisAction = new Action("Y",Action.AS_RADIO_BUTTON) {\r
110                 public void run() {\r
111                         if (lock == LockType.Y)\r
112                                 setLockType(LockType.NONE,false);\r
113                         else\r
114                                 setLockType(LockType.Y,false);\r
115                 }\r
116         };\r
117         yAxisAction.setImageDescriptor(Y_AXIS_ICON);\r
118         yAxisAction.setToolTipText("Lock Y-Axis");\r
119         zAxisAction = new Action("Z",Action.AS_RADIO_BUTTON) {\r
120                 public void run() {\r
121                         if (lock == LockType.Z)\r
122                                 setLockType(LockType.NONE,false);\r
123                         else\r
124                                 setLockType(LockType.Z,false);\r
125                 }\r
126         };\r
127         zAxisAction.setImageDescriptor(Z_AXIS_ICON);\r
128         zAxisAction.setToolTipText("Lock Z-Axis");\r
129         xPlaneAction = new Action("X",Action.AS_RADIO_BUTTON) {\r
130                 public void run() {\r
131                         if (lock == LockType.YZ)\r
132                                 setLockType(LockType.NONE,false);\r
133                         else\r
134                                 setLockType(LockType.YZ,false);\r
135                 }\r
136         };\r
137         xPlaneAction.setImageDescriptor(X_PLANE_ICON);\r
138         xPlaneAction.setToolTipText("Lock X-Plane");\r
139         yPlaneAction = new Action("Y",Action.AS_RADIO_BUTTON) {\r
140                 public void run() {\r
141                         if (lock == LockType.XZ)\r
142                                 setLockType(LockType.NONE,false);\r
143                         else\r
144                                 setLockType(LockType.XZ,false);\r
145                 }\r
146         };\r
147         yPlaneAction.setImageDescriptor(Y_PLANE_ICON);\r
148         yPlaneAction.setToolTipText("Lock Y-Plane");\r
149         zPlaneAction = new Action("Z",Action.AS_RADIO_BUTTON) {\r
150                 public void run() {\r
151                         if (lock == LockType.XY)\r
152                                 setLockType(LockType.NONE,false);\r
153                         else\r
154                                 setLockType(LockType.XY,false);\r
155                 }\r
156         };\r
157         zPlaneAction.setImageDescriptor(Z_PLANE_ICON);\r
158         zPlaneAction.setToolTipText("Lock Z-Plane");\r
159         cameraAction = new Action("C", Action.AS_CHECK_BOX) {\r
160                 public void run() {\r
161                         useCamera = this.isChecked();\r
162                 }\r
163         };\r
164         cameraAction.setImageDescriptor(CAMERA_ICON);\r
165         cameraAction.setToolTipText("Use camera");\r
166         splitPointAction = new SelectSplitPointAction(parent,this);\r
167         \r
168     }\r
169     \r
170     public void fillToolBar(IToolBarManager manager) {\r
171         \r
172         manager.add(cameraAction);\r
173         cameraAction.setChecked(useCamera);\r
174         manager.add(xAxisAction);\r
175         manager.add(yAxisAction);\r
176         manager.add(zAxisAction);\r
177         manager.add(xPlaneAction);\r
178         manager.add(yPlaneAction);\r
179         manager.add(zPlaneAction);  \r
180         \r
181     }\r
182 \r
183     enum LockType {NONE,X,Y,Z,XY,YZ,XZ,CUSTOM};\r
184     LockType lock = LockType.NONE;\r
185     \r
186     private void setLockType(LockType type, boolean force) {\r
187         if (force || lock != LockType.CUSTOM) {\r
188                 lock = type;\r
189         }\r
190         xAxisAction.setChecked(false);\r
191         yAxisAction.setChecked(false);\r
192         zAxisAction.setChecked(false);\r
193         xPlaneAction.setChecked(false);\r
194         yPlaneAction.setChecked(false);\r
195         zPlaneAction.setChecked(false);\r
196         xAxisAction.setEnabled(true);\r
197         yAxisAction.setEnabled(true);\r
198         zAxisAction.setEnabled(true);\r
199         xPlaneAction.setEnabled(true);\r
200         yPlaneAction.setEnabled(true);\r
201         zPlaneAction.setEnabled(true);\r
202         switch (lock) {\r
203         case X:\r
204                 xAxisAction.setChecked(true);\r
205                 break;\r
206         case Y:\r
207                 yAxisAction.setChecked(true);\r
208                 break;\r
209         case Z:\r
210                 zAxisAction.setChecked(true);\r
211                 break;  \r
212         case XY:\r
213                 zPlaneAction.setChecked(true);\r
214                 break;  \r
215         case XZ:\r
216                 yPlaneAction.setChecked(true);\r
217                 break;  \r
218         case YZ:\r
219                 xPlaneAction.setChecked(true);\r
220                 break;  \r
221         case CUSTOM:\r
222                 xAxisAction.setEnabled(false);\r
223                 yAxisAction.setEnabled(false);\r
224                 zAxisAction.setEnabled(false);\r
225                 xPlaneAction.setEnabled(false);\r
226                 yPlaneAction.setEnabled(false);\r
227                 zPlaneAction.setEnabled(false);\r
228                 break;\r
229         }\r
230     }\r
231     \r
232     private double BRANCH_SNAP_DISTANCE = 0.05;\r
233     private double NOZZLE_SNAP_DISTANCE = 0.05;\r
234     \r
235     private double istep = 10.0;\r
236     private int decimals = 2;\r
237     \r
238     private double pipeDiameter = 0.2;\r
239     private double elbowRadius = 0.5;\r
240     private double eps = 0.001;\r
241     \r
242     private ArrayList<Point3d> controlPoints = new ArrayList<Point3d>();\r
243 \r
244     private Point3d currentPoint = new Point3d();\r
245     private Point3d lastPoint = new Point3d();\r
246     \r
247     private Vector3d customLockDir = null;\r
248     \r
249     private Line selectionLine;\r
250     private List<Line> pipeShapes = new ArrayList<Line>();\r
251     private MaterialState ms;\r
252     \r
253     \r
254     private Resource selectedPort = null;\r
255     private PositionType selectedType = null;\r
256     private Resource beginComponentResource = null;\r
257     \r
258     private Resource endComponentResource = null;\r
259     private Resource endComponentPort = null;\r
260     private PositionType endPortType = null;\r
261     \r
262     private Resource highlightedResource = null;\r
263     \r
264     private boolean useCamera = false;\r
265     \r
266     private List<Pair<Resource, PositionType>> positions = null;\r
267     \r
268     private SelectSplitPointAction splitPointAction;\r
269     private PositionSelectionGizmo gizmo = null;\r
270     \r
271     \r
272     \r
273     private enum ToolState{NOT_ACTIVE, INITIALIZING, SELECTING_POSITION, SELECTING_SPLIT, ROUTING};\r
274     private ToolState state = ToolState.NOT_ACTIVE;\r
275     \r
276     @Override\r
277     public void activate() {\r
278         state = ToolState.INITIALIZING;\r
279         controlPoints.clear();\r
280         if (beginComponentResource == null) {\r
281                 List<IGraphicsNode> mos = parent.getSelectionAdapter().getSelectedObjects();\r
282             if (mos.size() != 1) {\r
283                 end();\r
284                 return;\r
285             }\r
286             beginComponentResource = mos.get(0).getResource();\r
287         }\r
288         parent.getSession().asyncRead(new GraphRequestAdapter() {\r
289                 @Override\r
290                 public GraphRequestStatus perform(Graph g) throws Exception {\r
291                         positions = checkStartNode(g,beginComponentResource);\r
292                         if (positions.size() == 0) {\r
293                                 positions = null;\r
294                                 end();\r
295                         } else {\r
296                                 state = ToolState.SELECTING_POSITION;\r
297                         }\r
298                         return GraphRequestStatus.transactionComplete();\r
299                 }\r
300         });\r
301         \r
302         if (ms == null) {\r
303                 ms = parent.getRenderingComponent().getDisplaySystem().getRenderer().createMaterialState();\r
304             ms.setEmissive(new ColorRGBA(1.f,1.f,1.f,1.f));\r
305         }\r
306 \r
307     }\r
308     \r
309     \r
310 \r
311     @Override\r
312     public void deactivate() {\r
313          for (Line l : pipeShapes)\r
314                 l.removeFromParent();\r
315          pipeShapes.clear();\r
316          if (selectionLine != null)\r
317                 selectionLine.removeFromParent();\r
318          selectionLine = null;\r
319          customLockDir = null;\r
320          \r
321          setLockType(LockType.NONE,true);\r
322          beginComponentResource = null;\r
323          endComponentResource = null;\r
324          detector.clearConstraintHighlights(); \r
325          state = ToolState.NOT_ACTIVE;\r
326          selectedPort = null;\r
327          selectedType = null;\r
328         \r
329     }\r
330     \r
331     private List<Pair<Resource, PositionType>> checkStartNode(Graph g, Resource resource) {\r
332         List<Pair<Resource, PositionType>> positions = new ArrayList<Pair<Resource,PositionType>>();\r
333         \r
334         IEntity beginComponent = EntityFactory.create(g, resource);\r
335         \r
336         if (beginComponent.isInstanceOf(ProcessResource.plant3Dresource.Nozzle)) {\r
337                 if (PipingTools2.isFreeNozzle(beginComponent)) {\r
338 \r
339                                 positions.add(new Pair<Resource, PositionType>(beginComponent.getSingleRelatedObject(ProcessResource.plant3Dresource.HasControlPoint).getResource(),PositionType.NEXT));\r
340                 } \r
341         } else if (beginComponent.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent)) {\r
342                 // variable length inline component is exception from other pipeline components,\r
343                 // since a new pipe can branch it\r
344                 VariableLengthInlineComponent vlic = new VariableLengthInlineComponent(beginComponent);\r
345             PipeControlPoint pcp = vlic.getControlPoint();\r
346             if (pcp.getNext() == null) {\r
347 \r
348                 positions.add(new Pair<Resource, PositionType>(pcp.getResource(),PositionType.NEXT));    \r
349             } else if (pcp.getPrevious() == null) {\r
350 \r
351                 positions.add(new Pair<Resource, PositionType>(pcp.getResource(),PositionType.PREVIOUS));\r
352             }\r
353             positions.add(new Pair<Resource, PositionType>(pcp.getResource(),PositionType.SPLIT));\r
354         } else if (beginComponent.isInstanceOf(ProcessResource.plant3Dresource.EndComponent)) {\r
355                 PipelineComponent component = new PipelineComponent(beginComponent);            \r
356                 PipeControlPoint pcp = component.getControlPoint();\r
357                 if (pcp.getNext() == null && pcp.getPrevious() == null) { \r
358                         throw new RuntimeException("End component " + beginComponent.getResource() + " is not connected to anything.");\r
359                         //positions.add(new Pair<Resource, PositionType>(pcp.getResource(),PositionType.NEXT));\r
360                 }\r
361                 for (PipeControlPoint p : pcp.getSubPoint()) {\r
362                         if (p.getNext() == null && p.getPrevious() == null) {\r
363                                 positions.add(new Pair<Resource, PositionType>(p.getResource(),PositionType.NEXT));\r
364                         }\r
365                 }\r
366         } else if (beginComponent.isInstanceOf(ProcessResource.plant3Dresource.PipelineComponent)) {\r
367                 \r
368                 PipelineComponent component = new PipelineComponent(beginComponent);\r
369                 \r
370                 PipeControlPoint pcp = component.getControlPoint();\r
371                 if (pcp.getNext() == null) {\r
372                         positions.add(new Pair<Resource, PositionType>(pcp.getResource(),PositionType.NEXT));\r
373                 } else if (pcp.getPrevious() == null) {\r
374                         positions.add(new Pair<Resource, PositionType>(pcp.getResource(),PositionType.PREVIOUS));\r
375                 }\r
376                 if (!beginComponent.isInstanceOf(ProcessResource.plant3Dresource.SizeChangeComponent)||\r
377                         !beginComponent.isInstanceOf(ProcessResource.plant3Dresource.OffsetComponent)) {\r
378                         for (PipeControlPoint p : pcp.getSubPoint()) {\r
379                                 if (p.getNext() == null && p.getPrevious() == null) {\r
380                                         positions.add(new Pair<Resource, PositionType>(p.getResource(),PositionType.NEXT));\r
381                                 }\r
382                         }\r
383                 }       \r
384         } else {\r
385             return positions;\r
386         }\r
387         return positions;\r
388     }\r
389 \r
390     @Override\r
391     public void update() {\r
392         \r
393         switch (state) {\r
394         case NOT_ACTIVE:\r
395                 return; // TODO : throw Exception?\r
396         case INITIALIZING:\r
397                 return;\r
398         case SELECTING_POSITION:\r
399                 updateSelectPosition();\r
400                 break;\r
401         case SELECTING_SPLIT:\r
402                 updateSelectSplit();\r
403                 break;\r
404         case ROUTING:\r
405                 updateRouting();\r
406                 break;\r
407         }\r
408         return;\r
409     }\r
410 \r
411     private void updateSelectPosition() {\r
412         \r
413         if (positions == null) {\r
414                 throw new RuntimeException("positions must be loaded before select position can be activated");\r
415         }\r
416         if (selectedPort != null) {\r
417                 throw new RuntimeException("position is already selected");\r
418         }\r
419         if (positions.size() == 1) {\r
420                         selectedPort = positions.get(0).first;\r
421                         selectedType = positions.get(0).second;\r
422                         state = ToolState.INITIALIZING;\r
423                         \r
424                         \r
425                         \r
426                         if (requiresNewPipeRun()){\r
427                                 if(!getNewPipeRunSpecs()) {\r
428                                         end();\r
429                                         return;\r
430                                 }\r
431                         }\r
432                         if (selectedType == PositionType.SPLIT) {\r
433                                 startSplitting();\r
434                         } else {\r
435                                 startRouting();\r
436                         }\r
437 \r
438                 } else if (gizmo == null) {\r
439                         state = ToolState.INITIALIZING; // asyncRead!\r
440                         parent.getSession().asyncRead(new GraphRequestAdapter() {\r
441                                 @Override\r
442                                 public GraphRequestStatus perform(Graph g) throws Exception {\r
443                                         List<Pair<Point3d, PositionType>> pos = new ArrayList<Pair<Point3d,PositionType>>();\r
444                                         for (Pair<Resource, PositionType> p : positions) {\r
445                                                 IEntity entity = EntityFactory.create(g,p.first);\r
446                                                 Point3d position = ControlPointTools.getRealPosition(entity, p.second);\r
447                                                 pos.add(new Pair<Point3d, PositionType>(position,p.second));\r
448                                         }\r
449                                         gizmo = new PositionSelectionGizmo(parent, pos);\r
450                                         parent.setGizmo(gizmo);\r
451                                         parent.getRenderingComponent().getNoShadowRoot().attachChild(gizmo.getNode());\r
452                                         state = ToolState.SELECTING_POSITION;\r
453                                         return GraphRequestStatus.transactionComplete();\r
454                                 }\r
455                         });\r
456                         \r
457                 } else {\r
458                         gizmo.update();\r
459                         \r
460                         if (input.keyPressed(KeyEvent.VK_ESCAPE)) {\r
461                         state = ToolState.INITIALIZING;\r
462                         parent.setGizmo(null);\r
463                         gizmo = null;\r
464                         end();\r
465                         return;\r
466                 }\r
467 \r
468                 if (gizmo.getSelected() >= 0 && input.mouseClicked() && input.clickButton() == MouseEvent.BUTTON1) {\r
469                         state = ToolState.INITIALIZING; // asyncRead!\r
470                         parent.setGizmo(null);\r
471                         selectedPort = positions.get(gizmo.getSelected()).first;\r
472                         selectedType = positions.get(gizmo.getSelected()).second;\r
473                         gizmo = null;\r
474                         \r
475                         if (selectedType == PositionType.SPLIT) {\r
476                                 startSplitting();       \r
477                         return;\r
478                         } else {\r
479                                 startRouting();\r
480                         }\r
481                 } \r
482                 \r
483                 if (useCamera) {\r
484                         parent.getDefaultAction().update();\r
485                         return;\r
486                 }\r
487                 }\r
488         \r
489     }\r
490     \r
491     private boolean requiresNewPipeRun() {\r
492         GraphRequestWithResult<Boolean> createsNewPipeline = new GraphRequestWithResult<Boolean>() {\r
493                         @Override\r
494                         public Boolean performWithResult(Graph g) throws Exception {\r
495                                 if(g.isInstanceOf(selectedPort, ProcessResource.plant3Dresource.NozzleControlPoint))\r
496                                         return true;\r
497                                 if (selectedType == PositionType.SPLIT)\r
498                                         return true;\r
499                                 return false;\r
500                                 \r
501                         }\r
502                 };\r
503                 parent.getSession().syncRead(createsNewPipeline);\r
504                 return createsNewPipeline.getResult();\r
505     }\r
506     \r
507     private boolean getNewPipeRunSpecs() {\r
508         PipelineDialog dialog;\r
509                 dialog = new PipelineDialog(parent.getRenderingComposite().getShell(),pipeDiameter,elbowRadius);\r
510                 if (dialog.open() == PipelineDialog.CANCEL) {\r
511                         end();\r
512                         return false;\r
513                 }\r
514                 pipeDiameter = dialog.getPipeDiameter();\r
515                 elbowRadius = dialog.getTurnRadius();\r
516                 return true;\r
517     }\r
518     \r
519     private void startRouting() {\r
520         state = ToolState.INITIALIZING;\r
521         parent.getSession().asyncRead(new GraphRequestAdapter() {\r
522                         @Override\r
523                         public GraphRequestStatus perform(Graph g) throws Exception {\r
524                                 PipeControlPoint pcp = new PipeControlPoint(g,selectedPort);\r
525                                 lastPoint = ControlPointTools.getRealPosition(pcp, selectedType);//G3DTools.getPoint(pcp.getWorldPosition());\r
526                                 if (pcp.isInstanceOf(ProcessResource.plant3Dresource.DirectedControlPoint)) {\r
527                                         lock = LockType.CUSTOM;\r
528                                         customLockDir = ControlPointTools.getDirectedControlPointDirection(pcp);\r
529                                 } else if (pcp.isInstanceOf(ProcessResource.plant3Dresource.FixedLengthControlPoint)||\r
530                                                    pcp.isInstanceOf(ProcessResource.plant3Dresource.TurnControlPoint)) {\r
531                                         lock = LockType.CUSTOM;\r
532                                         if (selectedType == PositionType.NEXT)\r
533                                                 customLockDir = ControlPointTools.getPathLegDirection(pcp, Direction.NEXT);\r
534                                         else\r
535                                                 customLockDir = ControlPointTools.getPathLegDirection(pcp, Direction.PREVIOUS);\r
536                                 } else {\r
537                                         lock = LockType.NONE;\r
538                                 }\r
539                                 IEntity pipeRun = ControlPointTools.getPipeRun(pcp);\r
540                                 if (pipeRun != null) {\r
541                                         pipeDiameter = pipeRun.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasPipeDiameter);\r
542                                         elbowRadius = pipeRun.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasTurnRadius);\r
543                                 }\r
544                                 return GraphRequestStatus.transactionComplete();\r
545                         }\r
546                         \r
547                         @Override\r
548                         public void requestCompleted(GraphRequestStatus status) {\r
549                                 createLine();\r
550                                 state = ToolState.ROUTING;\r
551                         }\r
552                 });\r
553     }\r
554     \r
555     private void startSplitting() {\r
556         parent.getSession().asyncRead(new GraphRequestAdapter() {\r
557                         @Override\r
558                         public GraphRequestStatus perform(Graph g) throws Exception {\r
559                                 PipeControlPoint pcp = new PipeControlPoint(g,selectedPort);\r
560                                 Point3d p1 = new Point3d();\r
561                                 Point3d p2 = new Point3d();\r
562                                 ControlPointTools.getInlineControlPointEnds(pcp, p1, p2);\r
563                                 splitPointAction.setSplit(p1, p2);\r
564                         splitPointAction.activate();\r
565                         state = ToolState.SELECTING_SPLIT;\r
566                                 return GraphRequestStatus.transactionComplete();\r
567                         }\r
568                 }); \r
569     }\r
570     \r
571    \r
572     private void updateSelectSplit() {\r
573         if (splitPointAction.active()) {\r
574                 splitPointAction.update();\r
575                 return;\r
576         } else {\r
577                 throw new RuntimeException("SplitPointAction should be active");\r
578         }\r
579     }\r
580     \r
581     @Override\r
582     public void setSplitPoint(Point3d point) {\r
583         splitPointAction.deactivate();\r
584         if (point == null) {\r
585                 end();\r
586                 return;\r
587         } else {\r
588                 \r
589                         \r
590                 lastPoint = point;\r
591                 createLine();\r
592                 state = ToolState.ROUTING;\r
593         }\r
594     }\r
595     \r
596     private void updateRouting() {\r
597         if(input.keyPressed(KeyEvent.VK_ESCAPE)) {\r
598             controlPoints.clear();\r
599             end();\r
600             return;\r
601         }\r
602         if (input.keyPressed(KeyEvent.VK_C)) {\r
603                 useCamera = !useCamera;\r
604                 cameraAction.setChecked(useCamera);\r
605         }\r
606         if (useCamera) {\r
607                 parent.getDefaultAction().update();\r
608                 return;\r
609         }\r
610         \r
611         parent.getSession().syncRead(new GraphRequestAdapter() {\r
612                  @Override\r
613                 public GraphRequestStatus perform(Graph g) throws Exception {\r
614         \r
615         Vector3d o = new Vector3d();\r
616         Vector3d d = new Vector3d();\r
617         parent.createPickRay(o, d);\r
618         if (!updateCurrentPoint(o, d))\r
619             return GraphRequestStatus.transactionComplete();\r
620         //Point3d startPoint = new Point3d();\r
621         double mu[] = new double[2];\r
622         \r
623         IEntity endTo = null;\r
624         PositionType endType = null;\r
625         IEntity endPort = null;\r
626         \r
627         if (parent.getSelectionAdapter().getHighlightSelection().size() > 0) {\r
628                 highlightedResource = parent.getSelectionAdapter().getHighlightSelection().getSelectionList().get(0);\r
629         } else {\r
630                 highlightedResource = null;\r
631         }\r
632 \r
633           if (highlightedResource != null) {\r
634                   IEntity highlightNode = EntityFactory.create(g,highlightedResource);\r
635                      \r
636                   if (lock == LockType.NONE) {\r
637                           if (highlightNode.isInstanceOf(ProcessResource.plant3Dresource.Nozzle) && endingToNozzle(highlightNode,o,d)) {\r
638                                   endTo = highlightNode;\r
639                           } else if (highlightNode.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent)) {\r
640                                   endTo = highlightNode;\r
641                                   endType = endingToStraight(new VariableLengthInlineComponent(highlightNode),mu,o,d);     \r
642                           } else if (highlightNode.isInstanceOf(ProcessResource.plant3Dresource.PipelineComponent) && (endPort = endingToComponent(highlightNode,o,d)) != null) {\r
643                                   endTo = highlightNode;\r
644                           } else {\r
645                                   updateRoute(o,d); \r
646                           }\r
647                   } else {  \r
648                           if (highlightNode.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent)  && (endType = endingLockToStraight(new VariableLengthInlineComponent(highlightNode),mu)) != null) {\r
649                                   endTo = highlightNode;\r
650                           } else if (highlightNode.isInstanceOf(ProcessResource.plant3Dresource.Nozzle) && endingLockToNozzle(highlightNode)) {\r
651                                   endTo = highlightNode;\r
652                           } else if (highlightNode.isInstanceOf(ProcessResource.plant3Dresource.PipelineComponent) && (endPort = endingLockToComponent(highlightNode)) != null) {\r
653                                   endTo = highlightNode;\r
654                           } else {\r
655                                   updateRoute(o,d);\r
656                           }\r
657                   }\r
658                                 \r
659               \r
660         } else {\r
661             updateRoute(o,d);\r
662         }\r
663         \r
664         parent.setViewChanged(true);\r
665         if (input.mouseClicked()) {\r
666             if (input.clickButton() == MouseEvent.BUTTON1) {\r
667                 if (controlPoints.size() > 0) {\r
668                     addPoint();\r
669                     setLockType(LockType.NONE,true);\r
670                     if (endTo != null) {\r
671                         endComponentResource = endTo.getResource();\r
672                         if (endPort != null)\r
673                                 endComponentPort = endPort.getResource();\r
674                         endPortType = endType;\r
675                         \r
676                         endPiping();\r
677                     }\r
678                 } else {\r
679                         throw new RuntimeException("kjf");\r
680 //                      // user was selecting position of branch\r
681 //                    lastPoint.set(startPoint);\r
682 //                    controlPoints.add(new Point3d(startPoint));\r
683 //                    if (selectionLine != null)\r
684 //                      selectionLine.removeFromParent();\r
685 //                    selectionLine = null;\r
686                 }\r
687             } else if (input.clickButton() == MouseEvent.BUTTON2){\r
688                 detector.updateConstraintReference();\r
689             } else if (input.clickButton() == MouseEvent.BUTTON3){      \r
690                 endPiping();\r
691             }\r
692         }\r
693         \r
694         return GraphRequestStatus.transactionComplete();\r
695                 } \r
696           });\r
697         \r
698     }\r
699     \r
700     private void createLine() {\r
701         controlPoints.add(new Point3d(lastPoint));\r
702         Line line = new Line();\r
703         line.setRenderState(ms);\r
704       \r
705         PipeComponentProvider.createStraightEdges(line, currentPoint, currentPoint, pipeDiameter*0.5);\r
706         pipeShapes.add(line);\r
707         parent.getRenderingComponent().getNoShadowRoot().attachChild(line);    \r
708         line.setCullMode(Geometry.CULL_NEVER);\r
709     }\r
710     \r
711     \r
712     /**\r
713      * Adds current point to pipeline\r
714      *\r
715      */\r
716     private void addPoint() {\r
717         \r
718         controlPoints.add(new Point3d(currentPoint));\r
719         Line line = new Line();\r
720         line.setRenderState(ms);\r
721         PipeComponentProvider.createStraightEdges(line, controlPoints.get(controlPoints.size() - 1), currentPoint, pipeDiameter*0.5);\r
722         pipeShapes.add(line);\r
723         parent.getRenderingComponent().getNoShadowRoot().attachChild(line);   \r
724         line.setCullMode(Geometry.CULL_NEVER);\r
725         lastPoint.set(currentPoint);\r
726     }\r
727     \r
728     /**\r
729      * Updates tool graphics for current point \r
730      */\r
731     private void updateCurrentPoint() {\r
732         PipeComponentProvider.createStraightEdges(pipeShapes.get(pipeShapes.size() - 1), controlPoints.get(controlPoints.size() - 1), currentPoint, pipeDiameter*0.5);\r
733     }\r
734     \r
735     /**\r
736      * Removes last point from pipeline\r
737      */\r
738     public void removePoint() {\r
739         if (controlPoints.size() < 2)\r
740                 return;\r
741         controlPoints.remove(controlPoints.size() - 1);\r
742 \r
743         pipeShapes.get(pipeShapes.size() - 1).removeFromParent();\r
744         pipeShapes.remove(pipeShapes.size() - 1);\r
745         PipeComponentProvider.createStraightEdges(pipeShapes.get(pipeShapes.size() - 1), controlPoints.get(controlPoints.size() - 1), currentPoint, pipeDiameter*0.5);\r
746         \r
747         lastPoint.set(controlPoints.get(controlPoints.size()-1));\r
748         if (controlPoints.size() < 2 && customLockDir != null) {\r
749                 setLockType(LockType.CUSTOM, true);\r
750         }\r
751     }\r
752     \r
753    \r
754     \r
755     private boolean endingToNozzle(IEntity nozzle,Vector3d o, Vector3d d) { \r
756         IEntity pcp = nozzle.getSingleRelatedObject(ProcessResource.plant3Dresource.HasControlPoint);\r
757         if (pcp != null && (pcp.getAtMostOneRelatedObject(ProcessResource.plant3Dresource.HasNext) != null ||\r
758                                     pcp.getAtMostOneRelatedObject(ProcessResource.plant3Dresource.HasPrevious) != null))\r
759                 return false; // nozzle is already connected to pipe\r
760         currentPoint = G3DTools.getPoint(nozzle.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition));\r
761         Point3d previousPipePoint = controlPoints.get(controlPoints.size() - 1);\r
762         Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint));\r
763         if (p != null) {\r
764             if (p.distance(currentPoint) > NOZZLE_SNAP_DISTANCE) {\r
765                 return false;\r
766             }\r
767         } \r
768         \r
769         updateCurrentPoint();\r
770         \r
771         setInfoText("Connect to nozzle " + currentPoint);\r
772         return true;\r
773     \r
774     }\r
775     \r
776     private PositionType endingToStraight(VariableLengthInlineComponent s, double mu[], Vector3d o, Vector3d d) {\r
777         String info = "";\r
778         Point3d sStart = new Point3d();\r
779         Point3d sEnd = new Point3d();\r
780         //detector.clearConstraintHighlights();\r
781         \r
782         Point3d previousPipePoint = controlPoints.get(controlPoints.size() - 1);\r
783         //String st = "";\r
784         if (lock == LockType.NONE) {\r
785             Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint));\r
786             if (p != null) {\r
787                 currentPoint = p;\r
788                 // snapping is detected, check if snapped point can create branch with straight\r
789                 PositionType t = endingLockToStraight(s, mu);\r
790                 if (t != null)\r
791                     return t;\r
792                 // if not, we'll have to remove highlight that was added when snapped point was detected\r
793                 detector.clearConstraintHighlights();\r
794             } \r
795                 \r
796             PipingTools2.getInlineComponentEnds(s, sStart, sEnd);\r
797             Vector3d sDir = new Vector3d(sEnd);\r
798             sDir.sub(sStart);\r
799             MathTools.intersectStraightStraight(sStart, sDir, o, d, currentPoint, new Point3d(), mu);\r
800             \r
801 \r
802         } else {\r
803             throw new RuntimeException("Lock shouldn't be on");\r
804 \r
805         }\r
806         \r
807         updateCurrentPoint();\r
808         \r
809         // branch point must lie between straight's ends. If connection point is exactly\r
810         // on straight end user may want to connect pipes to each other\r
811         // TODO : take account sizes of inline components)\r
812         // TODO : actually make connection if its detected\r
813         boolean connectPrev = false;\r
814         boolean connectNext = false;\r
815         \r
816         if (mu[0] < 0.0) {\r
817             currentPoint.set(sStart);\r
818             connectPrev = true;\r
819         }\r
820         else if (mu[0] > 1.0) {\r
821             currentPoint.set(sEnd);\r
822             connectNext = true;\r
823         }\r
824         boolean connect = false;\r
825         if (connectPrev) {\r
826             PipeControlPoint pcp = s.getControlPoint();\r
827             if (pcp.getPrevious() == null)\r
828                 connect = true;\r
829         } else if (connectNext) {\r
830                 PipeControlPoint pcp = s.getControlPoint();\r
831             if (pcp.getNext() == null)\r
832                 connect = true;\r
833         }\r
834         \r
835         updateCurrentPoint();\r
836         \r
837         if (connect)\r
838             info += "Connect pipes :";\r
839         else\r
840             info += "Make Branch :";\r
841         \r
842         setInfoText(info + currentPoint + " " + Math.max(0.0, Math.min(mu[0], 1.0)));\r
843         if (connect) {\r
844                 if (connectNext) {\r
845                         return PositionType.NEXT;\r
846                 } else {\r
847                         return PositionType.PREVIOUS;\r
848                 }\r
849                         \r
850         }\r
851         return PositionType.SPLIT;\r
852                 \r
853     }\r
854     \r
855     private IEntity endingToComponent(IEntity component, Vector3d o, Vector3d d) {\r
856         // TODO : scan all empty pcps of the component and select closest one.\r
857         return null;\r
858     }\r
859     \r
860     private PositionType endingLockToStraight(VariableLengthInlineComponent s, double mu[]) {\r
861         \r
862         Point3d sStart = new Point3d();//G3DTools.getPoint(s.getHasControlPoint().getPreviousPoint().getLocalPosition());\r
863         Point3d sEnd = new Point3d(); //G3DTools.getPoint(s.getHasControlPoint().getNextPoint().getLocalPosition());\r
864         PipingTools2.getInlineComponentEnds(s, sStart, sEnd);\r
865         Vector3d sDir = new Vector3d(sEnd);\r
866         sDir.sub(sStart);\r
867         Vector3d dir = new Vector3d(currentPoint);\r
868         Point3d prev = controlPoints.get(controlPoints.size() - 1);\r
869         dir.sub(prev);\r
870         // intersection point in pipe where branch would be inserted to\r
871         Vector3d branchPoint = new Vector3d();\r
872         // intersection point in straight pipe that is currently routed\r
873         Vector3d routePoint = new Vector3d();\r
874         MathTools.intersectStraightStraight(sStart, sDir, new Vector3d(prev), dir, branchPoint, routePoint, mu);\r
875         routePoint.sub(branchPoint);\r
876         // startPoint of branch must be between pipe ends\r
877         // TODO : take account sizes of elbows (or other components)\r
878         // branch point must be between pipe ends and intersection points must be quite close to each othert\r
879         if (mu[0] > 0.0 && mu[0] < 1.0 && routePoint.lengthSquared() < BRANCH_SNAP_DISTANCE) {\r
880             currentPoint.set(branchPoint);\r
881             \r
882             updateCurrentPoint();\r
883             \r
884             setInfoText("Make branch (l) :" + currentPoint + " " + Math.max(0.0, Math.min(mu[0], 1.0)) + " " + routePoint.lengthSquared());\r
885             return PositionType.SPLIT;\r
886         }\r
887         return null;\r
888     }\r
889     \r
890     private boolean endingLockToNozzle(IEntity nozzle) {\r
891          Vector3d dir = new Vector3d(currentPoint);\r
892          Point3d prev = controlPoints.get(controlPoints.size() - 1);\r
893          dir.sub(prev);\r
894          Point3d nozzleLoc = G3DTools.getPoint(nozzle.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition));\r
895          double u[] = new double[1];\r
896          Vector3d closest = MathTools.closestPointOnStraight(new Point3d(nozzleLoc), new Point3d(prev), new Vector3d(dir), u);\r
897          double dist = nozzleLoc.distanceSquared(new Point3d(closest));\r
898          if (dist < BRANCH_SNAP_DISTANCE) {\r
899                  // FIXME : directions should be checked (insert an elbow)\r
900                  currentPoint.set(nozzleLoc);\r
901                  updateCurrentPoint();\r
902                  setInfoText("Connect to nozzle (l) :" + currentPoint);\r
903                  return true;\r
904          } \r
905          //System.out.println(u[0]);\r
906         return false;\r
907     }\r
908     \r
909     private IEntity endingLockToComponent(IEntity component) {\r
910         // we'll must scan all free pcp's and their direction to accept the connection.\r
911         return null;\r
912     }\r
913     \r
914     private void updateRoute(Vector3d o, Vector3d d) {\r
915         detector.clearConstraintHighlights();\r
916         Point3d previousPipePoint = controlPoints.get(controlPoints.size() - 1);\r
917         String s = "";\r
918         if (lock == LockType.NONE) {\r
919             Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint));\r
920             if (p != null)\r
921                 currentPoint = p;\r
922             s += detector.getSnapString();\r
923 \r
924         } else {\r
925             Vector3d dir = new Vector3d(currentPoint);\r
926             dir.sub(previousPipePoint);\r
927             Point3d p = detector.getPointSnap(new Vector3d(previousPipePoint), dir);\r
928             if (p != null)\r
929                 currentPoint = p;\r
930             s += detector.getSnapString();\r
931 \r
932         }\r
933         \r
934         updateCurrentPoint();\r
935         s += currentPoint.toString();\r
936         setInfoText(s);\r
937     }\r
938     \r
939     private boolean updateCurrentPoint(Vector3d o, Vector3d d) {\r
940         if (lock != LockType.CUSTOM) {\r
941                 if (input.keyPressed(KeyEvent.VK_X)) {\r
942                                 if (lock == LockType.X)\r
943                                         setLockType(LockType.YZ,false);\r
944                                 else\r
945                                         setLockType(LockType.X,false);\r
946                         }\r
947                         if (input.keyPressed(KeyEvent.VK_Y)) {\r
948                                 if (lock == LockType.Y)\r
949                                         setLockType(LockType.XZ,false);\r
950                                 else\r
951                                         setLockType(LockType.Y,false);\r
952                         }\r
953                         if (input.keyPressed(KeyEvent.VK_Z)) {\r
954                                 if (lock == LockType.Z)\r
955                                         setLockType(LockType.XY,false);\r
956                                 else\r
957                                         setLockType(LockType.Z,false);\r
958                         }\r
959                         if (input.keyPressed(KeyEvent.VK_N)) {\r
960                                 setLockType(LockType.NONE,false);\r
961                         }\r
962                         if (input.keyPressed(KeyEvent.VK_BACK_SPACE)) {\r
963                                 removePoint();\r
964                         }\r
965         }\r
966         Vector3d point = new Vector3d(lastPoint);\r
967         boolean step = ((input.moveModifiers() & MouseEvent.CTRL_DOWN_MASK) > 0);\r
968         switch(lock) {\r
969         case X:\r
970             MathTools.intersectStraightStraight(point, new Vector3d(1.0,0.0,0.0), o,d, currentPoint, new Vector3d());\r
971             if (step) {\r
972                 currentPoint.x = Math.round(istep * currentPoint.x) / istep;\r
973                 BigDecimal bx = new BigDecimal(currentPoint.x);\r
974                 bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);\r
975                 currentPoint.x = bx.doubleValue();\r
976             }\r
977             break;\r
978         case Y:\r
979             MathTools.intersectStraightStraight(point, new Vector3d(0.0,1.0,0.0), o,d, currentPoint, new Vector3d());\r
980             if (step) {\r
981                 currentPoint.y = Math.round(istep * currentPoint.y) / istep;\r
982                 BigDecimal bx = new BigDecimal(currentPoint.y);\r
983                 bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);\r
984                 currentPoint.y = bx.doubleValue();\r
985             }\r
986             break;\r
987         case Z:\r
988             MathTools.intersectStraightStraight(point, new Vector3d(0.0,0.0,1.0), o,d, currentPoint, new Vector3d());\r
989             if (step) {\r
990                 currentPoint.z = Math.round(istep * currentPoint.z) / istep;\r
991                 BigDecimal bx = new BigDecimal(currentPoint.z);\r
992                 bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);\r
993                 currentPoint.z = bx.doubleValue();\r
994             }break;\r
995         case XY:\r
996             MathTools.intersectStraightPlane(o, d, point, new Vector3d(0.0,0.0,1.0), currentPoint);\r
997             break;\r
998         case XZ:\r
999             MathTools.intersectStraightPlane(o, d, point, new Vector3d(0.0,1.0,0.0), currentPoint);\r
1000             break;\r
1001         case YZ:\r
1002             MathTools.intersectStraightPlane(o, d, point, new Vector3d(1.0,0.0,0.0), currentPoint);\r
1003             break;\r
1004         case NONE:\r
1005             Vector3d normal = parent.getCamera().getUnNormalizedHeading();\r
1006             normal.normalize();\r
1007             \r
1008             MathTools.intersectStraightPlane(o, d, point, normal, currentPoint);\r
1009             break;\r
1010         case CUSTOM:\r
1011                 MathTools.intersectStraightStraight(point, new Vector3d(customLockDir), o,d, currentPoint, new Vector3d());\r
1012             double dist = MathTools.distanceFromPlane(new Vector3d(currentPoint), customLockDir, lastPoint);\r
1013                 if (dist < 0.0)\r
1014                         currentPoint.set(lastPoint);\r
1015             break;\r
1016         default:\r
1017             return false;\r
1018         }\r
1019         return true;\r
1020     }\r
1021     \r
1022    \r
1023     private ArrayList<Point3d> filterPoints() {\r
1024         ArrayList<Point3d> filteredControlPoints = new ArrayList<Point3d>();\r
1025         \r
1026         //  this loop filters control points that are not needed\r
1027         for (int i = 0; i < controlPoints.size() - 2; i++) {\r
1028             Point3d start = controlPoints.get(i);\r
1029             if (i == 0)\r
1030                 filteredControlPoints.add(start);\r
1031             \r
1032             Point3d middle = controlPoints.get(i+1);\r
1033             Point3d end = controlPoints.get(i+2);\r
1034             \r
1035             Vector3d dir1 = new Vector3d(middle);\r
1036             dir1.sub(start);\r
1037             Vector3d dir2 = new Vector3d(end);\r
1038             dir2.sub(middle);\r
1039             double angle = dir1.angle(dir2);\r
1040             if (angle > eps && angle < (Math.PI - eps))\r
1041                 filteredControlPoints.add(middle);\r
1042             // if angle is near PI pipe turns back to where it started\r
1043             // if angle is near zero, pipe is straight and there's no need for control point\r
1044             \r
1045             if (i == controlPoints.size() - 3)\r
1046                 filteredControlPoints.add(end);\r
1047             \r
1048         } \r
1049         return filteredControlPoints;\r
1050     }\r
1051     \r
1052     private PipeControlPoint connectPipeStart(Graph graph, PipeRun pipeRun, boolean reversed) {\r
1053         PipeControlPoint pcp = new PipeControlPoint(graph,selectedPort);\r
1054         IEntity beginComponent = EntityFactory.create(graph,beginComponentResource);\r
1055         if (beginComponent.isInstanceOf(ProcessResource.plant3Dresource.Nozzle)) {\r
1056                 PipingTools2.linkNozzleAndPipeRun(beginComponent, pipeRun);\r
1057                 // TODO : set diameters same\r
1058                 //reversed = false;\r
1059                 \r
1060         } else if (beginComponent.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent)) {\r
1061                 switch (selectedType) {\r
1062                 case NEXT:\r
1063                         {\r
1064                                 PipeControlPoint tcp = createTurn(graph, pipeRun, 0);\r
1065                                 connectControlPoints(pcp, tcp, reversed);\r
1066                                 return tcp;\r
1067                         }\r
1068                 case PREVIOUS:\r
1069                         {\r
1070                                 PipeControlPoint tcp = createTurn(graph, pipeRun, 0);\r
1071                                 connectControlPoints(pcp, tcp, reversed);\r
1072                                 return tcp;\r
1073                         }\r
1074                 case SPLIT:\r
1075                         //reversed = false;\r
1076                         // 1. create (non visible) splitting component.\r
1077                         PipelineComponent newComponent = PipingTools2.instantiatePipelineComponent(graph, PipingTools2.getPipeRun(beginComponent).getResource(), ProcessResource.plant3Dresource.BranchSplitComponent);                 \r
1078                         PipeControlPoint mainCP = newComponent.getControlPoint();\r
1079                         // 2. create control point for the branch\r
1080                         BranchEndControlPoint becp = BranchEndControlPoint.createDefault(graph);\r
1081                         mainCP.addSubPoint(becp);\r
1082                         pipeRun.addControlPoints(becp);\r
1083                         pcp = becp.toPipeControlPoint();\r
1084                         ControlPointTools.setWorldPosition(mainCP, controlPoints.get(0));\r
1085                         \r
1086                         PipingTools2.splitVariableLengthComponent(newComponent, beginComponent);\r
1087                 }\r
1088         } else if (beginComponent.isInstanceOf(ProcessResource.plant3Dresource.PipelineComponent)) {\r
1089                 //if (selectedType == PositionType.PREVIOUS)\r
1090                         //reversed = true;\r
1091                 //else\r
1092                         //reversed = false;\r
1093         } else {\r
1094                 throw new RuntimeException("unknown starting component");\r
1095         }\r
1096         \r
1097         return pcp;\r
1098     }\r
1099     \r
1100     private PipeControlPoint connectPipeEnd(Graph graph, PipeRun pipeline, boolean reversed) {\r
1101         PipeControlPoint pcp = null;\r
1102         IEntity endComponent = null;\r
1103         if (endComponentResource != null)\r
1104                 endComponent = EntityFactory.create(graph, endComponentResource);\r
1105         if (endComponent == null) {\r
1106                 return null;\r
1107         } else if (endComponent.isInstanceOf(ProcessResource.plant3Dresource.Nozzle)){\r
1108                 pcp = new PipeControlPoint(endComponent.getSingleRelatedObject(ProcessResource.plant3Dresource.HasControlPoint));\r
1109                 PipingTools2.linkNozzleAndPipeRun(endComponent, pipeline);\r
1110         } else if (endComponent.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent)) {\r
1111            assert(endPortType != null);\r
1112            if (endPortType == PositionType.SPLIT) {\r
1113                    //System.out.println(lastPoint + " " + currentPoint + " " + positions.get(positions.size() - 1));\r
1114                    Point3d pos = lastPoint;\r
1115                    // 1. create (non visible) splitting component.\r
1116                    PipelineComponent newComponent = PipingTools2.instantiatePipelineComponent(graph, PipingTools2.getPipeRun(endComponent).getResource(), ProcessResource.plant3Dresource.BranchSplitComponent);\r
1117                   \r
1118                    PipeControlPoint mainCP = newComponent.getControlPoint();\r
1119                    // 2. create control point for the branch\r
1120                    BranchEndControlPoint becp = BranchEndControlPoint.createDefault(graph);\r
1121                    mainCP.addSubPoint(becp);\r
1122                    pipeline.addControlPoints(becp);\r
1123                    pcp = becp.toPipeControlPoint();\r
1124                    ControlPointTools.setWorldPosition(mainCP, pos);\r
1125                    \r
1126                    PipingTools2.splitVariableLengthComponent(newComponent, endComponent);\r
1127            } else {\r
1128                    \r
1129            }      \r
1130         } else if (endComponent.isInstanceOf(ProcessResource.plant3Dresource.FixedLengthInlineComponent)) {\r
1131                 // attach to selected port, reverse the piperun if needed\r
1132                 pcp = new PipeControlPoint(graph,endComponentPort);\r
1133                 if (!reversed && pcp.getPrevious() != null || reversed && pcp.getNext() != null) {\r
1134                         PipingTools2.reversePipeRun(ControlPointTools.getPipeRun(pcp));\r
1135                 }\r
1136         }\r
1137         return pcp;\r
1138     }\r
1139     \r
1140     private PipeControlPoint createTurn(Graph coreTC,PipeRun pipeRun, int i) {\r
1141         PipelineComponent elbow = PipingTools2.instantiatePipelineComponent(coreTC,pipeRun.getResource(), ProcessResource.plant3Dresource.Elbow);\r
1142         G3DAPI.setWorldPosition(elbow, controlPoints.get(i));\r
1143         return elbow.getControlPoint();\r
1144     }\r
1145     \r
1146     private PipeControlPoint createInline(Graph graph, PipeRun pipeRun, int i) {\r
1147         Point3d p1 = controlPoints.get(i-1);\r
1148         Point3d p2 = controlPoints.get(i);\r
1149         Vector3d v = new Vector3d(p2);\r
1150         v.sub(p1);\r
1151         double length = v.length();\r
1152         v.scale(0.5);\r
1153         v.add(p1);\r
1154         PipelineComponent straight = PipingTools2.instantiatePipelineComponent(graph,pipeRun.getResource(), ProcessResource.plant3Dresource.Straight);\r
1155         G3DAPI.setWorldPosition(straight, v);\r
1156         straight.setRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength, length);\r
1157         return straight.getControlPoint();\r
1158         \r
1159     }\r
1160     \r
1161     private void connectControlPoints(PipeControlPoint previous, PipeControlPoint pcp, boolean reversed) {\r
1162         if (previous != null) {\r
1163                 PipeControlPoint sccp;\r
1164                 PipeControlPoint ocp;\r
1165                 if (previous.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)) {\r
1166                         sccp = previous;\r
1167                         ocp = sccp.getSubPoint().iterator().next();\r
1168                 } else if (previous.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)) {\r
1169                         ocp = previous;\r
1170                         sccp = ocp.getSubPointOf();\r
1171                 } else {\r
1172                         if (!reversed) {\r
1173                                         previous.setNext(pcp);\r
1174                                         pcp.setPrevious(previous);\r
1175                                 } else {\r
1176                                         previous.setPrevious(pcp);\r
1177                                         pcp.setNext(previous);\r
1178                                 }\r
1179                         return;\r
1180                 }\r
1181                 if (!reversed) {\r
1182                                 sccp.setNext(pcp);\r
1183                                 ocp.setNext(pcp);\r
1184                                 pcp.setPrevious(ocp);\r
1185                         } else {\r
1186                                 sccp.setPrevious(pcp);\r
1187                                 ocp.setPrevious(pcp);\r
1188                                 pcp.setNext(sccp);\r
1189                         }\r
1190                 \r
1191         }\r
1192     }\r
1193     \r
1194     private void endPiping() {\r
1195         state = ToolState.NOT_ACTIVE;\r
1196          \r
1197         if (controlPoints.size() > 2)   // if there's only two control points, filtering does nothing\r
1198             controlPoints = filterPoints();\r
1199         \r
1200         if (controlPoints.size() > 1) {\r
1201             parent.getSession().asyncWrite(new GraphRequestAdapter() {\r
1202                 @Override\r
1203                 public GraphRequestStatus perform(Graph graph) throws Exception {\r
1204                         PipeRun pipeline = null;\r
1205                     boolean reversed;\r
1206                     PipelineComponent beginComponent = new PipelineComponent(graph,beginComponentResource);\r
1207                     if (beginComponent.isInstanceOf(ProcessResource.plant3Dresource.Nozzle) ||\r
1208                                 selectedType == PositionType.SPLIT) {\r
1209 \r
1210                         \r
1211 //                      \r
1212                         pipeline = PipeRun.createDefault(graph);\r
1213                         ((ProcessEditor) parent).getPlant(graph).addChild(pipeline);\r
1214                         pipeline.setPipeDiameter(pipeDiameter);\r
1215                         pipeline.setTurnRadius(elbowRadius);\r
1216                         reversed = false;\r
1217                     } else if (beginComponent.isInstanceOf(ProcessResource.plant3Dresource.SizeChangeComponent)||\r
1218                                 beginComponent.isInstanceOf(ProcessResource.plant3Dresource.OffsetComponent)){\r
1219                         PipeControlPoint pcp = new PipeControlPoint(graph,selectedPort);\r
1220                         if (selectedType == PositionType.NEXT) {\r
1221                                 // get the piperun from offsetpoint\r
1222                                 reversed = false;\r
1223                                 pipeline = pcp.getSubPoint().iterator().next().getControlPointOfPipeRun();\r
1224                         } else if (selectedType == PositionType.PREVIOUS) {\r
1225                                 reversed = true;\r
1226                                 pipeline = pcp.getControlPointOfPipeRun();\r
1227                         } else {\r
1228                                 throw new RuntimeException("Wrong PsoitionType " + selectedType + " for a SizeChangeComponent");\r
1229                         }\r
1230                         \r
1231                     } else if (beginComponent.isInstanceOf(ProcessResource.plant3Dresource.PipelineComponent)) {\r
1232                         \r
1233                         pipeline = new PipeRun(beginComponent.getParent());\r
1234                         if (selectedType == PositionType.PREVIOUS) {\r
1235                                 reversed = true;\r
1236                         } else {\r
1237                                 reversed = false;\r
1238                         }\r
1239                     } else {\r
1240                         throw new RuntimeException("Cannot start routing pipe : object not supported!");\r
1241                     }\r
1242 \r
1243                     PipeControlPoint previous = null;\r
1244                     for (int i = 0; i < controlPoints.size(); i++) {\r
1245                         PipeControlPoint pcp = null;\r
1246                         if (i == 0) {\r
1247                             pcp = connectPipeStart(graph, pipeline,reversed);\r
1248 \r
1249                         } else {\r
1250                                 pcp = createInline(graph, pipeline, i);\r
1251                                 connectControlPoints(previous, pcp, reversed);\r
1252                                 previous = pcp;\r
1253                                 if (i == controlPoints.size() - 1) {\r
1254                                          pcp = connectPipeEnd(graph, pipeline, reversed);\r
1255                                 } else {\r
1256                                 \r
1257                                 pcp = createTurn(graph,pipeline,i);\r
1258                             }\r
1259                         }\r
1260                            \r
1261                         if (pcp != null) {\r
1262                                 connectControlPoints(previous, pcp, reversed);\r
1263                                 //pipeline.addSgetHasControlPointSet().add(pcp);\r
1264                                 previous = pcp;\r
1265                         }\r
1266                     }\r
1267                         return GraphRequestStatus.transactionComplete();\r
1268                 }\r
1269                 \r
1270                 @Override\r
1271                 public void requestCompleted(GraphRequestStatus status) {\r
1272                         endThreaded();\r
1273                 }\r
1274             });\r
1275 \r
1276                 \r
1277             \r
1278         } else {\r
1279             endThreaded();      \r
1280         }\r
1281     }\r
1282     \r
1283     private void endThreaded() {\r
1284         parent.getRenderingComposite().getDisplay().asyncExec(new Runnable() {\r
1285                         @Override\r
1286                         public void run() {\r
1287                                 end();\r
1288                         }\r
1289                 });\r
1290     }\r
1291 \r
1292     @Override\r
1293     public void init() {\r
1294         this.setText("Route pipe");\r
1295         this.setToolTipText("Starts routing a new pipeline");\r
1296         this.setImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/Straight.png"));\r
1297     }\r
1298 \r
1299     @Override\r
1300     public boolean usable(Graph g, List<Resource> resources) {\r
1301         if (resources.size() != 1) {\r
1302                 return false;\r
1303         }\r
1304         return checkStartNode(g,resources.get(0)).size() > 0;\r
1305     }\r
1306     \r
1307    \r
1308     \r
1309   public boolean acceptDrop(StructuredResourceSelection s, Resource[] ids) {\r
1310         if (s.size() != 1)\r
1311                 return false;\r
1312         if (ids == null)\r
1313                 return false;\r
1314         if (ids.length != 1)\r
1315                 return false;\r
1316         final Resource dropped = ids[0];\r
1317         final Resource target = s.iterator().next();\r
1318         GraphRequestWithResult<Boolean> query = new GraphRequestWithResult<Boolean>() {\r
1319                 @Override\r
1320                 public Boolean performWithResult(Graph g) throws Exception {\r
1321                         if(!g.isInstanceOf(dropped, ProcessResource.plant3Dresource.VariableLengthInlineComponent))\r
1322                                 return false;\r
1323                         // TODO : check that type is not abstract\r
1324                         List<Resource> list = new ArrayList<Resource>();\r
1325                         list.add(target);\r
1326                         return usable(g, list);\r
1327                 }\r
1328         };\r
1329         parent.getSession().syncRead(query);\r
1330         return query.getResult();\r
1331   }\r
1332   \r
1333    public void doDrop(StructuredResourceSelection s, Resource[] ids) {\r
1334            beginComponentResource = s.iterator().next(); \r
1335            parent.setCurrentAction(this);\r
1336    }\r
1337    \r
1338    public void setInfoText(String text) {\r
1339            \r
1340    }\r
1341 \r
1342 }