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);
98 detector = new org.simantics.g3d.vtk.swt.ConstraintDetector(panel);
101 public void setComponent(PipelineComponent component) {
102 this.startComponent = component;
104 if (this.startComponent.getNext() == null)
105 allowed.add(PositionType.NEXT);
106 if (this.startComponent.getPrevious() == null && !(this.startComponent instanceof Nozzle))
107 allowed.add(PositionType.PREVIOUS);
108 if (this.startComponent instanceof InlineComponent && !this.startComponent.getControlPoint().isFixed())
109 allowed.add(PositionType.SPLIT);
110 setEnabled(allowed.size() > 0);
113 public void deattach() {
115 startComponent = null;
116 nodeMap.commit("Route pipe");
122 public void attach() {
123 if (startComponent == null)
127 ThreadUtils.asyncExec(panel.getThreadQueue(), new Runnable() {
132 } catch (Exception e) {
134 ExceptionUtils.logAndShowError(e);
142 // private void attachUI() {
143 // //panel.setCursor(activeCursor);
144 // translateAxisGizmo.attach(panel.GetRenderer());
147 private void deattachUI() {
148 //panel.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
150 if (translateAxisGizmo.isAttached())
151 translateAxisGizmo.deattach();
152 if (splitPointSelectionGizmo.isAttached())
153 splitPointSelectionGizmo.deattach();
154 if (terminalSelectionGizmo.isAttached())
155 terminalSelectionGizmo.deattach();
156 if (infoActor != null) {
157 panel.getRenderer().RemoveActor(infoActor);
164 private List<PipelineComponent> added = new ArrayList<PipelineComponent>();
167 public boolean keyPressed(KeyEvent e) {
168 if (e.getKeyCode() == KeyEvent.VK_ESCAPE)
169 panel.useDefaultAction();
170 if (lock != LockType.CUSTOM) {
171 if ((e.getModifiersEx() & KeyEvent.SHIFT_DOWN_MASK) > 0) {
172 if (e.getKeyCode() == KeyEvent.VK_X) {
173 if (lock != LockType.XY && lock != LockType.XZ) {
174 setLockType(LockType.XY, false);
175 } else if (lock == LockType.XY) {
176 setLockType(LockType.XZ, false);
178 setLockType(LockType.NONE, false);
181 if (e.getKeyCode() == KeyEvent.VK_Y) {
182 if (lock != LockType.XY && lock != LockType.YZ) {
183 setLockType(LockType.XY, false);
184 } else if (lock == LockType.XY) {
185 setLockType(LockType.YZ, false);
187 setLockType(LockType.NONE, false);
190 if (e.getKeyCode() == KeyEvent.VK_Z) {
191 if (lock != LockType.XZ && lock != LockType.YZ) {
192 setLockType(LockType.XZ, false);
193 } else if (lock == LockType.XZ) {
194 setLockType(LockType.YZ, false);
196 setLockType(LockType.NONE, false);
200 if (e.getKeyCode() == KeyEvent.VK_X) {
201 if (lock != LockType.X)
202 setLockType(LockType.X,false);
204 setLockType(LockType.NONE,false);
206 if (e.getKeyCode() == KeyEvent.VK_Y) {
207 if (lock != LockType.Y)
208 setLockType(LockType.Y,false);
210 setLockType(LockType.NONE, false);
212 if (e.getKeyCode() == KeyEvent.VK_Z) {
213 if (lock != LockType.Z)
214 setLockType(LockType.Z, false);
216 setLockType(LockType.NONE, false);
220 if (e.getKeyCode() == KeyEvent.VK_C) {
221 useDefault = !useDefault;
222 System.out.println("UseDefault " + useDefault);
233 private void update() {
236 private void update(double x, double y) {
239 return; // TODO : throw Exception?
242 case SELECTING_POSITION:
244 case SELECTING_SPLIT:
253 boolean startRemovable = false;
255 private void activate() throws Exception {
256 state = ToolState.INITIALIZING;
259 if (allowed.size() == 1) {
260 pipeRun = startComponent.getPipeRun();
261 PipeControlPoint start = startComponent.getControlPoint();
262 boolean requiresBranching = false;
263 if (start.getNext() == null)
265 else if (start.getPrevious() == null) {
268 requiresBranching = true;
271 if (requiresBranching) {
272 activateSplit(start);
274 activateNextPrev(start);
276 } else if (allowed.size() == 0) {
277 panel.useDefaultAction();
278 state = ToolState.NOT_ACTIVE;
281 terminalSelectionGizmo.setComponent(startComponent, allowed);
282 terminalSelectionGizmo.attach(panel);
283 state = ToolState.SELECTING_POSITION;
291 private void activateNextPrev(PipeControlPoint start) throws Exception{
292 if (!reversed && start.isDualInline())
293 start = start.getSubPoint().get(0);
294 else if (reversed && start.isDualSub())
295 start = start.parent;
297 pipeRun = start.getPipeRun();
298 setPreviousPosition(start.getWorldPosition());
300 boolean startWithTurn = false;
301 if (startComponent instanceof Nozzle) {
302 direction = startComponent.getControlPoint().getDirectedControlPointDirection();
303 lock = LockType.CUSTOM;
304 } else if (startComponent instanceof PipelineComponent){
305 if (startComponent instanceof InlineComponent) {
306 direction = startComponent.getControlPoint().getPathLegDirection(reversed ? Direction.PREVIOUS : Direction.NEXT);
307 lock = LockType.CUSTOM;
308 if (((InlineComponent) startComponent).isVariableLength()) {
309 startWithTurn = true;
311 lock = LockType.NONE;
313 Vector3d v = new Vector3d();
315 start.getControlPointEnds(v, previousPosition);
317 start.getControlPointEnds(previousPosition,v);
319 } else if (startComponent instanceof TurnComponent) {
320 if (start.isFixed()) {
321 direction = startComponent.getControlPoint().getPathLegDirection(reversed ? Direction.PREVIOUS : Direction.NEXT);
322 lock = LockType.CUSTOM;
325 lock = LockType.NONE;
327 } else if (startComponent instanceof EndComponent) {
328 throw new Exception("Not supported");
332 throw new Exception("Not supported");
334 currentPosition = new Vector3d(previousPosition);
335 state = ToolState.ROUTING;
336 if (direction != null) {
337 direction.normalize();
340 startRemovable = start.isDeletable();
341 start.setDeletable(false);
346 if (direction != null)
347 currentPosition.add(direction);
348 InlineComponent straight = ComponentUtils.createStraight(root);
349 PipeControlPoint straightCP = straight.getControlPoint();
350 straight.setName(pipeRun.getUniqueName("Pipe"));
351 pipeRun.addChild(straight);
355 start.setNext(straightCP);
356 straightCP.setPrevious(start);
358 start.setPrevious(straightCP);
359 straightCP.setNext(start);
362 translateAxisGizmo.attach(panel);
363 setPreviousPosition(previousPosition);
364 updateCurrentPoint();
367 private void setPreviousPosition(Vector3d v) {
368 previousPosition = new Vector3d(v);
369 if (translateAxisGizmo.isAttached())
370 translateAxisGizmo.setPosition(previousPosition);
373 private void activateBranch(PipeControlPoint start) throws Exception{
374 pipeRun = start.getPipeRun();
375 setPreviousPosition(start.getWorldPosition());
378 lock = LockType.NONE;
380 currentPosition = new Vector3d(previousPosition);
381 state = ToolState.ROUTING;
382 if (direction != null) {
383 direction.normalize();
386 startRemovable = start.isDeletable();
387 start.setDeletable(false);
390 if (direction != null)
391 currentPosition.add(direction);
392 InlineComponent straight = ComponentUtils.createStraight(root);
393 PipeControlPoint straightCP = straight.getControlPoint();
394 straight.setName(pipeRun.getUniqueName("Pipe"));
395 pipeRun.addChild(straight);
399 start.setNext(straightCP);
400 straightCP.setPrevious(start);
403 start.setPrevious(straightCP);
404 straightCP.setNext(start);
408 translateAxisGizmo.attach(panel);
409 setPreviousPosition(previousPosition);
410 updateCurrentPoint();
413 private void activateSplit(PipeControlPoint start) throws Exception{
414 Point3d p1 = new Point3d();
415 Point3d p2 = new Point3d();
416 start.getInlineControlPointEnds(p1, p2);
417 splitPointSelectionGizmo.setSplit(p1, p2);
418 splitPointSelectionGizmo.attach(panel);
419 state = ToolState.SELECTING_SPLIT;
421 public void deactivate() {
422 for (PipelineComponent component : added) {
423 component.getControlPoint().setDeletable(true);
427 startComponent.getControlPoint().setDeletable(startRemovable);
431 setLockType(LockType.NONE, true);
432 startComponent = null;
438 currentPosition = null;
439 previousPosition = null;
440 startRemovable = false;
441 detector.clearConstraintHighlights();
442 state = ToolState.NOT_ACTIVE;
448 private void setLockType(LockType type, boolean force) {
449 if (force || lock != LockType.CUSTOM) {
455 translateAxisGizmo.setType(6);
458 translateAxisGizmo.setType(0);
461 translateAxisGizmo.setType(1);
464 translateAxisGizmo.setType(2);
467 translateAxisGizmo.setType(3);
470 translateAxisGizmo.setType(4);
473 translateAxisGizmo.setType(5);
481 public boolean mousePressed(MouseEvent e) {
483 getDefaultAction().mousePressed(e);
489 public boolean mouseReleased(MouseEvent e) {
491 getDefaultAction().mouseReleased(e);
497 public boolean mouseWheelMoved(MouseWheelEvent e) {
499 getDefaultAction().mouseWheelMoved(e);
505 public boolean mouseClicked(MouseEvent e) {
507 getDefaultAction().mouseClicked(e);
510 if (state == ToolState.ROUTING) {
512 if (e.getClickCount() == 1) {
513 if (e.getButton() == MouseEvent.BUTTON1) {
514 if (this.added.size() > 0) {
516 setLockType(LockType.NONE,true);
524 throw new RuntimeException("kjf");
525 // // user was selecting position of branch
526 // lastPoint.set(startPoint);
527 // controlPoints.add(new Point3d(startPoint));
528 // if (selectionLine != null)
529 // selectionLine.removeFromParent();
530 // selectionLine = null;
532 } else if (e.getButton() ==MouseEvent.BUTTON2){
534 } else if (e.getButton() == MouseEvent.BUTTON3){
538 } catch(Exception err) {
539 err.printStackTrace();
541 } else if (state == ToolState.SELECTING_POSITION) {
542 if (e.getClickCount() == 1 && e.getButton() == MouseEvent.BUTTON1) {
543 int type = panel.getPickType();
544 //panel.setPickType(0);
545 panel.setPickType(5);
546 vtkProp[] picked = panel.pick(e.getX(), e.getY());
547 panel.setPickType(type);
548 PositionType position = terminalSelectionGizmo.getPickedPosition(picked);
549 if (position != null) {
550 terminalSelectionGizmo.deattach();
552 if (position == PositionType.SPLIT) {
553 activateSplit(startComponent.getControlPoint());
554 } else if (position == PositionType.NEXT || position == PositionType.PREVIOUS) {
555 reversed = position == PositionType.PREVIOUS;
556 activateNextPrev(startComponent.getControlPoint());
558 panel.useDefaultAction();
560 } catch (Exception err) {
561 ExceptionUtils.logAndShowError(err);
562 panel.useDefaultAction();
566 } else if (state == ToolState.SELECTING_SPLIT) {
567 if (e.getClickCount() == 1 && e.getButton() == MouseEvent.BUTTON1) {
568 Tuple3d t = splitPointSelectionGizmo.getSplitPoint();
569 splitPointSelectionGizmo.deattach();
571 panel.useDefaultAction();
575 Vector3d pos = new Vector3d(t);
576 InlineComponent branchSplit = ComponentUtils.createBranchSplit((InlineComponent)startComponent, pos);
577 PipeControlPoint branchSplitCP = branchSplit.getControlPoint();
579 PipeRun newRun = new PipeRun();
580 String n = root.getUniqueName("PipeRun");
582 root.addChild(newRun);
583 PipeControlPoint pcp = new PipeControlPoint(branchSplit,newRun);
584 branchSplitCP.children.add(pcp);
585 pcp.parent = branchSplitCP;
586 pcp.setWorldOrientation(branchSplitCP.getWorldOrientation());
587 pcp.setWorldPosition(branchSplitCP.getWorldPosition());
588 startComponent = branchSplit;
590 } catch (Exception err) {
591 ExceptionUtils.logAndShowError(err);
592 panel.useDefaultAction();
599 private void updateConstraints() {
600 detector.clearConstraints();
601 if (hoverObject == null) {
604 if (hoverObject instanceof Nozzle) {
605 Nozzle n = (Nozzle)hoverObject;
606 detector.addContraintPoint(new Point3d(n.getWorldPosition()));
607 } else if (hoverObject instanceof InlineComponent) {
608 InlineComponent c = (InlineComponent)hoverObject;
609 Point3d p1 = new Point3d();
610 Point3d p2 = new Point3d();
612 detector.addContraintPoint(p1);
613 detector.addContraintPoint(p2);
614 } else if (hoverObject instanceof TurnComponent) {
615 TurnComponent n = (TurnComponent)hoverObject;
616 detector.addContraintPoint(new Point3d(n.getWorldPosition()));
621 public boolean mouseMoved(MouseEvent e) {
623 getDefaultAction().mouseMoved(e);
626 step = ((e.getModifiers() & MouseEvent.CTRL_MASK) > 0);
627 update(e.getX(), e.getY());
632 public boolean mouseDragged(MouseEvent e) {
634 getDefaultAction().mouseDragged(e);
641 private List<INode> isOverNode(int x, int y) {
642 List<INode> nodes = new ArrayList<INode>();
643 vtkProp picked[] = panel.pick2(x, y);
645 for (int i = 0; i < picked.length; i++) {
646 nodes.add(nodeMap.getNode(picked[i]));
652 INode hoverObject = null;
654 private void updateRouting(double x, double y) {
655 // if(input.keyPressed(KeyEvent.VK_ESCAPE)) {
656 // controlPoints.clear();
660 // if (input.keyPressed(KeyEvent.VK_C)) {
661 // useCamera = !useCamera;
662 // cameraAction.setChecked(useCamera);
665 //panel.getDefaultAction().update();
673 Ray ray = vtkUtil.createMouseRay(panel.getRenderer(),x, y);
674 Vector3d o = new Vector3d(ray.pos);
675 Vector3d d = ray.dir;
678 if (!updateCurrentPoint(o, d))
680 //Point3d startPoint = new Point3d();
681 double mu[] = new double[2];
687 List<INode> hover = isOverNode((int)x,(int)y);
688 if (hover.size() > 0) {
689 hoverObject = hover.get(0);
693 // System.out.println(hoverObject + " " + getLast());
694 if (hoverObject != null) {
695 if (hoverObject.equals(getLast()) ) {
697 for (int i = 1; i < hover.size(); i++) {
698 hoverObject = hover.get(i);
699 if (!getLast().equals(hoverObject)) {
708 // System.out.println(hoverObject);
709 if (hoverObject != null) {
711 if (lock == LockType.NONE) {
712 if (hoverObject instanceof Nozzle && endingToNozzle(hoverObject,o,d)) {
713 endTo = (Nozzle)hoverObject;
714 } else if (hoverObject instanceof InlineComponent && ((InlineComponent)hoverObject).isVariableLength()) {
715 endTo = (InlineComponent)hoverObject;
716 endType = endingToStraight(endTo,mu,o,d);
717 } else if (hoverObject instanceof PipelineComponent && (endPort = endingToComponent(hoverObject,o,d)) != null) {
718 endTo = (PipelineComponent)hoverObject;
723 if (hoverObject instanceof InlineComponent && ((InlineComponent)hoverObject).isVariableLength() && (endType = endingLockToStraight(hoverObject,mu)) != null) {
724 endTo = (InlineComponent)hoverObject;
725 } else if (hoverObject instanceof Nozzle && endingLockToNozzle(hoverObject)) {
726 endTo = (Nozzle)hoverObject;
727 } else if ((hoverObject instanceof PipelineComponent) && ((endPort = endingLockToComponent(hoverObject)) != null)) {
728 endTo = (PipelineComponent)hoverObject;
733 if (added.contains(endTo))
743 private boolean updateCurrentPoint(Vector3d o, Vector3d d) {
745 Vector3d point = new Vector3d(this.previousPosition);
749 MathTools.intersectStraightStraight(point, new Vector3d(1.0,0.0,0.0), o,d, currentPosition, new Vector3d());
751 currentPosition.x = Math.round(istep * currentPosition.x) / istep;
752 BigDecimal bx = new BigDecimal(currentPosition.x);
753 bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);
754 currentPosition.x = bx.doubleValue();
758 MathTools.intersectStraightStraight(point, new Vector3d(0.0,1.0,0.0), o,d, currentPosition, new Vector3d());
760 currentPosition.y = Math.round(istep * currentPosition.y) / istep;
761 BigDecimal bx = new BigDecimal(currentPosition.y);
762 bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);
763 currentPosition.y = bx.doubleValue();
767 MathTools.intersectStraightStraight(point, new Vector3d(0.0,0.0,1.0), o,d, currentPosition, new Vector3d());
769 currentPosition.z = Math.round(istep * currentPosition.z) / istep;
770 BigDecimal bx = new BigDecimal(currentPosition.z);
771 bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);
772 currentPosition.z = bx.doubleValue();
775 MathTools.intersectStraightPlane(o, d, point, new Vector3d(0.0,0.0,1.0), currentPosition);
778 MathTools.intersectStraightPlane(o, d, point, new Vector3d(0.0,1.0,0.0), currentPosition);
781 MathTools.intersectStraightPlane(o, d, point, new Vector3d(1.0,0.0,0.0), currentPosition);
784 Vector3d normal = new Vector3d(panel.getRenderer().GetActiveCamera().GetDirectionOfProjection());
787 MathTools.intersectStraightPlane(o, d, point, normal, currentPosition);
790 MathTools.intersectStraightStraight(point, new Vector3d(direction), o,d, currentPosition, new Vector3d());
791 double dist = MathTools.distanceFromPlane(new Vector3d(currentPosition), direction, previousPosition);
793 currentPosition.set(previousPosition);
801 private Vector3d getLockDir() {
806 return new Vector3d(1,0,0);
808 return new Vector3d(0,1,0);
810 return new Vector3d(0,0,1);
815 private void updateRoute(Vector3d o, Vector3d d) {
816 detector.clearConstraintHighlights();
817 Point3d previousPipePoint = new Point3d(previousPosition);
819 if (lock == LockType.NONE) {
820 Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint));
822 currentPosition = new Vector3d(p);
823 s += detector.getSnapString();
826 Vector3d dir = new Vector3d(currentPosition);
827 dir.sub(previousPipePoint);
828 Point3d p = detector.getPointSnap(new Vector3d(previousPipePoint), dir);
830 currentPosition = new Vector3d(p);
831 s += detector.getSnapString();
834 // System.out.println(previousPosition + " -> " + currentPosition);
835 // double dist = MathTools.distance(previousPosition, currentPosition);
836 // if (dist < pipeRun.getTurnRadius()) {
838 // Vector3d v = new Vector3d(currentPosition);
839 // v.sub(previousPosition);
840 // double vl = v.length();
841 // if (vl > MathTools.NEAR_ZERO) {
847 // v.scale(pipeRun.getTurnRadius());
848 // v.add(previousPosition);
849 // currentPosition.set(v);
852 updateCurrentPoint();
853 s += currentPosition.toString();
857 vtkTextActor infoActor;
859 private void setInfoText(String text) {
860 //System.out.println(text);
861 if (infoActor == null) {
862 infoActor = new vtkTextActor();
863 infoActor.GetTextProperty().SetColor(0.0, 0.0, 0.0);
864 infoActor.GetTextProperty().ShadowOff();
865 infoActor.GetTextProperty().ItalicOff();
866 infoActor.GetTextProperty().BoldOff();
867 infoActor.GetTextProperty().SetFontSize(18);
868 infoActor.GetTextProperty().Delete();
869 infoActor.GetProperty().SetColor(0.0, 0.0, 0.0);
870 infoActor.GetProperty().Delete();
873 infoActor.SetPosition(10,10);
874 panel.getRenderer().AddActor(infoActor);
876 infoActor.SetInput(text);
879 private boolean endingToNozzle(INode nozzleNode,Vector3d o, Vector3d d) {
880 Nozzle nozzle = (Nozzle)nozzleNode;
881 PipeControlPoint pcp =nozzle.getControlPoint();
882 if (pcp != null && (pcp.getNext() != null ||
883 pcp.getPrevious() != null))
884 return false; // nozzle is already connected to pipe
885 currentPosition = pcp.getWorldPosition();
886 Point3d previousPipePoint = new Point3d(previousPosition);
887 Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint));
889 if (MathTools.distance(p, currentPosition) > NOZZLE_SNAP_DISTANCE) {
894 updateCurrentPoint();
896 setInfoText("Connect to nozzle " + currentPosition);
901 private PositionType endingToStraight(INode straightNode, double mu[], Vector3d o, Vector3d d) {
902 InlineComponent s = (InlineComponent)straightNode;
904 Point3d sStart = new Point3d();
905 Point3d sEnd = new Point3d();
906 s.getEnds(sStart, sEnd);
907 //detector.clearConstraintHighlights();
909 Point3d previousPipePoint = new Point3d(previousPosition);
911 if (lock == LockType.NONE) {
912 Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint));
914 currentPosition = new Vector3d(p);
915 // snapping is detected, check if snapped point can create branch with straight
916 PositionType t = endingLockToStraight(s, mu);
919 // if not, we'll have to remove highlight that was added when snapped point was detected
920 detector.clearConstraintHighlights();
924 Vector3d sDir = new Vector3d(sEnd);
926 MathTools.intersectStraightStraight(sStart, sDir, o, d, currentPosition, new Point3d(), mu);
930 throw new RuntimeException("Lock shouldn't be on");
934 updateCurrentPoint();
936 // branch point must lie between straight's ends. If connection point is exactly
937 // on straight end user may want to connect pipes to each other
938 // TODO : take account sizes of inline components)
939 // TODO : actually make connection if its detected
940 boolean connectPrev = false;
941 boolean connectNext = false;
944 currentPosition.set(sStart);
947 else if (mu[0] > 1.0) {
948 currentPosition.set(sEnd);
951 boolean connect = false;
953 PipeControlPoint pcp = s.getControlPoint();
954 if (pcp.getPrevious() == null)
956 } else if (connectNext) {
957 PipeControlPoint pcp = s.getControlPoint();
958 if (pcp.getNext() == null)
962 updateCurrentPoint();
965 info += "Connect pipes :";
967 info += "Make Branch :";
969 setInfoText(info + currentPosition + " " + Math.max(0.0, Math.min(mu[0], 1.0)));
972 return PositionType.NEXT;
974 return PositionType.PREVIOUS;
978 return PositionType.SPLIT;
982 private PipeControlPoint endingToComponent(INode componentNode, Vector3d o, Vector3d d) {
983 PipelineComponent component = (PipelineComponent)componentNode;
984 PipeControlPoint pcp = component.getControlPoint();
985 if (component instanceof EndComponent) {
986 if (pcp.getNext() != null || pcp.getPrevious() != null)
989 } else if (component instanceof TurnComponent) {
990 if (pcp.getNext() == null || pcp.getPrevious() == null)
993 } else if (component instanceof InlineComponent) {
994 // TODO : scan all empty pcps of the component and select closest one.
995 if (pcp.getNext() == null || pcp.getPrevious() == null)
1003 private PositionType endingLockToStraight(INode straightNode, double mu[]) {
1004 InlineComponent s = (InlineComponent)straightNode;
1005 Point3d sStart = new Point3d();
1006 Point3d sEnd = new Point3d();
1007 s.getControlPoint().getInlineControlPointEnds(sStart, sEnd);
1008 Vector3d sDir = new Vector3d(sEnd);
1010 Vector3d dir = new Vector3d(currentPosition);
1011 Point3d prev = new Point3d(previousPosition);
1013 // intersection point in pipe where branch would be inserted to
1014 Vector3d branchPoint = new Vector3d();
1015 // intersection point in straight pipe that is currently routed
1016 Vector3d routePoint = new Vector3d();
1017 MathTools.intersectStraightStraight(sStart, sDir, new Vector3d(prev), dir, branchPoint, routePoint, mu);
1018 routePoint.sub(branchPoint);
1019 // startPoint of branch must be between pipe ends
1020 // TODO : take account sizes of elbows (or other components)
1021 // branch point must be between pipe ends and intersection points must be quite close to each other
1022 if (mu[0] > 0.0 && mu[0] < 1.0 && routePoint.lengthSquared() < BRANCH_SNAP_DISTANCE) {
1023 currentPosition.set(branchPoint);
1025 updateCurrentPoint();
1027 setInfoText("Make branch (l) :" + currentPosition + " " + Math.max(0.0, Math.min(mu[0], 1.0)) + " " + routePoint.lengthSquared());
1028 return PositionType.SPLIT;
1033 private boolean endingLockToNozzle(INode nozzleNode) {
1034 Nozzle nozzle = (Nozzle)nozzleNode;
1035 Vector3d dir = new Vector3d(currentPosition);
1036 Point3d prev = new Point3d(previousPosition);
1038 Vector3d nozzleLoc = nozzle.getWorldPosition();
1039 double u[] = new double[1];
1040 Vector3d closest = MathTools.closestPointOnStraight(new Point3d(nozzleLoc), new Point3d(prev), new Vector3d(dir), u);
1041 double dist = MathTools.distanceSquared(nozzleLoc,closest);
1042 if (dist < BRANCH_SNAP_DISTANCE) {
1043 // FIXME : directions should be checked (insert an elbow)
1044 currentPosition.set(nozzleLoc);
1045 updateCurrentPoint();
1046 setInfoText("Connect to nozzle (l) :" + currentPosition);
1049 //System.out.println(u[0]);
1053 private PipeControlPoint endingLockToComponent(INode componentNode) {
1054 // we'll must scan all free pcp's and their direction to accept the connection.
1058 private void addPoint() throws Exception {
1059 InlineComponent previous = (InlineComponent)getLast();
1060 PipeControlPoint previousCP = previous.getControlPoint();
1061 TurnComponent turn = ComponentUtils.createTurn(root);
1062 InlineComponent straight = ComponentUtils.createStraight(root);
1063 PipeControlPoint turnCP = turn.getControlPoint();
1064 PipeControlPoint straightCP = straight.getControlPoint();
1065 straight.setName(pipeRun.getUniqueName("Pipe"));
1066 turn.setName(pipeRun.getUniqueName("Elbow"));
1067 pipeRun.addChild(turn);
1068 pipeRun.addChild(straight);
1070 added.add(straight);
1072 turnCP.setDeletable(false); // mark turnCP nonDeletable so that PipingRules won't delete it immediately.
1075 previousCP.setNext(turnCP);
1076 turnCP.setPrevious(previousCP);
1077 turnCP.setNext(straightCP);
1078 straightCP.setPrevious(turnCP);
1080 previousCP.setPrevious(turnCP);
1081 turnCP.setNext(previousCP);
1082 turnCP.setPrevious(straightCP);
1083 straightCP.setNext(turnCP);
1086 turnCP.setWorldPosition(currentPosition);
1087 turnCP.setTurnAngle(0.0);
1088 turnCP.setLength(0.0);
1089 straightCP.setWorldPosition(currentPosition);
1090 straightCP.setLength(0.0);
1092 setPreviousPosition(currentPosition);
1093 updateCurrentPoint();
1100 * Updates tool graphics for current point
1102 private void updateCurrentPoint() {
1103 InlineComponent straight = (InlineComponent)added.get(added.size()-1);
1104 // TODO: the inline length is from previous update step.
1107 l = straight.getPrevious().getControlPoint().getInlineLength();
1109 l = straight.getNext().getControlPoint().getInlineLength();
1110 Vector3d v = new Vector3d();
1111 v.sub(currentPosition, previousPosition);
1112 double length = v.length();
1113 if (length > MathTools.NEAR_ZERO) {
1114 v.scale(1.0/length);
1115 v.scale(0.5*(length+l));
1116 v.add(previousPosition);
1117 straight.getControlPoint().setWorldPosition(v);
1118 straight.getControlPoint().setLength(length);
1121 PipingRules.positionUpdate(straight.getControlPoint(),false);
1122 } catch (Exception e) {
1123 // TODO Auto-generated catch block
1124 e.printStackTrace();
1128 private PipelineComponent getLast() {
1129 if (added.size() == 0)
1130 return startComponent;
1131 return added.get(added.size()-1);
1136 * Removes last point from pipeline
1138 public void removePoint() {
1139 if (added.size() < 3)
1141 InlineComponent straight = (InlineComponent)added.remove(added.size()-1);
1142 TurnComponent turn = (TurnComponent)added.remove(added.size()-1);
1143 straight.getControlPoint().remove();
1144 turn.getControlPoint().remove();
1145 if (added.size() > 1) {
1146 setPreviousPosition(added.get(added.size()-2).getWorldPosition());
1148 setPreviousPosition(startComponent.getWorldPosition());
1149 if (direction != null)
1150 setLockType(LockType.CUSTOM, true);
1155 private void endPiping() throws Exception {
1156 state = ToolState.NOT_ACTIVE;
1158 if (endTo != null) {
1159 ComponentUtils.connect(getLast(), endTo, endType, currentPosition);
1161 panel.useDefaultAction();