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.db.Resource;
17 import org.simantics.g3d.math.MathTools;
18 import org.simantics.g3d.math.Ray;
19 import org.simantics.g3d.scenegraph.NodeMap;
20 import org.simantics.g3d.scenegraph.base.INode;
21 import org.simantics.g3d.tools.ConstraintDetector;
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.ConstraintPointGizmo;
28 import org.simantics.plant3d.gizmo.SplitPointSelectionGizmo;
29 import org.simantics.plant3d.gizmo.TerminalSelectionGizmo;
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 ConstraintPointGizmo constraintPointGizmo;
67 private TerminalSelectionGizmo terminalSelectionGizmo;
68 private NodeMap<Resource,vtkProp,INode> nodeMap;
70 private enum ToolState{NOT_ACTIVE, INITIALIZING, SELECTING_POSITION, SELECTING_SPLIT, ROUTING};
71 private ToolState state = ToolState.NOT_ACTIVE;
73 private ConstraintDetector detector;// = new DummyConstraintDetector();
75 private boolean useDefault = false;
76 private Vector3d direction = null;
77 private Vector3d previousPosition = null;
78 private Vector3d currentPosition = null;
82 PipelineComponent endTo = null;
83 PositionType endType = null;
84 PipeControlPoint endPort = null;
86 boolean reversed = false;
88 private Set<PositionType> allowed = new HashSet<PositionType>();
91 public RoutePipeAction(InteractiveVtkComposite panel, P3DRootNode root) {
94 setText("Route Pipe");
95 setImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/Straight.png"));
96 nodeMap = root.getNodeMap();
97 splitPointSelectionGizmo = new SplitPointSelectionGizmo(panel);
98 terminalSelectionGizmo = new TerminalSelectionGizmo(panel);
99 constraintPointGizmo = new ConstraintPointGizmo(panel);
100 detector = new org.simantics.g3d.vtk.swt.ConstraintDetector(panel);
103 public void setComponent(PipelineComponent component) {
104 this.startComponent = component;
106 if (this.startComponent.getNext() == null)
107 allowed.add(PositionType.NEXT);
108 if (this.startComponent.getPrevious() == null && !(this.startComponent instanceof Nozzle))
109 allowed.add(PositionType.PREVIOUS);
110 if (this.startComponent instanceof InlineComponent && !this.startComponent.getControlPoint().isFixed())
111 allowed.add(PositionType.SPLIT);
112 setEnabled(allowed.size() > 0);
115 public void deattach() {
117 startComponent = null;
124 public void attach() {
125 if (startComponent == null)
129 ThreadUtils.asyncExec(panel.getThreadQueue(), new Runnable() {
134 } catch (Exception e) {
136 ExceptionUtils.logAndShowError(e);
144 // private void attachUI() {
145 // //panel.setCursor(activeCursor);
146 // translateAxisGizmo.attach(panel.GetRenderer());
149 private void deattachUI() {
150 //panel.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
152 if (translateAxisGizmo.isAttached())
153 translateAxisGizmo.deattach();
154 if (splitPointSelectionGizmo.isAttached())
155 splitPointSelectionGizmo.deattach();
156 if (terminalSelectionGizmo.isAttached())
157 terminalSelectionGizmo.deattach();
158 if (constraintPointGizmo.isAttached())
159 constraintPointGizmo.deattach();
160 if (infoActor != null) {
161 panel.getRenderer().RemoveActor(infoActor);
168 private List<PipelineComponent> added = new ArrayList<PipelineComponent>();
171 public boolean keyPressed(KeyEvent e) {
172 if (e.getKeyCode() == KeyEvent.VK_ESCAPE)
173 panel.useDefaultAction();
174 if (lock != LockType.CUSTOM) {
175 if ((e.getModifiersEx() & KeyEvent.SHIFT_DOWN_MASK) > 0) {
176 if (e.getKeyCode() == KeyEvent.VK_X) {
177 if (lock != LockType.XY && lock != LockType.XZ) {
178 setLockType(LockType.XY, false);
179 } else if (lock == LockType.XY) {
180 setLockType(LockType.XZ, false);
182 setLockType(LockType.NONE, false);
185 if (e.getKeyCode() == KeyEvent.VK_Y) {
186 if (lock != LockType.XY && lock != LockType.YZ) {
187 setLockType(LockType.XY, false);
188 } else if (lock == LockType.XY) {
189 setLockType(LockType.YZ, false);
191 setLockType(LockType.NONE, false);
194 if (e.getKeyCode() == KeyEvent.VK_Z) {
195 if (lock != LockType.XZ && lock != LockType.YZ) {
196 setLockType(LockType.XZ, false);
197 } else if (lock == LockType.XZ) {
198 setLockType(LockType.YZ, false);
200 setLockType(LockType.NONE, false);
204 if (e.getKeyCode() == KeyEvent.VK_X) {
205 if (lock != LockType.X)
206 setLockType(LockType.X,false);
208 setLockType(LockType.NONE,false);
210 if (e.getKeyCode() == KeyEvent.VK_Y) {
211 if (lock != LockType.Y)
212 setLockType(LockType.Y,false);
214 setLockType(LockType.NONE, false);
216 if (e.getKeyCode() == KeyEvent.VK_Z) {
217 if (lock != LockType.Z)
218 setLockType(LockType.Z, false);
220 setLockType(LockType.NONE, false);
224 if (e.getKeyCode() == KeyEvent.VK_C) {
225 useDefault = !useDefault;
226 System.out.println("UseDefault " + useDefault);
237 private void update() {
240 private void update(double x, double y) {
243 return; // TODO : throw Exception?
246 case SELECTING_POSITION:
248 case SELECTING_SPLIT:
257 boolean startRemovable = false;
259 private void activate() throws Exception {
260 state = ToolState.INITIALIZING;
263 if (allowed.size() == 1) {
264 pipeRun = startComponent.getPipeRun();
265 PipeControlPoint start = startComponent.getControlPoint();
266 boolean requiresBranching = false;
267 if (start.getNext() == null)
269 else if (start.getPrevious() == null) {
272 requiresBranching = true;
275 if (requiresBranching) {
276 activateSplit(start);
278 activateNextPrev(start);
280 } else if (allowed.size() == 0) {
281 panel.useDefaultAction();
282 state = ToolState.NOT_ACTIVE;
285 terminalSelectionGizmo.setComponent(startComponent, allowed);
286 terminalSelectionGizmo.attach(panel);
287 state = ToolState.SELECTING_POSITION;
295 private void activateNextPrev(PipeControlPoint start) throws Exception{
296 if (!reversed && start.isDualInline())
297 start = start.getSubPoint().get(0);
298 else if (reversed && start.isDualSub())
299 start = start.parent;
301 pipeRun = start.getPipeRun();
302 setPreviousPosition(start.getWorldPosition());
304 boolean startWithTurn = false;
305 if (startComponent instanceof Nozzle) {
306 direction = startComponent.getControlPoint().getDirectedControlPointDirection();
307 lock = LockType.CUSTOM;
308 } else if (startComponent instanceof PipelineComponent){
309 if (startComponent instanceof InlineComponent) {
310 direction = startComponent.getControlPoint().getPathLegDirection(reversed ? Direction.PREVIOUS : Direction.NEXT);
311 lock = LockType.CUSTOM;
312 if (((InlineComponent) startComponent).isVariableLength()) {
313 startWithTurn = true;
315 lock = LockType.NONE;
317 Vector3d v = new Vector3d();
319 start.getControlPointEnds(v, previousPosition);
321 start.getControlPointEnds(previousPosition,v);
323 } else if (startComponent instanceof TurnComponent) {
324 if (start.isFixed()) {
325 direction = startComponent.getControlPoint().getPathLegDirection(reversed ? Direction.PREVIOUS : Direction.NEXT);
326 lock = LockType.CUSTOM;
329 lock = LockType.NONE;
331 } else if (startComponent instanceof EndComponent) {
332 throw new Exception("Not supported");
336 throw new Exception("Not supported");
338 currentPosition = new Vector3d(previousPosition);
339 state = ToolState.ROUTING;
340 if (direction != null) {
341 direction.normalize();
344 startRemovable = start.isDeletable();
345 start.setDeletable(false);
350 if (direction != null)
351 currentPosition.add(direction);
352 InlineComponent straight = ComponentUtils.createStraight(root);
353 PipeControlPoint straightCP = straight.getControlPoint();
354 straight.setName(pipeRun.getUniqueName("Pipe"));
355 pipeRun.addChild(straight);
359 start.setNext(straightCP);
360 straightCP.setPrevious(start);
362 start.setPrevious(straightCP);
363 straightCP.setNext(start);
366 translateAxisGizmo.attach(panel);
367 setPreviousPosition(previousPosition);
368 updateCurrentPoint();
371 private void setPreviousPosition(Vector3d v) {
372 previousPosition = new Vector3d(v);
373 if (translateAxisGizmo.isAttached())
374 translateAxisGizmo.setPosition(previousPosition);
377 private void activateBranch(PipeControlPoint start) throws Exception{
378 pipeRun = start.getPipeRun();
379 setPreviousPosition(start.getWorldPosition());
382 lock = LockType.NONE;
384 currentPosition = new Vector3d(previousPosition);
385 state = ToolState.ROUTING;
386 if (direction != null) {
387 direction.normalize();
390 startRemovable = start.isDeletable();
391 start.setDeletable(false);
394 if (direction != null)
395 currentPosition.add(direction);
396 InlineComponent straight = ComponentUtils.createStraight(root);
397 PipeControlPoint straightCP = straight.getControlPoint();
398 straight.setName(pipeRun.getUniqueName("Pipe"));
399 pipeRun.addChild(straight);
403 start.setNext(straightCP);
404 straightCP.setPrevious(start);
407 start.setPrevious(straightCP);
408 straightCP.setNext(start);
412 translateAxisGizmo.attach(panel);
413 setPreviousPosition(previousPosition);
414 updateCurrentPoint();
417 private void activateSplit(PipeControlPoint start) throws Exception{
418 Point3d p1 = new Point3d();
419 Point3d p2 = new Point3d();
420 start.getInlineControlPointEnds(p1, p2);
421 splitPointSelectionGizmo.setSplit(p1, p2);
422 splitPointSelectionGizmo.attach(panel);
423 state = ToolState.SELECTING_SPLIT;
425 public void deactivate() {
426 if (added.size() > 0) {
427 for (PipelineComponent component : added) {
428 component.getControlPoint().setDeletable(true);
431 for (PipelineComponent comp : added) {
432 PipingRules.requestUpdate(comp.getControlPoint());
435 PipingRules.update();
436 nodeMap.commit("Route pipe");
437 } catch (Exception e) {
438 ExceptionUtils.logAndShowError(e);
443 startComponent.getControlPoint().setDeletable(startRemovable);
447 setLockType(LockType.NONE, true);
448 startComponent = null;
454 currentPosition = null;
455 previousPosition = null;
456 startRemovable = false;
457 detector.clearConstraintHighlights();
458 state = ToolState.NOT_ACTIVE;
463 private void setLockType(LockType type, boolean force) {
464 if (force || lock != LockType.CUSTOM) {
470 translateAxisGizmo.setType(6);
473 translateAxisGizmo.setType(0);
476 translateAxisGizmo.setType(1);
479 translateAxisGizmo.setType(2);
482 translateAxisGizmo.setType(3);
485 translateAxisGizmo.setType(4);
488 translateAxisGizmo.setType(5);
496 public boolean mousePressed(MouseEvent e) {
498 getDefaultAction().mousePressed(e);
504 public boolean mouseReleased(MouseEvent e) {
506 getDefaultAction().mouseReleased(e);
512 public boolean mouseWheelMoved(MouseWheelEvent e) {
514 getDefaultAction().mouseWheelMoved(e);
520 public boolean mouseClicked(MouseEvent e) {
522 getDefaultAction().mouseClicked(e);
525 if (state == ToolState.ROUTING) {
527 if (e.getClickCount() == 1) {
528 if (e.getButton() == MouseEvent.BUTTON1) {
529 if (this.added.size() > 0) {
531 setLockType(LockType.NONE,true);
539 throw new RuntimeException("kjf");
540 // // user was selecting position of branch
541 // lastPoint.set(startPoint);
542 // controlPoints.add(new Point3d(startPoint));
543 // if (selectionLine != null)
544 // selectionLine.removeFromParent();
545 // selectionLine = null;
547 } else if (e.getButton() ==MouseEvent.BUTTON2){
549 } else if (e.getButton() == MouseEvent.BUTTON3){
553 } catch(Exception err) {
554 err.printStackTrace();
556 } else if (state == ToolState.SELECTING_POSITION) {
557 if (e.getClickCount() == 1 && e.getButton() == MouseEvent.BUTTON1) {
558 int type = panel.getPickType();
559 //panel.setPickType(0);
560 panel.setPickType(5);
561 vtkProp[] picked = panel.pick(e.getX(), e.getY());
562 panel.setPickType(type);
563 PositionType position = terminalSelectionGizmo.getPickedPosition(picked);
564 if (position != null) {
565 terminalSelectionGizmo.deattach();
567 if (position == PositionType.SPLIT) {
568 activateSplit(startComponent.getControlPoint());
569 } else if (position == PositionType.NEXT || position == PositionType.PREVIOUS) {
570 reversed = position == PositionType.PREVIOUS;
571 activateNextPrev(startComponent.getControlPoint());
573 panel.useDefaultAction();
575 } catch (Exception err) {
576 ExceptionUtils.logAndShowError(err);
577 panel.useDefaultAction();
581 } else if (state == ToolState.SELECTING_SPLIT) {
582 if (e.getClickCount() == 1 && e.getButton() == MouseEvent.BUTTON1) {
583 Tuple3d t = splitPointSelectionGizmo.getSplitPoint();
584 splitPointSelectionGizmo.deattach();
586 panel.useDefaultAction();
590 Vector3d pos = new Vector3d(t);
591 InlineComponent branchSplit = ComponentUtils.createBranchSplit((InlineComponent)startComponent, pos);
592 PipeControlPoint branchSplitCP = branchSplit.getControlPoint();
594 PipeRun newRun = new PipeRun();
595 String n = root.getUniqueName("PipeRun");
597 root.addChild(newRun);
598 PipeControlPoint pcp = new PipeControlPoint(branchSplit,newRun);
599 branchSplitCP.children.add(pcp);
600 pcp.parent = branchSplitCP;
601 pcp.setWorldOrientation(branchSplitCP.getWorldOrientation());
602 pcp.setWorldPosition(branchSplitCP.getWorldPosition());
603 startComponent = branchSplit;
605 } catch (Exception err) {
606 ExceptionUtils.logAndShowError(err);
607 panel.useDefaultAction();
614 private void updateConstraints() {
615 detector.clearConstraints();
616 constraintPointGizmo.clearPositions();
617 if (hoverObject == null) {
618 if (constraintPointGizmo.isAttached())
619 constraintPointGizmo.deattach();
622 if (hoverObject instanceof Nozzle) {
623 Nozzle n = (Nozzle)hoverObject;
624 detector.addContraintPoint(new Point3d(n.getWorldPosition()));
625 } else if (hoverObject instanceof InlineComponent) {
626 InlineComponent c = (InlineComponent)hoverObject;
627 Point3d p1 = new Point3d();
628 Point3d p2 = new Point3d();
630 detector.addContraintPoint(p1);
631 detector.addContraintPoint(p2);
632 detector.addContraintPoint(new Point3d(c.getWorldPosition()));
633 } else if (hoverObject instanceof TurnComponent) {
634 TurnComponent n = (TurnComponent)hoverObject;
635 detector.addContraintPoint(new Point3d(n.getWorldPosition()));
637 if (detector.getConstraintPoints().size() > 0) {
638 for (Point3d p : detector.getConstraintPoints()) {
639 constraintPointGizmo.addPosition(new Vector3d(p));
641 if (constraintPointGizmo.isAttached())
642 constraintPointGizmo.deattach();
643 constraintPointGizmo.attach(panel);
648 public boolean mouseMoved(MouseEvent e) {
650 getDefaultAction().mouseMoved(e);
653 step = ((e.getModifiers() & MouseEvent.CTRL_MASK) > 0);
654 update(e.getX(), e.getY());
659 public boolean mouseDragged(MouseEvent e) {
661 getDefaultAction().mouseDragged(e);
668 private List<INode> isOverNode(int x, int y) {
669 List<INode> nodes = new ArrayList<INode>();
670 vtkProp picked[] = panel.pick2(x, y);
672 for (int i = 0; i < picked.length; i++) {
673 nodes.add(nodeMap.getNode(picked[i]));
679 INode hoverObject = null;
681 private void updateRouting(double x, double y) {
682 // if(input.keyPressed(KeyEvent.VK_ESCAPE)) {
683 // controlPoints.clear();
687 // if (input.keyPressed(KeyEvent.VK_C)) {
688 // useCamera = !useCamera;
689 // cameraAction.setChecked(useCamera);
692 //panel.getDefaultAction().update();
700 Ray ray = vtkUtil.createMouseRay(panel.getRenderer(),x, y);
701 Vector3d o = new Vector3d(ray.pos);
702 Vector3d d = ray.dir;
705 if (!updateCurrentPoint(o, d))
707 //Point3d startPoint = new Point3d();
708 double mu[] = new double[2];
714 List<INode> hover = isOverNode((int)x,(int)y);
715 if (hover.size() > 0) {
716 hoverObject = hover.get(0);
720 // System.out.println(hoverObject + " " + getLast());
721 if (hoverObject != null) {
722 if (hoverObject.equals(getLast()) ) {
724 for (int i = 1; i < hover.size(); i++) {
725 hoverObject = hover.get(i);
726 if (!getLast().equals(hoverObject)) {
735 // System.out.println(hoverObject);
736 if (hoverObject != null) {
738 if (lock == LockType.NONE) {
739 if (hoverObject instanceof Nozzle && endingToNozzle(hoverObject,o,d)) {
740 endTo = (Nozzle)hoverObject;
741 } else if (hoverObject instanceof InlineComponent && ((InlineComponent)hoverObject).isVariableLength()) {
742 endTo = (InlineComponent)hoverObject;
743 endType = endingToStraight(endTo,mu,o,d);
746 } else if (hoverObject instanceof PipelineComponent && (endPort = endingToComponent(hoverObject,o,d)) != null) {
747 endTo = (PipelineComponent)hoverObject;
752 if (hoverObject instanceof InlineComponent && ((InlineComponent)hoverObject).isVariableLength() && (endType = endingLockToStraight(hoverObject,mu)) != null) {
753 endTo = (InlineComponent)hoverObject;
754 } else if (hoverObject instanceof Nozzle && endingLockToNozzle(hoverObject)) {
755 endTo = (Nozzle)hoverObject;
756 } else if ((hoverObject instanceof PipelineComponent) && ((endPort = endingLockToComponent(hoverObject)) != null)) {
757 endTo = (PipelineComponent)hoverObject;
762 if (added.contains(endTo))
772 private boolean updateCurrentPoint(Vector3d o, Vector3d d) {
774 Vector3d point = new Vector3d(this.previousPosition);
778 MathTools.intersectStraightStraight(point, new Vector3d(1.0,0.0,0.0), o,d, currentPosition, new Vector3d());
780 currentPosition.x = Math.round(istep * currentPosition.x) / istep;
781 BigDecimal bx = new BigDecimal(currentPosition.x);
782 bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);
783 currentPosition.x = bx.doubleValue();
787 MathTools.intersectStraightStraight(point, new Vector3d(0.0,1.0,0.0), o,d, currentPosition, new Vector3d());
789 currentPosition.y = Math.round(istep * currentPosition.y) / istep;
790 BigDecimal bx = new BigDecimal(currentPosition.y);
791 bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);
792 currentPosition.y = bx.doubleValue();
796 MathTools.intersectStraightStraight(point, new Vector3d(0.0,0.0,1.0), o,d, currentPosition, new Vector3d());
798 currentPosition.z = Math.round(istep * currentPosition.z) / istep;
799 BigDecimal bx = new BigDecimal(currentPosition.z);
800 bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);
801 currentPosition.z = bx.doubleValue();
804 MathTools.intersectStraightPlane(o, d, point, new Vector3d(0.0,0.0,1.0), currentPosition);
807 MathTools.intersectStraightPlane(o, d, point, new Vector3d(0.0,1.0,0.0), currentPosition);
810 MathTools.intersectStraightPlane(o, d, point, new Vector3d(1.0,0.0,0.0), currentPosition);
813 Vector3d normal = new Vector3d(panel.getRenderer().GetActiveCamera().GetDirectionOfProjection());
816 MathTools.intersectStraightPlane(o, d, point, normal, currentPosition);
819 MathTools.intersectStraightStraight(point, new Vector3d(direction), o,d, currentPosition, new Vector3d());
820 double dist = MathTools.distanceFromPlane(new Vector3d(currentPosition), direction, previousPosition);
822 currentPosition.set(previousPosition);
830 private Vector3d getLockDir() {
835 return new Vector3d(1,0,0);
837 return new Vector3d(0,1,0);
839 return new Vector3d(0,0,1);
844 private void updateRoute(Vector3d o, Vector3d d) {
845 detector.clearConstraintHighlights();
846 Point3d previousPipePoint = new Point3d(previousPosition);
848 if (lock == LockType.NONE) {
849 Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint));
851 currentPosition = new Vector3d(p);
852 s += detector.getSnapString();
855 Vector3d dir = new Vector3d(currentPosition);
856 dir.sub(previousPipePoint);
857 Point3d p = detector.getPointSnap(new Vector3d(previousPipePoint), dir);
859 currentPosition = new Vector3d(p);
860 s += detector.getSnapString();
863 // System.out.println(previousPosition + " -> " + currentPosition);
864 // double dist = MathTools.distance(previousPosition, currentPosition);
865 // if (dist < pipeRun.getTurnRadius()) {
867 // Vector3d v = new Vector3d(currentPosition);
868 // v.sub(previousPosition);
869 // double vl = v.length();
870 // if (vl > MathTools.NEAR_ZERO) {
876 // v.scale(pipeRun.getTurnRadius());
877 // v.add(previousPosition);
878 // currentPosition.set(v);
881 updateCurrentPoint();
882 s += currentPosition.toString();
886 vtkTextActor infoActor;
888 private void setInfoText(String text) {
889 //System.out.println(text);
890 if (infoActor == null) {
891 infoActor = new vtkTextActor();
892 infoActor.GetTextProperty().SetColor(0.0, 0.0, 0.0);
893 infoActor.GetTextProperty().ShadowOff();
894 infoActor.GetTextProperty().ItalicOff();
895 infoActor.GetTextProperty().BoldOff();
896 infoActor.GetTextProperty().SetFontSize(18);
897 infoActor.GetTextProperty().Delete();
898 infoActor.GetProperty().SetColor(0.0, 0.0, 0.0);
899 infoActor.GetProperty().Delete();
902 infoActor.SetPosition(10,10);
903 panel.getRenderer().AddActor(infoActor);
905 infoActor.SetInput(text);
908 private boolean endingToNozzle(INode nozzleNode,Vector3d o, Vector3d d) {
909 Nozzle nozzle = (Nozzle)nozzleNode;
910 PipeControlPoint pcp =nozzle.getControlPoint();
911 if (pcp != null && (pcp.getNext() != null ||
912 pcp.getPrevious() != null))
913 return false; // nozzle is already connected to pipe
914 currentPosition = pcp.getWorldPosition();
915 Point3d previousPipePoint = new Point3d(previousPosition);
916 Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint));
918 if (MathTools.distance(p, currentPosition) > NOZZLE_SNAP_DISTANCE) {
923 updateCurrentPoint();
925 setInfoText("Connect to nozzle " + currentPosition);
930 private PositionType endingToStraight(INode straightNode, double mu[], Vector3d o, Vector3d d) {
931 InlineComponent s = (InlineComponent)straightNode;
933 Point3d sStart = new Point3d();
934 Point3d sEnd = new Point3d();
935 s.getEnds(sStart, sEnd);
936 //detector.clearConstraintHighlights();
938 Point3d previousPipePoint = new Point3d(previousPosition);
939 Point3d currentPipePoint = new Point3d(currentPosition);
941 if (lock == LockType.NONE) {
942 Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint));
944 currentPosition = new Vector3d(p);
945 // snapping is detected, check if snapped point can create branch with straight
946 PositionType t = endingLockToStraight(s, mu);
949 // if not, we'll have to remove highlight that was added when snapped point was detected
950 detector.clearConstraintHighlights();
953 Vector3d sDir = new Vector3d(sEnd);
955 MathTools.intersectStraightStraight(sStart, sDir, o, d, currentPosition, new Point3d(), mu);
959 throw new RuntimeException("Lock shouldn't be on");
963 updateCurrentPoint();
965 // branch point must lie between straight's ends. If connection point is exactly
966 // on straight end user may want to connect pipes to each other
967 // TODO : take account sizes of inline components)
969 boolean connectPrev = false;
970 boolean connectNext = false;
971 boolean branch = false;
975 else if (mu[0] > 0.9) {
981 PipeControlPoint pcp = s.getControlPoint();
982 if (pcp.getPrevious() != null)
984 } else if (connectNext) {
985 PipeControlPoint pcp = s.getControlPoint();
986 if (pcp.getNext() != null)
989 Vector3d dir = s.getControlPoint().getPathLegDirection(Direction.NEXT);
990 Vector3d currDir = getLast().getControlPoint().getPathLegDirection(Direction.NEXT);
993 double dot = dir.dot(currDir);
994 System.out.println(dot + " " + currDir + " " + dir);
995 if (dot > 0.95 || dot < -0.95) {
996 // pipes are almost in the same direction, creating a branch is not feasible.
1004 if (connectNext || connectPrev)
1005 info += "Connect pipes :";
1007 info += "Create a Branch :";
1009 setInfoText(info + currentPosition + " " + Math.max(0.0, Math.min(mu[0], 1.0)));
1011 currentPosition.set(sEnd);
1012 updateCurrentPoint();
1013 return PositionType.NEXT;
1014 } else if (connectPrev){
1015 currentPosition.set(sStart);
1016 updateCurrentPoint();
1017 return PositionType.PREVIOUS;
1018 } else if (branch) {
1019 return PositionType.SPLIT;
1021 currentPosition.set(currentPipePoint);
1022 updateCurrentPoint();
1028 private PipeControlPoint endingToComponent(INode componentNode, Vector3d o, Vector3d d) {
1029 PipelineComponent component = (PipelineComponent)componentNode;
1030 PipeControlPoint pcp = component.getControlPoint();
1031 if (component instanceof EndComponent) {
1032 if (pcp.getNext() != null || pcp.getPrevious() != null)
1035 } else if (component instanceof TurnComponent) {
1036 if (pcp.getNext() == null || pcp.getPrevious() == null)
1039 } else if (component instanceof InlineComponent) {
1040 // TODO : scan all empty pcps of the component and select closest one.
1041 if (pcp.getNext() == null || pcp.getPrevious() == null)
1049 private PositionType endingLockToStraight(INode straightNode, double mu[]) {
1050 InlineComponent s = (InlineComponent)straightNode;
1051 Point3d sStart = new Point3d();
1052 Point3d sEnd = new Point3d();
1053 s.getControlPoint().getInlineControlPointEnds(sStart, sEnd);
1054 Vector3d sDir = new Vector3d(sEnd);
1056 Vector3d dir = new Vector3d(currentPosition);
1057 Point3d prev = new Point3d(previousPosition);
1059 // intersection point in pipe where branch would be inserted to
1060 Vector3d branchPoint = new Vector3d();
1061 // intersection point in straight pipe that is currently routed
1062 Vector3d routePoint = new Vector3d();
1063 MathTools.intersectStraightStraight(sStart, sDir, new Vector3d(prev), dir, branchPoint, routePoint, mu);
1064 routePoint.sub(branchPoint);
1065 // startPoint of branch must be between pipe ends
1066 // TODO : take account sizes of elbows (or other components)
1067 // branch point must be between pipe ends and intersection points must be quite close to each other
1068 if (mu[0] > 0.0 && mu[0] < 1.0 && routePoint.lengthSquared() < BRANCH_SNAP_DISTANCE) {
1069 currentPosition.set(branchPoint);
1071 updateCurrentPoint();
1073 setInfoText("Create a branch (l) :" + currentPosition + " " + Math.max(0.0, Math.min(mu[0], 1.0)) + " " + routePoint.lengthSquared());
1074 return PositionType.SPLIT;
1079 private boolean endingLockToNozzle(INode nozzleNode) {
1080 Nozzle nozzle = (Nozzle)nozzleNode;
1081 Vector3d dir = new Vector3d(currentPosition);
1082 Point3d prev = new Point3d(previousPosition);
1084 Vector3d nozzleLoc = nozzle.getWorldPosition();
1085 double u[] = new double[1];
1086 Vector3d closest = MathTools.closestPointOnStraight(new Point3d(nozzleLoc), new Point3d(prev), new Vector3d(dir), u);
1087 double dist = MathTools.distanceSquared(nozzleLoc,closest);
1088 if (dist < BRANCH_SNAP_DISTANCE) {
1089 // FIXME : directions should be checked (insert an elbow)
1090 currentPosition.set(nozzleLoc);
1091 updateCurrentPoint();
1092 setInfoText("Connect to nozzle (l) :" + currentPosition);
1095 //System.out.println(u[0]);
1099 private PipeControlPoint endingLockToComponent(INode componentNode) {
1100 // we'll must scan all free pcp's and their direction to accept the connection.
1104 private void addPoint() throws Exception {
1105 InlineComponent previous = (InlineComponent)getLast();
1106 PipeControlPoint previousCP = previous.getControlPoint();
1107 TurnComponent turn = ComponentUtils.createTurn(root);
1108 InlineComponent straight = ComponentUtils.createStraight(root);
1109 PipeControlPoint turnCP = turn.getControlPoint();
1110 PipeControlPoint straightCP = straight.getControlPoint();
1111 straight.setName(pipeRun.getUniqueName("Pipe"));
1112 turn.setName(pipeRun.getUniqueName("Elbow"));
1113 pipeRun.addChild(turn);
1114 pipeRun.addChild(straight);
1116 added.add(straight);
1118 turnCP.setDeletable(false); // mark turnCP nonDeletable so that PipingRules won't delete it immediately.
1121 previousCP.setNext(turnCP);
1122 turnCP.setPrevious(previousCP);
1123 turnCP.setNext(straightCP);
1124 straightCP.setPrevious(turnCP);
1126 previousCP.setPrevious(turnCP);
1127 turnCP.setNext(previousCP);
1128 turnCP.setPrevious(straightCP);
1129 straightCP.setNext(turnCP);
1132 turnCP.setWorldPosition(currentPosition);
1133 turnCP.setTurnAngle(0.0);
1134 turnCP.setLength(0.0);
1135 straightCP.setWorldPosition(currentPosition);
1136 straightCP.setLength(0.0);
1138 setPreviousPosition(currentPosition);
1139 updateCurrentPoint();
1146 * Updates tool graphics for current point
1148 private void updateCurrentPoint() {
1149 InlineComponent straight = (InlineComponent)added.get(added.size()-1);
1150 // TODO: the inline length is from previous update step.
1153 l = straight.getPrevious().getControlPoint().getInlineLength();
1155 l = straight.getNext().getControlPoint().getInlineLength();
1156 Vector3d v = new Vector3d();
1157 v.sub(currentPosition, previousPosition);
1158 double length = v.length();
1159 if (length > MathTools.NEAR_ZERO) {
1160 v.scale(1.0/length);
1161 v.scale(0.5*(length+l));
1162 v.add(previousPosition);
1163 straight.getControlPoint().setWorldPosition(v);
1164 straight.getControlPoint().setLength(length);
1167 PipingRules.positionUpdate(straight.getControlPoint(),false);
1168 } catch (Exception e) {
1169 // TODO Auto-generated catch block
1170 e.printStackTrace();
1174 private PipelineComponent getLast() {
1175 if (added.size() == 0)
1176 return startComponent;
1177 return added.get(added.size()-1);
1182 * Removes last point from pipeline
1184 public void removePoint() {
1185 if (added.size() < 3)
1187 InlineComponent straight = (InlineComponent)added.remove(added.size()-1);
1188 TurnComponent turn = (TurnComponent)added.remove(added.size()-1);
1189 straight.getControlPoint().remove();
1190 turn.getControlPoint().remove();
1191 if (added.size() > 1) {
1192 setPreviousPosition(added.get(added.size()-2).getWorldPosition());
1194 setPreviousPosition(startComponent.getWorldPosition());
1195 if (direction != null)
1196 setLockType(LockType.CUSTOM, true);
1201 private void endPiping() throws Exception {
1202 state = ToolState.NOT_ACTIVE;
1204 if (endTo != null) {
1205 ComponentUtils.connect(getLast(), endTo, endType, currentPosition);
1207 panel.useDefaultAction();