1 package org.simantics.plant3d.actions;
3 import java.awt.event.KeyEvent;
4 import java.awt.event.MouseEvent;
5 import java.awt.event.MouseWheelEvent;
6 import java.math.BigDecimal;
7 import java.util.ArrayList;
8 import java.util.HashSet;
12 import javax.vecmath.Point3d;
13 import javax.vecmath.Tuple3d;
14 import javax.vecmath.Vector3d;
16 import org.simantics.g3d.math.MathTools;
17 import org.simantics.g3d.math.Ray;
18 import org.simantics.g3d.scenegraph.NodeMap;
19 import org.simantics.g3d.scenegraph.base.INode;
20 import org.simantics.g3d.tools.ConstraintDetector;
21 import org.simantics.g3d.tools.DummyConstraintDetector;
22 import org.simantics.g3d.vtk.gizmo.TranslateAxisGizmo;
23 import org.simantics.g3d.vtk.swt.InteractiveVtkComposite;
24 import org.simantics.g3d.vtk.swt.vtkSwtAction;
25 import org.simantics.g3d.vtk.utils.vtkUtil;
26 import org.simantics.plant3d.Activator;
27 import org.simantics.plant3d.gizmo.SplitPointSelectionGizmo;
28 import org.simantics.plant3d.gizmo.TerminalSelectionGizmo;
29 import org.simantics.plant3d.ontology.Plant3D;
30 import org.simantics.plant3d.scenegraph.EndComponent;
31 import org.simantics.plant3d.scenegraph.InlineComponent;
32 import org.simantics.plant3d.scenegraph.Nozzle;
33 import org.simantics.plant3d.scenegraph.P3DRootNode;
34 import org.simantics.plant3d.scenegraph.PipeRun;
35 import org.simantics.plant3d.scenegraph.PipelineComponent;
36 import org.simantics.plant3d.scenegraph.TurnComponent;
37 import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint;
38 import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint.Direction;
39 import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint.PositionType;
40 import org.simantics.plant3d.scenegraph.controlpoint.PipingRules;
41 import org.simantics.plant3d.utils.ComponentUtils;
42 import org.simantics.utils.threads.ThreadUtils;
43 import org.simantics.utils.ui.ExceptionUtils;
46 import vtk.vtkTextActor;
48 public class RoutePipeAction extends vtkSwtAction {
50 X, Y, Z, XY, YZ, XZ, NONE, CUSTOM
53 LockType lock = LockType.NONE;
54 private double BRANCH_SNAP_DISTANCE = 0.05;
55 private double NOZZLE_SNAP_DISTANCE = 0.05;
57 private double istep = 10.0;
58 private int decimals = 2;
60 private P3DRootNode root;
61 private PipelineComponent startComponent;
62 private PipeRun pipeRun;
64 private TranslateAxisGizmo translateAxisGizmo = new TranslateAxisGizmo();
65 private SplitPointSelectionGizmo splitPointSelectionGizmo;
66 private TerminalSelectionGizmo terminalSelectionGizmo;
67 private NodeMap<vtkProp,INode> nodeMap;
69 private enum ToolState{NOT_ACTIVE, INITIALIZING, SELECTING_POSITION, SELECTING_SPLIT, ROUTING};
70 private ToolState state = ToolState.NOT_ACTIVE;
72 private ConstraintDetector detector = new DummyConstraintDetector();
74 private boolean useDefault = false;
75 private Vector3d direction = null;
76 private Vector3d previousPosition = null;
77 private Vector3d currentPosition = null;
81 PipelineComponent endTo = null;
82 PositionType endType = null;
83 PipeControlPoint endPort = null;
85 boolean reversed = false;
87 private Set<PositionType> allowed = new HashSet<PositionType>();
90 public RoutePipeAction(InteractiveVtkComposite panel, P3DRootNode root) {
93 setText("Route Pipe");
94 setImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/Straight.png"));
95 nodeMap = root.getNodeMap();
96 splitPointSelectionGizmo = new SplitPointSelectionGizmo(panel);
97 terminalSelectionGizmo = new TerminalSelectionGizmo(panel);
100 public void setComponent(PipelineComponent component) {
101 this.startComponent = component;
103 if (this.startComponent.getNext() == null)
104 allowed.add(PositionType.NEXT);
105 if (this.startComponent.getPrevious() == null && !(this.startComponent instanceof Nozzle))
106 allowed.add(PositionType.PREVIOUS);
107 if (this.startComponent instanceof InlineComponent && !this.startComponent.getControlPoint().isFixed())
108 allowed.add(PositionType.SPLIT);
109 setEnabled(allowed.size() > 0);
112 public void deattach() {
114 startComponent = null;
115 nodeMap.commit("Route pipe");
121 public void attach() {
122 if (startComponent == null)
126 ThreadUtils.asyncExec(panel.getThreadQueue(), new Runnable() {
131 } catch (Exception e) {
133 ExceptionUtils.logAndShowError(e);
141 // private void attachUI() {
142 // //panel.setCursor(activeCursor);
143 // translateAxisGizmo.attach(panel.GetRenderer());
146 private void deattachUI() {
147 //panel.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
149 if (translateAxisGizmo.isAttached())
150 translateAxisGizmo.deattach();
151 if (splitPointSelectionGizmo.isAttached())
152 splitPointSelectionGizmo.deattach();
153 if (terminalSelectionGizmo.isAttached())
154 terminalSelectionGizmo.deattach();
155 if (infoActor != null) {
156 panel.getRenderer().RemoveActor(infoActor);
163 private List<PipelineComponent> added = new ArrayList<PipelineComponent>();
166 public boolean keyPressed(KeyEvent e) {
167 if (e.getKeyCode() == KeyEvent.VK_ESCAPE)
168 panel.useDefaultAction();
169 if (lock != LockType.CUSTOM) {
170 if ((e.getModifiersEx() & KeyEvent.SHIFT_DOWN_MASK) > 0) {
171 if (e.getKeyCode() == KeyEvent.VK_X) {
172 if (lock != LockType.XY && lock != LockType.XZ) {
173 setLockType(LockType.XY, false);
174 } else if (lock == LockType.XY) {
175 setLockType(LockType.XZ, false);
177 setLockType(LockType.NONE, false);
180 if (e.getKeyCode() == KeyEvent.VK_Y) {
181 if (lock != LockType.XY && lock != LockType.YZ) {
182 setLockType(LockType.XY, false);
183 } else if (lock == LockType.XY) {
184 setLockType(LockType.YZ, false);
186 setLockType(LockType.NONE, false);
189 if (e.getKeyCode() == KeyEvent.VK_Z) {
190 if (lock != LockType.XZ && lock != LockType.YZ) {
191 setLockType(LockType.XZ, false);
192 } else if (lock == LockType.XZ) {
193 setLockType(LockType.YZ, false);
195 setLockType(LockType.NONE, false);
199 if (e.getKeyCode() == KeyEvent.VK_X) {
200 if (lock != LockType.X)
201 setLockType(LockType.X,false);
203 setLockType(LockType.NONE,false);
205 if (e.getKeyCode() == KeyEvent.VK_Y) {
206 if (lock != LockType.Y)
207 setLockType(LockType.Y,false);
209 setLockType(LockType.NONE, false);
211 if (e.getKeyCode() == KeyEvent.VK_Z) {
212 if (lock != LockType.Z)
213 setLockType(LockType.Z, false);
215 setLockType(LockType.NONE, false);
219 if (e.getKeyCode() == KeyEvent.VK_C) {
220 useDefault = !useDefault;
221 System.out.println("UseDefault " + useDefault);
232 private void update() {
235 private void update(double x, double y) {
238 return; // TODO : throw Exception?
241 case SELECTING_POSITION:
243 case SELECTING_SPLIT:
252 boolean startRemovable = false;
254 private void activate() throws Exception {
255 state = ToolState.INITIALIZING;
258 if (allowed.size() == 1) {
259 pipeRun = startComponent.getPipeRun();
260 PipeControlPoint start = startComponent.getControlPoint();
261 boolean requiresBranching = false;
262 if (start.getNext() == null)
264 else if (start.getPrevious() == null) {
267 requiresBranching = true;
270 if (requiresBranching) {
271 activateSplit(start);
273 activateNextPrev(start);
275 } else if (allowed.size() == 0) {
276 panel.useDefaultAction();
277 state = ToolState.NOT_ACTIVE;
280 terminalSelectionGizmo.setComponent(startComponent, allowed);
281 terminalSelectionGizmo.attach(panel);
282 state = ToolState.SELECTING_POSITION;
290 private void activateNextPrev(PipeControlPoint start) throws Exception{
291 if (!reversed && start.isDualInline())
292 start = start.getSubPoint().get(0);
293 else if (reversed && start.isDualSub())
294 start = start.parent;
296 pipeRun = start.getPipeRun();
297 setPreviousPosition(start.getWorldPosition());
299 boolean startWithTurn = false;
300 if (startComponent instanceof Nozzle) {
301 direction = startComponent.getControlPoint().getDirectedControlPointDirection();
302 lock = LockType.CUSTOM;
303 } else if (startComponent instanceof PipelineComponent){
304 if (startComponent instanceof InlineComponent) {
305 direction = startComponent.getControlPoint().getPathLegDirection(reversed ? Direction.PREVIOUS : Direction.NEXT);
306 lock = LockType.CUSTOM;
307 if (((InlineComponent) startComponent).isVariableLength()) {
308 startWithTurn = true;
310 lock = LockType.NONE;
312 Vector3d v = new Vector3d();
314 start.getControlPointEnds(v, previousPosition);
316 start.getControlPointEnds(previousPosition,v);
318 } else if (startComponent instanceof TurnComponent) {
319 if (start.isFixed()) {
320 direction = startComponent.getControlPoint().getPathLegDirection(reversed ? Direction.PREVIOUS : Direction.NEXT);
321 lock = LockType.CUSTOM;
324 lock = LockType.NONE;
326 } else if (startComponent instanceof EndComponent) {
327 throw new Exception("Not supported");
331 throw new Exception("Not supported");
333 currentPosition = new Vector3d(previousPosition);
334 state = ToolState.ROUTING;
335 if (direction != null) {
336 direction.normalize();
339 startRemovable = start.isDeletable();
340 start.setDeletable(false);
345 if (direction != null)
346 currentPosition.add(direction);
347 InlineComponent straight = ComponentUtils.createStraight(root);
348 PipeControlPoint straightCP = straight.getControlPoint();
349 straight.setName(pipeRun.getUniqueName("Pipe"));
350 pipeRun.addChild(straight);
354 start.setNext(straightCP);
355 straightCP.setPrevious(start);
357 start.setPrevious(straightCP);
358 straightCP.setNext(start);
361 translateAxisGizmo.attach(panel);
362 setPreviousPosition(previousPosition);
363 updateCurrentPoint();
366 private void setPreviousPosition(Vector3d v) {
367 previousPosition = new Vector3d(v);
368 if (translateAxisGizmo.isAttached())
369 translateAxisGizmo.setPosition(previousPosition);
372 private void activateBranch(PipeControlPoint start) throws Exception{
373 pipeRun = start.getPipeRun();
374 setPreviousPosition(start.getWorldPosition());
377 lock = LockType.NONE;
379 currentPosition = new Vector3d(previousPosition);
380 state = ToolState.ROUTING;
381 if (direction != null) {
382 direction.normalize();
385 startRemovable = start.isDeletable();
386 start.setDeletable(false);
389 if (direction != null)
390 currentPosition.add(direction);
391 InlineComponent straight = ComponentUtils.createStraight(root);
392 PipeControlPoint straightCP = straight.getControlPoint();
393 straight.setName(pipeRun.getUniqueName("Pipe"));
394 pipeRun.addChild(straight);
398 start.setNext(straightCP);
399 straightCP.setPrevious(start);
402 start.setPrevious(straightCP);
403 straightCP.setNext(start);
407 translateAxisGizmo.attach(panel);
408 setPreviousPosition(previousPosition);
409 updateCurrentPoint();
412 private void activateSplit(PipeControlPoint start) throws Exception{
413 Point3d p1 = new Point3d();
414 Point3d p2 = new Point3d();
415 start.getInlineControlPointEnds(p1, p2);
416 splitPointSelectionGizmo.setSplit(p1, p2);
417 splitPointSelectionGizmo.attach(panel);
418 state = ToolState.SELECTING_SPLIT;
420 public void deactivate() {
421 for (PipelineComponent component : added) {
422 component.getControlPoint().setDeletable(true);
426 startComponent.getControlPoint().setDeletable(startRemovable);
430 setLockType(LockType.NONE, true);
431 startComponent = null;
437 currentPosition = null;
438 previousPosition = null;
439 startRemovable = false;
440 detector.clearConstraintHighlights();
441 state = ToolState.NOT_ACTIVE;
447 private void setLockType(LockType type, boolean force) {
448 if (force || lock != LockType.CUSTOM) {
454 translateAxisGizmo.setType(6);
457 translateAxisGizmo.setType(0);
460 translateAxisGizmo.setType(1);
463 translateAxisGizmo.setType(2);
466 translateAxisGizmo.setType(3);
469 translateAxisGizmo.setType(4);
472 translateAxisGizmo.setType(5);
480 public boolean mousePressed(MouseEvent e) {
482 getDefaultAction().mousePressed(e);
488 public boolean mouseReleased(MouseEvent e) {
490 getDefaultAction().mouseReleased(e);
496 public boolean mouseWheelMoved(MouseWheelEvent e) {
498 getDefaultAction().mouseWheelMoved(e);
504 public boolean mouseClicked(MouseEvent e) {
506 getDefaultAction().mouseClicked(e);
509 if (state == ToolState.ROUTING) {
511 if (e.getClickCount() == 1) {
512 if (e.getButton() == MouseEvent.BUTTON1) {
513 if (this.added.size() > 0) {
515 setLockType(LockType.NONE,true);
523 throw new RuntimeException("kjf");
524 // // user was selecting position of branch
525 // lastPoint.set(startPoint);
526 // controlPoints.add(new Point3d(startPoint));
527 // if (selectionLine != null)
528 // selectionLine.removeFromParent();
529 // selectionLine = null;
531 } else if (e.getButton() ==MouseEvent.BUTTON2){
532 // detector.updateConstraintReference();
533 } else if (e.getButton() == MouseEvent.BUTTON3){
537 } catch(Exception err) {
538 err.printStackTrace();
540 } else if (state == ToolState.SELECTING_POSITION) {
541 if (e.getClickCount() == 1 && e.getButton() == MouseEvent.BUTTON1) {
542 int type = panel.getPickType();
543 //panel.setPickType(0);
544 panel.setPickType(5);
545 vtkProp[] picked = panel.pick(e.getX(), e.getY());
546 panel.setPickType(type);
547 PositionType position = terminalSelectionGizmo.getPickedPosition(picked);
548 if (position != null) {
549 terminalSelectionGizmo.deattach();
551 if (position == PositionType.SPLIT) {
552 activateSplit(startComponent.getControlPoint());
553 } else if (position == PositionType.NEXT || position == PositionType.PREVIOUS) {
554 reversed = position == PositionType.PREVIOUS;
555 activateNextPrev(startComponent.getControlPoint());
557 panel.useDefaultAction();
559 } catch (Exception err) {
560 ExceptionUtils.logAndShowError(err);
561 panel.useDefaultAction();
565 } else if (state == ToolState.SELECTING_SPLIT) {
566 if (e.getClickCount() == 1 && e.getButton() == MouseEvent.BUTTON1) {
567 Tuple3d t = splitPointSelectionGizmo.getSplitPoint();
568 splitPointSelectionGizmo.deattach();
570 panel.useDefaultAction();
574 Vector3d pos = new Vector3d(t);
575 InlineComponent branchSplit = ComponentUtils.createBranchSplit((InlineComponent)startComponent, pos);
576 PipeControlPoint branchSplitCP = branchSplit.getControlPoint();
578 PipeRun newRun = new PipeRun();
579 String n = root.getUniqueName("PipeRun");
581 root.addChild(newRun);
582 PipeControlPoint pcp = new PipeControlPoint(branchSplit,newRun);
583 branchSplitCP.children.add(pcp);
584 pcp.parent = branchSplitCP;
585 pcp.setWorldOrientation(branchSplitCP.getWorldOrientation());
586 pcp.setWorldPosition(branchSplitCP.getWorldPosition());
587 startComponent = branchSplit;
589 } catch (Exception err) {
590 ExceptionUtils.logAndShowError(err);
591 panel.useDefaultAction();
599 public boolean mouseMoved(MouseEvent e) {
601 getDefaultAction().mouseMoved(e);
604 step = ((e.getModifiers() & MouseEvent.CTRL_MASK) > 0);
605 update(e.getX(), e.getY());
610 public boolean mouseDragged(MouseEvent e) {
612 getDefaultAction().mouseDragged(e);
619 private List<INode> isOverNode(int x, int y) {
620 List<INode> nodes = new ArrayList<INode>();
621 vtkProp picked[] = panel.pick2(x, y);
623 for (int i = 0; i < picked.length; i++) {
624 nodes.add(nodeMap.getNode(picked[i]));
632 private void updateRouting(double x, double y) {
633 // if(input.keyPressed(KeyEvent.VK_ESCAPE)) {
634 // controlPoints.clear();
638 // if (input.keyPressed(KeyEvent.VK_C)) {
639 // useCamera = !useCamera;
640 // cameraAction.setChecked(useCamera);
643 //panel.getDefaultAction().update();
651 Ray ray = vtkUtil.createMouseRay(panel.getRenderer(),x, y);
652 Vector3d o = new Vector3d(ray.pos);
653 Vector3d d = ray.dir;
656 if (!updateCurrentPoint(o, d))
658 //Point3d startPoint = new Point3d();
659 double mu[] = new double[2];
663 INode hoverObject = null;
665 List<INode> hover = isOverNode((int)x,(int)y);
666 if (hover.size() > 0) {
667 hoverObject = hover.get(0);
669 // System.out.println(hoverObject + " " + getLast());
670 if (hoverObject != null) {
671 if (hoverObject.equals(getLast()) ) {
673 for (int i = 1; i < hover.size(); i++) {
674 hoverObject = hover.get(i);
675 if (!getLast().equals(hoverObject)) {
684 // System.out.println(hoverObject);
685 if (hoverObject != null) {
687 if (lock == LockType.NONE) {
688 if (hoverObject instanceof Nozzle && endingToNozzle(hoverObject,o,d)) {
689 endTo = (Nozzle)hoverObject;
690 } else if (hoverObject instanceof InlineComponent && ((InlineComponent)hoverObject).isVariableLength()) {
691 endTo = (InlineComponent)hoverObject;
692 endType = endingToStraight(endTo,mu,o,d);
693 } else if (hoverObject instanceof PipelineComponent && (endPort = endingToComponent(hoverObject,o,d)) != null) {
694 endTo = (PipelineComponent)hoverObject;
699 if (hoverObject instanceof InlineComponent && ((InlineComponent)hoverObject).isVariableLength() && (endType = endingLockToStraight(hoverObject,mu)) != null) {
700 endTo = (InlineComponent)hoverObject;
701 } else if (hoverObject instanceof Nozzle && endingLockToNozzle(hoverObject)) {
702 endTo = (Nozzle)hoverObject;
703 } else if ((hoverObject instanceof PipelineComponent) && ((endPort = endingLockToComponent(hoverObject)) != null)) {
704 endTo = (PipelineComponent)hoverObject;
709 if (added.contains(endTo))
719 private boolean updateCurrentPoint(Vector3d o, Vector3d d) {
721 Vector3d point = new Vector3d(this.previousPosition);
725 MathTools.intersectStraightStraight(point, new Vector3d(1.0,0.0,0.0), o,d, currentPosition, new Vector3d());
727 currentPosition.x = Math.round(istep * currentPosition.x) / istep;
728 BigDecimal bx = new BigDecimal(currentPosition.x);
729 bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);
730 currentPosition.x = bx.doubleValue();
734 MathTools.intersectStraightStraight(point, new Vector3d(0.0,1.0,0.0), o,d, currentPosition, new Vector3d());
736 currentPosition.y = Math.round(istep * currentPosition.y) / istep;
737 BigDecimal bx = new BigDecimal(currentPosition.y);
738 bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);
739 currentPosition.y = bx.doubleValue();
743 MathTools.intersectStraightStraight(point, new Vector3d(0.0,0.0,1.0), o,d, currentPosition, new Vector3d());
745 currentPosition.z = Math.round(istep * currentPosition.z) / istep;
746 BigDecimal bx = new BigDecimal(currentPosition.z);
747 bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);
748 currentPosition.z = bx.doubleValue();
751 MathTools.intersectStraightPlane(o, d, point, new Vector3d(0.0,0.0,1.0), currentPosition);
754 MathTools.intersectStraightPlane(o, d, point, new Vector3d(0.0,1.0,0.0), currentPosition);
757 MathTools.intersectStraightPlane(o, d, point, new Vector3d(1.0,0.0,0.0), currentPosition);
760 Vector3d normal = new Vector3d(panel.getRenderer().GetActiveCamera().GetDirectionOfProjection());
763 MathTools.intersectStraightPlane(o, d, point, normal, currentPosition);
766 MathTools.intersectStraightStraight(point, new Vector3d(direction), o,d, currentPosition, new Vector3d());
767 double dist = MathTools.distanceFromPlane(new Vector3d(currentPosition), direction, previousPosition);
769 currentPosition.set(previousPosition);
777 private Vector3d getLockDir() {
782 return new Vector3d(1,0,0);
784 return new Vector3d(0,1,0);
786 return new Vector3d(0,0,1);
791 private void updateRoute(Vector3d o, Vector3d d) {
792 detector.clearConstraintHighlights();
793 Point3d previousPipePoint = new Point3d(previousPosition);
795 if (lock == LockType.NONE) {
796 Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint));
798 currentPosition = new Vector3d(p);
799 s += detector.getSnapString();
802 Vector3d dir = new Vector3d(currentPosition);
803 dir.sub(previousPipePoint);
804 Point3d p = detector.getPointSnap(new Vector3d(previousPipePoint), dir);
806 currentPosition = new Vector3d(p);
807 s += detector.getSnapString();
810 // System.out.println(previousPosition + " -> " + currentPosition);
811 // double dist = MathTools.distance(previousPosition, currentPosition);
812 // if (dist < pipeRun.getTurnRadius()) {
814 // Vector3d v = new Vector3d(currentPosition);
815 // v.sub(previousPosition);
816 // double vl = v.length();
817 // if (vl > MathTools.NEAR_ZERO) {
823 // v.scale(pipeRun.getTurnRadius());
824 // v.add(previousPosition);
825 // currentPosition.set(v);
828 updateCurrentPoint();
829 s += currentPosition.toString();
833 vtkTextActor infoActor;
835 private void setInfoText(String text) {
836 //System.out.println(text);
837 if (infoActor == null) {
838 infoActor = new vtkTextActor();
839 infoActor.GetTextProperty().SetColor(0.0, 0.0, 0.0);
840 infoActor.GetTextProperty().ShadowOff();
841 infoActor.GetTextProperty().ItalicOff();
842 infoActor.GetTextProperty().BoldOff();
843 infoActor.GetTextProperty().SetFontSize(18);
844 infoActor.GetTextProperty().Delete();
845 infoActor.GetProperty().SetColor(0.0, 0.0, 0.0);
846 infoActor.GetProperty().Delete();
849 infoActor.SetPosition(10,10);
850 panel.getRenderer().AddActor(infoActor);
852 infoActor.SetInput(text);
855 private boolean endingToNozzle(INode nozzleNode,Vector3d o, Vector3d d) {
856 Nozzle nozzle = (Nozzle)nozzleNode;
857 PipeControlPoint pcp =nozzle.getControlPoint();
858 if (pcp != null && (pcp.getNext() != null ||
859 pcp.getPrevious() != null))
860 return false; // nozzle is already connected to pipe
861 currentPosition = pcp.getWorldPosition();
862 Point3d previousPipePoint = new Point3d(previousPosition);
863 Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint));
865 if (MathTools.distance(p, currentPosition) > NOZZLE_SNAP_DISTANCE) {
870 updateCurrentPoint();
872 setInfoText("Connect to nozzle " + currentPosition);
877 private PositionType endingToStraight(INode straightNode, double mu[], Vector3d o, Vector3d d) {
878 InlineComponent s = (InlineComponent)straightNode;
880 Point3d sStart = new Point3d();
881 Point3d sEnd = new Point3d();
882 s.getEnds(sStart, sEnd);
883 //detector.clearConstraintHighlights();
885 Point3d previousPipePoint = new Point3d(previousPosition);
887 if (lock == LockType.NONE) {
888 Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint));
890 currentPosition = new Vector3d(p);
891 // snapping is detected, check if snapped point can create branch with straight
892 PositionType t = endingLockToStraight(s, mu);
895 // if not, we'll have to remove highlight that was added when snapped point was detected
896 detector.clearConstraintHighlights();
900 Vector3d sDir = new Vector3d(sEnd);
902 MathTools.intersectStraightStraight(sStart, sDir, o, d, currentPosition, new Point3d(), mu);
906 throw new RuntimeException("Lock shouldn't be on");
910 updateCurrentPoint();
912 // branch point must lie between straight's ends. If connection point is exactly
913 // on straight end user may want to connect pipes to each other
914 // TODO : take account sizes of inline components)
915 // TODO : actually make connection if its detected
916 boolean connectPrev = false;
917 boolean connectNext = false;
920 currentPosition.set(sStart);
923 else if (mu[0] > 1.0) {
924 currentPosition.set(sEnd);
927 boolean connect = false;
929 PipeControlPoint pcp = s.getControlPoint();
930 if (pcp.getPrevious() == null)
932 } else if (connectNext) {
933 PipeControlPoint pcp = s.getControlPoint();
934 if (pcp.getNext() == null)
938 updateCurrentPoint();
941 info += "Connect pipes :";
943 info += "Make Branch :";
945 setInfoText(info + currentPosition + " " + Math.max(0.0, Math.min(mu[0], 1.0)));
948 return PositionType.NEXT;
950 return PositionType.PREVIOUS;
954 return PositionType.SPLIT;
958 private PipeControlPoint endingToComponent(INode componentNode, Vector3d o, Vector3d d) {
959 PipelineComponent component = (PipelineComponent)componentNode;
960 PipeControlPoint pcp = component.getControlPoint();
961 if (component instanceof EndComponent) {
962 if (pcp.getNext() != null || pcp.getPrevious() != null)
965 } else if (component instanceof TurnComponent) {
966 if (pcp.getNext() == null || pcp.getPrevious() == null)
969 } else if (component instanceof InlineComponent) {
970 // TODO : scan all empty pcps of the component and select closest one.
971 if (pcp.getNext() == null || pcp.getPrevious() == null)
979 private PositionType endingLockToStraight(INode straightNode, double mu[]) {
980 InlineComponent s = (InlineComponent)straightNode;
981 Point3d sStart = new Point3d();
982 Point3d sEnd = new Point3d();
983 s.getControlPoint().getInlineControlPointEnds(sStart, sEnd);
984 Vector3d sDir = new Vector3d(sEnd);
986 Vector3d dir = new Vector3d(currentPosition);
987 Point3d prev = new Point3d(previousPosition);
989 // intersection point in pipe where branch would be inserted to
990 Vector3d branchPoint = new Vector3d();
991 // intersection point in straight pipe that is currently routed
992 Vector3d routePoint = new Vector3d();
993 MathTools.intersectStraightStraight(sStart, sDir, new Vector3d(prev), dir, branchPoint, routePoint, mu);
994 routePoint.sub(branchPoint);
995 // startPoint of branch must be between pipe ends
996 // TODO : take account sizes of elbows (or other components)
997 // branch point must be between pipe ends and intersection points must be quite close to each other
998 if (mu[0] > 0.0 && mu[0] < 1.0 && routePoint.lengthSquared() < BRANCH_SNAP_DISTANCE) {
999 currentPosition.set(branchPoint);
1001 updateCurrentPoint();
1003 setInfoText("Make branch (l) :" + currentPosition + " " + Math.max(0.0, Math.min(mu[0], 1.0)) + " " + routePoint.lengthSquared());
1004 return PositionType.SPLIT;
1009 private boolean endingLockToNozzle(INode nozzleNode) {
1010 Nozzle nozzle = (Nozzle)nozzleNode;
1011 Vector3d dir = new Vector3d(currentPosition);
1012 Point3d prev = new Point3d(previousPosition);
1014 Vector3d nozzleLoc = nozzle.getWorldPosition();
1015 double u[] = new double[1];
1016 Vector3d closest = MathTools.closestPointOnStraight(new Point3d(nozzleLoc), new Point3d(prev), new Vector3d(dir), u);
1017 double dist = MathTools.distanceSquared(nozzleLoc,closest);
1018 if (dist < BRANCH_SNAP_DISTANCE) {
1019 // FIXME : directions should be checked (insert an elbow)
1020 currentPosition.set(nozzleLoc);
1021 updateCurrentPoint();
1022 setInfoText("Connect to nozzle (l) :" + currentPosition);
1025 //System.out.println(u[0]);
1029 private PipeControlPoint endingLockToComponent(INode componentNode) {
1030 // we'll must scan all free pcp's and their direction to accept the connection.
1034 private void addPoint() throws Exception {
1035 InlineComponent previous = (InlineComponent)getLast();
1036 PipeControlPoint previousCP = previous.getControlPoint();
1037 TurnComponent turn = ComponentUtils.createTurn(root);
1038 InlineComponent straight = ComponentUtils.createStraight(root);
1039 PipeControlPoint turnCP = turn.getControlPoint();
1040 PipeControlPoint straightCP = straight.getControlPoint();
1041 straight.setName(pipeRun.getUniqueName("Pipe"));
1042 turn.setName(pipeRun.getUniqueName("Elbow"));
1043 pipeRun.addChild(turn);
1044 pipeRun.addChild(straight);
1046 added.add(straight);
1048 turnCP.setDeletable(false); // mark turnCP nonDeletable so that PipingRules won't delete it immediately.
1051 previousCP.setNext(turnCP);
1052 turnCP.setPrevious(previousCP);
1053 turnCP.setNext(straightCP);
1054 straightCP.setPrevious(turnCP);
1056 previousCP.setPrevious(turnCP);
1057 turnCP.setNext(previousCP);
1058 turnCP.setPrevious(straightCP);
1059 straightCP.setNext(turnCP);
1062 turnCP.setWorldPosition(currentPosition);
1063 turnCP.setTurnAngle(0.0);
1064 turnCP.setLength(0.0);
1065 straightCP.setWorldPosition(currentPosition);
1066 straightCP.setLength(0.0);
1068 setPreviousPosition(currentPosition);
1069 updateCurrentPoint();
1076 * Updates tool graphics for current point
1078 private void updateCurrentPoint() {
1079 InlineComponent straight = (InlineComponent)added.get(added.size()-1);
1080 // TODO: the inline length is from previous update step.
1083 l = straight.getPrevious().getControlPoint().getInlineLength();
1085 l = straight.getNext().getControlPoint().getInlineLength();
1086 Vector3d v = new Vector3d();
1087 v.sub(currentPosition, previousPosition);
1088 double length = v.length();
1089 if (length > MathTools.NEAR_ZERO) {
1090 v.scale(1.0/length);
1091 v.scale(0.5*(length+l));
1092 v.add(previousPosition);
1093 straight.getControlPoint().setWorldPosition(v);
1094 straight.getControlPoint().setLength(length);
1097 PipingRules.positionUpdate(straight.getControlPoint(),false);
1098 } catch (Exception e) {
1099 // TODO Auto-generated catch block
1100 e.printStackTrace();
1104 private PipelineComponent getLast() {
1105 if (added.size() == 0)
1106 return startComponent;
1107 return added.get(added.size()-1);
1112 * Removes last point from pipeline
1114 public void removePoint() {
1115 if (added.size() < 3)
1117 InlineComponent straight = (InlineComponent)added.remove(added.size()-1);
1118 TurnComponent turn = (TurnComponent)added.remove(added.size()-1);
1119 straight.getControlPoint().remove();
1120 turn.getControlPoint().remove();
1121 if (added.size() > 1) {
1122 setPreviousPosition(added.get(added.size()-2).getWorldPosition());
1124 setPreviousPosition(startComponent.getWorldPosition());
1125 if (direction != null)
1126 setLockType(LockType.CUSTOM, true);
1131 private void endPiping() throws Exception {
1132 state = ToolState.NOT_ACTIVE;
1134 if (endTo != null) {
1135 ComponentUtils.connect(getLast(), endTo, endType, currentPosition);
1137 panel.useDefaultAction();