package org.simantics.plant3d.actions; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import java.awt.event.MouseWheelEvent; import java.math.BigDecimal; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.vecmath.Point3d; import javax.vecmath.Tuple3d; import javax.vecmath.Vector3d; import org.simantics.db.Resource; import org.simantics.g3d.math.MathTools; import org.simantics.g3d.math.Ray; import org.simantics.g3d.scenegraph.NodeMap; import org.simantics.g3d.scenegraph.base.INode; import org.simantics.g3d.tools.ConstraintDetector; import org.simantics.g3d.vtk.gizmo.TranslateAxisGizmo; import org.simantics.g3d.vtk.swt.InteractiveVtkComposite; import org.simantics.g3d.vtk.swt.vtkSwtAction; import org.simantics.g3d.vtk.utils.vtkUtil; import org.simantics.plant3d.Activator; import org.simantics.plant3d.gizmo.ConstraintPointGizmo; import org.simantics.plant3d.gizmo.SplitPointSelectionGizmo; import org.simantics.plant3d.gizmo.TerminalSelectionGizmo; import org.simantics.plant3d.scenegraph.EndComponent; import org.simantics.plant3d.scenegraph.InlineComponent; import org.simantics.plant3d.scenegraph.Nozzle; import org.simantics.plant3d.scenegraph.P3DRootNode; import org.simantics.plant3d.scenegraph.PipeRun; import org.simantics.plant3d.scenegraph.PipelineComponent; import org.simantics.plant3d.scenegraph.TurnComponent; import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint; import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint.Direction; import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint.PositionType; import org.simantics.plant3d.scenegraph.controlpoint.PipingRules; import org.simantics.plant3d.utils.ComponentUtils; import org.simantics.utils.threads.ThreadUtils; import org.simantics.utils.ui.ExceptionUtils; import vtk.vtkProp; import vtk.vtkTextActor; public class RoutePipeAction extends vtkSwtAction { enum LockType { X, Y, Z, XY, YZ, XZ, NONE, CUSTOM }; LockType lock = LockType.NONE; boolean lockForced; private double BRANCH_SNAP_DISTANCE = 0.05; private double NOZZLE_SNAP_DISTANCE = 0.05; private static double BRANCH_DOT_PRODUCT = 0.95; // dot product value used for prevent branch creation private static double ALIGN_DOT_PRODUCT = 0.99; // dot product for creating turn when connecting pipes private double istep = 10.0; private int decimals = 2; private P3DRootNode root; protected PipelineComponent startComponent; protected PipeRun pipeRun; private boolean allowBranches; protected TranslateAxisGizmo translateAxisGizmo = new TranslateAxisGizmo(); private SplitPointSelectionGizmo splitPointSelectionGizmo; private ConstraintPointGizmo constraintPointGizmo; private TerminalSelectionGizmo terminalSelectionGizmo; private NodeMap nodeMap; protected enum ToolState{NOT_ACTIVE, INITIALIZING, SELECTING_POSITION, SELECTING_SPLIT, ROUTING}; protected ToolState state = ToolState.NOT_ACTIVE; private ConstraintDetector detector;// = new DummyConstraintDetector(); protected boolean useDefault = false; protected Vector3d direction = null; protected Vector3d previousPosition = null; protected Vector3d currentPosition = null; boolean step = false; PipelineComponent endTo = null; PositionType endType = null; PipeControlPoint endPort = null; boolean reversed = false; private Set allowed = new HashSet(); public RoutePipeAction(InteractiveVtkComposite panel, P3DRootNode root) { this(panel,root, true); } public RoutePipeAction(InteractiveVtkComposite panel, P3DRootNode root, boolean allowBranches) { super(panel); this.root = root; this.allowBranches = allowBranches; setText("Route Pipe"); setImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/Straight.png")); nodeMap = root.getNodeMap(); splitPointSelectionGizmo = new SplitPointSelectionGizmo(panel); terminalSelectionGizmo = new TerminalSelectionGizmo(panel); constraintPointGizmo = new ConstraintPointGizmo(panel); detector = new org.simantics.g3d.vtk.swt.ConstraintDetector(panel); } public void setComponent(PipelineComponent component) { this.startComponent = component; allowed.clear(); if (this.startComponent.getNext() == null) allowed.add(PositionType.NEXT); if (this.startComponent.getPrevious() == null && !(this.startComponent instanceof Nozzle)) allowed.add(PositionType.PREVIOUS); if (allowBranches && this.startComponent instanceof InlineComponent && !this.startComponent.getControlPoint().isFixedLength()) allowed.add(PositionType.SPLIT); setEnabled(allowed.size() > 0); } public void deattach() { deactivate(); startComponent = null; deattachUI(); super.deattach(); panel.refresh(); } public void attach() { if (startComponent == null) return; super.attach(); ThreadUtils.asyncExec(panel.getThreadQueue(), new Runnable() { public void run() { // attachUI(); try { activate(); } catch (Exception e) { deattach(); ExceptionUtils.logAndShowError(e); } } }); } // private void attachUI() { // //panel.setCursor(activeCursor); // translateAxisGizmo.attach(panel.GetRenderer()); // } private void deattachUI() { //panel.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); panel.lock(); if (translateAxisGizmo.isAttached()) translateAxisGizmo.deattach(); if (splitPointSelectionGizmo.isAttached()) splitPointSelectionGizmo.deattach(); if (terminalSelectionGizmo.isAttached()) terminalSelectionGizmo.deattach(); if (constraintPointGizmo.isAttached()) constraintPointGizmo.deattach(); if (infoActor != null) { panel.getRenderer().RemoveActor(infoActor); infoActor.Delete(); infoActor = null; } panel.unlock(); } protected List added = new ArrayList(); @Override public boolean keyPressed(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_ESCAPE) panel.useDefaultAction(); if (lock != LockType.CUSTOM || !lockForced) { if ((e.getModifiersEx() & KeyEvent.SHIFT_DOWN_MASK) > 0) { if (e.getKeyCode() == KeyEvent.VK_X) { if (lock != LockType.XY && lock != LockType.XZ) { setLockType(LockType.XY, false); } else if (lock == LockType.XY) { setLockType(LockType.XZ, false); } else { setLockType(LockType.NONE, false); } } if (e.getKeyCode() == KeyEvent.VK_Y) { if (lock != LockType.XY && lock != LockType.YZ) { setLockType(LockType.XY, false); } else if (lock == LockType.XY) { setLockType(LockType.YZ, false); } else { setLockType(LockType.NONE, false); } } if (e.getKeyCode() == KeyEvent.VK_Z) { if (lock != LockType.XZ && lock != LockType.YZ) { setLockType(LockType.XZ, false); } else if (lock == LockType.XZ) { setLockType(LockType.YZ, false); } else { setLockType(LockType.NONE, false); } } } else { if (e.getKeyCode() == KeyEvent.VK_X) { if (lock != LockType.X) setLockType(LockType.X,false); else setLockType(LockType.NONE,false); } if (e.getKeyCode() == KeyEvent.VK_Y) { if (lock != LockType.Y) setLockType(LockType.Y,false); else setLockType(LockType.NONE, false); } if (e.getKeyCode() == KeyEvent.VK_Z) { if (lock != LockType.Z) setLockType(LockType.Z, false); else setLockType(LockType.NONE, false); } if (e.getKeyCode() == KeyEvent.VK_L && direction != null) { if (lock != LockType.CUSTOM) setLockType(LockType.CUSTOM, false); else setLockType(LockType.NONE, false); } } } if (e.getKeyCode() == KeyEvent.VK_C) { useDefault = !useDefault; if (useDefault) setInfoText("Rotating camera"); System.out.println("UseDefault " + useDefault); } update(); return true; } private void update() { panel.refresh(); } private void update(double x, double y) { switch (state) { case NOT_ACTIVE: return; // TODO : throw Exception? case INITIALIZING: return; case SELECTING_POSITION: return; case SELECTING_SPLIT: return; case ROUTING: updateRouting(x,y); break; } return; } boolean startRemovable = false; protected void activate() throws Exception { state = ToolState.INITIALIZING; added.clear(); if (allowed.size() == 1) { pipeRun = startComponent.getPipeRun(); PipeControlPoint start = startComponent.getControlPoint(); boolean requiresBranching = false; if (start.getNext() == null) reversed = false; else if (start.getPrevious() == null) { reversed = true; } else { requiresBranching = true; } if (requiresBranching) { activateSplit(start); } else { activateNextPrev(start); } } else if (allowed.size() == 0) { panel.useDefaultAction(); state = ToolState.NOT_ACTIVE; return; } else { terminalSelectionGizmo.setComponent(startComponent, allowed); terminalSelectionGizmo.attach(panel); state = ToolState.SELECTING_POSITION; update(); } } protected void activateNextPrev(PipeControlPoint start) throws Exception{ if (!reversed && start.isDualInline()) start = start.getSubPoint().get(0); else if (reversed && start.isDualSub()) start = start.parent; pipeRun = start.getPipeRun(); setPreviousPosition(start.getWorldPosition()); boolean startWithTurn = false; if (startComponent instanceof Nozzle) { direction = startComponent.getControlPoint().getDirectedControlPointDirection(); lock = LockType.CUSTOM; lockForced = true; } else if (startComponent instanceof PipelineComponent){ if (startComponent instanceof InlineComponent) { direction = startComponent.getControlPoint().getPathLegDirection(reversed ? Direction.PREVIOUS : Direction.NEXT); lock = LockType.CUSTOM; lockForced = true; if (((InlineComponent) startComponent).isVariableLength()) { startWithTurn = true; direction = null; lock = LockType.NONE; lockForced = false; } Vector3d v = new Vector3d(); if (!reversed) { start.getControlPointEnds(v, previousPosition); } else { start.getControlPointEnds(previousPosition,v); } } else if (startComponent instanceof TurnComponent) { if (start.asFixedAngle()) { direction = startComponent.getControlPoint().getPathLegDirection(reversed ? Direction.PREVIOUS : Direction.NEXT); lock = LockType.CUSTOM; lockForced = start.isFixedAngle(); } else { direction = null; lock = LockType.NONE; lockForced = false; } } else if (startComponent instanceof EndComponent) { throw new Exception("Not supported"); } } else { throw new Exception("Not supported"); } currentPosition = new Vector3d(previousPosition); state = ToolState.ROUTING; if (direction != null) { direction.normalize(); } startRemovable = start.isDeletable(); start.setDeletable(false); if (startWithTurn) { addPoint(); } else { if (direction != null) currentPosition.add(direction); InlineComponent straight = ComponentUtils.createStraight(root); PipeControlPoint straightCP = straight.getControlPoint(); straight.setName(pipeRun.getUniqueName("Pipe")); pipeRun.addChild(straight); added.add(straight); if (!reversed) { start.setNext(straightCP); straightCP.setPrevious(start); } else { start.setPrevious(straightCP); straightCP.setNext(start); } } translateAxisGizmo.attach(panel); setPreviousPosition(previousPosition); updateCurrentPoint(); } protected void setPreviousPosition(Vector3d v) { previousPosition = new Vector3d(v); if (translateAxisGizmo.isAttached()) translateAxisGizmo.setPosition(previousPosition); } private void activateBranch(PipeControlPoint start) throws Exception{ pipeRun = start.getPipeRun(); setPreviousPosition(start.getWorldPosition()); direction = null; lock = LockType.NONE; currentPosition = new Vector3d(previousPosition); state = ToolState.ROUTING; if (direction != null) { direction.normalize(); } startRemovable = start.isDeletable(); start.setDeletable(false); if (direction != null) currentPosition.add(direction); InlineComponent straight = ComponentUtils.createStraight(root); PipeControlPoint straightCP = straight.getControlPoint(); straight.setName(pipeRun.getUniqueName("Pipe")); pipeRun.addChild(straight); added.add(straight); if (!reversed) { start.setNext(straightCP); straightCP.setPrevious(start); } else { start.setPrevious(straightCP); straightCP.setNext(start); } translateAxisGizmo.attach(panel); setPreviousPosition(previousPosition); updateCurrentPoint(); } private void activateSplit(PipeControlPoint start) throws Exception{ Point3d p1 = new Point3d(); Point3d p2 = new Point3d(); start.getInlineControlPointEnds(p1, p2); splitPointSelectionGizmo.setSplit(p1, p2); splitPointSelectionGizmo.attach(panel); state = ToolState.SELECTING_SPLIT; } public void deactivate() { if (added.size() > 0) { for (PipelineComponent component : added) { component.getControlPoint().setDeletable(true); } for (PipelineComponent comp : added) { PipingRules.requestUpdate(comp.getControlPoint()); } try { PipingRules.update(); nodeMap.commit("Route pipe"); } catch (Exception e) { ExceptionUtils.logAndShowError(e); } added.clear(); } startComponent.getControlPoint().setDeletable(startRemovable); direction = null; setLockType(LockType.NONE, true); startComponent = null; endTo = null; endPort = null; endType = null; pipeRun = null; allowed.clear(); currentPosition = null; previousPosition = null; startRemovable = false; detector.clearConstraintHighlights(); state = ToolState.NOT_ACTIVE; setEnabled(false); } private void setLockType(LockType type, boolean force) { if (force || (lock != LockType.CUSTOM || !lockForced) ) { lock = type; switch (lock) { case CUSTOM: case NONE: translateAxisGizmo.setType(6); break; case X: translateAxisGizmo.setType(0); break; case Y: translateAxisGizmo.setType(1); break; case Z: translateAxisGizmo.setType(2); break; case XY: translateAxisGizmo.setType(3); break; case XZ: translateAxisGizmo.setType(4); break; case YZ: translateAxisGizmo.setType(5); break; } } } @Override public boolean mousePressed(MouseEvent e) { if (useDefault) { getDefaultAction().mousePressed(e); } return true; } @Override public boolean mouseReleased(MouseEvent e) { if (useDefault) { getDefaultAction().mouseReleased(e); } return true; } @Override public boolean mouseWheelMoved(MouseWheelEvent e) { if (useDefault) { getDefaultAction().mouseWheelMoved(e); } return true; } @Override public boolean mouseClicked(MouseEvent e) { if (useDefault) { getDefaultAction().mouseClicked(e); return true; } if (state == ToolState.ROUTING) { try { if (e.getClickCount() == 1) { if (e.getButton() == MouseEvent.BUTTON1) { if (this.added.size() > 0) { setLockType(LockType.NONE,true); if (endTo != null) { endPiping(); } else { addPoint(); } } else { throw new RuntimeException("RoutePipeAction initlialization has been failed, no added components found"); // // user was selecting position of branch // lastPoint.set(startPoint); // controlPoints.add(new Point3d(startPoint)); // if (selectionLine != null) // selectionLine.removeFromParent(); // selectionLine = null; } } else if (e.getButton() ==MouseEvent.BUTTON2){ updateConstraints(); } else if (e.getButton() == MouseEvent.BUTTON3){ endPiping(); } } } catch(Exception err) { err.printStackTrace(); } } else if (state == ToolState.SELECTING_POSITION) { if (e.getClickCount() == 1 && e.getButton() == MouseEvent.BUTTON1) { int type = panel.getPickType(); //panel.setPickType(0); panel.setPickType(5); vtkProp[] picked = panel.pick(e.getX(), e.getY()); panel.setPickType(type); PositionType position = terminalSelectionGizmo.getPickedPosition(picked); if (position != null) { terminalSelectionGizmo.deattach(); try { if (position == PositionType.SPLIT) { activateSplit(startComponent.getControlPoint()); } else if (position == PositionType.NEXT || position == PositionType.PREVIOUS) { reversed = position == PositionType.PREVIOUS; activateNextPrev(startComponent.getControlPoint()); } else { panel.useDefaultAction(); } } catch (Exception err) { ExceptionUtils.logAndShowError(err); panel.useDefaultAction(); } } } } else if (state == ToolState.SELECTING_SPLIT) { if (e.getClickCount() == 1 && e.getButton() == MouseEvent.BUTTON1) { Tuple3d t = splitPointSelectionGizmo.getSplitPoint(); splitPointSelectionGizmo.deattach(); if (t == null) { panel.useDefaultAction(); return true; } try { Vector3d pos = new Vector3d(t); InlineComponent branchSplit = ComponentUtils.createBranchSplit((InlineComponent)startComponent, pos); PipeControlPoint branchSplitCP = branchSplit.getControlPoint(); reversed = false; PipeRun newRun = new PipeRun(); String n = root.getUniqueName("PipeRun"); newRun.setName(n); root.addChild(newRun); PipeControlPoint pcp = new PipeControlPoint(branchSplit,newRun); branchSplitCP.children.add(pcp); pcp.parent = branchSplitCP; pcp.setWorldOrientation(branchSplitCP.getWorldOrientation()); pcp.setWorldPosition(branchSplitCP.getWorldPosition()); startComponent = branchSplit; activateBranch(pcp); } catch (Exception err) { ExceptionUtils.logAndShowError(err); panel.useDefaultAction(); } } } return true; } private void updateConstraints() { detector.clearConstraints(); constraintPointGizmo.clearPositions(); if (hoverObject == null) { if (constraintPointGizmo.isAttached()) constraintPointGizmo.deattach(); return; } if (hoverObject instanceof Nozzle) { Nozzle n = (Nozzle)hoverObject; detector.addContraintPoint(new Point3d(n.getWorldPosition())); } else if (hoverObject instanceof InlineComponent) { InlineComponent c = (InlineComponent)hoverObject; Point3d p1 = new Point3d(); Point3d p2 = new Point3d(); c.getEnds(p1, p2); detector.addContraintPoint(p1); detector.addContraintPoint(p2); detector.addContraintPoint(new Point3d(c.getWorldPosition())); } else if (hoverObject instanceof TurnComponent) { TurnComponent n = (TurnComponent)hoverObject; detector.addContraintPoint(new Point3d(n.getWorldPosition())); } if (detector.getConstraintPoints().size() > 0) { for (Point3d p : detector.getConstraintPoints()) { constraintPointGizmo.addPosition(new Vector3d(p)); } if (constraintPointGizmo.isAttached()) constraintPointGizmo.deattach(); constraintPointGizmo.attach(panel); } } @Override public boolean mouseMoved(MouseEvent e) { if (useDefault) { getDefaultAction().mouseMoved(e); return true; } step = ((e.getModifiers() & MouseEvent.CTRL_MASK) > 0); update(e.getX(), e.getY()); return true; } @Override public boolean mouseDragged(MouseEvent e) { if (useDefault) getDefaultAction().mouseDragged(e); return true; } private List isOverNode(int x, int y) { List nodes = new ArrayList(); vtkProp picked[] = panel.pick2(x, y); if (picked !=null) { for (int i = 0; i < picked.length; i++) { nodes.add(nodeMap.getNode(picked[i])); } } return nodes; } INode hoverObject = null; protected void updateRouting(double x, double y) { if (useDefault) { //panel.getDefaultAction().update(); return; } endTo = null; endType = null; endPort = null; Ray ray = vtkUtil.createMouseRay(panel.getRenderer(),x, y); Vector3d o = new Vector3d(ray.pos); Vector3d d = ray.dir; if (!updateCurrentPoint(o, d)) return; //Point3d startPoint = new Point3d(); double mu[] = new double[2]; List hover = isOverNode((int)x,(int)y); if (hover.size() > 0) { hoverObject = hover.get(0); } else { hoverObject = null; } // System.out.println(hoverObject + " " + getLast()); if (hoverObject != null) { if (hoverObject.equals(getLast()) ) { boolean set = false; for (int i = 1; i < hover.size(); i++) { hoverObject = hover.get(i); if (!getLast().equals(hoverObject)) { set = true; break; } } if (!set) hoverObject = null; } } // System.out.println(hoverObject); if (hoverObject != null) { if (lock == LockType.NONE) { if (hoverObject instanceof Nozzle && endingToNozzle(hoverObject,o,d)) { endTo = (Nozzle)hoverObject; } else if (hoverObject instanceof InlineComponent && ((InlineComponent)hoverObject).isVariableLength()) { endTo = (InlineComponent)hoverObject; endType = endingToStraight(endTo,mu,o,d); if (endType == null) endTo = null; } else if (hoverObject instanceof PipelineComponent && (endPort = endingToComponent(hoverObject,o,d)) != null) { endTo = (PipelineComponent)hoverObject; } else { updateRoute(o,d); } } else { if (hoverObject instanceof InlineComponent && ((InlineComponent)hoverObject).isVariableLength() && (endType = endingLockToStraight(hoverObject,mu, new Point3d(currentPosition))) != null) { endTo = (InlineComponent)hoverObject; } else if (hoverObject instanceof Nozzle && endingLockToNozzle(hoverObject)) { endTo = (Nozzle)hoverObject; } else if ((hoverObject instanceof PipelineComponent) && ((endPort = endingLockToComponent(hoverObject)) != null)) { endTo = (PipelineComponent)hoverObject; } else { updateRoute(o,d); } } if (added.contains(endTo)) endTo = null; } else { updateRoute(o,d); } panel.refresh(); } protected boolean updateCurrentPoint(Vector3d o, Vector3d d) { Vector3d point = new Vector3d(this.previousPosition); switch(lock) { case X: MathTools.intersectStraightStraight(point, new Vector3d(1.0,0.0,0.0), o,d, currentPosition, new Vector3d()); if (step) { currentPosition.x = Math.round(istep * currentPosition.x) / istep; BigDecimal bx = new BigDecimal(currentPosition.x); bx.setScale(decimals, BigDecimal.ROUND_HALF_UP); currentPosition.x = bx.doubleValue(); } break; case Y: MathTools.intersectStraightStraight(point, new Vector3d(0.0,1.0,0.0), o,d, currentPosition, new Vector3d()); if (step) { currentPosition.y = Math.round(istep * currentPosition.y) / istep; BigDecimal bx = new BigDecimal(currentPosition.y); bx.setScale(decimals, BigDecimal.ROUND_HALF_UP); currentPosition.y = bx.doubleValue(); } break; case Z: MathTools.intersectStraightStraight(point, new Vector3d(0.0,0.0,1.0), o,d, currentPosition, new Vector3d()); if (step) { currentPosition.z = Math.round(istep * currentPosition.z) / istep; BigDecimal bx = new BigDecimal(currentPosition.z); bx.setScale(decimals, BigDecimal.ROUND_HALF_UP); currentPosition.z = bx.doubleValue(); }break; case XY: MathTools.intersectStraightPlane(o, d, point, new Vector3d(0.0,0.0,1.0), currentPosition); break; case XZ: MathTools.intersectStraightPlane(o, d, point, new Vector3d(0.0,1.0,0.0), currentPosition); break; case YZ: MathTools.intersectStraightPlane(o, d, point, new Vector3d(1.0,0.0,0.0), currentPosition); break; case NONE: Vector3d normal = new Vector3d(panel.getRenderer().GetActiveCamera().GetDirectionOfProjection()); normal.normalize(); MathTools.intersectStraightPlane(o, d, point, normal, currentPosition); break; case CUSTOM: MathTools.intersectStraightStraight(point, new Vector3d(direction), o,d, currentPosition, new Vector3d()); double dist = MathTools.distanceFromPlane(new Vector3d(currentPosition), direction, previousPosition); if (dist < 0.0) currentPosition.set(previousPosition); break; default: return false; } return true; } @SuppressWarnings("unused") private Vector3d getLockDir() { switch (lock) { case CUSTOM: return direction; case X: return new Vector3d(1,0,0); case Y: return new Vector3d(0,1,0); case Z: return new Vector3d(0,0,1); default: return null; } } protected void updateRoute(Vector3d o, Vector3d d) { detector.clearConstraintHighlights(); Point3d previousPipePoint = new Point3d(previousPosition); String s = ""; if (lock == LockType.NONE) { Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint)); if (p != null) currentPosition = new Vector3d(p); s += detector.getSnapString(); } else { Vector3d dir = new Vector3d(currentPosition); dir.sub(previousPipePoint); Point3d p = detector.getPointSnap(new Vector3d(previousPipePoint), dir); if (p != null) currentPosition = new Vector3d(p); s += detector.getSnapString(); } // System.out.println(previousPosition + " -> " + currentPosition); // double dist = MathTools.distance(previousPosition, currentPosition); // if (dist < pipeRun.getTurnRadius()) { // s += "Too close"; // Vector3d v = new Vector3d(currentPosition); // v.sub(previousPosition); // double vl = v.length(); // if (vl > MathTools.NEAR_ZERO) { // v.scale(1.0/vl); // } else { // // return; // } // v.scale(pipeRun.getTurnRadius()); // v.add(previousPosition); // currentPosition.set(v); // } updateCurrentPoint(); s += currentPosition.toString(); setInfoText(s); } vtkTextActor infoActor; private void setInfoText(String text) { //System.out.println(text); if (infoActor == null) { infoActor = new vtkTextActor(); infoActor.GetTextProperty().SetColor(0.0, 0.0, 0.0); infoActor.GetTextProperty().ShadowOff(); infoActor.GetTextProperty().ItalicOff(); infoActor.GetTextProperty().BoldOff(); infoActor.GetTextProperty().SetFontSize(18); infoActor.GetTextProperty().Delete(); infoActor.GetProperty().SetColor(0.0, 0.0, 0.0); infoActor.GetProperty().Delete(); infoActor.SetPosition(10,10); panel.getRenderer().AddActor(infoActor); } infoActor.SetInput(text); } private boolean endingToNozzle(INode nozzleNode,Vector3d o, Vector3d d) { Nozzle nozzle = (Nozzle)nozzleNode; PipeControlPoint pcp =nozzle.getControlPoint(); if (pcp != null && (pcp.getNext() != null || pcp.getPrevious() != null)) return false; // nozzle is already connected to pipe currentPosition = pcp.getWorldPosition(); Point3d previousPipePoint = new Point3d(previousPosition); Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint)); if (p != null) { if (MathTools.distance(p, currentPosition) > NOZZLE_SNAP_DISTANCE) { return false; } } updateCurrentPoint(); setInfoText("Connect to nozzle " + currentPosition); return true; } private PositionType endingToStraight(INode straightNode, double mu[], Vector3d o, Vector3d d) { // if (!allowBranches) { // updateCurrentPoint(); // return null; // } InlineComponent s = (InlineComponent)straightNode; Point3d sStart = new Point3d(); Point3d sEnd = new Point3d(); s.getEnds(sStart, sEnd); //detector.clearConstraintHighlights(); Point3d previousPipePoint = new Point3d(previousPosition); Point3d currentPipePoint = new Point3d(currentPosition); //String st = ""; if (lock == LockType.NONE) { Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint)); if (p != null) { currentPosition = new Vector3d(p); // snapping is detected, check if snapped point can create branch with straight PositionType t = endingLockToStraight(s, mu, currentPipePoint); if (t != null) return t; // if not, we'll have to remove highlight that was added when snapped point was detected detector.clearConstraintHighlights(); } Vector3d sDir = new Vector3d(sEnd); sDir.sub(sStart); MathTools.intersectStraightStraight(sStart, sDir, o, d, currentPosition, new Point3d(), mu); } else { throw new RuntimeException("Lock shouldn't be on"); } updateCurrentPoint(); // branch point must lie between straight's ends. If connection point is exactly // on straight end user may want to connect pipes to each other // TODO : take account sizes of inline components) return endingToStraight(mu, s, sStart, sEnd, currentPipePoint); } private PositionType endingToStraight(double mu[], InlineComponent s, Point3d sStart, Point3d sEnd , Point3d currentPipePoint) { String info = ""; boolean connectPrev = false; boolean connectNext = false; boolean branch = false; if (mu[0] < 0.1) { connectPrev = true; } else if (mu[0] > 0.9) { connectNext = true; } if (connectPrev) { PipeControlPoint pcp = s.getControlPoint(); if (pcp.getPrevious() != null) connectPrev = false; } else if (connectNext) { PipeControlPoint pcp = s.getControlPoint(); if (pcp.getNext() != null) connectNext = false; } else { Vector3d dir = s.getControlPoint().getPathLegDirection(Direction.NEXT); Vector3d currDir = getLast().getControlPoint().getPathLegDirection(Direction.NEXT); dir.normalize(); currDir.normalize(); double dot = dir.dot(currDir); System.out.println(dot + " " + currDir + " " + dir); if (dot > BRANCH_DOT_PRODUCT || dot < -BRANCH_DOT_PRODUCT) { // pipes are almost in the same direction, creating a branch is not feasible. branch = false; } else { branch = true; } } if (connectNext || connectPrev) info += "Connect pipes :"; else if (branch) info += "Create a Branch :"; setInfoText(info + currentPosition + " " + Math.max(0.0, Math.min(mu[0], 1.0))); if (connectNext) { currentPosition.set(sEnd); updateCurrentPoint(); return PositionType.NEXT; } else if (connectPrev){ currentPosition.set(sStart); updateCurrentPoint(); return PositionType.PREVIOUS; } else if (branch && allowBranches) { return PositionType.SPLIT; } else { currentPosition.set(currentPipePoint); updateCurrentPoint(); return null; } } private PipeControlPoint endingToComponent(INode componentNode, Vector3d o, Vector3d d) { PipelineComponent component = (PipelineComponent)componentNode; PipeControlPoint pcp = component.getControlPoint(); if (component instanceof EndComponent) { if (pcp.getNext() != null || pcp.getPrevious() != null) return null; return pcp; } else if (component instanceof TurnComponent) { if (pcp.getNext() == null || pcp.getPrevious() == null) return pcp; return null; } else if (component instanceof InlineComponent) { // TODO : scan all empty pcps of the component and select closest one. if (pcp.getNext() == null || pcp.getPrevious() == null) return pcp; return null; } return null; } private PositionType endingLockToStraight(INode straightNode, double mu[], Point3d currentPipePoint) { // if (!allowBranches) { // updateCurrentPoint(); // return null; // } InlineComponent s = (InlineComponent)straightNode; Point3d sStart = new Point3d(); Point3d sEnd = new Point3d(); s.getControlPoint().getInlineControlPointEnds(sStart, sEnd); Vector3d sDir = new Vector3d(sEnd); sDir.sub(sStart); Vector3d dir = new Vector3d(currentPosition); Point3d prev = new Point3d(previousPosition); dir.sub(prev); // intersection point in pipe where branch would be inserted to Vector3d branchPoint = new Vector3d(); // intersection point in straight pipe that is currently routed Vector3d routePoint = new Vector3d(); MathTools.intersectStraightStraight(sStart, sDir, new Vector3d(prev), dir, branchPoint, routePoint, mu); routePoint.sub(branchPoint); // startPoint of branch must be between pipe ends // TODO : take account sizes of elbows (or other components) // branch point must be between pipe ends and intersection points must be quite close to each other if (routePoint.lengthSquared() > BRANCH_SNAP_DISTANCE) return null; return endingToStraight(mu, s, sStart, sEnd, currentPipePoint); // if (mu[0] > 0.0 && mu[0] < 1.0 && routePoint.lengthSquared() < BRANCH_SNAP_DISTANCE) { // currentPosition.set(branchPoint); // // updateCurrentPoint(); // // setInfoText("Create a branch (l) :" + currentPosition + " " + Math.max(0.0, Math.min(mu[0], 1.0)) + " " + routePoint.lengthSquared()); // return PositionType.SPLIT; // } // return null; } private boolean endingLockToNozzle(INode nozzleNode) { Nozzle nozzle = (Nozzle)nozzleNode; Vector3d dir = new Vector3d(currentPosition); Point3d prev = new Point3d(previousPosition); dir.sub(prev); Vector3d nozzleLoc = nozzle.getWorldPosition(); double u[] = new double[1]; Vector3d closest = MathTools.closestPointOnStraight(new Point3d(nozzleLoc), new Point3d(prev), new Vector3d(dir), u); double dist = MathTools.distanceSquared(nozzleLoc,closest); if (dist < BRANCH_SNAP_DISTANCE) { // FIXME : directions should be checked (insert an elbow) currentPosition.set(nozzleLoc); updateCurrentPoint(); setInfoText("Connect to nozzle (l) :" + currentPosition); return true; } //System.out.println(u[0]); return false; } private PipeControlPoint endingLockToComponent(INode componentNode) { // we'll must scan all free pcp's and their direction to accept the connection. return null; } protected void addTurn() throws Exception{ InlineComponent previous = (InlineComponent)getLast(); PipeControlPoint previousCP = previous.getControlPoint(); TurnComponent turn = ComponentUtils.createTurn(root); PipeControlPoint turnCP = turn.getControlPoint(); turn.setName(pipeRun.getUniqueName("Elbow")); pipeRun.addChild(turn); added.add(turn); turnCP.setDeletable(false); // mark turnCP nonDeletable so that PipingRules won't delete it immediately. if (!reversed) { previousCP.setNext(turnCP); turnCP.setPrevious(previousCP); } else { previousCP.setPrevious(turnCP); turnCP.setNext(previousCP); } turnCP.setWorldPosition(currentPosition); turnCP.setTurnAngle(0.0); turnCP.setLength(0.0); } protected void addStraight() throws Exception{ TurnComponent turn = (TurnComponent)getLast(); PipeControlPoint turnCP = turn.getControlPoint(); InlineComponent straight = ComponentUtils.createStraight(root); PipeControlPoint straightCP = straight.getControlPoint(); straight.setName(pipeRun.getUniqueName("Pipe")); pipeRun.addChild(straight); added.add(straight); if (!reversed) { turnCP.setNext(straightCP); straightCP.setPrevious(turnCP); } else { turnCP.setPrevious(straightCP); straightCP.setNext(turnCP); } turnCP.setWorldPosition(currentPosition); turnCP.setTurnAngle(0.0); turnCP.setLength(0.0); straightCP.setWorldPosition(currentPosition); straightCP.setLength(0.0); } protected void addPoint() throws Exception { addTurn(); addStraight(); setPreviousPosition(currentPosition); updateCurrentPoint(); } /** * Updates tool graphics for current point */ protected void updateCurrentPoint() { InlineComponent straight = (InlineComponent)added.get(added.size()-1); // TODO: the inline length is from previous update step. double l; if (!reversed) l = straight.getPrevious().getControlPoint().getInlineLength(); else l = straight.getNext().getControlPoint().getInlineLength(); Vector3d v = new Vector3d(); v.sub(currentPosition, previousPosition); double length = v.length(); if (length > MathTools.NEAR_ZERO) { v.scale(1.0/length); v.scale(0.5*(length+l)); v.add(previousPosition); straight.getControlPoint().setWorldPosition(v); straight.getControlPoint().setLength(length); } try { PipingRules.positionUpdate(straight.getControlPoint(),false); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } private PipelineComponent getLast() { if (added.size() == 0) return startComponent; return added.get(added.size()-1); } /** * Removes last point from pipeline */ public void removePoint() { if (added.size() < 3) return; InlineComponent straight = (InlineComponent)added.remove(added.size()-1); TurnComponent turn = (TurnComponent)added.remove(added.size()-1); straight.getControlPoint().remove(); turn.getControlPoint().remove(); if (added.size() > 1) { setPreviousPosition(added.get(added.size()-2).getWorldPosition()); } else { setPreviousPosition(startComponent.getWorldPosition()); if (direction != null) setLockType(LockType.CUSTOM, true); } } protected void endPiping() throws Exception { state = ToolState.NOT_ACTIVE; if (endTo != null) { if (endType == PositionType.NEXT || endType == PositionType.PREVIOUS && endTo instanceof InlineComponent) { Vector3d dir = endTo.getControlPoint().getPathLegDirection(Direction.NEXT); Vector3d currDir = getLast().getControlPoint().getPathLegDirection(Direction.NEXT); dir.normalize(); currDir.normalize(); double dot = dir.dot(currDir); System.out.println(dot + " " + currDir + " " + dir); if (dot < ALIGN_DOT_PRODUCT && dot> -ALIGN_DOT_PRODUCT) { addTurn(); } } ComponentUtils.connect(getLast(), endTo, endType, currentPosition); } panel.useDefaultAction(); } }