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.eclipse.swt.SWT;
17 import org.eclipse.swt.events.SelectionAdapter;
18 import org.eclipse.swt.events.SelectionEvent;
19 import org.eclipse.swt.widgets.Button;
20 import org.eclipse.swt.widgets.Combo;
21 import org.eclipse.swt.widgets.Label;
22 import org.simantics.db.Resource;
23 import org.simantics.g3d.math.MathTools;
24 import org.simantics.g3d.math.Ray;
25 import org.simantics.g3d.scenegraph.NodeMap;
26 import org.simantics.g3d.scenegraph.base.INode;
27 import org.simantics.g3d.toolbar.ToolComposite;
28 import org.simantics.g3d.tools.ConstraintDetector;
29 import org.simantics.g3d.vtk.gizmo.TranslateAxisGizmo;
30 import org.simantics.g3d.vtk.swt.InteractiveVtkComposite;
31 import org.simantics.g3d.vtk.swt.vtkSwtAction;
32 import org.simantics.g3d.vtk.utils.vtkUtil;
33 import org.simantics.plant3d.Activator;
34 import org.simantics.plant3d.gizmo.ConstraintPointGizmo;
35 import org.simantics.plant3d.gizmo.SplitPointSelectionGizmo;
36 import org.simantics.plant3d.gizmo.TerminalSelectionGizmo;
37 import org.simantics.plant3d.scenegraph.EndComponent;
38 import org.simantics.plant3d.scenegraph.InlineComponent;
39 import org.simantics.plant3d.scenegraph.Nozzle;
40 import org.simantics.plant3d.scenegraph.P3DRootNode;
41 import org.simantics.plant3d.scenegraph.PipeRun;
42 import org.simantics.plant3d.scenegraph.PipelineComponent;
43 import org.simantics.plant3d.scenegraph.TurnComponent;
44 import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint;
45 import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint.Direction;
46 import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint.PositionType;
47 import org.simantics.plant3d.scenegraph.controlpoint.PipingRules;
48 import org.simantics.plant3d.utils.ComponentUtils;
49 import org.simantics.utils.threads.ThreadUtils;
50 import org.simantics.utils.ui.ExceptionUtils;
53 import vtk.vtkTextActor;
55 public class RoutePipeAction extends vtkSwtAction {
57 X, Y, Z, XY, XZ, YZ, NONE, CUSTOM
60 LockType lock = LockType.NONE;
62 private double BRANCH_SNAP_DISTANCE = 0.05;
63 private double NOZZLE_SNAP_DISTANCE = 0.05;
64 private static double BRANCH_DOT_PRODUCT = 0.95; // dot product value used for prevent branch creation
65 private static double ALIGN_DOT_PRODUCT = 0.99; // dot product for creating turn when connecting pipes
67 private double istep = 10.0;
68 private int decimals = 2;
70 private P3DRootNode root;
71 protected PipelineComponent startComponent;
72 protected PipeRun pipeRun;
73 private boolean allowBranches;
75 protected TranslateAxisGizmo translateAxisGizmo = new TranslateAxisGizmo();
76 private SplitPointSelectionGizmo splitPointSelectionGizmo;
77 private ConstraintPointGizmo constraintPointGizmo;
78 private TerminalSelectionGizmo terminalSelectionGizmo;
79 private NodeMap<Resource,vtkProp,INode> nodeMap;
81 protected enum ToolState{NOT_ACTIVE, INITIALIZING, SELECTING_POSITION, SELECTING_SPLIT, ROUTING};
82 protected ToolState state = ToolState.NOT_ACTIVE;
84 private ConstraintDetector detector;// = new DummyConstraintDetector();
86 protected boolean useDefault = false;
87 protected Vector3d direction = null;
88 protected Vector3d previousPosition = null;
89 protected Vector3d currentPosition = null;
93 PipelineComponent endTo = null;
94 PositionType endType = null;
95 PipeControlPoint endPort = null;
97 boolean reversed = false;
99 private Set<PositionType> allowed = new HashSet<PositionType>();
101 protected ToolComposite toolComposite;
102 protected Combo axisCombo;
103 protected Button cameraButton;
105 public RoutePipeAction(InteractiveVtkComposite panel, P3DRootNode root, ToolComposite toolComposite) {
106 this(panel,root, toolComposite, true);
109 public RoutePipeAction(InteractiveVtkComposite panel, P3DRootNode root, ToolComposite toolComposite, boolean allowBranches) {
112 this.allowBranches = allowBranches;
113 setText("Route Pipe");
114 setImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/Straight.png"));
115 nodeMap = root.getNodeMap();
116 splitPointSelectionGizmo = new SplitPointSelectionGizmo(panel);
117 terminalSelectionGizmo = new TerminalSelectionGizmo(panel);
118 constraintPointGizmo = new ConstraintPointGizmo(panel);
119 detector = new org.simantics.g3d.vtk.swt.ConstraintDetector(panel);
120 this.toolComposite = toolComposite;
123 public void setComponent(PipelineComponent component) {
124 this.startComponent = component;
126 if (this.startComponent.getNext() == null)
127 allowed.add(PositionType.NEXT);
128 if (this.startComponent.getPrevious() == null && !(this.startComponent instanceof Nozzle))
129 allowed.add(PositionType.PREVIOUS);
130 if (allowBranches && this.startComponent instanceof InlineComponent && !this.startComponent.getControlPoint().isFixedLength())
131 allowed.add(PositionType.SPLIT);
132 setEnabled(allowed.size() > 0);
135 protected void createTools(ToolComposite toolComposite) {
136 Label label = new Label(toolComposite, SWT.READ_ONLY);
137 label.setText("Route direction:");
138 axisCombo = new Combo(toolComposite, SWT.READ_ONLY);
145 axisCombo.add("None");
146 axisCombo.add("Custom");
147 axisCombo.addSelectionListener(new SelectionAdapter() {
149 public void widgetSelected(SelectionEvent e) {
150 Combo c = (Combo)e.getSource();
151 setLockType(LockType.values()[c.getSelectionIndex()],false);
152 panel.getComponent().setFocus();
156 axisCombo.select(lock.ordinal());
157 cameraButton = new Button(toolComposite, SWT.TOGGLE);
158 cameraButton.setText("Camera");
159 cameraButton.setSelection(useDefault);
160 cameraButton.addSelectionListener(new SelectionAdapter() {
162 public void widgetSelected(SelectionEvent e) {
163 setUseDefault(((Button)e.getSource()).getSelection());
164 panel.getComponent().setFocus();
167 Button close = new Button(toolComposite, SWT.PUSH);
168 close.setText("Close");
169 close.addSelectionListener(new SelectionAdapter() {
170 public void widgetSelected(SelectionEvent e) {
171 panel.useDefaultAction();
174 toolComposite.relayout();
177 public void deattach() {
179 if (toolComposite != null) {
180 toolComposite.clear();
185 startComponent = null;
192 public void attach() {
193 if (startComponent == null)
195 if (toolComposite != null) {
196 createTools(toolComposite);
199 ThreadUtils.asyncExec(panel.getThreadQueue(), new Runnable() {
204 } catch (Exception e) {
206 ExceptionUtils.logAndShowError(e);
214 // private void attachUI() {
215 // //panel.setCursor(activeCursor);
216 // translateAxisGizmo.attach(panel.GetRenderer());
219 private void deattachUI() {
220 //panel.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
222 if (translateAxisGizmo.isAttached())
223 translateAxisGizmo.deattach();
224 if (splitPointSelectionGizmo.isAttached())
225 splitPointSelectionGizmo.deattach();
226 if (terminalSelectionGizmo.isAttached())
227 terminalSelectionGizmo.deattach();
228 if (constraintPointGizmo.isAttached())
229 constraintPointGizmo.deattach();
230 if (infoActor != null) {
231 panel.getRenderer().RemoveActor(infoActor);
238 protected List<PipelineComponent> added = new ArrayList<PipelineComponent>();
241 public boolean keyPressed(KeyEvent e) {
242 if (e.getKeyCode() == KeyEvent.VK_ESCAPE)
243 panel.useDefaultAction();
244 if (lock != LockType.CUSTOM || !lockForced) {
245 if ((e.getModifiersEx() & KeyEvent.SHIFT_DOWN_MASK) > 0) {
246 if (e.getKeyCode() == KeyEvent.VK_X) {
247 if (lock != LockType.XY && lock != LockType.XZ) {
248 setLockType(LockType.XY, false);
249 } else if (lock == LockType.XY) {
250 setLockType(LockType.XZ, false);
252 setLockType(LockType.NONE, false);
255 if (e.getKeyCode() == KeyEvent.VK_Y) {
256 if (lock != LockType.XY && lock != LockType.YZ) {
257 setLockType(LockType.XY, false);
258 } else if (lock == LockType.XY) {
259 setLockType(LockType.YZ, false);
261 setLockType(LockType.NONE, false);
264 if (e.getKeyCode() == KeyEvent.VK_Z) {
265 if (lock != LockType.XZ && lock != LockType.YZ) {
266 setLockType(LockType.XZ, false);
267 } else if (lock == LockType.XZ) {
268 setLockType(LockType.YZ, false);
270 setLockType(LockType.NONE, false);
274 if (e.getKeyCode() == KeyEvent.VK_X) {
275 if (lock != LockType.X)
276 setLockType(LockType.X,false);
278 setLockType(LockType.NONE,false);
280 if (e.getKeyCode() == KeyEvent.VK_Y) {
281 if (lock != LockType.Y)
282 setLockType(LockType.Y,false);
284 setLockType(LockType.NONE, false);
286 if (e.getKeyCode() == KeyEvent.VK_Z) {
287 if (lock != LockType.Z)
288 setLockType(LockType.Z, false);
290 setLockType(LockType.NONE, false);
292 if (e.getKeyCode() == KeyEvent.VK_L && direction != null) {
293 if (lock != LockType.CUSTOM)
294 setLockType(LockType.CUSTOM, false);
296 setLockType(LockType.NONE, false);
300 if (e.getKeyCode() == KeyEvent.VK_C) {
301 setUseDefault(!useDefault);
308 private void setUseDefault(boolean b) {
311 setInfoText("Rotating camera");
312 if (cameraButton != null)
313 cameraButton.setSelection(useDefault);
317 private void update() {
320 private void update(double x, double y) {
323 return; // TODO : throw Exception?
326 case SELECTING_POSITION:
328 case SELECTING_SPLIT:
337 boolean startRemovable = false;
339 protected void activate() throws Exception {
340 state = ToolState.INITIALIZING;
343 if (allowed.size() == 1) {
344 pipeRun = startComponent.getPipeRun();
345 PipeControlPoint start = startComponent.getControlPoint();
346 boolean requiresBranching = false;
347 if (start.getNext() == null)
349 else if (start.getPrevious() == null) {
352 requiresBranching = true;
355 if (requiresBranching) {
356 activateSplit(start);
358 activateNextPrev(start);
360 } else if (allowed.size() == 0) {
361 panel.useDefaultAction();
362 state = ToolState.NOT_ACTIVE;
365 terminalSelectionGizmo.setComponent(startComponent, allowed);
366 terminalSelectionGizmo.attach(panel);
367 state = ToolState.SELECTING_POSITION;
375 protected void activateNextPrev(PipeControlPoint start) throws Exception{
376 if (!reversed && start.isDualInline())
377 start = start.getDualSub();
378 else if (reversed && start.isDualSub())
379 start = start.parent;
381 pipeRun = start.getPipeRun();
382 setPreviousPosition(start.getWorldPosition());
384 boolean startWithTurn = false;
385 if (startComponent instanceof Nozzle) {
386 direction = startComponent.getControlPoint().getDirectedControlPointDirection();
387 lock = LockType.CUSTOM;
389 } else if (startComponent instanceof PipelineComponent){
390 if (startComponent instanceof InlineComponent) {
391 direction = startComponent.getControlPoint().getPathLegDirection(reversed ? Direction.PREVIOUS : Direction.NEXT);
392 lock = LockType.CUSTOM;
394 if (((InlineComponent) startComponent).isVariableLength()) {
395 startWithTurn = true;
397 lock = LockType.NONE;
400 Vector3d v = new Vector3d();
402 start.getControlPointEnds(v, previousPosition);
404 start.getControlPointEnds(previousPosition,v);
406 } else if (startComponent instanceof TurnComponent) {
407 if (start.asFixedAngle()) {
408 direction = startComponent.getControlPoint().getPathLegDirection(reversed ? Direction.PREVIOUS : Direction.NEXT);
409 lock = LockType.CUSTOM;
410 lockForced = start.isFixedAngle();
413 lock = LockType.NONE;
416 } else if (startComponent instanceof EndComponent) {
417 throw new Exception("Not supported");
421 throw new Exception("Not supported");
423 currentPosition = new Vector3d(previousPosition);
424 state = ToolState.ROUTING;
425 if (direction != null) {
426 direction.normalize();
429 startRemovable = start.isDeletable();
430 start.setDeletable(false);
435 if (direction != null)
436 currentPosition.add(direction);
437 InlineComponent straight = ComponentUtils.createStraight(root);
438 PipeControlPoint straightCP = straight.getControlPoint();
439 straight.setName(pipeRun.getUniqueName("Pipe"));
440 pipeRun.addChild(straight);
444 start.setNext(straightCP);
445 straightCP.setPrevious(start);
447 start.setPrevious(straightCP);
448 straightCP.setNext(start);
451 translateAxisGizmo.attach(panel);
452 setPreviousPosition(previousPosition);
453 updateCurrentPoint();
457 protected void setPreviousPosition(Vector3d v) {
458 previousPosition = new Vector3d(v);
459 if (translateAxisGizmo.isAttached())
460 translateAxisGizmo.setPosition(previousPosition);
463 private void activateBranch(PipeControlPoint start) throws Exception{
464 pipeRun = start.getPipeRun();
465 setPreviousPosition(start.getWorldPosition());
468 lock = LockType.NONE;
470 currentPosition = new Vector3d(previousPosition);
471 state = ToolState.ROUTING;
472 if (direction != null) {
473 direction.normalize();
476 startRemovable = start.isDeletable();
477 start.setDeletable(false);
480 if (direction != null)
481 currentPosition.add(direction);
482 InlineComponent straight = ComponentUtils.createStraight(root);
483 PipeControlPoint straightCP = straight.getControlPoint();
484 straight.setName(pipeRun.getUniqueName("Pipe"));
485 pipeRun.addChild(straight);
489 start.setNext(straightCP);
490 straightCP.setPrevious(start);
493 start.setPrevious(straightCP);
494 straightCP.setNext(start);
498 translateAxisGizmo.attach(panel);
499 setPreviousPosition(previousPosition);
500 updateCurrentPoint();
504 private void activateSplit(PipeControlPoint start) throws Exception{
505 Point3d p1 = new Point3d();
506 Point3d p2 = new Point3d();
507 start.getInlineControlPointEnds(p1, p2);
508 splitPointSelectionGizmo.setSplit(p1, p2);
509 splitPointSelectionGizmo.attach(panel);
510 state = ToolState.SELECTING_SPLIT;
512 public void deactivate() {
513 if (added.size() > 0) {
514 for (PipelineComponent component : added) {
515 component.getControlPoint().setDeletable(true);
518 for (PipelineComponent comp : added) {
519 PipingRules.requestUpdate(comp.getControlPoint());
522 PipingRules.update();
523 nodeMap.commit("Route pipe");
524 } catch (Exception e) {
525 ExceptionUtils.logAndShowError(e);
530 startComponent.getControlPoint().setDeletable(startRemovable);
534 setLockType(LockType.NONE, true);
535 startComponent = null;
541 currentPosition = null;
542 previousPosition = null;
543 startRemovable = false;
544 detector.clearConstraintHighlights();
545 state = ToolState.NOT_ACTIVE;
550 private void setLockType(LockType type, boolean force) {
551 if (type == LockType.CUSTOM && (direction == null || added.size() > 0)) {
553 } else if (force || (lock != LockType.CUSTOM || !lockForced || added.size() > 0) ) {
560 translateAxisGizmo.setType(6);
563 translateAxisGizmo.setType(0);
566 translateAxisGizmo.setType(1);
569 translateAxisGizmo.setType(2);
572 translateAxisGizmo.setType(3);
575 translateAxisGizmo.setType(4);
578 translateAxisGizmo.setType(5);
587 private void updateWidget() {
588 if (axisCombo != null) {
589 axisCombo.select(lock.ordinal());
590 axisCombo.setEnabled(!lockForced || lock != LockType.CUSTOM);
595 public boolean mousePressed(MouseEvent e) {
597 getDefaultAction().mousePressed(e);
603 public boolean mouseReleased(MouseEvent e) {
605 getDefaultAction().mouseReleased(e);
611 public boolean mouseWheelMoved(MouseWheelEvent e) {
613 getDefaultAction().mouseWheelMoved(e);
619 public boolean mouseClicked(MouseEvent e) {
621 getDefaultAction().mouseClicked(e);
624 if (state == ToolState.ROUTING) {
626 if (e.getClickCount() == 1) {
627 if (e.getButton() == MouseEvent.BUTTON1) {
628 if (this.added.size() > 0) {
630 setLockType(LockType.NONE,true);
638 throw new RuntimeException("RoutePipeAction initialization has failed, no added components found");
639 // // user was selecting position of branch
640 // lastPoint.set(startPoint);
641 // controlPoints.add(new Point3d(startPoint));
642 // if (selectionLine != null)
643 // selectionLine.removeFromParent();
644 // selectionLine = null;
646 } else if (e.getButton() ==MouseEvent.BUTTON2){
648 } else if (e.getButton() == MouseEvent.BUTTON3){
652 } catch(Exception err) {
653 err.printStackTrace();
655 } else if (state == ToolState.SELECTING_POSITION) {
656 if (e.getClickCount() == 1 && e.getButton() == MouseEvent.BUTTON1) {
657 int type = panel.getPickType();
658 //panel.setPickType(0);
659 panel.setPickType(5);
660 vtkProp[] picked = panel.pick(e.getX(), e.getY());
661 panel.setPickType(type);
662 PositionType position = terminalSelectionGizmo.getPickedPosition(picked);
663 if (position != null) {
664 terminalSelectionGizmo.deattach();
666 if (position == PositionType.SPLIT) {
667 activateSplit(startComponent.getControlPoint());
668 } else if (position == PositionType.NEXT || position == PositionType.PREVIOUS) {
669 reversed = position == PositionType.PREVIOUS;
670 activateNextPrev(startComponent.getControlPoint());
672 panel.useDefaultAction();
674 } catch (Exception err) {
675 ExceptionUtils.logAndShowError(err);
676 panel.useDefaultAction();
680 } else if (state == ToolState.SELECTING_SPLIT) {
681 if (e.getClickCount() == 1 && e.getButton() == MouseEvent.BUTTON1) {
682 Tuple3d t = splitPointSelectionGizmo.getSplitPoint();
683 splitPointSelectionGizmo.deattach();
685 panel.useDefaultAction();
689 Vector3d pos = new Vector3d(t);
690 InlineComponent branchSplit = ComponentUtils.createBranchSplit((InlineComponent)startComponent, pos);
691 PipeControlPoint branchSplitCP = branchSplit.getControlPoint();
693 PipeRun newRun = new PipeRun();
694 String n = root.getUniqueName("PipeRun");
696 root.addChild(newRun);
697 PipeControlPoint pcp = new PipeControlPoint(branchSplit,newRun);
698 branchSplitCP.children.add(pcp);
699 pcp.parent = branchSplitCP;
700 pcp.setWorldOrientation(branchSplitCP.getWorldOrientation());
701 pcp.setWorldPosition(branchSplitCP.getWorldPosition());
702 startComponent = branchSplit;
704 } catch (Exception err) {
705 ExceptionUtils.logAndShowError(err);
706 panel.useDefaultAction();
713 private void updateConstraints() {
714 detector.clearConstraints();
715 constraintPointGizmo.clearPositions();
716 if (hoverObject == null) {
717 if (constraintPointGizmo.isAttached())
718 constraintPointGizmo.deattach();
721 if (hoverObject instanceof Nozzle) {
722 Nozzle n = (Nozzle)hoverObject;
723 detector.addContraintPoint(new Point3d(n.getWorldPosition()));
724 } else if (hoverObject instanceof InlineComponent) {
725 InlineComponent c = (InlineComponent)hoverObject;
726 Point3d p1 = new Point3d();
727 Point3d p2 = new Point3d();
729 detector.addContraintPoint(p1);
730 detector.addContraintPoint(p2);
731 detector.addContraintPoint(new Point3d(c.getWorldPosition()));
732 } else if (hoverObject instanceof TurnComponent) {
733 TurnComponent n = (TurnComponent)hoverObject;
734 detector.addContraintPoint(new Point3d(n.getWorldPosition()));
736 if (detector.getConstraintPoints().size() > 0) {
737 for (Point3d p : detector.getConstraintPoints()) {
738 constraintPointGizmo.addPosition(new Vector3d(p));
740 if (constraintPointGizmo.isAttached())
741 constraintPointGizmo.deattach();
742 constraintPointGizmo.attach(panel);
747 public boolean mouseMoved(MouseEvent e) {
749 getDefaultAction().mouseMoved(e);
752 step = ((e.getModifiers() & MouseEvent.CTRL_MASK) > 0);
753 update(e.getX(), e.getY());
758 public boolean mouseDragged(MouseEvent e) {
760 getDefaultAction().mouseDragged(e);
767 private List<INode> isOverNode(int x, int y) {
768 List<INode> nodes = new ArrayList<INode>();
769 vtkProp picked[] = panel.pick2(x, y);
771 for (int i = 0; i < picked.length; i++) {
772 nodes.add(nodeMap.getNode(picked[i]));
778 INode hoverObject = null;
780 protected void updateRouting(double x, double y) {
782 //panel.getDefaultAction().update();
790 Ray ray = vtkUtil.createMouseRay(panel.getRenderer(),x, y);
791 Vector3d o = new Vector3d(ray.pos);
792 Vector3d d = ray.dir;
795 if (!updateCurrentPoint(o, d))
797 //Point3d startPoint = new Point3d();
798 double mu[] = new double[2];
804 List<INode> hover = isOverNode((int)x,(int)y);
805 if (hover.size() > 0) {
806 hoverObject = hover.get(0);
810 // System.out.println(hoverObject + " " + getLast());
811 if (hoverObject != null) {
812 if (hoverObject.equals(getLast()) ) {
814 for (int i = 1; i < hover.size(); i++) {
815 hoverObject = hover.get(i);
816 if (!getLast().equals(hoverObject)) {
825 // System.out.println(hoverObject);
826 if (hoverObject != null) {
828 if (lock == LockType.NONE) {
829 if (hoverObject instanceof Nozzle && endingToNozzle(hoverObject,o,d)) {
830 endTo = (Nozzle)hoverObject;
831 } else if (hoverObject instanceof InlineComponent && ((InlineComponent)hoverObject).isVariableLength()) {
832 endTo = (InlineComponent)hoverObject;
833 endType = endingToStraight(endTo,mu,o,d);
836 } else if (hoverObject instanceof PipelineComponent && (endPort = endingToComponent(hoverObject,o,d)) != null) {
837 endTo = (PipelineComponent)hoverObject;
842 if (hoverObject instanceof InlineComponent && ((InlineComponent)hoverObject).isVariableLength() && (endType = endingLockToStraight(hoverObject,mu, new Point3d(currentPosition))) != null) {
843 endTo = (InlineComponent)hoverObject;
844 } else if (hoverObject instanceof Nozzle && endingLockToNozzle(hoverObject)) {
845 endTo = (Nozzle)hoverObject;
846 } else if ((hoverObject instanceof PipelineComponent) && ((endPort = endingLockToComponent(hoverObject)) != null)) {
847 endTo = (PipelineComponent)hoverObject;
852 if (added.contains(endTo))
862 protected boolean updateCurrentPoint(Vector3d o, Vector3d d) {
864 Vector3d point = new Vector3d(this.previousPosition);
868 MathTools.intersectStraightStraight(point, new Vector3d(1.0,0.0,0.0), o,d, currentPosition, new Vector3d());
870 currentPosition.x = Math.round(istep * currentPosition.x) / istep;
871 BigDecimal bx = new BigDecimal(currentPosition.x);
872 bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);
873 currentPosition.x = bx.doubleValue();
877 MathTools.intersectStraightStraight(point, new Vector3d(0.0,1.0,0.0), o,d, currentPosition, new Vector3d());
879 currentPosition.y = Math.round(istep * currentPosition.y) / istep;
880 BigDecimal bx = new BigDecimal(currentPosition.y);
881 bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);
882 currentPosition.y = bx.doubleValue();
886 MathTools.intersectStraightStraight(point, new Vector3d(0.0,0.0,1.0), o,d, currentPosition, new Vector3d());
888 currentPosition.z = Math.round(istep * currentPosition.z) / istep;
889 BigDecimal bx = new BigDecimal(currentPosition.z);
890 bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);
891 currentPosition.z = bx.doubleValue();
894 MathTools.intersectStraightPlane(o, d, point, new Vector3d(0.0,0.0,1.0), currentPosition);
897 MathTools.intersectStraightPlane(o, d, point, new Vector3d(0.0,1.0,0.0), currentPosition);
900 MathTools.intersectStraightPlane(o, d, point, new Vector3d(1.0,0.0,0.0), currentPosition);
903 Vector3d normal = new Vector3d(panel.getRenderer().GetActiveCamera().GetDirectionOfProjection());
906 MathTools.intersectStraightPlane(o, d, point, normal, currentPosition);
909 MathTools.intersectStraightStraight(point, new Vector3d(direction), o,d, currentPosition, new Vector3d());
910 double dist = MathTools.distanceFromPlane(new Vector3d(currentPosition), direction, previousPosition);
912 currentPosition.set(previousPosition);
920 @SuppressWarnings("unused")
921 private Vector3d getLockDir() {
926 return new Vector3d(1,0,0);
928 return new Vector3d(0,1,0);
930 return new Vector3d(0,0,1);
936 protected void updateRoute(Vector3d o, Vector3d d) {
937 detector.clearConstraintHighlights();
938 Point3d previousPipePoint = new Point3d(previousPosition);
940 if (lock == LockType.NONE) {
941 Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint));
943 currentPosition = new Vector3d(p);
944 s += detector.getSnapString();
947 Vector3d dir = new Vector3d(currentPosition);
948 dir.sub(previousPipePoint);
949 Point3d p = detector.getPointSnap(new Vector3d(previousPipePoint), dir);
951 currentPosition = new Vector3d(p);
952 s += detector.getSnapString();
955 // System.out.println(previousPosition + " -> " + currentPosition);
956 // double dist = MathTools.distance(previousPosition, currentPosition);
957 // if (dist < pipeRun.getTurnRadius()) {
959 // Vector3d v = new Vector3d(currentPosition);
960 // v.sub(previousPosition);
961 // double vl = v.length();
962 // if (vl > MathTools.NEAR_ZERO) {
968 // v.scale(pipeRun.getTurnRadius());
969 // v.add(previousPosition);
970 // currentPosition.set(v);
973 updateCurrentPoint();
974 s += currentPosition.toString();
978 vtkTextActor infoActor;
980 private void setInfoText(String text) {
981 //System.out.println(text);
982 if (infoActor == null) {
983 infoActor = new vtkTextActor();
984 infoActor.GetTextProperty().SetColor(0.0, 0.0, 0.0);
985 infoActor.GetTextProperty().ShadowOff();
986 infoActor.GetTextProperty().ItalicOff();
987 infoActor.GetTextProperty().BoldOff();
988 infoActor.GetTextProperty().SetFontSize(18);
989 infoActor.GetTextProperty().Delete();
990 infoActor.GetProperty().SetColor(0.0, 0.0, 0.0);
991 infoActor.GetProperty().Delete();
994 infoActor.SetPosition(10,10);
995 panel.getRenderer().AddActor(infoActor);
997 infoActor.SetInput(text);
1000 private boolean endingToNozzle(INode nozzleNode,Vector3d o, Vector3d d) {
1001 Nozzle nozzle = (Nozzle)nozzleNode;
1002 PipeControlPoint pcp =nozzle.getControlPoint();
1003 if (pcp != null && (pcp.getNext() != null ||
1004 pcp.getPrevious() != null))
1005 return false; // nozzle is already connected to pipe
1006 currentPosition = pcp.getWorldPosition();
1007 Point3d previousPipePoint = new Point3d(previousPosition);
1008 Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint));
1010 if (MathTools.distance(p, currentPosition) > NOZZLE_SNAP_DISTANCE) {
1015 updateCurrentPoint();
1017 setInfoText("Connect to nozzle " + currentPosition);
1022 private PositionType endingToStraight(INode straightNode, double mu[], Vector3d o, Vector3d d) {
1023 // if (!allowBranches) {
1024 // updateCurrentPoint();
1027 InlineComponent s = (InlineComponent)straightNode;
1029 Point3d sStart = new Point3d();
1030 Point3d sEnd = new Point3d();
1031 s.getEnds(sStart, sEnd);
1032 //detector.clearConstraintHighlights();
1034 Point3d previousPipePoint = new Point3d(previousPosition);
1035 Point3d currentPipePoint = new Point3d(currentPosition);
1037 if (lock == LockType.NONE) {
1038 Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint));
1040 currentPosition = new Vector3d(p);
1041 // snapping is detected, check if snapped point can create branch with straight
1042 PositionType t = endingLockToStraight(s, mu, currentPipePoint);
1045 // if not, we'll have to remove highlight that was added when snapped point was detected
1046 detector.clearConstraintHighlights();
1049 Vector3d sDir = new Vector3d(sEnd);
1051 MathTools.intersectStraightStraight(sStart, sDir, o, d, currentPosition, new Point3d(), mu);
1055 throw new RuntimeException("Lock shouldn't be on");
1059 updateCurrentPoint();
1061 // branch point must lie between straight's ends. If connection point is exactly
1062 // on straight end user may want to connect pipes to each other
1063 // TODO : take account sizes of inline components)
1064 return endingToStraight(mu, s, sStart, sEnd, currentPipePoint);
1067 private PositionType endingToStraight(double mu[], InlineComponent s, Point3d sStart, Point3d sEnd , Point3d currentPipePoint) {
1070 boolean connectPrev = false;
1071 boolean connectNext = false;
1072 boolean branch = false;
1076 else if (mu[0] > 0.9) {
1082 PipeControlPoint pcp = s.getControlPoint();
1083 if (pcp.getPrevious() != null)
1084 connectPrev = false;
1085 } else if (connectNext) {
1086 PipeControlPoint pcp = s.getControlPoint();
1087 if (pcp.getNext() != null)
1088 connectNext = false;
1090 Vector3d dir = s.getControlPoint().getPathLegDirection(Direction.NEXT);
1091 Vector3d currDir = getLast().getControlPoint().getPathLegDirection(Direction.NEXT);
1093 currDir.normalize();
1094 double dot = dir.dot(currDir);
1095 System.out.println(dot + " " + currDir + " " + dir);
1096 if (dot > BRANCH_DOT_PRODUCT || dot < -BRANCH_DOT_PRODUCT) {
1097 // pipes are almost in the same direction, creating a branch is not feasible.
1105 if (connectNext || connectPrev)
1106 info += "Connect pipes :";
1108 info += "Create a Branch :";
1110 setInfoText(info + currentPosition + " " + Math.max(0.0, Math.min(mu[0], 1.0)));
1112 currentPosition.set(sEnd);
1113 updateCurrentPoint();
1114 return PositionType.NEXT;
1115 } else if (connectPrev){
1116 currentPosition.set(sStart);
1117 updateCurrentPoint();
1118 return PositionType.PREVIOUS;
1119 } else if (branch && allowBranches) {
1120 return PositionType.SPLIT;
1122 currentPosition.set(currentPipePoint);
1123 updateCurrentPoint();
1128 private PipeControlPoint endingToComponent(INode componentNode, Vector3d o, Vector3d d) {
1129 PipelineComponent component = (PipelineComponent)componentNode;
1130 PipeControlPoint pcp = component.getControlPoint();
1131 PipeControlPoint connect = null;
1132 if (component instanceof EndComponent) {
1133 if (pcp.getNext() != null || pcp.getPrevious() != null)
1136 } else if (component instanceof TurnComponent) {
1137 if (pcp.getNext() == null || pcp.getPrevious() == null)
1141 } else if (component instanceof InlineComponent) {
1142 // TODO : scan all empty pcps of the component and select closest one.
1143 if (pcp.getNext() == null || pcp.getPrevious() == null)
1148 if (connect != null) {
1149 currentPosition.set(connect.getWorldPosition());
1150 updateCurrentPoint();
1151 setInfoText("Connect to " + component.getName());
1157 private PositionType endingLockToStraight(INode straightNode, double mu[], Point3d currentPipePoint) {
1158 // if (!allowBranches) {
1159 // updateCurrentPoint();
1162 InlineComponent s = (InlineComponent)straightNode;
1163 Point3d sStart = new Point3d();
1164 Point3d sEnd = new Point3d();
1165 s.getControlPoint().getInlineControlPointEnds(sStart, sEnd);
1166 Vector3d sDir = new Vector3d(sEnd);
1168 Vector3d dir = new Vector3d(currentPosition);
1169 Point3d prev = new Point3d(previousPosition);
1171 // intersection point in pipe where branch would be inserted to
1172 Vector3d branchPoint = new Vector3d();
1173 // intersection point in straight pipe that is currently routed
1174 Vector3d routePoint = new Vector3d();
1175 MathTools.intersectStraightStraight(sStart, sDir, new Vector3d(prev), dir, branchPoint, routePoint, mu);
1176 routePoint.sub(branchPoint);
1177 // startPoint of branch must be between pipe ends
1178 // TODO : take account sizes of elbows (or other components)
1179 // branch point must be between pipe ends and intersection points must be quite close to each other
1181 if (routePoint.lengthSquared() > BRANCH_SNAP_DISTANCE)
1184 return endingToStraight(mu, s, sStart, sEnd, currentPipePoint);
1186 // if (mu[0] > 0.0 && mu[0] < 1.0 && routePoint.lengthSquared() < BRANCH_SNAP_DISTANCE) {
1187 // currentPosition.set(branchPoint);
1189 // updateCurrentPoint();
1191 // setInfoText("Create a branch (l) :" + currentPosition + " " + Math.max(0.0, Math.min(mu[0], 1.0)) + " " + routePoint.lengthSquared());
1192 // return PositionType.SPLIT;
1197 private boolean endingLockToNozzle(INode nozzleNode) {
1198 Nozzle nozzle = (Nozzle)nozzleNode;
1199 Vector3d dir = new Vector3d(currentPosition);
1200 Point3d prev = new Point3d(previousPosition);
1202 Vector3d nozzleLoc = nozzle.getWorldPosition();
1203 double u[] = new double[1];
1204 Vector3d closest = MathTools.closestPointOnStraight(new Point3d(nozzleLoc), new Point3d(prev), new Vector3d(dir), u);
1205 double dist = MathTools.distanceSquared(nozzleLoc,closest);
1206 if (dist < BRANCH_SNAP_DISTANCE) {
1207 // FIXME : directions should be checked (insert an elbow)
1208 currentPosition.set(nozzleLoc);
1209 updateCurrentPoint();
1210 setInfoText("Connect to nozzle (l) :" + currentPosition);
1213 //System.out.println(u[0]);
1217 private PipeControlPoint endingLockToComponent(INode componentNode) {
1218 // we'll must scan all free pcp's and their direction to accept the connection.
1222 protected void addTurn() throws Exception{
1223 InlineComponent previous = (InlineComponent)getLast();
1224 PipeControlPoint previousCP = previous.getControlPoint();
1225 TurnComponent turn = ComponentUtils.createTurn(root);
1226 PipeControlPoint turnCP = turn.getControlPoint();
1227 turn.setName(pipeRun.getUniqueName("Elbow"));
1228 pipeRun.addChild(turn);
1230 turnCP.setDeletable(false); // mark turnCP nonDeletable so that PipingRules won't delete it immediately.
1232 previousCP.setNext(turnCP);
1233 turnCP.setPrevious(previousCP);
1235 previousCP.setPrevious(turnCP);
1236 turnCP.setNext(previousCP);
1239 turnCP.setWorldPosition(currentPosition);
1240 turnCP.setTurnAngle(0.0);
1241 turnCP.setLength(0.0);
1245 protected void addStraight() throws Exception{
1246 TurnComponent turn = (TurnComponent)getLast();
1247 PipeControlPoint turnCP = turn.getControlPoint();
1249 InlineComponent straight = ComponentUtils.createStraight(root);
1251 PipeControlPoint straightCP = straight.getControlPoint();
1252 straight.setName(pipeRun.getUniqueName("Pipe"));
1255 pipeRun.addChild(straight);
1257 added.add(straight);
1262 turnCP.setNext(straightCP);
1263 straightCP.setPrevious(turnCP);
1265 turnCP.setPrevious(straightCP);
1266 straightCP.setNext(turnCP);
1269 turnCP.setWorldPosition(currentPosition);
1270 turnCP.setTurnAngle(0.0);
1271 turnCP.setLength(0.0);
1272 straightCP.setWorldPosition(currentPosition);
1273 straightCP.setLength(0.0);
1277 protected void addPoint() throws Exception {
1280 setPreviousPosition(currentPosition);
1281 updateCurrentPoint();
1288 * Updates tool graphics for current point
1290 protected void updateCurrentPoint() {
1291 InlineComponent straight = (InlineComponent)added.get(added.size()-1);
1292 // TODO: the inline length is from previous update step.
1295 l = straight.getPrevious().getControlPoint().getInlineLength();
1297 l = straight.getNext().getControlPoint().getInlineLength();
1298 Vector3d v = new Vector3d();
1299 v.sub(currentPosition, previousPosition);
1300 double length = v.length();
1301 if (length > MathTools.NEAR_ZERO) {
1302 v.scale(1.0/length);
1303 v.scale(0.5*(length+l));
1304 v.add(previousPosition);
1305 straight.getControlPoint().setWorldPosition(v);
1306 straight.getControlPoint().setLength(length);
1309 PipingRules.positionUpdate(straight.getControlPoint(),false);
1310 } catch (Exception e) {
1311 // TODO Auto-generated catch block
1312 e.printStackTrace();
1316 private PipelineComponent getLast() {
1317 if (added.size() == 0)
1318 return startComponent;
1319 return added.get(added.size()-1);
1324 * Removes last point from pipeline
1326 public void removePoint() {
1327 if (added.size() < 3)
1329 InlineComponent straight = (InlineComponent)added.remove(added.size()-1);
1330 TurnComponent turn = (TurnComponent)added.remove(added.size()-1);
1331 straight.getControlPoint().remove();
1332 turn.getControlPoint().remove();
1333 if (added.size() > 1) {
1334 setPreviousPosition(added.get(added.size()-2).getWorldPosition());
1336 setPreviousPosition(startComponent.getWorldPosition());
1337 if (direction != null)
1338 setLockType(LockType.CUSTOM, true);
1343 protected void endPiping() throws Exception {
1344 state = ToolState.NOT_ACTIVE;
1346 if (endTo != null) {
1347 if (endType == PositionType.NEXT || endType == PositionType.PREVIOUS && endTo instanceof InlineComponent) {
1348 Vector3d dir = endTo.getControlPoint().getPathLegDirection(Direction.NEXT);
1349 Vector3d currDir = getLast().getControlPoint().getPathLegDirection(Direction.NEXT);
1351 currDir.normalize();
1352 double dot = dir.dot(currDir);
1353 System.out.println(dot + " " + currDir + " " + dir);
1354 if (dot < ALIGN_DOT_PRODUCT && dot> -ALIGN_DOT_PRODUCT) {
1359 ComponentUtils.connect(getLast(), endTo, endType, currentPosition);
1361 panel.useDefaultAction();