]> gerrit.simantics Code Review - simantics/3d.git/blobdiff - 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
index 17455a328b0797cef34dc296d560aff852090ea7..a57fcc4c0be6d4e48db55f71710e2c1515f18be8 100644 (file)
@@ -2,6 +2,7 @@ package org.simantics.plant3d.actions;
 
 import java.awt.event.KeyEvent;
 import java.awt.event.MouseEvent;
+import java.awt.event.MouseWheelEvent;
 import java.math.BigDecimal;
 import java.util.ArrayList;
 import java.util.HashSet;
@@ -12,20 +13,20 @@ import javax.vecmath.Point3d;
 import javax.vecmath.Tuple3d;
 import javax.vecmath.Vector3d;
 
+import org.simantics.db.Resource;
 import org.simantics.g3d.math.MathTools;
 import org.simantics.g3d.math.Ray;
 import org.simantics.g3d.scenegraph.NodeMap;
 import org.simantics.g3d.scenegraph.base.INode;
 import org.simantics.g3d.tools.ConstraintDetector;
-import org.simantics.g3d.tools.DummyConstraintDetector;
 import org.simantics.g3d.vtk.gizmo.TranslateAxisGizmo;
 import org.simantics.g3d.vtk.swt.InteractiveVtkComposite;
 import org.simantics.g3d.vtk.swt.vtkSwtAction;
 import org.simantics.g3d.vtk.utils.vtkUtil;
 import org.simantics.plant3d.Activator;
+import org.simantics.plant3d.gizmo.ConstraintPointGizmo;
 import org.simantics.plant3d.gizmo.SplitPointSelectionGizmo;
 import org.simantics.plant3d.gizmo.TerminalSelectionGizmo;
-import org.simantics.plant3d.ontology.Plant3D;
 import org.simantics.plant3d.scenegraph.EndComponent;
 import org.simantics.plant3d.scenegraph.InlineComponent;
 import org.simantics.plant3d.scenegraph.Nozzle;
@@ -50,50 +51,61 @@ public class RoutePipeAction extends vtkSwtAction {
        };
 
        LockType lock = LockType.NONE;
+       boolean lockForced;
        private double BRANCH_SNAP_DISTANCE = 0.05;
        private double NOZZLE_SNAP_DISTANCE = 0.05;
+       private static double BRANCH_DOT_PRODUCT = 0.95; // dot product value used for prevent branch creation
+       private static double ALIGN_DOT_PRODUCT = 0.99; // dot product for creating turn when connecting pipes
 
        private double istep = 10.0;
        private int decimals = 2;
 
        private P3DRootNode root;
-       private PipelineComponent startComponent;
-       private PipeRun pipeRun;
+       protected PipelineComponent startComponent;
+       protected PipeRun pipeRun;
+       private boolean allowBranches;
 
-       private TranslateAxisGizmo translateAxisGizmo = new TranslateAxisGizmo();
+       protected TranslateAxisGizmo translateAxisGizmo = new TranslateAxisGizmo();
        private SplitPointSelectionGizmo splitPointSelectionGizmo;
+       private ConstraintPointGizmo constraintPointGizmo;
        private TerminalSelectionGizmo terminalSelectionGizmo;
-       private NodeMap<vtkProp,INode> nodeMap;
+       private NodeMap<Resource,vtkProp,INode> nodeMap;
        
-       private enum ToolState{NOT_ACTIVE, INITIALIZING, SELECTING_POSITION, SELECTING_SPLIT, ROUTING};
-       private ToolState state = ToolState.NOT_ACTIVE;
+       protected enum ToolState{NOT_ACTIVE, INITIALIZING, SELECTING_POSITION, SELECTING_SPLIT, ROUTING};
+       protected ToolState state = ToolState.NOT_ACTIVE;
        
-       private ConstraintDetector detector = new DummyConstraintDetector();
+       private ConstraintDetector detector;// = new DummyConstraintDetector();
        
-       private boolean useDefault = false;
-       private Vector3d direction = null;
-       private Vector3d previousPosition = null;
-       private Vector3d currentPosition = null;
+       protected boolean useDefault = false;
+       protected Vector3d direction = null;
+       protected Vector3d previousPosition = null;
+       protected Vector3d currentPosition = null;
        
        boolean step = false;
        
        PipelineComponent endTo = null;
