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;
58 private double istep = 10.0;
59 private int decimals = 2;
61 private P3DRootNode root;
62 protected PipelineComponent startComponent;
63 protected PipeRun pipeRun;
64 private boolean allowBranches;
66 protected TranslateAxisGizmo translateAxisGizmo = new TranslateAxisGizmo();
67 private SplitPointSelectionGizmo splitPointSelectionGizmo;
68 private ConstraintPointGizmo constraintPointGizmo;
69 private TerminalSelectionGizmo terminalSelectionGizmo;
70 private NodeMap<Resource,vtkProp,INode> nodeMap;
72 protected enum ToolState{NOT_ACTIVE, INITIALIZING, SELECTING_POSITION, SELECTING_SPLIT, ROUTING};
73 protected ToolState state = ToolState.NOT_ACTIVE;
75 private ConstraintDetector detector;// = new DummyConstraintDetector();
77 protected boolean useDefault = false;
78 protected Vector3d direction = null;
79 protected Vector3d previousPosition = null;
80 protected Vector3d currentPosition = null;
84 PipelineComponent endTo = null;
85 PositionType endType = null;
86 PipeControlPoint endPort = null;
88 boolean reversed = false;
90 private Set<PositionType> allowed = new HashSet<PositionType>();
92 public RoutePipeAction(InteractiveVtkComposite panel, P3DRootNode root) {
93 this(panel,root, true);
96 public RoutePipeAction(InteractiveVtkComposite panel, P3DRootNode root, boolean allowBranches) {
99 this.allowBranches = allowBranches;
100 setText("Route Pipe");
101 setImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/Straight.png"));
102 nodeMap = root.getNodeMap();
103 splitPointSelectionGizmo = new SplitPointSelectionGizmo(panel);
104 terminalSelectionGizmo = new TerminalSelectionGizmo(panel);
105 constraintPointGizmo = new ConstraintPointGizmo(panel);
106 detector = new org.simantics.g3d.vtk.swt.ConstraintDetector(panel);
109 public void setComponent(PipelineComponent component) {
110 this.startComponent = component;
112 if (this.startComponent.getNext() == null)
113 allowed.add(PositionType.NEXT);
114 if (this.startComponent.getPrevious() == null && !(this.startComponent instanceof Nozzle))
115 allowed.add(PositionType.PREVIOUS);
116 if (allowBranches && this.startComponent instanceof InlineComponent && !this.startComponent.getControlPoint().isFixedLength())
117 allowed.add(PositionType.SPLIT);
118 setEnabled(allowed.size() > 0);
121 public void deattach() {
123 startComponent = null;
130 public void attach() {
131 if (startComponent == null)
135 ThreadUtils.asyncExec(panel.getThreadQueue(), new Runnable() {
140 } catch (Exception e) {
142 ExceptionUtils.logAndShowError(e);
150 // private void attachUI() {
151 // //panel.setCursor(activeCursor);
152 // translateAxisGizmo.attach(panel.GetRenderer());
155 private void deattachUI() {
156 //panel.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
158 if (translateAxisGizmo.isAttached())
159 translateAxisGizmo.deattach();
160 if (splitPointSelectionGizmo.isAttached())
161 splitPointSelectionGizmo.deattach();
162 if (terminalSelectionGizmo.isAttached())
163 terminalSelectionGizmo.deattach();
164 if (constraintPointGizmo.isAttached())
165 constraintPointGizmo.deattach();
166 if (infoActor != null) {
167 panel.getRenderer().RemoveActor(infoActor);
174 protected List<PipelineComponent> added = new ArrayList<PipelineComponent>();
177 public boolean keyPressed(KeyEvent e) {
178 if (e.getKeyCode() == KeyEvent.VK_ESCAPE)
179 panel.useDefaultAction();
180 if (lock != LockType.CUSTOM || !lockForced) {
181 if ((e.getModifiersEx() & KeyEvent.SHIFT_DOWN_MASK) > 0) {
182 if (e.getKeyCode() == KeyEvent.VK_X) {
183 if (lock != LockType.XY && lock != LockType.XZ) {
184 setLockType(LockType.XY, false);
185 } else if (lock == LockType.XY) {
186 setLockType(LockType.XZ, false);
188 setLockType(LockType.NONE, false);
191 if (e.getKeyCode() == KeyEvent.VK_Y) {
192 if (lock != LockType.XY && lock != LockType.YZ) {
193 setLockType(LockType.XY, false);
194 } else if (lock == LockType.XY) {
195 setLockType(LockType.YZ, false);
197 setLockType(LockType.NONE, false);
200 if (e.getKeyCode() == KeyEvent.VK_Z) {
201 if (lock != LockType.XZ && lock != LockType.YZ) {
202 setLockType(LockType.XZ, false);
203 } else if (lock == LockType.XZ) {
204 setLockType(LockType.YZ, false);
206 setLockType(LockType.NONE, false);
210 if (e.getKeyCode() == KeyEvent.VK_X) {
211 if (lock != LockType.X)
212 setLockType(LockType.X,false);
214 setLockType(LockType.NONE,false);
216 if (e.getKeyCode() == KeyEvent.VK_Y) {
217 if (lock != LockType.Y)
218 setLockType(LockType.Y,false);
220 setLockType(LockType.NONE, false);
222 if (e.getKeyCode() == KeyEvent.VK_Z) {
223 if (lock != LockType.Z)
224 setLockType(LockType.Z, false);
226 setLockType(LockType.NONE, false);
228 if (e.getKeyCode() == KeyEvent.VK_L && direction != null) {
229 if (lock != LockType.CUSTOM)
230 setLockType(LockType.CUSTOM, false);
232 setLockType(LockType.NONE, false);
236 if (e.getKeyCode() == KeyEvent.VK_C) {
237 useDefault = !useDefault;
239 setInfoText("Rotating camera");
240 System.out.println("UseDefault " + useDefault);
251 private void update() {
254 private void update(double x, double y) {
257 return; // TODO : throw Exception?
260 case SELECTING_POSITION:
262 case SELECTING_SPLIT:
271 boolean startRemovable = false;
273 protected void activate() throws Exception {
274 state = ToolState.INITIALIZING;
277 if (allowed.size() == 1) {
278 pipeRun = startComponent.getPipeRun();
279 PipeControlPoint start = startComponent.getControlPoint();
280 boolean requiresBranching = false;
281 if (start.getNext() == null)
283 else if (start.getPrevious() == null) {
286 requiresBranching = true;
289 if (requiresBranching) {
290 activateSplit(start);
292 activateNextPrev(start);
294 } else if (allowed.size() == 0) {
295 panel.useDefaultAction();
296 state = ToolState.NOT_ACTIVE;
299 terminalSelectionGizmo.setComponent(startComponent, allowed);
300 terminalSelectionGizmo.attach(panel);
301 state = ToolState.SELECTING_POSITION;
309 protected void activateNextPrev(PipeControlPoint start) throws Exception{
310 if (!reversed && start.isDualInline())
311 start = start.getSubPoint().get(0);
312 else if (reversed && start.isDualSub())
313 start = start.parent;
315 pipeRun = start.getPipeRun();
316 setPreviousPosition(start.getWorldPosition());
318 boolean startWithTurn = false;
319 if (startComponent instanceof Nozzle) {
320 direction = startComponent.getControlPoint().getDirectedControlPointDirection();
321 lock = LockType.CUSTOM;
323 } else if (startComponent instanceof PipelineComponent){
324 if (startComponent instanceof InlineComponent) {
325 direction = startComponent.getControlPoint().getPathLegDirection(reversed ? Direction.PREVIOUS : Direction.NEXT);
326 lock = LockType.CUSTOM;
328 if (((InlineComponent) startComponent).isVariableLength()) {
329 startWithTurn = true;
331 lock = LockType.NONE;
334 Vector3d v = new Vector3d();
336 start.getControlPointEnds(v, previousPosition);
338 start.getControlPointEnds(previousPosition,v);
340 } else if (startComponent instanceof TurnComponent) {
341 if (start.asFixedAngle()) {
342 direction = startComponent.getControlPoint().getPathLegDirection(reversed ? Direction.PREVIOUS : Direction.NEXT);
343 lock = LockType.CUSTOM;
344 lockForced = start.isFixedAngle();
347 lock = LockType.NONE;
350 } else if (startComponent instanceof EndComponent) {
351 throw new Exception("Not supported");
355 throw new Exception("Not supported");
357 currentPosition = new Vector3d(previousPosition);
358 state = ToolState.ROUTING;
359 if (direction != null) {
360 direction.normalize();
363 startRemovable = start.isDeletable();
364 start.setDeletable(false);
369 if (direction != null)
370 currentPosition.add(direction);
371 InlineComponent straight = ComponentUtils.createStraight(root);
372 PipeControlPoint straightCP = straight.getControlPoint();
373 straight.setName(pipeRun.getUniqueName("Pipe"));
374 pipeRun.addChild(straight);
378 start.setNext(straightCP);
379 straightCP.setPrevious(start);
381 start.setPrevious(straightCP);
382 straightCP.setNext(start);
385 translateAxisGizmo.attach(panel);
386 setPreviousPosition(previousPosition);
387 updateCurrentPoint();
390 protected void setPreviousPosition(Vector3d v) {
391 previousPosition = new Vector3d(v);
392 if (translateAxisGizmo.isAttached())
393 translateAxisGizmo.setPosition(previousPosition);
396 private void activateBranch(PipeControlPoint start) throws Exception{
397 pipeRun = start.getPipeRun();
398 setPreviousPosition(start.getWorldPosition());
401 lock = LockType.NONE;
403 currentPosition = new Vector3d(previousPosition);
404 state = ToolState.ROUTING;
405 if (direction != null) {
406 direction.normalize();
409 startRemovable = start.isDeletable();
410 start.setDeletable(false);
413 if (direction != null)
414 currentPosition.add(direction);
415 InlineComponent straight = ComponentUtils.createStraight(root);
416 PipeControlPoint straightCP = straight.getControlPoint();
417 straight.setName(pipeRun.getUniqueName("Pipe"));
418 pipeRun.addChild(straight);
422 start.setNext(straightCP);
423 straightCP.setPrevious(start);
426 start.setPrevious(straightCP);
427 straightCP.setNext(start);
431 translateAxisGizmo.attach(panel);
432 setPreviousPosition(previousPosition);
433 updateCurrentPoint();
436 private void activateSplit(PipeControlPoint start) throws Exception{
437 Point3d p1 = new Point3d();
438 Point3d p2 = new Point3d();
439 start.getInlineControlPointEnds(p1, p2);
440 splitPointSelectionGizmo.setSplit(p1, p2);
441 splitPointSelectionGizmo.attach(panel);
442 state = ToolState.SELECTING_SPLIT;
444 public void deactivate() {
445 if (added.size() > 0) {
446 for (PipelineComponent component : added) {
447 component.getControlPoint().setDeletable(true);
450 for (PipelineComponent comp : added) {
451 PipingRules.requestUpdate(comp.getControlPoint());
454 PipingRules.update();
455 nodeMap.commit("Route pipe");
456 } catch (Exception e) {
457 ExceptionUtils.logAndShowError(e);
462 startComponent.getControlPoint().setDeletable(startRemovable);
466 setLockType(LockType.NONE, true);
467 startComponent = null;
473 currentPosition = null;
474 previousPosition = null;
475 startRemovable = false;
476 detector.clearConstraintHighlights();
477 state = ToolState.NOT_ACTIVE;
482 private void setLockType(LockType type, boolean force) {
483 if (force || (lock != LockType.CUSTOM || !lockForced) ) {
489 translateAxisGizmo.setType(6);
492 translateAxisGizmo.setType(0);
495 translateAxisGizmo.setType(1);
498 translateAxisGizmo.setType(2);
501 translateAxisGizmo.setType(3);
504 translateAxisGizmo.setType(4);
507 translateAxisGizmo.setType(5);
515 public boolean mousePressed(MouseEvent e) {
517 getDefaultAction().mousePressed(e);
523 public boolean mouseReleased(MouseEvent e) {
525 getDefaultAction().mouseReleased(e);
531 public boolean mouseWheelMoved(MouseWheelEvent e) {
533 getDefaultAction().mouseWheelMoved(e);
539 public boolean mouseClicked(MouseEvent e) {
541 getDefaultAction().mouseClicked(e);
544 if (state == ToolState.ROUTING) {
546 if (e.getClickCount() == 1) {
547 if (e.getButton() == MouseEvent.BUTTON1) {
548 if (this.added.size() > 0) {
550 setLockType(LockType.NONE,true);
558 throw new RuntimeException("RoutePipeAction initlialization has been failed, no added components found");
559 // // user was selecting position of branch
560 // lastPoint.set(startPoint);
561 // controlPoints.add(new Point3d(startPoint));
562 // if (selectionLine != null)
563 // selectionLine.removeFromParent();
564 // selectionLine = null;
566 } else if (e.getButton() ==MouseEvent.BUTTON2){
568 } else if (e.getButton() == MouseEvent.BUTTON3){
572 } catch(Exception err) {
573 err.printStackTrace();
575 } else if (state == ToolState.SELECTING_POSITION) {
576 if (e.getClickCount() == 1 && e.getButton() == MouseEvent.BUTTON1) {
577 int type = panel.getPickType();
578 //panel.setPickType(0);
579 panel.setPickType(5);
580 vtkProp[] picked = panel.pick(e.getX(), e.getY());
581 panel.setPickType(type);
582 PositionType position = terminalSelectionGizmo.getPickedPosition(picked);
583 if (position != null) {
584 terminalSelectionGizmo.deattach();
586 if (position == PositionType.SPLIT) {
587 activateSplit(startComponent.getControlPoint());
588 } else if (position == PositionType.NEXT || position == PositionType.PREVIOUS) {
589 reversed = position == PositionType.PREVIOUS;
590 activateNextPrev(startComponent.getControlPoint());
592 panel.useDefaultAction();
594 } catch (Exception err) {
595 ExceptionUtils.logAndShowError(err);
596 panel.useDefaultAction();
600 } else if (state == ToolState.SELECTING_SPLIT) {
601 if (e.getClickCount() == 1 && e.getButton() == MouseEvent.BUTTON1) {
602 Tuple3d t = splitPointSelectionGizmo.getSplitPoint();
603 splitPointSelectionGizmo.deattach();
605 panel.useDefaultAction();
609 Vector3d pos = new Vector3d(t);
610 InlineComponent branchSplit = ComponentUtils.createBranchSplit((InlineComponent)startComponent, pos);
611 PipeControlPoint branchSplitCP = branchSplit.getControlPoint();
613 PipeRun newRun = new PipeRun();
614 String n = root.getUniqueName("PipeRun");
616 root.addChild(newRun);
617 PipeControlPoint pcp = new PipeControlPoint(branchSplit,newRun);
618 branchSplitCP.children.add(pcp);
619 pcp.parent = branchSplitCP;
620 pcp.setWorldOrientation(branchSplitCP.getWorldOrientation());
621 pcp.setWorldPosition(branchSplitCP.getWorldPosition());
622 startComponent = branchSplit;
624 } catch (Exception err) {
625 ExceptionUtils.logAndShowError(err);
626 panel.useDefaultAction();
633 private void updateConstraints() {
634 detector.clearConstraints();
635 constraintPointGizmo.clearPositions();
636 if (hoverObject == null) {
637 if (constraintPointGizmo.isAttached())
638 constraintPointGizmo.deattach();
641 if (hoverObject instanceof Nozzle) {
642 Nozzle n = (Nozzle)hoverObject;
643 detector.addContraintPoint(new Point3d(n.getWorldPosition()));
644 } else if (hoverObject instanceof InlineComponent) {
645 InlineComponent c = (InlineComponent)hoverObject;
646 Point3d p1 = new Point3d();
647 Point3d p2 = new Point3d();
649 detector.addContraintPoint(p1);
650 detector.addContraintPoint(p2);
651 detector.addContraintPoint(new Point3d(c.getWorldPosition()));
652 } else if (hoverObject instanceof TurnComponent) {
653 TurnComponent n = (TurnComponent)hoverObject;
654 detector.addContraintPoint(new Point3d(n.getWorldPosition()));
656 if (detector.getConstraintPoints().size() > 0) {
657 for (Point3d p : detector.getConstraintPoints()) {
658 constraintPointGizmo.addPosition(new Vector3d(p));
660 if (constraintPointGizmo.isAttached())
661 constraintPointGizmo.deattach();
662 constraintPointGizmo.attach(panel);
667 public boolean mouseMoved(MouseEvent e) {
669 getDefaultAction().mouseMoved(e);
672 step = ((e.getModifiers() & MouseEvent.CTRL_MASK) > 0);
673 update(e.getX(), e.getY());
678 public boolean mouseDragged(MouseEvent e) {
680 getDefaultAction().mouseDragged(e);
687 private List<INode> isOverNode(int x, int y) {
688 List<INode> nodes = new ArrayList<INode>();
689 vtkProp picked[] = panel.pick2(x, y);
691 for (int i = 0; i < picked.length; i++) {
692 nodes.add(nodeMap.getNode(picked[i]));
698 INode hoverObject = null;
700 protected void updateRouting(double x, double y) {
702 //panel.getDefaultAction().update();
710 Ray ray = vtkUtil.createMouseRay(panel.getRenderer(),x, y);
711 Vector3d o = new Vector3d(ray.pos);
712 Vector3d d = ray.dir;
715 if (!updateCurrentPoint(o, d))
717 //Point3d startPoint = new Point3d();
718 double mu[] = new double[2];
724 List<INode> hover = isOverNode((int)x,(int)y);
725 if (hover.size() > 0) {
726 hoverObject = hover.get(0);
730 // System.out.println(hoverObject + " " + getLast());
731 if (hoverObject != null) {
732 if (hoverObject.equals(getLast()) ) {
734 for (int i = 1; i < hover.size(); i++) {
735 hoverObject = hover.get(i);
736 if (!getLast().equals(hoverObject)) {
745 // System.out.println(hoverObject);
746 if (hoverObject != null) {
748 if (lock == LockType.NONE) {
749 if (hoverObject instanceof Nozzle && endingToNozzle(hoverObject,o,d)) {
750 endTo = (Nozzle)hoverObject;
751 } else if (hoverObject instanceof InlineComponent && ((InlineComponent)hoverObject).isVariableLength()) {
752 endTo = (InlineComponent)hoverObject;
753 endType = endingToStraight(endTo,mu,o,d);
756 } else if (hoverObject instanceof PipelineComponent && (endPort = endingToComponent(hoverObject,o,d)) != null) {
757 endTo = (PipelineComponent)hoverObject;
762 if (hoverObject instanceof InlineComponent && ((InlineComponent)hoverObject).isVariableLength() && (endType = endingLockToStraight(hoverObject,mu)) != null) {
763 endTo = (InlineComponent)hoverObject;
764 } else if (hoverObject instanceof Nozzle && endingLockToNozzle(hoverObject)) {
765 endTo = (Nozzle)hoverObject;
766 } else if ((hoverObject instanceof PipelineComponent) && ((endPort = endingLockToComponent(hoverObject)) != null)) {
767 endTo = (PipelineComponent)hoverObject;
772 if (added.contains(endTo))
782 protected boolean updateCurrentPoint(Vector3d o, Vector3d d) {
784 Vector3d point = new Vector3d(this.previousPosition);
788 MathTools.intersectStraightStraight(point, new Vector3d(1.0,0.0,0.0), o,d, currentPosition, new Vector3d());
790 currentPosition.x = Math.round(istep * currentPosition.x) / istep;
791 BigDecimal bx = new BigDecimal(currentPosition.x);
792 bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);
793 currentPosition.x = bx.doubleValue();
797 MathTools.intersectStraightStraight(point, new Vector3d(0.0,1.0,0.0), o,d, currentPosition, new Vector3d());
799 currentPosition.y = Math.round(istep * currentPosition.y) / istep;
800 BigDecimal bx = new BigDecimal(currentPosition.y);
801 bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);
802 currentPosition.y = bx.doubleValue();
806 MathTools.intersectStraightStraight(point, new Vector3d(0.0,0.0,1.0), o,d, currentPosition, new Vector3d());
808 currentPosition.z = Math.round(istep * currentPosition.z) / istep;
809 BigDecimal bx = new BigDecimal(currentPosition.z);
810 bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);
811 currentPosition.z = bx.doubleValue();
814 MathTools.intersectStraightPlane(o, d, point, new Vector3d(0.0,0.0,1.0), currentPosition);
817 MathTools.intersectStraightPlane(o, d, point, new Vector3d(0.0,1.0,0.0), currentPosition);
820 MathTools.intersectStraightPlane(o, d, point, new Vector3d(1.0,0.0,0.0), currentPosition);
823 Vector3d normal = new Vector3d(panel.getRenderer().GetActiveCamera().GetDirectionOfProjection());
826 MathTools.intersectStraightPlane(o, d, point, normal, currentPosition);
829 MathTools.intersectStraightStraight(point, new Vector3d(direction), o,d, currentPosition, new Vector3d());
830 double dist = MathTools.distanceFromPlane(new Vector3d(currentPosition), direction, previousPosition);
832 currentPosition.set(previousPosition);
840 private Vector3d getLockDir() {
845 return new Vector3d(1,0,0);
847 return new Vector3d(0,1,0);
849 return new Vector3d(0,0,1);
854 protected void updateRoute(Vector3d o, Vector3d d) {
855 detector.clearConstraintHighlights();
856 Point3d previousPipePoint = new Point3d(previousPosition);
858 if (lock == LockType.NONE) {
859 Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint));
861 currentPosition = new Vector3d(p);
862 s += detector.getSnapString();
865 Vector3d dir = new Vector3d(currentPosition);
866 dir.sub(previousPipePoint);
867 Point3d p = detector.getPointSnap(new Vector3d(previousPipePoint), dir);
869 currentPosition = new Vector3d(p);
870 s += detector.getSnapString();
873 // System.out.println(previousPosition + " -> " + currentPosition);
874 // double dist = MathTools.distance(previousPosition, currentPosition);
875 // if (dist < pipeRun.getTurnRadius()) {
877 // Vector3d v = new Vector3d(currentPosition);
878 // v.sub(previousPosition);
879 // double vl = v.length();
880 // if (vl > MathTools.NEAR_ZERO) {
886 // v.scale(pipeRun.getTurnRadius());
887 // v.add(previousPosition);
888 // currentPosition.set(v);
891 updateCurrentPoint();
892 s += currentPosition.toString();
896 vtkTextActor infoActor;
898 private void setInfoText(String text) {
899 //System.out.println(text);
900 if (infoActor == null) {
901 infoActor = new vtkTextActor();
902 infoActor.GetTextProperty().SetColor(0.0, 0.0, 0.0);
903 infoActor.GetTextProperty().ShadowOff();
904 infoActor.GetTextProperty().ItalicOff();
905 infoActor.GetTextProperty().BoldOff();
906 infoActor.GetTextProperty().SetFontSize(18);
907 infoActor.GetTextProperty().Delete();
908 infoActor.GetProperty().SetColor(0.0, 0.0, 0.0);
909 infoActor.GetProperty().Delete();
912 infoActor.SetPosition(10,10);
913 panel.getRenderer().AddActor(infoActor);
915 infoActor.SetInput(text);
918 private boolean endingToNozzle(INode nozzleNode,Vector3d o, Vector3d d) {
919 Nozzle nozzle = (Nozzle)nozzleNode;
920 PipeControlPoint pcp =nozzle.getControlPoint();
921 if (pcp != null && (pcp.getNext() != null ||
922 pcp.getPrevious() != null))
923 return false; // nozzle is already connected to pipe
924 currentPosition = pcp.getWorldPosition();
925 Point3d previousPipePoint = new Point3d(previousPosition);
926 Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint));
928 if (MathTools.distance(p, currentPosition) > NOZZLE_SNAP_DISTANCE) {
933 updateCurrentPoint();
935 setInfoText("Connect to nozzle " + currentPosition);
940 private PositionType endingToStraight(INode straightNode, double mu[], Vector3d o, Vector3d d) {
941 if (!allowBranches) {
942 updateCurrentPoint();
945 InlineComponent s = (InlineComponent)straightNode;
947 Point3d sStart = new Point3d();
948 Point3d sEnd = new Point3d();
949 s.getEnds(sStart, sEnd);
950 //detector.clearConstraintHighlights();
952 Point3d previousPipePoint = new Point3d(previousPosition);
953 Point3d currentPipePoint = new Point3d(currentPosition);
955 if (lock == LockType.NONE) {
956 Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint));
958 currentPosition = new Vector3d(p);
959 // snapping is detected, check if snapped point can create branch with straight
960 PositionType t = endingLockToStraight(s, mu);
963 // if not, we'll have to remove highlight that was added when snapped point was detected
964 detector.clearConstraintHighlights();
967 Vector3d sDir = new Vector3d(sEnd);
969 MathTools.intersectStraightStraight(sStart, sDir, o, d, currentPosition, new Point3d(), mu);
973 throw new RuntimeException("Lock shouldn't be on");
977 updateCurrentPoint();
979 // branch point must lie between straight's ends. If connection point is exactly
980 // on straight end user may want to connect pipes to each other
981 // TODO : take account sizes of inline components)
983 boolean connectPrev = false;
984 boolean connectNext = false;
985 boolean branch = false;
989 else if (mu[0] > 0.9) {
995 PipeControlPoint pcp = s.getControlPoint();
996 if (pcp.getPrevious() != null)
998 } else if (connectNext) {
999 PipeControlPoint pcp = s.getControlPoint();
1000 if (pcp.getNext() != null)
1001 connectNext = false;
1003 Vector3d dir = s.getControlPoint().getPathLegDirection(Direction.NEXT);
1004 Vector3d currDir = getLast().getControlPoint().getPathLegDirection(Direction.NEXT);
1006 currDir.normalize();
1007 double dot = dir.dot(currDir);
1008 System.out.println(dot + " " + currDir + " " + dir);
1009 if (dot > 0.95 || dot < -0.95) {
1010 // pipes are almost in the same direction, creating a branch is not feasible.
1018 if (connectNext || connectPrev)
1019 info += "Connect pipes :";
1021 info += "Create a Branch :";
1023 setInfoText(info + currentPosition + " " + Math.max(0.0, Math.min(mu[0], 1.0)));
1025 currentPosition.set(sEnd);
1026 updateCurrentPoint();
1027 return PositionType.NEXT;
1028 } else if (connectPrev){
1029 currentPosition.set(sStart);
1030 updateCurrentPoint();
1031 return PositionType.PREVIOUS;
1032 } else if (branch) {
1033 return PositionType.SPLIT;
1035 currentPosition.set(currentPipePoint);
1036 updateCurrentPoint();
1042 private PipeControlPoint endingToComponent(INode componentNode, Vector3d o, Vector3d d) {
1043 PipelineComponent component = (PipelineComponent)componentNode;
1044 PipeControlPoint pcp = component.getControlPoint();
1045 if (component instanceof EndComponent) {
1046 if (pcp.getNext() != null || pcp.getPrevious() != null)
1049 } else if (component instanceof TurnComponent) {
1050 if (pcp.getNext() == null || pcp.getPrevious() == null)
1053 } else if (component instanceof InlineComponent) {
1054 // TODO : scan all empty pcps of the component and select closest one.
1055 if (pcp.getNext() == null || pcp.getPrevious() == null)
1063 private PositionType endingLockToStraight(INode straightNode, double mu[]) {
1064 if (!allowBranches) {
1065 updateCurrentPoint();
1068 InlineComponent s = (InlineComponent)straightNode;
1069 Point3d sStart = new Point3d();
1070 Point3d sEnd = new Point3d();
1071 s.getControlPoint().getInlineControlPointEnds(sStart, sEnd);
1072 Vector3d sDir = new Vector3d(sEnd);
1074 Vector3d dir = new Vector3d(currentPosition);
1075 Point3d prev = new Point3d(previousPosition);
1077 // intersection point in pipe where branch would be inserted to
1078 Vector3d branchPoint = new Vector3d();
1079 // intersection point in straight pipe that is currently routed
1080 Vector3d routePoint = new Vector3d();
1081 MathTools.intersectStraightStraight(sStart, sDir, new Vector3d(prev), dir, branchPoint, routePoint, mu);
1082 routePoint.sub(branchPoint);
1083 // startPoint of branch must be between pipe ends
1084 // TODO : take account sizes of elbows (or other components)
1085 // branch point must be between pipe ends and intersection points must be quite close to each other
1086 if (mu[0] > 0.0 && mu[0] < 1.0 && routePoint.lengthSquared() < BRANCH_SNAP_DISTANCE) {
1087 currentPosition.set(branchPoint);
1089 updateCurrentPoint();
1091 setInfoText("Create a branch (l) :" + currentPosition + " " + Math.max(0.0, Math.min(mu[0], 1.0)) + " " + routePoint.lengthSquared());
1092 return PositionType.SPLIT;
1097 private boolean endingLockToNozzle(INode nozzleNode) {
1098 Nozzle nozzle = (Nozzle)nozzleNode;
1099 Vector3d dir = new Vector3d(currentPosition);
1100 Point3d prev = new Point3d(previousPosition);
1102 Vector3d nozzleLoc = nozzle.getWorldPosition();
1103 double u[] = new double[1];
1104 Vector3d closest = MathTools.closestPointOnStraight(new Point3d(nozzleLoc), new Point3d(prev), new Vector3d(dir), u);
1105 double dist = MathTools.distanceSquared(nozzleLoc,closest);
1106 if (dist < BRANCH_SNAP_DISTANCE) {
1107 // FIXME : directions should be checked (insert an elbow)
1108 currentPosition.set(nozzleLoc);
1109 updateCurrentPoint();
1110 setInfoText("Connect to nozzle (l) :" + currentPosition);
1113 //System.out.println(u[0]);
1117 private PipeControlPoint endingLockToComponent(INode componentNode) {
1118 // we'll must scan all free pcp's and their direction to accept the connection.
1122 protected void addPoint() throws Exception {
1123 InlineComponent previous = (InlineComponent)getLast();
1124 PipeControlPoint previousCP = previous.getControlPoint();
1125 TurnComponent turn = ComponentUtils.createTurn(root);
1126 InlineComponent straight = ComponentUtils.createStraight(root);
1127 PipeControlPoint turnCP = turn.getControlPoint();
1128 PipeControlPoint straightCP = straight.getControlPoint();
1129 straight.setName(pipeRun.getUniqueName("Pipe"));
1130 turn.setName(pipeRun.getUniqueName("Elbow"));
1131 pipeRun.addChild(turn);
1132 pipeRun.addChild(straight);
1134 added.add(straight);
1136 turnCP.setDeletable(false); // mark turnCP nonDeletable so that PipingRules won't delete it immediately.
1139 previousCP.setNext(turnCP);
1140 turnCP.setPrevious(previousCP);
1141 turnCP.setNext(straightCP);
1142 straightCP.setPrevious(turnCP);
1144 previousCP.setPrevious(turnCP);
1145 turnCP.setNext(previousCP);
1146 turnCP.setPrevious(straightCP);
1147 straightCP.setNext(turnCP);
1150 turnCP.setWorldPosition(currentPosition);
1151 turnCP.setTurnAngle(0.0);
1152 turnCP.setLength(0.0);
1153 straightCP.setWorldPosition(currentPosition);
1154 straightCP.setLength(0.0);
1156 setPreviousPosition(currentPosition);
1157 updateCurrentPoint();
1164 * Updates tool graphics for current point
1166 protected void updateCurrentPoint() {
1167 InlineComponent straight = (InlineComponent)added.get(added.size()-1);
1168 // TODO: the inline length is from previous update step.
1171 l = straight.getPrevious().getControlPoint().getInlineLength();
1173 l = straight.getNext().getControlPoint().getInlineLength();
1174 Vector3d v = new Vector3d();
1175 v.sub(currentPosition, previousPosition);
1176 double length = v.length();
1177 if (length > MathTools.NEAR_ZERO) {
1178 v.scale(1.0/length);
1179 v.scale(0.5*(length+l));
1180 v.add(previousPosition);
1181 straight.getControlPoint().setWorldPosition(v);
1182 straight.getControlPoint().setLength(length);
1185 PipingRules.positionUpdate(straight.getControlPoint(),false);
1186 } catch (Exception e) {
1187 // TODO Auto-generated catch block
1188 e.printStackTrace();
1192 private PipelineComponent getLast() {
1193 if (added.size() == 0)
1194 return startComponent;
1195 return added.get(added.size()-1);
1200 * Removes last point from pipeline
1202 public void removePoint() {
1203 if (added.size() < 3)
1205 InlineComponent straight = (InlineComponent)added.remove(added.size()-1);
1206 TurnComponent turn = (TurnComponent)added.remove(added.size()-1);
1207 straight.getControlPoint().remove();
1208 turn.getControlPoint().remove();
1209 if (added.size() > 1) {
1210 setPreviousPosition(added.get(added.size()-2).getWorldPosition());
1212 setPreviousPosition(startComponent.getWorldPosition());
1213 if (direction != null)
1214 setLockType(LockType.CUSTOM, true);
1219 protected void endPiping() throws Exception {
1220 state = ToolState.NOT_ACTIVE;
1222 if (endTo != null) {
1223 ComponentUtils.connect(getLast(), endTo, endType, currentPosition);
1225 panel.useDefaultAction();