+package org.simantics.proconf.g3d.shapeeditor.tools;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.Iterator;\r
+import java.util.List;\r
+import java.util.TreeMap;\r
+import java.util.Map.Entry;\r
+\r
+import javax.vecmath.AxisAngle4d;\r
+import javax.vecmath.Point3d;\r
+\r
+import org.eclipse.jface.action.Action;\r
+import org.eclipse.jface.action.IMenuManager;\r
+import org.eclipse.jface.action.IToolBarManager;\r
+import org.eclipse.jface.action.MenuManager;\r
+import org.eclipse.jface.resource.ImageDescriptor;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.layout.FormAttachment;\r
+import org.eclipse.swt.layout.FormData;\r
+import org.eclipse.swt.layout.FormLayout;\r
+import org.eclipse.swt.layout.GridData;\r
+import org.eclipse.swt.layout.GridLayout;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.swt.widgets.Text;\r
+import org.eclipse.ui.ISharedImages;\r
+import org.eclipse.ui.PlatformUI;\r
+import org.simantics.db.Graph;\r
+import org.simantics.db.GraphRequestAdapter;\r
+import org.simantics.db.GraphRequestStatus;\r
+import org.simantics.db.Resource;\r
+import org.simantics.layer0.stubs.Property;\r
+import org.simantics.layer0.utils.EntityFactory;\r
+import org.simantics.layer0.utils.IEntity;\r
+import org.simantics.layer0.utils.instantiation.Instance;\r
+import org.simantics.layer0.utils.instantiation.InstanceFactory;\r
+import org.simantics.proconf.g3d.actions.ContextAction;\r
+import org.simantics.proconf.g3d.actions.FocusAction;\r
+import org.simantics.proconf.g3d.actions.RemoveAction;\r
+import org.simantics.proconf.g3d.actions.RotateAction;\r
+import org.simantics.proconf.g3d.actions.TranslateAction;\r
+import org.simantics.proconf.g3d.actions.WriteAction;\r
+import org.simantics.proconf.g3d.base.EditorContribution;\r
+import org.simantics.proconf.g3d.base.G3DAPI;\r
+import org.simantics.proconf.g3d.base.G3DTools;\r
+import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase;\r
+import org.simantics.proconf.g3d.common.StructuredResourceSelection;\r
+import org.simantics.proconf.g3d.csg.stubs.BooleanOperation;\r
+import org.simantics.proconf.g3d.csg.stubs.CSGModel;\r
+import org.simantics.proconf.g3d.csg.stubs.CSGShape;\r
+import org.simantics.proconf.g3d.csg.stubs.Difference;\r
+import org.simantics.proconf.g3d.csg.stubs.Intersection;\r
+import org.simantics.proconf.g3d.csg.stubs.Primitive;\r
+import org.simantics.proconf.g3d.csg.stubs.Union;\r
+import org.simantics.proconf.g3d.scenegraph.IGraphicsNode;\r
+import org.simantics.proconf.g3d.shapeeditor.Activator;\r
+import org.simantics.proconf.g3d.shapeeditor.ShapeEditorResources;\r
+import org.simantics.proconf.g3d.shapeeditor.views.ShapeEditorBase;\r
+import org.simantics.proconf.g3d.stubs.G3DNode;\r
+import org.simantics.proconf.g3d.stubs.Shape;\r
+import org.simantics.utils.ErrorLogger;\r
+\r
+public class CSGModellingContribution implements EditorContribution {\r
+ \r
+ private static ImageDescriptor INTERSECTION_IMAGE = Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID,"icons/intersection.png");\r
+ private static ImageDescriptor UNION_IMAGE = Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/union.png");\r
+ private static ImageDescriptor DIFFERENCE_IMAGE = Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID,"icons/difference.png");\r
+\r
+ private ShapeEditorBase parent;\r
+ \r
+ private List<ContextAction> actions = new ArrayList<ContextAction>();\r
+ \r
+ private List<Action> addActions = new ArrayList<Action>();\r
+ private ContextAction unionAction;\r
+ private ContextAction differenceAction;\r
+ private ContextAction intersectionAction;\r
+ private ContextAction splitAction;\r
+ private ContextAction linkAction;\r
+ private ContextAction unlinkAction;\r
+ private ContextAction translateAction;\r
+ private ContextAction rotateAction;\r
+ private ContextAction removeAction;\r
+ \r
+ private Composite infoComposite;\r
+ private Text infoText;\r
+ \r
+ \r
+ public CSGModellingContribution(ThreeDimensionalEditorBase parent) {\r
+ this.parent = (ShapeEditorBase)parent; \r
+ }\r
+ \r
+ @Override\r
+ public String getName() {\r
+ return "Shape Editing";\r
+ }\r
+ \r
+ @Override\r
+ public void initialize(Graph graph) {\r
+ makeActions(graph);\r
+ }\r
+ \r
+ @Override\r
+ public void createControl(Composite parent) {\r
+ FormLayout flayout = new FormLayout();\r
+ parent.setLayout(flayout);\r
+ infoComposite = new Composite(parent, SWT.BORDER);\r
+ FormData data = new FormData();\r
+ data.top = new FormAttachment(0, 0);\r
+ data.left = new FormAttachment(0, 0);\r
+ data.right = new FormAttachment(100, 0);\r
+ data.bottom = new FormAttachment(infoComposite, 0, SWT.TOP);\r
+ this.parent.getRenderingComposite().setLayoutData(data);\r
+ data = new FormData();\r
+ data.left = new FormAttachment(0, 0);\r
+ data.right = new FormAttachment(100, 0);\r
+ data.bottom = new FormAttachment(100, 0);\r
+ data.height = 18;\r
+ infoComposite.setLayoutData(data);\r
+ GridLayout layout = new GridLayout(1,false);\r
+ layout.marginWidth = 1;\r
+ layout.marginHeight = 1;\r
+ infoComposite.setLayout(layout);\r
+ infoText = new Text(infoComposite, SWT.NONE);\r
+ GridData gdata = new GridData();\r
+ gdata.grabExcessHorizontalSpace = true;\r
+ gdata.horizontalAlignment = SWT.FILL;\r
+ infoText.setLayoutData(gdata);\r
+ }\r
+ \r
+ @Override\r
+ public void disposeControl() {\r
+ infoComposite.dispose();\r
+ }\r
+ \r
+ @Override\r
+ public void fillContextMenu(Graph graph, IMenuManager manager, StructuredResourceSelection selection) {\r
+\r
+ if (selection.isEmpty()) {\r
+ MenuManager addMenu = new MenuManager("Add", "add");\r
+ addMenu.setRemoveAllWhenShown(false);\r
+ for (Action a : addActions) {\r
+ addMenu.add(a);\r
+ }\r
+ manager.add(addMenu);\r
+ }\r
+\r
+ }\r
+ \r
+ protected void makeActions(Graph graph) {\r
+ actions.add(translateAction = new TranslateAction(parent) {\r
+ @Override\r
+ public void setInfoText(String text) {\r
+ infoText.setText(text);\r
+ }\r
+ });\r
+ actions.add(rotateAction = new RotateAction(parent){\r
+ @Override\r
+ public void setInfoText(String text) {\r
+ infoText.setText(text);\r
+ }\r
+ });\r
+ actions.add(removeAction = new RemoveAction(parent));\r
+ actions.add(new FocusAction(parent));\r
+\r
+ \r
+ IEntity primitive = EntityFactory.create(graph,ShapeEditorResources.csgResource.Primitive);\r
+ \r
+ Collection<IEntity> primitives = primitive.getRelatedObjects(graph.getBuiltins().SupertypeOf);\r
+\r
+ TreeMap<String, Resource> sorter = new TreeMap<String, Resource>();\r
+ for (IEntity p : primitives) {\r
+ String key = p.getName();\r
+ if (key.equals(""))\r
+ key = "ERROR (" + p.getURI() + ")";\r
+ sorter.put(key, p.getResource());\r
+ }\r
+\r
+ for (Entry<String, Resource> e : sorter.entrySet()) {\r
+ final String name = e.getKey();\r
+ final Resource r = e.getValue();\r
+ Action a = new Action() {\r
+ Resource res;\r
+ public void run() {\r
+ parent.getSession().asyncWrite(new GraphRequestAdapter() {\r
+ @Override\r
+ public GraphRequestStatus perform(Graph g) throws Exception {\r
+\r
+ Instance ins = InstanceFactory.getInstanceOfType(g,r);\r
+ Resource instance = ins.instantiate(g);\r
+ Shape shape = new Shape(g,instance);\r
+ res = shape.getResource();\r
+ resetShape(shape);\r
+ CSGModel model = new CSGModel(g,parent.getModelResource());\r
+ model.addStatement(ShapeEditorResources.g3dResource.HasChild, shape.getResource());\r
+ return GraphRequestStatus.transactionComplete();\r
+ }\r
+ \r
+ @Override\r
+ public void handleException(Throwable e) {\r
+ super.handleException(e);\r
+ ErrorLogger.defaultLogError("Adding " + name + " failed.", e);\r
+ }\r
+ \r
+ @Override\r
+ public void requestCompleted(GraphRequestStatus status) {\r
+ parent.getRenderingComposite().getDisplay().asyncExec(new Runnable(){\r
+ public void run() {\r
+ parent.getSelectionAdapter().updateSelection(new StructuredResourceSelection(res));\r
+ }\r
+ });\r
+ }\r
+ });\r
+ }\r
+ };\r
+ a.setText(name);\r
+ a.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(ISharedImages.IMG_OBJS_INFO_TSK));\r
+ addActions.add(a);\r
+\r
+ }\r
+\r
+ unionAction = new WriteAction(parent,false) {\r
+\r
+ Resource r;\r
+ @Override\r
+ public boolean usable(Graph graph,List<Resource> resources) {\r
+ if (resources.size() >= 2)\r
+ return true;\r
+ return false;\r
+ }\r
+\r
+ public GraphRequestStatus doChanges(Graph graph) {\r
+ List<IGraphicsNode> list = parent.getSelectionAdapter().getSelectedObjects();\r
+ if (list.size() < 2) {\r
+ showMessage("Union works between two objects");\r
+ return GraphRequestStatus.transactionCancel();\r
+ }\r
+ Resource r1 = list.get(0).getResource();\r
+ CSGShape shape1 = new CSGShape(graph,r1);\r
+\r
+ G3DNode parent = shape1.getParent();\r
+ if (parent == null) {\r
+ showMessage("Primary shape has no parent, don't know what to do");\r
+ return GraphRequestStatus.transactionCancel();\r
+ }\r
+ BooleanOperation op = Union.createDefault(graph).toBooleanOperation(); //FIXME : stubcast\r
+ r = op.getResource();\r
+ if (createBooleanOp(op, parent, shape1, list))\r
+ return GraphRequestStatus.transactionComplete();\r
+ else\r
+ return GraphRequestStatus.transactionCancel();\r
+ }\r
+ \r
+ @Override\r
+ public void afterChanges(GraphRequestStatus status) {\r
+ parent.getRenderingComposite().getDisplay().asyncExec(new Runnable(){\r
+ public void run() {\r
+ parent.getSelectionAdapter().updateSelection(new StructuredResourceSelection(r));\r
+ }\r
+ });\r
+ }\r
+ };\r
+ unionAction.setText("Union");\r
+ unionAction.setToolTipText("Union");\r
+ unionAction.setImageDescriptor(UNION_IMAGE);\r
+\r
+ differenceAction = new WriteAction(parent,false) {\r
+\r
+ Resource r;\r
+ @Override\r
+ public boolean usable(Graph graph,List<Resource> resources) {\r
+ if (resources.size() >= 2)\r
+ return true;\r
+ return false;\r
+ }\r
+\r
+ public GraphRequestStatus doChanges(Graph graph) {\r
+ List<IGraphicsNode> list = parent.getSelectionAdapter().getSelectedObjects();\r
+ if (list.size() < 2) {\r
+ showMessage("Difference works between two objects");\r
+ return GraphRequestStatus.transactionCancel();\r
+ }\r
+ CSGShape shape1 = new CSGShape(graph,list.get(0).getResource());\r
+ G3DNode parent = shape1.getParent();\r
+ if (parent == null) {\r
+ showMessage("Primary shape has no parent, don't know what to do");\r
+ return GraphRequestStatus.transactionCancel();\r
+ }\r
+ BooleanOperation op = Difference.createDefault(graph).toBooleanOperation(); //FIXME : stubcast\r
+ r = op.getResource();\r
+ if (createBooleanOp(op, parent, shape1, list))\r
+ return GraphRequestStatus.transactionComplete();\r
+ else\r
+ return GraphRequestStatus.transactionCancel();\r
+ }\r
+ \r
+ @Override\r
+ public void afterChanges(GraphRequestStatus status) {\r
+ parent.getRenderingComposite().getDisplay().asyncExec(new Runnable(){\r
+ public void run() {\r
+ parent.getSelectionAdapter().updateSelection(new StructuredResourceSelection(r));\r
+ }\r
+ });\r
+ }\r
+ };\r
+ differenceAction.setText("Difference");\r
+ differenceAction.setToolTipText("Difference");\r
+ differenceAction.setImageDescriptor(DIFFERENCE_IMAGE);\r
+\r
+ intersectionAction = new WriteAction(parent,false) {\r
+ Resource r;\r
+ @Override\r
+ public boolean usable(Graph graph,List<Resource> resources) {\r
+ if (resources.size() >= 2)\r
+ return true;\r
+ return false;\r
+ }\r
+\r
+ public GraphRequestStatus doChanges(Graph graph) {\r
+ List<IGraphicsNode> list = parent.getSelectionAdapter()\r
+ .getSelectedObjects();\r
+ if (list.size() < 2) {\r
+ showMessage("Intersection works between two objects");\r
+ return GraphRequestStatus.transactionCancel();\r
+ }\r
+ CSGShape shape1 = new CSGShape(graph,list.get(0).getResource());\r
+ G3DNode parent = shape1.getParent();\r
+ if (parent == null) {\r
+ showMessage("Primary shape has no parent, don't know what to do");\r
+ return GraphRequestStatus.transactionCancel();\r
+ }\r
+ BooleanOperation op = Intersection.createDefault(graph).toBooleanOperation(); //FIXME : stubcast\r
+ r = op.getResource();\r
+ if (createBooleanOp(op, parent, shape1, list))\r
+ return GraphRequestStatus.transactionComplete();\r
+ else\r
+ return GraphRequestStatus.transactionCancel();\r
+ }\r
+ \r
+ @Override\r
+ public void afterChanges(GraphRequestStatus status) {\r
+ parent.getRenderingComposite().getDisplay().asyncExec(new Runnable(){\r
+ public void run() {\r
+ parent.getSelectionAdapter().updateSelection(new StructuredResourceSelection(r));\r
+ }\r
+ });\r
+ \r
+ }\r
+ };\r
+ intersectionAction.setText("Intersection");\r
+ intersectionAction.setToolTipText("Intersection");\r
+ intersectionAction.setImageDescriptor(INTERSECTION_IMAGE);\r
+\r
+ splitAction = new WriteAction(parent,false) {\r
+\r
+ @Override\r
+ public boolean usable(Graph graph,List<Resource> resources) {\r
+ if (resources.size() == 1) {\r
+ Resource r = resources.iterator().next();\r
+ IEntity t = EntityFactory.create(graph,r);\r
+ if (t.isInstanceOf(ShapeEditorResources.csgResource.BooleanOperation)) {\r
+ return true;\r
+ }\r
+ }\r
+\r
+ return false;\r
+ }\r
+ \r
+ \r
+ \r
+ public GraphRequestStatus doChanges(Graph graph) {\r
+ List<IGraphicsNode> list = parent.getSelectionAdapter().getSelectedObjects();\r
+ if (list.size() != 1) {\r
+ showMessage("Split requires one object");\r
+ return GraphRequestStatus.transactionCancel();\r
+ }\r
+ Resource deletedResource = list.get(0).getResource();\r
+ IEntity deletedEntity = EntityFactory.create(graph,deletedResource);\r
+ if (!deletedEntity.isInstanceOf(ShapeEditorResources.csgResource.BooleanOperation)) {\r
+ showMessage("Split requires boolean operation");\r
+ return GraphRequestStatus.transactionCancel();\r
+ }\r
+ Collection<IEntity> parents = deletedEntity.getRelatedObjects(ShapeEditorResources.g3dResource.HasParent);\r
+ if (parents.size() != 1) {\r
+ showMessage("Shape has " + parents.size()\r
+ + " parents, don't know what to do");\r
+ return GraphRequestStatus.transactionCancel();\r
+ }\r
+ IEntity parent = parents.iterator().next();\r
+ // find all shapes and their positions and orientations relative to world coordinates\r
+ BooleanOperation op = new BooleanOperation(deletedEntity);\r
+ CSGShape shape1 = op.getMainShape();\r
+ Point3d shape1WorldPos = G3DTools.getPoint(shape1.getWorldPosition());\r
+ AxisAngle4d shape1WorldRot = G3DTools.getOrientation(shape1.getWorldOrientation());\r
+ //System.out.println(shape1WorldPos + " " + shape1WorldRot);\r
+ Collection<CSGShape> shape2s = op.getSecondaryShape();\r
+\r
+ ArrayList<Point3d> shape2WorldPos = new ArrayList<Point3d>();\r
+ ArrayList<AxisAngle4d> shape2WorldRot = new ArrayList<AxisAngle4d>();\r
+ for (CSGShape shape : shape2s) {\r
+ Point3d pos = G3DTools.getPoint(shape.getWorldPosition());\r
+ AxisAngle4d rot = G3DTools.getOrientation(shape.getWorldOrientation());\r
+ shape2WorldPos.add(pos);\r
+ shape2WorldRot.add(rot);\r
+ //System.out.println(pos + " " + rot);\r
+ }\r
+\r
+ // removed boolean operation is either connected to model or another boolean operation.\r
+ CSGModel m = new CSGModel(graph,CSGModellingContribution.this.parent.getModelResource());\r
+ if (parent.getResource().equals(CSGModellingContribution.this.parent.getModelResource())) {\r
+ // if deleted boolean operation is connected to the model,\r
+ // all its children are added to the model\r
+\r
+ m.removeStatement(ShapeEditorResources.g3dResource.HasChild, op);\r
+ m.addStatement(ShapeEditorResources.g3dResource.HasChild, shape1);\r
+ for (CSGShape shape2 : shape2s) {\r
+ m.addStatement(ShapeEditorResources.g3dResource.HasChild, shape2);\r
+ }\r
+\r
+ } else {\r
+ // deleted boolean operation is connected to another boolean\r
+ // operation\r
+ // if the deleted boolean operation is primary child, we'll\r
+ // must replace it with deleted boolean operations\r
+ // primary child\r
+ if (!parent.isInstanceOf(ShapeEditorResources.csgResource.BooleanOperation)) {\r
+ ErrorLogger.defaultLogError("Parent shape is not a boolean operation nor model ?!", null);\r
+ return GraphRequestStatus.transactionCancel();\r
+ }\r
+ BooleanOperation parentOp = new BooleanOperation(parent);\r
+ // we'll have to list all secondary shapes in parent boolean\r
+ // op so that we can find the correct relatio\r
+ Collection<IEntity> parentShape2s = parentOp.getRelatedObjects(ShapeEditorResources.csgResource.HasSecondaryShape);\r
+\r
+ if (parentOp.getMainShape().getResource().equals(deletedResource)) {\r
+ // split boolean operation is the primary child in the\r
+ // parent boolean operation\r
+ parent.removeStatement(ShapeEditorResources.csgResource.HasMainShape,deletedResource);\r
+ // graph.commitChanges(ShapeEditorView.this);\r
+ parent.addStatement(ShapeEditorResources.csgResource.HasMainShape, shape1);\r
+ // graph.commitChanges(ShapeEditorView.this);\r
+ for (CSGShape shape2 : shape2s) {\r
+ m.addStatement(ShapeEditorResources.g3dResource.HasChild, shape2);\r
+ }\r
+ } else if (contains(parentShape2s, deletedResource)) {\r
+ // split boolean operation is one of the secondary\r
+ // shapes in the parent boolean operation\r
+ parent.removeStatement(ShapeEditorResources.csgResource.HasSecondaryShape,deletedResource);\r
+ // graph.commitChanges(ShapeEditorView.this);\r
+ parent.addStatement(ShapeEditorResources.csgResource.HasSecondaryShape,shape1);\r
+ // graph.commitChanges(ShapeEditorView.this);\r
+\r
+ // model.getConsistOfShapeSet().add(shape2);\r
+ for (CSGShape shape2 : shape2s) {\r
+ m.addStatement(ShapeEditorResources.g3dResource.HasChild, shape2);\r
+ }\r
+ } else {\r
+ ErrorLogger.defaultLogError("Parent shape is not a boolean operation nor model ?!", null);\r
+ return GraphRequestStatus.transactionCancel();\r
+ }\r
+ }\r
+ deletedEntity.removeStatement(ShapeEditorResources.csgResource.HasMainShape, shape1);\r
+ for (CSGShape shape2 : shape2s)\r
+ deletedEntity.removeStatement(ShapeEditorResources.csgResource.HasSecondaryShape, shape2);\r
+ //graph.commit();\r
+ //System.out.println("Setting original transformations");\r
+ //G3DTools.setTuple3(shape1.getWorldPosition(), shape1WorldPos);\r
+ //G3DTools.setOrientation(shape1.getWorldOrientation(), shape1WorldRot);\r
+ G3DAPI.setWorldTransformation(shape1, shape1WorldPos,shape1WorldRot);\r
+ \r
+ int i = 0;\r
+ for (CSGShape shape : shape2s) {\r
+ G3DAPI.setWorldTransformation(shape, shape2WorldPos.get(i),shape2WorldRot.get(i));\r
+ //G3DTools.setTuple3(shape.getWorldPosition(), shape2WorldPos.get(i));\r
+ //G3DTools.setOrientation(shape.getWorldOrientation(),shape2WorldRot.get(i));\r
+ i++;\r
+ }\r
+ return GraphRequestStatus.transactionComplete();\r
+\r
+ }\r
+ };\r
+ splitAction.setText("Split");\r
+ splitAction.setToolTipText("Split");\r
+ splitAction.setImageDescriptor(PlatformUI.getWorkbench()\r
+ .getSharedImages().getImageDescriptor(\r
+ ISharedImages.IMG_OBJS_INFO_TSK));\r
+\r
+ linkAction = new WriteAction(parent,false) {\r
+ Resource r;\r
+ @Override\r
+ public boolean usable(Graph graph,List<Resource> resources) {\r
+ if (resources.size() == 2) {\r
+ Iterator<Resource> i = resources.iterator();\r
+ Shape s1 = new Shape(graph,i.next());\r
+ Shape s2 = new Shape(graph,i.next());\r
+ if (s1.getRelatedObjects(ShapeEditorResources.g3dResource.GeometryDefinitionOf).size() == 0 &&\r
+ s2.getRelatedObjects(ShapeEditorResources.g3dResource.GeometryDefinitionOf).size() == 0)\r
+ return true;\r
+\r
+ }\r
+ return false;\r
+ }\r
+\r
+ public GraphRequestStatus doChanges(Graph graph) {\r
+ List<IGraphicsNode> list = parent.getSelectionAdapter().getSelectedObjects();\r
+ if (list.size() != 2) {\r
+ showMessage("Link works between two objects");\r
+ return GraphRequestStatus.transactionCancel();\r
+ }\r
+ Resource r1 = list.get(0).getResource();\r
+ Resource r2 = list.get(1).getResource();\r
+\r
+ CSGShape shape1 = new CSGShape(graph,r1);\r
+ CSGShape shape2 = new CSGShape(graph,r2);\r
+ \r
+ Point3d p = G3DTools.getPoint(shape2.getWorldPosition());\r
+ AxisAngle4d aa = G3DTools.getOrientation(shape2.getWorldOrientation());\r
+ //System.out.println(p + " " + aa);\r
+ shape2.removeRelatedStatements(ShapeEditorResources.g3dResource.HasParent);\r
+ r = shape2.getResource();\r
+ //System.out.println("Link remove commit");\r
+ //graph.commitChanges(ShapeEditorView.this);\r
+ //shape1.getChild().add(shape2.toG3DNode()); //FIXME : stubcast\r
+ shape1.addStatement(ShapeEditorResources.g3dResource.HasChild, shape2);\r
+ // FIXME : this is needed\r
+ //System.out.println("Link add commit");\r
+ //graph.commitChanges(ShapeEditorView.this);\r
+ //G3DTools.setTuple3(shape2.getWorldPosition(), p);\r
+ //G3DTools.setOrientation(shape2.getWorldOrientation(), aa);\r
+ G3DAPI.setWorldTransformation(shape2, p, aa);\r
+ return GraphRequestStatus.transactionComplete();\r
+ }\r
+ \r
+ @Override\r
+ public void afterChanges(GraphRequestStatus status) {\r
+ parent.getRenderingComposite().getDisplay().asyncExec(new Runnable(){\r
+ public void run() {\r
+ parent.getSelectionAdapter().updateSelection(new StructuredResourceSelection(r));\r
+ }\r
+ });\r
+ }\r
+ };\r
+ linkAction.setText("Link");\r
+ linkAction.setToolTipText("Link");\r
+ linkAction.setImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/link.png"));\r
+\r
+ unlinkAction = new WriteAction(parent,false) {\r
+ Resource r;\r
+ @Override\r
+ public boolean usable(Graph graph,List<Resource> resources) {\r
+ if (resources.size() == 1) {\r
+ Iterator<Resource> i = resources.iterator();\r
+ Shape s1 = new Shape(graph,i.next());\r
+ return (s1.getRelatedObjects(ShapeEditorResources.g3dResource.GeometryDefinitionOf).size() == 0\r
+ && s1.getParent() != null && !s1.getParent()\r
+ .getResource().equals(CSGModellingContribution.this.parent.getModelResource()));\r
+\r
+ }\r
+ return false;\r
+ }\r
+\r
+ public GraphRequestStatus doChanges(Graph graph) {\r
+ List<IGraphicsNode> list = parent.getSelectionAdapter().getSelectedObjects();\r
+ if (list.size() != 1) {\r
+ showMessage("Unlink works with one object");\r
+ return GraphRequestStatus.transactionCancel();\r
+ }\r
+ Resource r1 = list.get(0).getResource();\r
+\r
+ CSGShape shape1 = new CSGShape(graph,r1);\r
+ CSGModel m = new CSGModel(graph,CSGModellingContribution.this.parent.getModelResource());\r
+ Point3d p = G3DTools.getPoint(shape1.getWorldPosition());\r
+ AxisAngle4d aa = G3DTools.getOrientation(shape1.getWorldOrientation());\r
+ shape1.removeRelatedStatements(ShapeEditorResources.g3dResource.HasParent);\r
+ //graph.commitChanges(ShapeEditorView.this);\r
+ m.addStatement(ShapeEditorResources.g3dResource.HasChild, shape1);\r
+ // FIXME : this is needed\r
+ //graph.commitChanges(ShapeEditorView.this);\r
+ //G3DTools.setTuple3(shape1.getWorldPosition(), p);\r
+ //G3DTools.setOrientation(shape1.getWorldOrientation(), aa);\r
+ G3DAPI.setWorldTransformation(shape1, p, aa);\r
+ r = shape1.getResource();\r
+ return GraphRequestStatus.transactionComplete();\r
+ }\r
+ \r
+ @Override\r
+ public void afterChanges(GraphRequestStatus status) {\r
+ parent.getRenderingComposite().getDisplay().asyncExec(new Runnable(){\r
+ public void run() {\r
+ parent.getSelectionAdapter().updateSelection(new StructuredResourceSelection(r));\r
+ }\r
+ });\r
+ }\r
+ };\r
+ unlinkAction.setText("Unlink");\r
+ unlinkAction.setToolTipText("Unlink");\r
+ unlinkAction.setImageDescriptor(Activator.imageDescriptorFromPlugin(\r
+ Activator.PLUGIN_ID, "icons/unlink.png"));\r
+\r
+ actions.add(unionAction);\r
+ actions.add(intersectionAction);\r
+ actions.add(differenceAction);\r
+ actions.add(splitAction);\r
+ actions.add(linkAction);\r
+ actions.add(unlinkAction);\r
+ }\r
+ \r
+ boolean contains(ArrayList<Resource> parentShape2sIds, Resource id) {\r
+ for (int i = 0; i < parentShape2sIds.size(); i++) {\r
+ if (parentShape2sIds.get(i).equals(id))\r
+ return true;\r
+\r
+ }\r
+ return false;\r
+ }\r
+ \r
+ boolean contains(Collection<IEntity> parentShape2sIds, Resource id) {\r
+ for (IEntity e : parentShape2sIds) {\r
+ if (e.getResource().equals(id))\r
+ return true;\r
+\r
+ }\r
+ return false;\r
+ }\r
+\r
+ private boolean createBooleanOp(BooleanOperation op, G3DNode parent,\r
+ CSGShape shape1, List<IGraphicsNode> list) {\r
+\r
+ resetShape(op.toShape()); //FIXME : stubcast\r
+ // new boolean operation is added to the first shape's parent\r
+ // the parent is the model\r
+\r
+ Point3d refPos = G3DTools.getPoint(shape1.getLocalPosition());\r
+ G3DTools.setTuple3(op.getLocalPosition(), refPos);\r
+ refPos.negate();\r
+ G3DTools.addTuple3(shape1.getLocalPosition(), refPos);\r
+ op.removeRelatedStatements(ShapeEditorResources.csgResource.HasMainShape);\r
+ op.addStatement(ShapeEditorResources.csgResource.HasMainShape, shape1);\r
+ \r
+ if (!replaceShape(parent, shape1.toShape(), op.toShape())) { //FIXME : stubcast\r
+ return false;\r
+ }\r
+ //model.getConsistOfSet().remove(shape1);\r
+ for (int i = 1; i < list.size(); i++) {\r
+ CSGShape shape2 = new CSGShape(op.getGraph(),list.get(i).getResource());\r
+ G3DTools.addTuple3(shape2.getLocalPosition(), refPos);\r
+ G3DNode shape2parent = shape2.getParent();\r
+ if (shape2parent != null) {\r
+ // we'll must link before removing or shape will be deleted\r
+ //op.addStatement(ShapeEditorResources.csgResource.HasSecondaryShape,shape2); \r
+ //if (!replaceShape(shape2parent, shape2, null)) {\r
+ // op.removeStatement(ShapeEditorResources.csgResource.HasSecondaryShape, shape2);\r
+ // // shape couldn't be removed so we'll remove the link\r
+ //}\r
+ \r
+ if (replaceShape(shape2parent, shape2.toShape(), null)) { //FIXME : stubcast\r
+ op.addStatement(ShapeEditorResources.csgResource.HasSecondaryShape,shape2);\r
+ }\r
+ }\r
+ }\r
+ // Commit is not needed because this is final call in all transactions\r
+ //graph.commitChanges(ShapeEditorView.this);\r
+ return true;\r
+ }\r
+\r
+ /**\r
+ * Replaces or removes parent from shape\r
+ * @param parent parent containing shape\r
+ * @param removed the shape\r
+ * @param added the replacing shape or null\r
+ * @return true if replacing or removing was successful\r
+ * @throws TransactionException\r
+ */\r
+ private boolean replaceShape(G3DNode parent, Shape removed, Shape added) {\r
+ assert (parent != null);\r
+ assert (removed != null);\r
+\r
+ \r
+ //CSGModel m = CSGModelFactory.create(parent.getGraph(),model);\r
+ if (parent.getResource().equals(this.parent.getModelResource())) {\r
+ // parent is model (rootnode). \r
+ // shape is connected to it with "Has Child" relation\r
+ parent.removeStatement(ShapeEditorResources.g3dResource.HasChild, removed);\r
+ if (added != null) {\r
+ parent.addStatement(ShapeEditorResources.g3dResource.HasChild, added);\r
+ }\r
+ } else {\r
+ // the first shape's parent is boolean operation\r
+ // so we must know if its connected as a primary shape or as a secondary shape\r
+ if (!parent.isInstanceOf(ShapeEditorResources.csgResource.BooleanOperation)) {\r
+ ErrorLogger.defaultLogError("Parent shape is not a boolean operation nor model ?!",null);\r
+ return false;\r
+ }\r
+ BooleanOperation parentOp = new BooleanOperation(parent);\r
+ // listing all secondary shapes in the parent boolean operation\r
+ Collection<CSGShape> parentShape2s = parentOp.getSecondaryShape();\r
+ ArrayList<Resource> parentShape2sIds = new ArrayList<Resource>();\r
+ for (CSGShape shape2 : parentShape2s)\r
+ parentShape2sIds.add(shape2.getResource());\r
+ if (parentOp.getMainShape().getResource().equals(removed.getResource())) {\r
+ if (added == null) {\r
+ return false;\r
+ }\r
+ parent.removeStatement(ShapeEditorResources.csgResource.HasMainShape, removed);\r
+ parent.addStatement(ShapeEditorResources.csgResource.HasMainShape, added);\r
+ \r
+ } else if (contains(parentShape2sIds, removed.getResource())) {\r
+\r
+ parent.removeStatement(ShapeEditorResources.csgResource.HasSecondaryShape, removed);\r
+ parent.addStatement(ShapeEditorResources.csgResource.HasSecondaryShape, added); \r
+ \r
+ } else {\r
+ ErrorLogger.defaultLogError("Parent shape is not a boolean operation nor model ?!",null);\r
+ //coreTC.cancelTransaction();\r
+ return false;\r
+ }\r
+ }\r
+ return true;\r
+ }\r
+\r
+ /**\r
+ * Resets shape to identity rotation and zero translation\r
+ * \r
+ * @param shape\r
+ */\r
+ private void resetShape(Shape shape) {\r
+ G3DTools.resetTransformation(shape);\r
+ Graph graph = shape.getGraph();\r
+ if (shape.isInstanceOf(ShapeEditorResources.csgResource.Primitive)) {\r
+ Primitive prim = new Primitive(shape);\r
+ Collection<Property> c = prim.getSizingProperty();\r
+ if (c.size() == 0)\r
+ ErrorLogger.getDefault().logWarning("Shape does not contain sizing properties.", null);\r
+ \r
+ for (Property p : c) {\r
+ if (p.isInstanceOf(graph.getBuiltins().Double)) {\r
+ graph.setScalarDouble(p.getResource(), 1.0);\r
+ } else if (p.isInstanceOf(graph.getBuiltins().Integer)) {\r
+ graph.setScalarInteger(p.getResource(), 1);\r
+ } else {\r
+ ErrorLogger.getDefault().logWarning("Cannot handle sizing property " + p.getName() , null);\r
+ }\r
+ }\r
+ }\r
+ \r
+ }\r
+ \r
+ protected void showMessage(String s) {\r
+ parent.showMessage(s);\r
+ }\r
+ \r
+ @Override\r
+ public Collection<ContextAction> getActions() {\r
+ return actions;\r
+ }\r
+ \r
+ \r
+ @Override\r
+ public void fillLocalToolBar(IToolBarManager manager) {\r
+\r
+ }\r
+ \r
+ @Override\r
+ public void fillLocalPullDown(IMenuManager manager) {\r
+ \r
+ }\r
+ \r
+ @Override\r
+ public void dispose() {\r
+ \r
+ }\r
+ \r
+ @Override\r
+ public void run() {\r
+\r
+ }\r
+\r
+}\r