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.db.Resource;
17 import org.simantics.g3d.math.MathTools;
18 import org.simantics.g3d.math.Ray;
19 import org.simantics.g3d.scenegraph.NodeMap;
20 import org.simantics.g3d.scenegraph.base.INode;
21 import org.simantics.g3d.tools.ConstraintDetector;
22 import org.simantics.g3d.vtk.gizmo.TranslateAxisGizmo;
23 import org.simantics.g3d.vtk.swt.InteractiveVtkComposite;
24 import org.simantics.g3d.vtk.swt.vtkSwtAction;
25 import org.simantics.g3d.vtk.utils.vtkUtil;
26 import org.simantics.plant3d.Activator;
27 import org.simantics.plant3d.gizmo.ConstraintPointGizmo;
28 import org.simantics.plant3d.gizmo.SplitPointSelectionGizmo;
29 import org.simantics.plant3d.gizmo.TerminalSelectionGizmo;
30 import org.simantics.plant3d.scenegraph.EndComponent;
31 import org.simantics.plant3d.scenegraph.InlineComponent;
32 import org.simantics.plant3d.scenegraph.Nozzle;
33 import org.simantics.plant3d.scenegraph.P3DRootNode;
34 import org.simantics.plant3d.scenegraph.PipeRun;
35 import org.simantics.plant3d.scenegraph.PipelineComponent;
36 import org.simantics.plant3d.scenegraph.TurnComponent;
37 import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint;
38 import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint.Direction;
39 import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint.PositionType;
40 import org.simantics.plant3d.scenegraph.controlpoint.PipingRules;
41 import org.simantics.plant3d.utils.ComponentUtils;
42 import org.simantics.utils.threads.ThreadUtils;
43 import org.simantics.utils.ui.ExceptionUtils;
46 import vtk.vtkTextActor;
48 public class RoutePipeAction extends vtkSwtAction {
50 X, Y, Z, XY, YZ, XZ, NONE, CUSTOM
53 LockType lock = LockType.NONE;
55 private double BRANCH_SNAP_DISTANCE = 0.05;
56 private double NOZZLE_SNAP_DISTANCE = 0.05;
57 private static double BRANCH_DOT_PRODUCT = 0.95; // dot product value used for prevent branch creation
58 private static double ALIGN_DOT_PRODUCT = 0.99; // dot product for creating turn when connecting pipes
60 private double istep = 10.0;
61 private int decimals = 2;
63 private P3DRootNode root;
64 protected PipelineComponent startComponent;
65 protected PipeRun pipeRun;
66 private boolean allowBranches;
68 protected TranslateAxisGizmo translateAxisGizmo = new TranslateAxisGizmo();
69 private SplitPointSelectionGizmo splitPointSelectionGizmo;
70 private ConstraintPointGizmo constraintPointGizmo;
71 private TerminalSelectionGizmo terminalSelectionGizmo;
72 private NodeMap<Resource,vtkProp,INode> nodeMap;
74 protected enum ToolState{NOT_ACTIVE, INITIALIZING, SELECTING_POSITION, SELECTING_SPLIT, ROUTING};
75 protected ToolState state = ToolState.NOT_ACTIVE;
77 private ConstraintDetector detector;// = new DummyConstraintDetector();
79 protected boolean useDefault = false;
80 protected Vector3d direction = null;
81 protected Vector3d previousPosition = null;
82 protected Vector3d currentPosition = null;
86 PipelineComponent endTo = null;
87 PositionType endType = null;
88 PipeControlPoint endPort = null;
90 boolean reversed = false;
92 private Set<PositionType> allowed = new HashSet<PositionType>();
94 public RoutePipeAction(InteractiveVtkComposite panel, P3DRootNode root) {
95 this(panel,root, true);
98 public RoutePipeAction(InteractiveVtkComposite panel, P3DRootNode root, boolean allowBranches) {
101 this.allowBranches = allowBranches;
102 setText("Route Pipe");
103 setImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/Straight.png"));
104 nodeMap = root.getNodeMap();
105 splitPointSelectionGizmo = new SplitPointSelectionGizmo(panel);
106 terminalSelectionGizmo = new TerminalSelectionGizmo(panel);
107 constraintPointGizmo = new ConstraintPointGizmo(panel);
108 detector = new org.simantics.g3d.vtk.swt.ConstraintDetector(panel);
111 public void setComponent(PipelineComponent component) {
112 this.startComponent = component;
114 if (this.startComponent.getNext() == null)
115 allowed.add(PositionType.NEXT);
116 if (this.startComponent.getPrevious() == null && !(this.startComponent instanceof Nozzle))
117 allowed.add(PositionType.PREVIOUS);
118 if (allowBranches && this.startComponent instanceof InlineComponent && !this.startComponent.getControlPoint().isFixedLength())
119 allowed.add(PositionType.SPLIT);
120 setEnabled(allowed.size() > 0);
123 public void deattach() {
125 startComponent = null;
132 public void attach() {
133 if (startComponent == null)
137 ThreadUtils.asyncExec(panel.getThreadQueue(), new Runnable() {
142 } catch (Exception e) {
144 ExceptionUtils.logAndShowError(e);
152 // private void attachUI() {
153 // //panel.setCursor(activeCursor);
154 // translateAxisGizmo.attach(panel.GetRenderer());
157 private void deattachUI() {
158 //panel.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
160 if (translateAxisGizmo.isAttached())
161 translateAxisGizmo.deattach();
162 if (splitPointSelectionGizmo.isAttached())
163 splitPointSelectionGizmo.deattach();
164 if (terminalSelectionGizmo.isAttached())
165 terminalSelectionGizmo.deattach();
166 if (constraintPointGizmo.isAttached())
167 constraintPointGizmo.deattach();
168 if (infoActor != null) {
169 panel.getRenderer().RemoveActor(infoActor);
176 protected List<PipelineComponent> added = new ArrayList<PipelineComponent>();
179 public boolean keyPressed(KeyEvent e) {
180 if (e.getKeyCode() == KeyEvent.VK_ESCAPE)
181 panel.useDefaultAction();
182 if (lock != LockType.CUSTOM || !lockForced) {
183 if ((e.getModifiersEx() & KeyEvent.SHIFT_DOWN_MASK) > 0) {
184 if (e.getKeyCode() == KeyEvent.VK_X) {
185 if (lock != LockType.XY && lock != LockType.XZ) {
186 setLockType(LockType.XY, false);
187 } else if (lock == LockType.XY) {
188 setLockType(LockType.XZ, false);
190 setLockType(LockType.NONE, false);
193 if (e.getKeyCode() == KeyEvent.VK_Y) {
194 if (lock != LockType.XY && lock != LockType.YZ) {
195 setLockType(LockType.XY, false);
196 } else if (lock == LockType.XY) {
197 setLockType(LockType.YZ, false);
199 setLockType(LockType.NONE, false);
202 if (e.getKeyCode() == KeyEvent.VK_Z) {
203 if (lock != LockType.XZ && lock != LockType.YZ) {
204 setLockType(LockType.XZ, false);
205 } else if (lock == LockType.XZ) {
206 setLockType(LockType.YZ, false);
208 setLockType(LockType.NONE, false);
212 if (e.getKeyCode() == KeyEvent.VK_X) {
213 if (lock != LockType.X)
214 setLockType(LockType.X,false);
216 setLockType(LockType.NONE,false);
218 if (e.getKeyCode() == KeyEvent.VK_Y) {
219 if (lock != LockType.Y)
220 setLockType(LockType.Y,false);
222 setLockType(LockType.NONE, false);
224 if (e.getKeyCode() == KeyEvent.VK_Z) {
225 if (lock != LockType.Z)
226 setLockType(LockType.Z, false);
228 setLockType(LockType.NONE, false);
230 if (e.getKeyCode() == KeyEvent.VK_L && direction != null) {
231 if (lock != LockType.CUSTOM)
232 setLockType(LockType.CUSTOM, false);
234 setLockType(LockType.NONE, false);
238 if (e.getKeyCode() == KeyEvent.VK_C) {
239 useDefault = !useDefault;
241 setInfoText("Rotating camera");
242 System.out.println("UseDefault " + useDefault);
253 private void update() {
256 private void update(double x, double y) {
259 return; // TODO : throw Exception?
262 case SELECTING_POSITION:
264 case SELECTING_SPLIT:
273 boolean startRemovable = false;
275 protected void activate() throws Exception {
276 state = ToolState.INITIALIZING;
279 if (allowed.size() == 1) {
280 pipeRun = startComponent.getPipeRun();
281 PipeControlPoint start = startComponent.getControlPoint();
282 boolean requiresBranching = false;
283 if (start.getNext() == null)
285 else if (start.getPrevious() == null) {
288 requiresBranching = true;
291 if (requiresBranching) {
292 activateSplit(start);
294 activateNextPrev(start);
296 } else if (allowed.size() == 0) {
297 panel.useDefaultAction();
298 state = ToolState.NOT_ACTIVE;
301 terminalSelectionGizmo.setComponent(startComponent, allowed);
302 terminalSelectionGizmo.attach(panel);
303 state = ToolState.SELECTING_POSITION;
311 protected void activateNextPrev(PipeControlPoint start) throws Exception{
312 if (!reversed && start.isDualInline())
313 start = start.getSubPoint().get(0);
314 else if (reversed && start.isDualSub())
315 start = start.parent;
317 pipeRun = start.getPipeRun();
318 setPreviousPosition(start.getWorldPosition());
320 boolean startWithTurn = false;
321 if (startComponent instanceof Nozzle) {
322 direction = startComponent.getControlPoint().getDirectedControlPointDirection();
323 lock = LockType.CUSTOM;
325 } else if (startComponent instanceof PipelineComponent){
326 if (startComponent instanceof InlineComponent) {
327 direction = startComponent.getControlPoint().getPathLegDirection(reversed ? Direction.PREVIOUS : Direction.NEXT);
328 lock = LockType.CUSTOM;
330 if (((InlineComponent) startComponent).isVariableLength()) {
331 startWithTurn = true;
333 lock = LockType.NONE;
336 Vector3d v = new Vector3d();
338 start.getControlPointEnds(v, previousPosition);
340 start.getControlPointEnds(previousPosition,v);
342 } else if (startComponent instanceof TurnComponent) {
343 if (start.asFixedAngle()) {
344 direction = startComponent.getControlPoint().getPathLegDirection(reversed ? Direction.PREVIOUS : Direction.NEXT);
345 lock = LockType.CUSTOM;
346 lockForced = start.isFixedAngle();
349 lock = LockType.NONE;
352 } else if (startComponent instanceof EndComponent) {
353 throw new Exception("Not supported");
357 throw new Exception("Not supported");
359 currentPosition = new Vector3d(previousPosition);
360 state = ToolState.ROUTING;
361 if (direction != null) {
362 direction.normalize();
365 startRemovable = start.isDeletable();
366 start.setDeletable(false);
371 if (direction != null)
372 currentPosition.add(direction);
373 InlineComponent straight = ComponentUtils.createStraight(root);
374 PipeControlPoint straightCP = straight.getControlPoint();
375 straight.setName(pipeRun.getUniqueName("Pipe"));
376 pipeRun.addChild(straight);
380 start.setNext(straightCP);
381 straightCP.setPrevious(start);
383 start.setPrevious(straightCP);
384 straightCP.setNext(start);
387 translateAxisGizmo.attach(panel);
388 setPreviousPosition(previousPosition);
389 updateCurrentPoint();
392 protected void setPreviousPosition(Vector3d v) {
393 previousPosition = new Vector3d(v);
394 if (translateAxisGizmo.isAttached())
395 translateAxisGizmo.setPosition(previousPosition);
398 private void activateBranch(PipeControlPoint start) throws Exception{
399 pipeRun = start.getPipeRun();
400 setPreviousPosition(start.getWorldPosition());
403 lock = LockType.NONE;
405 currentPosition = new Vector3d(previousPosition);
406 state = ToolState.ROUTING;
407 if (direction != null) {
408 direction.normalize();
411 startRemovable = start.isDeletable();
412 start.setDeletable(false);
415 if (direction != null)
416 currentPosition.add(direction);
417 InlineComponent straight = ComponentUtils.createStraight(root);
418 PipeControlPoint straightCP = straight.getControlPoint();
419 straight.setName(pipeRun.getUniqueName("Pipe"));
420 pipeRun.addChild(straight);
424 start.setNext(straightCP);
425 straightCP.setPrevious(start);
428 start.setPrevious(straightCP);
429 straightCP.setNext(start);
433 translateAxisGizmo.attach(panel);
434 setPreviousPosition(previousPosition);
435 updateCurrentPoint();
438 private void activateSplit(PipeControlPoint start) throws Exception{
439 Point3d p1 = new Point3d();
440 Point3d p2 = new Point3d();
441 start.getInlineControlPointEnds(p1, p2);
442 splitPointSelectionGizmo.setSplit(p1, p2);
443 splitPointSelectionGizmo.attach(panel);
444 state = ToolState.SELECTING_SPLIT;
446 public void deactivate() {
447 if (added.size() > 0) {
448 for (PipelineComponent component : added) {
449 component.getControlPoint().setDeletable(true);
452 for (PipelineComponent comp : added) {
453 PipingRules.requestUpdate(comp.getControlPoint());
456 PipingRules.update();
457 nodeMap.commit("Route pipe");
458 } catch (Exception e) {
459 ExceptionUtils.logAndShowError(e);
464 startComponent.getControlPoint().setDeletable(startRemovable);
468 setLockType(LockType.NONE, true);
469 startComponent = null;
475 currentPosition = null;
476 previousPosition = null;
477 startRemovable = false;
478 detector.clearConstraintHighlights();
479 state = ToolState.NOT_ACTIVE;
484 private void setLockType(LockType type, boolean force) {
485 if (force || (lock != LockType.CUSTOM || !lockForced) ) {
491 translateAxisGizmo.setType(6);
494 translateAxisGizmo.setType(0);
497 translateAxisGizmo.setType(1);
500 translateAxisGizmo.setType(2);
503 translateAxisGizmo.setType(3);
506 translateAxisGizmo.setType(4);
509 translateAxisGizmo.setType(5);
517 public boolean mousePressed(MouseEvent e) {
519 getDefaultAction().mousePressed(e);
525 public boolean mouseReleased(MouseEvent e) {
527 getDefaultAction().mouseReleased(e);
533 public boolean mouseWheelMoved(MouseWheelEvent e) {
535 getDefaultAction().mouseWheelMoved(e);
541 public boolean mouseClicked(MouseEvent e) {
543 getDefaultAction().mouseClicked(e);
546 if (state == ToolState.ROUTING) {
548 if (e.getClickCount() == 1) {
549 if (e.getButton() == MouseEvent.BUTTON1) {
550 if (this.added.size() > 0) {
552 setLockType(LockType.NONE,true);
560 throw new RuntimeException("RoutePipeAction initlialization has been failed, no added components found");
561 // // user was selecting position of branch
562 // lastPoint.set(startPoint);
563 // controlPoints.add(new Point3d(startPoint));
564 // if (selectionLine != null)
565 // selectionLine.removeFromParent();
566 // selectionLine = null;
568 } else if (e.getButton() ==MouseEvent.BUTTON2){
570 } else if (e.getButton() == MouseEvent.BUTTON3){
574 } catch(Exception err) {
575 err.printStackTrace();
577 } else if (state == ToolState.SELECTING_POSITION) {
578 if (e.getClickCount() == 1 && e.getButton() == MouseEvent.BUTTON1) {
579 int type = panel.getPickType();
580 //panel.setPickType(0);
581 panel.setPickType(5);
582 vtkProp[] picked = panel.pick(e.getX(), e.getY());
583 panel.setPickType(type);
584 PositionType position = terminalSelectionGizmo.getPickedPosition(picked);
585 if (position != null) {
586 terminalSelectionGizmo.deattach();
588 if (position == PositionType.SPLIT) {
589 activateSplit(startComponent.getControlPoint());
590 } else if (position == PositionType.NEXT || position == PositionType.PREVIOUS) {
591 reversed = position == PositionType.PREVIOUS;
592 activateNextPrev(startComponent.getControlPoint());
594 panel.useDefaultAction();
596 } catch (Exception err) {
597 ExceptionUtils.logAndShowError(err);
598 panel.useDefaultAction();
602 } else if (state == ToolState.SELECTING_SPLIT) {
603 if (e.getClickCount() == 1 && e.getButton() == MouseEvent.BUTTON1) {
604 Tuple3d t = splitPointSelectionGizmo.getSplitPoint();
605 splitPointSelectionGizmo.deattach();
607 panel.useDefaultAction();
611 Vector3d pos = new Vector3d(t);
612 InlineComponent branchSplit = ComponentUtils.createBranchSplit((InlineComponent)startComponent, pos);
613 PipeControlPoint branchSplitCP = branchSplit.getControlPoint();
615 PipeRun newRun = new PipeRun();
616 String n = root.getUniqueName("PipeRun");
618 root.addChild(newRun);
619 PipeControlPoint pcp = new PipeControlPoint(branchSplit,newRun);
620 branchSplitCP.children.add(pcp);
621 pcp.parent = branchSplitCP;
622 pcp.setWorldOrientation(branchSplitCP.getWorldOrientation());
623 pcp.setWorldPosition(branchSplitCP.getWorldPosition());
624 startComponent = branchSplit;
626 } catch (Exception err) {
627 ExceptionUtils.logAndShowError(err);
628 panel.useDefaultAction();
635 private void updateConstraints() {
636 detector.clearConstraints();
637 constraintPointGizmo.clearPositions();
638 if (hoverObject == null) {
639 if (constraintPointGizmo.isAttached())
640 constraintPointGizmo.deattach();
643 if (hoverObject instanceof Nozzle) {
644 Nozzle n = (Nozzle)hoverObject;
645 detector.addContraintPoint(new Point3d(n.getWorldPosition()));
646 } else if (hoverObject instanceof InlineComponent) {
647 InlineComponent c = (InlineComponent)hoverObject;
648 Point3d p1 = new Point3d();
649 Point3d p2 = new Point3d();
651 detector.addContraintPoint(p1);
652 detector.addContraintPoint(p2);
653 detector.addContraintPoint(new Point3d(c.getWorldPosition()));
654 } else if (hoverObject instanceof TurnComponent) {
655 TurnComponent n = (TurnComponent)hoverObject;
656 detector.addContraintPoint(new Point3d(n.getWorldPosition()));
658 if (detector.getConstraintPoints().size() > 0) {
659 for (Point3d p : detector.getConstraintPoints()) {
660 constraintPointGizmo.addPosition(new Vector3d(p));
662 if (constraintPointGizmo.isAttached())
663 constraintPointGizmo.deattach();
664 constraintPointGizmo.attach(panel);
669 public boolean mouseMoved(MouseEvent e) {
671 getDefaultAction().mouseMoved(e);
674 step = ((e.getModifiers() & MouseEvent.CTRL_MASK) > 0);
675 update(e.getX(), e.getY());
680 public boolean mouseDragged(MouseEvent e) {
682 getDefaultAction().mouseDragged(e);
689 private List<INode> isOverNode(int x, int y) {
690 List<INode> nodes = new ArrayList<INode>();
691 vtkProp picked[] = panel.pick2(x, y);
693 for (int i = 0; i < picked.length; i++) {
694 nodes.add(nodeMap.getNode(picked[i]));
700 INode hoverObject = null;
702 protected void updateRouting(double x, double y) {
704 //panel.getDefaultAction().update();
712 Ray ray = vtkUtil.createMouseRay(panel.getRenderer(),x, y);
713 Vector3d o = new Vector3d(ray.pos);
714 Vector3d d = ray.dir;
717 if (!updateCurrentPoint(o, d))
719 //Point3d startPoint = new Point3d();
720 double mu[] = new double[2];
726 List<INode> hover = isOverNode((int)x,(int)y);
727 if (hover.size() > 0) {
728 hoverObject = hover.get(0);
732 // System.out.println(hoverObject + " " + getLast());
733 if (hoverObject != null) {
734 if (hoverObject.equals(getLast()) ) {
736 for (int i = 1; i < hover.size(); i++) {
737 hoverObject = hover.get(i);
738 if (!getLast().equals(hoverObject)) {
747 // System.out.println(hoverObject);
748 if (hoverObject != null) {
750 if (lock == LockType.NONE) {
751 if (hoverObject instanceof Nozzle && endingToNozzle(hoverObject,o,d)) {
752 endTo = (Nozzle)hoverObject;
753 } else if (hoverObject instanceof InlineComponent && ((InlineComponent)hoverObject).isVariableLength()) {
754 endTo = (InlineComponent)hoverObject;
755 endType = endingToStraight(endTo,mu,o,d);
758 } else if (hoverObject instanceof PipelineComponent && (endPort = endingToComponent(hoverObject,o,d)) != null) {
759 endTo = (PipelineComponent)hoverObject;
764 if (hoverObject instanceof InlineComponent && ((InlineComponent)hoverObject).isVariableLength() && (endType = endingLockToStraight(hoverObject,mu, new Point3d(currentPosition))) != null) {
765 endTo = (InlineComponent)hoverObject;
766 } else if (hoverObject instanceof Nozzle && endingLockToNozzle(hoverObject)) {
767 endTo = (Nozzle)hoverObject;
768 } else if ((hoverObject instanceof PipelineComponent) && ((endPort = endingLockToComponent(hoverObject)) != null)) {
769 endTo = (PipelineComponent)hoverObject;
774 if (added.contains(endTo))
784 protected boolean updateCurrentPoint(Vector3d o, Vector3d d) {
786 Vector3d point = new Vector3d(this.previousPosition);
790 MathTools.intersectStraightStraight(point, new Vector3d(1.0,0.0,0.0), o,d, currentPosition, new Vector3d());
792 currentPosition.x = Math.round(istep * currentPosition.x) / istep;
793 BigDecimal bx = new BigDecimal(currentPosition.x);
794 bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);
795 currentPosition.x = bx.doubleValue();
799 MathTools.intersectStraightStraight(point, new Vector3d(0.0,1.0,0.0), o,d, currentPosition, new Vector3d());
801 currentPosition.y = Math.round(istep * currentPosition.y) / istep;
802 BigDecimal bx = new BigDecimal(currentPosition.y);
803 bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);
804 currentPosition.y = bx.doubleValue();
808 MathTools.intersectStraightStraight(point, new Vector3d(0.0,0.0,1.0), o,d, currentPosition, new Vector3d());
810 currentPosition.z = Math.round(istep * currentPosition.z) / istep;
811 BigDecimal bx = new BigDecimal(currentPosition.z);
812 bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);
813 currentPosition.z = bx.doubleValue();
816 MathTools.intersectStraightPlane(o, d, point, new Vector3d(0.0,0.0,1.0), currentPosition);
819 MathTools.intersectStraightPlane(o, d, point, new Vector3d(0.0,1.0,0.0), currentPosition);
822 MathTools.intersectStraightPlane(o, d, point, new Vector3d(1.0,0.0,0.0), currentPosition);
825 Vector3d normal = new Vector3d(panel.getRenderer().GetActiveCamera().GetDirectionOfProjection());
828 MathTools.intersectStraightPlane(o, d, point, normal, currentPosition);
831 MathTools.intersectStraightStraight(point, new Vector3d(direction), o,d, currentPosition, new Vector3d());
832 double dist = MathTools.distanceFromPlane(new Vector3d(currentPosition), direction, previousPosition);
834 currentPosition.set(previousPosition);
842 @SuppressWarnings("unused")
843 private Vector3d getLockDir() {
848 return new Vector3d(1,0,0);
850 return new Vector3d(0,1,0);
852 return new Vector3d(0,0,1);
858 protected void updateRoute(Vector3d o, Vector3d d) {
859 detector.clearConstraintHighlights();
860 Point3d previousPipePoint = new Point3d(previousPosition);
862 if (lock == LockType.NONE) {
863 Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint));
865 currentPosition = new Vector3d(p);
866 s += detector.getSnapString();
869 Vector3d dir = new Vector3d(currentPosition);
870 dir.sub(previousPipePoint);
871 Point3d p = detector.getPointSnap(new Vector3d(previousPipePoint), dir);
873 currentPosition = new Vector3d(p);
874 s += detector.getSnapString();
877 // System.out.println(previousPosition + " -> " + currentPosition);
878 // double dist = MathTools.distance(previousPosition, currentPosition);
879 // if (dist < pipeRun.getTurnRadius()) {
881 // Vector3d v = new Vector3d(currentPosition);
882 // v.sub(previousPosition);
883 // double vl = v.length();
884 // if (vl > MathTools.NEAR_ZERO) {
890 // v.scale(pipeRun.getTurnRadius());
891 // v.add(previousPosition);
892 // currentPosition.set(v);
895 updateCurrentPoint();
896 s += currentPosition.toString();
900 vtkTextActor infoActor;
902 private void setInfoText(String text) {
903 //System.out.println(text);
904 if (infoActor == null) {
905 infoActor = new vtkTextActor();
906 infoActor.GetTextProperty().SetColor(0.0, 0.0, 0.0);
907 infoActor.GetTextProperty().ShadowOff();
908 infoActor.GetTextProperty().ItalicOff();
909 infoActor.GetTextProperty().BoldOff();
910 infoActor.GetTextProperty().SetFontSize(18);
911 infoActor.GetTextProperty().Delete();
912 infoActor.GetProperty().SetColor(0.0, 0.0, 0.0);
913 infoActor.GetProperty().Delete();
916 infoActor.SetPosition(10,10);
917 panel.getRenderer().AddActor(infoActor);
919 infoActor.SetInput(text);
922 private boolean endingToNozzle(INode nozzleNode,Vector3d o, Vector3d d) {
923 Nozzle nozzle = (Nozzle)nozzleNode;
924 PipeControlPoint pcp =nozzle.getControlPoint();
925 if (pcp != null && (pcp.getNext() != null ||
926 pcp.getPrevious() != null))
927 return false; // nozzle is already connected to pipe
928 currentPosition = pcp.getWorldPosition();
929 Point3d previousPipePoint = new Point3d(previousPosition);
930 Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint));
932 if (MathTools.distance(p, currentPosition) > NOZZLE_SNAP_DISTANCE) {
937 updateCurrentPoint();
939 setInfoText("Connect to nozzle " + currentPosition);
944 private PositionType endingToStraight(INode straightNode, double mu[], Vector3d o, Vector3d d) {
945 // if (!allowBranches) {
946 // updateCurrentPoint();
949 InlineComponent s = (InlineComponent)straightNode;
951 Point3d sStart = new Point3d();
952 Point3d sEnd = new Point3d();
953 s.getEnds(sStart, sEnd);
954 //detector.clearConstraintHighlights();
956 Point3d previousPipePoint = new Point3d(previousPosition);
957 Point3d currentPipePoint = new Point3d(currentPosition);
959 if (lock == LockType.NONE) {
960 Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint));
962 currentPosition = new Vector3d(p);
963 // snapping is detected, check if snapped point can create branch with straight
964 PositionType t = endingLockToStraight(s, mu, currentPipePoint);
967 // if not, we'll have to remove highlight that was added when snapped point was detected
968 detector.clearConstraintHighlights();
971 Vector3d sDir = new Vector3d(sEnd);
973 MathTools.intersectStraightStraight(sStart, sDir, o, d, currentPosition, new Point3d(), mu);
977 throw new RuntimeException("Lock shouldn't be on");
981 updateCurrentPoint();
983 // branch point must lie between straight's ends. If connection point is exactly
984 // on straight end user may want to connect pipes to each other
985 // TODO : take account sizes of inline components)
986 return endingToStraight(mu, s, sStart, sEnd, currentPipePoint);
989 private PositionType endingToStraight(double mu[], InlineComponent s, Point3d sStart, Point3d sEnd , Point3d currentPipePoint) {
992 boolean connectPrev = false;
993 boolean connectNext = false;
994 boolean branch = false;
998 else if (mu[0] > 0.9) {
1004 PipeControlPoint pcp = s.getControlPoint();
1005 if (pcp.getPrevious() != null)
1006 connectPrev = false;
1007 } else if (connectNext) {
1008 PipeControlPoint pcp = s.getControlPoint();
1009 if (pcp.getNext() != null)
1010 connectNext = false;
1012 Vector3d dir = s.getControlPoint().getPathLegDirection(Direction.NEXT);
1013 Vector3d currDir = getLast().getControlPoint().getPathLegDirection(Direction.NEXT);
1015 currDir.normalize();
1016 double dot = dir.dot(currDir);
1017 System.out.println(dot + " " + currDir + " " + dir);
1018 if (dot > BRANCH_DOT_PRODUCT || dot < -BRANCH_DOT_PRODUCT) {
1019 // pipes are almost in the same direction, creating a branch is not feasible.
1027 if (connectNext || connectPrev)
1028 info += "Connect pipes :";
1030 info += "Create a Branch :";
1032 setInfoText(info + currentPosition + " " + Math.max(0.0, Math.min(mu[0], 1.0)));
1034 currentPosition.set(sEnd);
1035 updateCurrentPoint();
1036 return PositionType.NEXT;
1037 } else if (connectPrev){
1038 currentPosition.set(sStart);
1039 updateCurrentPoint();
1040 return PositionType.PREVIOUS;
1041 } else if (branch && allowBranches) {
1042 return PositionType.SPLIT;
1044 currentPosition.set(currentPipePoint);
1045 updateCurrentPoint();
1050 private PipeControlPoint endingToComponent(INode componentNode, Vector3d o, Vector3d d) {
1051 PipelineComponent component = (PipelineComponent)componentNode;
1052 PipeControlPoint pcp = component.getControlPoint();
1053 if (component instanceof EndComponent) {
1054 if (pcp.getNext() != null || pcp.getPrevious() != null)
1057 } else if (component instanceof TurnComponent) {
1058 if (pcp.getNext() == null || pcp.getPrevious() == null)
1061 } else if (component instanceof InlineComponent) {
1062 // TODO : scan all empty pcps of the component and select closest one.
1063 if (pcp.getNext() == null || pcp.getPrevious() == null)
1071 private PositionType endingLockToStraight(INode straightNode, double mu[], Point3d currentPipePoint) {
1072 // if (!allowBranches) {
1073 // updateCurrentPoint();
1076 InlineComponent s = (InlineComponent)straightNode;
1077 Point3d sStart = new Point3d();
1078 Point3d sEnd = new Point3d();
1079 s.getControlPoint().getInlineControlPointEnds(sStart, sEnd);
1080 Vector3d sDir = new Vector3d(sEnd);
1082 Vector3d dir = new Vector3d(currentPosition);
1083 Point3d prev = new Point3d(previousPosition);
1085 // intersection point in pipe where branch would be inserted to
1086 Vector3d branchPoint = new Vector3d();
1087 // intersection point in straight pipe that is currently routed
1088 Vector3d routePoint = new Vector3d();
1089 MathTools.intersectStraightStraight(sStart, sDir, new Vector3d(prev), dir, branchPoint, routePoint, mu);
1090 routePoint.sub(branchPoint);
1091 // startPoint of branch must be between pipe ends
1092 // TODO : take account sizes of elbows (or other components)
1093 // branch point must be between pipe ends and intersection points must be quite close to each other
1095 if (routePoint.lengthSquared() > BRANCH_SNAP_DISTANCE)
1098 return endingToStraight(mu, s, sStart, sEnd, currentPipePoint);
1100 // if (mu[0] > 0.0 && mu[0] < 1.0 && routePoint.lengthSquared() < BRANCH_SNAP_DISTANCE) {
1101 // currentPosition.set(branchPoint);
1103 // updateCurrentPoint();
1105 // setInfoText("Create a branch (l) :" + currentPosition + " " + Math.max(0.0, Math.min(mu[0], 1.0)) + " " + routePoint.lengthSquared());
1106 // return PositionType.SPLIT;
1111 private boolean endingLockToNozzle(INode nozzleNode) {
1112 Nozzle nozzle = (Nozzle)nozzleNode;
1113 Vector3d dir = new Vector3d(currentPosition);
1114 Point3d prev = new Point3d(previousPosition);
1116 Vector3d nozzleLoc = nozzle.getWorldPosition();
1117 double u[] = new double[1];
1118 Vector3d closest = MathTools.closestPointOnStraight(new Point3d(nozzleLoc), new Point3d(prev), new Vector3d(dir), u);
1119 double dist = MathTools.distanceSquared(nozzleLoc,closest);
1120 if (dist < BRANCH_SNAP_DISTANCE) {
1121 // FIXME : directions should be checked (insert an elbow)
1122 currentPosition.set(nozzleLoc);
1123 updateCurrentPoint();
1124 setInfoText("Connect to nozzle (l) :" + currentPosition);
1127 //System.out.println(u[0]);
1131 private PipeControlPoint endingLockToComponent(INode componentNode) {
1132 // we'll must scan all free pcp's and their direction to accept the connection.
1136 protected void addTurn() throws Exception{
1137 InlineComponent previous = (InlineComponent)getLast();
1138 PipeControlPoint previousCP = previous.getControlPoint();
1139 TurnComponent turn = ComponentUtils.createTurn(root);
1140 PipeControlPoint turnCP = turn.getControlPoint();
1141 turn.setName(pipeRun.getUniqueName("Elbow"));
1142 pipeRun.addChild(turn);
1144 turnCP.setDeletable(false); // mark turnCP nonDeletable so that PipingRules won't delete it immediately.
1146 previousCP.setNext(turnCP);
1147 turnCP.setPrevious(previousCP);
1149 previousCP.setPrevious(turnCP);
1150 turnCP.setNext(previousCP);
1153 turnCP.setWorldPosition(currentPosition);
1154 turnCP.setTurnAngle(0.0);
1155 turnCP.setLength(0.0);
1159 protected void addStraight() throws Exception{
1160 TurnComponent turn = (TurnComponent)getLast();
1161 PipeControlPoint turnCP = turn.getControlPoint();
1163 InlineComponent straight = ComponentUtils.createStraight(root);
1165 PipeControlPoint straightCP = straight.getControlPoint();
1166 straight.setName(pipeRun.getUniqueName("Pipe"));
1169 pipeRun.addChild(straight);
1171 added.add(straight);
1176 turnCP.setNext(straightCP);
1177 straightCP.setPrevious(turnCP);
1179 turnCP.setPrevious(straightCP);
1180 straightCP.setNext(turnCP);
1183 turnCP.setWorldPosition(currentPosition);
1184 turnCP.setTurnAngle(0.0);
1185 turnCP.setLength(0.0);
1186 straightCP.setWorldPosition(currentPosition);
1187 straightCP.setLength(0.0);
1191 protected void addPoint() throws Exception {
1194 setPreviousPosition(currentPosition);
1195 updateCurrentPoint();
1202 * Updates tool graphics for current point
1204 protected void updateCurrentPoint() {
1205 InlineComponent straight = (InlineComponent)added.get(added.size()-1);
1206 // TODO: the inline length is from previous update step.
1209 l = straight.getPrevious().getControlPoint().getInlineLength();
1211 l = straight.getNext().getControlPoint().getInlineLength();
1212 Vector3d v = new Vector3d();
1213 v.sub(currentPosition, previousPosition);
1214 double length = v.length();
1215 if (length > MathTools.NEAR_ZERO) {
1216 v.scale(1.0/length);
1217 v.scale(0.5*(length+l));
1218 v.add(previousPosition);
1219 straight.getControlPoint().setWorldPosition(v);
1220 straight.getControlPoint().setLength(length);
1223 PipingRules.positionUpdate(straight.getControlPoint(),false);
1224 } catch (Exception e) {
1225 // TODO Auto-generated catch block
1226 e.printStackTrace();
1230 private PipelineComponent getLast() {
1231 if (added.size() == 0)
1232 return startComponent;
1233 return added.get(added.size()-1);
1238 * Removes last point from pipeline
1240 public void removePoint() {
1241 if (added.size() < 3)
1243 InlineComponent straight = (InlineComponent)added.remove(added.size()-1);
1244 TurnComponent turn = (TurnComponent)added.remove(added.size()-1);
1245 straight.getControlPoint().remove();
1246 turn.getControlPoint().remove();
1247 if (added.size() > 1) {
1248 setPreviousPosition(added.get(added.size()-2).getWorldPosition());
1250 setPreviousPosition(startComponent.getWorldPosition());
1251 if (direction != null)
1252 setLockType(LockType.CUSTOM, true);
1257 protected void endPiping() throws Exception {
1258 state = ToolState.NOT_ACTIVE;
1260 if (endTo != null) {
1261 if (endType == PositionType.NEXT || endType == PositionType.PREVIOUS && endTo instanceof InlineComponent) {
1262 Vector3d dir = endTo.getControlPoint().getPathLegDirection(Direction.NEXT);
1263 Vector3d currDir = getLast().getControlPoint().getPathLegDirection(Direction.NEXT);
1265 currDir.normalize();
1266 double dot = dir.dot(currDir);
1267 System.out.println(dot + " " + currDir + " " + dir);
1268 if (dot < ALIGN_DOT_PRODUCT && dot> -ALIGN_DOT_PRODUCT) {
1273 ComponentUtils.connect(getLast(), endTo, endType, currentPosition);
1275 panel.useDefaultAction();