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() {
180 if (toolComposite != null) {
181 toolComposite.clear();
186 startComponent = null;
193 public void attach() {
194 if (startComponent == null)
196 if (toolComposite != null) {
197 createTools(toolComposite);
201 ThreadUtils.asyncExec(panel.getThreadQueue(), new Runnable() {
206 } catch (Exception e) {
208 ExceptionUtils.logAndShowError(e);
216 // private void attachUI() {
217 // //panel.setCursor(activeCursor);
218 // translateAxisGizmo.attach(panel.GetRenderer());
221 private void deattachUI() {
222 //panel.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
224 if (translateAxisGizmo.isAttached())
225 translateAxisGizmo.deattach();
226 if (splitPointSelectionGizmo.isAttached())
227 splitPointSelectionGizmo.deattach();
228 if (terminalSelectionGizmo.isAttached())
229 terminalSelectionGizmo.deattach();
230 if (constraintPointGizmo.isAttached())
231 constraintPointGizmo.deattach();
232 if (infoActor != null) {
233 panel.getRenderer().RemoveActor(infoActor);
240 protected List<PipelineComponent> added = new ArrayList<PipelineComponent>();
243 public boolean keyPressed(KeyEvent e) {
244 if (e.getKeyCode() == KeyEvent.VK_ESCAPE)
245 panel.useDefaultAction();
246 if (lock != LockType.CUSTOM || !lockForced) {
247 if ((e.getModifiersEx() & KeyEvent.SHIFT_DOWN_MASK) > 0) {
248 if (e.getKeyCode() == KeyEvent.VK_X) {
249 if (lock != LockType.XY && lock != LockType.XZ) {
250 setLockType(LockType.XY, false);
251 } else if (lock == LockType.XY) {
252 setLockType(LockType.XZ, false);
254 setLockType(LockType.NONE, false);
257 if (e.getKeyCode() == KeyEvent.VK_Y) {
258 if (lock != LockType.XY && lock != LockType.YZ) {
259 setLockType(LockType.XY, false);
260 } else if (lock == LockType.XY) {
261 setLockType(LockType.YZ, false);
263 setLockType(LockType.NONE, false);
266 if (e.getKeyCode() == KeyEvent.VK_Z) {
267 if (lock != LockType.XZ && lock != LockType.YZ) {
268 setLockType(LockType.XZ, false);
269 } else if (lock == LockType.XZ) {
270 setLockType(LockType.YZ, false);
272 setLockType(LockType.NONE, false);
276 if (e.getKeyCode() == KeyEvent.VK_X) {
277 if (lock != LockType.X)
278 setLockType(LockType.X,false);
280 setLockType(LockType.NONE,false);
282 if (e.getKeyCode() == KeyEvent.VK_Y) {
283 if (lock != LockType.Y)
284 setLockType(LockType.Y,false);
286 setLockType(LockType.NONE, false);
288 if (e.getKeyCode() == KeyEvent.VK_Z) {
289 if (lock != LockType.Z)
290 setLockType(LockType.Z, false);
292 setLockType(LockType.NONE, false);
294 if (e.getKeyCode() == KeyEvent.VK_L && direction != null) {
295 if (lock != LockType.CUSTOM)
296 setLockType(LockType.CUSTOM, false);
298 setLockType(LockType.NONE, false);
302 if (e.getKeyCode() == KeyEvent.VK_C) {
303 setUseDefault(!useDefault);
310 private void setUseDefault(boolean b) {
313 setInfoText("Rotating camera");
314 if (cameraButton != null)
315 cameraButton.setSelection(useDefault);
319 private void update() {
322 private void update(double x, double y) {
325 return; // TODO : throw Exception?
328 case SELECTING_POSITION:
330 case SELECTING_SPLIT:
339 boolean startRemovable = false;
341 protected void activate() throws Exception {
342 state = ToolState.INITIALIZING;
345 if (allowed.size() == 1) {
346 pipeRun = startComponent.getPipeRun();
347 PipeControlPoint start = startComponent.getControlPoint();
348 boolean requiresBranching = false;
349 if (start.getNext() == null)
351 else if (start.getPrevious() == null) {
354 requiresBranching = true;
357 if (requiresBranching) {
358 activateSplit(start);
360 activateNextPrev(start);
362 } else if (allowed.size() == 0) {
363 panel.useDefaultAction();
364 state = ToolState.NOT_ACTIVE;
367 terminalSelectionGizmo.setComponent(startComponent, allowed);
368 terminalSelectionGizmo.attach(panel);
369 state = ToolState.SELECTING_POSITION;
377 protected void activateNextPrev(PipeControlPoint start) throws Exception{
378 if (!reversed && start.isDualInline())
379 start = start.getDualSub();
380 else if (reversed && start.isDualSub())
381 start = start.parent;
383 pipeRun = start.getPipeRun();
384 setPreviousPosition(start.getWorldPosition());
386 boolean startWithTurn = false;
387 if (startComponent instanceof Nozzle) {
388 direction = startComponent.getControlPoint().getDirectedControlPointDirection();
389 lock = LockType.CUSTOM;
391 } else if (startComponent instanceof PipelineComponent){
392 if (startComponent instanceof InlineComponent) {
393 direction = startComponent.getControlPoint().getPathLegDirection(reversed ? Direction.PREVIOUS : Direction.NEXT);
394 lock = LockType.CUSTOM;
396 if (((InlineComponent) startComponent).isVariableLength()) {
397 startWithTurn = true;
399 lock = LockType.NONE;
402 Vector3d v = new Vector3d();
404 start.getControlPointEnds(v, previousPosition);
406 start.getControlPointEnds(previousPosition,v);
408 } else if (startComponent instanceof TurnComponent) {
409 if (start.asFixedAngle()) {
410 direction = startComponent.getControlPoint().getPathLegDirection(reversed ? Direction.PREVIOUS : Direction.NEXT);
411 lock = LockType.CUSTOM;
412 lockForced = start.isFixedAngle();
415 lock = LockType.NONE;
418 } else if (startComponent instanceof EndComponent) {
419 throw new Exception("Not supported");
423 throw new Exception("Not supported");
425 currentPosition = new Vector3d(previousPosition);
426 state = ToolState.ROUTING;
427 if (direction != null) {
428 direction.normalize();
431 startRemovable = start.isDeletable();
432 start.setDeletable(false);
437 if (direction != null)
438 currentPosition.add(direction);
439 InlineComponent straight = ComponentUtils.createStraight(root);
440 PipeControlPoint straightCP = straight.getControlPoint();
441 straight.setName(pipeRun.getUniqueName("Pipe"));
442 pipeRun.addChild(straight);
446 start.setNext(straightCP);
447 straightCP.setPrevious(start);
449 start.setPrevious(straightCP);
450 straightCP.setNext(start);
453 translateAxisGizmo.attach(panel);
454 setPreviousPosition(previousPosition);
455 updateCurrentPoint();
459 protected void setPreviousPosition(Vector3d v) {
460 previousPosition = new Vector3d(v);
461 if (translateAxisGizmo.isAttached())
462 translateAxisGizmo.setPosition(previousPosition);
465 private void activateBranch(PipeControlPoint start) throws Exception{
466 pipeRun = start.getPipeRun();
467 setPreviousPosition(start.getWorldPosition());
470 lock = LockType.NONE;
472 currentPosition = new Vector3d(previousPosition);
473 state = ToolState.ROUTING;
474 if (direction != null) {
475 direction.normalize();
478 startRemovable = start.isDeletable();
479 start.setDeletable(false);
482 if (direction != null)
483 currentPosition.add(direction);
484 InlineComponent straight = ComponentUtils.createStraight(root);
485 PipeControlPoint straightCP = straight.getControlPoint();
486 straight.setName(pipeRun.getUniqueName("Pipe"));
487 pipeRun.addChild(straight);
491 start.setNext(straightCP);
492 straightCP.setPrevious(start);
495 start.setPrevious(straightCP);
496 straightCP.setNext(start);
500 translateAxisGizmo.attach(panel);
501 setPreviousPosition(previousPosition);
502 updateCurrentPoint();
506 private void activateSplit(PipeControlPoint start) throws Exception{
507 Point3d p1 = new Point3d();
508 Point3d p2 = new Point3d();
509 start.getInlineControlPointEnds(p1, p2);
510 splitPointSelectionGizmo.setSplit(p1, p2);
511 splitPointSelectionGizmo.attach(panel);
512 state = ToolState.SELECTING_SPLIT;
514 public void deactivate() {
515 if (added.size() > 0) {
516 for (PipelineComponent component : added) {
517 component.getControlPoint().setDeletable(true);
520 for (PipelineComponent comp : added) {
521 PipingRules.requestUpdate(comp.getControlPoint());
524 PipingRules.update();
525 nodeMap.commit("Route pipe");
526 } catch (Exception e) {
527 ExceptionUtils.logAndShowError(e);
532 startComponent.getControlPoint().setDeletable(startRemovable);
536 setLockType(LockType.NONE, true);
537 startComponent = null;
543 currentPosition = null;
544 previousPosition = null;
545 startRemovable = false;
546 detector.clearConstraintHighlights();
547 state = ToolState.NOT_ACTIVE;
552 private void setLockType(LockType type, boolean force) {
553 if (type == LockType.CUSTOM && (direction == null || added.size() > 0)) {
555 } else if (force || (lock != LockType.CUSTOM || !lockForced || added.size() > 0) ) {
562 translateAxisGizmo.setType(6);
565 translateAxisGizmo.setType(0);
568 translateAxisGizmo.setType(1);
571 translateAxisGizmo.setType(2);
574 translateAxisGizmo.setType(3);
577 translateAxisGizmo.setType(4);
580 translateAxisGizmo.setType(5);
589 private void updateWidget() {
590 if (axisCombo != null) {
591 axisCombo.select(lock.ordinal());
592 axisCombo.setEnabled(!lockForced || lock != LockType.CUSTOM);
597 public boolean mousePressed(MouseEvent e) {
599 getDefaultAction().mousePressed(e);
605 public boolean mouseReleased(MouseEvent e) {
607 getDefaultAction().mouseReleased(e);
613 public boolean mouseWheelMoved(MouseWheelEvent e) {
615 getDefaultAction().mouseWheelMoved(e);
621 public boolean mouseClicked(MouseEvent e) {
623 getDefaultAction().mouseClicked(e);
626 if (state == ToolState.ROUTING) {
628 if (e.getClickCount() == 1) {
629 if (e.getButton() == MouseEvent.BUTTON1) {
630 if (this.added.size() > 0) {
632 setLockType(LockType.NONE,true);
640 throw new RuntimeException("RoutePipeAction initialization has failed, no added components found");
641 // // user was selecting position of branch
642 // lastPoint.set(startPoint);
643 // controlPoints.add(new Point3d(startPoint));
644 // if (selectionLine != null)
645 // selectionLine.removeFromParent();
646 // selectionLine = null;
648 } else if (e.getButton() ==MouseEvent.BUTTON2){
650 } else if (e.getButton() == MouseEvent.BUTTON3){
654 } catch(Exception err) {
655 err.printStackTrace();
657 } else if (state == ToolState.SELECTING_POSITION) {
658 if (e.getClickCount() == 1 && e.getButton() == MouseEvent.BUTTON1) {
659 int type = panel.getPickType();
660 //panel.setPickType(0);
661 panel.setPickType(5);
662 vtkProp[] picked = panel.pick(e.getX(), e.getY());
663 panel.setPickType(type);
664 PositionType position = terminalSelectionGizmo.getPickedPosition(picked);
665 if (position != null) {
666 terminalSelectionGizmo.deattach();
668 if (position == PositionType.SPLIT) {
669 activateSplit(startComponent.getControlPoint());
670 } else if (position == PositionType.NEXT || position == PositionType.PREVIOUS) {
671 reversed = position == PositionType.PREVIOUS;
672 activateNextPrev(startComponent.getControlPoint());
674 panel.useDefaultAction();
676 } catch (Exception err) {
677 ExceptionUtils.logAndShowError(err);
678 panel.useDefaultAction();
682 } else if (state == ToolState.SELECTING_SPLIT) {
683 if (e.getClickCount() == 1 && e.getButton() == MouseEvent.BUTTON1) {
684 Tuple3d t = splitPointSelectionGizmo.getSplitPoint();
685 splitPointSelectionGizmo.deattach();
687 panel.useDefaultAction();
691 Vector3d pos = new Vector3d(t);
692 InlineComponent branchSplit = ComponentUtils.createBranchSplit((InlineComponent)startComponent, pos);
693 PipeControlPoint branchSplitCP = branchSplit.getControlPoint();
695 PipeRun newRun = new PipeRun();
696 String n = root.getUniqueName("PipeRun");
698 root.addChild(newRun);
699 PipeControlPoint pcp = new PipeControlPoint(branchSplit,newRun);
700 branchSplitCP.children.add(pcp);
701 pcp.parent = branchSplitCP;
702 pcp.setWorldOrientation(branchSplitCP.getWorldOrientation());
703 pcp.setWorldPosition(branchSplitCP.getWorldPosition());
704 startComponent = branchSplit;
706 } catch (Exception err) {
707 ExceptionUtils.logAndShowError(err);
708 panel.useDefaultAction();
715 private void updateConstraints() {
716 detector.clearConstraints();
717 constraintPointGizmo.clearPositions();
718 if (hoverObject == null) {
719 if (constraintPointGizmo.isAttached())
720 constraintPointGizmo.deattach();
723 if (hoverObject instanceof Nozzle) {
724 Nozzle n = (Nozzle)hoverObject;
725 detector.addContraintPoint(new Point3d(n.getWorldPosition()));
726 } else if (hoverObject instanceof InlineComponent) {
727 InlineComponent c = (InlineComponent)hoverObject;
728 Point3d p1 = new Point3d();
729 Point3d p2 = new Point3d();
731 detector.addContraintPoint(p1);
732 detector.addContraintPoint(p2);
733 detector.addContraintPoint(new Point3d(c.getWorldPosition()));
734 } else if (hoverObject instanceof TurnComponent) {
735 TurnComponent n = (TurnComponent)hoverObject;
736 detector.addContraintPoint(new Point3d(n.getWorldPosition()));
738 if (detector.getConstraintPoints().size() > 0) {
739 for (Point3d p : detector.getConstraintPoints()) {
740 constraintPointGizmo.addPosition(new Vector3d(p));
742 if (constraintPointGizmo.isAttached())
743 constraintPointGizmo.deattach();
744 constraintPointGizmo.attach(panel);
749 public boolean mouseMoved(MouseEvent e) {
751 getDefaultAction().mouseMoved(e);
754 step = ((e.getModifiers() & MouseEvent.CTRL_MASK) > 0);
755 update(e.getX(), e.getY());
760 public boolean mouseDragged(MouseEvent e) {
762 getDefaultAction().mouseDragged(e);
769 private List<INode> isOverNode(int x, int y) {
770 List<INode> nodes = new ArrayList<INode>();
771 vtkProp picked[] = panel.pick2(x, y);
773 for (int i = 0; i < picked.length; i++) {
774 nodes.add(nodeMap.getNode(picked[i]));
780 INode hoverObject = null;
782 protected void updateRouting(double x, double y) {
784 //panel.getDefaultAction().update();
792 Ray ray = vtkUtil.createMouseRay(panel.getRenderer(),x, y);
793 Vector3d o = new Vector3d(ray.pos);
794 Vector3d d = ray.dir;
797 if (!updateCurrentPoint(o, d))
799 //Point3d startPoint = new Point3d();
800 double mu[] = new double[2];
806 List<INode> hover = isOverNode((int)x,(int)y);
807 if (hover.size() > 0) {
808 hoverObject = hover.get(0);
812 // System.out.println(hoverObject + " " + getLast());
813 if (hoverObject != null) {
814 if (hoverObject.equals(getLast()) ) {
816 for (int i = 1; i < hover.size(); i++) {
817 hoverObject = hover.get(i);
818 if (!getLast().equals(hoverObject)) {
827 // System.out.println(hoverObject);
828 if (hoverObject != null) {
830 if (lock == LockType.NONE) {
831 if (hoverObject instanceof Nozzle && endingToNozzle(hoverObject,o,d)) {
832 endTo = (Nozzle)hoverObject;
833 } else if (hoverObject instanceof InlineComponent && ((InlineComponent)hoverObject).isVariableLength()) {
834 endTo = (InlineComponent)hoverObject;
835 endType = endingToStraight(endTo,mu,o,d);
838 } else if (hoverObject instanceof PipelineComponent && (endPort = endingToComponent(hoverObject,o,d)) != null) {
839 endTo = (PipelineComponent)hoverObject;
844 if (hoverObject instanceof InlineComponent && ((InlineComponent)hoverObject).isVariableLength() && (endType = endingLockToStraight(hoverObject,mu, new Point3d(currentPosition))) != null) {
845 endTo = (InlineComponent)hoverObject;
846 } else if (hoverObject instanceof Nozzle && endingLockToNozzle(hoverObject)) {
847 endTo = (Nozzle)hoverObject;
848 } else if ((hoverObject instanceof PipelineComponent) && ((endPort = endingLockToComponent(hoverObject)) != null)) {
849 endTo = (PipelineComponent)hoverObject;
854 if (added.contains(endTo))
864 protected boolean updateCurrentPoint(Vector3d o, Vector3d d) {
866 Vector3d point = new Vector3d(this.previousPosition);
870 MathTools.intersectStraightStraight(point, new Vector3d(1.0,0.0,0.0), o,d, currentPosition, new Vector3d());
872 currentPosition.x = Math.round(istep * currentPosition.x) / istep;
873 BigDecimal bx = new BigDecimal(currentPosition.x);
874 bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);
875 currentPosition.x = bx.doubleValue();
879 MathTools.intersectStraightStraight(point, new Vector3d(0.0,1.0,0.0), o,d, currentPosition, new Vector3d());
881 currentPosition.y = Math.round(istep * currentPosition.y) / istep;
882 BigDecimal bx = new BigDecimal(currentPosition.y);
883 bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);
884 currentPosition.y = bx.doubleValue();
888 MathTools.intersectStraightStraight(point, new Vector3d(0.0,0.0,1.0), o,d, currentPosition, new Vector3d());
890 currentPosition.z = Math.round(istep * currentPosition.z) / istep;
891 BigDecimal bx = new BigDecimal(currentPosition.z);
892 bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);
893 currentPosition.z = bx.doubleValue();
896 MathTools.intersectStraightPlane(o, d, point, new Vector3d(0.0,0.0,1.0), currentPosition);
899 MathTools.intersectStraightPlane(o, d, point, new Vector3d(0.0,1.0,0.0), currentPosition);
902 MathTools.intersectStraightPlane(o, d, point, new Vector3d(1.0,0.0,0.0), currentPosition);
905 Vector3d normal = new Vector3d(panel.getRenderer().GetActiveCamera().GetDirectionOfProjection());
908 MathTools.intersectStraightPlane(o, d, point, normal, currentPosition);
911 MathTools.intersectStraightStraight(point, new Vector3d(direction), o,d, currentPosition, new Vector3d());
912 double dist = MathTools.distanceFromPlane(new Vector3d(currentPosition), direction, previousPosition);
914 currentPosition.set(previousPosition);
922 @SuppressWarnings("unused")
923 private Vector3d getLockDir() {
928 return new Vector3d(1,0,0);
930 return new Vector3d(0,1,0);
932 return new Vector3d(0,0,1);
938 protected void updateRoute(Vector3d o, Vector3d d) {
939 detector.clearConstraintHighlights();
940 Point3d previousPipePoint = new Point3d(previousPosition);
942 if (lock == LockType.NONE) {
943 Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint));
945 currentPosition = new Vector3d(p);
946 s += detector.getSnapString();
949 Vector3d dir = new Vector3d(currentPosition);
950 dir.sub(previousPipePoint);
951 Point3d p = detector.getPointSnap(new Vector3d(previousPipePoint), dir);
953 currentPosition = new Vector3d(p);
954 s += detector.getSnapString();
957 // System.out.println(previousPosition + " -> " + currentPosition);
958 // double dist = MathTools.distance(previousPosition, currentPosition);
959 // if (dist < pipeRun.getTurnRadius()) {
961 // Vector3d v = new Vector3d(currentPosition);
962 // v.sub(previousPosition);
963 // double vl = v.length();
964 // if (vl > MathTools.NEAR_ZERO) {
970 // v.scale(pipeRun.getTurnRadius());
971 // v.add(previousPosition);
972 // currentPosition.set(v);
975 updateCurrentPoint();
976 s += currentPosition.toString();
980 vtkTextActor infoActor;
982 private void setInfoText(String text) {
983 //System.out.println(text);
984 if (infoActor == null) {
985 infoActor = new vtkTextActor();
986 infoActor.GetTextProperty().SetColor(0.0, 0.0, 0.0);
987 infoActor.GetTextProperty().ShadowOff();
988 infoActor.GetTextProperty().ItalicOff();
989 infoActor.GetTextProperty().BoldOff();
990 infoActor.GetTextProperty().SetFontSize(18);
991 infoActor.GetTextProperty().Delete();
992 infoActor.GetProperty().SetColor(0.0, 0.0, 0.0);
993 infoActor.GetProperty().Delete();
996 infoActor.SetPosition(10,10);
997 panel.getRenderer().AddActor(infoActor);
999 infoActor.SetInput(text);
1002 private boolean endingToNozzle(INode nozzleNode,Vector3d o, Vector3d d) {
1003 Nozzle nozzle = (Nozzle)nozzleNode;
1004 PipeControlPoint pcp =nozzle.getControlPoint();
1005 if (pcp != null && (pcp.getNext() != null ||
1006 pcp.getPrevious() != null))
1007 return false; // nozzle is already connected to pipe
1008 currentPosition = pcp.getWorldPosition();
1009 Point3d previousPipePoint = new Point3d(previousPosition);
1010 Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint));
1012 if (MathTools.distance(p, currentPosition) > NOZZLE_SNAP_DISTANCE) {
1017 updateCurrentPoint();
1019 setInfoText("Connect to nozzle " + currentPosition);
1024 private PositionType endingToStraight(INode straightNode, double mu[], Vector3d o, Vector3d d) {
1025 // if (!allowBranches) {
1026 // updateCurrentPoint();
1029 InlineComponent s = (InlineComponent)straightNode;
1031 Point3d sStart = new Point3d();
1032 Point3d sEnd = new Point3d();
1033 s.getEnds(sStart, sEnd);
1034 //detector.clearConstraintHighlights();
1036 Point3d previousPipePoint = new Point3d(previousPosition);
1037 Point3d currentPipePoint = new Point3d(currentPosition);
1039 if (lock == LockType.NONE) {
1040 Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint));
1042 currentPosition = new Vector3d(p);
1043 // snapping is detected, check if snapped point can create branch with straight
1044 PositionType t = endingLockToStraight(s, mu, currentPipePoint);
1047 // if not, we'll have to remove highlight that was added when snapped point was detected
1048 detector.clearConstraintHighlights();
1051 Vector3d sDir = new Vector3d(sEnd);
1053 MathTools.intersectStraightStraight(sStart, sDir, o, d, currentPosition, new Point3d(), mu);
1057 throw new RuntimeException("Lock shouldn't be on");
1061 updateCurrentPoint();
1063 // branch point must lie between straight's ends. If connection point is exactly
1064 // on straight end user may want to connect pipes to each other
1065 // TODO : take account sizes of inline components)
1066 return endingToStraight(mu, s, sStart, sEnd, currentPipePoint);
1069 private PositionType endingToStraight(double mu[], InlineComponent s, Point3d sStart, Point3d sEnd , Point3d currentPipePoint) {
1072 boolean connectPrev = false;
1073 boolean connectNext = false;
1074 boolean branch = false;
1078 else if (mu[0] > 0.9) {
1084 PipeControlPoint pcp = s.getControlPoint();
1085 if (pcp.getPrevious() != null)
1086 connectPrev = false;
1087 } else if (connectNext) {
1088 PipeControlPoint pcp = s.getControlPoint();
1089 if (pcp.getNext() != null)
1090 connectNext = false;
1092 Vector3d dir = s.getControlPoint().getPathLegDirection(Direction.NEXT);
1093 Vector3d currDir = getLast().getControlPoint().getPathLegDirection(Direction.NEXT);
1095 currDir.normalize();
1096 double dot = dir.dot(currDir);
1097 System.out.println(dot + " " + currDir + " " + dir);
1098 if (dot > BRANCH_DOT_PRODUCT || dot < -BRANCH_DOT_PRODUCT) {
1099 // pipes are almost in the same direction, creating a branch is not feasible.
1107 if (connectNext || connectPrev)
1108 info += "Connect pipes :";
1110 info += "Create a Branch :";
1112 setInfoText(info + currentPosition + " " + Math.max(0.0, Math.min(mu[0], 1.0)));
1114 currentPosition.set(sEnd);
1115 updateCurrentPoint();
1116 return PositionType.NEXT;
1117 } else if (connectPrev){
1118 currentPosition.set(sStart);
1119 updateCurrentPoint();
1120 return PositionType.PREVIOUS;
1121 } else if (branch && allowBranches) {
1122 return PositionType.SPLIT;
1124 currentPosition.set(currentPipePoint);
1125 updateCurrentPoint();
1130 private PipeControlPoint endingToComponent(INode componentNode, Vector3d o, Vector3d d) {
1131 PipelineComponent component = (PipelineComponent)componentNode;
1132 PipeControlPoint pcp = component.getControlPoint();
1133 PipeControlPoint connect = null;
1134 if (component instanceof EndComponent) {
1135 if (pcp.getNext() != null || pcp.getPrevious() != null)
1138 } else if (component instanceof TurnComponent) {
1139 if (pcp.getNext() == null || pcp.getPrevious() == null)
1143 } else if (component instanceof InlineComponent) {
1144 // TODO : scan all empty pcps of the component and select closest one.
1145 if (pcp.getNext() == null || pcp.getPrevious() == null)
1150 if (connect != null) {
1151 currentPosition.set(connect.getWorldPosition());
1152 updateCurrentPoint();
1153 setInfoText("Connect to " + component.getName());
1159 private PositionType endingLockToStraight(INode straightNode, double mu[], Point3d currentPipePoint) {
1160 // if (!allowBranches) {
1161 // updateCurrentPoint();
1164 InlineComponent s = (InlineComponent)straightNode;
1165 Point3d sStart = new Point3d();
1166 Point3d sEnd = new Point3d();
1167 s.getControlPoint().getInlineControlPointEnds(sStart, sEnd);
1168 Vector3d sDir = new Vector3d(sEnd);
1170 Vector3d dir = new Vector3d(currentPosition);
1171 Point3d prev = new Point3d(previousPosition);
1173 // intersection point in pipe where branch would be inserted to
1174 Vector3d branchPoint = new Vector3d();
1175 // intersection point in straight pipe that is currently routed
1176 Vector3d routePoint = new Vector3d();
1177 MathTools.intersectStraightStraight(sStart, sDir, new Vector3d(prev), dir, branchPoint, routePoint, mu);
1178 routePoint.sub(branchPoint);
1179 // startPoint of branch must be between pipe ends
1180 // TODO : take account sizes of elbows (or other components)
1181 // branch point must be between pipe ends and intersection points must be quite close to each other
1183 if (routePoint.lengthSquared() > BRANCH_SNAP_DISTANCE)
1186 return endingToStraight(mu, s, sStart, sEnd, currentPipePoint);
1188 // if (mu[0] > 0.0 && mu[0] < 1.0 && routePoint.lengthSquared() < BRANCH_SNAP_DISTANCE) {
1189 // currentPosition.set(branchPoint);
1191 // updateCurrentPoint();
1193 // setInfoText("Create a branch (l) :" + currentPosition + " " + Math.max(0.0, Math.min(mu[0], 1.0)) + " " + routePoint.lengthSquared());
1194 // return PositionType.SPLIT;
1199 private boolean endingLockToNozzle(INode nozzleNode) {
1200 Nozzle nozzle = (Nozzle)nozzleNode;
1201 Vector3d dir = new Vector3d(currentPosition);
1202 Point3d prev = new Point3d(previousPosition);
1204 Vector3d nozzleLoc = nozzle.getWorldPosition();
1205 double u[] = new double[1];
1206 Vector3d closest = MathTools.closestPointOnStraight(new Point3d(nozzleLoc), new Point3d(prev), new Vector3d(dir), u);
1207 double dist = MathTools.distanceSquared(nozzleLoc,closest);
1208 if (dist < BRANCH_SNAP_DISTANCE) {
1209 // FIXME : directions should be checked (insert an elbow)
1210 currentPosition.set(nozzleLoc);
1211 updateCurrentPoint();
1212 setInfoText("Connect to nozzle (l) :" + currentPosition);
1215 //System.out.println(u[0]);
1219 private PipeControlPoint endingLockToComponent(INode componentNode) {
1220 // we'll must scan all free pcp's and their direction to accept the connection.
1224 protected void addTurn() throws Exception{
1225 InlineComponent previous = (InlineComponent)getLast();
1226 PipeControlPoint previousCP = previous.getControlPoint();
1227 TurnComponent turn = ComponentUtils.createTurn(root);
1228 PipeControlPoint turnCP = turn.getControlPoint();
1229 turn.setName(pipeRun.getUniqueName("Elbow"));
1230 pipeRun.addChild(turn);
1232 turnCP.setDeletable(false); // mark turnCP nonDeletable so that PipingRules won't delete it immediately.
1234 previousCP.setNext(turnCP);
1235 turnCP.setPrevious(previousCP);
1237 previousCP.setPrevious(turnCP);
1238 turnCP.setNext(previousCP);
1241 turnCP.setWorldPosition(currentPosition);
1242 turnCP.setTurnAngle(0.0);
1243 turnCP.setLength(0.0);
1247 protected void addStraight() throws Exception{
1248 TurnComponent turn = (TurnComponent)getLast();
1249 PipeControlPoint turnCP = turn.getControlPoint();
1251 InlineComponent straight = ComponentUtils.createStraight(root);
1253 PipeControlPoint straightCP = straight.getControlPoint();
1254 straight.setName(pipeRun.getUniqueName("Pipe"));
1257 pipeRun.addChild(straight);
1259 added.add(straight);
1264 turnCP.setNext(straightCP);
1265 straightCP.setPrevious(turnCP);
1267 turnCP.setPrevious(straightCP);
1268 straightCP.setNext(turnCP);
1271 turnCP.setWorldPosition(currentPosition);
1272 turnCP.setTurnAngle(0.0);
1273 turnCP.setLength(0.0);
1274 straightCP.setWorldPosition(currentPosition);
1275 straightCP.setLength(0.0);
1279 protected void addPoint() throws Exception {
1282 setPreviousPosition(currentPosition);
1283 updateCurrentPoint();
1290 * Updates tool graphics for current point
1292 protected void updateCurrentPoint() {
1293 InlineComponent straight = (InlineComponent)added.get(added.size()-1);
1294 // TODO: the inline length is from previous update step.
1297 l = straight.getPrevious().getControlPoint().getInlineLength();
1299 l = straight.getNext().getControlPoint().getInlineLength();
1300 Vector3d v = new Vector3d();
1301 v.sub(currentPosition, previousPosition);
1302 double length = v.length();
1303 if (length > MathTools.NEAR_ZERO) {
1304 v.scale(1.0/length);
1305 v.scale(0.5*(length+l));
1306 v.add(previousPosition);
1307 straight.getControlPoint().setWorldPosition(v);
1308 straight.getControlPoint().setLength(length);
1311 PipingRules.positionUpdate(straight.getControlPoint(),false);
1312 } catch (Exception e) {
1313 // TODO Auto-generated catch block
1314 e.printStackTrace();
1318 private PipelineComponent getLast() {
1319 if (added.size() == 0)
1320 return startComponent;
1321 return added.get(added.size()-1);
1326 * Removes last point from pipeline
1328 public void removePoint() {
1329 if (added.size() < 3)
1331 InlineComponent straight = (InlineComponent)added.remove(added.size()-1);
1332 TurnComponent turn = (TurnComponent)added.remove(added.size()-1);
1333 straight.getControlPoint().remove();
1334 turn.getControlPoint().remove();
1335 if (added.size() > 1) {
1336 setPreviousPosition(added.get(added.size()-2).getWorldPosition());
1338 setPreviousPosition(startComponent.getWorldPosition());
1339 if (direction != null)
1340 setLockType(LockType.CUSTOM, true);
1345 protected void endPiping() throws Exception {
1346 state = ToolState.NOT_ACTIVE;
1348 if (endTo != null) {
1349 if (endType == PositionType.NEXT || endType == PositionType.PREVIOUS && endTo instanceof InlineComponent) {
1350 Vector3d dir = endTo.getControlPoint().getPathLegDirection(Direction.NEXT);
1351 Vector3d currDir = getLast().getControlPoint().getPathLegDirection(Direction.NEXT);
1353 currDir.normalize();
1354 double dot = dir.dot(currDir);
1355 System.out.println(dot + " " + currDir + " " + dir);
1356 if (dot < ALIGN_DOT_PRODUCT && dot> -ALIGN_DOT_PRODUCT) {
1361 ComponentUtils.connect(getLast(), endTo, endType, currentPosition);
1363 panel.useDefaultAction();