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.ConstraintPointGizmo;
27 import org.simantics.plant3d.gizmo.SplitPointSelectionGizmo;
28 import org.simantics.plant3d.gizmo.TerminalSelectionGizmo;
29 import org.simantics.plant3d.scenegraph.EndComponent;
30 import org.simantics.plant3d.scenegraph.InlineComponent;
31 import org.simantics.plant3d.scenegraph.Nozzle;
32 import org.simantics.plant3d.scenegraph.P3DRootNode;
33 import org.simantics.plant3d.scenegraph.PipeRun;
34 import org.simantics.plant3d.scenegraph.PipelineComponent;
35 import org.simantics.plant3d.scenegraph.TurnComponent;
36 import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint;
37 import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint.Direction;
38 import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint.PositionType;
39 import org.simantics.plant3d.scenegraph.controlpoint.PipingRules;
40 import org.simantics.plant3d.utils.ComponentUtils;
41 import org.simantics.utils.threads.ThreadUtils;
42 import org.simantics.utils.ui.ExceptionUtils;
45 import vtk.vtkTextActor;
47 public class RoutePipeAction extends vtkSwtAction {
49 X, Y, Z, XY, YZ, XZ, NONE, CUSTOM
52 LockType lock = LockType.NONE;
53 private double BRANCH_SNAP_DISTANCE = 0.05;
54 private double NOZZLE_SNAP_DISTANCE = 0.05;
56 private double istep = 10.0;
57 private int decimals = 2;
59 private P3DRootNode root;
60 private PipelineComponent startComponent;
61 private PipeRun pipeRun;
63 private TranslateAxisGizmo translateAxisGizmo = new TranslateAxisGizmo();
64 private SplitPointSelectionGizmo splitPointSelectionGizmo;
65 private ConstraintPointGizmo constraintPointGizmo;
66 private TerminalSelectionGizmo terminalSelectionGizmo;
67 private NodeMap<vtkProp,INode> nodeMap;
69 private enum ToolState{NOT_ACTIVE, INITIALIZING, SELECTING_POSITION, SELECTING_SPLIT, ROUTING};
70 private ToolState state = ToolState.NOT_ACTIVE;
72 private ConstraintDetector detector;// = new DummyConstraintDetector();
74 private boolean useDefault = false;
75 private Vector3d direction = null;
76 private Vector3d previousPosition = null;
77 private Vector3d currentPosition = null;
81 PipelineComponent endTo = null;
82 PositionType endType = null;
83 PipeControlPoint endPort = null;
85 boolean reversed = false;
87 private Set<PositionType> allowed = new HashSet<PositionType>();
90 public RoutePipeAction(InteractiveVtkComposite panel, P3DRootNode root) {
93 setText("Route Pipe");
94 setImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/Straight.png"));
95 nodeMap = root.getNodeMap();
96 splitPointSelectionGizmo = new SplitPointSelectionGizmo(panel);
97 terminalSelectionGizmo = new TerminalSelectionGizmo(panel);
98 constraintPointGizmo = new ConstraintPointGizmo(panel);
99 detector = new org.simantics.g3d.vtk.swt.ConstraintDetector(panel);
102 public void setComponent(PipelineComponent component) {
103 this.startComponent = component;
105 if (this.startComponent.getNext() == null)
106 allowed.add(PositionType.NEXT);
107 if (this.startComponent.getPrevious() == null && !(this.startComponent instanceof Nozzle))
108 allowed.add(PositionType.PREVIOUS);
109 if (this.startComponent instanceof InlineComponent && !this.startComponent.getControlPoint().isFixed())
110 allowed.add(PositionType.SPLIT);
111 setEnabled(allowed.size() > 0);
114 public void deattach() {
116 startComponent = null;
123 public void attach() {
124 if (startComponent == null)
128 ThreadUtils.asyncExec(panel.getThreadQueue(), new Runnable() {
133 } catch (Exception e) {
135 ExceptionUtils.logAndShowError(e);
143 // private void attachUI() {
144 // //panel.setCursor(activeCursor);
145 // translateAxisGizmo.attach(panel.GetRenderer());
148 private void deattachUI() {
149 //panel.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
151 if (translateAxisGizmo.isAttached())
152 translateAxisGizmo.deattach();
153 if (splitPointSelectionGizmo.isAttached())
154 splitPointSelectionGizmo.deattach();
155 if (terminalSelectionGizmo.isAttached())
156 terminalSelectionGizmo.deattach();
157 if (constraintPointGizmo.isAttached())
158 constraintPointGizmo.deattach();
159 if (infoActor != null) {
160 panel.getRenderer().RemoveActor(infoActor);
167 private List<PipelineComponent> added = new ArrayList<PipelineComponent>();
170 public boolean keyPressed(KeyEvent e) {
171 if (e.getKeyCode() == KeyEvent.VK_ESCAPE)
172 panel.useDefaultAction();
173 if (lock != LockType.CUSTOM) {
174 if ((e.getModifiersEx() & KeyEvent.SHIFT_DOWN_MASK) > 0) {
175 if (e.getKeyCode() == KeyEvent.VK_X) {
176 if (lock != LockType.XY && lock != LockType.XZ) {
177 setLockType(LockType.XY, false);
178 } else if (lock == LockType.XY) {
179 setLockType(LockType.XZ, false);
181 setLockType(LockType.NONE, false);
184 if (e.getKeyCode() == KeyEvent.VK_Y) {
185 if (lock != LockType.XY && lock != LockType.YZ) {
186 setLockType(LockType.XY, false);
187 } else if (lock == LockType.XY) {
188 setLockType(LockType.YZ, false);
190 setLockType(LockType.NONE, false);
193 if (e.getKeyCode() == KeyEvent.VK_Z) {
194 if (lock != LockType.XZ && lock != LockType.YZ) {
195 setLockType(LockType.XZ, false);
196 } else if (lock == LockType.XZ) {
197 setLockType(LockType.YZ, false);
199 setLockType(LockType.NONE, false);
203 if (e.getKeyCode() == KeyEvent.VK_X) {
204 if (lock != LockType.X)
205 setLockType(LockType.X,false);
207 setLockType(LockType.NONE,false);
209 if (e.getKeyCode() == KeyEvent.VK_Y) {
210 if (lock != LockType.Y)
211 setLockType(LockType.Y,false);
213 setLockType(LockType.NONE, false);
215 if (e.getKeyCode() == KeyEvent.VK_Z) {
216 if (lock != LockType.Z)
217 setLockType(LockType.Z, false);
219 setLockType(LockType.NONE, false);
223 if (e.getKeyCode() == KeyEvent.VK_C) {
224 useDefault = !useDefault;
225 System.out.println("UseDefault " + useDefault);
236 private void update() {
239 private void update(double x, double y) {
242 return; // TODO : throw Exception?
245 case SELECTING_POSITION:
247 case SELECTING_SPLIT:
256 boolean startRemovable = false;
258 private void activate() throws Exception {
259 state = ToolState.INITIALIZING;
262 if (allowed.size() == 1) {
263 pipeRun = startComponent.getPipeRun();
264 PipeControlPoint start = startComponent.getControlPoint();
265 boolean requiresBranching = false;
266 if (start.getNext() == null)
268 else if (start.getPrevious() == null) {
271 requiresBranching = true;
274 if (requiresBranching) {
275 activateSplit(start);
277 activateNextPrev(start);
279 } else if (allowed.size() == 0) {
280 panel.useDefaultAction();
281 state = ToolState.NOT_ACTIVE;
284 terminalSelectionGizmo.setComponent(startComponent, allowed);
285 terminalSelectionGizmo.attach(panel);
286 state = ToolState.SELECTING_POSITION;
294 private void activateNextPrev(PipeControlPoint start) throws Exception{
295 if (!reversed && start.isDualInline())
296 start = start.getSubPoint().get(0);
297 else if (reversed && start.isDualSub())
298 start = start.parent;
300 pipeRun = start.getPipeRun();
301 setPreviousPosition(start.getWorldPosition());
303 boolean startWithTurn = false;
304 if (startComponent instanceof Nozzle) {
305 direction = startComponent.getControlPoint().getDirectedControlPointDirection();
306 lock = LockType.CUSTOM;
307 } else if (startComponent instanceof PipelineComponent){
308 if (startComponent instanceof InlineComponent) {
309 direction = startComponent.getControlPoint().getPathLegDirection(reversed ? Direction.PREVIOUS : Direction.NEXT);
310 lock = LockType.CUSTOM;
311 if (((InlineComponent) startComponent).isVariableLength()) {
312 startWithTurn = true;
314 lock = LockType.NONE;
316 Vector3d v = new Vector3d();
318 start.getControlPointEnds(v, previousPosition);
320 start.getControlPointEnds(previousPosition,v);
322 } else if (startComponent instanceof TurnComponent) {
323 if (start.isFixed()) {
324 direction = startComponent.getControlPoint().getPathLegDirection(reversed ? Direction.PREVIOUS : Direction.NEXT);
325 lock = LockType.CUSTOM;
328 lock = LockType.NONE;
330 } else if (startComponent instanceof EndComponent) {
331 throw new Exception("Not supported");
335 throw new Exception("Not supported");
337 currentPosition = new Vector3d(previousPosition);
338 state = ToolState.ROUTING;
339 if (direction != null) {
340 direction.normalize();
343 startRemovable = start.isDeletable();
344 start.setDeletable(false);
349 if (direction != null)
350 currentPosition.add(direction);
351 InlineComponent straight = ComponentUtils.createStraight(root);
352 PipeControlPoint straightCP = straight.getControlPoint();
353 straight.setName(pipeRun.getUniqueName("Pipe"));
354 pipeRun.addChild(straight);
358 start.setNext(straightCP);
359 straightCP.setPrevious(start);
361 start.setPrevious(straightCP);
362 straightCP.setNext(start);
365 translateAxisGizmo.attach(panel);
366 setPreviousPosition(previousPosition);
367 updateCurrentPoint();
370 private void setPreviousPosition(Vector3d v) {
371 previousPosition = new Vector3d(v);
372 if (translateAxisGizmo.isAttached())
373 translateAxisGizmo.setPosition(previousPosition);
376 private void activateBranch(PipeControlPoint start) throws Exception{
377 pipeRun = start.getPipeRun();
378 setPreviousPosition(start.getWorldPosition());
381 lock = LockType.NONE;
383 currentPosition = new Vector3d(previousPosition);
384 state = ToolState.ROUTING;
385 if (direction != null) {
386 direction.normalize();
389 startRemovable = start.isDeletable();
390 start.setDeletable(false);
393 if (direction != null)
394 currentPosition.add(direction);
395 InlineComponent straight = ComponentUtils.createStraight(root);
396 PipeControlPoint straightCP = straight.getControlPoint();
397 straight.setName(pipeRun.getUniqueName("Pipe"));
398 pipeRun.addChild(straight);
402 start.setNext(straightCP);
403 straightCP.setPrevious(start);
406 start.setPrevious(straightCP);
407 straightCP.setNext(start);
411 translateAxisGizmo.attach(panel);
412 setPreviousPosition(previousPosition);
413 updateCurrentPoint();
416 private void activateSplit(PipeControlPoint start) throws Exception{
417 Point3d p1 = new Point3d();
418 Point3d p2 = new Point3d();
419 start.getInlineControlPointEnds(p1, p2);
420 splitPointSelectionGizmo.setSplit(p1, p2);
421 splitPointSelectionGizmo.attach(panel);
422 state = ToolState.SELECTING_SPLIT;
424 public void deactivate() {
425 if (added.size() > 0) {
426 for (PipelineComponent component : added) {
427 component.getControlPoint().setDeletable(true);
430 for (PipelineComponent comp : added) {
431 PipingRules.requestUpdate(comp.getControlPoint());
434 PipingRules.update();
435 nodeMap.commit("Route pipe");
436 } catch (Exception e) {
437 ExceptionUtils.logAndShowError(e);
442 startComponent.getControlPoint().setDeletable(startRemovable);
446 setLockType(LockType.NONE, true);
447 startComponent = null;
453 currentPosition = null;
454 previousPosition = null;
455 startRemovable = false;
456 detector.clearConstraintHighlights();
457 state = ToolState.NOT_ACTIVE;
462 private void setLockType(LockType type, boolean force) {
463 if (force || lock != LockType.CUSTOM) {
469 translateAxisGizmo.setType(6);
472 translateAxisGizmo.setType(0);
475 translateAxisGizmo.setType(1);
478 translateAxisGizmo.setType(2);
481 translateAxisGizmo.setType(3);
484 translateAxisGizmo.setType(4);
487 translateAxisGizmo.setType(5);
495 public boolean mousePressed(MouseEvent e) {
497 getDefaultAction().mousePressed(e);
503 public boolean mouseReleased(MouseEvent e) {
505 getDefaultAction().mouseReleased(e);
511 public boolean mouseWheelMoved(MouseWheelEvent e) {
513 getDefaultAction().mouseWheelMoved(e);
519 public boolean mouseClicked(MouseEvent e) {
521 getDefaultAction().mouseClicked(e);
524 if (state == ToolState.ROUTING) {
526 if (e.getClickCount() == 1) {
527 if (e.getButton() == MouseEvent.BUTTON1) {
528 if (this.added.size() > 0) {
530 setLockType(LockType.NONE,true);
538 throw new RuntimeException("kjf");
539 // // user was selecting position of branch
540 // lastPoint.set(startPoint);
541 // controlPoints.add(new Point3d(startPoint));
542 // if (selectionLine != null)
543 // selectionLine.removeFromParent();
544 // selectionLine = null;
546 } else if (e.getButton() ==MouseEvent.BUTTON2){
548 } else if (e.getButton() == MouseEvent.BUTTON3){
552 } catch(Exception err) {
553 err.printStackTrace();
555 } else if (state == ToolState.SELECTING_POSITION) {
556 if (e.getClickCount() == 1 && e.getButton() == MouseEvent.BUTTON1) {
557 int type = panel.getPickType();
558 //panel.setPickType(0);
559 panel.setPickType(5);
560 vtkProp[] picked = panel.pick(e.getX(), e.getY());
561 panel.setPickType(type);
562 PositionType position = terminalSelectionGizmo.getPickedPosition(picked);
563 if (position != null) {
564 terminalSelectionGizmo.deattach();
566 if (position == PositionType.SPLIT) {
567 activateSplit(startComponent.getControlPoint());
568 } else if (position == PositionType.NEXT || position == PositionType.PREVIOUS) {
569 reversed = position == PositionType.PREVIOUS;
570 activateNextPrev(startComponent.getControlPoint());
572 panel.useDefaultAction();
574 } catch (Exception err) {
575 ExceptionUtils.logAndShowError(err);
576 panel.useDefaultAction();
580 } else if (state == ToolState.SELECTING_SPLIT) {
581 if (e.getClickCount() == 1 && e.getButton() == MouseEvent.BUTTON1) {
582 Tuple3d t = splitPointSelectionGizmo.getSplitPoint();
583 splitPointSelectionGizmo.deattach();
585 panel.useDefaultAction();
589 Vector3d pos = new Vector3d(t);
590 InlineComponent branchSplit = ComponentUtils.createBranchSplit((InlineComponent)startComponent, pos);
591 PipeControlPoint branchSplitCP = branchSplit.getControlPoint();
593 PipeRun newRun = new PipeRun();
594 String n = root.getUniqueName("PipeRun");
596 root.addChild(newRun);
597 PipeControlPoint pcp = new PipeControlPoint(branchSplit,newRun);
598 branchSplitCP.children.add(pcp);
599 pcp.parent = branchSplitCP;
600 pcp.setWorldOrientation(branchSplitCP.getWorldOrientation());
601 pcp.setWorldPosition(branchSplitCP.getWorldPosition());
602 startComponent = branchSplit;
604 } catch (Exception err) {
605 ExceptionUtils.logAndShowError(err);
606 panel.useDefaultAction();
613 private void updateConstraints() {
614 detector.clearConstraints();
615 constraintPointGizmo.clearPositions();
616 if (hoverObject == null) {
617 if (constraintPointGizmo.isAttached())
618 constraintPointGizmo.deattach();
621 if (hoverObject instanceof Nozzle) {
622 Nozzle n = (Nozzle)hoverObject;
623 detector.addContraintPoint(new Point3d(n.getWorldPosition()));
624 } else if (hoverObject instanceof InlineComponent) {
625 InlineComponent c = (InlineComponent)hoverObject;
626 Point3d p1 = new Point3d();
627 Point3d p2 = new Point3d();
629 detector.addContraintPoint(p1);
630 detector.addContraintPoint(p2);
631 detector.addContraintPoint(new Point3d(c.getWorldPosition()));
632 } else if (hoverObject instanceof TurnComponent) {
633 TurnComponent n = (TurnComponent)hoverObject;
634 detector.addContraintPoint(new Point3d(n.getWorldPosition()));
636 if (detector.getConstraintPoints().size() > 0) {
637 for (Point3d p : detector.getConstraintPoints()) {
638 constraintPointGizmo.addPosition(new Vector3d(p));
640 if (constraintPointGizmo.isAttached())
641 constraintPointGizmo.deattach();
642 constraintPointGizmo.attach(panel);
647 public boolean mouseMoved(MouseEvent e) {
649 getDefaultAction().mouseMoved(e);
652 step = ((e.getModifiers() & MouseEvent.CTRL_MASK) > 0);
653 update(e.getX(), e.getY());
658 public boolean mouseDragged(MouseEvent e) {
660 getDefaultAction().mouseDragged(e);
667 private List<INode> isOverNode(int x, int y) {
668 List<INode> nodes = new ArrayList<INode>();
669 vtkProp picked[] = panel.pick2(x, y);
671 for (int i = 0; i < picked.length; i++) {
672 nodes.add(nodeMap.getNode(picked[i]));
678 INode hoverObject = null;
680 private void updateRouting(double x, double y) {
681 // if(input.keyPressed(KeyEvent.VK_ESCAPE)) {
682 // controlPoints.clear();
686 // if (input.keyPressed(KeyEvent.VK_C)) {
687 // useCamera = !useCamera;
688 // cameraAction.setChecked(useCamera);
691 //panel.getDefaultAction().update();
699 Ray ray = vtkUtil.createMouseRay(panel.getRenderer(),x, y);
700 Vector3d o = new Vector3d(ray.pos);
701 Vector3d d = ray.dir;
704 if (!updateCurrentPoint(o, d))
706 //Point3d startPoint = new Point3d();
707 double mu[] = new double[2];
713 List<INode> hover = isOverNode((int)x,(int)y);
714 if (hover.size() > 0) {
715 hoverObject = hover.get(0);
719 // System.out.println(hoverObject + " " + getLast());
720 if (hoverObject != null) {
721 if (hoverObject.equals(getLast()) ) {
723 for (int i = 1; i < hover.size(); i++) {
724 hoverObject = hover.get(i);
725 if (!getLast().equals(hoverObject)) {
734 // System.out.println(hoverObject);
735 if (hoverObject != null) {
737 if (lock == LockType.NONE) {
738 if (hoverObject instanceof Nozzle && endingToNozzle(hoverObject,o,d)) {
739 endTo = (Nozzle)hoverObject;
740 } else if (hoverObject instanceof InlineComponent && ((InlineComponent)hoverObject).isVariableLength()) {
741 endTo = (InlineComponent)hoverObject;
742 endType = endingToStraight(endTo,mu,o,d);
745 } else if (hoverObject instanceof PipelineComponent && (endPort = endingToComponent(hoverObject,o,d)) != null) {
746 endTo = (PipelineComponent)hoverObject;
751 if (hoverObject instanceof InlineComponent && ((InlineComponent)hoverObject).isVariableLength() && (endType = endingLockToStraight(hoverObject,mu)) != null) {
752 endTo = (InlineComponent)hoverObject;
753 } else if (hoverObject instanceof Nozzle && endingLockToNozzle(hoverObject)) {
754 endTo = (Nozzle)hoverObject;
755 } else if ((hoverObject instanceof PipelineComponent) && ((endPort = endingLockToComponent(hoverObject)) != null)) {
756 endTo = (PipelineComponent)hoverObject;
761 if (added.contains(endTo))
771 private boolean updateCurrentPoint(Vector3d o, Vector3d d) {
773 Vector3d point = new Vector3d(this.previousPosition);
777 MathTools.intersectStraightStraight(point, new Vector3d(1.0,0.0,0.0), o,d, currentPosition, new Vector3d());
779 currentPosition.x = Math.round(istep * currentPosition.x) / istep;
780 BigDecimal bx = new BigDecimal(currentPosition.x);
781 bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);
782 currentPosition.x = bx.doubleValue();
786 MathTools.intersectStraightStraight(point, new Vector3d(0.0,1.0,0.0), o,d, currentPosition, new Vector3d());
788 currentPosition.y = Math.round(istep * currentPosition.y) / istep;
789 BigDecimal bx = new BigDecimal(currentPosition.y);
790 bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);
791 currentPosition.y = bx.doubleValue();
795 MathTools.intersectStraightStraight(point, new Vector3d(0.0,0.0,1.0), o,d, currentPosition, new Vector3d());
797 currentPosition.z = Math.round(istep * currentPosition.z) / istep;
798 BigDecimal bx = new BigDecimal(currentPosition.z);
799 bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);
800 currentPosition.z = bx.doubleValue();
803 MathTools.intersectStraightPlane(o, d, point, new Vector3d(0.0,0.0,1.0), currentPosition);
806 MathTools.intersectStraightPlane(o, d, point, new Vector3d(0.0,1.0,0.0), currentPosition);
809 MathTools.intersectStraightPlane(o, d, point, new Vector3d(1.0,0.0,0.0), currentPosition);
812 Vector3d normal = new Vector3d(panel.getRenderer().GetActiveCamera().GetDirectionOfProjection());
815 MathTools.intersectStraightPlane(o, d, point, normal, currentPosition);
818 MathTools.intersectStraightStraight(point, new Vector3d(direction), o,d, currentPosition, new Vector3d());
819 double dist = MathTools.distanceFromPlane(new Vector3d(currentPosition), direction, previousPosition);
821 currentPosition.set(previousPosition);
829 private Vector3d getLockDir() {
834 return new Vector3d(1,0,0);
836 return new Vector3d(0,1,0);
838 return new Vector3d(0,0,1);
843 private void updateRoute(Vector3d o, Vector3d d) {
844 detector.clearConstraintHighlights();
845 Point3d previousPipePoint = new Point3d(previousPosition);
847 if (lock == LockType.NONE) {
848 Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint));
850 currentPosition = new Vector3d(p);
851 s += detector.getSnapString();
854 Vector3d dir = new Vector3d(currentPosition);
855 dir.sub(previousPipePoint);
856 Point3d p = detector.getPointSnap(new Vector3d(previousPipePoint), dir);
858 currentPosition = new Vector3d(p);
859 s += detector.getSnapString();
862 // System.out.println(previousPosition + " -> " + currentPosition);
863 // double dist = MathTools.distance(previousPosition, currentPosition);
864 // if (dist < pipeRun.getTurnRadius()) {
866 // Vector3d v = new Vector3d(currentPosition);
867 // v.sub(previousPosition);
868 // double vl = v.length();
869 // if (vl > MathTools.NEAR_ZERO) {
875 // v.scale(pipeRun.getTurnRadius());
876 // v.add(previousPosition);
877 // currentPosition.set(v);
880 updateCurrentPoint();
881 s += currentPosition.toString();
885 vtkTextActor infoActor;
887 private void setInfoText(String text) {
888 //System.out.println(text);
889 if (infoActor == null) {
890 infoActor = new vtkTextActor();
891 infoActor.GetTextProperty().SetColor(0.0, 0.0, 0.0);
892 infoActor.GetTextProperty().ShadowOff();
893 infoActor.GetTextProperty().ItalicOff();
894 infoActor.GetTextProperty().BoldOff();
895 infoActor.GetTextProperty().SetFontSize(18);
896 infoActor.GetTextProperty().Delete();
897 infoActor.GetProperty().SetColor(0.0, 0.0, 0.0);
898 infoActor.GetProperty().Delete();
901 infoActor.SetPosition(10,10);
902 panel.getRenderer().AddActor(infoActor);
904 infoActor.SetInput(text);
907 private boolean endingToNozzle(INode nozzleNode,Vector3d o, Vector3d d) {
908 Nozzle nozzle = (Nozzle)nozzleNode;
909 PipeControlPoint pcp =nozzle.getControlPoint();
910 if (pcp != null && (pcp.getNext() != null ||
911 pcp.getPrevious() != null))
912 return false; // nozzle is already connected to pipe
913 currentPosition = pcp.getWorldPosition();
914 Point3d previousPipePoint = new Point3d(previousPosition);
915 Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint));
917 if (MathTools.distance(p, currentPosition) > NOZZLE_SNAP_DISTANCE) {
922 updateCurrentPoint();
924 setInfoText("Connect to nozzle " + currentPosition);
929 private PositionType endingToStraight(INode straightNode, double mu[], Vector3d o, Vector3d d) {
930 InlineComponent s = (InlineComponent)straightNode;
932 Point3d sStart = new Point3d();
933 Point3d sEnd = new Point3d();
934 s.getEnds(sStart, sEnd);
935 //detector.clearConstraintHighlights();
937 Point3d previousPipePoint = new Point3d(previousPosition);
938 Point3d currentPipePoint = new Point3d(currentPosition);
940 if (lock == LockType.NONE) {
941 Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint));
943 currentPosition = new Vector3d(p);
944 // snapping is detected, check if snapped point can create branch with straight
945 PositionType t = endingLockToStraight(s, mu);
948 // if not, we'll have to remove highlight that was added when snapped point was detected
949 detector.clearConstraintHighlights();
952 Vector3d sDir = new Vector3d(sEnd);
954 MathTools.intersectStraightStraight(sStart, sDir, o, d, currentPosition, new Point3d(), mu);
958 throw new RuntimeException("Lock shouldn't be on");
962 updateCurrentPoint();
964 // branch point must lie between straight's ends. If connection point is exactly
965 // on straight end user may want to connect pipes to each other
966 // TODO : take account sizes of inline components)
968 boolean connectPrev = false;
969 boolean connectNext = false;
970 boolean branch = false;
974 else if (mu[0] > 0.9) {
980 PipeControlPoint pcp = s.getControlPoint();
981 if (pcp.getPrevious() != null)
983 } else if (connectNext) {
984 PipeControlPoint pcp = s.getControlPoint();
985 if (pcp.getNext() != null)
988 Vector3d dir = s.getControlPoint().getPathLegDirection(Direction.NEXT);
989 Vector3d currDir = getLast().getControlPoint().getPathLegDirection(Direction.NEXT);
992 double dot = dir.dot(currDir);
993 System.out.println(dot + " " + currDir + " " + dir);
994 if (dot > 0.95 || dot < -0.95) {
995 // pipes are almost in the same direction, creating a branch is not feasible.
1003 if (connectNext || connectPrev)
1004 info += "Connect pipes :";
1006 info += "Create a Branch :";
1008 setInfoText(info + currentPosition + " " + Math.max(0.0, Math.min(mu[0], 1.0)));
1010 currentPosition.set(sEnd);
1011 updateCurrentPoint();
1012 return PositionType.NEXT;
1013 } else if (connectPrev){
1014 currentPosition.set(sStart);
1015 updateCurrentPoint();
1016 return PositionType.PREVIOUS;
1017 } else if (branch) {
1018 return PositionType.SPLIT;
1020 currentPosition.set(currentPipePoint);
1021 updateCurrentPoint();
1027 private PipeControlPoint endingToComponent(INode componentNode, Vector3d o, Vector3d d) {
1028 PipelineComponent component = (PipelineComponent)componentNode;
1029 PipeControlPoint pcp = component.getControlPoint();
1030 if (component instanceof EndComponent) {
1031 if (pcp.getNext() != null || pcp.getPrevious() != null)
1034 } else if (component instanceof TurnComponent) {
1035 if (pcp.getNext() == null || pcp.getPrevious() == null)
1038 } else if (component instanceof InlineComponent) {
1039 // TODO : scan all empty pcps of the component and select closest one.
1040 if (pcp.getNext() == null || pcp.getPrevious() == null)
1048 private PositionType endingLockToStraight(INode straightNode, double mu[]) {
1049 InlineComponent s = (InlineComponent)straightNode;
1050 Point3d sStart = new Point3d();
1051 Point3d sEnd = new Point3d();
1052 s.getControlPoint().getInlineControlPointEnds(sStart, sEnd);
1053 Vector3d sDir = new Vector3d(sEnd);
1055 Vector3d dir = new Vector3d(currentPosition);
1056 Point3d prev = new Point3d(previousPosition);
1058 // intersection point in pipe where branch would be inserted to
1059 Vector3d branchPoint = new Vector3d();
1060 // intersection point in straight pipe that is currently routed
1061 Vector3d routePoint = new Vector3d();
1062 MathTools.intersectStraightStraight(sStart, sDir, new Vector3d(prev), dir, branchPoint, routePoint, mu);
1063 routePoint.sub(branchPoint);
1064 // startPoint of branch must be between pipe ends
1065 // TODO : take account sizes of elbows (or other components)
1066 // branch point must be between pipe ends and intersection points must be quite close to each other
1067 if (mu[0] > 0.0 && mu[0] < 1.0 && routePoint.lengthSquared() < BRANCH_SNAP_DISTANCE) {
1068 currentPosition.set(branchPoint);
1070 updateCurrentPoint();
1072 setInfoText("Create a branch (l) :" + currentPosition + " " + Math.max(0.0, Math.min(mu[0], 1.0)) + " " + routePoint.lengthSquared());
1073 return PositionType.SPLIT;
1078 private boolean endingLockToNozzle(INode nozzleNode) {
1079 Nozzle nozzle = (Nozzle)nozzleNode;
1080 Vector3d dir = new Vector3d(currentPosition);
1081 Point3d prev = new Point3d(previousPosition);
1083 Vector3d nozzleLoc = nozzle.getWorldPosition();
1084 double u[] = new double[1];
1085 Vector3d closest = MathTools.closestPointOnStraight(new Point3d(nozzleLoc), new Point3d(prev), new Vector3d(dir), u);
1086 double dist = MathTools.distanceSquared(nozzleLoc,closest);
1087 if (dist < BRANCH_SNAP_DISTANCE) {
1088 // FIXME : directions should be checked (insert an elbow)
1089 currentPosition.set(nozzleLoc);
1090 updateCurrentPoint();
1091 setInfoText("Connect to nozzle (l) :" + currentPosition);
1094 //System.out.println(u[0]);
1098 private PipeControlPoint endingLockToComponent(INode componentNode) {
1099 // we'll must scan all free pcp's and their direction to accept the connection.
1103 private void addPoint() throws Exception {
1104 InlineComponent previous = (InlineComponent)getLast();
1105 PipeControlPoint previousCP = previous.getControlPoint();
1106 TurnComponent turn = ComponentUtils.createTurn(root);
1107 InlineComponent straight = ComponentUtils.createStraight(root);
1108 PipeControlPoint turnCP = turn.getControlPoint();
1109 PipeControlPoint straightCP = straight.getControlPoint();
1110 straight.setName(pipeRun.getUniqueName("Pipe"));
1111 turn.setName(pipeRun.getUniqueName("Elbow"));
1112 pipeRun.addChild(turn);
1113 pipeRun.addChild(straight);
1115 added.add(straight);
1117 turnCP.setDeletable(false); // mark turnCP nonDeletable so that PipingRules won't delete it immediately.
1120 previousCP.setNext(turnCP);
1121 turnCP.setPrevious(previousCP);
1122 turnCP.setNext(straightCP);
1123 straightCP.setPrevious(turnCP);
1125 previousCP.setPrevious(turnCP);
1126 turnCP.setNext(previousCP);
1127 turnCP.setPrevious(straightCP);
1128 straightCP.setNext(turnCP);
1131 turnCP.setWorldPosition(currentPosition);
1132 turnCP.setTurnAngle(0.0);
1133 turnCP.setLength(0.0);
1134 straightCP.setWorldPosition(currentPosition);
1135 straightCP.setLength(0.0);
1137 setPreviousPosition(currentPosition);
1138 updateCurrentPoint();
1145 * Updates tool graphics for current point
1147 private void updateCurrentPoint() {
1148 InlineComponent straight = (InlineComponent)added.get(added.size()-1);
1149 // TODO: the inline length is from previous update step.
1152 l = straight.getPrevious().getControlPoint().getInlineLength();
1154 l = straight.getNext().getControlPoint().getInlineLength();
1155 Vector3d v = new Vector3d();
1156 v.sub(currentPosition, previousPosition);
1157 double length = v.length();
1158 if (length > MathTools.NEAR_ZERO) {
1159 v.scale(1.0/length);
1160 v.scale(0.5*(length+l));
1161 v.add(previousPosition);
1162 straight.getControlPoint().setWorldPosition(v);
1163 straight.getControlPoint().setLength(length);
1166 PipingRules.positionUpdate(straight.getControlPoint(),false);
1167 } catch (Exception e) {
1168 // TODO Auto-generated catch block
1169 e.printStackTrace();
1173 private PipelineComponent getLast() {
1174 if (added.size() == 0)
1175 return startComponent;
1176 return added.get(added.size()-1);
1181 * Removes last point from pipeline
1183 public void removePoint() {
1184 if (added.size() < 3)
1186 InlineComponent straight = (InlineComponent)added.remove(added.size()-1);
1187 TurnComponent turn = (TurnComponent)added.remove(added.size()-1);
1188 straight.getControlPoint().remove();
1189 turn.getControlPoint().remove();
1190 if (added.size() > 1) {
1191 setPreviousPosition(added.get(added.size()-2).getWorldPosition());
1193 setPreviousPosition(startComponent.getWorldPosition());
1194 if (direction != null)
1195 setLockType(LockType.CUSTOM, true);
1200 private void endPiping() throws Exception {
1201 state = ToolState.NOT_ACTIVE;
1203 if (endTo != null) {
1204 ComponentUtils.connect(getLast(), endTo, endType, currentPosition);
1206 panel.useDefaultAction();