+/*******************************************************************************\r
+ * Copyright (c) 2007 VTT Technical Research Centre of Finland and others.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ * VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package fi.vtt.simantics.processeditor.actions;\r
+\r
+import java.awt.event.KeyEvent;\r
+import java.awt.event.MouseEvent;\r
+import java.math.BigDecimal;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import javax.vecmath.Point3d;\r
+import javax.vecmath.Vector3d;\r
+\r
+import org.eclipse.jface.action.Action;\r
+import org.eclipse.jface.action.IToolBarManager;\r
+import org.eclipse.jface.resource.ImageDescriptor;\r
+import org.simantics.db.Graph;\r
+import org.simantics.db.GraphRequestAdapter;\r
+import org.simantics.db.GraphRequestStatus;\r
+import org.simantics.db.GraphRequestWithResult;\r
+import org.simantics.db.Resource;\r
+import org.simantics.layer0.utils.EntityFactory;\r
+import org.simantics.layer0.utils.IEntity;\r
+import org.simantics.proconf.g3d.actions.InteractiveAction;\r
+import org.simantics.proconf.g3d.base.ConstraintDetector;\r
+import org.simantics.proconf.g3d.base.G3DAPI;\r
+import org.simantics.proconf.g3d.base.G3DTools;\r
+import org.simantics.proconf.g3d.base.MathTools;\r
+import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase;\r
+import org.simantics.proconf.g3d.common.StructuredResourceSelection;\r
+import org.simantics.proconf.g3d.dnd.DropListener;\r
+import org.simantics.proconf.g3d.scenegraph.IGraphicsNode;\r
+import org.simantics.utils.datastructures.Pair;\r
+\r
+import com.jme.renderer.ColorRGBA;\r
+import com.jme.scene.Geometry;\r
+import com.jme.scene.Line;\r
+import com.jme.scene.state.MaterialState;\r
+\r
+import fi.vtt.simantics.processeditor.Activator;\r
+import fi.vtt.simantics.processeditor.ProcessResource;\r
+import fi.vtt.simantics.processeditor.common.ControlPointTools;\r
+import fi.vtt.simantics.processeditor.common.PipeComponentProvider;\r
+import fi.vtt.simantics.processeditor.common.PipingTools2;\r
+import fi.vtt.simantics.processeditor.common.PipingTools2.Direction;\r
+import fi.vtt.simantics.processeditor.dialogs.PipelineDialog;\r
+import fi.vtt.simantics.processeditor.gizmo.PositionSelectionGizmo;\r
+import fi.vtt.simantics.processeditor.stubs.BranchEndControlPoint;\r
+import fi.vtt.simantics.processeditor.stubs.PipeControlPoint;\r
+import fi.vtt.simantics.processeditor.stubs.PipeRun;\r
+import fi.vtt.simantics.processeditor.stubs.PipelineComponent;\r
+import fi.vtt.simantics.processeditor.stubs.VariableLengthInlineComponent;\r
+import fi.vtt.simantics.processeditor.views.ProcessEditor;\r
+\r
+/**\r
+ * Action for Routing Pipes\r
+ * \r
+ * FIXME : does several thing that should be done by PipingTools.\r
+ * TODO : instead of using lines to show route of pipe, generate pipe and change it real-time\r
+ * \r
+ * @author MLMARKO\r
+ *\r
+ */\r
+public class RoutePipeAction extends InteractiveAction implements DropListener, SplitPointListener {\r
+ \r
+ \r
+ private static final ImageDescriptor X_AXIS_ICON = Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/x-axis.png");\r
+ private static final ImageDescriptor Y_AXIS_ICON = Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/y-axis.png");\r
+ private static final ImageDescriptor Z_AXIS_ICON = Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/z-axis.png");\r
+ private static final ImageDescriptor X_PLANE_ICON = Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/x-plane.png");\r
+ private static final ImageDescriptor Y_PLANE_ICON = Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/y-plane.png");\r
+ private static final ImageDescriptor Z_PLANE_ICON = Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/z-plane.png");\r
+ \r
+ private static final ImageDescriptor CAMERA_ICON = Activator.imageDescriptorFromPlugin("org.simantics.proconf.g3d", "icons/eye.png");\r
+ \r
+ \r
+ private Action xAxisAction;\r
+ private Action yAxisAction;\r
+ private Action zAxisAction;\r
+ private Action xPlaneAction;\r
+ private Action yPlaneAction;\r
+ private Action zPlaneAction;\r
+ \r
+ private Action cameraAction;\r
+ \r
+ ConstraintDetector detector = null;\r
+ \r
+ public RoutePipeAction(ThreeDimensionalEditorBase parent) {\r
+ super(parent);\r
+ detector = new ConstraintDetector(parent);\r
+ xAxisAction = new Action("X",Action.AS_RADIO_BUTTON) {\r
+ public void run() {\r
+ if (lock == LockType.X)\r
+ setLockType(LockType.NONE,false);\r
+ else\r
+ setLockType(LockType.X,false);\r
+ }\r
+ };\r
+ xAxisAction.setImageDescriptor(X_AXIS_ICON);\r
+ xAxisAction.setToolTipText("Lock X-Axis");\r
+ yAxisAction = new Action("Y",Action.AS_RADIO_BUTTON) {\r
+ public void run() {\r
+ if (lock == LockType.Y)\r
+ setLockType(LockType.NONE,false);\r
+ else\r
+ setLockType(LockType.Y,false);\r
+ }\r
+ };\r
+ yAxisAction.setImageDescriptor(Y_AXIS_ICON);\r
+ yAxisAction.setToolTipText("Lock Y-Axis");\r
+ zAxisAction = new Action("Z",Action.AS_RADIO_BUTTON) {\r
+ public void run() {\r
+ if (lock == LockType.Z)\r
+ setLockType(LockType.NONE,false);\r
+ else\r
+ setLockType(LockType.Z,false);\r
+ }\r
+ };\r
+ zAxisAction.setImageDescriptor(Z_AXIS_ICON);\r
+ zAxisAction.setToolTipText("Lock Z-Axis");\r
+ xPlaneAction = new Action("X",Action.AS_RADIO_BUTTON) {\r
+ public void run() {\r
+ if (lock == LockType.YZ)\r
+ setLockType(LockType.NONE,false);\r
+ else\r
+ setLockType(LockType.YZ,false);\r
+ }\r
+ };\r
+ xPlaneAction.setImageDescriptor(X_PLANE_ICON);\r
+ xPlaneAction.setToolTipText("Lock X-Plane");\r
+ yPlaneAction = new Action("Y",Action.AS_RADIO_BUTTON) {\r
+ public void run() {\r
+ if (lock == LockType.XZ)\r
+ setLockType(LockType.NONE,false);\r
+ else\r
+ setLockType(LockType.XZ,false);\r
+ }\r
+ };\r
+ yPlaneAction.setImageDescriptor(Y_PLANE_ICON);\r
+ yPlaneAction.setToolTipText("Lock Y-Plane");\r
+ zPlaneAction = new Action("Z",Action.AS_RADIO_BUTTON) {\r
+ public void run() {\r
+ if (lock == LockType.XY)\r
+ setLockType(LockType.NONE,false);\r
+ else\r
+ setLockType(LockType.XY,false);\r
+ }\r
+ };\r
+ zPlaneAction.setImageDescriptor(Z_PLANE_ICON);\r
+ zPlaneAction.setToolTipText("Lock Z-Plane");\r
+ cameraAction = new Action("C", Action.AS_CHECK_BOX) {\r
+ public void run() {\r
+ useCamera = this.isChecked();\r
+ }\r
+ };\r
+ cameraAction.setImageDescriptor(CAMERA_ICON);\r
+ cameraAction.setToolTipText("Use camera");\r
+ splitPointAction = new SelectSplitPointAction(parent,this);\r
+ \r
+ }\r
+ \r
+ public void fillToolBar(IToolBarManager manager) {\r
+ \r
+ manager.add(cameraAction);\r
+ cameraAction.setChecked(useCamera);\r
+ manager.add(xAxisAction);\r
+ manager.add(yAxisAction);\r
+ manager.add(zAxisAction);\r
+ manager.add(xPlaneAction);\r
+ manager.add(yPlaneAction);\r
+ manager.add(zPlaneAction); \r
+ \r
+ }\r
+\r
+ enum LockType {NONE,X,Y,Z,XY,YZ,XZ,CUSTOM};\r
+ LockType lock = LockType.NONE;\r
+ \r
+ private void setLockType(LockType type, boolean force) {\r
+ if (force || lock != LockType.CUSTOM) {\r
+ lock = type;\r
+ }\r
+ xAxisAction.setChecked(false);\r
+ yAxisAction.setChecked(false);\r
+ zAxisAction.setChecked(false);\r
+ xPlaneAction.setChecked(false);\r
+ yPlaneAction.setChecked(false);\r
+ zPlaneAction.setChecked(false);\r
+ xAxisAction.setEnabled(true);\r
+ yAxisAction.setEnabled(true);\r
+ zAxisAction.setEnabled(true);\r
+ xPlaneAction.setEnabled(true);\r
+ yPlaneAction.setEnabled(true);\r
+ zPlaneAction.setEnabled(true);\r
+ switch (lock) {\r
+ case X:\r
+ xAxisAction.setChecked(true);\r
+ break;\r
+ case Y:\r
+ yAxisAction.setChecked(true);\r
+ break;\r
+ case Z:\r
+ zAxisAction.setChecked(true);\r
+ break; \r
+ case XY:\r
+ zPlaneAction.setChecked(true);\r
+ break; \r
+ case XZ:\r
+ yPlaneAction.setChecked(true);\r
+ break; \r
+ case YZ:\r
+ xPlaneAction.setChecked(true);\r
+ break; \r
+ case CUSTOM:\r
+ xAxisAction.setEnabled(false);\r
+ yAxisAction.setEnabled(false);\r
+ zAxisAction.setEnabled(false);\r
+ xPlaneAction.setEnabled(false);\r
+ yPlaneAction.setEnabled(false);\r
+ zPlaneAction.setEnabled(false);\r
+ break;\r
+ }\r
+ }\r
+ \r
+ private double BRANCH_SNAP_DISTANCE = 0.05;\r
+ private double NOZZLE_SNAP_DISTANCE = 0.05;\r
+ \r
+ private double istep = 10.0;\r
+ private int decimals = 2;\r
+ \r
+ private double pipeDiameter = 0.2;\r
+ private double elbowRadius = 0.5;\r
+ private double eps = 0.001;\r
+ \r
+ private ArrayList<Point3d> controlPoints = new ArrayList<Point3d>();\r
+\r
+ private Point3d currentPoint = new Point3d();\r
+ private Point3d lastPoint = new Point3d();\r
+ \r
+ private Vector3d customLockDir = null;\r
+ \r
+ private Line selectionLine;\r
+ private List<Line> pipeShapes = new ArrayList<Line>();\r
+ private MaterialState ms;\r
+ \r
+ \r
+ private Resource selectedPort = null;\r
+ private PositionType selectedType = null;\r
+ private Resource beginComponentResource = null;\r
+ \r
+ private Resource endComponentResource = null;\r
+ private Resource endComponentPort = null;\r
+ private PositionType endPortType = null;\r
+ \r
+ private Resource highlightedResource = null;\r
+ \r
+ private boolean useCamera = false;\r
+ \r
+ private List<Pair<Resource, PositionType>> positions = null;\r
+ \r
+ private SelectSplitPointAction splitPointAction;\r
+ private PositionSelectionGizmo gizmo = null;\r
+ \r
+ \r
+ \r
+ private enum ToolState{NOT_ACTIVE, INITIALIZING, SELECTING_POSITION, SELECTING_SPLIT, ROUTING};\r
+ private ToolState state = ToolState.NOT_ACTIVE;\r
+ \r
+ @Override\r
+ public void activate() {\r
+ state = ToolState.INITIALIZING;\r
+ controlPoints.clear();\r
+ if (beginComponentResource == null) {\r
+ List<IGraphicsNode> mos = parent.getSelectionAdapter().getSelectedObjects();\r
+ if (mos.size() != 1) {\r
+ end();\r
+ return;\r
+ }\r
+ beginComponentResource = mos.get(0).getResource();\r
+ }\r
+ parent.getSession().asyncRead(new GraphRequestAdapter() {\r
+ @Override\r
+ public GraphRequestStatus perform(Graph g) throws Exception {\r
+ positions = checkStartNode(g,beginComponentResource);\r
+ if (positions.size() == 0) {\r
+ positions = null;\r
+ end();\r
+ } else {\r
+ state = ToolState.SELECTING_POSITION;\r
+ }\r
+ return GraphRequestStatus.transactionComplete();\r
+ }\r
+ });\r
+ \r
+ if (ms == null) {\r
+ ms = parent.getRenderingComponent().getDisplaySystem().getRenderer().createMaterialState();\r
+ ms.setEmissive(new ColorRGBA(1.f,1.f,1.f,1.f));\r
+ }\r
+\r
+ }\r
+ \r
+ \r
+\r
+ @Override\r
+ public void deactivate() {\r
+ for (Line l : pipeShapes)\r
+ l.removeFromParent();\r
+ pipeShapes.clear();\r
+ if (selectionLine != null)\r
+ selectionLine.removeFromParent();\r
+ selectionLine = null;\r
+ customLockDir = null;\r
+ \r
+ setLockType(LockType.NONE,true);\r
+ beginComponentResource = null;\r
+ endComponentResource = null;\r
+ detector.clearConstraintHighlights(); \r
+ state = ToolState.NOT_ACTIVE;\r
+ selectedPort = null;\r
+ selectedType = null;\r
+ \r
+ }\r
+ \r
+ private List<Pair<Resource, PositionType>> checkStartNode(Graph g, Resource resource) {\r
+ List<Pair<Resource, PositionType>> positions = new ArrayList<Pair<Resource,PositionType>>();\r
+ \r
+ IEntity beginComponent = EntityFactory.create(g, resource);\r
+ \r
+ if (beginComponent.isInstanceOf(ProcessResource.plant3Dresource.Nozzle)) {\r
+ if (PipingTools2.isFreeNozzle(beginComponent)) {\r
+\r
+ positions.add(new Pair<Resource, PositionType>(beginComponent.getSingleRelatedObject(ProcessResource.plant3Dresource.HasControlPoint).getResource(),PositionType.NEXT));\r
+ } \r
+ } else if (beginComponent.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent)) {\r
+ // variable length inline component is exception from other pipeline components,\r
+ // since a new pipe can branch it\r
+ VariableLengthInlineComponent vlic = new VariableLengthInlineComponent(beginComponent);\r
+ PipeControlPoint pcp = vlic.getControlPoint();\r
+ if (pcp.getNext() == null) {\r
+\r
+ positions.add(new Pair<Resource, PositionType>(pcp.getResource(),PositionType.NEXT)); \r
+ } else if (pcp.getPrevious() == null) {\r
+\r
+ positions.add(new Pair<Resource, PositionType>(pcp.getResource(),PositionType.PREVIOUS));\r
+ }\r
+ positions.add(new Pair<Resource, PositionType>(pcp.getResource(),PositionType.SPLIT));\r
+ } else if (beginComponent.isInstanceOf(ProcessResource.plant3Dresource.EndComponent)) {\r
+ PipelineComponent component = new PipelineComponent(beginComponent); \r
+ PipeControlPoint pcp = component.getControlPoint();\r
+ if (pcp.getNext() == null && pcp.getPrevious() == null) { \r
+ throw new RuntimeException("End component " + beginComponent.getResource() + " is not connected to anything.");\r
+ //positions.add(new Pair<Resource, PositionType>(pcp.getResource(),PositionType.NEXT));\r
+ }\r
+ for (PipeControlPoint p : pcp.getSubPoint()) {\r
+ if (p.getNext() == null && p.getPrevious() == null) {\r
+ positions.add(new Pair<Resource, PositionType>(p.getResource(),PositionType.NEXT));\r
+ }\r
+ }\r
+ } else if (beginComponent.isInstanceOf(ProcessResource.plant3Dresource.PipelineComponent)) {\r
+ \r
+ PipelineComponent component = new PipelineComponent(beginComponent);\r
+ \r
+ PipeControlPoint pcp = component.getControlPoint();\r
+ if (pcp.getNext() == null) {\r
+ positions.add(new Pair<Resource, PositionType>(pcp.getResource(),PositionType.NEXT));\r
+ } else if (pcp.getPrevious() == null) {\r
+ positions.add(new Pair<Resource, PositionType>(pcp.getResource(),PositionType.PREVIOUS));\r
+ }\r
+ if (!beginComponent.isInstanceOf(ProcessResource.plant3Dresource.SizeChangeComponent)||\r
+ !beginComponent.isInstanceOf(ProcessResource.plant3Dresource.OffsetComponent)) {\r
+ for (PipeControlPoint p : pcp.getSubPoint()) {\r
+ if (p.getNext() == null && p.getPrevious() == null) {\r
+ positions.add(new Pair<Resource, PositionType>(p.getResource(),PositionType.NEXT));\r
+ }\r
+ }\r
+ } \r
+ } else {\r
+ return positions;\r
+ }\r
+ return positions;\r
+ }\r
+\r
+ @Override\r
+ public void update() {\r
+ \r
+ switch (state) {\r
+ case NOT_ACTIVE:\r
+ return; // TODO : throw Exception?\r
+ case INITIALIZING:\r
+ return;\r
+ case SELECTING_POSITION:\r
+ updateSelectPosition();\r
+ break;\r
+ case SELECTING_SPLIT:\r
+ updateSelectSplit();\r
+ break;\r
+ case ROUTING:\r
+ updateRouting();\r
+ break;\r
+ }\r
+ return;\r
+ }\r
+\r
+ private void updateSelectPosition() {\r
+ \r
+ if (positions == null) {\r
+ throw new RuntimeException("positions must be loaded before select position can be activated");\r
+ }\r
+ if (selectedPort != null) {\r
+ throw new RuntimeException("position is already selected");\r
+ }\r
+ if (positions.size() == 1) {\r
+ selectedPort = positions.get(0).first;\r
+ selectedType = positions.get(0).second;\r
+ state = ToolState.INITIALIZING;\r
+ \r
+ \r
+ \r
+ if (requiresNewPipeRun()){\r
+ if(!getNewPipeRunSpecs()) {\r
+ end();\r
+ return;\r
+ }\r
+ }\r
+ if (selectedType == PositionType.SPLIT) {\r
+ startSplitting();\r
+ } else {\r
+ startRouting();\r
+ }\r
+\r
+ } else if (gizmo == null) {\r
+ state = ToolState.INITIALIZING; // asyncRead!\r
+ parent.getSession().asyncRead(new GraphRequestAdapter() {\r
+ @Override\r
+ public GraphRequestStatus perform(Graph g) throws Exception {\r
+ List<Pair<Point3d, PositionType>> pos = new ArrayList<Pair<Point3d,PositionType>>();\r
+ for (Pair<Resource, PositionType> p : positions) {\r
+ IEntity entity = EntityFactory.create(g,p.first);\r
+ Point3d position = ControlPointTools.getRealPosition(entity, p.second);\r
+ pos.add(new Pair<Point3d, PositionType>(position,p.second));\r
+ }\r
+ gizmo = new PositionSelectionGizmo(parent, pos);\r
+ parent.setGizmo(gizmo);\r
+ parent.getRenderingComponent().getNoShadowRoot().attachChild(gizmo.getNode());\r
+ state = ToolState.SELECTING_POSITION;\r
+ return GraphRequestStatus.transactionComplete();\r
+ }\r
+ });\r
+ \r
+ } else {\r
+ gizmo.update();\r
+ \r
+ if (input.keyPressed(KeyEvent.VK_ESCAPE)) {\r
+ state = ToolState.INITIALIZING;\r
+ parent.setGizmo(null);\r
+ gizmo = null;\r
+ end();\r
+ return;\r
+ }\r
+\r
+ if (gizmo.getSelected() >= 0 && input.mouseClicked() && input.clickButton() == MouseEvent.BUTTON1) {\r
+ state = ToolState.INITIALIZING; // asyncRead!\r
+ parent.setGizmo(null);\r
+ selectedPort = positions.get(gizmo.getSelected()).first;\r
+ selectedType = positions.get(gizmo.getSelected()).second;\r
+ gizmo = null;\r
+ \r
+ if (selectedType == PositionType.SPLIT) {\r
+ startSplitting(); \r
+ return;\r
+ } else {\r
+ startRouting();\r
+ }\r
+ } \r
+ \r
+ if (useCamera) {\r
+ parent.getDefaultAction().update();\r
+ return;\r
+ }\r
+ }\r
+ \r
+ }\r
+ \r
+ private boolean requiresNewPipeRun() {\r
+ GraphRequestWithResult<Boolean> createsNewPipeline = new GraphRequestWithResult<Boolean>() {\r
+ @Override\r
+ public Boolean performWithResult(Graph g) throws Exception {\r
+ if(g.isInstanceOf(selectedPort, ProcessResource.plant3Dresource.NozzleControlPoint))\r
+ return true;\r
+ if (selectedType == PositionType.SPLIT)\r
+ return true;\r
+ return false;\r
+ \r
+ }\r
+ };\r
+ parent.getSession().syncRead(createsNewPipeline);\r
+ return createsNewPipeline.getResult();\r
+ }\r
+ \r
+ private boolean getNewPipeRunSpecs() {\r
+ PipelineDialog dialog;\r
+ dialog = new PipelineDialog(parent.getRenderingComposite().getShell(),pipeDiameter,elbowRadius);\r
+ if (dialog.open() == PipelineDialog.CANCEL) {\r
+ end();\r
+ return false;\r
+ }\r
+ pipeDiameter = dialog.getPipeDiameter();\r
+ elbowRadius = dialog.getTurnRadius();\r
+ return true;\r
+ }\r
+ \r
+ private void startRouting() {\r
+ state = ToolState.INITIALIZING;\r
+ parent.getSession().asyncRead(new GraphRequestAdapter() {\r
+ @Override\r
+ public GraphRequestStatus perform(Graph g) throws Exception {\r
+ PipeControlPoint pcp = new PipeControlPoint(g,selectedPort);\r
+ lastPoint = ControlPointTools.getRealPosition(pcp, selectedType);//G3DTools.getPoint(pcp.getWorldPosition());\r
+ if (pcp.isInstanceOf(ProcessResource.plant3Dresource.DirectedControlPoint)) {\r
+ lock = LockType.CUSTOM;\r
+ customLockDir = ControlPointTools.getDirectedControlPointDirection(pcp);\r
+ } else if (pcp.isInstanceOf(ProcessResource.plant3Dresource.FixedLengthControlPoint)||\r
+ pcp.isInstanceOf(ProcessResource.plant3Dresource.TurnControlPoint)) {\r
+ lock = LockType.CUSTOM;\r
+ if (selectedType == PositionType.NEXT)\r
+ customLockDir = ControlPointTools.getPathLegDirection(pcp, Direction.NEXT);\r
+ else\r
+ customLockDir = ControlPointTools.getPathLegDirection(pcp, Direction.PREVIOUS);\r
+ } else {\r
+ lock = LockType.NONE;\r
+ }\r
+ IEntity pipeRun = ControlPointTools.getPipeRun(pcp);\r
+ if (pipeRun != null) {\r
+ pipeDiameter = pipeRun.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasPipeDiameter);\r
+ elbowRadius = pipeRun.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasTurnRadius);\r
+ }\r
+ return GraphRequestStatus.transactionComplete();\r
+ }\r
+ \r
+ @Override\r
+ public void requestCompleted(GraphRequestStatus status) {\r
+ createLine();\r
+ state = ToolState.ROUTING;\r
+ }\r
+ });\r
+ }\r
+ \r
+ private void startSplitting() {\r
+ parent.getSession().asyncRead(new GraphRequestAdapter() {\r
+ @Override\r
+ public GraphRequestStatus perform(Graph g) throws Exception {\r
+ PipeControlPoint pcp = new PipeControlPoint(g,selectedPort);\r
+ Point3d p1 = new Point3d();\r
+ Point3d p2 = new Point3d();\r
+ ControlPointTools.getInlineControlPointEnds(pcp, p1, p2);\r
+ splitPointAction.setSplit(p1, p2);\r
+ splitPointAction.activate();\r
+ state = ToolState.SELECTING_SPLIT;\r
+ return GraphRequestStatus.transactionComplete();\r
+ }\r
+ }); \r
+ }\r
+ \r
+ \r
+ private void updateSelectSplit() {\r
+ if (splitPointAction.active()) {\r
+ splitPointAction.update();\r
+ return;\r
+ } else {\r
+ throw new RuntimeException("SplitPointAction should be active");\r
+ }\r
+ }\r
+ \r
+ @Override\r
+ public void setSplitPoint(Point3d point) {\r
+ splitPointAction.deactivate();\r
+ if (point == null) {\r
+ end();\r
+ return;\r
+ } else {\r
+ \r
+ \r
+ lastPoint = point;\r
+ createLine();\r
+ state = ToolState.ROUTING;\r
+ }\r
+ }\r
+ \r
+ private void updateRouting() {\r
+ if(input.keyPressed(KeyEvent.VK_ESCAPE)) {\r
+ controlPoints.clear();\r
+ end();\r
+ return;\r
+ }\r
+ if (input.keyPressed(KeyEvent.VK_C)) {\r
+ useCamera = !useCamera;\r
+ cameraAction.setChecked(useCamera);\r
+ }\r
+ if (useCamera) {\r
+ parent.getDefaultAction().update();\r
+ return;\r
+ }\r
+ \r
+ parent.getSession().syncRead(new GraphRequestAdapter() {\r
+ @Override\r
+ public GraphRequestStatus perform(Graph g) throws Exception {\r
+ \r
+ Vector3d o = new Vector3d();\r
+ Vector3d d = new Vector3d();\r
+ parent.createPickRay(o, d);\r
+ if (!updateCurrentPoint(o, d))\r
+ return GraphRequestStatus.transactionComplete();\r
+ //Point3d startPoint = new Point3d();\r
+ double mu[] = new double[2];\r
+ \r
+ IEntity endTo = null;\r
+ PositionType endType = null;\r
+ IEntity endPort = null;\r
+ \r
+ if (parent.getSelectionAdapter().getHighlightSelection().size() > 0) {\r
+ highlightedResource = parent.getSelectionAdapter().getHighlightSelection().getSelectionList().get(0);\r
+ } else {\r
+ highlightedResource = null;\r
+ }\r
+\r
+ if (highlightedResource != null) {\r
+ IEntity highlightNode = EntityFactory.create(g,highlightedResource);\r
+ \r
+ if (lock == LockType.NONE) {\r
+ if (highlightNode.isInstanceOf(ProcessResource.plant3Dresource.Nozzle) && endingToNozzle(highlightNode,o,d)) {\r
+ endTo = highlightNode;\r
+ } else if (highlightNode.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent)) {\r
+ endTo = highlightNode;\r
+ endType = endingToStraight(new VariableLengthInlineComponent(highlightNode),mu,o,d); \r
+ } else if (highlightNode.isInstanceOf(ProcessResource.plant3Dresource.PipelineComponent) && (endPort = endingToComponent(highlightNode,o,d)) != null) {\r
+ endTo = highlightNode;\r
+ } else {\r
+ updateRoute(o,d); \r
+ }\r
+ } else { \r
+ if (highlightNode.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent) && (endType = endingLockToStraight(new VariableLengthInlineComponent(highlightNode),mu)) != null) {\r
+ endTo = highlightNode;\r
+ } else if (highlightNode.isInstanceOf(ProcessResource.plant3Dresource.Nozzle) && endingLockToNozzle(highlightNode)) {\r
+ endTo = highlightNode;\r
+ } else if (highlightNode.isInstanceOf(ProcessResource.plant3Dresource.PipelineComponent) && (endPort = endingLockToComponent(highlightNode)) != null) {\r
+ endTo = highlightNode;\r
+ } else {\r
+ updateRoute(o,d);\r
+ }\r
+ }\r
+ \r
+ \r
+ } else {\r
+ updateRoute(o,d);\r
+ }\r
+ \r
+ parent.setViewChanged(true);\r
+ if (input.mouseClicked()) {\r
+ if (input.clickButton() == MouseEvent.BUTTON1) {\r
+ if (controlPoints.size() > 0) {\r
+ addPoint();\r
+ setLockType(LockType.NONE,true);\r
+ if (endTo != null) {\r
+ endComponentResource = endTo.getResource();\r
+ if (endPort != null)\r
+ endComponentPort = endPort.getResource();\r
+ endPortType = endType;\r
+ \r
+ endPiping();\r
+ }\r
+ } else {\r
+ throw new RuntimeException("kjf");\r
+// // user was selecting position of branch\r
+// lastPoint.set(startPoint);\r
+// controlPoints.add(new Point3d(startPoint));\r
+// if (selectionLine != null)\r
+// selectionLine.removeFromParent();\r
+// selectionLine = null;\r
+ }\r
+ } else if (input.clickButton() == MouseEvent.BUTTON2){\r
+ detector.updateConstraintReference();\r
+ } else if (input.clickButton() == MouseEvent.BUTTON3){ \r
+ endPiping();\r
+ }\r
+ }\r
+ \r
+ return GraphRequestStatus.transactionComplete();\r
+ } \r
+ });\r
+ \r
+ }\r
+ \r
+ private void createLine() {\r
+ controlPoints.add(new Point3d(lastPoint));\r
+ Line line = new Line();\r
+ line.setRenderState(ms);\r
+ \r
+ PipeComponentProvider.createStraightEdges(line, currentPoint, currentPoint, pipeDiameter*0.5);\r
+ pipeShapes.add(line);\r
+ parent.getRenderingComponent().getNoShadowRoot().attachChild(line); \r
+ line.setCullMode(Geometry.CULL_NEVER);\r
+ }\r
+ \r
+ \r
+ /**\r
+ * Adds current point to pipeline\r
+ *\r
+ */\r
+ private void addPoint() {\r
+ \r
+ controlPoints.add(new Point3d(currentPoint));\r
+ Line line = new Line();\r
+ line.setRenderState(ms);\r
+ PipeComponentProvider.createStraightEdges(line, controlPoints.get(controlPoints.size() - 1), currentPoint, pipeDiameter*0.5);\r
+ pipeShapes.add(line);\r
+ parent.getRenderingComponent().getNoShadowRoot().attachChild(line); \r
+ line.setCullMode(Geometry.CULL_NEVER);\r
+ lastPoint.set(currentPoint);\r
+ }\r
+ \r
+ /**\r
+ * Updates tool graphics for current point \r
+ */\r
+ private void updateCurrentPoint() {\r
+ PipeComponentProvider.createStraightEdges(pipeShapes.get(pipeShapes.size() - 1), controlPoints.get(controlPoints.size() - 1), currentPoint, pipeDiameter*0.5);\r
+ }\r
+ \r
+ /**\r
+ * Removes last point from pipeline\r
+ */\r
+ public void removePoint() {\r
+ if (controlPoints.size() < 2)\r
+ return;\r
+ controlPoints.remove(controlPoints.size() - 1);\r
+\r
+ pipeShapes.get(pipeShapes.size() - 1).removeFromParent();\r
+ pipeShapes.remove(pipeShapes.size() - 1);\r
+ PipeComponentProvider.createStraightEdges(pipeShapes.get(pipeShapes.size() - 1), controlPoints.get(controlPoints.size() - 1), currentPoint, pipeDiameter*0.5);\r
+ \r
+ lastPoint.set(controlPoints.get(controlPoints.size()-1));\r
+ if (controlPoints.size() < 2 && customLockDir != null) {\r
+ setLockType(LockType.CUSTOM, true);\r
+ }\r
+ }\r
+ \r
+ \r
+ \r
+ private boolean endingToNozzle(IEntity nozzle,Vector3d o, Vector3d d) { \r
+ IEntity pcp = nozzle.getSingleRelatedObject(ProcessResource.plant3Dresource.HasControlPoint);\r
+ if (pcp != null && (pcp.getAtMostOneRelatedObject(ProcessResource.plant3Dresource.HasNext) != null ||\r
+ pcp.getAtMostOneRelatedObject(ProcessResource.plant3Dresource.HasPrevious) != null))\r
+ return false; // nozzle is already connected to pipe\r
+ currentPoint = G3DTools.getPoint(nozzle.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition));\r
+ Point3d previousPipePoint = controlPoints.get(controlPoints.size() - 1);\r
+ Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint));\r
+ if (p != null) {\r
+ if (p.distance(currentPoint) > NOZZLE_SNAP_DISTANCE) {\r
+ return false;\r
+ }\r
+ } \r
+ \r
+ updateCurrentPoint();\r
+ \r
+ setInfoText("Connect to nozzle " + currentPoint);\r
+ return true;\r
+ \r
+ }\r
+ \r
+ private PositionType endingToStraight(VariableLengthInlineComponent s, double mu[], Vector3d o, Vector3d d) {\r
+ String info = "";\r
+ Point3d sStart = new Point3d();\r
+ Point3d sEnd = new Point3d();\r
+ //detector.clearConstraintHighlights();\r
+ \r
+ Point3d previousPipePoint = controlPoints.get(controlPoints.size() - 1);\r
+ //String st = "";\r
+ if (lock == LockType.NONE) {\r
+ Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint));\r
+ if (p != null) {\r
+ currentPoint = p;\r
+ // snapping is detected, check if snapped point can create branch with straight\r
+ PositionType t = endingLockToStraight(s, mu);\r
+ if (t != null)\r
+ return t;\r
+ // if not, we'll have to remove highlight that was added when snapped point was detected\r
+ detector.clearConstraintHighlights();\r
+ } \r
+ \r
+ PipingTools2.getInlineComponentEnds(s, sStart, sEnd);\r
+ Vector3d sDir = new Vector3d(sEnd);\r
+ sDir.sub(sStart);\r
+ MathTools.intersectStraightStraight(sStart, sDir, o, d, currentPoint, new Point3d(), mu);\r
+ \r
+\r
+ } else {\r
+ throw new RuntimeException("Lock shouldn't be on");\r
+\r
+ }\r
+ \r
+ updateCurrentPoint();\r
+ \r
+ // branch point must lie between straight's ends. If connection point is exactly\r
+ // on straight end user may want to connect pipes to each other\r
+ // TODO : take account sizes of inline components)\r
+ // TODO : actually make connection if its detected\r
+ boolean connectPrev = false;\r
+ boolean connectNext = false;\r
+ \r
+ if (mu[0] < 0.0) {\r
+ currentPoint.set(sStart);\r
+ connectPrev = true;\r
+ }\r
+ else if (mu[0] > 1.0) {\r
+ currentPoint.set(sEnd);\r
+ connectNext = true;\r
+ }\r
+ boolean connect = false;\r
+ if (connectPrev) {\r
+ PipeControlPoint pcp = s.getControlPoint();\r
+ if (pcp.getPrevious() == null)\r
+ connect = true;\r
+ } else if (connectNext) {\r
+ PipeControlPoint pcp = s.getControlPoint();\r
+ if (pcp.getNext() == null)\r
+ connect = true;\r
+ }\r
+ \r
+ updateCurrentPoint();\r
+ \r
+ if (connect)\r
+ info += "Connect pipes :";\r
+ else\r
+ info += "Make Branch :";\r
+ \r
+ setInfoText(info + currentPoint + " " + Math.max(0.0, Math.min(mu[0], 1.0)));\r
+ if (connect) {\r
+ if (connectNext) {\r
+ return PositionType.NEXT;\r
+ } else {\r
+ return PositionType.PREVIOUS;\r
+ }\r
+ \r
+ }\r
+ return PositionType.SPLIT;\r
+ \r
+ }\r
+ \r
+ private IEntity endingToComponent(IEntity component, Vector3d o, Vector3d d) {\r
+ // TODO : scan all empty pcps of the component and select closest one.\r
+ return null;\r
+ }\r
+ \r
+ private PositionType endingLockToStraight(VariableLengthInlineComponent s, double mu[]) {\r
+ \r
+ Point3d sStart = new Point3d();//G3DTools.getPoint(s.getHasControlPoint().getPreviousPoint().getLocalPosition());\r
+ Point3d sEnd = new Point3d(); //G3DTools.getPoint(s.getHasControlPoint().getNextPoint().getLocalPosition());\r
+ PipingTools2.getInlineComponentEnds(s, sStart, sEnd);\r
+ Vector3d sDir = new Vector3d(sEnd);\r
+ sDir.sub(sStart);\r
+ Vector3d dir = new Vector3d(currentPoint);\r
+ Point3d prev = controlPoints.get(controlPoints.size() - 1);\r
+ dir.sub(prev);\r
+ // intersection point in pipe where branch would be inserted to\r
+ Vector3d branchPoint = new Vector3d();\r
+ // intersection point in straight pipe that is currently routed\r
+ Vector3d routePoint = new Vector3d();\r
+ MathTools.intersectStraightStraight(sStart, sDir, new Vector3d(prev), dir, branchPoint, routePoint, mu);\r
+ routePoint.sub(branchPoint);\r
+ // startPoint of branch must be between pipe ends\r
+ // TODO : take account sizes of elbows (or other components)\r
+ // branch point must be between pipe ends and intersection points must be quite close to each othert\r
+ if (mu[0] > 0.0 && mu[0] < 1.0 && routePoint.lengthSquared() < BRANCH_SNAP_DISTANCE) {\r
+ currentPoint.set(branchPoint);\r
+ \r
+ updateCurrentPoint();\r
+ \r
+ setInfoText("Make branch (l) :" + currentPoint + " " + Math.max(0.0, Math.min(mu[0], 1.0)) + " " + routePoint.lengthSquared());\r
+ return PositionType.SPLIT;\r
+ }\r
+ return null;\r
+ }\r
+ \r
+ private boolean endingLockToNozzle(IEntity nozzle) {\r
+ Vector3d dir = new Vector3d(currentPoint);\r
+ Point3d prev = controlPoints.get(controlPoints.size() - 1);\r
+ dir.sub(prev);\r
+ Point3d nozzleLoc = G3DTools.getPoint(nozzle.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition));\r
+ double u[] = new double[1];\r
+ Vector3d closest = MathTools.closestPointOnStraight(new Point3d(nozzleLoc), new Point3d(prev), new Vector3d(dir), u);\r
+ double dist = nozzleLoc.distanceSquared(new Point3d(closest));\r
+ if (dist < BRANCH_SNAP_DISTANCE) {\r
+ // FIXME : directions should be checked (insert an elbow)\r
+ currentPoint.set(nozzleLoc);\r
+ updateCurrentPoint();\r
+ setInfoText("Connect to nozzle (l) :" + currentPoint);\r
+ return true;\r
+ } \r
+ //System.out.println(u[0]);\r
+ return false;\r
+ }\r
+ \r
+ private IEntity endingLockToComponent(IEntity component) {\r
+ // we'll must scan all free pcp's and their direction to accept the connection.\r
+ return null;\r
+ }\r
+ \r
+ private void updateRoute(Vector3d o, Vector3d d) {\r
+ detector.clearConstraintHighlights();\r
+ Point3d previousPipePoint = controlPoints.get(controlPoints.size() - 1);\r
+ String s = "";\r
+ if (lock == LockType.NONE) {\r
+ Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint));\r
+ if (p != null)\r
+ currentPoint = p;\r
+ s += detector.getSnapString();\r
+\r
+ } else {\r
+ Vector3d dir = new Vector3d(currentPoint);\r
+ dir.sub(previousPipePoint);\r
+ Point3d p = detector.getPointSnap(new Vector3d(previousPipePoint), dir);\r
+ if (p != null)\r
+ currentPoint = p;\r
+ s += detector.getSnapString();\r
+\r
+ }\r
+ \r
+ updateCurrentPoint();\r
+ s += currentPoint.toString();\r
+ setInfoText(s);\r
+ }\r
+ \r
+ private boolean updateCurrentPoint(Vector3d o, Vector3d d) {\r
+ if (lock != LockType.CUSTOM) {\r
+ if (input.keyPressed(KeyEvent.VK_X)) {\r
+ if (lock == LockType.X)\r
+ setLockType(LockType.YZ,false);\r
+ else\r
+ setLockType(LockType.X,false);\r
+ }\r
+ if (input.keyPressed(KeyEvent.VK_Y)) {\r
+ if (lock == LockType.Y)\r
+ setLockType(LockType.XZ,false);\r
+ else\r
+ setLockType(LockType.Y,false);\r
+ }\r
+ if (input.keyPressed(KeyEvent.VK_Z)) {\r
+ if (lock == LockType.Z)\r
+ setLockType(LockType.XY,false);\r
+ else\r
+ setLockType(LockType.Z,false);\r
+ }\r
+ if (input.keyPressed(KeyEvent.VK_N)) {\r
+ setLockType(LockType.NONE,false);\r
+ }\r
+ if (input.keyPressed(KeyEvent.VK_BACK_SPACE)) {\r
+ removePoint();\r
+ }\r
+ }\r
+ Vector3d point = new Vector3d(lastPoint);\r
+ boolean step = ((input.moveModifiers() & MouseEvent.CTRL_DOWN_MASK) > 0);\r
+ switch(lock) {\r
+ case X:\r
+ MathTools.intersectStraightStraight(point, new Vector3d(1.0,0.0,0.0), o,d, currentPoint, new Vector3d());\r
+ if (step) {\r
+ currentPoint.x = Math.round(istep * currentPoint.x) / istep;\r
+ BigDecimal bx = new BigDecimal(currentPoint.x);\r
+ bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);\r
+ currentPoint.x = bx.doubleValue();\r
+ }\r
+ break;\r
+ case Y:\r
+ MathTools.intersectStraightStraight(point, new Vector3d(0.0,1.0,0.0), o,d, currentPoint, new Vector3d());\r
+ if (step) {\r
+ currentPoint.y = Math.round(istep * currentPoint.y) / istep;\r
+ BigDecimal bx = new BigDecimal(currentPoint.y);\r
+ bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);\r
+ currentPoint.y = bx.doubleValue();\r
+ }\r
+ break;\r
+ case Z:\r
+ MathTools.intersectStraightStraight(point, new Vector3d(0.0,0.0,1.0), o,d, currentPoint, new Vector3d());\r
+ if (step) {\r
+ currentPoint.z = Math.round(istep * currentPoint.z) / istep;\r
+ BigDecimal bx = new BigDecimal(currentPoint.z);\r
+ bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);\r
+ currentPoint.z = bx.doubleValue();\r
+ }break;\r
+ case XY:\r
+ MathTools.intersectStraightPlane(o, d, point, new Vector3d(0.0,0.0,1.0), currentPoint);\r
+ break;\r
+ case XZ:\r
+ MathTools.intersectStraightPlane(o, d, point, new Vector3d(0.0,1.0,0.0), currentPoint);\r
+ break;\r
+ case YZ:\r
+ MathTools.intersectStraightPlane(o, d, point, new Vector3d(1.0,0.0,0.0), currentPoint);\r
+ break;\r
+ case NONE:\r
+ Vector3d normal = parent.getCamera().getUnNormalizedHeading();\r
+ normal.normalize();\r
+ \r
+ MathTools.intersectStraightPlane(o, d, point, normal, currentPoint);\r
+ break;\r
+ case CUSTOM:\r
+ MathTools.intersectStraightStraight(point, new Vector3d(customLockDir), o,d, currentPoint, new Vector3d());\r
+ double dist = MathTools.distanceFromPlane(new Vector3d(currentPoint), customLockDir, lastPoint);\r
+ if (dist < 0.0)\r
+ currentPoint.set(lastPoint);\r
+ break;\r
+ default:\r
+ return false;\r
+ }\r
+ return true;\r
+ }\r
+ \r
+ \r
+ private ArrayList<Point3d> filterPoints() {\r
+ ArrayList<Point3d> filteredControlPoints = new ArrayList<Point3d>();\r
+ \r
+ // this loop filters control points that are not needed\r
+ for (int i = 0; i < controlPoints.size() - 2; i++) {\r
+ Point3d start = controlPoints.get(i);\r
+ if (i == 0)\r
+ filteredControlPoints.add(start);\r
+ \r
+ Point3d middle = controlPoints.get(i+1);\r
+ Point3d end = controlPoints.get(i+2);\r
+ \r
+ Vector3d dir1 = new Vector3d(middle);\r
+ dir1.sub(start);\r
+ Vector3d dir2 = new Vector3d(end);\r
+ dir2.sub(middle);\r
+ double angle = dir1.angle(dir2);\r
+ if (angle > eps && angle < (Math.PI - eps))\r
+ filteredControlPoints.add(middle);\r
+ // if angle is near PI pipe turns back to where it started\r
+ // if angle is near zero, pipe is straight and there's no need for control point\r
+ \r
+ if (i == controlPoints.size() - 3)\r
+ filteredControlPoints.add(end);\r
+ \r
+ } \r
+ return filteredControlPoints;\r
+ }\r
+ \r
+ private PipeControlPoint connectPipeStart(Graph graph, PipeRun pipeRun, boolean reversed) {\r
+ PipeControlPoint pcp = new PipeControlPoint(graph,selectedPort);\r
+ IEntity beginComponent = EntityFactory.create(graph,beginComponentResource);\r
+ if (beginComponent.isInstanceOf(ProcessResource.plant3Dresource.Nozzle)) {\r
+ PipingTools2.linkNozzleAndPipeRun(beginComponent, pipeRun);\r
+ // TODO : set diameters same\r
+ //reversed = false;\r
+ \r
+ } else if (beginComponent.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent)) {\r
+ switch (selectedType) {\r
+ case NEXT:\r
+ {\r
+ PipeControlPoint tcp = createTurn(graph, pipeRun, 0);\r
+ connectControlPoints(pcp, tcp, reversed);\r
+ return tcp;\r
+ }\r
+ case PREVIOUS:\r
+ {\r
+ PipeControlPoint tcp = createTurn(graph, pipeRun, 0);\r
+ connectControlPoints(pcp, tcp, reversed);\r
+ return tcp;\r
+ }\r
+ case SPLIT:\r
+ //reversed = false;\r
+ // 1. create (non visible) splitting component.\r
+ PipelineComponent newComponent = PipingTools2.instantiatePipelineComponent(graph, PipingTools2.getPipeRun(beginComponent).getResource(), ProcessResource.plant3Dresource.BranchSplitComponent); \r
+ PipeControlPoint mainCP = newComponent.getControlPoint();\r
+ // 2. create control point for the branch\r
+ BranchEndControlPoint becp = BranchEndControlPoint.createDefault(graph);\r
+ mainCP.addSubPoint(becp);\r
+ pipeRun.addControlPoints(becp);\r
+ pcp = becp.toPipeControlPoint();\r
+ ControlPointTools.setWorldPosition(mainCP, controlPoints.get(0));\r
+ \r
+ PipingTools2.splitVariableLengthComponent(newComponent, beginComponent);\r
+ }\r
+ } else if (beginComponent.isInstanceOf(ProcessResource.plant3Dresource.PipelineComponent)) {\r
+ //if (selectedType == PositionType.PREVIOUS)\r
+ //reversed = true;\r
+ //else\r
+ //reversed = false;\r
+ } else {\r
+ throw new RuntimeException("unknown starting component");\r
+ }\r
+ \r
+ return pcp;\r
+ }\r
+ \r
+ private PipeControlPoint connectPipeEnd(Graph graph, PipeRun pipeline, boolean reversed) {\r
+ PipeControlPoint pcp = null;\r
+ IEntity endComponent = null;\r
+ if (endComponentResource != null)\r
+ endComponent = EntityFactory.create(graph, endComponentResource);\r
+ if (endComponent == null) {\r
+ return null;\r
+ } else if (endComponent.isInstanceOf(ProcessResource.plant3Dresource.Nozzle)){\r
+ pcp = new PipeControlPoint(endComponent.getSingleRelatedObject(ProcessResource.plant3Dresource.HasControlPoint));\r
+ PipingTools2.linkNozzleAndPipeRun(endComponent, pipeline);\r
+ } else if (endComponent.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent)) {\r
+ assert(endPortType != null);\r
+ if (endPortType == PositionType.SPLIT) {\r
+ //System.out.println(lastPoint + " " + currentPoint + " " + positions.get(positions.size() - 1));\r
+ Point3d pos = lastPoint;\r
+ // 1. create (non visible) splitting component.\r
+ PipelineComponent newComponent = PipingTools2.instantiatePipelineComponent(graph, PipingTools2.getPipeRun(endComponent).getResource(), ProcessResource.plant3Dresource.BranchSplitComponent);\r
+ \r
+ PipeControlPoint mainCP = newComponent.getControlPoint();\r
+ // 2. create control point for the branch\r
+ BranchEndControlPoint becp = BranchEndControlPoint.createDefault(graph);\r
+ mainCP.addSubPoint(becp);\r
+ pipeline.addControlPoints(becp);\r
+ pcp = becp.toPipeControlPoint();\r
+ ControlPointTools.setWorldPosition(mainCP, pos);\r
+ \r
+ PipingTools2.splitVariableLengthComponent(newComponent, endComponent);\r
+ } else {\r
+ \r
+ } \r
+ } else if (endComponent.isInstanceOf(ProcessResource.plant3Dresource.FixedLengthInlineComponent)) {\r
+ // attach to selected port, reverse the piperun if needed\r
+ pcp = new PipeControlPoint(graph,endComponentPort);\r
+ if (!reversed && pcp.getPrevious() != null || reversed && pcp.getNext() != null) {\r
+ PipingTools2.reversePipeRun(ControlPointTools.getPipeRun(pcp));\r
+ }\r
+ }\r
+ return pcp;\r
+ }\r
+ \r
+ private PipeControlPoint createTurn(Graph coreTC,PipeRun pipeRun, int i) {\r
+ PipelineComponent elbow = PipingTools2.instantiatePipelineComponent(coreTC,pipeRun.getResource(), ProcessResource.plant3Dresource.Elbow);\r
+ G3DAPI.setWorldPosition(elbow, controlPoints.get(i));\r
+ return elbow.getControlPoint();\r
+ }\r
+ \r
+ private PipeControlPoint createInline(Graph graph, PipeRun pipeRun, int i) {\r
+ Point3d p1 = controlPoints.get(i-1);\r
+ Point3d p2 = controlPoints.get(i);\r
+ Vector3d v = new Vector3d(p2);\r
+ v.sub(p1);\r
+ double length = v.length();\r
+ v.scale(0.5);\r
+ v.add(p1);\r
+ PipelineComponent straight = PipingTools2.instantiatePipelineComponent(graph,pipeRun.getResource(), ProcessResource.plant3Dresource.Straight);\r
+ G3DAPI.setWorldPosition(straight, v);\r
+ straight.setRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength, length);\r
+ return straight.getControlPoint();\r
+ \r
+ }\r
+ \r
+ private void connectControlPoints(PipeControlPoint previous, PipeControlPoint pcp, boolean reversed) {\r
+ if (previous != null) {\r
+ PipeControlPoint sccp;\r
+ PipeControlPoint ocp;\r
+ if (previous.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)) {\r
+ sccp = previous;\r
+ ocp = sccp.getSubPoint().iterator().next();\r
+ } else if (previous.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)) {\r
+ ocp = previous;\r
+ sccp = ocp.getSubPointOf();\r
+ } else {\r
+ if (!reversed) {\r
+ previous.setNext(pcp);\r
+ pcp.setPrevious(previous);\r
+ } else {\r
+ previous.setPrevious(pcp);\r
+ pcp.setNext(previous);\r
+ }\r
+ return;\r
+ }\r
+ if (!reversed) {\r
+ sccp.setNext(pcp);\r
+ ocp.setNext(pcp);\r
+ pcp.setPrevious(ocp);\r
+ } else {\r
+ sccp.setPrevious(pcp);\r
+ ocp.setPrevious(pcp);\r
+ pcp.setNext(sccp);\r
+ }\r
+ \r
+ }\r
+ }\r
+ \r
+ private void endPiping() {\r
+ state = ToolState.NOT_ACTIVE;\r
+ \r
+ if (controlPoints.size() > 2) // if there's only two control points, filtering does nothing\r
+ controlPoints = filterPoints();\r
+ \r
+ if (controlPoints.size() > 1) {\r
+ parent.getSession().asyncWrite(new GraphRequestAdapter() {\r
+ @Override\r
+ public GraphRequestStatus perform(Graph graph) throws Exception {\r
+ PipeRun pipeline = null;\r
+ boolean reversed;\r
+ PipelineComponent beginComponent = new PipelineComponent(graph,beginComponentResource);\r
+ if (beginComponent.isInstanceOf(ProcessResource.plant3Dresource.Nozzle) ||\r
+ selectedType == PositionType.SPLIT) {\r
+\r
+ \r
+// \r
+ pipeline = PipeRun.createDefault(graph);\r
+ ((ProcessEditor) parent).getPlant(graph).addChild(pipeline);\r
+ pipeline.setPipeDiameter(pipeDiameter);\r
+ pipeline.setTurnRadius(elbowRadius);\r
+ reversed = false;\r
+ } else if (beginComponent.isInstanceOf(ProcessResource.plant3Dresource.SizeChangeComponent)||\r
+ beginComponent.isInstanceOf(ProcessResource.plant3Dresource.OffsetComponent)){\r
+ PipeControlPoint pcp = new PipeControlPoint(graph,selectedPort);\r
+ if (selectedType == PositionType.NEXT) {\r
+ // get the piperun from offsetpoint\r
+ reversed = false;\r
+ pipeline = pcp.getSubPoint().iterator().next().getControlPointOfPipeRun();\r
+ } else if (selectedType == PositionType.PREVIOUS) {\r
+ reversed = true;\r
+ pipeline = pcp.getControlPointOfPipeRun();\r
+ } else {\r
+ throw new RuntimeException("Wrong PsoitionType " + selectedType + " for a SizeChangeComponent");\r
+ }\r
+ \r
+ } else if (beginComponent.isInstanceOf(ProcessResource.plant3Dresource.PipelineComponent)) {\r
+ \r
+ pipeline = new PipeRun(beginComponent.getParent());\r
+ if (selectedType == PositionType.PREVIOUS) {\r
+ reversed = true;\r
+ } else {\r
+ reversed = false;\r
+ }\r
+ } else {\r
+ throw new RuntimeException("Cannot start routing pipe : object not supported!");\r
+ }\r
+\r
+ PipeControlPoint previous = null;\r
+ for (int i = 0; i < controlPoints.size(); i++) {\r
+ PipeControlPoint pcp = null;\r
+ if (i == 0) {\r
+ pcp = connectPipeStart(graph, pipeline,reversed);\r
+\r
+ } else {\r
+ pcp = createInline(graph, pipeline, i);\r
+ connectControlPoints(previous, pcp, reversed);\r
+ previous = pcp;\r
+ if (i == controlPoints.size() - 1) {\r
+ pcp = connectPipeEnd(graph, pipeline, reversed);\r
+ } else {\r
+ \r
+ pcp = createTurn(graph,pipeline,i);\r
+ }\r
+ }\r
+ \r
+ if (pcp != null) {\r
+ connectControlPoints(previous, pcp, reversed);\r
+ //pipeline.addSgetHasControlPointSet().add(pcp);\r
+ previous = pcp;\r
+ }\r
+ }\r
+ return GraphRequestStatus.transactionComplete();\r
+ }\r
+ \r
+ @Override\r
+ public void requestCompleted(GraphRequestStatus status) {\r
+ endThreaded();\r
+ }\r
+ });\r
+\r
+ \r
+ \r
+ } else {\r
+ endThreaded(); \r
+ }\r
+ }\r
+ \r
+ private void endThreaded() {\r
+ parent.getRenderingComposite().getDisplay().asyncExec(new Runnable() {\r
+ @Override\r
+ public void run() {\r
+ end();\r
+ }\r
+ });\r
+ }\r
+\r
+ @Override\r
+ public void init() {\r
+ this.setText("Route pipe");\r
+ this.setToolTipText("Starts routing a new pipeline");\r
+ this.setImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/Straight.png"));\r
+ }\r
+\r
+ @Override\r
+ public boolean usable(Graph g, List<Resource> resources) {\r
+ if (resources.size() != 1) {\r
+ return false;\r
+ }\r
+ return checkStartNode(g,resources.get(0)).size() > 0;\r
+ }\r
+ \r
+ \r
+ \r
+ public boolean acceptDrop(StructuredResourceSelection s, Resource[] ids) {\r
+ if (s.size() != 1)\r
+ return false;\r
+ if (ids == null)\r
+ return false;\r
+ if (ids.length != 1)\r
+ return false;\r
+ final Resource dropped = ids[0];\r
+ final Resource target = s.iterator().next();\r
+ GraphRequestWithResult<Boolean> query = new GraphRequestWithResult<Boolean>() {\r
+ @Override\r
+ public Boolean performWithResult(Graph g) throws Exception {\r
+ if(!g.isInstanceOf(dropped, ProcessResource.plant3Dresource.VariableLengthInlineComponent))\r
+ return false;\r
+ // TODO : check that type is not abstract\r
+ List<Resource> list = new ArrayList<Resource>();\r
+ list.add(target);\r
+ return usable(g, list);\r
+ }\r
+ };\r
+ parent.getSession().syncRead(query);\r
+ return query.getResult();\r
+ }\r
+ \r
+ public void doDrop(StructuredResourceSelection s, Resource[] ids) {\r
+ beginComponentResource = s.iterator().next(); \r
+ parent.setCurrentAction(this);\r
+ }\r
+ \r
+ public void setInfoText(String text) {\r
+ \r
+ }\r
+\r
+}
\ No newline at end of file