package fi.vtt.simantics.processeditor.tools; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.net.URL; import java.util.ArrayList; import java.util.Collection; import java.util.List; import javax.vecmath.AxisAngle4d; import javax.vecmath.Point3d; import javax.vecmath.Quat4d; import javax.vecmath.Vector3d; import org.eclipse.core.runtime.FileLocator; import org.eclipse.core.runtime.Path; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.IToolBarManager; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.layout.FormAttachment; import org.eclipse.swt.layout.FormData; import org.eclipse.swt.layout.FormLayout; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.simantics.db.Graph; import org.simantics.db.GraphRequestAdapter; import org.simantics.db.GraphRequestStatus; import org.simantics.db.Resource; import org.simantics.proconf.g3d.actions.ContextAction; import org.simantics.proconf.g3d.base.EditorContribution; import org.simantics.proconf.g3d.base.G3DTools; import org.simantics.proconf.g3d.base.MathTools; import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; import org.simantics.proconf.g3d.base.VecmathJmeTools; import org.simantics.proconf.g3d.common.StructuredResourceSelection; import org.simantics.utils.ErrorLogger; import com.jme.renderer.ColorRGBA; import com.jme.scene.Geometry; import com.jme.scene.Node; import com.jme.scene.Spatial; import com.jme.scene.TriMesh; import com.jme.scene.shape.Sphere; import com.jme.scene.state.MaterialState; import com.jme.util.export.Savable; import com.jme.util.export.binary.BinaryImporter; import com.jmex.model.converters.ObjToJme; import fi.vtt.simantics.processeditor.Activator; import fi.vtt.simantics.processeditor.ProcessResource; import fi.vtt.simantics.processeditor.common.PipeComponentProvider; import fi.vtt.simantics.processeditor.stubs.DirectedControlPoint; import fi.vtt.simantics.processeditor.stubs.PipeControlPoint; public class ControlPointContribution implements EditorContribution { private List actions = new ArrayList(); private ThreeDimensionalEditorBase parent; private Resource componentResource; private Resource controlPointResource; private Composite sideComposite; private double radius = 0.2; private double radius2 = 0.1; private double angle = Math.PI / 4.0; public ControlPointContribution(ThreeDimensionalEditorBase parent) { this.parent = parent; } @Override public void createControl(Composite parent) { FormLayout flayout = new FormLayout(); parent.setLayout(flayout); sideComposite = 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(sideComposite, 0, SWT.LEFT); data.bottom = new FormAttachment(100,0); this.parent.getRenderingComposite().setLayoutData(data); GridLayout layout = new GridLayout(1,false); layout.marginHeight = 1; layout.marginWidth = 1; sideComposite.setLayout(layout); data = new FormData(); data.top = new FormAttachment(0, 0); data.bottom = new FormAttachment(100,0); data.right = new FormAttachment(100,0); sideComposite.setLayoutData(data); Button showCPButton = new Button(sideComposite,SWT.TOGGLE); showCPButton.setText("Show CtrlPts"); showCPButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { Button b = (Button)e.widget; showControlPoints(b.getSelection()); } }); Button addCPButton = new Button(sideComposite,SWT.PUSH); addCPButton.setText("Add CtrlPt"); addCPButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { addControlPoint(); } }); Button removeCPButton = new Button(sideComposite,SWT.PUSH); removeCPButton.setText("Remove CtrlPt"); removeCPButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { } }); Button showPipesButton = new Button(sideComposite,SWT.TOGGLE); showPipesButton.setText("Pipes"); showPipesButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { Button b = (Button)e.widget; showPipes(b.getSelection()); } }); } @Override public void disposeControl() { sideComposite.dispose(); } @Override public void fillContextMenu(Graph graph, IMenuManager manager, StructuredResourceSelection selection) { } @Override public void fillLocalPullDown(IMenuManager manager) { } @Override public void fillLocalToolBar(IToolBarManager manager) { } @Override public Collection getActions() { return actions; } @Override public String getName() { return "Control Points"; } List pipes = new ArrayList(); List controlPoints = new ArrayList(); private void showPipes(boolean show) { if (show) { if (!pipes.isEmpty()) { for (Node n : pipes) { n.removeFromParent(); n.dispose(); } pipes.clear(); } parent.getSession().asyncRead(new GraphRequestAdapter() { @Override public GraphRequestStatus perform(Graph g) throws Exception { PipeControlPoint pcp = new PipeControlPoint(g,controlPointResource); if (pcp.isInstanceOf(ProcessResource.plant3Dresource.EndComponentControlPoint)) { Node n = new Node(); TriMesh mesh = new TriMesh(); Point3d p1 = new Point3d(-10.0,0.0,0.0); Point3d p2 = new Point3d( 0.0,0.0,0.0); PipeComponentProvider.createStraightGeometry(p1, p2, radius, new Geometry[]{mesh}); n.attachChild(mesh); parent.getRenderingComponent().getShadowRoot().attachChild(n); pipes.add(n); } else if (pcp.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)) { double length = 0.5; Double d = pcp.getAtMostOneRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength); if (d != null) length = d; double offset = 0.0; d = pcp.getAtMostOneRelatedScalarDouble(ProcessResource.plant3Dresource.HasOffset); if (d != null) offset = d; double r = radius; if (pcp.isInstanceOf(ProcessResource.plant3Dresource.SizeChangeControlPoint)) { r = radius2; } Node n = new Node(); TriMesh mesh = new TriMesh(); Point3d p1 = new Point3d(-10.0,0.0,0.0); Point3d p2 = new Point3d( -length*0.5,0.0,0.0); PipeComponentProvider.createStraightGeometry(p1, p2, radius, new Geometry[]{mesh}); n.attachChild(mesh); parent.getRenderingComponent().getShadowRoot().attachChild(n); pipes.add(n); n = new Node(); mesh = new TriMesh(); p1 = new Point3d(10.0,offset,0.0); p2 = new Point3d(length*0.5,offset,0.0); PipeComponentProvider.createStraightGeometry(p1, p2, r, new Geometry[]{mesh}); n.attachChild(mesh); parent.getRenderingComponent().getShadowRoot().attachChild(n); pipes.add(n); } else if (pcp.isInstanceOf(ProcessResource.plant3Dresource.InlineControlPoint)) { double length = 0.5; Double d = pcp.getAtMostOneRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength); if (d != null) length = d; Node n = new Node(); TriMesh mesh = new TriMesh(); Point3d p1 = new Point3d(-10.0,0.0,0.0); Point3d p2 = new Point3d( -length*0.5,0.0,0.0); PipeComponentProvider.createStraightGeometry(p1, p2, radius, new Geometry[]{mesh}); n.attachChild(mesh); parent.getRenderingComponent().getShadowRoot().attachChild(n); pipes.add(n); n = new Node(); mesh = new TriMesh(); p1 = new Point3d(10.0,0.0,0.0); p2 = new Point3d(length*0.5,0.0,0.0); PipeComponentProvider.createStraightGeometry(p1, p2, radius, new Geometry[]{mesh}); n.attachChild(mesh); parent.getRenderingComponent().getShadowRoot().attachChild(n); pipes.add(n); } else if (pcp.isInstanceOf(ProcessResource.plant3Dresource.TurnControlPoint)) { double length = 0.5; Double d = pcp.getAtMostOneRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength); if (d != null) length = d; Node n = new Node(); TriMesh mesh = new TriMesh(); Point3d p1 = new Point3d(-10.0,0.0,0.0); Point3d p2 = new Point3d( -length*0.5,0.0,0.0); PipeComponentProvider.createStraightGeometry(p1, p2, radius, new Geometry[]{mesh}); n.attachChild(mesh); parent.getRenderingComponent().getShadowRoot().attachChild(n); pipes.add(n); n = new Node(); mesh = new TriMesh(); p1 = new Point3d(10.0,0.0,0.0); p2 = new Point3d(length*0.5,0.0,0.0); Quat4d q = new Quat4d(); q.set(new AxisAngle4d(0.0,1.0,0.0,angle)); MathTools.rotate(q, p1, p1); MathTools.rotate(q, p2, p2); PipeComponentProvider.createStraightGeometry(p1, p2, radius, new Geometry[]{mesh}); n.attachChild(mesh); parent.getRenderingComponent().getShadowRoot().attachChild(n); pipes.add(n); } else if (pcp.isInstanceOf(ProcessResource.plant3Dresource.DirectedControlPoint)) { Node n = new Node(); TriMesh mesh = new TriMesh(); Point3d p1 = new Point3d(10.0,0.0,0.0); Point3d p2 = new Point3d( 0.0,0.0,0.0); PipeComponentProvider.createStraightGeometry(p1, p2, radius, new Geometry[]{mesh}); n.attachChild(mesh); parent.getRenderingComponent().getShadowRoot().attachChild(n); pipes.add(n); } if(!pcp.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)) { Collection subPoints = pcp.getSubPoint(); } parent.setViewChanged(true); return GraphRequestStatus.transactionComplete(); } }); } else { if (!pipes.isEmpty()) { for (Node n : pipes) { n.removeFromParent(); n.dispose(); } pipes.clear(); parent.setViewChanged(true); } } } private void showControlPoints(boolean show) { if (show) { if (!controlPoints.isEmpty()) { for (Node n : controlPoints) { n.removeFromParent(); n.dispose(); } } parent.getSession().asyncRead(new GraphRequestAdapter() { @Override public GraphRequestStatus perform(Graph g) throws Exception { PipeControlPoint pcp = new PipeControlPoint(g,controlPointResource); Vector3d p = G3DTools.getVector(pcp.getWorldPosition()); Node n = new Node(); Spatial sphere = new Sphere("",5,8,0.1f); n.attachChild(sphere); n.setLocalTranslation(VecmathJmeTools.get(p)); MaterialState ms = parent.getRenderingComponent().getDisplaySystem().getRenderer().createMaterialState(); ms.setDiffuse(new ColorRGBA(1.f,0.f,0.f,0.f)); sphere.setRenderState(ms); sphere.setName(Long.toString(pcp.getResource().getResourceId())); parent.getRenderingComponent().getNoShadowRoot().attachChild(n); controlPoints.add(n); Collection subPoints = pcp.getSubPoint(); ms = parent.getRenderingComponent().getDisplaySystem().getRenderer().createMaterialState(); ms.setDiffuse(new ColorRGBA(0.f,1.f,0.f,0.f)); for (PipeControlPoint cp : subPoints) { p = G3DTools.getVector(cp.getWorldPosition()); n = new Node(); if (cp.isInstanceOf(ProcessResource.plant3Dresource.DirectedControlPoint)) { sphere = getDCPMesh(); if (sphere == null) sphere = new Sphere("",5,8,0.1f); } else { sphere = new Sphere("",5,8,0.1f); } sphere.setName(Long.toString(cp.getResource().getResourceId())); n.attachChild(sphere); n.setLocalTranslation(VecmathJmeTools.get(p)); sphere.setRenderState(ms); parent.getRenderingComponent().getNoShadowRoot().attachChild(n); controlPoints.add(n); } parent.setViewChanged(true); return GraphRequestStatus.transactionComplete(); } }); } else { if (!controlPoints.isEmpty()) { for (Node n : controlPoints) { n.removeFromParent(); n.dispose(); } parent.setViewChanged(true); } } } @Override public void initialize(Graph graph) { Resource modelResource = parent.getInputResource(); Resource inverse = graph.getInverse(ProcessResource.plant3Dresource.HasGraphics); Collection equipment = graph.getObjects(modelResource, inverse); if (equipment.size() != 1) throw new RuntimeException("Cannot find component for model " + modelResource); componentResource = equipment.iterator().next(); Collection pcp = graph.getObjects(componentResource, ProcessResource.plant3Dresource.HasControlPoint); if (pcp.size() != 1) throw new RuntimeException("Cannot find control point for component " + componentResource); controlPointResource = pcp.iterator().next(); } @Override public void dispose() { } @Override public void run() { } private void addControlPoint() { parent.getSession().asyncWrite(new GraphRequestAdapter() { @Override public GraphRequestStatus perform(Graph g) throws Exception { DirectedControlPoint dcp = DirectedControlPoint.createDefault(g); PipeControlPoint pcp = new PipeControlPoint(g,controlPointResource); pcp.addStatement(ProcessResource.plant3Dresource.HasSubPoint, dcp); return GraphRequestStatus.transactionComplete(); } }); } private Spatial getDCPMesh() { try { ObjToJme converter=new ObjToJme(); String file = "data/dcp.obj"; URL objFile=FileLocator.find(Activator.getDefault().getBundle(),new Path(file),null); converter.setProperty("mtllib",objFile); ByteArrayOutputStream BO=new ByteArrayOutputStream(); //System.out.println("Starting to convert .obj to .jme"); converter.convert(objFile.openStream(),BO); Savable s = BinaryImporter.getInstance().load(new ByteArrayInputStream(BO.toByteArray())); return (Spatial)s; } catch (Exception e) { ErrorLogger.defaultLogError(e); return null; } } }