package fi.vtt.simantics.processeditor.tools; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.IToolBarManager; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.swt.SWT; import org.eclipse.swt.layout.FormAttachment; import org.eclipse.swt.layout.FormData; import org.eclipse.swt.layout.FormLayout; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Text; import org.simantics.db.Graph; import org.simantics.db.GraphRequestStatus; import org.simantics.db.Resource; import org.simantics.layer0.utils.EntityFactory; import org.simantics.layer0.utils.IEntity; import org.simantics.proconf.g3d.actions.ContextAction; import org.simantics.proconf.g3d.actions.FocusAction; import org.simantics.proconf.g3d.actions.RemoveAction; import org.simantics.proconf.g3d.actions.RotateAction; import org.simantics.proconf.g3d.actions.TranslateAction; import org.simantics.proconf.g3d.base.EditorContribution; import org.simantics.proconf.g3d.common.StructuredResourceSelection; import org.simantics.utils.ui.jface.MenuTools; import com.jme.intersection.CollisionData; import com.jme.intersection.CollisionResults; import com.jme.intersection.TriangleCollisionResults; import com.jme.scene.Geometry; import com.jme.scene.Node; import com.jme.scene.Spatial; import fi.vtt.simantics.processeditor.Activator; import fi.vtt.simantics.processeditor.ProcessResource; import fi.vtt.simantics.processeditor.actions.InsertComponentAction; import fi.vtt.simantics.processeditor.actions.InsertEquipmentAction; import fi.vtt.simantics.processeditor.actions.InsertNozzleAction; import fi.vtt.simantics.processeditor.actions.ReversePipelineAction; import fi.vtt.simantics.processeditor.actions.RoutePipeAction; import fi.vtt.simantics.processeditor.actions.TranslateElbowAction; import fi.vtt.simantics.processeditor.actions.TranslateInlineComponentAction; import fi.vtt.simantics.processeditor.actions.TranslateStraightAction; import fi.vtt.simantics.processeditor.common.ControlPointTools; import fi.vtt.simantics.processeditor.stubs.InlineComponent; import fi.vtt.simantics.processeditor.stubs.PipeControlPoint; import fi.vtt.simantics.processeditor.views.ProcessEditor; public class PlantEditContribution implements EditorContribution { private List actions = new ArrayList(); private ProcessEditor parent; private Composite infoComposite; private Text infoText; private Action checkInterferencesAction = null; public PlantEditContribution(ProcessEditor parent) { this.parent = parent; } @Override public void createControl(Composite parent) { FormLayout flayout = new FormLayout(); parent.setLayout(flayout); infoComposite = new Composite(parent, SWT.BORDER); FormData data = new FormData(); data.top = new FormAttachment(0, 0); data.left = new FormAttachment(0, 0); data.right = new FormAttachment(100, 0); data.bottom = new FormAttachment(infoComposite, 0, SWT.TOP); this.parent.getRenderingComposite().setLayoutData(data); data = new FormData(); data.left = new FormAttachment(0, 0); data.right = new FormAttachment(100, 0); data.bottom = new FormAttachment(100, 0); data.height = 18; infoComposite.setLayoutData(data); GridLayout layout = new GridLayout(1,false); layout.marginWidth = 1; layout.marginHeight = 1; infoComposite.setLayout(layout); infoText = new Text(infoComposite, SWT.NONE); GridData gdata = new GridData(); gdata.grabExcessHorizontalSpace = true; gdata.horizontalAlignment = SWT.FILL; infoText.setLayoutData(gdata); } @Override public void disposeControl() { infoComposite.dispose(); } @Override public void dispose() { } @Override public void fillContextMenu(Graph graph, IMenuManager manager, StructuredResourceSelection selection) { } @Override public void fillLocalPullDown(IMenuManager manager) { MenuTools.getOrCreate(parent.getMenuID(),"Advanced", manager).add(checkInterferencesAction); } @Override public void fillLocalToolBar(IToolBarManager manager) { } @Override public Collection getActions() { return actions; } @Override public String getName() { return "Plant Editing"; } @Override public void initialize(Graph graph) { actions.add(new TranslateAction(parent){ @Override public boolean usable(Graph graph,List resources) { if (super.usable(graph, resources)) { for (Resource r : resources) { // FIXME : use new ontology : // 1. lose ends works like end components (just what this code does, but type checks are not correct) // 2. connected components are moved inline. (TranslateInlineAction) IEntity t = EntityFactory.create(graph, r); if (t.isInstanceOf(ProcessResource.plant3Dresource.InlineComponent)) { InlineComponent component = new InlineComponent(t); PipeControlPoint pcp = component.getControlPoint(); if (pcp.getNext() != null && pcp.getPrevious() != null) return false; } } return true; } return false; } @Override public void setInfoText(String text) { infoText.setText(text); } }); actions.add(new TranslateInlineComponentAction(parent) { @Override public void setInfoText(String text) { infoText.setText(text); } }); actions.add(new TranslateStraightAction(parent) { @Override public void setInfoText(String text) { infoText.setText(text); } }); actions.add(new TranslateElbowAction(parent) { @Override public void setInfoText(String text) { infoText.setText(text); } }); actions.add(new RotateAction(parent){ @Override public boolean usable(Graph graph,List resources) { if (super.usable(graph,resources)) { for (Resource r : resources) { IEntity t = EntityFactory.create(graph,r); // FIXME : use new ontology // TODO : create rotate action that can rotate inline components // TODO : ontology change: pipes and similar components cannot be rotated, since there is no point to do that. if (t.isInstanceOf(ProcessResource.plant3Dresource.InlineComponent)) { return false; } } return true; } return false; } @Override public void setInfoText(String text) { infoText.setText(text); } }); actions.add(new RemoveAction(parent) { @Override public GraphRequestStatus doChanges(Graph graph) { Iterator i = parent.getSelectionAdapter().getCurrentSelection().iterator(); while (i.hasNext()) { Resource s = i.next(); IEntity r = EntityFactory.create(graph, s); if (r.isInstanceOf(ProcessResource.g3dResource.G3DNode)) { Collection parentNode= r.getRelatedObjects(ProcessResource.g3dResource.HasParent); if (parentNode.size() == 1) { Collection rs = r.getRelatedObjects(ProcessResource.plant3Dresource.HasControlPoint); for (IEntity cp : rs) { ControlPointTools.removeControlPoint(new PipeControlPoint(cp)); } r.removeRelatedStatements(ProcessResource.g3dResource.HasParent); } else { if (parentNode.size() == 0) { parent.showMessage("Object has no parent, don't know what to do!"); } else { parent.showMessage("Object has more than one parent, don't know what to do!"); } } } } //parent.getSelectionAdapter().setSelection(new StructuredResourceSelection()); return GraphRequestStatus.transactionComplete(); } }); actions.add(new FocusAction(parent)); actions.add(new RoutePipeAction(parent){ @Override public void setInfoText(String text) { infoText.setText(text); } }); actions.add(new InsertComponentAction(parent)); actions.add(new InsertEquipmentAction(parent)); actions.add(new InsertNozzleAction(parent)); actions.add(new ReversePipelineAction(parent)); checkInterferencesAction = new Action() { public void run() { CollisionResults results = new TriangleCollisionResults(); //getRenderingComponent().getNormalRoot().calculateCollisions(getRenderingComponent().getNormalRoot(), results); collide(parent.getRenderingComponent().getShadowRoot(),parent.getRenderingComponent().getShadowRoot(),results); results = filterResults(results); for (int i = 0; i < results.getNumber(); i++) { CollisionData data = results.getCollisionData(i); Geometry s = data.getSourceMesh(); Geometry t = data.getTargetMesh(); MessageDialog dialog = new MessageDialog(parent.getRenderingComposite().getShell(),"Interference " + i + " / " + results.getNumber(), null, "Interference between " + s + " and " + t,MessageDialog.WARNING,new String[]{"Next","Cancel"},0); try { Resource sid = parent.getScenegraphAdapter().getNodeResource(s.getName()); Resource tid = parent.getScenegraphAdapter().getNodeResource(t.getName()); StructuredResourceSelection sel = new StructuredResourceSelection(); if (sid == tid) { sel.add(sid); } else { sel.add(sid); sel.add(tid); } parent.getSelectionAdapter().setSelection(sel); } catch(NumberFormatException e) { } if (dialog.open() == 1) break; } } private void collide(Spatial s, Spatial p, CollisionResults r) { s.calculateCollisions(p, r); if (s instanceof Node) { Node n = (Node)s; for (Spatial t : n.getChildren()) collide(t,p,r); } } private CollisionResults filterResults(CollisionResults results) { CollisionResults r = new TriangleCollisionResults(); for (int i = 0; i < results.getNumber(); i++) { CollisionData d = results.getCollisionData(i); if (d.getSourceMesh() == d.getTargetMesh()) continue; boolean found = false; for (int j = 0; j < r.getNumber(); j++) { CollisionData d2 = r.getCollisionData(j); if (d2.getSourceMesh() == d.getSourceMesh() && d2.getTargetMesh() == d.getTargetMesh()) { found = true; break; } if (d2.getSourceMesh() == d.getTargetMesh() && d2.getTargetMesh() == d.getSourceMesh()) { found = true; break; } } if (!found) { if (d.getSourceTris().size() == 0) continue; if (d.getTargetTris().size() == 0) continue; r.addCollisionData(d); } } return r; } }; checkInterferencesAction.setText("Interferences"); checkInterferencesAction.setImageDescriptor(Activator.imageDescriptorFromPlugin("fi.vtt.proconf.ode", "icons/silk/delete.png")); } @Override public void run() { } }