1 package org.simantics.plant3d.actions;
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;
12 import javax.vecmath.Point3d;
13 import javax.vecmath.Tuple3d;
14 import javax.vecmath.Vector3d;
16 import org.simantics.g3d.math.MathTools;
17 import org.simantics.g3d.math.Ray;
18 import org.simantics.g3d.scenegraph.NodeMap;
19 import org.simantics.g3d.scenegraph.base.INode;
20 import org.simantics.g3d.tools.ConstraintDetector;
21 import org.simantics.g3d.vtk.gizmo.TranslateAxisGizmo;
22 import org.simantics.g3d.vtk.swt.InteractiveVtkComposite;
23 import org.simantics.g3d.vtk.swt.vtkSwtAction;
24 import org.simantics.g3d.vtk.utils.vtkUtil;
25 import org.simantics.plant3d.Activator;
26 import org.simantics.plant3d.gizmo.SplitPointSelectionGizmo;
27 import org.simantics.plant3d.gizmo.TerminalSelectionGizmo;
28 import org.simantics.plant3d.scenegraph.EndComponent;
29 import org.simantics.plant3d.scenegraph.InlineComponent;
30 import org.simantics.plant3d.scenegraph.Nozzle;
31 import org.simantics.plant3d.scenegraph.P3DRootNode;
32 import org.simantics.plant3d.scenegraph.PipeRun;
33 import org.simantics.plant3d.scenegraph.PipelineComponent;
34 import org.simantics.plant3d.scenegraph.TurnComponent;
35 import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint;
36 import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint.Direction;
37 import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint.PositionType;
38 import org.simantics.plant3d.scenegraph.controlpoint.PipingRules;
39 import org.simantics.plant3d.utils.ComponentUtils;
40 import org.simantics.utils.threads.ThreadUtils;
41 import org.simantics.utils.ui.ExceptionUtils;
44 import vtk.vtkTextActor;
46 public class RoutePipeAction extends vtkSwtAction {
48 X, Y, Z, XY, YZ, XZ, NONE, CUSTOM
51 LockType lock = LockType.NONE;
52 private double BRANCH_SNAP_DISTANCE = 0.05;
53 private double NOZZLE_SNAP_DISTANCE = 0.05;
55 private double istep = 10.0;
56 private int decimals = 2;
58 private P3DRootNode root;
59 private PipelineComponent startComponent;
60 private PipeRun pipeRun;
62 private TranslateAxisGizmo translateAxisGizmo = new TranslateAxisGizmo();
63 private SplitPointSelectionGizmo splitPointSelectionGizmo;
64 private TerminalSelectionGizmo terminalSelectionGizmo;
65 private NodeMap<vtkProp,INode> nodeMap;
67 private enum ToolState{NOT_ACTIVE, INITIALIZING, SELECTING_POSITION, SELECTING_SPLIT, ROUTING};
68 private ToolState state = ToolState.NOT_ACTIVE;
70 private ConstraintDetector detector;// = new DummyConstraintDetector();
72 private boolean useDefault = false;
73 private Vector3d direction = null;
74 private Vector3d previousPosition = null;
75 private Vector3d currentPosition = null;
79 PipelineComponent endTo = null;
80 PositionType endType = null;
81 PipeControlPoint endPort = null;
83 boolean reversed = false;
85 private Set<PositionType> allowed = new HashSet<PositionType>();
88 public RoutePipeAction(InteractiveVtkComposite panel, P3DRootNode root) {
91 setText("Route Pipe");
92 setImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/Straight.png"));
93 nodeMap = root.getNodeMap();
94 splitPointSelectionGizmo = new SplitPointSelectionGizmo(panel);
95 terminalSelectionGizmo = new TerminalSelectionGizmo(panel);
96 detector = new org.simantics.g3d.vtk.swt.ConstraintDetector(panel);
99 public void setComponent(PipelineComponent component) {
100 this.startComponent = component;
102 if (this.startComponent.getNext() == null)
103 allowed.add(PositionType.NEXT);
104 if (this.startComponent.getPrevious() == null && !(this.startComponent instanceof Nozzle))
105 allowed.add(PositionType.PREVIOUS);
106 if (this.startComponent instanceof InlineComponent && !this.startComponent.getControlPoint().isFixed())
107 allowed.add(PositionType.SPLIT);
108 setEnabled(allowed.size() > 0);
111 public void deattach() {
113 startComponent = null;
114 nodeMap.commit("Route pipe");
120 public void attach() {
121 if (startComponent == null)
125 ThreadUtils.asyncExec(panel.getThreadQueue(), new Runnable() {
130 } catch (Exception e) {
132 ExceptionUtils.logAndShowError(e);
140 // private void attachUI() {
141 // //panel.setCursor(activeCursor);
142 // translateAxisGizmo.attach(panel.GetRenderer());
145 private void deattachUI() {
146 //panel.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
148 if (translateAxisGizmo.isAttached())
149 translateAxisGizmo.deattach();
150 if (splitPointSelectionGizmo.isAttached())
151 splitPointSelectionGizmo.deattach();
152 if (terminalSelectionGizmo.isAttached())
153 terminalSelectionGizmo.deattach();
154 if (infoActor != null) {
155 panel.getRenderer().RemoveActor(infoActor);
162 private List<PipelineComponent> added = new ArrayList<PipelineComponent>();
165 public boolean keyPressed(KeyEvent e) {
166 if (e.getKeyCode() == KeyEvent.VK_ESCAPE)
167 panel.useDefaultAction();
168 if (lock != LockType.CUSTOM) {
169 if ((e.getModifiersEx() & KeyEvent.SHIFT_DOWN_MASK) > 0) {
170 if (e.getKeyCode() == KeyEvent.VK_X) {
171 if (lock != LockType.XY && lock != LockType.XZ) {
172 setLockType(LockType.XY, false);
173 } else if (lock == LockType.XY) {
174 setLockType(LockType.XZ, false);
176 setLockType(LockType.NONE, false);
179 if (e.getKeyCode() == KeyEvent.VK_Y) {
180 if (lock != LockType.XY && lock != LockType.YZ) {
181 setLockType(LockType.XY, false);
182 } else if (lock == LockType.XY) {
183 setLockType(LockType.YZ, false);
185 setLockType(LockType.NONE, false);
188 if (e.getKeyCode() == KeyEvent.VK_Z) {
189 if (lock != LockType.XZ && lock != LockType.YZ) {
190 setLockType(LockType.XZ, false);
191 } else if (lock == LockType.XZ) {
192 setLockType(LockType.YZ, false);
194 setLockType(LockType.NONE, false);
198 if (e.getKeyCode() == KeyEvent.VK_X) {
199 if (lock != LockType.X)
200 setLockType(LockType.X,false);
202 setLockType(LockType.NONE,false);
204 if (e.getKeyCode() == KeyEvent.VK_Y) {
205 if (lock != LockType.Y)
206 setLockType(LockType.Y,false);
208 setLockType(LockType.NONE, false);
210 if (e.getKeyCode() == KeyEvent.VK_Z) {
211 if (lock != LockType.Z)
212 setLockType(LockType.Z, false);
214 setLockType(LockType.NONE, false);
218 if (e.getKeyCode() == KeyEvent.VK_C) {
219 useDefault = !useDefault;
220 System.out.println("UseDefault " + useDefault);
231 private void update() {
234 private void update(double x, double y) {
237 return; // TODO : throw Exception?
240 case SELECTING_POSITION:
242 case SELECTING_SPLIT:
251 boolean startRemovable = false;
253 private void activate() throws Exception {
254 state = ToolState.INITIALIZING;
257 if (allowed.size() == 1) {
258 pipeRun = startComponent.getPipeRun();
259 PipeControlPoint start = startComponent.getControlPoint();
260 boolean requiresBranching = false;
261 if (start.getNext() == null)
263 else if (start.getPrevious() == null) {
266 requiresBranching = true;
269 if (requiresBranching) {
270 activateSplit(start);
272 activateNextPrev(start);
274 } else if (allowed.size() == 0) {
275 panel.useDefaultAction();
276 state = ToolState.NOT_ACTIVE;
279 terminalSelectionGizmo.setComponent(startComponent, allowed);
280 terminalSelectionGizmo.attach(panel);
281 state = ToolState.SELECTING_POSITION;
289 private void activateNextPrev(PipeControlPoint start) throws Exception{
290 if (!reversed && start.isDualInline())
291 start = start.getSubPoint().get(0);
292 else if (reversed && start.isDualSub())
293 start = start.parent;
295 pipeRun = start.getPipeRun();
296 setPreviousPosition(start.getWorldPosition());
298 boolean startWithTurn = false;
299 if (startComponent instanceof Nozzle) {
300 direction = startComponent.getControlPoint().getDirectedControlPointDirection();
301 lock = LockType.CUSTOM;
302 } else if (startComponent instanceof PipelineComponent){
303 if (startComponent instanceof InlineComponent) {
304 direction = startComponent.getControlPoint().getPathLegDirection(reversed ? Direction.PREVIOUS : Direction.NEXT);
305 lock = LockType.CUSTOM;
306 if (((InlineComponent) startComponent).isVariableLength()) {
307 startWithTurn = true;
309 lock = LockType.NONE;
311 Vector3d v = new Vector3d();
313 start.getControlPointEnds(v, previousPosition);
315 start.getControlPointEnds(previousPosition,v);
317 } else if (startComponent instanceof TurnComponent) {
318 if (start.isFixed()) {
319 direction = startComponent.getControlPoint().getPathLegDirection(reversed ? Direction.PREVIOUS : Direction.NEXT);
320 lock = LockType.CUSTOM;
323 lock = LockType.NONE;
325 } else if (startComponent instanceof EndComponent) {
326 throw new Exception("Not supported");
330 throw new Exception("Not supported");
332 currentPosition = new Vector3d(previousPosition);
333 state = ToolState.ROUTING;
334 if (direction != null) {
335 direction.normalize();
338 startRemovable = start.isDeletable();
339 start.setDeletable(false);
344 if (direction != null)
345 currentPosition.add(direction);
346 InlineComponent straight = ComponentUtils.createStraight(root);
347 PipeControlPoint straightCP = straight.getControlPoint();
348 straight.setName(pipeRun.getUniqueName("Pipe"));
349 pipeRun.addChild(straight);
353 start.setNext(straightCP);
354 straightCP.setPrevious(start);
356 start.setPrevious(straightCP);
357 straightCP.setNext(start);
360 translateAxisGizmo.attach(panel);
361 setPreviousPosition(previousPosition);
362 updateCurrentPoint();
365 private void setPreviousPosition(Vector3d v) {
366 previousPosition = new Vector3d(v);
367 if (translateAxisGizmo.isAttached())
368 translateAxisGizmo.setPosition(previousPosition);
371 private void activateBranch(PipeControlPoint start) throws Exception{
372 pipeRun = start.getPipeRun();
373 setPreviousPosition(start.getWorldPosition());
376 lock = LockType.NONE;
378 currentPosition = new Vector3d(previousPosition);
379 state = ToolState.ROUTING;
380 if (direction != null) {
381 direction.normalize();
384 startRemovable = start.isDeletable();
385 start.setDeletable(false);
388 if (direction != null)
389 currentPosition.add(direction);
390 InlineComponent straight = ComponentUtils.createStraight(root);
391 PipeControlPoint straightCP = straight.getControlPoint();
392 straight.setName(pipeRun.getUniqueName("Pipe"));
393 pipeRun.addChild(straight);
397 start.setNext(straightCP);
398 straightCP.setPrevious(start);
401 start.setPrevious(straightCP);
402 straightCP.setNext(start);
406 translateAxisGizmo.attach(panel);
407 setPreviousPosition(previousPosition);
408 updateCurrentPoint();
411 private void activateSplit(PipeControlPoint start) throws Exception{
412 Point3d p1 = new Point3d();
413 Point3d p2 = new Point3d();
414 start.getInlineControlPointEnds(p1, p2);
415 splitPointSelectionGizmo.setSplit(p1, p2);
416 splitPointSelectionGizmo.attach(panel);
417 state = ToolState.SELECTING_SPLIT;
419 public void deactivate() {
420 for (PipelineComponent component : added) {
421 component.getControlPoint().setDeletable(true);
425 startComponent.getControlPoint().setDeletable(startRemovable);
429 setLockType(LockType.NONE, true);
430 startComponent = null;
436 currentPosition = null;
437 previousPosition = null;
438 startRemovable = false;
439 detector.clearConstraintHighlights();
440 state = ToolState.NOT_ACTIVE;
445 private void setLockType(LockType type, boolean force) {
446 if (force || lock != LockType.CUSTOM) {
452 translateAxisGizmo.setType(6);
455 translateAxisGizmo.setType(0);
458 translateAxisGizmo.setType(1);
461 translateAxisGizmo.setType(2);
464 translateAxisGizmo.setType(3);
467 translateAxisGizmo.setType(4);
470 translateAxisGizmo.setType(5);
478 public boolean mousePressed(MouseEvent e) {
480 getDefaultAction().mousePressed(e);
486 public boolean mouseReleased(MouseEvent e) {
488 getDefaultAction().mouseReleased(e);
494 public boolean mouseWheelMoved(MouseWheelEvent e) {
496 getDefaultAction().mouseWheelMoved(e);
502 public boolean mouseClicked(MouseEvent e) {
504 getDefaultAction().mouseClicked(e);
507 if (state == ToolState.ROUTING) {
509 if (e.getClickCount() == 1) {
510 if (e.getButton() == MouseEvent.BUTTON1) {
511 if (this.added.size() > 0) {
513 setLockType(LockType.NONE,true);
521 throw new RuntimeException("kjf");
522 // // user was selecting position of branch
523 // lastPoint.set(startPoint);
524 // controlPoints.add(new Point3d(startPoint));
525 // if (selectionLine != null)
526 // selectionLine.removeFromParent();
527 // selectionLine = null;
529 } else if (e.getButton() ==MouseEvent.BUTTON2){
531 } else if (e.getButton() == MouseEvent.BUTTON3){
535 } catch(Exception err) {
536 err.printStackTrace();
538 } else if (state == ToolState.SELECTING_POSITION) {
539 if (e.getClickCount() == 1 && e.getButton() == MouseEvent.BUTTON1) {
540 int type = panel.getPickType();
541 //panel.setPickType(0);
542 panel.setPickType(5);
543 vtkProp[] picked = panel.pick(e.getX(), e.getY());
544 panel.setPickType(type);
545 PositionType position = terminalSelectionGizmo.getPickedPosition(picked);
546 if (position != null) {
547 terminalSelectionGizmo.deattach();
549 if (position == PositionType.SPLIT) {
550 activateSplit(startComponent.getControlPoint());
551 } else if (position == PositionType.NEXT || position == PositionType.PREVIOUS) {
552 reversed = position == PositionType.PREVIOUS;
553 activateNextPrev(startComponent.getControlPoint());
555 panel.useDefaultAction();
557 } catch (Exception err) {
558 ExceptionUtils.logAndShowError(err);
559 panel.useDefaultAction();
563 } else if (state == ToolState.SELECTING_SPLIT) {
564 if (e.getClickCount() == 1 && e.getButton() == MouseEvent.BUTTON1) {
565 Tuple3d t = splitPointSelectionGizmo.getSplitPoint();
566 splitPointSelectionGizmo.deattach();
568 panel.useDefaultAction();
572 Vector3d pos = new Vector3d(t);
573 InlineComponent branchSplit = ComponentUtils.createBranchSplit((InlineComponent)startComponent, pos);
574 PipeControlPoint branchSplitCP = branchSplit.getControlPoint();
576 PipeRun newRun = new PipeRun();
577 String n = root.getUniqueName("PipeRun");
579 root.addChild(newRun);
580 PipeControlPoint pcp = new PipeControlPoint(branchSplit,newRun);
581 branchSplitCP.children.add(pcp);
582 pcp.parent = branchSplitCP;
583 pcp.setWorldOrientation(branchSplitCP.getWorldOrientation());
584 pcp.setWorldPosition(branchSplitCP.getWorldPosition());
585 startComponent = branchSplit;
587 } catch (Exception err) {
588 ExceptionUtils.logAndShowError(err);
589 panel.useDefaultAction();
596 private void updateConstraints() {
597 detector.clearConstraints();
598 if (hoverObject == null) {
601 if (hoverObject instanceof Nozzle) {
602 Nozzle n = (Nozzle)hoverObject;
603 detector.addContraintPoint(new Point3d(n.getWorldPosition()));
604 } else if (hoverObject instanceof InlineComponent) {
605 InlineComponent c = (InlineComponent)hoverObject;
606 Point3d p1 = new Point3d();
607 Point3d p2 = new Point3d();
609 detector.addContraintPoint(p1);
610 detector.addContraintPoint(p2);
611 } else if (hoverObject instanceof TurnComponent) {
612 TurnComponent n = (TurnComponent)hoverObject;
613 detector.addContraintPoint(new Point3d(n.getWorldPosition()));
618 public boolean mouseMoved(MouseEvent e) {
620 getDefaultAction().mouseMoved(e);
623 step = ((e.getModifiers() & MouseEvent.CTRL_MASK) > 0);
624 update(e.getX(), e.getY());
629 public boolean mouseDragged(MouseEvent e) {
631 getDefaultAction().mouseDragged(e);
638 private List<INode> isOverNode(int x, int y) {
639 List<INode> nodes = new ArrayList<INode>();
640 vtkProp picked[] = panel.pick2(x, y);
642 for (int i = 0; i < picked.length; i++) {
643 nodes.add(nodeMap.getNode(picked[i]));
649 INode hoverObject = null;
651 private void updateRouting(double x, double y) {
652 // if(input.keyPressed(KeyEvent.VK_ESCAPE)) {
653 // controlPoints.clear();
657 // if (input.keyPressed(KeyEvent.VK_C)) {
658 // useCamera = !useCamera;
659 // cameraAction.setChecked(useCamera);
662 //panel.getDefaultAction().update();
670 Ray ray = vtkUtil.createMouseRay(panel.getRenderer(),x, y);
671 Vector3d o = new Vector3d(ray.pos);
672 Vector3d d = ray.dir;
675 if (!updateCurrentPoint(o, d))
677 //Point3d startPoint = new Point3d();
678 double mu[] = new double[2];
684 List<INode> hover = isOverNode((int)x,(int)y);
685 if (hover.size() > 0) {
686 hoverObject = hover.get(0);
690 // System.out.println(hoverObject + " " + getLast());
691 if (hoverObject != null) {
692 if (hoverObject.equals(getLast()) ) {
694 for (int i = 1; i < hover.size(); i++) {
695 hoverObject = hover.get(i);
696 if (!getLast().equals(hoverObject)) {
705 // System.out.println(hoverObject);
706 if (hoverObject != null) {
708 if (lock == LockType.NONE) {
709 if (hoverObject instanceof Nozzle && endingToNozzle(hoverObject,o,d)) {
710 endTo = (Nozzle)hoverObject;
711 } else if (hoverObject instanceof InlineComponent && ((InlineComponent)hoverObject).isVariableLength()) {
712 endTo = (InlineComponent)hoverObject;
713 endType = endingToStraight(endTo,mu,o,d);
716 } else if (hoverObject instanceof PipelineComponent && (endPort = endingToComponent(hoverObject,o,d)) != null) {
717 endTo = (PipelineComponent)hoverObject;
722 if (hoverObject instanceof InlineComponent && ((InlineComponent)hoverObject).isVariableLength() && (endType = endingLockToStraight(hoverObject,mu)) != null) {
723 endTo = (InlineComponent)hoverObject;
724 } else if (hoverObject instanceof Nozzle && endingLockToNozzle(hoverObject)) {
725 endTo = (Nozzle)hoverObject;
726 } else if ((hoverObject instanceof PipelineComponent) && ((endPort = endingLockToComponent(hoverObject)) != null)) {
727 endTo = (PipelineComponent)hoverObject;
732 if (added.contains(endTo))
742 private boolean updateCurrentPoint(Vector3d o, Vector3d d) {
744 Vector3d point = new Vector3d(this.previousPosition);
748 MathTools.intersectStraightStraight(point, new Vector3d(1.0,0.0,0.0), o,d, currentPosition, new Vector3d());
750 currentPosition.x = Math.round(istep * currentPosition.x) / istep;
751 BigDecimal bx = new BigDecimal(currentPosition.x);
752 bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);
753 currentPosition.x = bx.doubleValue();
757 MathTools.intersectStraightStraight(point, new Vector3d(0.0,1.0,0.0), o,d, currentPosition, new Vector3d());
759 currentPosition.y = Math.round(istep * currentPosition.y) / istep;
760 BigDecimal bx = new BigDecimal(currentPosition.y);
761 bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);
762 currentPosition.y = bx.doubleValue();
766 MathTools.intersectStraightStraight(point, new Vector3d(0.0,0.0,1.0), o,d, currentPosition, new Vector3d());
768 currentPosition.z = Math.round(istep * currentPosition.z) / istep;
769 BigDecimal bx = new BigDecimal(currentPosition.z);
770 bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);
771 currentPosition.z = bx.doubleValue();
774 MathTools.intersectStraightPlane(o, d, point, new Vector3d(0.0,0.0,1.0), currentPosition);
777 MathTools.intersectStraightPlane(o, d, point, new Vector3d(0.0,1.0,0.0), currentPosition);
780 MathTools.intersectStraightPlane(o, d, point, new Vector3d(1.0,0.0,0.0), currentPosition);
783 Vector3d normal = new Vector3d(panel.getRenderer().GetActiveCamera().GetDirectionOfProjection());
786 MathTools.intersectStraightPlane(o, d, point, normal, currentPosition);
789 MathTools.intersectStraightStraight(point, new Vector3d(direction), o,d, currentPosition, new Vector3d());
790 double dist = MathTools.distanceFromPlane(new Vector3d(currentPosition), direction, previousPosition);
792 currentPosition.set(previousPosition);
800 private Vector3d getLockDir() {
805 return new Vector3d(1,0,0);
807 return new Vector3d(0,1,0);
809 return new Vector3d(0,0,1);
814 private void updateRoute(Vector3d o, Vector3d d) {
815 detector.clearConstraintHighlights();
816 Point3d previousPipePoint = new Point3d(previousPosition);
818 if (lock == LockType.NONE) {
819 Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint));
821 currentPosition = new Vector3d(p);
822 s += detector.getSnapString();
825 Vector3d dir = new Vector3d(currentPosition);
826 dir.sub(previousPipePoint);
827 Point3d p = detector.getPointSnap(new Vector3d(previousPipePoint), dir);
829 currentPosition = new Vector3d(p);
830 s += detector.getSnapString();
833 // System.out.println(previousPosition + " -> " + currentPosition);
834 // double dist = MathTools.distance(previousPosition, currentPosition);
835 // if (dist < pipeRun.getTurnRadius()) {
837 // Vector3d v = new Vector3d(currentPosition);
838 // v.sub(previousPosition);
839 // double vl = v.length();
840 // if (vl > MathTools.NEAR_ZERO) {
846 // v.scale(pipeRun.getTurnRadius());
847 // v.add(previousPosition);
848 // currentPosition.set(v);
851 updateCurrentPoint();
852 s += currentPosition.toString();
856 vtkTextActor infoActor;
858 private void setInfoText(String text) {
859 //System.out.println(text);
860 if (infoActor == null) {
861 infoActor = new vtkTextActor();
862 infoActor.GetTextProperty().SetColor(0.0, 0.0, 0.0);
863 infoActor.GetTextProperty().ShadowOff();
864 infoActor.GetTextProperty().ItalicOff();
865 infoActor.GetTextProperty().BoldOff();
866 infoActor.GetTextProperty().SetFontSize(18);
867 infoActor.GetTextProperty().Delete();
868 infoActor.GetProperty().SetColor(0.0, 0.0, 0.0);
869 infoActor.GetProperty().Delete();
872 infoActor.SetPosition(10,10);
873 panel.getRenderer().AddActor(infoActor);
875 infoActor.SetInput(text);
878 private boolean endingToNozzle(INode nozzleNode,Vector3d o, Vector3d d) {
879 Nozzle nozzle = (Nozzle)nozzleNode;
880 PipeControlPoint pcp =nozzle.getControlPoint();
881 if (pcp != null && (pcp.getNext() != null ||
882 pcp.getPrevious() != null))
883 return false; // nozzle is already connected to pipe
884 currentPosition = pcp.getWorldPosition();
885 Point3d previousPipePoint = new Point3d(previousPosition);
886 Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint));
888 if (MathTools.distance(p, currentPosition) > NOZZLE_SNAP_DISTANCE) {
893 updateCurrentPoint();
895 setInfoText("Connect to nozzle " + currentPosition);
900 private PositionType endingToStraight(INode straightNode, double mu[], Vector3d o, Vector3d d) {
901 InlineComponent s = (InlineComponent)straightNode;
903 Point3d sStart = new Point3d();
904 Point3d sEnd = new Point3d();
905 s.getEnds(sStart, sEnd);
906 //detector.clearConstraintHighlights();
908 Point3d previousPipePoint = new Point3d(previousPosition);
909 Point3d currentPipePoint = new Point3d(currentPosition);
911 if (lock == LockType.NONE) {
912 Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint));
914 currentPosition = new Vector3d(p);
915 // snapping is detected, check if snapped point can create branch with straight
916 PositionType t = endingLockToStraight(s, mu);
919 // if not, we'll have to remove highlight that was added when snapped point was detected
920 detector.clearConstraintHighlights();
923 Vector3d sDir = new Vector3d(sEnd);
925 MathTools.intersectStraightStraight(sStart, sDir, o, d, currentPosition, new Point3d(), mu);
929 throw new RuntimeException("Lock shouldn't be on");
933 updateCurrentPoint();
935 // branch point must lie between straight's ends. If connection point is exactly
936 // on straight end user may want to connect pipes to each other
937 // TODO : take account sizes of inline components)
939 boolean connectPrev = false;
940 boolean connectNext = false;
941 boolean branch = false;
945 else if (mu[0] > 0.9) {
951 PipeControlPoint pcp = s.getControlPoint();
952 if (pcp.getPrevious() != null)
954 } else if (connectNext) {
955 PipeControlPoint pcp = s.getControlPoint();
956 if (pcp.getNext() != null)
959 Vector3d dir = s.getControlPoint().getPathLegDirection(Direction.NEXT);
960 Vector3d currDir = getLast().getControlPoint().getPathLegDirection(Direction.NEXT);
963 double dot = dir.dot(currDir);
964 System.out.println(dot + " " + currDir + " " + dir);
965 if (dot > 0.95 || dot < -0.95) {
966 // pipes are almost in the same direction, creating a branch is not feasible.
974 if (connectNext || connectPrev)
975 info += "Connect pipes :";
977 info += "Create a Branch :";
979 setInfoText(info + currentPosition + " " + Math.max(0.0, Math.min(mu[0], 1.0)));
981 currentPosition.set(sEnd);
982 updateCurrentPoint();
983 return PositionType.NEXT;
984 } else if (connectPrev){
985 currentPosition.set(sStart);
986 updateCurrentPoint();
987 return PositionType.PREVIOUS;
989 return PositionType.SPLIT;
991 currentPosition.set(currentPipePoint);
992 updateCurrentPoint();
998 private PipeControlPoint endingToComponent(INode componentNode, Vector3d o, Vector3d d) {
999 PipelineComponent component = (PipelineComponent)componentNode;
1000 PipeControlPoint pcp = component.getControlPoint();
1001 if (component instanceof EndComponent) {
1002 if (pcp.getNext() != null || pcp.getPrevious() != null)
1005 } else if (component instanceof TurnComponent) {
1006 if (pcp.getNext() == null || pcp.getPrevious() == null)
1009 } else if (component instanceof InlineComponent) {
1010 // TODO : scan all empty pcps of the component and select closest one.
1011 if (pcp.getNext() == null || pcp.getPrevious() == null)
1019 private PositionType endingLockToStraight(INode straightNode, double mu[]) {
1020 InlineComponent s = (InlineComponent)straightNode;
1021 Point3d sStart = new Point3d();
1022 Point3d sEnd = new Point3d();
1023 s.getControlPoint().getInlineControlPointEnds(sStart, sEnd);
1024 Vector3d sDir = new Vector3d(sEnd);
1026 Vector3d dir = new Vector3d(currentPosition);
1027 Point3d prev = new Point3d(previousPosition);
1029 // intersection point in pipe where branch would be inserted to
1030 Vector3d branchPoint = new Vector3d();
1031 // intersection point in straight pipe that is currently routed
1032 Vector3d routePoint = new Vector3d();
1033 MathTools.intersectStraightStraight(sStart, sDir, new Vector3d(prev), dir, branchPoint, routePoint, mu);
1034 routePoint.sub(branchPoint);
1035 // startPoint of branch must be between pipe ends
1036 // TODO : take account sizes of elbows (or other components)
1037 // branch point must be between pipe ends and intersection points must be quite close to each other
1038 if (mu[0] > 0.0 && mu[0] < 1.0 && routePoint.lengthSquared() < BRANCH_SNAP_DISTANCE) {
1039 currentPosition.set(branchPoint);
1041 updateCurrentPoint();
1043 setInfoText("Create a branch (l) :" + currentPosition + " " + Math.max(0.0, Math.min(mu[0], 1.0)) + " " + routePoint.lengthSquared());
1044 return PositionType.SPLIT;
1049 private boolean endingLockToNozzle(INode nozzleNode) {
1050 Nozzle nozzle = (Nozzle)nozzleNode;
1051 Vector3d dir = new Vector3d(currentPosition);
1052 Point3d prev = new Point3d(previousPosition);
1054 Vector3d nozzleLoc = nozzle.getWorldPosition();
1055 double u[] = new double[1];
1056 Vector3d closest = MathTools.closestPointOnStraight(new Point3d(nozzleLoc), new Point3d(prev), new Vector3d(dir), u);
1057 double dist = MathTools.distanceSquared(nozzleLoc,closest);
1058 if (dist < BRANCH_SNAP_DISTANCE) {
1059 // FIXME : directions should be checked (insert an elbow)
1060 currentPosition.set(nozzleLoc);
1061 updateCurrentPoint();
1062 setInfoText("Connect to nozzle (l) :" + currentPosition);
1065 //System.out.println(u[0]);
1069 private PipeControlPoint endingLockToComponent(INode componentNode) {
1070 // we'll must scan all free pcp's and their direction to accept the connection.
1074 private void addPoint() throws Exception {
1075 InlineComponent previous = (InlineComponent)getLast();
1076 PipeControlPoint previousCP = previous.getControlPoint();
1077 TurnComponent turn = ComponentUtils.createTurn(root);
1078 InlineComponent straight = ComponentUtils.createStraight(root);
1079 PipeControlPoint turnCP = turn.getControlPoint();
1080 PipeControlPoint straightCP = straight.getControlPoint();
1081 straight.setName(pipeRun.getUniqueName("Pipe"));
1082 turn.setName(pipeRun.getUniqueName("Elbow"));
1083 pipeRun.addChild(turn);
1084 pipeRun.addChild(straight);
1086 added.add(straight);
1088 turnCP.setDeletable(false); // mark turnCP nonDeletable so that PipingRules won't delete it immediately.
1091 previousCP.setNext(turnCP);
1092 turnCP.setPrevious(previousCP);
1093 turnCP.setNext(straightCP);
1094 straightCP.setPrevious(turnCP);
1096 previousCP.setPrevious(turnCP);
1097 turnCP.setNext(previousCP);
1098 turnCP.setPrevious(straightCP);
1099 straightCP.setNext(turnCP);
1102 turnCP.setWorldPosition(currentPosition);
1103 turnCP.setTurnAngle(0.0);
1104 turnCP.setLength(0.0);
1105 straightCP.setWorldPosition(currentPosition);
1106 straightCP.setLength(0.0);
1108 setPreviousPosition(currentPosition);
1109 updateCurrentPoint();
1116 * Updates tool graphics for current point
1118 private void updateCurrentPoint() {
1119 InlineComponent straight = (InlineComponent)added.get(added.size()-1);
1120 // TODO: the inline length is from previous update step.
1123 l = straight.getPrevious().getControlPoint().getInlineLength();
1125 l = straight.getNext().getControlPoint().getInlineLength();
1126 Vector3d v = new Vector3d();
1127 v.sub(currentPosition, previousPosition);
1128 double length = v.length();
1129 if (length > MathTools.NEAR_ZERO) {
1130 v.scale(1.0/length);
1131 v.scale(0.5*(length+l));
1132 v.add(previousPosition);
1133 straight.getControlPoint().setWorldPosition(v);
1134 straight.getControlPoint().setLength(length);
1137 PipingRules.positionUpdate(straight.getControlPoint(),false);
1138 } catch (Exception e) {
1139 // TODO Auto-generated catch block
1140 e.printStackTrace();
1144 private PipelineComponent getLast() {
1145 if (added.size() == 0)
1146 return startComponent;
1147 return added.get(added.size()-1);
1152 * Removes last point from pipeline
1154 public void removePoint() {
1155 if (added.size() < 3)
1157 InlineComponent straight = (InlineComponent)added.remove(added.size()-1);
1158 TurnComponent turn = (TurnComponent)added.remove(added.size()-1);
1159 straight.getControlPoint().remove();
1160 turn.getControlPoint().remove();
1161 if (added.size() > 1) {
1162 setPreviousPosition(added.get(added.size()-2).getWorldPosition());
1164 setPreviousPosition(startComponent.getWorldPosition());
1165 if (direction != null)
1166 setLockType(LockType.CUSTOM, true);
1171 private void endPiping() throws Exception {
1172 state = ToolState.NOT_ACTIVE;
1174 if (endTo != null) {
1175 ComponentUtils.connect(getLast(), endTo, endType, currentPosition);
1177 panel.useDefaultAction();