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;
54 private double BRANCH_SNAP_DISTANCE = 0.05;
55 private double NOZZLE_SNAP_DISTANCE = 0.05;
57 private double istep = 10.0;
58 private int decimals = 2;
60 private P3DRootNode root;
61 protected PipelineComponent startComponent;
62 protected PipeRun pipeRun;
63 private boolean allowBranches;
65 protected TranslateAxisGizmo translateAxisGizmo = new TranslateAxisGizmo();
66 private SplitPointSelectionGizmo splitPointSelectionGizmo;
67 private ConstraintPointGizmo constraintPointGizmo;
68 private TerminalSelectionGizmo terminalSelectionGizmo;
69 private NodeMap<Resource,vtkProp,INode> nodeMap;
71 protected enum ToolState{NOT_ACTIVE, INITIALIZING, SELECTING_POSITION, SELECTING_SPLIT, ROUTING};
72 protected ToolState state = ToolState.NOT_ACTIVE;
74 private ConstraintDetector detector;// = new DummyConstraintDetector();
76 protected boolean useDefault = false;
77 protected Vector3d direction = null;
78 protected Vector3d previousPosition = null;
79 protected Vector3d currentPosition = null;
83 PipelineComponent endTo = null;
84 PositionType endType = null;
85 PipeControlPoint endPort = null;
87 boolean reversed = false;
89 private Set<PositionType> allowed = new HashSet<PositionType>();
91 public RoutePipeAction(InteractiveVtkComposite panel, P3DRootNode root) {
92 this(panel,root, true);
95 public RoutePipeAction(InteractiveVtkComposite panel, P3DRootNode root, boolean allowBranches) {
98 this.allowBranches = allowBranches;
99 setText("Route Pipe");
100 setImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/Straight.png"));
101 nodeMap = root.getNodeMap();
102 splitPointSelectionGizmo = new SplitPointSelectionGizmo(panel);
103 terminalSelectionGizmo = new TerminalSelectionGizmo(panel);
104 constraintPointGizmo = new ConstraintPointGizmo(panel);
105 detector = new org.simantics.g3d.vtk.swt.ConstraintDetector(panel);
108 public void setComponent(PipelineComponent component) {
109 this.startComponent = component;
111 if (this.startComponent.getNext() == null)
112 allowed.add(PositionType.NEXT);
113 if (this.startComponent.getPrevious() == null && !(this.startComponent instanceof Nozzle))
114 allowed.add(PositionType.PREVIOUS);
115 if (allowBranches && this.startComponent instanceof InlineComponent && !this.startComponent.getControlPoint().isFixed())
116 allowed.add(PositionType.SPLIT);
117 setEnabled(allowed.size() > 0);
120 public void deattach() {
122 startComponent = null;
129 public void attach() {
130 if (startComponent == null)
134 ThreadUtils.asyncExec(panel.getThreadQueue(), new Runnable() {
139 } catch (Exception e) {
141 ExceptionUtils.logAndShowError(e);
149 // private void attachUI() {
150 // //panel.setCursor(activeCursor);
151 // translateAxisGizmo.attach(panel.GetRenderer());
154 private void deattachUI() {
155 //panel.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
157 if (translateAxisGizmo.isAttached())
158 translateAxisGizmo.deattach();
159 if (splitPointSelectionGizmo.isAttached())
160 splitPointSelectionGizmo.deattach();
161 if (terminalSelectionGizmo.isAttached())
162 terminalSelectionGizmo.deattach();
163 if (constraintPointGizmo.isAttached())
164 constraintPointGizmo.deattach();
165 if (infoActor != null) {
166 panel.getRenderer().RemoveActor(infoActor);
173 protected List<PipelineComponent> added = new ArrayList<PipelineComponent>();
176 public boolean keyPressed(KeyEvent e) {
177 if (e.getKeyCode() == KeyEvent.VK_ESCAPE)
178 panel.useDefaultAction();
179 if (lock != LockType.CUSTOM) {
180 if ((e.getModifiersEx() & KeyEvent.SHIFT_DOWN_MASK) > 0) {
181 if (e.getKeyCode() == KeyEvent.VK_X) {
182 if (lock != LockType.XY && lock != LockType.XZ) {
183 setLockType(LockType.XY, false);
184 } else if (lock == LockType.XY) {
185 setLockType(LockType.XZ, false);
187 setLockType(LockType.NONE, false);
190 if (e.getKeyCode() == KeyEvent.VK_Y) {
191 if (lock != LockType.XY && lock != LockType.YZ) {
192 setLockType(LockType.XY, false);
193 } else if (lock == LockType.XY) {
194 setLockType(LockType.YZ, false);
196 setLockType(LockType.NONE, false);
199 if (e.getKeyCode() == KeyEvent.VK_Z) {
200 if (lock != LockType.XZ && lock != LockType.YZ) {
201 setLockType(LockType.XZ, false);
202 } else if (lock == LockType.XZ) {
203 setLockType(LockType.YZ, false);
205 setLockType(LockType.NONE, false);
209 if (e.getKeyCode() == KeyEvent.VK_X) {
210 if (lock != LockType.X)
211 setLockType(LockType.X,false);
213 setLockType(LockType.NONE,false);
215 if (e.getKeyCode() == KeyEvent.VK_Y) {
216 if (lock != LockType.Y)
217 setLockType(LockType.Y,false);
219 setLockType(LockType.NONE, false);
221 if (e.getKeyCode() == KeyEvent.VK_Z) {
222 if (lock != LockType.Z)
223 setLockType(LockType.Z, false);
225 setLockType(LockType.NONE, false);
229 if (e.getKeyCode() == KeyEvent.VK_C) {
230 useDefault = !useDefault;
231 System.out.println("UseDefault " + useDefault);
242 private void update() {
245 private void update(double x, double y) {
248 return; // TODO : throw Exception?
251 case SELECTING_POSITION:
253 case SELECTING_SPLIT:
262 boolean startRemovable = false;
264 protected void activate() throws Exception {
265 state = ToolState.INITIALIZING;
268 if (allowed.size() == 1) {
269 pipeRun = startComponent.getPipeRun();
270 PipeControlPoint start = startComponent.getControlPoint();
271 boolean requiresBranching = false;
272 if (start.getNext() == null)
274 else if (start.getPrevious() == null) {
277 requiresBranching = true;
280 if (requiresBranching) {
281 activateSplit(start);
283 activateNextPrev(start);
285 } else if (allowed.size() == 0) {
286 panel.useDefaultAction();
287 state = ToolState.NOT_ACTIVE;
290 terminalSelectionGizmo.setComponent(startComponent, allowed);
291 terminalSelectionGizmo.attach(panel);
292 state = ToolState.SELECTING_POSITION;
300 protected void activateNextPrev(PipeControlPoint start) throws Exception{
301 if (!reversed && start.isDualInline())
302 start = start.getSubPoint().get(0);
303 else if (reversed && start.isDualSub())
304 start = start.parent;
306 pipeRun = start.getPipeRun();
307 setPreviousPosition(start.getWorldPosition());
309 boolean startWithTurn = false;
310 if (startComponent instanceof Nozzle) {
311 direction = startComponent.getControlPoint().getDirectedControlPointDirection();
312 lock = LockType.CUSTOM;
313 } else if (startComponent instanceof PipelineComponent){
314 if (startComponent instanceof InlineComponent) {
315 direction = startComponent.getControlPoint().getPathLegDirection(reversed ? Direction.PREVIOUS : Direction.NEXT);
316 lock = LockType.CUSTOM;
317 if (((InlineComponent) startComponent).isVariableLength()) {
318 startWithTurn = true;
320 lock = LockType.NONE;
322 Vector3d v = new Vector3d();
324 start.getControlPointEnds(v, previousPosition);
326 start.getControlPointEnds(previousPosition,v);
328 } else if (startComponent instanceof TurnComponent) {
329 if (start.isFixed()) {
330 direction = startComponent.getControlPoint().getPathLegDirection(reversed ? Direction.PREVIOUS : Direction.NEXT);
331 lock = LockType.CUSTOM;
334 lock = LockType.NONE;
336 } else if (startComponent instanceof EndComponent) {
337 throw new Exception("Not supported");
341 throw new Exception("Not supported");
343 currentPosition = new Vector3d(previousPosition);
344 state = ToolState.ROUTING;
345 if (direction != null) {
346 direction.normalize();
349 startRemovable = start.isDeletable();
350 start.setDeletable(false);
355 if (direction != null)
356 currentPosition.add(direction);
357 InlineComponent straight = ComponentUtils.createStraight(root);
358 PipeControlPoint straightCP = straight.getControlPoint();
359 straight.setName(pipeRun.getUniqueName("Pipe"));
360 pipeRun.addChild(straight);
364 start.setNext(straightCP);
365 straightCP.setPrevious(start);
367 start.setPrevious(straightCP);
368 straightCP.setNext(start);
371 translateAxisGizmo.attach(panel);
372 setPreviousPosition(previousPosition);
373 updateCurrentPoint();
376 protected void setPreviousPosition(Vector3d v) {
377 previousPosition = new Vector3d(v);
378 if (translateAxisGizmo.isAttached())
379 translateAxisGizmo.setPosition(previousPosition);
382 private void activateBranch(PipeControlPoint start) throws Exception{
383 pipeRun = start.getPipeRun();
384 setPreviousPosition(start.getWorldPosition());
387 lock = LockType.NONE;
389 currentPosition = new Vector3d(previousPosition);
390 state = ToolState.ROUTING;
391 if (direction != null) {
392 direction.normalize();
395 startRemovable = start.isDeletable();
396 start.setDeletable(false);
399 if (direction != null)
400 currentPosition.add(direction);
401 InlineComponent straight = ComponentUtils.createStraight(root);
402 PipeControlPoint straightCP = straight.getControlPoint();
403 straight.setName(pipeRun.getUniqueName("Pipe"));
404 pipeRun.addChild(straight);
408 start.setNext(straightCP);
409 straightCP.setPrevious(start);
412 start.setPrevious(straightCP);
413 straightCP.setNext(start);
417 translateAxisGizmo.attach(panel);
418 setPreviousPosition(previousPosition);
419 updateCurrentPoint();
422 private void activateSplit(PipeControlPoint start) throws Exception{
423 Point3d p1 = new Point3d();
424 Point3d p2 = new Point3d();
425 start.getInlineControlPointEnds(p1, p2);
426 splitPointSelectionGizmo.setSplit(p1, p2);
427 splitPointSelectionGizmo.attach(panel);
428 state = ToolState.SELECTING_SPLIT;
430 public void deactivate() {
431 if (added.size() > 0) {
432 for (PipelineComponent component : added) {
433 component.getControlPoint().setDeletable(true);
436 for (PipelineComponent comp : added) {
437 PipingRules.requestUpdate(comp.getControlPoint());
440 PipingRules.update();
441 nodeMap.commit("Route pipe");
442 } catch (Exception e) {
443 ExceptionUtils.logAndShowError(e);
448 startComponent.getControlPoint().setDeletable(startRemovable);
452 setLockType(LockType.NONE, true);
453 startComponent = null;
459 currentPosition = null;
460 previousPosition = null;
461 startRemovable = false;
462 detector.clearConstraintHighlights();
463 state = ToolState.NOT_ACTIVE;
468 private void setLockType(LockType type, boolean force) {
469 if (force || lock != LockType.CUSTOM) {
475 translateAxisGizmo.setType(6);
478 translateAxisGizmo.setType(0);
481 translateAxisGizmo.setType(1);
484 translateAxisGizmo.setType(2);
487 translateAxisGizmo.setType(3);
490 translateAxisGizmo.setType(4);
493 translateAxisGizmo.setType(5);
501 public boolean mousePressed(MouseEvent e) {
503 getDefaultAction().mousePressed(e);
509 public boolean mouseReleased(MouseEvent e) {
511 getDefaultAction().mouseReleased(e);
517 public boolean mouseWheelMoved(MouseWheelEvent e) {
519 getDefaultAction().mouseWheelMoved(e);
525 public boolean mouseClicked(MouseEvent e) {
527 getDefaultAction().mouseClicked(e);
530 if (state == ToolState.ROUTING) {
532 if (e.getClickCount() == 1) {
533 if (e.getButton() == MouseEvent.BUTTON1) {
534 if (this.added.size() > 0) {
536 setLockType(LockType.NONE,true);
544 throw new RuntimeException("RoutePipeAction initlialization has been failed, no added components found");
545 // // user was selecting position of branch
546 // lastPoint.set(startPoint);
547 // controlPoints.add(new Point3d(startPoint));
548 // if (selectionLine != null)
549 // selectionLine.removeFromParent();
550 // selectionLine = null;
552 } else if (e.getButton() ==MouseEvent.BUTTON2){
554 } else if (e.getButton() == MouseEvent.BUTTON3){
558 } catch(Exception err) {
559 err.printStackTrace();
561 } else if (state == ToolState.SELECTING_POSITION) {
562 if (e.getClickCount() == 1 && e.getButton() == MouseEvent.BUTTON1) {
563 int type = panel.getPickType();
564 //panel.setPickType(0);
565 panel.setPickType(5);
566 vtkProp[] picked = panel.pick(e.getX(), e.getY());
567 panel.setPickType(type);
568 PositionType position = terminalSelectionGizmo.getPickedPosition(picked);
569 if (position != null) {
570 terminalSelectionGizmo.deattach();
572 if (position == PositionType.SPLIT) {
573 activateSplit(startComponent.getControlPoint());
574 } else if (position == PositionType.NEXT || position == PositionType.PREVIOUS) {
575 reversed = position == PositionType.PREVIOUS;
576 activateNextPrev(startComponent.getControlPoint());
578 panel.useDefaultAction();
580 } catch (Exception err) {
581 ExceptionUtils.logAndShowError(err);
582 panel.useDefaultAction();
586 } else if (state == ToolState.SELECTING_SPLIT) {
587 if (e.getClickCount() == 1 && e.getButton() == MouseEvent.BUTTON1) {
588 Tuple3d t = splitPointSelectionGizmo.getSplitPoint();
589 splitPointSelectionGizmo.deattach();
591 panel.useDefaultAction();
595 Vector3d pos = new Vector3d(t);
596 InlineComponent branchSplit = ComponentUtils.createBranchSplit((InlineComponent)startComponent, pos);
597 PipeControlPoint branchSplitCP = branchSplit.getControlPoint();
599 PipeRun newRun = new PipeRun();
600 String n = root.getUniqueName("PipeRun");
602 root.addChild(newRun);
603 PipeControlPoint pcp = new PipeControlPoint(branchSplit,newRun);
604 branchSplitCP.children.add(pcp);
605 pcp.parent = branchSplitCP;
606 pcp.setWorldOrientation(branchSplitCP.getWorldOrientation());
607 pcp.setWorldPosition(branchSplitCP.getWorldPosition());
608 startComponent = branchSplit;
610 } catch (Exception err) {
611 ExceptionUtils.logAndShowError(err);
612 panel.useDefaultAction();
619 private void updateConstraints() {
620 detector.clearConstraints();
621 constraintPointGizmo.clearPositions();
622 if (hoverObject == null) {
623 if (constraintPointGizmo.isAttached())
624 constraintPointGizmo.deattach();
627 if (hoverObject instanceof Nozzle) {
628 Nozzle n = (Nozzle)hoverObject;
629 detector.addContraintPoint(new Point3d(n.getWorldPosition()));
630 } else if (hoverObject instanceof InlineComponent) {
631 InlineComponent c = (InlineComponent)hoverObject;
632 Point3d p1 = new Point3d();
633 Point3d p2 = new Point3d();
635 detector.addContraintPoint(p1);
636 detector.addContraintPoint(p2);
637 detector.addContraintPoint(new Point3d(c.getWorldPosition()));
638 } else if (hoverObject instanceof TurnComponent) {
639 TurnComponent n = (TurnComponent)hoverObject;
640 detector.addContraintPoint(new Point3d(n.getWorldPosition()));
642 if (detector.getConstraintPoints().size() > 0) {
643 for (Point3d p : detector.getConstraintPoints()) {
644 constraintPointGizmo.addPosition(new Vector3d(p));
646 if (constraintPointGizmo.isAttached())
647 constraintPointGizmo.deattach();
648 constraintPointGizmo.attach(panel);
653 public boolean mouseMoved(MouseEvent e) {
655 getDefaultAction().mouseMoved(e);
658 step = ((e.getModifiers() & MouseEvent.CTRL_MASK) > 0);
659 update(e.getX(), e.getY());
664 public boolean mouseDragged(MouseEvent e) {
666 getDefaultAction().mouseDragged(e);
673 private List<INode> isOverNode(int x, int y) {
674 List<INode> nodes = new ArrayList<INode>();
675 vtkProp picked[] = panel.pick2(x, y);
677 for (int i = 0; i < picked.length; i++) {
678 nodes.add(nodeMap.getNode(picked[i]));
684 INode hoverObject = null;
686 protected void updateRouting(double x, double y) {
688 //panel.getDefaultAction().update();
696 Ray ray = vtkUtil.createMouseRay(panel.getRenderer(),x, y);
697 Vector3d o = new Vector3d(ray.pos);
698 Vector3d d = ray.dir;
701 if (!updateCurrentPoint(o, d))
703 //Point3d startPoint = new Point3d();
704 double mu[] = new double[2];
710 List<INode> hover = isOverNode((int)x,(int)y);
711 if (hover.size() > 0) {
712 hoverObject = hover.get(0);
716 // System.out.println(hoverObject + " " + getLast());
717 if (hoverObject != null) {
718 if (hoverObject.equals(getLast()) ) {
720 for (int i = 1; i < hover.size(); i++) {
721 hoverObject = hover.get(i);
722 if (!getLast().equals(hoverObject)) {
731 // System.out.println(hoverObject);
732 if (hoverObject != null) {
734 if (lock == LockType.NONE) {
735 if (hoverObject instanceof Nozzle && endingToNozzle(hoverObject,o,d)) {
736 endTo = (Nozzle)hoverObject;
737 } else if (hoverObject instanceof InlineComponent && ((InlineComponent)hoverObject).isVariableLength()) {
738 endTo = (InlineComponent)hoverObject;
739 endType = endingToStraight(endTo,mu,o,d);
742 } else if (hoverObject instanceof PipelineComponent && (endPort = endingToComponent(hoverObject,o,d)) != null) {
743 endTo = (PipelineComponent)hoverObject;
748 if (hoverObject instanceof InlineComponent && ((InlineComponent)hoverObject).isVariableLength() && (endType = endingLockToStraight(hoverObject,mu)) != null) {
749 endTo = (InlineComponent)hoverObject;
750 } else if (hoverObject instanceof Nozzle && endingLockToNozzle(hoverObject)) {
751 endTo = (Nozzle)hoverObject;
752 } else if ((hoverObject instanceof PipelineComponent) && ((endPort = endingLockToComponent(hoverObject)) != null)) {
753 endTo = (PipelineComponent)hoverObject;
758 if (added.contains(endTo))
768 protected boolean updateCurrentPoint(Vector3d o, Vector3d d) {
770 Vector3d point = new Vector3d(this.previousPosition);
774 MathTools.intersectStraightStraight(point, new Vector3d(1.0,0.0,0.0), o,d, currentPosition, new Vector3d());
776 currentPosition.x = Math.round(istep * currentPosition.x) / istep;
777 BigDecimal bx = new BigDecimal(currentPosition.x);
778 bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);
779 currentPosition.x = bx.doubleValue();
783 MathTools.intersectStraightStraight(point, new Vector3d(0.0,1.0,0.0), o,d, currentPosition, new Vector3d());
785 currentPosition.y = Math.round(istep * currentPosition.y) / istep;
786 BigDecimal bx = new BigDecimal(currentPosition.y);
787 bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);
788 currentPosition.y = bx.doubleValue();
792 MathTools.intersectStraightStraight(point, new Vector3d(0.0,0.0,1.0), o,d, currentPosition, new Vector3d());
794 currentPosition.z = Math.round(istep * currentPosition.z) / istep;
795 BigDecimal bx = new BigDecimal(currentPosition.z);
796 bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);
797 currentPosition.z = bx.doubleValue();
800 MathTools.intersectStraightPlane(o, d, point, new Vector3d(0.0,0.0,1.0), currentPosition);
803 MathTools.intersectStraightPlane(o, d, point, new Vector3d(0.0,1.0,0.0), currentPosition);
806 MathTools.intersectStraightPlane(o, d, point, new Vector3d(1.0,0.0,0.0), currentPosition);
809 Vector3d normal = new Vector3d(panel.getRenderer().GetActiveCamera().GetDirectionOfProjection());
812 MathTools.intersectStraightPlane(o, d, point, normal, currentPosition);
815 MathTools.intersectStraightStraight(point, new Vector3d(direction), o,d, currentPosition, new Vector3d());
816 double dist = MathTools.distanceFromPlane(new Vector3d(currentPosition), direction, previousPosition);
818 currentPosition.set(previousPosition);
826 private Vector3d getLockDir() {
831 return new Vector3d(1,0,0);
833 return new Vector3d(0,1,0);
835 return new Vector3d(0,0,1);
840 protected void updateRoute(Vector3d o, Vector3d d) {
841 detector.clearConstraintHighlights();
842 Point3d previousPipePoint = new Point3d(previousPosition);
844 if (lock == LockType.NONE) {
845 Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint));
847 currentPosition = new Vector3d(p);
848 s += detector.getSnapString();
851 Vector3d dir = new Vector3d(currentPosition);
852 dir.sub(previousPipePoint);
853 Point3d p = detector.getPointSnap(new Vector3d(previousPipePoint), dir);
855 currentPosition = new Vector3d(p);
856 s += detector.getSnapString();
859 // System.out.println(previousPosition + " -> " + currentPosition);
860 // double dist = MathTools.distance(previousPosition, currentPosition);
861 // if (dist < pipeRun.getTurnRadius()) {
863 // Vector3d v = new Vector3d(currentPosition);
864 // v.sub(previousPosition);
865 // double vl = v.length();
866 // if (vl > MathTools.NEAR_ZERO) {
872 // v.scale(pipeRun.getTurnRadius());
873 // v.add(previousPosition);
874 // currentPosition.set(v);
877 updateCurrentPoint();
878 s += currentPosition.toString();
882 vtkTextActor infoActor;
884 private void setInfoText(String text) {
885 //System.out.println(text);
886 if (infoActor == null) {
887 infoActor = new vtkTextActor();
888 infoActor.GetTextProperty().SetColor(0.0, 0.0, 0.0);
889 infoActor.GetTextProperty().ShadowOff();
890 infoActor.GetTextProperty().ItalicOff();
891 infoActor.GetTextProperty().BoldOff();
892 infoActor.GetTextProperty().SetFontSize(18);
893 infoActor.GetTextProperty().Delete();
894 infoActor.GetProperty().SetColor(0.0, 0.0, 0.0);
895 infoActor.GetProperty().Delete();
898 infoActor.SetPosition(10,10);
899 panel.getRenderer().AddActor(infoActor);
901 infoActor.SetInput(text);
904 private boolean endingToNozzle(INode nozzleNode,Vector3d o, Vector3d d) {
905 Nozzle nozzle = (Nozzle)nozzleNode;
906 PipeControlPoint pcp =nozzle.getControlPoint();
907 if (pcp != null && (pcp.getNext() != null ||
908 pcp.getPrevious() != null))
909 return false; // nozzle is already connected to pipe
910 currentPosition = pcp.getWorldPosition();
911 Point3d previousPipePoint = new Point3d(previousPosition);
912 Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint));
914 if (MathTools.distance(p, currentPosition) > NOZZLE_SNAP_DISTANCE) {
919 updateCurrentPoint();
921 setInfoText("Connect to nozzle " + currentPosition);
926 private PositionType endingToStraight(INode straightNode, double mu[], Vector3d o, Vector3d d) {
927 if (!allowBranches) {
928 updateCurrentPoint();
931 InlineComponent s = (InlineComponent)straightNode;
933 Point3d sStart = new Point3d();
934 Point3d sEnd = new Point3d();
935 s.getEnds(sStart, sEnd);
936 //detector.clearConstraintHighlights();
938 Point3d previousPipePoint = new Point3d(previousPosition);
939 Point3d currentPipePoint = new Point3d(currentPosition);
941 if (lock == LockType.NONE) {
942 Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint));
944 currentPosition = new Vector3d(p);
945 // snapping is detected, check if snapped point can create branch with straight
946 PositionType t = endingLockToStraight(s, mu);
949 // if not, we'll have to remove highlight that was added when snapped point was detected
950 detector.clearConstraintHighlights();
953 Vector3d sDir = new Vector3d(sEnd);
955 MathTools.intersectStraightStraight(sStart, sDir, o, d, currentPosition, new Point3d(), mu);
959 throw new RuntimeException("Lock shouldn't be on");
963 updateCurrentPoint();
965 // branch point must lie between straight's ends. If connection point is exactly
966 // on straight end user may want to connect pipes to each other
967 // TODO : take account sizes of inline components)
969 boolean connectPrev = false;
970 boolean connectNext = false;
971 boolean branch = false;
975 else if (mu[0] > 0.9) {
981 PipeControlPoint pcp = s.getControlPoint();
982 if (pcp.getPrevious() != null)
984 } else if (connectNext) {
985 PipeControlPoint pcp = s.getControlPoint();
986 if (pcp.getNext() != null)
989 Vector3d dir = s.getControlPoint().getPathLegDirection(Direction.NEXT);
990 Vector3d currDir = getLast().getControlPoint().getPathLegDirection(Direction.NEXT);
993 double dot = dir.dot(currDir);
994 System.out.println(dot + " " + currDir + " " + dir);
995 if (dot > 0.95 || dot < -0.95) {
996 // pipes are almost in the same direction, creating a branch is not feasible.
1004 if (connectNext || connectPrev)
1005 info += "Connect pipes :";
1007 info += "Create a Branch :";
1009 setInfoText(info + currentPosition + " " + Math.max(0.0, Math.min(mu[0], 1.0)));
1011 currentPosition.set(sEnd);
1012 updateCurrentPoint();
1013 return PositionType.NEXT;
1014 } else if (connectPrev){
1015 currentPosition.set(sStart);
1016 updateCurrentPoint();
1017 return PositionType.PREVIOUS;
1018 } else if (branch) {
1019 return PositionType.SPLIT;
1021 currentPosition.set(currentPipePoint);
1022 updateCurrentPoint();
1028 private PipeControlPoint endingToComponent(INode componentNode, Vector3d o, Vector3d d) {
1029 PipelineComponent component = (PipelineComponent)componentNode;
1030 PipeControlPoint pcp = component.getControlPoint();
1031 if (component instanceof EndComponent) {
1032 if (pcp.getNext() != null || pcp.getPrevious() != null)
1035 } else if (component instanceof TurnComponent) {
1036 if (pcp.getNext() == null || pcp.getPrevious() == null)
1039 } else if (component instanceof InlineComponent) {
1040 // TODO : scan all empty pcps of the component and select closest one.
1041 if (pcp.getNext() == null || pcp.getPrevious() == null)
1049 private PositionType endingLockToStraight(INode straightNode, double mu[]) {
1050 if (!allowBranches) {
1051 updateCurrentPoint();
1054 InlineComponent s = (InlineComponent)straightNode;
1055 Point3d sStart = new Point3d();
1056 Point3d sEnd = new Point3d();
1057 s.getControlPoint().getInlineControlPointEnds(sStart, sEnd);
1058 Vector3d sDir = new Vector3d(sEnd);
1060 Vector3d dir = new Vector3d(currentPosition);
1061 Point3d prev = new Point3d(previousPosition);
1063 // intersection point in pipe where branch would be inserted to
1064 Vector3d branchPoint = new Vector3d();
1065 // intersection point in straight pipe that is currently routed
1066 Vector3d routePoint = new Vector3d();
1067 MathTools.intersectStraightStraight(sStart, sDir, new Vector3d(prev), dir, branchPoint, routePoint, mu);
1068 routePoint.sub(branchPoint);
1069 // startPoint of branch must be between pipe ends
1070 // TODO : take account sizes of elbows (or other components)
1071 // branch point must be between pipe ends and intersection points must be quite close to each other
1072 if (mu[0] > 0.0 && mu[0] < 1.0 && routePoint.lengthSquared() < BRANCH_SNAP_DISTANCE) {
1073 currentPosition.set(branchPoint);
1075 updateCurrentPoint();
1077 setInfoText("Create a branch (l) :" + currentPosition + " " + Math.max(0.0, Math.min(mu[0], 1.0)) + " " + routePoint.lengthSquared());
1078 return PositionType.SPLIT;
1083 private boolean endingLockToNozzle(INode nozzleNode) {
1084 Nozzle nozzle = (Nozzle)nozzleNode;
1085 Vector3d dir = new Vector3d(currentPosition);
1086 Point3d prev = new Point3d(previousPosition);
1088 Vector3d nozzleLoc = nozzle.getWorldPosition();
1089 double u[] = new double[1];
1090 Vector3d closest = MathTools.closestPointOnStraight(new Point3d(nozzleLoc), new Point3d(prev), new Vector3d(dir), u);
1091 double dist = MathTools.distanceSquared(nozzleLoc,closest);
1092 if (dist < BRANCH_SNAP_DISTANCE) {
1093 // FIXME : directions should be checked (insert an elbow)
1094 currentPosition.set(nozzleLoc);
1095 updateCurrentPoint();
1096 setInfoText("Connect to nozzle (l) :" + currentPosition);
1099 //System.out.println(u[0]);
1103 private PipeControlPoint endingLockToComponent(INode componentNode) {
1104 // we'll must scan all free pcp's and their direction to accept the connection.
1108 protected void addPoint() throws Exception {
1109 InlineComponent previous = (InlineComponent)getLast();
1110 PipeControlPoint previousCP = previous.getControlPoint();
1111 TurnComponent turn = ComponentUtils.createTurn(root);
1112 InlineComponent straight = ComponentUtils.createStraight(root);
1113 PipeControlPoint turnCP = turn.getControlPoint();
1114 PipeControlPoint straightCP = straight.getControlPoint();
1115 straight.setName(pipeRun.getUniqueName("Pipe"));
1116 turn.setName(pipeRun.getUniqueName("Elbow"));
1117 pipeRun.addChild(turn);
1118 pipeRun.addChild(straight);
1120 added.add(straight);
1122 turnCP.setDeletable(false); // mark turnCP nonDeletable so that PipingRules won't delete it immediately.
1125 previousCP.setNext(turnCP);
1126 turnCP.setPrevious(previousCP);
1127 turnCP.setNext(straightCP);
1128 straightCP.setPrevious(turnCP);
1130 previousCP.setPrevious(turnCP);
1131 turnCP.setNext(previousCP);
1132 turnCP.setPrevious(straightCP);
1133 straightCP.setNext(turnCP);
1136 turnCP.setWorldPosition(currentPosition);
1137 turnCP.setTurnAngle(0.0);
1138 turnCP.setLength(0.0);
1139 straightCP.setWorldPosition(currentPosition);
1140 straightCP.setLength(0.0);
1142 setPreviousPosition(currentPosition);
1143 updateCurrentPoint();
1150 * Updates tool graphics for current point
1152 protected void updateCurrentPoint() {
1153 InlineComponent straight = (InlineComponent)added.get(added.size()-1);
1154 // TODO: the inline length is from previous update step.
1157 l = straight.getPrevious().getControlPoint().getInlineLength();
1159 l = straight.getNext().getControlPoint().getInlineLength();
1160 Vector3d v = new Vector3d();
1161 v.sub(currentPosition, previousPosition);
1162 double length = v.length();
1163 if (length > MathTools.NEAR_ZERO) {
1164 v.scale(1.0/length);
1165 v.scale(0.5*(length+l));
1166 v.add(previousPosition);
1167 straight.getControlPoint().setWorldPosition(v);
1168 straight.getControlPoint().setLength(length);
1171 PipingRules.positionUpdate(straight.getControlPoint(),false);
1172 } catch (Exception e) {
1173 // TODO Auto-generated catch block
1174 e.printStackTrace();
1178 private PipelineComponent getLast() {
1179 if (added.size() == 0)
1180 return startComponent;
1181 return added.get(added.size()-1);
1186 * Removes last point from pipeline
1188 public void removePoint() {
1189 if (added.size() < 3)
1191 InlineComponent straight = (InlineComponent)added.remove(added.size()-1);
1192 TurnComponent turn = (TurnComponent)added.remove(added.size()-1);
1193 straight.getControlPoint().remove();
1194 turn.getControlPoint().remove();
1195 if (added.size() > 1) {
1196 setPreviousPosition(added.get(added.size()-2).getWorldPosition());
1198 setPreviousPosition(startComponent.getWorldPosition());
1199 if (direction != null)
1200 setLockType(LockType.CUSTOM, true);
1205 protected void endPiping() throws Exception {
1206 state = ToolState.NOT_ACTIVE;
1208 if (endTo != null) {
1209 ComponentUtils.connect(getLast(), endTo, endType, currentPosition);
1211 panel.useDefaultAction();