]> gerrit.simantics Code Review - simantics/3d.git/blob - org.simantics.plant3d/src/org/simantics/plant3d/actions/RoutePipeAction.java
Compiler warning elimination
[simantics/3d.git] / org.simantics.plant3d / src / org / simantics / plant3d / actions / RoutePipeAction.java
1 package org.simantics.plant3d.actions;
2
3 import java.awt.event.KeyEvent;
4 import java.awt.event.MouseEvent;
5 import java.awt.event.MouseWheelEvent;
6 import java.math.BigDecimal;
7 import java.util.ArrayList;
8 import java.util.HashSet;
9 import java.util.List;
10 import java.util.Set;
11
12 import javax.vecmath.Point3d;
13 import javax.vecmath.Tuple3d;
14 import javax.vecmath.Vector3d;
15
16 import org.simantics.db.Resource;
17 import org.simantics.g3d.math.MathTools;
18 import org.simantics.g3d.math.Ray;
19 import org.simantics.g3d.scenegraph.NodeMap;
20 import org.simantics.g3d.scenegraph.base.INode;
21 import org.simantics.g3d.tools.ConstraintDetector;
22 import org.simantics.g3d.vtk.gizmo.TranslateAxisGizmo;
23 import org.simantics.g3d.vtk.swt.InteractiveVtkComposite;
24 import org.simantics.g3d.vtk.swt.vtkSwtAction;
25 import org.simantics.g3d.vtk.utils.vtkUtil;
26 import org.simantics.plant3d.Activator;
27 import org.simantics.plant3d.gizmo.ConstraintPointGizmo;
28 import org.simantics.plant3d.gizmo.SplitPointSelectionGizmo;
29 import org.simantics.plant3d.gizmo.TerminalSelectionGizmo;
30 import org.simantics.plant3d.scenegraph.EndComponent;
31 import org.simantics.plant3d.scenegraph.InlineComponent;
32 import org.simantics.plant3d.scenegraph.Nozzle;
33 import org.simantics.plant3d.scenegraph.P3DRootNode;
34 import org.simantics.plant3d.scenegraph.PipeRun;
35 import org.simantics.plant3d.scenegraph.PipelineComponent;
36 import org.simantics.plant3d.scenegraph.TurnComponent;
37 import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint;
38 import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint.Direction;
39 import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint.PositionType;
40 import org.simantics.plant3d.scenegraph.controlpoint.PipingRules;
41 import org.simantics.plant3d.utils.ComponentUtils;
42 import org.simantics.utils.threads.ThreadUtils;
43 import org.simantics.utils.ui.ExceptionUtils;
44
45 import vtk.vtkProp;
46 import vtk.vtkTextActor;
47
48 public class RoutePipeAction extends vtkSwtAction {
49         enum LockType {
50                 X, Y, Z, XY, YZ, XZ, NONE, CUSTOM
51         };
52
53         LockType lock = LockType.NONE;
54         boolean lockForced;
55         private double BRANCH_SNAP_DISTANCE = 0.05;
56         private double NOZZLE_SNAP_DISTANCE = 0.05;
57         private static double BRANCH_DOT_PRODUCT = 0.95; // dot product value used for prevent branch creation
58         private static double ALIGN_DOT_PRODUCT = 0.99; // dot product for creating turn when connecting pipes
59
60         private double istep = 10.0;
61         private int decimals = 2;
62
63         private P3DRootNode root;
64         protected PipelineComponent startComponent;
65         protected PipeRun pipeRun;
66         private boolean allowBranches;
67
68         protected TranslateAxisGizmo translateAxisGizmo = new TranslateAxisGizmo();
69         private SplitPointSelectionGizmo splitPointSelectionGizmo;
70         private ConstraintPointGizmo constraintPointGizmo;
71         private TerminalSelectionGizmo terminalSelectionGizmo;
72         private NodeMap<Resource,vtkProp,INode> nodeMap;
73         
74         protected enum ToolState{NOT_ACTIVE, INITIALIZING, SELECTING_POSITION, SELECTING_SPLIT, ROUTING};
75         protected ToolState state = ToolState.NOT_ACTIVE;
76         
77         private ConstraintDetector detector;// = new DummyConstraintDetector();
78         
79         protected boolean useDefault = false;
80         protected Vector3d direction = null;
81         protected Vector3d previousPosition = null;
82         protected Vector3d currentPosition = null;
83         
84         boolean step = false;
85         
86         PipelineComponent endTo = null;
87         PositionType endType = null;
88         PipeControlPoint endPort = null;
89         
90         boolean reversed = false;
91         
92         private Set<PositionType> allowed = new HashSet<PositionType>();
93         
94         public RoutePipeAction(InteractiveVtkComposite panel, P3DRootNode root) {
95             this(panel,root, true);
96         }
97         
98         public RoutePipeAction(InteractiveVtkComposite panel, P3DRootNode root, boolean allowBranches) {
99                 super(panel);
100                 this.root = root;
101                 this.allowBranches = allowBranches;
102                 setText("Route Pipe");
103                 setImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/Straight.png"));
104                 nodeMap = root.getNodeMap();
105                 splitPointSelectionGizmo = new SplitPointSelectionGizmo(panel);
106                 terminalSelectionGizmo = new TerminalSelectionGizmo(panel);
107                 constraintPointGizmo = new ConstraintPointGizmo(panel);
108                 detector = new org.simantics.g3d.vtk.swt.ConstraintDetector(panel);
109         }
110         
111         public void setComponent(PipelineComponent component) {
112                 this.startComponent = component;
113                 allowed.clear();
114                 if (this.startComponent.getNext() == null)
115                         allowed.add(PositionType.NEXT);
116                 if (this.startComponent.getPrevious() == null && !(this.startComponent instanceof Nozzle))
117                         allowed.add(PositionType.PREVIOUS);
118                 if (allowBranches && this.startComponent instanceof InlineComponent && !this.startComponent.getControlPoint().isFixedLength())
119                         allowed.add(PositionType.SPLIT);
120                 setEnabled(allowed.size() > 0);
121         }
122         
123         public void deattach() {
124                 deactivate();
125                 startComponent = null;
126                 
127                 deattachUI();
128                 super.deattach();
129                 panel.refresh();
130         }
131         
132         public void attach() {
133                 if (startComponent == null)
134                         return;
135                 
136                 super.attach();
137                 ThreadUtils.asyncExec(panel.getThreadQueue(), new Runnable() {
138                         public void run() {
139 //                              attachUI();
140                                 try {
141                                         activate();
142                                 } catch (Exception e) {
143                                         deattach();
144                                         ExceptionUtils.logAndShowError(e);
145                                 }
146                                 
147                         }
148                 });
149                 
150         }
151         
152 //      private void attachUI() {
153 //              //panel.setCursor(activeCursor);
154 //              translateAxisGizmo.attach(panel.GetRenderer());
155 //      }
156         
157         private void deattachUI() {
158                 //panel.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
159                 panel.lock();
160                 if (translateAxisGizmo.isAttached())
161                         translateAxisGizmo.deattach();
162                 if (splitPointSelectionGizmo.isAttached())
163                         splitPointSelectionGizmo.deattach();
164                 if (terminalSelectionGizmo.isAttached())
165                         terminalSelectionGizmo.deattach();
166                 if (constraintPointGizmo.isAttached())
167                     constraintPointGizmo.deattach();
168                 if (infoActor != null) {
169                         panel.getRenderer().RemoveActor(infoActor);
170                         infoActor.Delete();
171                         infoActor = null;
172                 }
173                 panel.unlock();
174         }
175         
176         protected List<PipelineComponent> added = new ArrayList<PipelineComponent>();
177         
178         @Override
179         public boolean keyPressed(KeyEvent e) {
180                 if (e.getKeyCode() == KeyEvent.VK_ESCAPE)
181                         panel.useDefaultAction();
182                 if (lock != LockType.CUSTOM || !lockForced) {
183                         if ((e.getModifiersEx() & KeyEvent.SHIFT_DOWN_MASK) > 0) {
184                                 if (e.getKeyCode() == KeyEvent.VK_X) {
185                                         if (lock != LockType.XY && lock != LockType.XZ) {
186                                                 setLockType(LockType.XY, false);
187                                         } else if (lock == LockType.XY) {
188                                                 setLockType(LockType.XZ, false);
189                                         } else {
190                                                 setLockType(LockType.NONE, false);
191                                         }
192                                 }
193                                 if (e.getKeyCode() == KeyEvent.VK_Y) {
194                                         if (lock != LockType.XY && lock != LockType.YZ) {
195                                                 setLockType(LockType.XY, false);
196                                         } else if (lock == LockType.XY) {
197                                                 setLockType(LockType.YZ, false);
198                                         } else {
199                                                 setLockType(LockType.NONE, false);
200                                         }
201                                 }
202                                 if (e.getKeyCode() == KeyEvent.VK_Z) {
203                                         if (lock != LockType.XZ && lock != LockType.YZ) {
204                                                 setLockType(LockType.XZ, false);
205                                         } else if (lock == LockType.XZ) {
206                                                 setLockType(LockType.YZ, false);
207                                         } else {
208                                                 setLockType(LockType.NONE, false);
209                                         }
210                                 }
211                         } else {
212                                 if (e.getKeyCode() == KeyEvent.VK_X) {
213                                         if (lock != LockType.X)
214                                                 setLockType(LockType.X,false);
215                                         else
216                                                 setLockType(LockType.NONE,false);
217                                 }
218                                 if (e.getKeyCode() == KeyEvent.VK_Y) {
219                                         if (lock != LockType.Y)
220                                                 setLockType(LockType.Y,false);
221                                         else
222                                                 setLockType(LockType.NONE, false);
223                                 }
224                                 if (e.getKeyCode() == KeyEvent.VK_Z) {
225                                         if (lock != LockType.Z)
226                                                 setLockType(LockType.Z, false);
227                                         else
228                                                 setLockType(LockType.NONE, false);
229                                 }
230                                 if (e.getKeyCode() == KeyEvent.VK_L && direction != null) {
231                                     if (lock != LockType.CUSTOM)
232                         setLockType(LockType.CUSTOM, false);
233                     else
234                         setLockType(LockType.NONE, false);
235                                 }
236                         }
237                 }
238                 if (e.getKeyCode() == KeyEvent.VK_C) {
239                         useDefault = !useDefault;
240                         if (useDefault)
241                             setInfoText("Rotating camera");
242                         System.out.println("UseDefault " + useDefault);
243                 }
244                 
245                 
246                 
247                 
248                 update();
249                 return true;
250         }
251         
252         
253         private void update() {
254                 panel.refresh();
255         }
256         private void update(double x, double y) {
257                 switch (state) {
258                 case NOT_ACTIVE:
259                         return; // TODO : throw Exception?
260                 case INITIALIZING:
261                         return;
262                 case SELECTING_POSITION:
263                         return;
264                 case SELECTING_SPLIT:
265                         return;
266                 case ROUTING:
267                         updateRouting(x,y);
268                         break;
269                 }
270                 return;
271         }
272         
273         boolean startRemovable = false;
274         
275         protected void activate() throws Exception {
276                 state = ToolState.INITIALIZING;
277                 added.clear();
278                 
279                 if (allowed.size() == 1) {
280                         pipeRun = startComponent.getPipeRun();
281                         PipeControlPoint start = startComponent.getControlPoint();
282                         boolean requiresBranching = false;
283                         if (start.getNext() == null)
284                                 reversed = false;
285                         else if (start.getPrevious() == null) {
286                                 reversed = true;
287                         } else {
288                                 requiresBranching = true;
289                         }
290                         
291                         if (requiresBranching) {
292                                 activateSplit(start);
293                         } else {
294                                 activateNextPrev(start);
295                         }
296                 } else if (allowed.size() == 0) {
297                         panel.useDefaultAction();
298                         state = ToolState.NOT_ACTIVE;
299                         return;
300                 } else {
301                         terminalSelectionGizmo.setComponent(startComponent, allowed);
302                         terminalSelectionGizmo.attach(panel);
303                         state = ToolState.SELECTING_POSITION;
304                         update();
305                 }
306                 
307         }
308         
309         
310         
311         protected void activateNextPrev(PipeControlPoint start) throws Exception{
312                 if (!reversed && start.isDualInline())
313                         start = start.getSubPoint().get(0);
314                 else if (reversed && start.isDualSub())
315                         start = start.parent;
316                 
317                 pipeRun = start.getPipeRun();
318                 setPreviousPosition(start.getWorldPosition());
319                 
320                 boolean startWithTurn = false;
321                 if (startComponent instanceof Nozzle) {
322                         direction = startComponent.getControlPoint().getDirectedControlPointDirection();
323                         lock = LockType.CUSTOM;
324                         lockForced = true;
325                 } else if (startComponent instanceof PipelineComponent){
326                         if (startComponent instanceof InlineComponent) {
327                                 direction = startComponent.getControlPoint().getPathLegDirection(reversed ? Direction.PREVIOUS : Direction.NEXT);
328                                 lock = LockType.CUSTOM;
329                                 lockForced = true;
330                                 if (((InlineComponent) startComponent).isVariableLength()) {
331                                         startWithTurn = true;
332                                         direction = null;
333                                         lock = LockType.NONE;
334                                         lockForced = false;
335                                 } 
336                                 Vector3d v = new Vector3d();
337                                 if (!reversed) {
338                                         start.getControlPointEnds(v, previousPosition);
339                                 } else {
340                                         start.getControlPointEnds(previousPosition,v);
341                                 }
342                         } else if (startComponent instanceof TurnComponent) {
343                                 if (start.asFixedAngle()) {
344                                         direction = startComponent.getControlPoint().getPathLegDirection(reversed ? Direction.PREVIOUS : Direction.NEXT);
345                                         lock = LockType.CUSTOM;
346                                         lockForced = start.isFixedAngle();
347                                 } else {
348                                         direction = null;
349                                         lock = LockType.NONE;
350                                         lockForced = false;
351                                 }
352                         } else if (startComponent instanceof EndComponent) {
353                                 throw new Exception("Not supported");
354                         }
355                         
356                 } else {
357                         throw new Exception("Not supported");
358                 }
359                 currentPosition = new Vector3d(previousPosition);
360                 state = ToolState.ROUTING;
361                 if (direction != null) {
362                         direction.normalize();
363                         
364                 } 
365                 startRemovable = start.isDeletable();
366                 start.setDeletable(false);
367                 
368                 if (startWithTurn) {
369                         addPoint();
370                 } else {
371                         if (direction != null)
372                                 currentPosition.add(direction);
373                         InlineComponent straight = ComponentUtils.createStraight(root);
374                         PipeControlPoint straightCP = straight.getControlPoint();
375                         straight.setName(pipeRun.getUniqueName("Pipe"));
376                         pipeRun.addChild(straight);
377                         added.add(straight);
378         
379                         if (!reversed) {
380                                 start.setNext(straightCP);
381                                 straightCP.setPrevious(start);
382                         } else {
383                                 start.setPrevious(straightCP);
384                                 straightCP.setNext(start);
385                         }
386                 }
387                 translateAxisGizmo.attach(panel);
388                 setPreviousPosition(previousPosition);
389                 updateCurrentPoint();
390         }
391         
392         protected void setPreviousPosition(Vector3d v) {
393                 previousPosition = new Vector3d(v);
394                 if (translateAxisGizmo.isAttached())
395                         translateAxisGizmo.setPosition(previousPosition);
396         }
397         
398         private void activateBranch(PipeControlPoint start) throws Exception{
399                 pipeRun = start.getPipeRun();
400                 setPreviousPosition(start.getWorldPosition());
401                 
402                 direction = null;
403                 lock = LockType.NONE;
404                 
405                 currentPosition = new Vector3d(previousPosition);
406                 state = ToolState.ROUTING;
407                 if (direction != null) {
408                         direction.normalize();
409                         
410                 } 
411                 startRemovable = start.isDeletable();
412                 start.setDeletable(false);
413                 
414                 
415                 if (direction != null)
416                         currentPosition.add(direction);
417                 InlineComponent straight = ComponentUtils.createStraight(root);
418                 PipeControlPoint straightCP = straight.getControlPoint();
419                 straight.setName(pipeRun.getUniqueName("Pipe"));
420                 pipeRun.addChild(straight);
421                 added.add(straight);
422
423                 if (!reversed) {
424                         start.setNext(straightCP);
425                         straightCP.setPrevious(start);
426                         
427                 } else {
428                         start.setPrevious(straightCP);
429                         straightCP.setNext(start);
430                         
431                 }
432                 
433                 translateAxisGizmo.attach(panel);
434                 setPreviousPosition(previousPosition);
435                 updateCurrentPoint();
436         }
437         
438         private void activateSplit(PipeControlPoint start) throws Exception{
439                 Point3d p1 = new Point3d();
440                 Point3d p2 = new Point3d();
441                 start.getInlineControlPointEnds(p1, p2);
442                 splitPointSelectionGizmo.setSplit(p1, p2);
443                 splitPointSelectionGizmo.attach(panel);
444                 state = ToolState.SELECTING_SPLIT;
445         }
446         public void deactivate() {
447             if (added.size() > 0) {
448             for (PipelineComponent component : added) {
449                         component.getControlPoint().setDeletable(true);
450                 }
451                 
452             for (PipelineComponent comp : added) {
453                 PipingRules.requestUpdate(comp.getControlPoint());
454             }
455             try {
456                 PipingRules.update();
457                 nodeMap.commit("Route pipe");
458             } catch (Exception e) {
459                 ExceptionUtils.logAndShowError(e);
460             }
461             added.clear();        
462         }
463                 
464                 startComponent.getControlPoint().setDeletable(startRemovable);
465
466                 direction = null;
467
468                 setLockType(LockType.NONE, true);
469                 startComponent = null;
470                 endTo = null;
471                 endPort = null;
472                 endType = null;
473                 pipeRun = null;
474                 allowed.clear();
475                 currentPosition = null;
476                 previousPosition = null;
477                 startRemovable = false;
478                 detector.clearConstraintHighlights();
479                 state = ToolState.NOT_ACTIVE;
480                 setEnabled(false);              
481
482         }
483         
484         private void setLockType(LockType type, boolean force) {
485                 if (force || (lock != LockType.CUSTOM || !lockForced) ) {
486                         lock = type;
487                         
488                         switch (lock) {
489                         case CUSTOM:
490                         case NONE:
491                                 translateAxisGizmo.setType(6);
492                                 break;
493                         case X:
494                                 translateAxisGizmo.setType(0);
495                                 break;
496                         case Y:
497                                 translateAxisGizmo.setType(1);
498                                 break;
499                         case Z:
500                                 translateAxisGizmo.setType(2);
501                                 break;
502                         case XY:
503                                 translateAxisGizmo.setType(3);
504                                 break;
505                         case XZ:
506                                 translateAxisGizmo.setType(4);
507                                 break;
508                         case YZ:
509                                 translateAxisGizmo.setType(5);
510                                 break;
511                                 
512                         }
513                 }
514         }
515         
516         @Override
517         public boolean mousePressed(MouseEvent e) {
518                 if (useDefault) {
519                         getDefaultAction().mousePressed(e);
520                 }
521                 return true;
522         }
523
524         @Override
525         public boolean mouseReleased(MouseEvent e) {
526                 if (useDefault) {
527                         getDefaultAction().mouseReleased(e);
528                 }
529                 return true;
530         }
531         
532         @Override
533         public boolean mouseWheelMoved(MouseWheelEvent e) {
534                 if (useDefault) {
535                         getDefaultAction().mouseWheelMoved(e);
536                 }
537                 return true;
538         }
539         
540         @Override
541         public boolean mouseClicked(MouseEvent e) {
542                 if (useDefault) {
543                         getDefaultAction().mouseClicked(e);
544                         return true;
545                 }
546                 if (state == ToolState.ROUTING) {
547                         try {
548                                 if (e.getClickCount() == 1) {
549                                         if (e.getButton() == MouseEvent.BUTTON1) {
550                                                 if (this.added.size() > 0) {
551                                                         
552                                                         setLockType(LockType.NONE,true);
553                                                         if (endTo != null) {
554                                                                 
555                                                                 endPiping();
556                                                         } else {
557                                                                 addPoint();
558                                                         }
559                                                 } else {
560                                                         throw new RuntimeException("RoutePipeAction initlialization has been failed, no added components found");
561                 //                      // user was selecting position of branch
562                 //                    lastPoint.set(startPoint);
563                 //                    controlPoints.add(new Point3d(startPoint));
564                 //                    if (selectionLine != null)
565                 //                      selectionLine.removeFromParent();
566                 //                    selectionLine = null;
567                                                 }
568                                         } else if (e.getButton() ==MouseEvent.BUTTON2){
569                                             updateConstraints();
570                                         } else if (e.getButton() == MouseEvent.BUTTON3){      
571                                                 endPiping();
572                                         }
573                                 }
574                         } catch(Exception err) {
575                                 err.printStackTrace();
576                         }
577                 } else if (state == ToolState.SELECTING_POSITION) {
578                         if (e.getClickCount() == 1 && e.getButton() == MouseEvent.BUTTON1) {
579                                 int type = panel.getPickType();
580                                 //panel.setPickType(0);
581                                 panel.setPickType(5);
582                                 vtkProp[] picked = panel.pick(e.getX(), e.getY());
583                                 panel.setPickType(type);
584                                 PositionType position = terminalSelectionGizmo.getPickedPosition(picked);
585                                 if (position != null) {
586                                         terminalSelectionGizmo.deattach();
587                                         try {
588                                         if (position == PositionType.SPLIT) {
589                                                 activateSplit(startComponent.getControlPoint());
590                                         } else if (position == PositionType.NEXT || position == PositionType.PREVIOUS) {
591                                                 reversed = position == PositionType.PREVIOUS;
592                                                 activateNextPrev(startComponent.getControlPoint());
593                                         } else {
594                                                 panel.useDefaultAction();
595                                         }
596                                         } catch (Exception err) {
597                                                 ExceptionUtils.logAndShowError(err);
598                                                 panel.useDefaultAction();
599                                         }
600                                 }
601                         } 
602                 } else if (state == ToolState.SELECTING_SPLIT) {
603                         if (e.getClickCount() == 1 && e.getButton() == MouseEvent.BUTTON1) {
604                                 Tuple3d t = splitPointSelectionGizmo.getSplitPoint();
605                                 splitPointSelectionGizmo.deattach();
606                                 if (t == null) {
607                                         panel.useDefaultAction();
608                                         return true;
609                                 }
610                                 try {
611                                         Vector3d pos = new Vector3d(t);
612                                         InlineComponent branchSplit = ComponentUtils.createBranchSplit((InlineComponent)startComponent, pos);
613                                         PipeControlPoint branchSplitCP = branchSplit.getControlPoint();
614                                         reversed = false;
615                                         PipeRun newRun = new PipeRun();
616                                         String n = root.getUniqueName("PipeRun");
617                                         newRun.setName(n);
618                                         root.addChild(newRun);
619                                         PipeControlPoint pcp = new PipeControlPoint(branchSplit,newRun);
620                                         branchSplitCP.children.add(pcp);
621                                         pcp.parent = branchSplitCP;
622                                         pcp.setWorldOrientation(branchSplitCP.getWorldOrientation());
623                                         pcp.setWorldPosition(branchSplitCP.getWorldPosition());
624                                         startComponent = branchSplit;
625                                         activateBranch(pcp);
626                                 } catch (Exception err) {
627                                         ExceptionUtils.logAndShowError(err);
628                                         panel.useDefaultAction();
629                                 }
630                         }
631                 }
632                 return true;
633         }
634         
635         private void updateConstraints() {
636             detector.clearConstraints();
637             constraintPointGizmo.clearPositions();
638             if (hoverObject == null) {
639                 if (constraintPointGizmo.isAttached())
640                     constraintPointGizmo.deattach();
641                 return;
642             }
643             if (hoverObject instanceof Nozzle) {
644             Nozzle n = (Nozzle)hoverObject;
645             detector.addContraintPoint(new Point3d(n.getWorldPosition()));
646             } else if (hoverObject instanceof InlineComponent) {
647                 InlineComponent c = (InlineComponent)hoverObject;
648                 Point3d p1 = new Point3d();
649                 Point3d p2 = new Point3d();
650                 c.getEnds(p1, p2);
651                 detector.addContraintPoint(p1);
652                 detector.addContraintPoint(p2);
653                 detector.addContraintPoint(new Point3d(c.getWorldPosition()));
654             } else if (hoverObject instanceof TurnComponent) {
655                 TurnComponent n = (TurnComponent)hoverObject;
656             detector.addContraintPoint(new Point3d(n.getWorldPosition()));
657             }
658             if (detector.getConstraintPoints().size() > 0) {
659                 for (Point3d p : detector.getConstraintPoints()) {
660                     constraintPointGizmo.addPosition(new Vector3d(p));
661                 }
662                 if (constraintPointGizmo.isAttached())
663                     constraintPointGizmo.deattach();
664                 constraintPointGizmo.attach(panel);
665             }
666         }
667         
668         @Override
669         public boolean mouseMoved(MouseEvent e) {
670                 if (useDefault) {
671                         getDefaultAction().mouseMoved(e);
672                         return true;
673                 }
674                 step = ((e.getModifiers() & MouseEvent.CTRL_MASK) > 0);
675                 update(e.getX(), e.getY());
676                 return true;
677         }
678         
679         @Override
680         public boolean mouseDragged(MouseEvent e) {
681                 if (useDefault)
682                         getDefaultAction().mouseDragged(e);
683                 return true;
684         }
685         
686
687         
688         
689         private List<INode> isOverNode(int x, int y) {
690                 List<INode> nodes = new ArrayList<INode>(); 
691                 vtkProp picked[] = panel.pick2(x, y);
692                 if (picked !=null) {
693                         for (int i = 0; i < picked.length; i++) {
694                                 nodes.add(nodeMap.getNode(picked[i]));
695                         }
696                 }
697                 return nodes;
698         }
699         
700         INode hoverObject = null;
701
702         protected void updateRouting(double x, double y) {
703                 if (useDefault) {
704                         //panel.getDefaultAction().update();
705                         return;
706                 }
707                 
708                 endTo = null;
709                 endType = null;
710                 endPort = null;
711
712                 Ray ray = vtkUtil.createMouseRay(panel.getRenderer(),x, y);
713                 Vector3d o = new Vector3d(ray.pos);
714                 Vector3d d = ray.dir;
715                 
716                 
717                 if (!updateCurrentPoint(o, d))
718                         return;
719                 //Point3d startPoint = new Point3d();
720                 double mu[] = new double[2];
721                 
722                 
723                 
724                 
725                 
726                 List<INode> hover = isOverNode((int)x,(int)y);
727                 if (hover.size() > 0) {
728                         hoverObject = hover.get(0);
729                 } else {
730                     hoverObject = null;
731                 }
732 //              System.out.println(hoverObject + " " + getLast());
733                 if (hoverObject != null) {
734                         if (hoverObject.equals(getLast()) ) {
735                                 boolean set = false;
736                                 for (int i = 1; i < hover.size(); i++) {
737                                         hoverObject = hover.get(i);
738                                         if (!getLast().equals(hoverObject)) {
739                                                 set = true;
740                                                 break;
741                                         }
742                                 }
743                                 if (!set)
744                                         hoverObject = null;
745                         }
746                 }
747 //              System.out.println(hoverObject);
748                 if (hoverObject != null) {
749
750                         if (lock == LockType.NONE) {
751                                 if (hoverObject instanceof Nozzle && endingToNozzle(hoverObject,o,d)) {
752                                         endTo = (Nozzle)hoverObject;
753                                 } else if (hoverObject instanceof InlineComponent && ((InlineComponent)hoverObject).isVariableLength()) {
754                                         endTo = (InlineComponent)hoverObject;
755                                         endType = endingToStraight(endTo,mu,o,d);     
756                                         if (endType == null)
757                                             endTo = null;
758                                 } else if (hoverObject instanceof PipelineComponent && (endPort = endingToComponent(hoverObject,o,d)) != null) {
759                                         endTo = (PipelineComponent)hoverObject;
760                                 } else {
761                                         updateRoute(o,d); 
762                                 }
763                         } else {  
764                                 if (hoverObject instanceof InlineComponent && ((InlineComponent)hoverObject).isVariableLength() && (endType = endingLockToStraight(hoverObject,mu, new Point3d(currentPosition))) != null) {
765                                         endTo = (InlineComponent)hoverObject;
766                                 } else if (hoverObject instanceof Nozzle && endingLockToNozzle(hoverObject)) {
767                                         endTo = (Nozzle)hoverObject;
768                                 } else if ((hoverObject instanceof PipelineComponent) &&  ((endPort = endingLockToComponent(hoverObject)) != null)) {
769                                         endTo = (PipelineComponent)hoverObject;
770                                 } else {
771                                         updateRoute(o,d);
772                                 }
773                         }
774                         if (added.contains(endTo))
775                                 endTo = null;
776
777                 } else {
778                         updateRoute(o,d);
779                 }
780                 
781                 panel.refresh();
782         }
783         
784         protected boolean updateCurrentPoint(Vector3d o, Vector3d d) {
785
786                 Vector3d point = new Vector3d(this.previousPosition);
787                 
788                 switch(lock) {
789                 case X:
790                         MathTools.intersectStraightStraight(point, new Vector3d(1.0,0.0,0.0), o,d, currentPosition, new Vector3d());
791                         if (step) {
792                                 currentPosition.x = Math.round(istep * currentPosition.x) / istep;
793                                 BigDecimal bx = new BigDecimal(currentPosition.x);
794                                 bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);
795                                 currentPosition.x = bx.doubleValue();
796                         }
797                         break;
798                 case Y:
799                         MathTools.intersectStraightStraight(point, new Vector3d(0.0,1.0,0.0), o,d, currentPosition, new Vector3d());
800                         if (step) {
801                                 currentPosition.y = Math.round(istep * currentPosition.y) / istep;
802                                 BigDecimal bx = new BigDecimal(currentPosition.y);
803                                 bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);
804                                 currentPosition.y = bx.doubleValue();
805                         }
806                         break;
807                 case Z:
808                         MathTools.intersectStraightStraight(point, new Vector3d(0.0,0.0,1.0), o,d, currentPosition, new Vector3d());
809                         if (step) {
810                                 currentPosition.z = Math.round(istep * currentPosition.z) / istep;
811                                 BigDecimal bx = new BigDecimal(currentPosition.z);
812                                 bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);
813                                 currentPosition.z = bx.doubleValue();
814                         }break;
815                 case XY:
816                         MathTools.intersectStraightPlane(o, d, point, new Vector3d(0.0,0.0,1.0), currentPosition);
817                         break;
818                 case XZ:
819                         MathTools.intersectStraightPlane(o, d, point, new Vector3d(0.0,1.0,0.0), currentPosition);
820                         break;
821                 case YZ:
822                         MathTools.intersectStraightPlane(o, d, point, new Vector3d(1.0,0.0,0.0), currentPosition);
823                         break;
824                 case NONE:
825                         Vector3d normal = new Vector3d(panel.getRenderer().GetActiveCamera().GetDirectionOfProjection());
826                         normal.normalize();
827                         
828                         MathTools.intersectStraightPlane(o, d, point, normal, currentPosition);
829                         break;
830                 case CUSTOM:
831                         MathTools.intersectStraightStraight(point, new Vector3d(direction), o,d, currentPosition, new Vector3d());
832                         double dist = MathTools.distanceFromPlane(new Vector3d(currentPosition), direction, previousPosition);
833                         if (dist < 0.0)
834                                 currentPosition.set(previousPosition);
835                         break;
836                 default:
837                         return false;
838                 }
839                 return true;
840         }
841         
842         @SuppressWarnings("unused")
843         private Vector3d getLockDir() {
844                 switch (lock) {
845                 case CUSTOM:
846                         return direction;
847                 case X:
848                         return new Vector3d(1,0,0);
849                 case Y:
850                         return new Vector3d(0,1,0);
851                 case Z:
852                         return new Vector3d(0,0,1);
853                 default:
854                         return null;
855                 }
856         }
857         
858         protected void updateRoute(Vector3d o, Vector3d d) {
859                 detector.clearConstraintHighlights();
860                 Point3d previousPipePoint = new Point3d(previousPosition);
861                 String s = "";
862                 if (lock == LockType.NONE) {
863                         Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint));
864                         if (p != null)
865                                 currentPosition = new Vector3d(p);
866                         s += detector.getSnapString();
867
868                 } else {
869                         Vector3d dir = new Vector3d(currentPosition);
870                         dir.sub(previousPipePoint);
871                         Point3d p = detector.getPointSnap(new Vector3d(previousPipePoint), dir);
872                         if (p != null)
873                                 currentPosition = new Vector3d(p);
874                         s += detector.getSnapString();
875
876                 }
877 //              System.out.println(previousPosition + " -> " + currentPosition);
878 //              double dist = MathTools.distance(previousPosition, currentPosition);
879 //              if (dist < pipeRun.getTurnRadius()) {
880 //                      s += "Too close";
881 //                      Vector3d v = new Vector3d(currentPosition);
882 //                      v.sub(previousPosition);
883 //                      double vl = v.length();
884 //                      if (vl > MathTools.NEAR_ZERO) {
885 //                              v.scale(1.0/vl);
886 //                      } else {
887 //
888 //                              return;
889 //                      }
890 //                      v.scale(pipeRun.getTurnRadius());
891 //                      v.add(previousPosition);
892 //                      currentPosition.set(v);
893 //              }
894                 
895                 updateCurrentPoint();
896                 s += currentPosition.toString();
897                 setInfoText(s);
898         }
899         
900         vtkTextActor infoActor;
901         
902         private void setInfoText(String text) {
903                 //System.out.println(text);
904                 if (infoActor == null) {
905                         infoActor = new vtkTextActor();
906                         infoActor.GetTextProperty().SetColor(0.0, 0.0, 0.0);
907                         infoActor.GetTextProperty().ShadowOff();
908                         infoActor.GetTextProperty().ItalicOff();
909                         infoActor.GetTextProperty().BoldOff();
910                         infoActor.GetTextProperty().SetFontSize(18);
911                         infoActor.GetTextProperty().Delete();
912                         infoActor.GetProperty().SetColor(0.0, 0.0, 0.0);
913                         infoActor.GetProperty().Delete();
914
915                         
916                         infoActor.SetPosition(10,10);
917                         panel.getRenderer().AddActor(infoActor);
918                 }
919                 infoActor.SetInput(text);
920         }
921         
922         private boolean endingToNozzle(INode nozzleNode,Vector3d o, Vector3d d) {
923                 Nozzle nozzle = (Nozzle)nozzleNode;
924                 PipeControlPoint pcp  =nozzle.getControlPoint();
925                 if (pcp != null && (pcp.getNext() != null ||
926                                                         pcp.getPrevious() != null))
927                         return false; // nozzle is already connected to pipe
928                 currentPosition = pcp.getWorldPosition();
929                 Point3d previousPipePoint = new Point3d(previousPosition);
930                 Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint));
931                 if (p != null) {
932                         if (MathTools.distance(p, currentPosition) > NOZZLE_SNAP_DISTANCE) {
933                                 return false;
934                         }
935                 } 
936                 
937                 updateCurrentPoint();
938                 
939                 setInfoText("Connect to nozzle " + currentPosition);
940                 return true;
941         
942         }
943         
944         private PositionType endingToStraight(INode straightNode, double mu[], Vector3d o, Vector3d d) {
945 //          if (!allowBranches) {
946 //              updateCurrentPoint();
947 //            return null;
948 //          }
949                 InlineComponent s = (InlineComponent)straightNode;
950                 
951                 Point3d sStart = new Point3d();
952                 Point3d sEnd = new Point3d();
953                 s.getEnds(sStart, sEnd);
954                 //detector.clearConstraintHighlights();
955                 
956                 Point3d previousPipePoint = new Point3d(previousPosition);
957                 Point3d currentPipePoint = new Point3d(currentPosition);
958                 //String st = "";
959                 if (lock == LockType.NONE) {
960                         Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint));
961                         if (p != null) {
962                                 currentPosition = new Vector3d(p);
963                                 // snapping is detected, check if snapped point can create branch with straight
964                                 PositionType t = endingLockToStraight(s, mu, currentPipePoint);
965                                 if (t != null)
966                                         return t;
967                                 // if not, we'll have to remove highlight that was added when snapped point was detected
968                                 detector.clearConstraintHighlights();   
969                         }
970                         
971                         Vector3d sDir = new Vector3d(sEnd);
972                         sDir.sub(sStart);
973                         MathTools.intersectStraightStraight(sStart, sDir, o, d, currentPosition, new Point3d(), mu);
974                         
975
976                 } else {
977                         throw new RuntimeException("Lock shouldn't be on");
978
979                 }
980                 
981                 updateCurrentPoint();
982                 
983                 // branch point must lie between straight's ends. If connection point is exactly
984                 // on straight end user may want to connect pipes to each other
985                 // TODO : take account sizes of inline components)
986                 return endingToStraight(mu, s, sStart, sEnd, currentPipePoint);
987         }
988         
989         private PositionType endingToStraight(double mu[], InlineComponent s, Point3d sStart, Point3d sEnd , Point3d currentPipePoint) {
990             String info = "";
991             
992             boolean connectPrev = false;
993         boolean connectNext = false;
994         boolean branch = false;
995         if (mu[0] < 0.1) {
996             connectPrev = true;
997         }
998         else if (mu[0] > 0.9) {
999             connectNext = true;
1000         }
1001
1002           
1003         if (connectPrev) {
1004             PipeControlPoint pcp = s.getControlPoint();
1005             if (pcp.getPrevious() != null)
1006                 connectPrev = false;
1007         } else if (connectNext) {
1008             PipeControlPoint pcp = s.getControlPoint();
1009             if (pcp.getNext() != null)
1010                 connectNext = false;
1011         } else {
1012             Vector3d dir = s.getControlPoint().getPathLegDirection(Direction.NEXT);
1013             Vector3d currDir = getLast().getControlPoint().getPathLegDirection(Direction.NEXT);
1014             dir.normalize();
1015             currDir.normalize();
1016             double dot = dir.dot(currDir);
1017             System.out.println(dot + " " + currDir + " " + dir);
1018             if (dot > BRANCH_DOT_PRODUCT || dot < -BRANCH_DOT_PRODUCT) {
1019                 // pipes are almost in the same direction, creating a branch is not feasible.
1020                 branch = false;
1021             } else {
1022                 branch = true;
1023             }
1024         }
1025         
1026             
1027         if (connectNext || connectPrev)
1028             info += "Connect pipes :";
1029         else if (branch)
1030             info += "Create a Branch :";
1031         
1032         setInfoText(info + currentPosition + " " + Math.max(0.0, Math.min(mu[0], 1.0)));
1033         if (connectNext) {
1034             currentPosition.set(sEnd);
1035             updateCurrentPoint();
1036             return PositionType.NEXT;
1037         } else if (connectPrev){
1038             currentPosition.set(sStart);
1039             updateCurrentPoint();
1040             return PositionType.PREVIOUS;
1041         } else if (branch && allowBranches) {
1042             return PositionType.SPLIT;
1043         } else {
1044             currentPosition.set(currentPipePoint);
1045             updateCurrentPoint();
1046             return null;
1047         }
1048         }
1049         
1050         private PipeControlPoint endingToComponent(INode componentNode, Vector3d o, Vector3d d) {
1051                 PipelineComponent component = (PipelineComponent)componentNode;
1052                 PipeControlPoint pcp = component.getControlPoint();
1053                 if (component instanceof EndComponent) {
1054                         if (pcp.getNext() != null || pcp.getPrevious() != null)
1055                                 return null;
1056                         return pcp;
1057                 } else if (component instanceof TurnComponent) {
1058                         if (pcp.getNext() == null || pcp.getPrevious() == null)
1059                                 return pcp;
1060                         return null;
1061                 } else if (component instanceof InlineComponent) {
1062                         // TODO : scan all empty pcps of the component and select closest one.
1063                         if (pcp.getNext() == null || pcp.getPrevious() == null)
1064                                 return pcp;
1065                         return null;
1066                 }
1067
1068                 return null;
1069         }
1070         
1071         private PositionType endingLockToStraight(INode straightNode, double mu[], Point3d currentPipePoint) {
1072 //          if (!allowBranches) {
1073 //            updateCurrentPoint();
1074 //            return null;
1075 //        }
1076                 InlineComponent s = (InlineComponent)straightNode;
1077                 Point3d sStart = new Point3d();
1078                 Point3d sEnd = new Point3d(); 
1079                 s.getControlPoint().getInlineControlPointEnds(sStart, sEnd);  
1080                 Vector3d sDir = new Vector3d(sEnd);
1081                 sDir.sub(sStart);
1082                 Vector3d dir = new Vector3d(currentPosition);
1083                 Point3d prev = new Point3d(previousPosition);
1084                 dir.sub(prev);
1085                 // intersection point in pipe where branch would be inserted to
1086                 Vector3d branchPoint = new Vector3d();
1087                 // intersection point in straight pipe that is currently routed
1088                 Vector3d routePoint = new Vector3d();
1089                 MathTools.intersectStraightStraight(sStart, sDir, new Vector3d(prev), dir, branchPoint, routePoint, mu);
1090                 routePoint.sub(branchPoint);
1091                 // startPoint of branch must be between pipe ends
1092                 // TODO : take account sizes of elbows (or other components)
1093                 // branch point must be between pipe ends and intersection points must be quite close to each other
1094                 
1095                 if (routePoint.lengthSquared() > BRANCH_SNAP_DISTANCE)
1096                     return null;
1097                 
1098                 return endingToStraight(mu, s, sStart, sEnd, currentPipePoint);
1099                 
1100 //              if (mu[0] > 0.0 && mu[0] < 1.0 && routePoint.lengthSquared() < BRANCH_SNAP_DISTANCE) {
1101 //                      currentPosition.set(branchPoint);
1102 //                      
1103 //                      updateCurrentPoint();
1104 //                      
1105 //                      setInfoText("Create a branch (l) :" + currentPosition + " " + Math.max(0.0, Math.min(mu[0], 1.0)) + " " + routePoint.lengthSquared());
1106 //                      return PositionType.SPLIT;
1107 //              }
1108 //              return null;
1109         }
1110         
1111         private boolean endingLockToNozzle(INode nozzleNode) {
1112                 Nozzle nozzle = (Nozzle)nozzleNode;
1113                 Vector3d dir = new Vector3d(currentPosition);
1114                 Point3d prev = new Point3d(previousPosition);
1115                 dir.sub(prev);
1116                 Vector3d nozzleLoc = nozzle.getWorldPosition();
1117                 double u[] = new double[1];
1118                 Vector3d closest = MathTools.closestPointOnStraight(new Point3d(nozzleLoc), new Point3d(prev), new Vector3d(dir), u);
1119                 double dist = MathTools.distanceSquared(nozzleLoc,closest);
1120                 if (dist < BRANCH_SNAP_DISTANCE) {
1121                         // FIXME : directions should be checked (insert an elbow)
1122                         currentPosition.set(nozzleLoc);
1123                         updateCurrentPoint();
1124                         setInfoText("Connect to nozzle (l) :" + currentPosition);
1125                         return true;
1126                 } 
1127                 //System.out.println(u[0]);
1128                 return false;
1129         }
1130         
1131         private PipeControlPoint endingLockToComponent(INode componentNode) {
1132                 // we'll must scan all free pcp's and their direction to accept the connection.
1133                 return null;
1134         }
1135         
1136         protected void addTurn() throws Exception{
1137             InlineComponent previous = (InlineComponent)getLast();
1138         PipeControlPoint previousCP = previous.getControlPoint();
1139         TurnComponent turn = ComponentUtils.createTurn(root);
1140         PipeControlPoint turnCP = turn.getControlPoint();
1141         turn.setName(pipeRun.getUniqueName("Elbow"));
1142         pipeRun.addChild(turn);
1143         added.add(turn);
1144         turnCP.setDeletable(false); // mark turnCP nonDeletable so that PipingRules won't delete it immediately.
1145         if (!reversed) {
1146             previousCP.setNext(turnCP);
1147             turnCP.setPrevious(previousCP);
1148         } else {
1149             previousCP.setPrevious(turnCP);
1150             turnCP.setNext(previousCP);
1151         }
1152         
1153         turnCP.setWorldPosition(currentPosition);
1154         turnCP.setTurnAngle(0.0);
1155         turnCP.setLength(0.0);
1156         
1157         }
1158         
1159         protected void addStraight() throws Exception{
1160         TurnComponent turn = (TurnComponent)getLast();
1161         PipeControlPoint turnCP = turn.getControlPoint();
1162         
1163         InlineComponent straight = ComponentUtils.createStraight(root);
1164         
1165         PipeControlPoint straightCP = straight.getControlPoint();
1166         straight.setName(pipeRun.getUniqueName("Pipe"));
1167         
1168         
1169         pipeRun.addChild(straight);
1170         
1171         added.add(straight);
1172         
1173         
1174         
1175         if (!reversed) {
1176             turnCP.setNext(straightCP);
1177             straightCP.setPrevious(turnCP);
1178         } else {
1179             turnCP.setPrevious(straightCP);
1180             straightCP.setNext(turnCP);
1181         }
1182         
1183         turnCP.setWorldPosition(currentPosition);
1184         turnCP.setTurnAngle(0.0);
1185         turnCP.setLength(0.0);
1186         straightCP.setWorldPosition(currentPosition);
1187         straightCP.setLength(0.0);
1188             
1189         }
1190         
1191         protected void addPoint() throws Exception {
1192                 addTurn();
1193                 addStraight();
1194                 setPreviousPosition(currentPosition);
1195                 updateCurrentPoint();
1196                 
1197                 
1198                 
1199         }
1200         
1201         /**
1202          * Updates tool graphics for current point 
1203          */
1204         protected void updateCurrentPoint() {
1205                 InlineComponent straight = (InlineComponent)added.get(added.size()-1);
1206                 // TODO: the inline length is from previous update step.
1207                 double l;
1208                 if (!reversed)
1209                         l = straight.getPrevious().getControlPoint().getInlineLength();
1210                 else
1211                         l = straight.getNext().getControlPoint().getInlineLength();
1212                 Vector3d v = new Vector3d();
1213                 v.sub(currentPosition, previousPosition);
1214                 double length = v.length();
1215                 if (length > MathTools.NEAR_ZERO) {
1216                         v.scale(1.0/length);
1217                         v.scale(0.5*(length+l));
1218                         v.add(previousPosition);
1219                         straight.getControlPoint().setWorldPosition(v);
1220                         straight.getControlPoint().setLength(length);
1221                 }
1222                 try {
1223                         PipingRules.positionUpdate(straight.getControlPoint(),false);
1224                 } catch (Exception e) {
1225                         // TODO Auto-generated catch block
1226                         e.printStackTrace();
1227                 }
1228         }
1229         
1230         private PipelineComponent getLast() {
1231                 if (added.size() == 0)
1232                         return startComponent;
1233                 return added.get(added.size()-1);
1234         }
1235         
1236         
1237         /**
1238          * Removes last point from pipeline
1239          */
1240         public void removePoint() {
1241                 if (added.size() < 3)
1242                         return;
1243                 InlineComponent straight = (InlineComponent)added.remove(added.size()-1);
1244                 TurnComponent turn = (TurnComponent)added.remove(added.size()-1);
1245                 straight.getControlPoint().remove();
1246                 turn.getControlPoint().remove();
1247                 if (added.size() > 1) {
1248                         setPreviousPosition(added.get(added.size()-2).getWorldPosition());
1249                 } else {
1250                         setPreviousPosition(startComponent.getWorldPosition());
1251                         if (direction != null)
1252                                 setLockType(LockType.CUSTOM, true);
1253                 }
1254                 
1255         }
1256         
1257         protected void endPiping() throws Exception {
1258                 state = ToolState.NOT_ACTIVE;
1259                 
1260                 if (endTo != null) {
1261                     if (endType == PositionType.NEXT || endType == PositionType.PREVIOUS && endTo instanceof InlineComponent) {
1262                         Vector3d dir = endTo.getControlPoint().getPathLegDirection(Direction.NEXT);
1263                     Vector3d currDir = getLast().getControlPoint().getPathLegDirection(Direction.NEXT);
1264                     dir.normalize();
1265                     currDir.normalize();
1266                     double dot = dir.dot(currDir);
1267                     System.out.println(dot + " " + currDir + " " + dir);
1268                     if (dot < ALIGN_DOT_PRODUCT && dot> -ALIGN_DOT_PRODUCT) {
1269                         addTurn();    
1270                     }
1271                         
1272                     }
1273                         ComponentUtils.connect(getLast(), endTo, endType, currentPosition);
1274                 }
1275                 panel.useDefaultAction();
1276         }
1277 }