1 package org.simantics.plant3d.actions;
3 import java.awt.event.KeyEvent;
4 import java.awt.event.MouseEvent;
5 import java.math.BigDecimal;
6 import java.util.ArrayList;
7 import java.util.HashSet;
11 import javax.vecmath.Point3d;
12 import javax.vecmath.Tuple3d;
13 import javax.vecmath.Vector3d;
15 import org.simantics.g3d.math.MathTools;
16 import org.simantics.g3d.math.Ray;
17 import org.simantics.g3d.scenegraph.NodeMap;
18 import org.simantics.g3d.scenegraph.base.INode;
19 import org.simantics.g3d.tools.ConstraintDetector;
20 import org.simantics.g3d.tools.DummyConstraintDetector;
21 import org.simantics.g3d.vtk.gizmo.TranslateAxisGizmo;
22 import org.simantics.g3d.vtk.swt.InteractiveVtkComposite;
23 import org.simantics.g3d.vtk.swt.vtkSwtAction;
24 import org.simantics.g3d.vtk.utils.vtkUtil;
25 import org.simantics.plant3d.Activator;
26 import org.simantics.plant3d.gizmo.SplitPointSelectionGizmo;
27 import org.simantics.plant3d.gizmo.TerminalSelectionGizmo;
28 import org.simantics.plant3d.ontology.Plant3D;
29 import org.simantics.plant3d.scenegraph.EndComponent;
30 import org.simantics.plant3d.scenegraph.InlineComponent;
31 import org.simantics.plant3d.scenegraph.Nozzle;
32 import org.simantics.plant3d.scenegraph.P3DRootNode;
33 import org.simantics.plant3d.scenegraph.PipeRun;
34 import org.simantics.plant3d.scenegraph.PipelineComponent;
35 import org.simantics.plant3d.scenegraph.TurnComponent;
36 import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint;
37 import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint.Direction;
38 import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint.PositionType;
39 import org.simantics.plant3d.scenegraph.controlpoint.PipingRules;
40 import org.simantics.plant3d.utils.ComponentUtils;
41 import org.simantics.utils.threads.ThreadUtils;
42 import org.simantics.utils.ui.ExceptionUtils;
45 import vtk.vtkTextActor;
47 public class RoutePipeAction extends vtkSwtAction {
49 X, Y, Z, XY, YZ, XZ, NONE, CUSTOM
52 LockType lock = LockType.NONE;
53 private double BRANCH_SNAP_DISTANCE = 0.05;
54 private double NOZZLE_SNAP_DISTANCE = 0.05;
56 private double istep = 10.0;
57 private int decimals = 2;
59 private P3DRootNode root;
60 private PipelineComponent startComponent;
61 private PipeRun pipeRun;
63 private TranslateAxisGizmo translateAxisGizmo = new TranslateAxisGizmo();
64 private SplitPointSelectionGizmo splitPointSelectionGizmo;
65 private TerminalSelectionGizmo terminalSelectionGizmo;
66 private NodeMap<vtkProp,INode> nodeMap;
68 private enum ToolState{NOT_ACTIVE, INITIALIZING, SELECTING_POSITION, SELECTING_SPLIT, ROUTING};
69 private ToolState state = ToolState.NOT_ACTIVE;
71 private ConstraintDetector detector = new DummyConstraintDetector();
73 private boolean useDefault = false;
74 private Vector3d direction = null;
75 private Vector3d previousPosition = null;
76 private Vector3d currentPosition = null;
80 PipelineComponent endTo = null;
81 PositionType endType = null;
82 PipeControlPoint endPort = null;
84 boolean reversed = false;
86 private Set<PositionType> allowed = new HashSet<PositionType>();
89 public RoutePipeAction(InteractiveVtkComposite panel, P3DRootNode root) {
92 setText("Route Pipe");
93 setImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/Straight.png"));
94 nodeMap = root.getNodeMap();
95 splitPointSelectionGizmo = new SplitPointSelectionGizmo(panel);
96 terminalSelectionGizmo = new TerminalSelectionGizmo(panel);
99 public void setComponent(PipelineComponent component) {
100 this.startComponent = component;
102 if (this.startComponent.getNext() == null)
103 allowed.add(PositionType.NEXT);
104 if (this.startComponent.getPrevious() == null && !(this.startComponent instanceof Nozzle))
105 allowed.add(PositionType.PREVIOUS);
106 if (this.startComponent instanceof InlineComponent && !this.startComponent.getControlPoint().isFixed())
107 allowed.add(PositionType.SPLIT);
108 setEnabled(allowed.size() > 0);
111 public void deattach() {
113 startComponent = null;
114 nodeMap.commit("Route pipe");
120 public void attach() {
121 if (startComponent == null)
125 ThreadUtils.asyncExec(panel.getThreadQueue(), new Runnable() {
130 } catch (Exception e) {
132 ExceptionUtils.logAndShowError(e);
140 // private void attachUI() {
141 // //panel.setCursor(activeCursor);
142 // translateAxisGizmo.attach(panel.GetRenderer());
145 private void deattachUI() {
146 //panel.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
148 if (translateAxisGizmo.isAttached())
149 translateAxisGizmo.deattach();
150 if (splitPointSelectionGizmo.isAttached())
151 splitPointSelectionGizmo.deattach();
152 if (terminalSelectionGizmo.isAttached())
153 terminalSelectionGizmo.deattach();
154 if (infoActor != null) {
155 panel.getRenderer().RemoveActor(infoActor);
162 private List<PipelineComponent> added = new ArrayList<PipelineComponent>();
165 public boolean keyPressed(KeyEvent e) {
166 if (e.getKeyCode() == KeyEvent.VK_ESCAPE)
167 panel.useDefaultAction();
168 if (lock != LockType.CUSTOM) {
169 if ((e.getModifiersEx() & KeyEvent.SHIFT_DOWN_MASK) > 0) {
170 if (e.getKeyCode() == KeyEvent.VK_X) {
171 if (lock != LockType.XY && lock != LockType.XZ) {
172 setLockType(LockType.XY, false);
173 } else if (lock == LockType.XY) {
174 setLockType(LockType.XZ, false);
176 setLockType(LockType.NONE, false);
179 if (e.getKeyCode() == KeyEvent.VK_Y) {
180 if (lock != LockType.XY && lock != LockType.YZ) {
181 setLockType(LockType.XY, false);
182 } else if (lock == LockType.XY) {
183 setLockType(LockType.YZ, false);
185 setLockType(LockType.NONE, false);
188 if (e.getKeyCode() == KeyEvent.VK_Z) {
189 if (lock != LockType.XZ && lock != LockType.YZ) {
190 setLockType(LockType.XZ, false);
191 } else if (lock == LockType.XZ) {
192 setLockType(LockType.YZ, false);
194 setLockType(LockType.NONE, false);
198 if (e.getKeyCode() == KeyEvent.VK_X) {
199 if (lock != LockType.X)
200 setLockType(LockType.X,false);
202 setLockType(LockType.NONE,false);
204 if (e.getKeyCode() == KeyEvent.VK_Y) {
205 if (lock != LockType.Y)
206 setLockType(LockType.Y,false);
208 setLockType(LockType.NONE, false);
210 if (e.getKeyCode() == KeyEvent.VK_Z) {
211 if (lock != LockType.Z)
212 setLockType(LockType.Z, false);
214 setLockType(LockType.NONE, false);
218 if (e.getKeyCode() == KeyEvent.VK_C) {
219 useDefault = !useDefault;
220 System.out.println("UseDefault " + useDefault);
231 private void update() {
234 private void update(double x, double y) {
237 return; // TODO : throw Exception?
240 case SELECTING_POSITION:
242 case SELECTING_SPLIT:
251 boolean startRemovable = false;
253 private void activate() throws Exception {
254 state = ToolState.INITIALIZING;
257 if (allowed.size() == 1) {
258 pipeRun = startComponent.getPipeRun();
259 PipeControlPoint start = startComponent.getControlPoint();
260 boolean requiresBranching = false;
261 if (start.getNext() == null)
263 else if (start.getPrevious() == null) {
266 requiresBranching = true;
269 if (requiresBranching) {
270 activateSplit(start);
272 activateNextPrev(start);
274 } else if (allowed.size() == 0) {
275 panel.useDefaultAction();
276 state = ToolState.NOT_ACTIVE;
279 terminalSelectionGizmo.setComponent(startComponent, allowed);
280 terminalSelectionGizmo.attach(panel);
281 state = ToolState.SELECTING_POSITION;
289 private void activateNextPrev(PipeControlPoint start) throws Exception{
290 if (!reversed && start.isDualInline())
291 start = start.getSubPoint().get(0);
292 else if (reversed && start.isDualSub())
293 start = start.parent;
295 pipeRun = start.getPipeRun();
296 setPreviousPosition(start.getWorldPosition());
298 boolean startWithTurn = false;
299 if (startComponent instanceof Nozzle) {
300 direction = startComponent.getControlPoint().getDirectedControlPointDirection();
301 lock = LockType.CUSTOM;
302 } else if (startComponent instanceof PipelineComponent){
303 if (startComponent instanceof InlineComponent) {
304 direction = startComponent.getControlPoint().getPathLegDirection(reversed ? Direction.PREVIOUS : Direction.NEXT);
305 lock = LockType.CUSTOM;
306 if (startComponent.getType().equals(Plant3D.URIs.Builtin_Straight)) {
307 startWithTurn = true;
309 lock = LockType.NONE;
311 Vector3d v = new Vector3d();
313 start.getControlPointEnds(v, previousPosition);
315 start.getControlPointEnds(previousPosition,v);
317 } else if (startComponent instanceof TurnComponent) {
318 if (start.isFixed()) {
319 direction = startComponent.getControlPoint().getPathLegDirection(reversed ? Direction.PREVIOUS : Direction.NEXT);
320 lock = LockType.CUSTOM;
323 lock = LockType.NONE;
325 } else if (startComponent instanceof EndComponent) {
326 throw new Exception("Not supported");
330 throw new Exception("Not supported");
332 currentPosition = new Vector3d(previousPosition);
333 state = ToolState.ROUTING;
334 if (direction != null) {
335 direction.normalize();
338 startRemovable = start.isDeletable();
339 start.setDeletable(false);
344 if (direction != null)
345 currentPosition.add(direction);
346 InlineComponent straight = ComponentUtils.createStraight(root);
347 PipeControlPoint straightCP = straight.getControlPoint();
348 straight.setName(pipeRun.getUniqueName("Pipe"));
349 pipeRun.addChild(straight);
353 start.setNext(straightCP);
354 straightCP.setPrevious(start);
356 start.setPrevious(straightCP);
357 straightCP.setNext(start);
360 translateAxisGizmo.attach(panel);
361 setPreviousPosition(previousPosition);
362 updateCurrentPoint();
365 private void setPreviousPosition(Vector3d v) {
366 previousPosition = new Vector3d(v);
367 if (translateAxisGizmo.isAttached())
368 translateAxisGizmo.setPosition(previousPosition);
371 private void activateBranch(PipeControlPoint start) throws Exception{
372 pipeRun = start.getPipeRun();
373 setPreviousPosition(start.getWorldPosition());
376 lock = LockType.NONE;
378 currentPosition = new Vector3d(previousPosition);
379 state = ToolState.ROUTING;
380 if (direction != null) {
381 direction.normalize();
384 startRemovable = start.isDeletable();
385 start.setDeletable(false);
388 if (direction != null)
389 currentPosition.add(direction);
390 InlineComponent straight = ComponentUtils.createStraight(root);
391 PipeControlPoint straightCP = straight.getControlPoint();
392 straight.setName(pipeRun.getUniqueName("Pipe"));
393 pipeRun.addChild(straight);
397 start.setNext(straightCP);
398 straightCP.setPrevious(start);
401 start.setPrevious(straightCP);
402 straightCP.setNext(start);
406 translateAxisGizmo.attach(panel);
407 setPreviousPosition(previousPosition);
408 updateCurrentPoint();
411 private void activateSplit(PipeControlPoint start) throws Exception{
412 Point3d p1 = new Point3d();
413 Point3d p2 = new Point3d();
414 start.getInlineControlPointEnds(p1, p2);
415 splitPointSelectionGizmo.setSplit(p1, p2);
416 splitPointSelectionGizmo.attach(panel);
417 state = ToolState.SELECTING_SPLIT;
419 public void deactivate() {
420 for (PipelineComponent component : added) {
421 component.getControlPoint().setDeletable(true);
425 startComponent.getControlPoint().setDeletable(startRemovable);
429 setLockType(LockType.NONE, true);
430 startComponent = null;
436 currentPosition = null;
437 previousPosition = null;
438 startRemovable = false;
439 detector.clearConstraintHighlights();
440 state = ToolState.NOT_ACTIVE;
446 private void setLockType(LockType type, boolean force) {
447 if (force || lock != LockType.CUSTOM) {
453 translateAxisGizmo.setType(6);
456 translateAxisGizmo.setType(0);
459 translateAxisGizmo.setType(1);
462 translateAxisGizmo.setType(2);
465 translateAxisGizmo.setType(3);
468 translateAxisGizmo.setType(4);
471 translateAxisGizmo.setType(5);
479 public boolean mousePressed(MouseEvent e) {
481 getDefaultAction().mousePressed(e);
487 public boolean mouseReleased(MouseEvent e) {
489 getDefaultAction().mouseReleased(e);
495 public boolean mouseClicked(MouseEvent e) {
497 getDefaultAction().mouseClicked(e);
500 if (state == ToolState.ROUTING) {
502 if (e.getClickCount() == 1) {
503 if (e.getButton() == MouseEvent.BUTTON1) {
504 if (this.added.size() > 0) {
506 setLockType(LockType.NONE,true);
514 throw new RuntimeException("kjf");
515 // // user was selecting position of branch
516 // lastPoint.set(startPoint);
517 // controlPoints.add(new Point3d(startPoint));
518 // if (selectionLine != null)
519 // selectionLine.removeFromParent();
520 // selectionLine = null;
522 } else if (e.getButton() ==MouseEvent.BUTTON2){
523 // detector.updateConstraintReference();
524 } else if (e.getButton() == MouseEvent.BUTTON3){
528 } catch(Exception err) {
529 err.printStackTrace();
531 } else if (state == ToolState.SELECTING_POSITION) {
532 if (e.getClickCount() == 1 && e.getButton() == MouseEvent.BUTTON1) {
533 int type = panel.getPickType();
534 //panel.setPickType(0);
535 panel.setPickType(5);
536 vtkProp[] picked = panel.pick(e.getX(), e.getY());
537 panel.setPickType(type);
538 PositionType position = terminalSelectionGizmo.getPickedPosition(picked);
539 if (position != null) {
540 terminalSelectionGizmo.deattach();
542 if (position == PositionType.SPLIT) {
543 activateSplit(startComponent.getControlPoint());
544 } else if (position == PositionType.NEXT || position == PositionType.PREVIOUS) {
545 reversed = position == PositionType.PREVIOUS;
546 activateNextPrev(startComponent.getControlPoint());
548 panel.useDefaultAction();
550 } catch (Exception err) {
551 ExceptionUtils.logAndShowError(err);
552 panel.useDefaultAction();
556 } else if (state == ToolState.SELECTING_SPLIT) {
557 if (e.getClickCount() == 1 && e.getButton() == MouseEvent.BUTTON1) {
558 Tuple3d t = splitPointSelectionGizmo.getSplitPoint();
559 splitPointSelectionGizmo.deattach();
561 panel.useDefaultAction();
565 Vector3d pos = new Vector3d(t);
566 InlineComponent branchSplit = createBranchSplit((InlineComponent)startComponent, pos);
567 PipeControlPoint branchSplitCP = branchSplit.getControlPoint();
569 PipeRun newRun = new PipeRun();
570 String n = root.getUniqueName("PipeRun");
572 root.addChild(newRun);
573 PipeControlPoint pcp = new PipeControlPoint(branchSplit,newRun);
574 branchSplitCP.children.add(pcp);
575 pcp.parent = branchSplitCP;
576 pcp.setWorldOrientation(branchSplitCP.getWorldOrientation());
577 pcp.setWorldPosition(branchSplitCP.getWorldPosition());
578 startComponent = branchSplit;
580 } catch (Exception err) {
581 ExceptionUtils.logAndShowError(err);
582 panel.useDefaultAction();
589 private InlineComponent createBranchSplit(InlineComponent component, Vector3d pos) throws Exception{
590 InlineComponent branchSplit = ComponentUtils.createBranchSplit(root);
591 String branchName = component.getPipeRun().getUniqueName("Branch");
592 branchSplit.setName(branchName);
593 component.getPipeRun().addChild(branchSplit);
594 PipeControlPoint branchSplitCP = branchSplit.getControlPoint();
595 branchSplitCP.setWorldPosition(pos);
596 PipingRules.splitVariableLengthComponent(branchSplit, component, false);
601 public boolean mouseMoved(MouseEvent e) {
603 getDefaultAction().mouseMoved(e);
606 step = ((e.getModifiers() & MouseEvent.CTRL_DOWN_MASK) > 0);
607 update(e.getX(), e.getY());
612 public boolean mouseDragged(MouseEvent e) {
614 getDefaultAction().mouseDragged(e);
621 private List<INode> isOverNode(int x, int y) {
622 List<INode> nodes = new ArrayList<INode>();
623 vtkProp picked[] = panel.pick2(x, y);
625 for (int i = 0; i < picked.length; i++) {
626 nodes.add(nodeMap.getNode(picked[i]));
634 private void updateRouting(double x, double y) {
635 // if(input.keyPressed(KeyEvent.VK_ESCAPE)) {
636 // controlPoints.clear();
640 // if (input.keyPressed(KeyEvent.VK_C)) {
641 // useCamera = !useCamera;
642 // cameraAction.setChecked(useCamera);
645 //panel.getDefaultAction().update();
653 Ray ray = vtkUtil.createMouseRay(panel.getRenderer(),x, y);
654 Vector3d o = new Vector3d(ray.pos);
655 Vector3d d = ray.dir;
658 if (!updateCurrentPoint(o, d))
660 //Point3d startPoint = new Point3d();
661 double mu[] = new double[2];
665 INode hoverObject = null;
667 List<INode> hover = isOverNode((int)x,(int)y);
668 if (hover.size() > 0) {
669 hoverObject = hover.get(0);
671 // System.out.println(hoverObject + " " + getLast());
672 if (hoverObject != null) {
673 if (hoverObject.equals(getLast()) ) {
675 for (int i = 1; i < hover.size(); i++) {
676 hoverObject = hover.get(i);
677 if (!getLast().equals(hoverObject)) {
686 // System.out.println(hoverObject);
687 if (hoverObject != null) {
689 if (lock == LockType.NONE) {
690 if (hoverObject instanceof Nozzle && endingToNozzle(hoverObject,o,d)) {
691 endTo = (Nozzle)hoverObject;
692 } else if (hoverObject instanceof InlineComponent && ((InlineComponent)hoverObject).isVariableLength()) {
693 endTo = (InlineComponent)hoverObject;
694 endType = endingToStraight(endTo,mu,o,d);
695 } else if (hoverObject instanceof PipelineComponent && (endPort = endingToComponent(hoverObject,o,d)) != null) {
696 endTo = (PipelineComponent)hoverObject;
701 if (hoverObject instanceof InlineComponent && ((InlineComponent)hoverObject).isVariableLength() && (endType = endingLockToStraight(hoverObject,mu)) != null) {
702 endTo = (InlineComponent)hoverObject;;
703 } else if (hoverObject instanceof Nozzle && endingLockToNozzle(hoverObject)) {
704 endTo = (Nozzle)hoverObject;
705 } else if ((hoverObject instanceof PipelineComponent) && ((endPort = endingLockToComponent(hoverObject)) != null)) {
706 endTo = (PipelineComponent)hoverObject;
711 if (added.contains(endTo))
721 private boolean updateCurrentPoint(Vector3d o, Vector3d d) {
723 Vector3d point = new Vector3d(this.previousPosition);
727 MathTools.intersectStraightStraight(point, new Vector3d(1.0,0.0,0.0), o,d, currentPosition, new Vector3d());
729 currentPosition.x = Math.round(istep * currentPosition.x) / istep;
730 BigDecimal bx = new BigDecimal(currentPosition.x);
731 bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);
732 currentPosition.x = bx.doubleValue();
736 MathTools.intersectStraightStraight(point, new Vector3d(0.0,1.0,0.0), o,d, currentPosition, new Vector3d());
738 currentPosition.y = Math.round(istep * currentPosition.y) / istep;
739 BigDecimal bx = new BigDecimal(currentPosition.y);
740 bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);
741 currentPosition.y = bx.doubleValue();
745 MathTools.intersectStraightStraight(point, new Vector3d(0.0,0.0,1.0), o,d, currentPosition, new Vector3d());
747 currentPosition.z = Math.round(istep * currentPosition.z) / istep;
748 BigDecimal bx = new BigDecimal(currentPosition.z);
749 bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);
750 currentPosition.z = bx.doubleValue();
753 MathTools.intersectStraightPlane(o, d, point, new Vector3d(0.0,0.0,1.0), currentPosition);
756 MathTools.intersectStraightPlane(o, d, point, new Vector3d(0.0,1.0,0.0), currentPosition);
759 MathTools.intersectStraightPlane(o, d, point, new Vector3d(1.0,0.0,0.0), currentPosition);
762 Vector3d normal = new Vector3d(panel.getRenderer().GetActiveCamera().GetDirectionOfProjection());
765 MathTools.intersectStraightPlane(o, d, point, normal, currentPosition);
768 MathTools.intersectStraightStraight(point, new Vector3d(direction), o,d, currentPosition, new Vector3d());
769 double dist = MathTools.distanceFromPlane(new Vector3d(currentPosition), direction, previousPosition);
771 currentPosition.set(previousPosition);
779 private Vector3d getLockDir() {
784 return new Vector3d(1,0,0);
786 return new Vector3d(0,1,0);
788 return new Vector3d(0,0,1);
793 private void updateRoute(Vector3d o, Vector3d d) {
794 detector.clearConstraintHighlights();
795 Point3d previousPipePoint = new Point3d(previousPosition);
797 if (lock == LockType.NONE) {
798 Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint));
800 currentPosition = new Vector3d(p);
801 s += detector.getSnapString();
804 Vector3d dir = new Vector3d(currentPosition);
805 dir.sub(previousPipePoint);
806 Point3d p = detector.getPointSnap(new Vector3d(previousPipePoint), dir);
808 currentPosition = new Vector3d(p);
809 s += detector.getSnapString();
813 updateCurrentPoint();
814 s += currentPosition.toString();
818 vtkTextActor infoActor;
820 private void setInfoText(String text) {
821 //System.out.println(text);
822 if (infoActor == null) {
823 infoActor = new vtkTextActor();
824 infoActor.GetTextProperty().SetColor(0.0, 0.0, 0.0);
825 infoActor.GetTextProperty().ShadowOff();
826 infoActor.GetTextProperty().ItalicOff();
827 infoActor.GetTextProperty().BoldOff();
828 infoActor.GetTextProperty().SetFontSize(18);
829 infoActor.GetTextProperty().Delete();
830 infoActor.GetProperty().SetColor(0.0, 0.0, 0.0);
831 infoActor.GetProperty().Delete();
834 infoActor.SetPosition(10,10);
835 panel.getRenderer().AddActor(infoActor);
837 infoActor.SetInput(text);
840 private boolean endingToNozzle(INode nozzleNode,Vector3d o, Vector3d d) {
841 Nozzle nozzle = (Nozzle)nozzleNode;
842 PipeControlPoint pcp =nozzle.getControlPoint();
843 if (pcp != null && (pcp.getNext() != null ||
844 pcp.getPrevious() != null))
845 return false; // nozzle is already connected to pipe
846 currentPosition = pcp.getWorldPosition();
847 Point3d previousPipePoint = new Point3d(previousPosition);
848 Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint));
850 if (MathTools.distance(p, currentPosition) > NOZZLE_SNAP_DISTANCE) {
855 updateCurrentPoint();
857 setInfoText("Connect to nozzle " + currentPosition);
862 private PositionType endingToStraight(INode straightNode, double mu[], Vector3d o, Vector3d d) {
863 InlineComponent s = (InlineComponent)straightNode;
865 Point3d sStart = new Point3d();
866 Point3d sEnd = new Point3d();
867 s.getControlPointEnds(sStart, sEnd);
868 //detector.clearConstraintHighlights();
870 Point3d previousPipePoint = new Point3d(previousPosition);
872 if (lock == LockType.NONE) {
873 Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint));
875 currentPosition = new Vector3d(p);
876 // snapping is detected, check if snapped point can create branch with straight
877 PositionType t = endingLockToStraight(s, mu);
880 // if not, we'll have to remove highlight that was added when snapped point was detected
881 detector.clearConstraintHighlights();
885 Vector3d sDir = new Vector3d(sEnd);
887 MathTools.intersectStraightStraight(sStart, sDir, o, d, currentPosition, new Point3d(), mu);
891 throw new RuntimeException("Lock shouldn't be on");
895 updateCurrentPoint();
897 // branch point must lie between straight's ends. If connection point is exactly
898 // on straight end user may want to connect pipes to each other
899 // TODO : take account sizes of inline components)
900 // TODO : actually make connection if its detected
901 boolean connectPrev = false;
902 boolean connectNext = false;
905 currentPosition.set(sStart);
908 else if (mu[0] > 1.0) {
909 currentPosition.set(sEnd);
912 boolean connect = false;
914 PipeControlPoint pcp = s.getControlPoint();
915 if (pcp.getPrevious() == null)
917 } else if (connectNext) {
918 PipeControlPoint pcp = s.getControlPoint();
919 if (pcp.getNext() == null)
923 updateCurrentPoint();
926 info += "Connect pipes :";
928 info += "Make Branch :";
930 setInfoText(info + currentPosition + " " + Math.max(0.0, Math.min(mu[0], 1.0)));
933 return PositionType.NEXT;
935 return PositionType.PREVIOUS;
939 return PositionType.SPLIT;
943 private PipeControlPoint endingToComponent(INode componentNode, Vector3d o, Vector3d d) {
944 PipelineComponent component = (PipelineComponent)componentNode;
945 PipeControlPoint pcp = component.getControlPoint();
946 if (component instanceof EndComponent) {
947 if (pcp.getNext() != null || pcp.getPrevious() != null)
950 } else if (component instanceof TurnComponent) {
951 if (pcp.getNext() == null || pcp.getPrevious() == null)
954 } else if (component instanceof InlineComponent) {
955 // TODO : scan all empty pcps of the component and select closest one.
956 if (pcp.getNext() == null || pcp.getPrevious() == null)
964 private PositionType endingLockToStraight(INode straightNode, double mu[]) {
965 InlineComponent s = (InlineComponent)straightNode;
966 Point3d sStart = new Point3d();//G3DTools.getPoint(s.getHasControlPoint().getPreviousPoint().getLocalPosition());
967 Point3d sEnd = new Point3d(); //G3DTools.getPoint(s.getHasControlPoint().getNextPoint().getLocalPosition());
968 s.getControlPoint().getInlineControlPointEnds(sStart, sEnd);
969 Vector3d sDir = new Vector3d(sEnd);
971 Vector3d dir = new Vector3d(currentPosition);
972 Point3d prev = new Point3d(previousPosition);
974 // intersection point in pipe where branch would be inserted to
975 Vector3d branchPoint = new Vector3d();
976 // intersection point in straight pipe that is currently routed
977 Vector3d routePoint = new Vector3d();
978 MathTools.intersectStraightStraight(sStart, sDir, new Vector3d(prev), dir, branchPoint, routePoint, mu);
979 routePoint.sub(branchPoint);
980 // startPoint of branch must be between pipe ends
981 // TODO : take account sizes of elbows (or other components)
982 // branch point must be between pipe ends and intersection points must be quite close to each othert
983 if (mu[0] > 0.0 && mu[0] < 1.0 && routePoint.lengthSquared() < BRANCH_SNAP_DISTANCE) {
984 currentPosition.set(branchPoint);
986 updateCurrentPoint();
988 setInfoText("Make branch (l) :" + currentPosition + " " + Math.max(0.0, Math.min(mu[0], 1.0)) + " " + routePoint.lengthSquared());
989 return PositionType.SPLIT;
994 private boolean endingLockToNozzle(INode nozzleNode) {
995 Nozzle nozzle = (Nozzle)nozzleNode;
996 Vector3d dir = new Vector3d(currentPosition);
997 Point3d prev = new Point3d(previousPosition);
999 Vector3d nozzleLoc = nozzle.getWorldPosition();
1000 double u[] = new double[1];
1001 Vector3d closest = MathTools.closestPointOnStraight(new Point3d(nozzleLoc), new Point3d(prev), new Vector3d(dir), u);
1002 double dist = MathTools.distanceSquared(nozzleLoc,closest);
1003 if (dist < BRANCH_SNAP_DISTANCE) {
1004 // FIXME : directions should be checked (insert an elbow)
1005 currentPosition.set(nozzleLoc);
1006 updateCurrentPoint();
1007 setInfoText("Connect to nozzle (l) :" + currentPosition);
1010 //System.out.println(u[0]);
1014 private PipeControlPoint endingLockToComponent(INode componentNode) {
1015 // we'll must scan all free pcp's and their direction to accept the connection.
1019 private void addPoint() throws Exception {
1020 InlineComponent previous = (InlineComponent)getLast();
1021 PipeControlPoint previousCP = previous.getControlPoint();
1022 TurnComponent turn = ComponentUtils.createTurn(root);
1023 InlineComponent straight = ComponentUtils.createStraight(root);
1024 PipeControlPoint turnCP = turn.getControlPoint();
1025 PipeControlPoint straightCP = straight.getControlPoint();
1026 straight.setName(pipeRun.getUniqueName("Pipe"));
1027 turn.setName(pipeRun.getUniqueName("Elbow"));
1028 pipeRun.addChild(turn);
1029 pipeRun.addChild(straight);
1031 added.add(straight);
1033 turnCP.setDeletable(false); // mark turnCP nonDeletable so that PipingRules won't delete it immediately.
1036 previousCP.setNext(turnCP);
1037 turnCP.setPrevious(previousCP);
1038 turnCP.setNext(straightCP);
1039 straightCP.setPrevious(turnCP);
1041 previousCP.setPrevious(turnCP);
1042 turnCP.setNext(previousCP);
1043 turnCP.setPrevious(straightCP);
1044 straightCP.setNext(turnCP);
1047 turnCP.setWorldPosition(currentPosition);
1048 turnCP.setTurnAngle(0.0);
1049 turnCP.setLength(0.0);
1050 straightCP.setWorldPosition(currentPosition);
1051 straightCP.setLength(0.0);
1053 setPreviousPosition(currentPosition);
1054 updateCurrentPoint();
1061 * Updates tool graphics for current point
1063 private void updateCurrentPoint() {
1064 // PipeComponentProvider.createStraightEdges(pipeShapes.get(pipeShapes.size() - 1), controlPoints.get(controlPoints.size() - 1), currentPoint, pipeDiameter*0.5);
1065 InlineComponent straight = (InlineComponent)added.get(added.size()-1);
1066 // FIXME : does not take account space the the previous elbow reserves.
1067 Vector3d v = new Vector3d();
1068 v.sub(currentPosition, previousPosition);
1069 double length = v.length();
1071 v.add(previousPosition);
1072 straight.getControlPoint().setWorldPosition(v);
1073 straight.getControlPoint().setLength(length);
1075 PipingRules.positionUpdate(straight.getControlPoint(),false);
1076 } catch (Exception e) {
1077 // TODO Auto-generated catch block
1078 e.printStackTrace();
1082 private PipelineComponent getLast() {
1083 if (added.size() == 0)
1084 return startComponent;
1085 return added.get(added.size()-1);
1090 * Removes last point from pipeline
1092 public void removePoint() {
1093 if (added.size() < 3)
1095 InlineComponent straight = (InlineComponent)added.remove(added.size()-1);
1096 TurnComponent turn = (TurnComponent)added.remove(added.size()-1);
1097 straight.getControlPoint().remove();
1098 turn.getControlPoint().remove();
1099 if (added.size() > 1) {
1100 setPreviousPosition(added.get(added.size()-2).getWorldPosition());
1102 setPreviousPosition(startComponent.getWorldPosition());
1103 if (direction != null)
1104 setLockType(LockType.CUSTOM, true);
1109 private void endPiping() throws Exception {
1110 state = ToolState.NOT_ACTIVE;
1112 if (endTo != null) {
1113 PipeControlPoint endCP = endTo.getControlPoint();
1114 if (endType == null || endType == PositionType.NEXT || endType == PositionType.PREVIOUS) {
1116 PipelineComponent current = getLast();
1117 PipeControlPoint currentCP = current.getControlPoint();
1119 boolean requiresReverse = false;
1120 if (!reversed && endCP.getPrevious() != null) {
1121 requiresReverse = true;
1122 } else if (reversed && endCP.getNext() != null) {
1123 requiresReverse = true;
1125 PipeRun other = endCP.getPipeRun();
1126 boolean mergeRuns = pipeRun.equalSpecs(other);
1128 if (requiresReverse) {
1129 // Pipe line must be traversible with next/previous relations without direction change.
1130 // Now the component, where we are connecting the created pipeline is defined in different order.
1131 PipingRules.reverse(other);
1135 // Runs have compatible specs and must be merged
1136 if (pipeRun != other) // FIXME: temporary workaround.
1137 PipingRules.merge(pipeRun, other);
1139 currentCP.setNext(endCP);
1140 endCP.setPrevious(currentCP);
1142 currentCP.setPrevious(endCP);
1143 endCP.setNext(currentCP);
1146 // Runs do not have compatible specs, and a reducer must be attached in between.
1147 InlineComponent reducer = ComponentUtils.createReducer(root);
1148 PipeControlPoint pcp = reducer.getControlPoint();
1149 PipeControlPoint ocp = pcp.getSubPoint().get(0);
1151 Vector3d endPos = endCP.getWorldPosition();
1152 Vector3d currentPos = currentCP.getWorldPosition();
1153 Vector3d v = new Vector3d(endPos);
1158 PipingRules.addSizeChange(reversed, pipeRun, other, reducer, currentCP, endCP);
1160 pcp.setWorldPosition(v);
1161 reducer.updateParameters();
1164 } else if (endType == PositionType.SPLIT) {
1165 InlineComponent branchSplit = createBranchSplit((InlineComponent)endTo, currentPosition);
1166 PipeControlPoint branchSplitCP = branchSplit.getControlPoint();
1167 PipeControlPoint pcp = new PipeControlPoint(branchSplit,pipeRun);
1168 branchSplitCP.children.add(pcp);
1169 pcp.parent = branchSplitCP;
1170 pcp.setWorldOrientation(branchSplitCP.getWorldOrientation());
1171 pcp.setWorldPosition(branchSplitCP.getWorldPosition());
1173 PipelineComponent current = getLast();
1174 PipeControlPoint currentCP = current.getControlPoint();
1178 pcp.setPrevious(currentCP);
1179 currentCP.setNext(pcp);
1181 pcp.setNext(currentCP);
1182 currentCP.setPrevious(pcp);
1186 PipingRules.positionUpdate(endCP);
1188 panel.useDefaultAction();