-    PositionType endType = null;
-    PipeControlPoint endPort = null;
-    
-    boolean reversed = false;
-    
-    private Set<PositionType> allowed = new HashSet<PositionType>();
-    
+       PositionType endType = null;
+       PipeControlPoint endPort = null;
+       
+       boolean reversed = false;
+       
+       private Set<PositionType> allowed = new HashSet<PositionType>();
        
        public RoutePipeAction(InteractiveVtkComposite panel, P3DRootNode root) {
+           this(panel,root, true);
+       }
+       
+       public RoutePipeAction(InteractiveVtkComposite panel, P3DRootNode root, boolean allowBranches) {
                super(panel);
                this.root = root;
+               this.allowBranches = allowBranches;
                setText("Route Pipe");
                setImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/Straight.png"));
                nodeMap = root.getNodeMap();
                splitPointSelectionGizmo = new SplitPointSelectionGizmo(panel);
                terminalSelectionGizmo = new TerminalSelectionGizmo(panel);
+               constraintPointGizmo = new ConstraintPointGizmo(panel);
+               detector = new org.simantics.g3d.vtk.swt.ConstraintDetector(panel);
        }
        
        public void setComponent(PipelineComponent component) {
@@ -103,7 +115,7 @@ public class RoutePipeAction extends vtkSwtAction {
                        allowed.add(PositionType.NEXT);
                if (this.startComponent.getPrevious() == null && !(this.startComponent instanceof Nozzle))
                        allowed.add(PositionType.PREVIOUS);
-               if (this.startComponent instanceof InlineComponent && !this.startComponent.getControlPoint().isFixed())
+               if (allowBranches && this.startComponent instanceof InlineComponent && !this.startComponent.getControlPoint().isFixedLength())
                        allowed.add(PositionType.SPLIT);
                setEnabled(allowed.size() > 0);
        }
@@ -111,7 +123,7 @@ public class RoutePipeAction extends vtkSwtAction {
        public void deattach() {
                deactivate();
                startComponent = null;
-               nodeMap.commit("Route pipe");
+               
                deattachUI();
                super.deattach();
                panel.refresh();
@@ -151,6 +163,8 @@ public class RoutePipeAction extends vtkSwtAction {
                        splitPointSelectionGizmo.deattach();
                if (terminalSelectionGizmo.isAttached())
                        terminalSelectionGizmo.deattach();
+               if (constraintPointGizmo.isAttached())
+                   constraintPointGizmo.deattach();
                if (infoActor != null) {
                        panel.getRenderer().RemoveActor(infoActor);
                        infoActor.Delete();
@@ -159,13 +173,13 @@ public class RoutePipeAction extends vtkSwtAction {
                panel.unlock();
        }
        
-       private List<PipelineComponent> added = new ArrayList<PipelineComponent>();
+       protected List<PipelineComponent> added = new ArrayList<PipelineComponent>();
        
        @Override
        public boolean keyPressed(KeyEvent e) {
                if (e.getKeyCode() == KeyEvent.VK_ESCAPE)
                        panel.useDefaultAction();
-               if (lock != LockType.CUSTOM) {
+               if (lock != LockType.CUSTOM || !lockForced) {
                        if ((e.getModifiersEx() & KeyEvent.SHIFT_DOWN_MASK) > 0) {
                                if (e.getKeyCode() == KeyEvent.VK_X) {
                                        if (lock != LockType.XY && lock != LockType.XZ) {
@@ -213,10 +227,18 @@ public class RoutePipeAction extends vtkSwtAction {
                                        else
                                                setLockType(LockType.NONE, false);
                                }
+                               if (e.getKeyCode() == KeyEvent.VK_L && direction != null) {
+                                   if (lock != LockType.CUSTOM)
+                        setLockType(LockType.CUSTOM, false);
+                    else
+                        setLockType(LockType.NONE, false);
+                               }
                        }
                }
                if (e.getKeyCode() == KeyEvent.VK_C) {
                        useDefault = !useDefault;
+                       if (useDefault)
+                           setInfoText("Rotating camera");
                        System.out.println("UseDefault " + useDefault);
                }
                
@@ -233,24 +255,24 @@ public class RoutePipeAction extends vtkSwtAction {
        }
        private void update(double x, double y) {
                switch (state) {
-       case NOT_ACTIVE:
-               return; // TODO : throw Exception?
-       case INITIALIZING:
-               return;
-       case SELECTING_POSITION:
-               return;
-       case SELECTING_SPLIT:
-               return;
-       case ROUTING:
-               updateRouting(x,y);
-               break;
-       }
-       return;
+               case NOT_ACTIVE:
+                       return; // TODO : throw Exception?
+               case INITIALIZING:
+                       return;
+               case SELECTING_POSITION:
+                       return;
+               case SELECTING_SPLIT:
+                       return;
+               case ROUTING:
+                       updateRouting(x,y);
+                       break;
+               }
+               return;
        }
        
        boolean startRemovable = false;
        
-       private void activate() throws Exception {
+       protected void activate() throws Exception {
                state = ToolState.INITIALIZING;
                added.clear();
                
@@ -286,7 +308,7 @@ public class RoutePipeAction extends vtkSwtAction {
        
        
        
-       private void activateNextPrev(PipeControlPoint start) throws Exception{
+       protected void activateNextPrev(PipeControlPoint start) throws Exception{
                if (!reversed && start.isDualInline())
                        start = start.getSubPoint().get(0);
                else if (reversed && start.isDualSub())
@@ -299,14 +321,17 @@ public class RoutePipeAction extends vtkSwtAction {
                if (startComponent instanceof Nozzle) {
                        direction = startComponent.getControlPoint().getDirectedControlPointDirection();
                        lock = LockType.CUSTOM;
+                       lockForced = true;
                } else if (startComponent instanceof PipelineComponent){
                        if (startComponent instanceof InlineComponent) {
                                direction = startComponent.getControlPoint().getPathLegDirection(reversed ? Direction.PREVIOUS : Direction.NEXT);
                                lock = LockType.CUSTOM;
-                               if (startComponent.getType().equals(Plant3D.URIs.Builtin_Straight)) {
+                               lockForced = true;
+                               if (((InlineComponent) startComponent).isVariableLength()) {
                                        startWithTurn = true;
                                        direction = null;
                                        lock = LockType.NONE;
+                                       lockForced = false;
                                } 
                                Vector3d v = new Vector3d();
                                if (!reversed) {
@@ -315,12 +340,14 @@ public class RoutePipeAction extends vtkSwtAction {
                                        start.getControlPointEnds(previousPosition,v);
                                }
                        } else if (startComponent instanceof TurnComponent) {
-                               if (start.isFixed()) {
+                               if (start.asFixedAngle()) {
                                        direction = startComponent.getControlPoint().getPathLegDirection(reversed ? Direction.PREVIOUS : Direction.NEXT);
                                        lock = LockType.CUSTOM;
+                                       lockForced = start.isFixedAngle();
                                } else {
                                        direction = null;
                                        lock = LockType.NONE;
+                                       lockForced = false;
                                }
                        } else if (startComponent instanceof EndComponent) {
                                throw new Exception("Not supported");
@@ -362,7 +389,7 @@ public class RoutePipeAction extends vtkSwtAction {
                updateCurrentPoint();
        }
        
-       private void setPreviousPosition(Vector3d v) {
+       protected void setPreviousPosition(Vector3d v) {
                previousPosition = new Vector3d(v);
                if (translateAxisGizmo.isAttached())
                        translateAxisGizmo.setPosition(previousPosition);
@@ -417,11 +444,23 @@ public class RoutePipeAction extends vtkSwtAction {
                state = ToolState.SELECTING_SPLIT;
        }
        public void deactivate() {
-               for (PipelineComponent component : added) {
-                       component.getControlPoint().setDeletable(true);
-               }
+           if (added.size() > 0) {
+           for (PipelineComponent component : added) {
+                       component.getControlPoint().setDeletable(true);
+               }
+               
+            for (PipelineComponent comp : added) {
+                PipingRules.requestUpdate(comp.getControlPoint());
+            }
+            try {
+                PipingRules.update();
+                nodeMap.commit("Route pipe");
+            } catch (Exception e) {
+                ExceptionUtils.logAndShowError(e);
+            }
+            added.clear();        
+        }
                
-               added.clear();
                startComponent.getControlPoint().setDeletable(startRemovable);
 
                direction = null;
@@ -438,13 +477,12 @@ public class RoutePipeAction extends vtkSwtAction {
                startRemovable = false;
                detector.clearConstraintHighlights();
                state = ToolState.NOT_ACTIVE;
-               setEnabled(false);
-               
+               setEnabled(false);              
 
        }
        
        private void setLockType(LockType type, boolean force) {
-               if (force || lock != LockType.CUSTOM) {
+               if (force || (lock != LockType.CUSTOM || !lockForced) ) {
                        lock = type;
                        
                        switch (lock) {
@@ -491,6 +529,14 @@ public class RoutePipeAction extends vtkSwtAction {
                return true;
        }
        
+       @Override
+       public boolean mouseWheelMoved(MouseWheelEvent e) {
+               if (useDefault) {
+                       getDefaultAction().mouseWheelMoved(e);
+               }
+               return true;
+       }
+       
        @Override
        public boolean mouseClicked(MouseEvent e) {
                if (useDefault) {
@@ -500,31 +546,31 @@ public class RoutePipeAction extends vtkSwtAction {
                if (state == ToolState.ROUTING) {
                        try {
                                if (e.getClickCount() == 1) {
-                           if (e.getButton() == MouseEvent.BUTTON1) {
-                               if (this.added.size() > 0) {
-                                 
-                                   setLockType(LockType.NONE,true);
-                                   if (endTo != null) {
-                                       
-                                       endPiping();
-                                   } else {
-                                       addPoint();
-                                   }
-                               } else {
-                                       throw new RuntimeException("kjf");
+                                       if (e.getButton() == MouseEvent.BUTTON1) {
+                                               if (this.added.size() > 0) {
+                                                       
+                                                       setLockType(LockType.NONE,true);
+                                                       if (endTo != null) {
+                                                               
+                                                               endPiping();
+                                                       } else {
+                                                               addPoint();
+                                                       }
+                                               } else {
+                                                       throw new RuntimeException("RoutePipeAction initlialization has been failed, no added components found");
                //                      // user was selecting position of branch
                //                    lastPoint.set(startPoint);
                //                    controlPoints.add(new Point3d(startPoint));
                //                    if (selectionLine != null)
                //                      selectionLine.removeFromParent();
                //                    selectionLine = null;
-                               }
-                           } else if (e.getButton() ==MouseEvent.BUTTON2){
-               //                detector.updateConstraintReference();
-                           } else if (e.getButton() == MouseEvent.BUTTON3){      
-                               endPiping();
-                           }
-                       }
+                                               }
+                                       } else if (e.getButton() ==MouseEvent.BUTTON2){
+                                           updateConstraints();
+                                       } else if (e.getButton() == MouseEvent.BUTTON3){      
+                                               endPiping();
+                                       }
+                               }
                        } catch(Exception err) {
                                err.printStackTrace();
                        }
@@ -563,7 +609,7 @@ public class RoutePipeAction extends vtkSwtAction {
                                }
                                try {
                                        Vector3d pos = new Vector3d(t);
-                                       InlineComponent branchSplit = createBranchSplit((InlineComponent)startComponent, pos);
+                                       InlineComponent branchSplit = ComponentUtils.createBranchSplit((InlineComponent)startComponent, pos);
                                        PipeControlPoint branchSplitCP = branchSplit.getControlPoint();
                                        reversed = false;
                                        PipeRun newRun = new PipeRun();
@@ -586,15 +632,37 @@ public class RoutePipeAction extends vtkSwtAction {
                return true;
        }
        
-       private InlineComponent createBranchSplit(InlineComponent component, Vector3d pos) throws Exception{
-               InlineComponent branchSplit = ComponentUtils.createBranchSplit(root);
-               String branchName = component.getPipeRun().getUniqueName("Branch");
-               branchSplit.setName(branchName);
-               component.getPipeRun().addChild(branchSplit);
-               PipeControlPoint branchSplitCP = branchSplit.getControlPoint();
-               branchSplitCP.setWorldPosition(pos);
-               PipingRules.splitVariableLengthComponent(branchSplit, component, false);
-               return branchSplit;
+       private void updateConstraints() {
+           detector.clearConstraints();
+           constraintPointGizmo.clearPositions();
+           if (hoverObject == null) {
+               if (constraintPointGizmo.isAttached())
+                   constraintPointGizmo.deattach();
+               return;
+           }
+           if (hoverObject instanceof Nozzle) {
+            Nozzle n = (Nozzle)hoverObject;
+            detector.addContraintPoint(new Point3d(n.getWorldPosition()));
+           } else if (hoverObject instanceof InlineComponent) {
+               InlineComponent c = (InlineComponent)hoverObject;
+               Point3d p1 = new Point3d();
+               Point3d p2 = new Point3d();
+               c.getEnds(p1, p2);
+               detector.addContraintPoint(p1);
+               detector.addContraintPoint(p2);
+               detector.addContraintPoint(new Point3d(c.getWorldPosition()));
+           } else if (hoverObject instanceof TurnComponent) {
+               TurnComponent n = (TurnComponent)hoverObject;
+            detector.addContraintPoint(new Point3d(n.getWorldPosition()));
+           }
+           if (detector.getConstraintPoints().size() > 0) {
+               for (Point3d p : detector.getConstraintPoints()) {
+                   constraintPointGizmo.addPosition(new Vector3d(p));
+               }
+               if (constraintPointGizmo.isAttached())
+                   constraintPointGizmo.deattach();
+               constraintPointGizmo.attach(panel);
+           }
        }
        
        @Override
@@ -603,7 +671,7 @@ public class RoutePipeAction extends vtkSwtAction {
                        getDefaultAction().mouseMoved(e);
                        return true;
                }
-               step = ((e.getModifiers() & MouseEvent.CTRL_DOWN_MASK) > 0);
+               step = ((e.getModifiers() & MouseEvent.CTRL_MASK) > 0);
                update(e.getX(), e.getY());
                return true;
        }
@@ -629,562 +697,581 @@ public class RoutePipeAction extends vtkSwtAction {
                return nodes;
        }
        
-        
-     
-        private void updateRouting(double x, double y) {
-//             if(input.keyPressed(KeyEvent.VK_ESCAPE)) {
-//                 controlPoints.clear();
-//                 end();
-//                 return;
-//             }
-//             if (input.keyPressed(KeyEvent.VK_C)) {
-//                     useCamera = !useCamera;
-//                     cameraAction.setChecked(useCamera);
-//             }
-               if (useDefault) {
-                       //panel.getDefaultAction().update();
-                       return;
-               }
-               
-               endTo = null;
-               endType = null;
-               endPort = null;
+       INode hoverObject = null;
 
-               Ray ray = vtkUtil.createMouseRay(panel.getRenderer(),x, y);
-               Vector3d o = new Vector3d(ray.pos);
-               Vector3d d = ray.dir;
-               
-               
-               if (!updateCurrentPoint(o, d))
-                   return;
-               //Point3d startPoint = new Point3d();
-               double mu[] = new double[2];
-               
-               
-               
-               INode hoverObject = null;
-               
-               List<INode> hover = isOverNode((int)x,(int)y);
-               if (hover.size() > 0) {
-                       hoverObject = hover.get(0);
-               } 
+       protected void updateRouting(double x, double y) {
+               if (useDefault) {
+                       //panel.getDefaultAction().update();
+                       return;
+               }
+               
+               endTo = null;
+               endType = null;
+               endPort = null;
+
+               Ray ray = vtkUtil.createMouseRay(panel.getRenderer(),x, y);
+               Vector3d o = new Vector3d(ray.pos);
+               Vector3d d = ray.dir;
+               
+               
+               if (!updateCurrentPoint(o, d))
+                       return;
+               //Point3d startPoint = new Point3d();
+               double mu[] = new double[2];
+               
+               
+               
+               
+               
+               List<INode> hover = isOverNode((int)x,(int)y);
+               if (hover.size() > 0) {
+                       hoverObject = hover.get(0);
+               } else {
+                   hoverObject = null;
+               }
 //             System.out.println(hoverObject + " " + getLast());
-               if (hoverObject != null) {
-                       if (hoverObject.equals(getLast()) ) {
-                               boolean set = false;
-                               for (int i = 1; i < hover.size(); i++) {
-                                       hoverObject = hover.get(i);
-                                       if (!getLast().equals(hoverObject)) {
-                                               set = true;
-                                               break;
-                                       }
-                               }
-                               if (!set)
-                                       hoverObject = null;
-                       }
-               }
+               if (hoverObject != null) {
+                       if (hoverObject.equals(getLast()) ) {
+                               boolean set = false;
+                               for (int i = 1; i < hover.size(); i++) {
+                                       hoverObject = hover.get(i);
+                                       if (!getLast().equals(hoverObject)) {
+                                               set = true;
+                                               break;
+                                       }
+                               }
+                               if (!set)
+                                       hoverObject = null;
+                       }
+               }
 //             System.out.println(hoverObject);
-                 if (hoverObject != null) {
-                            
-                         if (lock == LockType.NONE) {
-                                 if (hoverObject instanceof Nozzle && endingToNozzle(hoverObject,o,d)) {
-                                         endTo = (Nozzle)hoverObject;
-                                 } else if (hoverObject instanceof InlineComponent && ((InlineComponent)hoverObject).isVariableLength()) {
-                                         endTo = (InlineComponent)hoverObject;
-                                         endType = endingToStraight(endTo,mu,o,d);     
-                                 } else if (hoverObject instanceof PipelineComponent && (endPort = endingToComponent(hoverObject,o,d)) != null) {
-                                         endTo = (PipelineComponent)hoverObject;
-                                 } else {
-                                         updateRoute(o,d); 
-                                 }
-                         } else {  
-                                 if (hoverObject instanceof InlineComponent && ((InlineComponent)hoverObject).isVariableLength() && (endType = endingLockToStraight(hoverObject,mu)) != null) {
-                                         endTo = (InlineComponent)hoverObject;;
-                                 } else if (hoverObject instanceof Nozzle && endingLockToNozzle(hoverObject)) {
-                                         endTo = (Nozzle)hoverObject;
-                                 } else if ((hoverObject instanceof PipelineComponent) &&  ((endPort = endingLockToComponent(hoverObject)) != null)) {
-                                         endTo = (PipelineComponent)hoverObject;
-                                 } else {
-                                         updateRoute(o,d);
-                                 }
-                         }
-                         if (added.contains(endTo))
-                                 endTo = null;
-                     
-               } else {
-                   updateRoute(o,d);
-               }
-                 
-               panel.refresh();
-           }
-           
-           private boolean updateCurrentPoint(Vector3d o, Vector3d d) {
+               if (hoverObject != null) {
 
-               Vector3d point = new Vector3d(this.previousPosition);
-               
-               switch(lock) {
-               case X:
-                   MathTools.intersectStraightStraight(point, new Vector3d(1.0,0.0,0.0), o,d, currentPosition, new Vector3d());
-                   if (step) {
-                       currentPosition.x = Math.round(istep * currentPosition.x) / istep;
-                       BigDecimal bx = new BigDecimal(currentPosition.x);
-                       bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);
-                       currentPosition.x = bx.doubleValue();
-                   }
-                   break;
-               case Y:
-                   MathTools.intersectStraightStraight(point, new Vector3d(0.0,1.0,0.0), o,d, currentPosition, new Vector3d());
-                   if (step) {
-                       currentPosition.y = Math.round(istep * currentPosition.y) / istep;
-                       BigDecimal bx = new BigDecimal(currentPosition.y);
-                       bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);
-                       currentPosition.y = bx.doubleValue();
-                   }
-                   break;
-               case Z:
-                   MathTools.intersectStraightStraight(point, new Vector3d(0.0,0.0,1.0), o,d, currentPosition, new Vector3d());
-                   if (step) {
-                       currentPosition.z = Math.round(istep * currentPosition.z) / istep;
-                       BigDecimal bx = new BigDecimal(currentPosition.z);
-                       bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);
-                       currentPosition.z = bx.doubleValue();
-                   }break;
-               case XY:
-                   MathTools.intersectStraightPlane(o, d, point, new Vector3d(0.0,0.0,1.0), currentPosition);
-                   break;
-               case XZ:
-                   MathTools.intersectStraightPlane(o, d, point, new Vector3d(0.0,1.0,0.0), currentPosition);
-                   break;
-               case YZ:
-                   MathTools.intersectStraightPlane(o, d, point, new Vector3d(1.0,0.0,0.0), currentPosition);
-                   break;
-               case NONE:
-                       Vector3d normal = new Vector3d(panel.getRenderer().GetActiveCamera().GetDirectionOfProjection());
-                   normal.normalize();
-                   
-                   MathTools.intersectStraightPlane(o, d, point, normal, currentPosition);
-                   break;
-               case CUSTOM:
-                       MathTools.intersectStraightStraight(point, new Vector3d(direction), o,d, currentPosition, new Vector3d());
-                   double dist = MathTools.distanceFromPlane(new Vector3d(currentPosition), direction, previousPosition);
-                       if (dist < 0.0)
-                               currentPosition.set(previousPosition);
-                   break;
-               default:
-                   return false;
-               }
-               return true;
-           }
-           
-           private Vector3d getLockDir() {
-               switch (lock) {
-               case CUSTOM:
-                       return direction;
-               case X:
-                       return new Vector3d(1,0,0);
-               case Y:
-                       return new Vector3d(0,1,0);
-               case Z:
-                       return new Vector3d(0,0,1);
-               }
-               return null;
-           }
-           
-           private void updateRoute(Vector3d o, Vector3d d) {
-               detector.clearConstraintHighlights();
-               Point3d previousPipePoint = new Point3d(previousPosition);
-               String s = "";
-               if (lock == LockType.NONE) {
-                   Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint));
-                   if (p != null)
-                       currentPosition = new Vector3d(p);
-                   s += detector.getSnapString();
+                       if (lock == LockType.NONE) {
+                               if (hoverObject instanceof Nozzle && endingToNozzle(hoverObject,o,d)) {
+                                       endTo = (Nozzle)hoverObject;
+                               } else if (hoverObject instanceof InlineComponent && ((InlineComponent)hoverObject).isVariableLength()) {
+                                       endTo = (InlineComponent)hoverObject;
+                                       endType = endingToStraight(endTo,mu,o,d);     
+                                       if (endType == null)
+                                           endTo = null;
+                               } else if (hoverObject instanceof PipelineComponent && (endPort = endingToComponent(hoverObject,o,d)) != null) {
+                                       endTo = (PipelineComponent)hoverObject;
+                               } else {
+                                       updateRoute(o,d); 
+                               }
+                       } else {  
+                               if (hoverObject instanceof InlineComponent && ((InlineComponent)hoverObject).isVariableLength() && (endType = endingLockToStraight(hoverObject,mu, new Point3d(currentPosition))) != null) {
+                                       endTo = (InlineComponent)hoverObject;
+                               } else if (hoverObject instanceof Nozzle && endingLockToNozzle(hoverObject)) {
+                                       endTo = (Nozzle)hoverObject;
+                               } else if ((hoverObject instanceof PipelineComponent) &&  ((endPort = endingLockToComponent(hoverObject)) != null)) {
+                                       endTo = (PipelineComponent)hoverObject;
+                               } else {
+                                       updateRoute(o,d);
+                               }
+                       }
+                       if (added.contains(endTo))
+                               endTo = null;
 
-               } else {
-                   Vector3d dir = new Vector3d(currentPosition);
-                   dir.sub(previousPipePoint);
-                   Point3d p = detector.getPointSnap(new Vector3d(previousPipePoint), dir);
-                   if (p != null)
-                       currentPosition = new Vector3d(p);
-                   s += detector.getSnapString();
+               } else {
+                       updateRoute(o,d);
+               }
+               
+               panel.refresh();
+       }
+       
+       protected boolean updateCurrentPoint(Vector3d o, Vector3d d) {
 
-               }
-               
-               updateCurrentPoint();
-               s += currentPosition.toString();
-               setInfoText(s);
-           }
-           
-           vtkTextActor infoActor;
-           
-           private void setInfoText(String text) {
-               //System.out.println(text);
-               if (infoActor == null) {
-                       infoActor = new vtkTextActor();
-                       infoActor.GetTextProperty().SetColor(0.0, 0.0, 0.0);
-                       infoActor.GetTextProperty().ShadowOff();
-                       infoActor.GetTextProperty().ItalicOff();
-                       infoActor.GetTextProperty().BoldOff();
-                       infoActor.GetTextProperty().SetFontSize(18);
-                       infoActor.GetTextProperty().Delete();
-                       infoActor.GetProperty().SetColor(0.0, 0.0, 0.0);
-                       infoActor.GetProperty().Delete();
+               Vector3d point = new Vector3d(this.previousPosition);
+               
+               switch(lock) {
+               case X:
+                       MathTools.intersectStraightStraight(point, new Vector3d(1.0,0.0,0.0), o,d, currentPosition, new Vector3d());
+                       if (step) {
+                               currentPosition.x = Math.round(istep * currentPosition.x) / istep;
+                               BigDecimal bx = new BigDecimal(currentPosition.x);
+                               bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);
+                               currentPosition.x = bx.doubleValue();
+                       }
+                       break;
+               case Y:
+                       MathTools.intersectStraightStraight(point, new Vector3d(0.0,1.0,0.0), o,d, currentPosition, new Vector3d());
+                       if (step) {
+                               currentPosition.y = Math.round(istep * currentPosition.y) / istep;
+                               BigDecimal bx = new BigDecimal(currentPosition.y);
+                               bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);
+                               currentPosition.y = bx.doubleValue();
+                       }
+                       break;
+               case Z:
+                       MathTools.intersectStraightStraight(point, new Vector3d(0.0,0.0,1.0), o,d, currentPosition, new Vector3d());
+                       if (step) {
+                               currentPosition.z = Math.round(istep * currentPosition.z) / istep;
+                               BigDecimal bx = new BigDecimal(currentPosition.z);
+                               bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);
+                               currentPosition.z = bx.doubleValue();
+                       }break;
+               case XY:
+                       MathTools.intersectStraightPlane(o, d, point, new Vector3d(0.0,0.0,1.0), currentPosition);
+                       break;
+               case XZ:
+                       MathTools.intersectStraightPlane(o, d, point, new Vector3d(0.0,1.0,0.0), currentPosition);
+                       break;
+               case YZ:
+                       MathTools.intersectStraightPlane(o, d, point, new Vector3d(1.0,0.0,0.0), currentPosition);
+                       break;
+               case NONE:
+                       Vector3d normal = new Vector3d(panel.getRenderer().GetActiveCamera().GetDirectionOfProjection());
+                       normal.normalize();
+                       
+                       MathTools.intersectStraightPlane(o, d, point, normal, currentPosition);
+                       break;
+               case CUSTOM:
+                       MathTools.intersectStraightStraight(point, new Vector3d(direction), o,d, currentPosition, new Vector3d());
+                       double dist = MathTools.distanceFromPlane(new Vector3d(currentPosition), direction, previousPosition);
+                       if (dist < 0.0)
+                               currentPosition.set(previousPosition);
+                       break;
+               default:
+                       return false;
+               }
+               return true;
+       }
+       
+       @SuppressWarnings("unused")
+       private Vector3d getLockDir() {
+               switch (lock) {
+               case CUSTOM:
+                       return direction;
+               case X:
+                       return new Vector3d(1,0,0);
+               case Y:
+                       return new Vector3d(0,1,0);
+               case Z:
+                       return new Vector3d(0,0,1);
+               default:
+                       return null;
+               }
+       }
+       
+       protected void updateRoute(Vector3d o, Vector3d d) {
+               detector.clearConstraintHighlights();
+               Point3d previousPipePoint = new Point3d(previousPosition);
+               String s = "";
+               if (lock == LockType.NONE) {
+                       Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint));
+                       if (p != null)
+                               currentPosition = new Vector3d(p);
+                       s += detector.getSnapString();
 
-                               
-                       infoActor.SetPosition(10,10);
-                               panel.getRenderer().AddActor(infoActor);
-               }
-               infoActor.SetInput(text);
-           }
-           
-           private boolean endingToNozzle(INode nozzleNode,Vector3d o, Vector3d d) {
-               Nozzle nozzle = (Nozzle)nozzleNode;
-               PipeControlPoint pcp  =nozzle.getControlPoint();
-               if (pcp != null && (pcp.getNext() != null ||
-                                           pcp.getPrevious() != null))
-                       return false; // nozzle is already connected to pipe
-               currentPosition = pcp.getWorldPosition();
-               Point3d previousPipePoint = new Point3d(previousPosition);
-               Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint));
-               if (p != null) {
-                   if (MathTools.distance(p, currentPosition) > NOZZLE_SNAP_DISTANCE) {
-                       return false;
-                   }
-               } 
-               
-               updateCurrentPoint();
-               
-               setInfoText("Connect to nozzle " + currentPosition);
-               return true;
-           
-           }
-           
-           private PositionType endingToStraight(INode straightNode, double mu[], Vector3d o, Vector3d d) {
-               InlineComponent s = (InlineComponent)straightNode;
-               String info = "";
-               Point3d sStart = new Point3d();
-               Point3d sEnd = new Point3d();
-               s.getControlPointEnds(sStart, sEnd);
-               //detector.clearConstraintHighlights();
-               
-               Point3d previousPipePoint = new Point3d(previousPosition);
-               //String st = "";
-               if (lock == LockType.NONE) {
-                   Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint));
-                   if (p != null) {
-                       currentPosition = new Vector3d(p);
-                       // snapping is detected, check if snapped point can create branch with straight
-                       PositionType t = endingLockToStraight(s, mu);
-                       if (t != null)
-                           return t;
-                       // if not, we'll have to remove highlight that was added when snapped point was detected
-                       detector.clearConstraintHighlights();
-                   } 
-                     
+               } else {
+                       Vector3d dir = new Vector3d(currentPosition);
+                       dir.sub(previousPipePoint);
+                       Point3d p = detector.getPointSnap(new Vector3d(previousPipePoint), dir);
+                       if (p != null)
+                               currentPosition = new Vector3d(p);
+                       s += detector.getSnapString();
 
-                   Vector3d sDir = new Vector3d(sEnd);
-                   sDir.sub(sStart);
-                   MathTools.intersectStraightStraight(sStart, sDir, o, d, currentPosition, new Point3d(), mu);
-                   
+               }
+//             System.out.println(previousPosition + " -> " + currentPosition);
+//             double dist = MathTools.distance(previousPosition, currentPosition);
+//             if (dist < pipeRun.getTurnRadius()) {
+//                     s += "Too close";
+//                     Vector3d v = new Vector3d(currentPosition);
+//                     v.sub(previousPosition);
+//                     double vl = v.length();
+//                     if (vl > MathTools.NEAR_ZERO) {
+//                             v.scale(1.0/vl);
+//                     } else {
+//
+//                             return;
+//                     }
+//                     v.scale(pipeRun.getTurnRadius());
+//                     v.add(previousPosition);
+//                     currentPosition.set(v);
+//             }
+               
+               updateCurrentPoint();
+               s += currentPosition.toString();
+               setInfoText(s);
+       }
+       
+       vtkTextActor infoActor;
+       
+       private void setInfoText(String text) {
+               //System.out.println(text);
+               if (infoActor == null) {
+                       infoActor = new vtkTextActor();
+                       infoActor.GetTextProperty().SetColor(0.0, 0.0, 0.0);
+                       infoActor.GetTextProperty().ShadowOff();
+                       infoActor.GetTextProperty().ItalicOff();
+                       infoActor.GetTextProperty().BoldOff();
+                       infoActor.GetTextProperty().SetFontSize(18);
+                       infoActor.GetTextProperty().Delete();
+                       infoActor.GetProperty().SetColor(0.0, 0.0, 0.0);
+                       infoActor.GetProperty().Delete();
 
-               } else {
-                   throw new RuntimeException("Lock shouldn't be on");
+                       
+                       infoActor.SetPosition(10,10);
+                       panel.getRenderer().AddActor(infoActor);
+               }
+               infoActor.SetInput(text);
+       }
+       
+       private boolean endingToNozzle(INode nozzleNode,Vector3d o, Vector3d d) {
+               Nozzle nozzle = (Nozzle)nozzleNode;
+               PipeControlPoint pcp  =nozzle.getControlPoint();
+               if (pcp != null && (pcp.getNext() != null ||
+                                                       pcp.getPrevious() != null))
+                       return false; // nozzle is already connected to pipe
+               currentPosition = pcp.getWorldPosition();
+               Point3d previousPipePoint = new Point3d(previousPosition);
+               Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint));
+               if (p != null) {
+                       if (MathTools.distance(p, currentPosition) > NOZZLE_SNAP_DISTANCE) {
+                               return false;
+                       }
+               } 
+               
+               updateCurrentPoint();
+               
+               setInfoText("Connect to nozzle " + currentPosition);
+               return true;
+       
+       }
+       
+       private PositionType endingToStraight(INode straightNode, double mu[], Vector3d o, Vector3d d) {
+//         if (!allowBranches) {
+//             updateCurrentPoint();
+//            return null;
+//         }
+               InlineComponent s = (InlineComponent)straightNode;
+               
+               Point3d sStart = new Point3d();
+               Point3d sEnd = new Point3d();
+               s.getEnds(sStart, sEnd);
+               //detector.clearConstraintHighlights();
+               
+               Point3d previousPipePoint = new Point3d(previousPosition);
+               Point3d currentPipePoint = new Point3d(currentPosition);
+               //String st = "";
+               if (lock == LockType.NONE) {
+                       Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint));
+                       if (p != null) {
+                               currentPosition = new Vector3d(p);
+                               // snapping is detected, check if snapped point can create branch with straight
+                               PositionType t = endingLockToStraight(s, mu, currentPipePoint);
+                               if (t != null)
+                                       return t;
+                               // if not, we'll have to remove highlight that was added when snapped point was detected
+                               detector.clearConstraintHighlights();   
+                       }
+                       
+                       Vector3d sDir = new Vector3d(sEnd);
+                       sDir.sub(sStart);
+                       MathTools.intersectStraightStraight(sStart, sDir, o, d, currentPosition, new Point3d(), mu);
+                       
 
-               }
-               
-               updateCurrentPoint();
-               
-               // branch point must lie between straight's ends. If connection point is exactly
-               // on straight end user may want to connect pipes to each other
-               // TODO : take account sizes of inline components)
-               // TODO : actually make connection if its detected
-               boolean connectPrev = false;
-               boolean connectNext = false;
-               
-               if (mu[0] < 0.0) {
-                   currentPosition.set(sStart);
-                   connectPrev = true;
-               }
-               else if (mu[0] > 1.0) {
-                   currentPosition.set(sEnd);
-                   connectNext = true;
-               }
-               boolean connect = false;
-               if (connectPrev) {
-                   PipeControlPoint pcp = s.getControlPoint();
-                   if (pcp.getPrevious() == null)
-                       connect = true;
-               } else if (connectNext) {
-                       PipeControlPoint pcp = s.getControlPoint();
-                   if (pcp.getNext() == null)
-                       connect = true;
-               }
-               
-               updateCurrentPoint();
-               
-               if (connect)
-                   info += "Connect pipes :";
-               else
-                   info += "Make Branch :";
-               
-               setInfoText(info + currentPosition + " " + Math.max(0.0, Math.min(mu[0], 1.0)));
-               if (connect) {
-                       if (connectNext) {
-                               return PositionType.NEXT;
-                       } else {
-                               return PositionType.PREVIOUS;
-                       }
-                               
-               }
-               return PositionType.SPLIT;
-                       
-           }
-           
-           private PipeControlPoint endingToComponent(INode componentNode, Vector3d o, Vector3d d) {
-               PipelineComponent component = (PipelineComponent)componentNode;
-               PipeControlPoint pcp = component.getControlPoint();
-               if (component instanceof EndComponent) {
-                       if (pcp.getNext() != null || pcp.getPrevious() != null)
-                               return null;
-                       return pcp;
-               } else if (component instanceof TurnComponent) {
-                       if (pcp.getNext() == null || pcp.getPrevious() == null)
-                               return pcp;
-                       return null;
-               } else if (component instanceof InlineComponent) {
-                       // TODO : scan all empty pcps of the component and select closest one.
-                       if (pcp.getNext() == null || pcp.getPrevious() == null)
-                               return pcp;
-                       return null;
-               }
+               } else {
+                       throw new RuntimeException("Lock shouldn't be on");
 
-               return null;
-           }
-           
-           private PositionType endingLockToStraight(INode straightNode, double mu[]) {
-               InlineComponent s = (InlineComponent)straightNode;
-               Point3d sStart = new Point3d();//G3DTools.getPoint(s.getHasControlPoint().getPreviousPoint().getLocalPosition());
-               Point3d sEnd = new Point3d(); //G3DTools.getPoint(s.getHasControlPoint().getNextPoint().getLocalPosition());
-               s.getControlPoint().getInlineControlPointEnds(sStart, sEnd);  
-               Vector3d sDir = new Vector3d(sEnd);
-               sDir.sub(sStart);
-               Vector3d dir = new Vector3d(currentPosition);
-               Point3d prev = new Point3d(previousPosition);
-               dir.sub(prev);
-               // intersection point in pipe where branch would be inserted to
-               Vector3d branchPoint = new Vector3d();
-               // intersection point in straight pipe that is currently routed
-               Vector3d routePoint = new Vector3d();
-               MathTools.intersectStraightStraight(sStart, sDir, new Vector3d(prev), dir, branchPoint, routePoint, mu);
-               routePoint.sub(branchPoint);
-               // startPoint of branch must be between pipe ends
-               // TODO : take account sizes of elbows (or other components)
-               // branch point must be between pipe ends and intersection points must be quite close to each othert
-               if (mu[0] > 0.0 && mu[0] < 1.0 && routePoint.lengthSquared() < BRANCH_SNAP_DISTANCE) {
-                   currentPosition.set(branchPoint);
-                   
-                   updateCurrentPoint();
-                   
-                   setInfoText("Make branch (l) :" + currentPosition + " " + Math.max(0.0, Math.min(mu[0], 1.0)) + " " + routePoint.lengthSquared());
-                   return PositionType.SPLIT;
-               }
-               return null;
-           }
-           
-           private boolean endingLockToNozzle(INode nozzleNode) {
-               Nozzle nozzle = (Nozzle)nozzleNode;
-                Vector3d dir = new Vector3d(currentPosition);
-                Point3d prev = new Point3d(previousPosition);
-                dir.sub(prev);
-                Vector3d nozzleLoc = nozzle.getWorldPosition();
-                double u[] = new double[1];
-                Vector3d closest = MathTools.closestPointOnStraight(new Point3d(nozzleLoc), new Point3d(prev), new Vector3d(dir), u);
-                double dist = MathTools.distanceSquared(nozzleLoc,closest);
-                if (dist < BRANCH_SNAP_DISTANCE) {
-                        // FIXME : directions should be checked (insert an elbow)
-                        currentPosition.set(nozzleLoc);
-                        updateCurrentPoint();
-                        setInfoText("Connect to nozzle (l) :" + currentPosition);
-                        return true;
-                } 
-                //System.out.println(u[0]);
-               return false;
-           }
-           
-           private PipeControlPoint endingLockToComponent(INode componentNode) {
-               // we'll must scan all free pcp's and their direction to accept the connection.
-               return null;
-           }
-           
-           private void addPoint() throws Exception {
-               InlineComponent previous = (InlineComponent)getLast();
-               PipeControlPoint previousCP = previous.getControlPoint();
-               TurnComponent turn = ComponentUtils.createTurn(root);
-               InlineComponent straight = ComponentUtils.createStraight(root);
-               PipeControlPoint turnCP = turn.getControlPoint();
-               PipeControlPoint straightCP = straight.getControlPoint();
-               straight.setName(pipeRun.getUniqueName("Pipe"));
-               turn.setName(pipeRun.getUniqueName("Elbow"));
-               pipeRun.addChild(turn);
-               pipeRun.addChild(straight);
-               added.add(turn);
-               added.add(straight);
-               
-               turnCP.setDeletable(false); // mark turnCP nonDeletable so that PipingRules won't delete it immediately.
-               
-               if (!reversed) {
-                       previousCP.setNext(turnCP);
-                       turnCP.setPrevious(previousCP);
-                       turnCP.setNext(straightCP);
-                       straightCP.setPrevious(turnCP);
-               } else {
-                       previousCP.setPrevious(turnCP);
-                       turnCP.setNext(previousCP);
-                       turnCP.setPrevious(straightCP);
-                       straightCP.setNext(turnCP);
-               }
-               
-               turnCP.setWorldPosition(currentPosition);
-               turnCP.setTurnAngle(0.0);
-               turnCP.setLength(0.0);
-               straightCP.setWorldPosition(currentPosition);
-               straightCP.setLength(0.0);
-               
-               setPreviousPosition(currentPosition);
-               updateCurrentPoint();
-               
-               
-               
-           }
-           
-           /**
-            * Updates tool graphics for current point 
-            */
-           private void updateCurrentPoint() {
-//             PipeComponentProvider.createStraightEdges(pipeShapes.get(pipeShapes.size() - 1), controlPoints.get(controlPoints.size() - 1), currentPoint, pipeDiameter*0.5);
-               InlineComponent straight = (InlineComponent)added.get(added.size()-1);
-               // FIXME : does not take account space the the previous elbow reserves. 
-               Vector3d v = new Vector3d();
-               v.sub(currentPosition, previousPosition);
-               double length = v.length();
-               v.scale(0.5);
-               v.add(previousPosition);
-               straight.getControlPoint().setWorldPosition(v);
-               straight.getControlPoint().setLength(length);
-               try {
-                               PipingRules.positionUpdate(straight.getControlPoint(),false);
-                       } catch (Exception e) {
-                               // TODO Auto-generated catch block
-                               e.printStackTrace();
-                       }
-           }
-           
-           private PipelineComponent getLast() {
-               if (added.size() == 0)
-                       return startComponent;
-               return added.get(added.size()-1);
-           }
-          
+               }
+               
+               updateCurrentPoint();
+               
+               // branch point must lie between straight's ends. If connection point is exactly
+               // on straight end user may want to connect pipes to each other
+               // TODO : take account sizes of inline components)
+               return endingToStraight(mu, s, sStart, sEnd, currentPipePoint);
+       }
+       
+       private PositionType endingToStraight(double mu[], InlineComponent s, Point3d sStart, Point3d sEnd , Point3d currentPipePoint) {
+           String info = "";
            
-           /**
-            * Removes last point from pipeline
-            */
-           public void removePoint() {
-               if (added.size() < 3)
-                       return;
-               InlineComponent straight = (InlineComponent)added.remove(added.size()-1);
-               TurnComponent turn = (TurnComponent)added.remove(added.size()-1);
-               straight.getControlPoint().remove();
-               turn.getControlPoint().remove();
-               if (added.size() > 1) {
-                       setPreviousPosition(added.get(added.size()-2).getWorldPosition());
-               } else {
-                       setPreviousPosition(startComponent.getWorldPosition());
-                       if (direction != null)
-                               setLockType(LockType.CUSTOM, true);
-               }
-               
-           }
+           boolean connectPrev = false;
+        boolean connectNext = false;
+        boolean branch = false;
+        if (mu[0] < 0.1) {
+            connectPrev = true;
+        }
+        else if (mu[0] > 0.9) {
+            connectNext = true;
+        }
+
+          
+        if (connectPrev) {
+            PipeControlPoint pcp = s.getControlPoint();
+            if (pcp.getPrevious() != null)
+                connectPrev = false;
+        } else if (connectNext) {
+            PipeControlPoint pcp = s.getControlPoint();
+            if (pcp.getNext() != null)
+                connectNext = false;
+        } else {
+            Vector3d dir = s.getControlPoint().getPathLegDirection(Direction.NEXT);
+            Vector3d currDir = getLast().getControlPoint().getPathLegDirection(Direction.NEXT);
+            dir.normalize();
+            currDir.normalize();
+            double dot = dir.dot(currDir);
+            System.out.println(dot + " " + currDir + " " + dir);
+            if (dot > BRANCH_DOT_PRODUCT || dot < -BRANCH_DOT_PRODUCT) {
+                // pipes are almost in the same direction, creating a branch is not feasible.
+                branch = false;
+            } else {
+                branch = true;
+            }
+        }
+        
+            
+        if (connectNext || connectPrev)
+            info += "Connect pipes :";
+        else if (branch)
+            info += "Create a Branch :";
+        
+        setInfoText(info + currentPosition + " " + Math.max(0.0, Math.min(mu[0], 1.0)));
+        if (connectNext) {
+            currentPosition.set(sEnd);
+            updateCurrentPoint();
+            return PositionType.NEXT;
+        } else if (connectPrev){
+            currentPosition.set(sStart);
+            updateCurrentPoint();
+            return PositionType.PREVIOUS;
+        } else if (branch && allowBranches) {
+            return PositionType.SPLIT;
+        } else {
+            currentPosition.set(currentPipePoint);
+            updateCurrentPoint();
+            return null;
+        }
+       }
+       
+       private PipeControlPoint endingToComponent(INode componentNode, Vector3d o, Vector3d d) {
+               PipelineComponent component = (PipelineComponent)componentNode;
+               PipeControlPoint pcp = component.getControlPoint();
+               if (component instanceof EndComponent) {
+                       if (pcp.getNext() != null || pcp.getPrevious() != null)
+                               return null;
+                       return pcp;
+               } else if (component instanceof TurnComponent) {
+                       if (pcp.getNext() == null || pcp.getPrevious() == null)
+                               return pcp;
+                       return null;
+               } else if (component instanceof InlineComponent) {
+                       // TODO : scan all empty pcps of the component and select closest one.
+                       if (pcp.getNext() == null || pcp.getPrevious() == null)
+                               return pcp;
+                       return null;
+               }
+
+               return null;
+       }
+       
+       private PositionType endingLockToStraight(INode straightNode, double mu[], Point3d currentPipePoint) {
+//         if (!allowBranches) {
+//            updateCurrentPoint();
+//            return null;
+//        }
+               InlineComponent s = (InlineComponent)straightNode;
+               Point3d sStart = new Point3d();
+               Point3d sEnd = new Point3d(); 
+               s.getControlPoint().getInlineControlPointEnds(sStart, sEnd);  
+               Vector3d sDir = new Vector3d(sEnd);
+               sDir.sub(sStart);
+               Vector3d dir = new Vector3d(currentPosition);
+               Point3d prev = new Point3d(previousPosition);
+               dir.sub(prev);
+               // intersection point in pipe where branch would be inserted to
+               Vector3d branchPoint = new Vector3d();
+               // intersection point in straight pipe that is currently routed
+               Vector3d routePoint = new Vector3d();
+               MathTools.intersectStraightStraight(sStart, sDir, new Vector3d(prev), dir, branchPoint, routePoint, mu);
+               routePoint.sub(branchPoint);
+               // startPoint of branch must be between pipe ends
+               // TODO : take account sizes of elbows (or other components)
+               // branch point must be between pipe ends and intersection points must be quite close to each other
+               
+               if (routePoint.lengthSquared() > BRANCH_SNAP_DISTANCE)
+                   return null;
+               
+               return endingToStraight(mu, s, sStart, sEnd, currentPipePoint);
+               
+//             if (mu[0] > 0.0 && mu[0] < 1.0 && routePoint.lengthSquared() < BRANCH_SNAP_DISTANCE) {
+//                     currentPosition.set(branchPoint);
+//                     
+//                     updateCurrentPoint();
+//                     
+//                     setInfoText("Create a branch (l) :" + currentPosition + " " + Math.max(0.0, Math.min(mu[0], 1.0)) + " " + routePoint.lengthSquared());
+//                     return PositionType.SPLIT;
+//             }
+//             return null;
+       }
+       
+       private boolean endingLockToNozzle(INode nozzleNode) {
+               Nozzle nozzle = (Nozzle)nozzleNode;
+               Vector3d dir = new Vector3d(currentPosition);
+               Point3d prev = new Point3d(previousPosition);
+               dir.sub(prev);
+               Vector3d nozzleLoc = nozzle.getWorldPosition();
+               double u[] = new double[1];
+               Vector3d closest = MathTools.closestPointOnStraight(new Point3d(nozzleLoc), new Point3d(prev), new Vector3d(dir), u);
+               double dist = MathTools.distanceSquared(nozzleLoc,closest);
+               if (dist < BRANCH_SNAP_DISTANCE) {
+                       // FIXME : directions should be checked (insert an elbow)
+                       currentPosition.set(nozzleLoc);
+                       updateCurrentPoint();
+                       setInfoText("Connect to nozzle (l) :" + currentPosition);
+                       return true;
+               } 
+               //System.out.println(u[0]);
+               return false;
+       }
+       
+       private PipeControlPoint endingLockToComponent(INode componentNode) {
+               // we'll must scan all free pcp's and their direction to accept the connection.
+               return null;
+       }
+       
+       protected void addTurn() throws Exception{
+           InlineComponent previous = (InlineComponent)getLast();
+        PipeControlPoint previousCP = previous.getControlPoint();
+        TurnComponent turn = ComponentUtils.createTurn(root);
+        PipeControlPoint turnCP = turn.getControlPoint();
+        turn.setName(pipeRun.getUniqueName("Elbow"));
+        pipeRun.addChild(turn);
+        added.add(turn);
+        turnCP.setDeletable(false); // mark turnCP nonDeletable so that PipingRules won't delete it immediately.
+        if (!reversed) {
+            previousCP.setNext(turnCP);
+            turnCP.setPrevious(previousCP);
+        } else {
+            previousCP.setPrevious(turnCP);
+            turnCP.setNext(previousCP);
+        }
+        
+        turnCP.setWorldPosition(currentPosition);
+        turnCP.setTurnAngle(0.0);
+        turnCP.setLength(0.0);
+        
+       }
+       
+       protected void addStraight() throws Exception{
+        TurnComponent turn = (TurnComponent)getLast();
+        PipeControlPoint turnCP = turn.getControlPoint();
+        
+        InlineComponent straight = ComponentUtils.createStraight(root);
+        
+        PipeControlPoint straightCP = straight.getControlPoint();
+        straight.setName(pipeRun.getUniqueName("Pipe"));
+        
+        
+        pipeRun.addChild(straight);
+        
+        added.add(straight);
+        
+        
+        
+        if (!reversed) {
+            turnCP.setNext(straightCP);
+            straightCP.setPrevious(turnCP);
+        } else {
+            turnCP.setPrevious(straightCP);
+            straightCP.setNext(turnCP);
+        }
+        
+        turnCP.setWorldPosition(currentPosition);
+        turnCP.setTurnAngle(0.0);
+        turnCP.setLength(0.0);
+        straightCP.setWorldPosition(currentPosition);
+        straightCP.setLength(0.0);
            
-           private void endPiping() throws Exception {
-               state = ToolState.NOT_ACTIVE;
-                
-               if (endTo != null) {
-                       PipeControlPoint endCP = endTo.getControlPoint();
-                       if (endType == null || endType == PositionType.NEXT || endType == PositionType.PREVIOUS) {
-                               
-                               PipelineComponent current = getLast();
-                               PipeControlPoint currentCP = current.getControlPoint();
-                               
-                               boolean requiresReverse = false;
-                               if (!reversed && endCP.getPrevious() != null) {
-                                       requiresReverse = true;
-                               } else if (reversed && endCP.getNext() != null) {
-                                       requiresReverse = true;
-                               }
-                               PipeRun other = endCP.getPipeRun();
-                               boolean mergeRuns = pipeRun.equalSpecs(other);
-                               
-                               if (requiresReverse) {
-                                       // Pipe line must be traversible with next/previous relations without direction change.
-                                       // Now the component, where we are connecting the created pipeline is defined in different order.
-                                       PipingRules.reverse(other);
-                                       
-                               }
-                               if (mergeRuns) {
-                                       // Runs have compatible specs and must be merged
-                                       if (pipeRun != other) // FIXME: temporary workaround.
-                                               PipingRules.merge(pipeRun, other);
-                                       if (!reversed) {
-                                               currentCP.setNext(endCP);
-                                               endCP.setPrevious(currentCP);
-                                       } else {
-                                               currentCP.setPrevious(endCP);
-                                               endCP.setNext(currentCP);
-                                       }
-                               } else {
-                                       // Runs do not have compatible specs, and a reducer must be attached in between.
-                                       InlineComponent reducer = ComponentUtils.createReducer(root);
-                                       PipeControlPoint pcp = reducer.getControlPoint();
-                                       PipeControlPoint ocp = pcp.getSubPoint().get(0);
-                                       
-                                       Vector3d endPos = endCP.getWorldPosition();
-                                       Vector3d currentPos = currentCP.getWorldPosition();
-                                       Vector3d v = new Vector3d(endPos);
-                                       v.sub(currentPos);
-                                       v.scale(0.5);
-                                       v.add(currentPos);
-                                       
-                                       PipingRules.addSizeChange(reversed, pipeRun, other, reducer, currentCP, endCP);
-                                       
-                                       pcp.setWorldPosition(v);
-                                       reducer.updateParameters();
-                               }
-                               
-                       } else if (endType == PositionType.SPLIT) {
-                               InlineComponent branchSplit = createBranchSplit((InlineComponent)endTo, currentPosition);
-                                       PipeControlPoint branchSplitCP = branchSplit.getControlPoint();
-                                       PipeControlPoint pcp = new PipeControlPoint(branchSplit,pipeRun);
-                                       branchSplitCP.children.add(pcp);
-                                       pcp.parent = branchSplitCP;
-                                       pcp.setWorldOrientation(branchSplitCP.getWorldOrientation());
-                                       pcp.setWorldPosition(branchSplitCP.getWorldPosition());
-                                       
-                                       PipelineComponent current = getLast();
-                               PipeControlPoint currentCP = current.getControlPoint();
-                               
-                               
-                               if(!reversed) {
-                                       pcp.setPrevious(currentCP);
-                                       currentCP.setNext(pcp);
-                               } else {
-                                       pcp.setNext(currentCP);
-                                       currentCP.setPrevious(pcp);
-                               }
-                                       
-                       }
-                       PipingRules.positionUpdate(endCP);
-               }
-               panel.useDefaultAction();
-           }
+       }
+       
+       protected void addPoint() throws Exception {
+               addTurn();
+               addStraight();
+               setPreviousPosition(currentPosition);
+               updateCurrentPoint();
+               
+               
+               
+       }
+       
+       /**
+        * Updates tool graphics for current point 
+        */
+       protected void updateCurrentPoint() {
+               InlineComponent straight = (InlineComponent)added.get(added.size()-1);
+               // TODO: the inline length is from previous update step.
+               double l;
+               if (!reversed)
+                       l = straight.getPrevious().getControlPoint().getInlineLength();
+               else
+                       l = straight.getNext().getControlPoint().getInlineLength();
+               Vector3d v = new Vector3d();
+               v.sub(currentPosition, previousPosition);
+               double length = v.length();
+               if (length > MathTools.NEAR_ZERO) {
+                       v.scale(1.0/length);
+                       v.scale(0.5*(length+l));
+                       v.add(previousPosition);
+                       straight.getControlPoint().setWorldPosition(v);
+                       straight.getControlPoint().setLength(length);
+               }
+               try {
+                       PipingRules.positionUpdate(straight.getControlPoint(),false);
+               } catch (Exception e) {
+                       // TODO Auto-generated catch block
+                       e.printStackTrace();
+               }
+       }
+       
+       private PipelineComponent getLast() {
+               if (added.size() == 0)
+                       return startComponent;
+               return added.get(added.size()-1);
+       }
+       
+       
+       /**
+        * Removes last point from pipeline
+        */
+       public void removePoint() {
+               if (added.size() < 3)
+                       return;
+               InlineComponent straight = (InlineComponent)added.remove(added.size()-1);
+               TurnComponent turn = (TurnComponent)added.remove(added.size()-1);
+               straight.getControlPoint().remove();
+               turn.getControlPoint().remove();
+               if (added.size() > 1) {
+                       setPreviousPosition(added.get(added.size()-2).getWorldPosition());
+               } else {
+                       setPreviousPosition(startComponent.getWorldPosition());
+                       if (direction != null)
+                               setLockType(LockType.CUSTOM, true);
+               }
+               
+       }
+       
+       protected void endPiping() throws Exception {
+               state = ToolState.NOT_ACTIVE;
+               
+               if (endTo != null) {
+                   if (endType == PositionType.NEXT || endType == PositionType.PREVIOUS && endTo instanceof InlineComponent) {
+                       Vector3d dir = endTo.getControlPoint().getPathLegDirection(Direction.NEXT);
+                   Vector3d currDir = getLast().getControlPoint().getPathLegDirection(Direction.NEXT);
+                   dir.normalize();
+                   currDir.normalize();
+                   double dot = dir.dot(currDir);
+                   System.out.println(dot + " " + currDir + " " + dir);
+                   if (dot < ALIGN_DOT_PRODUCT && dot> -ALIGN_DOT_PRODUCT) {
+                       addTurn();    
+                   }
+                       
+                   }
+                       ComponentUtils.connect(getLast(), endTo, endType, currentPosition);
+               }
+               panel.useDefaultAction();
+       }
 }