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().getInlineDir();
394 if (reversed) direction.negate();
395 lock = LockType.CUSTOM;
397 if (((InlineComponent) startComponent).isVariableLength()) {
398 startWithTurn = true;
400 lock = LockType.NONE;
403 Vector3d v = new Vector3d();
405 start.getControlPointEnds(v, previousPosition);
407 start.getControlPointEnds(previousPosition,v);
409 } else if (startComponent instanceof TurnComponent) {
410 if (start.asFixedAngle()) {
411 direction = startComponent.getControlPoint().getPathLegDirection(reversed ? Direction.PREVIOUS : Direction.NEXT);
412 lock = LockType.CUSTOM;
413 lockForced = start.isFixedAngle();
416 lock = LockType.NONE;
419 } else if (startComponent instanceof EndComponent) {
420 throw new Exception("Not supported");
424 throw new Exception("Not supported");
426 currentPosition = new Vector3d(previousPosition);
427 state = ToolState.ROUTING;
428 if (direction != null) {
429 direction.normalize();
432 startRemovable = start.isDeletable();
433 start.setDeletable(false);
438 if (direction != null)
439 currentPosition.add(direction);
440 InlineComponent straight = ComponentUtils.createStraight(root);
441 PipeControlPoint straightCP = straight.getControlPoint();
442 straight.setName(pipeRun.getUniqueName("Pipe"));
443 pipeRun.addChild(straight);
447 start.setNext(straightCP);
448 straightCP.setPrevious(start);
450 start.setPrevious(straightCP);
451 straightCP.setNext(start);
454 translateAxisGizmo.attach(panel);
455 setPreviousPosition(previousPosition);
456 updateCurrentPoint();
460 protected void setPreviousPosition(Vector3d v) {
461 previousPosition = new Vector3d(v);
462 if (translateAxisGizmo.isAttached())
463 translateAxisGizmo.setPosition(previousPosition);
466 private void activateBranch(PipeControlPoint start) throws Exception{
467 pipeRun = start.getPipeRun();
468 setPreviousPosition(start.getWorldPosition());
471 lock = LockType.NONE;
473 currentPosition = new Vector3d(previousPosition);
474 state = ToolState.ROUTING;
475 if (direction != null) {
476 direction.normalize();
479 startRemovable = start.isDeletable();
480 start.setDeletable(false);
483 if (direction != null)
484 currentPosition.add(direction);
485 InlineComponent straight = ComponentUtils.createStraight(root);
486 PipeControlPoint straightCP = straight.getControlPoint();
487 straight.setName(pipeRun.getUniqueName("Pipe"));
488 pipeRun.addChild(straight);
492 start.setNext(straightCP);
493 straightCP.setPrevious(start);
496 start.setPrevious(straightCP);
497 straightCP.setNext(start);
501 translateAxisGizmo.attach(panel);
502 setPreviousPosition(previousPosition);
503 updateCurrentPoint();
507 private void activateSplit(PipeControlPoint start) throws Exception{
508 Point3d p1 = new Point3d();
509 Point3d p2 = new Point3d();
510 start.getInlineControlPointEnds(p1, p2);
511 splitPointSelectionGizmo.setSplit(p1, p2);
512 splitPointSelectionGizmo.attach(panel);
513 state = ToolState.SELECTING_SPLIT;
515 public void deactivate() {
516 if (added.size() > 0) {
517 for (PipelineComponent component : added) {
518 component.getControlPoint().setDeletable(true);
521 for (PipelineComponent comp : added) {
522 PipingRules.requestUpdate(comp.getControlPoint());
525 PipingRules.update();
526 nodeMap.commit("Route pipe");
527 } catch (Exception e) {
528 ExceptionUtils.logAndShowError(e);
533 startComponent.getControlPoint().setDeletable(startRemovable);
537 setLockType(LockType.NONE, true);
538 startComponent = null;
544 currentPosition = null;
545 previousPosition = null;
546 startRemovable = false;
547 detector.clearConstraintHighlights();
548 state = ToolState.NOT_ACTIVE;
553 private void setLockType(LockType type, boolean force) {
554 if (type == LockType.CUSTOM && (direction == null || added.size() > 0)) {
556 } else if (force || (lock != LockType.CUSTOM || !lockForced || added.size() > 0) ) {
563 translateAxisGizmo.setType(6);
566 translateAxisGizmo.setType(0);
569 translateAxisGizmo.setType(1);
572 translateAxisGizmo.setType(2);
575 translateAxisGizmo.setType(3);
578 translateAxisGizmo.setType(4);
581 translateAxisGizmo.setType(5);
590 private void updateWidget() {
591 if (axisCombo != null) {
592 axisCombo.select(lock.ordinal());
593 axisCombo.setEnabled(!lockForced || lock != LockType.CUSTOM);
598 public boolean mousePressed(MouseEvent e) {
600 getDefaultAction().mousePressed(e);
606 public boolean mouseReleased(MouseEvent e) {
608 getDefaultAction().mouseReleased(e);
614 public boolean mouseWheelMoved(MouseWheelEvent e) {
616 getDefaultAction().mouseWheelMoved(e);
622 public boolean mouseClicked(MouseEvent e) {
624 getDefaultAction().mouseClicked(e);
627 if (state == ToolState.ROUTING) {
629 if (e.getClickCount() == 1) {
630 if (e.getButton() == MouseEvent.BUTTON1) {
631 if (this.added.size() > 0) {
633 setLockType(LockType.NONE,true);
641 throw new RuntimeException("RoutePipeAction initialization has failed, no added components found");
642 // // user was selecting position of branch
643 // lastPoint.set(startPoint);
644 // controlPoints.add(new Point3d(startPoint));
645 // if (selectionLine != null)
646 // selectionLine.removeFromParent();
647 // selectionLine = null;
649 } else if (e.getButton() ==MouseEvent.BUTTON2){
651 } else if (e.getButton() == MouseEvent.BUTTON3){
655 } catch(Exception err) {
656 err.printStackTrace();
658 } else if (state == ToolState.SELECTING_POSITION) {
659 if (e.getClickCount() == 1 && e.getButton() == MouseEvent.BUTTON1) {
660 int type = panel.getPickType();
661 //panel.setPickType(0);
662 panel.setPickType(5);
663 vtkProp[] picked = panel.pick(e.getX(), e.getY());
664 panel.setPickType(type);
665 PositionType position = terminalSelectionGizmo.getPickedPosition(picked);
666 if (position != null) {
667 terminalSelectionGizmo.deattach();
669 if (position == PositionType.SPLIT) {
670 activateSplit(startComponent.getControlPoint());
671 } else if (position == PositionType.NEXT || position == PositionType.PREVIOUS) {
672 reversed = position == PositionType.PREVIOUS;
673 activateNextPrev(startComponent.getControlPoint());
675 panel.useDefaultAction();
677 } catch (Exception err) {
678 ExceptionUtils.logAndShowError(err);
679 panel.useDefaultAction();
683 } else if (state == ToolState.SELECTING_SPLIT) {
684 if (e.getClickCount() == 1 && e.getButton() == MouseEvent.BUTTON1) {
685 Tuple3d t = splitPointSelectionGizmo.getSplitPoint();
686 splitPointSelectionGizmo.deattach();
688 panel.useDefaultAction();
692 Vector3d pos = new Vector3d(t);
693 InlineComponent branchSplit = ComponentUtils.createBranchSplit((InlineComponent)startComponent, pos);
694 PipeControlPoint branchSplitCP = branchSplit.getControlPoint();
696 PipeRun newRun = new PipeRun();
697 String n = root.getUniqueName("PipeRun");
699 root.addChild(newRun);
700 PipeControlPoint pcp = new PipeControlPoint(branchSplit,newRun);
701 branchSplitCP.children.add(pcp);
702 pcp.parent = branchSplitCP;
703 pcp.setWorldOrientation(branchSplitCP.getWorldOrientation());
704 pcp.setWorldPosition(branchSplitCP.getWorldPosition());
705 startComponent = branchSplit;
707 } catch (Exception err) {
708 ExceptionUtils.logAndShowError(err);
709 panel.useDefaultAction();
716 private void updateConstraints() {
717 detector.clearConstraints();
718 constraintPointGizmo.clearPositions();
719 if (hoverObject == null) {
720 if (constraintPointGizmo.isAttached())
721 constraintPointGizmo.deattach();
724 if (hoverObject instanceof Nozzle) {
725 Nozzle n = (Nozzle)hoverObject;
726 detector.addContraintPoint(new Point3d(n.getWorldPosition()));
727 } else if (hoverObject instanceof InlineComponent) {
728 InlineComponent c = (InlineComponent)hoverObject;
729 Point3d p1 = new Point3d();
730 Point3d p2 = new Point3d();
732 detector.addContraintPoint(p1);
733 detector.addContraintPoint(p2);
734 detector.addContraintPoint(new Point3d(c.getWorldPosition()));
735 } else if (hoverObject instanceof TurnComponent) {
736 TurnComponent n = (TurnComponent)hoverObject;
737 detector.addContraintPoint(new Point3d(n.getWorldPosition()));
739 if (detector.getConstraintPoints().size() > 0) {
740 for (Point3d p : detector.getConstraintPoints()) {
741 constraintPointGizmo.addPosition(new Vector3d(p));
743 if (constraintPointGizmo.isAttached())
744 constraintPointGizmo.deattach();
745 constraintPointGizmo.attach(panel);
750 public boolean mouseMoved(MouseEvent e) {
752 getDefaultAction().mouseMoved(e);
755 step = ((e.getModifiers() & MouseEvent.CTRL_MASK) > 0);
756 update(e.getX(), e.getY());
761 public boolean mouseDragged(MouseEvent e) {
763 getDefaultAction().mouseDragged(e);
770 private List<INode> isOverNode(int x, int y) {
771 List<INode> nodes = new ArrayList<INode>();
772 vtkProp picked[] = panel.pick2(x, y);
774 for (int i = 0; i < picked.length; i++) {
775 nodes.add(nodeMap.getNode(picked[i]));
781 INode hoverObject = null;
783 protected void updateRouting(double x, double y) {
785 //panel.getDefaultAction().update();
793 Ray ray = vtkUtil.createMouseRay(panel.getRenderer(),x, y);
794 Vector3d o = new Vector3d(ray.pos);
795 Vector3d d = ray.dir;
798 if (!updateCurrentPoint(o, d))
800 //Point3d startPoint = new Point3d();
801 double mu[] = new double[2];
807 List<INode> hover = isOverNode((int)x,(int)y);
808 if (hover.size() > 0) {
809 hoverObject = hover.get(0);
813 // System.out.println(hoverObject + " " + getLast());
814 if (hoverObject != null) {
815 if (hoverObject.equals(getLast()) ) {
817 for (int i = 1; i < hover.size(); i++) {
818 hoverObject = hover.get(i);
819 if (!getLast().equals(hoverObject)) {
828 // System.out.println(hoverObject);
829 if (hoverObject != null) {
831 if (lock == LockType.NONE) {
832 if (hoverObject instanceof Nozzle && endingToNozzle(hoverObject,o,d)) {
833 endTo = (Nozzle)hoverObject;
834 } else if (hoverObject instanceof InlineComponent && ((InlineComponent)hoverObject).isVariableLength()) {
835 endTo = (InlineComponent)hoverObject;
836 endType = endingToStraight(endTo,mu,o,d);
839 } else if (hoverObject instanceof PipelineComponent && (endPort = endingToComponent(hoverObject,o,d)) != null) {
840 endTo = (PipelineComponent)hoverObject;
845 if (hoverObject instanceof InlineComponent && ((InlineComponent)hoverObject).isVariableLength() && (endType = endingLockToStraight(hoverObject,mu, new Point3d(currentPosition))) != null) {
846 endTo = (InlineComponent)hoverObject;
847 } else if (hoverObject instanceof Nozzle && endingLockToNozzle(hoverObject)) {
848 endTo = (Nozzle)hoverObject;
849 } else if ((hoverObject instanceof PipelineComponent) && ((endPort = endingLockToComponent(hoverObject)) != null)) {
850 endTo = (PipelineComponent)hoverObject;
855 if (added.contains(endTo))
865 protected boolean updateCurrentPoint(Vector3d o, Vector3d d) {
867 Vector3d point = new Vector3d(this.previousPosition);
871 MathTools.intersectStraightStraight(point, new Vector3d(1.0,0.0,0.0), o,d, currentPosition, new Vector3d());
873 currentPosition.x = Math.round(istep * currentPosition.x) / istep;
874 BigDecimal bx = new BigDecimal(currentPosition.x);
875 bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);
876 currentPosition.x = bx.doubleValue();
880 MathTools.intersectStraightStraight(point, new Vector3d(0.0,1.0,0.0), o,d, currentPosition, new Vector3d());
882 currentPosition.y = Math.round(istep * currentPosition.y) / istep;
883 BigDecimal bx = new BigDecimal(currentPosition.y);
884 bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);
885 currentPosition.y = bx.doubleValue();
889 MathTools.intersectStraightStraight(point, new Vector3d(0.0,0.0,1.0), o,d, currentPosition, new Vector3d());
891 currentPosition.z = Math.round(istep * currentPosition.z) / istep;
892 BigDecimal bx = new BigDecimal(currentPosition.z);
893 bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);
894 currentPosition.z = bx.doubleValue();
897 MathTools.intersectStraightPlane(o, d, point, new Vector3d(0.0,0.0,1.0), currentPosition);
900 MathTools.intersectStraightPlane(o, d, point, new Vector3d(0.0,1.0,0.0), currentPosition);
903 MathTools.intersectStraightPlane(o, d, point, new Vector3d(1.0,0.0,0.0), currentPosition);
906 Vector3d normal = new Vector3d(panel.getRenderer().GetActiveCamera().GetDirectionOfProjection());
909 MathTools.intersectStraightPlane(o, d, point, normal, currentPosition);
912 MathTools.intersectStraightStraight(point, new Vector3d(direction), o,d, currentPosition, new Vector3d());
913 double dist = MathTools.distanceFromPlane(new Vector3d(currentPosition), direction, previousPosition);
915 currentPosition.set(previousPosition);
923 @SuppressWarnings("unused")
924 private Vector3d getLockDir() {
929 return new Vector3d(1,0,0);
931 return new Vector3d(0,1,0);
933 return new Vector3d(0,0,1);
939 protected void updateRoute(Vector3d o, Vector3d d) {
940 detector.clearConstraintHighlights();
941 Point3d previousPipePoint = new Point3d(previousPosition);
943 if (lock == LockType.NONE) {
944 Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint));
946 currentPosition = new Vector3d(p);
947 s += detector.getSnapString();
950 Vector3d dir = new Vector3d(currentPosition);
951 dir.sub(previousPipePoint);
952 Point3d p = detector.getPointSnap(new Vector3d(previousPipePoint), dir);
954 currentPosition = new Vector3d(p);
955 s += detector.getSnapString();
958 // System.out.println(previousPosition + " -> " + currentPosition);
959 // double dist = MathTools.distance(previousPosition, currentPosition);
960 // if (dist < pipeRun.getTurnRadius()) {
962 // Vector3d v = new Vector3d(currentPosition);
963 // v.sub(previousPosition);
964 // double vl = v.length();
965 // if (vl > MathTools.NEAR_ZERO) {
971 // v.scale(pipeRun.getTurnRadius());
972 // v.add(previousPosition);
973 // currentPosition.set(v);
976 updateCurrentPoint();
977 s += currentPosition.toString();
981 vtkTextActor infoActor;
983 private void setInfoText(String text) {
984 //System.out.println(text);
985 if (infoActor == null) {
986 infoActor = new vtkTextActor();
987 infoActor.GetTextProperty().SetColor(0.0, 0.0, 0.0);
988 infoActor.GetTextProperty().ShadowOff();
989 infoActor.GetTextProperty().ItalicOff();
990 infoActor.GetTextProperty().BoldOff();
991 infoActor.GetTextProperty().SetFontSize(18);
992 infoActor.GetTextProperty().Delete();
993 infoActor.GetProperty().SetColor(0.0, 0.0, 0.0);
994 infoActor.GetProperty().Delete();
997 infoActor.SetPosition(10,10);
998 panel.getRenderer().AddActor(infoActor);
1000 infoActor.SetInput(text);
1003 private boolean endingToNozzle(INode nozzleNode,Vector3d o, Vector3d d) {
1004 Nozzle nozzle = (Nozzle)nozzleNode;
1005 PipeControlPoint pcp =nozzle.getControlPoint();
1006 if (pcp != null && (pcp.getNext() != null ||
1007 pcp.getPrevious() != null))
1008 return false; // nozzle is already connected to pipe
1009 currentPosition = pcp.getWorldPosition();
1010 Point3d previousPipePoint = new Point3d(previousPosition);
1011 Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint));
1013 if (MathTools.distance(p, currentPosition) > NOZZLE_SNAP_DISTANCE) {
1018 updateCurrentPoint();
1020 setInfoText("Connect to nozzle " + currentPosition);
1025 private PositionType endingToStraight(INode straightNode, double mu[], Vector3d o, Vector3d d) {
1026 // if (!allowBranches) {
1027 // updateCurrentPoint();
1030 InlineComponent s = (InlineComponent)straightNode;
1032 Point3d sStart = new Point3d();
1033 Point3d sEnd = new Point3d();
1034 s.getEnds(sStart, sEnd);
1035 //detector.clearConstraintHighlights();
1037 Point3d previousPipePoint = new Point3d(previousPosition);
1038 Point3d currentPipePoint = new Point3d(currentPosition);
1040 if (lock == LockType.NONE) {
1041 Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint));
1043 currentPosition = new Vector3d(p);
1044 // snapping is detected, check if snapped point can create branch with straight
1045 PositionType t = endingLockToStraight(s, mu, currentPipePoint);
1048 // if not, we'll have to remove highlight that was added when snapped point was detected
1049 detector.clearConstraintHighlights();
1052 Vector3d sDir = new Vector3d(sEnd);
1054 MathTools.intersectStraightStraight(sStart, sDir, o, d, currentPosition, new Point3d(), mu);
1058 throw new RuntimeException("Lock shouldn't be on");
1062 updateCurrentPoint();
1064 // branch point must lie between straight's ends. If connection point is exactly
1065 // on straight end user may want to connect pipes to each other
1066 // TODO : take account sizes of inline components)
1067 return endingToStraight(mu, s, sStart, sEnd, currentPipePoint);
1070 private PositionType endingToStraight(double mu[], InlineComponent s, Point3d sStart, Point3d sEnd , Point3d currentPipePoint) {
1073 boolean connectPrev = false;
1074 boolean connectNext = false;
1075 boolean branch = false;
1079 else if (mu[0] > 0.9) {
1085 PipeControlPoint pcp = s.getControlPoint();
1086 if (pcp.getPrevious() != null)
1087 connectPrev = false;
1088 } else if (connectNext) {
1089 PipeControlPoint pcp = s.getControlPoint();
1090 if (pcp.getNext() != null)
1091 connectNext = false;
1093 Vector3d dir = s.getControlPoint().getPathLegDirection(Direction.NEXT);
1094 Vector3d currDir = getLast().getControlPoint().getPathLegDirection(Direction.NEXT);
1096 currDir.normalize();
1097 double dot = dir.dot(currDir);
1098 System.out.println(dot + " " + currDir + " " + dir);
1099 if (dot > BRANCH_DOT_PRODUCT || dot < -BRANCH_DOT_PRODUCT) {
1100 // pipes are almost in the same direction, creating a branch is not feasible.
1108 if (connectNext || connectPrev)
1109 info += "Connect pipes :";
1111 info += "Create a Branch :";
1113 setInfoText(info + currentPosition + " " + Math.max(0.0, Math.min(mu[0], 1.0)));
1115 currentPosition.set(sEnd);
1116 updateCurrentPoint();
1117 return PositionType.NEXT;
1118 } else if (connectPrev){
1119 currentPosition.set(sStart);
1120 updateCurrentPoint();
1121 return PositionType.PREVIOUS;
1122 } else if (branch && allowBranches) {
1123 return PositionType.SPLIT;
1125 currentPosition.set(currentPipePoint);
1126 updateCurrentPoint();
1131 private PipeControlPoint endingToComponent(INode componentNode, Vector3d o, Vector3d d) {
1132 PipelineComponent component = (PipelineComponent)componentNode;
1133 PipeControlPoint pcp = component.getControlPoint();
1134 PipeControlPoint connect = null;
1135 if (component instanceof EndComponent) {
1136 if (pcp.getNext() != null || pcp.getPrevious() != null)
1139 } else if (component instanceof TurnComponent) {
1140 if (pcp.getNext() == null || pcp.getPrevious() == null)
1144 } else if (component instanceof InlineComponent) {
1145 // TODO : scan all empty pcps of the component and select closest one.
1146 if (pcp.getNext() == null || pcp.getPrevious() == null)
1151 if (connect != null) {
1152 currentPosition.set(connect.getWorldPosition());
1153 updateCurrentPoint();
1154 setInfoText("Connect to " + component.getName());
1160 private PositionType endingLockToStraight(INode straightNode, double mu[], Point3d currentPipePoint) {
1161 // if (!allowBranches) {
1162 // updateCurrentPoint();
1165 InlineComponent s = (InlineComponent)straightNode;
1166 Point3d sStart = new Point3d();
1167 Point3d sEnd = new Point3d();
1168 s.getControlPoint().getInlineControlPointEnds(sStart, sEnd);
1169 Vector3d sDir = new Vector3d(sEnd);
1171 Vector3d dir = new Vector3d(currentPosition);
1172 Point3d prev = new Point3d(previousPosition);
1174 // intersection point in pipe where branch would be inserted to
1175 Vector3d branchPoint = new Vector3d();
1176 // intersection point in straight pipe that is currently routed
1177 Vector3d routePoint = new Vector3d();
1178 MathTools.intersectStraightStraight(sStart, sDir, new Vector3d(prev), dir, branchPoint, routePoint, mu);
1179 routePoint.sub(branchPoint);
1180 // startPoint of branch must be between pipe ends
1181 // TODO : take account sizes of elbows (or other components)
1182 // branch point must be between pipe ends and intersection points must be quite close to each other
1184 if (routePoint.lengthSquared() > BRANCH_SNAP_DISTANCE)
1187 return endingToStraight(mu, s, sStart, sEnd, currentPipePoint);
1189 // if (mu[0] > 0.0 && mu[0] < 1.0 && routePoint.lengthSquared() < BRANCH_SNAP_DISTANCE) {
1190 // currentPosition.set(branchPoint);
1192 // updateCurrentPoint();
1194 // setInfoText("Create a branch (l) :" + currentPosition + " " + Math.max(0.0, Math.min(mu[0], 1.0)) + " " + routePoint.lengthSquared());
1195 // return PositionType.SPLIT;
1200 private boolean endingLockToNozzle(INode nozzleNode) {
1201 Nozzle nozzle = (Nozzle)nozzleNode;
1202 Vector3d dir = new Vector3d(currentPosition);
1203 Point3d prev = new Point3d(previousPosition);
1205 Vector3d nozzleLoc = nozzle.getWorldPosition();
1206 double u[] = new double[1];
1207 Vector3d closest = MathTools.closestPointOnStraight(new Point3d(nozzleLoc), new Point3d(prev), new Vector3d(dir), u);
1208 double dist = MathTools.distanceSquared(nozzleLoc,closest);
1209 if (dist < BRANCH_SNAP_DISTANCE) {
1210 // FIXME : directions should be checked (insert an elbow)
1211 currentPosition.set(nozzleLoc);
1212 updateCurrentPoint();
1213 setInfoText("Connect to nozzle (l) :" + currentPosition);
1216 //System.out.println(u[0]);
1220 private PipeControlPoint endingLockToComponent(INode componentNode) {
1221 // we'll must scan all free pcp's and their direction to accept the connection.
1225 protected void addTurn() throws Exception{
1226 InlineComponent previous = (InlineComponent)getLast();
1227 PipeControlPoint previousCP = previous.getControlPoint();
1228 TurnComponent turn = ComponentUtils.createTurn(root);
1229 PipeControlPoint turnCP = turn.getControlPoint();
1230 turn.setName(pipeRun.getUniqueName("Elbow"));
1231 pipeRun.addChild(turn);
1233 turnCP.setDeletable(false); // mark turnCP nonDeletable so that PipingRules won't delete it immediately.
1235 previousCP.setNext(turnCP);
1236 turnCP.setPrevious(previousCP);
1238 previousCP.setPrevious(turnCP);
1239 turnCP.setNext(previousCP);
1242 turnCP.setWorldPosition(currentPosition);
1243 turnCP.setTurnAngle(0.0);
1244 turnCP.setLength(0.0);
1248 protected void addStraight() throws Exception{
1249 TurnComponent turn = (TurnComponent)getLast();
1250 PipeControlPoint turnCP = turn.getControlPoint();
1252 InlineComponent straight = ComponentUtils.createStraight(root);
1254 PipeControlPoint straightCP = straight.getControlPoint();
1255 straight.setName(pipeRun.getUniqueName("Pipe"));
1258 pipeRun.addChild(straight);
1260 added.add(straight);
1265 turnCP.setNext(straightCP);
1266 straightCP.setPrevious(turnCP);
1268 turnCP.setPrevious(straightCP);
1269 straightCP.setNext(turnCP);
1272 turnCP.setWorldPosition(currentPosition);
1273 turnCP.setTurnAngle(0.0);
1274 turnCP.setLength(0.0);
1275 straightCP.setWorldPosition(currentPosition);
1276 straightCP.setLength(0.0);
1280 protected void addPoint() throws Exception {
1283 setPreviousPosition(currentPosition);
1284 updateCurrentPoint();
1291 * Updates tool graphics for current point
1293 protected void updateCurrentPoint() {
1294 InlineComponent straight = (InlineComponent)added.get(added.size()-1);
1295 // TODO: the inline length is from previous update step.
1298 l = straight.getPrevious().getControlPoint().getInlineLength();
1300 l = straight.getNext().getControlPoint().getInlineLength();
1301 Vector3d v = new Vector3d();
1302 v.sub(currentPosition, previousPosition);
1303 double length = v.length();
1304 if (length > MathTools.NEAR_ZERO) {
1305 v.scale(1.0/length);
1306 v.scale(0.5*(length+l));
1307 v.add(previousPosition);
1308 straight.getControlPoint().setWorldPosition(v);
1309 straight.getControlPoint().setLength(length);
1312 PipingRules.positionUpdate(straight.getControlPoint(),false);
1313 } catch (Exception e) {
1314 // TODO Auto-generated catch block
1315 e.printStackTrace();
1319 private PipelineComponent getLast() {
1320 if (added.size() == 0)
1321 return startComponent;
1322 return added.get(added.size()-1);
1327 * Removes last point from pipeline
1329 public void removePoint() {
1330 if (added.size() < 3)
1332 InlineComponent straight = (InlineComponent)added.remove(added.size()-1);
1333 TurnComponent turn = (TurnComponent)added.remove(added.size()-1);
1334 straight.getControlPoint().remove();
1335 turn.getControlPoint().remove();
1336 if (added.size() > 1) {
1337 setPreviousPosition(added.get(added.size()-2).getWorldPosition());
1339 setPreviousPosition(startComponent.getWorldPosition());
1340 if (direction != null)
1341 setLockType(LockType.CUSTOM, true);
1346 protected void endPiping() throws Exception {
1347 state = ToolState.NOT_ACTIVE;
1349 if (endTo != null) {
1350 if (endType == PositionType.NEXT || endType == PositionType.PREVIOUS && endTo instanceof InlineComponent) {
1351 Vector3d dir = endTo.getControlPoint().getPathLegDirection(Direction.NEXT);
1352 Vector3d currDir = getLast().getControlPoint().getPathLegDirection(Direction.NEXT);
1354 currDir.normalize();
1355 double dot = dir.dot(currDir);
1356 System.out.println(dot + " " + currDir + " " + dir);
1357 if (dot < ALIGN_DOT_PRODUCT && dot> -ALIGN_DOT_PRODUCT) {
1362 ComponentUtils.connect(getLast(), endTo, endType, currentPosition);
1364 panel.useDefaultAction();