]> gerrit.simantics Code Review - simantics/3d.git/blob
dd80c96b3264090759f55f713462b3430705d759
[simantics/3d.git] /
1 package org.simantics.proconf.g3d.shapeeditor.tools;\r
2 \r
3 import java.util.ArrayList;\r
4 import java.util.Collection;\r
5 import java.util.Iterator;\r
6 import java.util.List;\r
7 import java.util.TreeMap;\r
8 import java.util.Map.Entry;\r
9 \r
10 import javax.vecmath.AxisAngle4d;\r
11 import javax.vecmath.Point3d;\r
12 \r
13 import org.eclipse.jface.action.Action;\r
14 import org.eclipse.jface.action.IMenuManager;\r
15 import org.eclipse.jface.action.IToolBarManager;\r
16 import org.eclipse.jface.action.MenuManager;\r
17 import org.eclipse.jface.resource.ImageDescriptor;\r
18 import org.eclipse.swt.SWT;\r
19 import org.eclipse.swt.layout.FormAttachment;\r
20 import org.eclipse.swt.layout.FormData;\r
21 import org.eclipse.swt.layout.FormLayout;\r
22 import org.eclipse.swt.layout.GridData;\r
23 import org.eclipse.swt.layout.GridLayout;\r
24 import org.eclipse.swt.widgets.Composite;\r
25 import org.eclipse.swt.widgets.Text;\r
26 import org.eclipse.ui.ISharedImages;\r
27 import org.eclipse.ui.PlatformUI;\r
28 import org.simantics.db.Graph;\r
29 import org.simantics.db.GraphRequestAdapter;\r
30 import org.simantics.db.GraphRequestStatus;\r
31 import org.simantics.db.Resource;\r
32 import org.simantics.layer0.stubs.Property;\r
33 import org.simantics.layer0.utils.EntityFactory;\r
34 import org.simantics.layer0.utils.IEntity;\r
35 import org.simantics.layer0.utils.instantiation.Instance;\r
36 import org.simantics.layer0.utils.instantiation.InstanceFactory;\r
37 import org.simantics.proconf.g3d.actions.ContextAction;\r
38 import org.simantics.proconf.g3d.actions.FocusAction;\r
39 import org.simantics.proconf.g3d.actions.RemoveAction;\r
40 import org.simantics.proconf.g3d.actions.RotateAction;\r
41 import org.simantics.proconf.g3d.actions.TranslateAction;\r
42 import org.simantics.proconf.g3d.actions.WriteAction;\r
43 import org.simantics.proconf.g3d.base.EditorContribution;\r
44 import org.simantics.proconf.g3d.base.G3DAPI;\r
45 import org.simantics.proconf.g3d.base.G3DTools;\r
46 import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase;\r
47 import org.simantics.proconf.g3d.common.StructuredResourceSelection;\r
48 import org.simantics.proconf.g3d.csg.stubs.BooleanOperation;\r
49 import org.simantics.proconf.g3d.csg.stubs.CSGModel;\r
50 import org.simantics.proconf.g3d.csg.stubs.CSGShape;\r
51 import org.simantics.proconf.g3d.csg.stubs.Difference;\r
52 import org.simantics.proconf.g3d.csg.stubs.Intersection;\r
53 import org.simantics.proconf.g3d.csg.stubs.Primitive;\r
54 import org.simantics.proconf.g3d.csg.stubs.Union;\r
55 import org.simantics.proconf.g3d.scenegraph.IGraphicsNode;\r
56 import org.simantics.proconf.g3d.shapeeditor.Activator;\r
57 import org.simantics.proconf.g3d.shapeeditor.ShapeEditorResources;\r
58 import org.simantics.proconf.g3d.shapeeditor.views.ShapeEditorBase;\r
59 import org.simantics.proconf.g3d.stubs.G3DNode;\r
60 import org.simantics.proconf.g3d.stubs.Shape;\r
61 import org.simantics.utils.ErrorLogger;\r
62 \r
63 public class CSGModellingContribution implements EditorContribution {\r
64         \r
65         private static ImageDescriptor INTERSECTION_IMAGE = Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID,"icons/intersection.png");\r
66         private static ImageDescriptor UNION_IMAGE = Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/union.png");\r
67         private static ImageDescriptor DIFFERENCE_IMAGE = Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID,"icons/difference.png");\r
68 \r
69         private ShapeEditorBase parent;\r
70         \r
71         private List<ContextAction> actions = new ArrayList<ContextAction>();\r
72         \r
73         private List<Action> addActions = new ArrayList<Action>();\r
74         private ContextAction unionAction;\r
75         private ContextAction differenceAction;\r
76         private ContextAction intersectionAction;\r
77         private ContextAction splitAction;\r
78         private ContextAction linkAction;\r
79         private ContextAction unlinkAction;\r
80         private ContextAction translateAction;\r
81         private ContextAction rotateAction;\r
82         private ContextAction removeAction;\r
83         \r
84         private Composite infoComposite;\r
85         private Text infoText;\r
86         \r
87         \r
88         public CSGModellingContribution(ThreeDimensionalEditorBase parent) {\r
89                 this.parent = (ShapeEditorBase)parent;  \r
90         }\r
91         \r
92         @Override\r
93         public String getName() {\r
94                 return "Shape Editing";\r
95         }\r
96         \r
97         @Override\r
98         public void initialize(Graph graph) {\r
99                 makeActions(graph);\r
100         }\r
101         \r
102         @Override\r
103         public void createControl(Composite parent) {\r
104                 FormLayout flayout = new FormLayout();\r
105                 parent.setLayout(flayout);\r
106                 infoComposite = new Composite(parent, SWT.BORDER);\r
107                 FormData data = new FormData();\r
108                 data.top = new FormAttachment(0, 0);\r
109                 data.left = new FormAttachment(0, 0);\r
110                 data.right = new FormAttachment(100, 0);\r
111                 data.bottom = new FormAttachment(infoComposite, 0, SWT.TOP);\r
112                 this.parent.getRenderingComposite().setLayoutData(data);\r
113                 data = new FormData();\r
114                 data.left = new FormAttachment(0, 0);\r
115                 data.right = new FormAttachment(100, 0);\r
116                 data.bottom = new FormAttachment(100, 0);\r
117                 data.height = 18;\r
118                 infoComposite.setLayoutData(data);\r
119                 GridLayout layout = new GridLayout(1,false);\r
120                 layout.marginWidth = 1;\r
121                 layout.marginHeight = 1;\r
122                 infoComposite.setLayout(layout);\r
123                 infoText = new Text(infoComposite, SWT.NONE);\r
124                 GridData gdata = new GridData();\r
125                 gdata.grabExcessHorizontalSpace = true;\r
126                 gdata.horizontalAlignment = SWT.FILL;\r
127                 infoText.setLayoutData(gdata);\r
128         }\r
129         \r
130         @Override\r
131         public void disposeControl() {\r
132                 infoComposite.dispose();\r
133         }\r
134         \r
135         @Override\r
136         public void fillContextMenu(Graph graph, IMenuManager manager, StructuredResourceSelection selection) {\r
137 \r
138                 if (selection.isEmpty()) {\r
139                         MenuManager addMenu = new MenuManager("Add", "add");\r
140                         addMenu.setRemoveAllWhenShown(false);\r
141                         for (Action a : addActions) {\r
142                                 addMenu.add(a);\r
143                         }\r
144                         manager.add(addMenu);\r
145                 }\r
146 \r
147         }\r
148         \r
149         protected void makeActions(Graph graph) {\r
150                 actions.add(translateAction = new TranslateAction(parent) {\r
151                         @Override\r
152                         public void setInfoText(String text) {\r
153                                 infoText.setText(text);\r
154                         }\r
155                 });\r
156                 actions.add(rotateAction = new RotateAction(parent){\r
157                         @Override\r
158                         public void setInfoText(String text) {\r
159                                 infoText.setText(text);\r
160                         }\r
161                 });\r
162                 actions.add(removeAction = new RemoveAction(parent));\r
163                 actions.add(new FocusAction(parent));\r
164 \r
165                 \r
166                 IEntity primitive = EntityFactory.create(graph,ShapeEditorResources.csgResource.Primitive);\r
167                 \r
168                 Collection<IEntity> primitives = primitive.getRelatedObjects(graph.getBuiltins().SupertypeOf);\r
169 \r
170                 TreeMap<String, Resource> sorter = new TreeMap<String, Resource>();\r
171                 for (IEntity p : primitives) {\r
172                         String key = p.getName();\r
173                         if (key.equals(""))\r
174                                 key = "ERROR (" + p.getURI() + ")";\r
175                         sorter.put(key, p.getResource());\r
176                 }\r
177 \r
178                 for (Entry<String, Resource> e : sorter.entrySet()) {\r
179                         final String name = e.getKey();\r
180                         final Resource r = e.getValue();\r
181                         Action a = new Action() {\r
182                                 Resource res;\r
183                                 public void run() {\r
184                                         parent.getSession().asyncWrite(new GraphRequestAdapter() {\r
185                                                 @Override\r
186                                                 public GraphRequestStatus perform(Graph g) throws Exception {\r
187 \r
188                                                         Instance ins = InstanceFactory.getInstanceOfType(g,r);\r
189                                                         Resource instance = ins.instantiate(g);\r
190                                                         Shape shape = new Shape(g,instance);\r
191                                                         res = shape.getResource();\r
192                                                         resetShape(shape);\r
193                                                         CSGModel model = new CSGModel(g,parent.getModelResource());\r
194                                                         model.addStatement(ShapeEditorResources.g3dResource.HasChild, shape.getResource());\r
195                                                         return GraphRequestStatus.transactionComplete();\r
196                                                 }\r
197                                                 \r
198                                                 @Override\r
199                                                 public void handleException(Throwable e) {\r
200                                                         super.handleException(e);\r
201                                                         ErrorLogger.defaultLogError("Adding " + name + " failed.", e);\r
202                                                 }\r
203                                                 \r
204                                                 @Override\r
205                                                 public void requestCompleted(GraphRequestStatus status) {\r
206                                                         parent.getRenderingComposite().getDisplay().asyncExec(new Runnable(){\r
207                                                                 public void run() {\r
208                                                                         parent.getSelectionAdapter().updateSelection(new StructuredResourceSelection(res));\r
209                                                                 }\r
210                                                         });\r
211                                                 }\r
212                                         });\r
213                                 }\r
214                         };\r
215                         a.setText(name);\r
216                         a.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(ISharedImages.IMG_OBJS_INFO_TSK));\r
217                         addActions.add(a);\r
218 \r
219                 }\r
220 \r
221                 unionAction = new WriteAction(parent,false) {\r
222 \r
223                         Resource r;\r
224                         @Override\r
225                         public boolean usable(Graph graph,List<Resource> resources) {\r
226                                 if (resources.size() >= 2)\r
227                                         return true;\r
228                                 return false;\r
229                         }\r
230 \r
231                         public GraphRequestStatus doChanges(Graph graph) {\r
232                                 List<IGraphicsNode> list = parent.getSelectionAdapter().getSelectedObjects();\r
233                                 if (list.size() < 2) {\r
234                                         showMessage("Union works between two objects");\r
235                                         return GraphRequestStatus.transactionCancel();\r
236                                 }\r
237                                 Resource r1 = list.get(0).getResource();\r
238                                 CSGShape shape1 = new CSGShape(graph,r1);\r
239 \r
240                                 G3DNode parent = shape1.getParent();\r
241                                 if (parent == null) {\r
242                                         showMessage("Primary shape has no parent, don't know what to do");\r
243                                         return GraphRequestStatus.transactionCancel();\r
244                                 }\r
245                                 BooleanOperation op = Union.createDefault(graph).toBooleanOperation(); //FIXME : stubcast\r
246                                 r = op.getResource();\r
247                                 if (createBooleanOp(op, parent, shape1, list))\r
248                                         return GraphRequestStatus.transactionComplete();\r
249                                 else\r
250                                         return GraphRequestStatus.transactionCancel();\r
251                         }\r
252                         \r
253                         @Override\r
254                         public void afterChanges(GraphRequestStatus status) {\r
255                                 parent.getRenderingComposite().getDisplay().asyncExec(new Runnable(){\r
256                                         public void run() {\r
257                                                 parent.getSelectionAdapter().updateSelection(new StructuredResourceSelection(r));\r
258                                         }\r
259                                 });\r
260                         }\r
261                 };\r
262                 unionAction.setText("Union");\r
263                 unionAction.setToolTipText("Union");\r
264                 unionAction.setImageDescriptor(UNION_IMAGE);\r
265 \r
266                 differenceAction = new WriteAction(parent,false) {\r
267 \r
268                         Resource r;\r
269                         @Override\r
270                         public boolean usable(Graph graph,List<Resource> resources) {\r
271                                 if (resources.size() >= 2)\r
272                                         return true;\r
273                                 return false;\r
274                         }\r
275 \r
276                         public GraphRequestStatus doChanges(Graph graph) {\r
277                                 List<IGraphicsNode> list = parent.getSelectionAdapter().getSelectedObjects();\r
278                                 if (list.size() < 2) {\r
279                                         showMessage("Difference works between two objects");\r
280                                         return GraphRequestStatus.transactionCancel();\r
281                                 }\r
282                                 CSGShape shape1 = new CSGShape(graph,list.get(0).getResource());\r
283                                 G3DNode parent = shape1.getParent();\r
284                                 if (parent == null) {\r
285                                         showMessage("Primary shape has no parent, don't know what to do");\r
286                                         return GraphRequestStatus.transactionCancel();\r
287                                 }\r
288                                 BooleanOperation op = Difference.createDefault(graph).toBooleanOperation(); //FIXME : stubcast\r
289                                 r = op.getResource();\r
290                                 if (createBooleanOp(op, parent, shape1, list))\r
291                                         return GraphRequestStatus.transactionComplete();\r
292                                 else\r
293                                         return GraphRequestStatus.transactionCancel();\r
294                         }\r
295                         \r
296                         @Override\r
297                         public void afterChanges(GraphRequestStatus status) {\r
298                                 parent.getRenderingComposite().getDisplay().asyncExec(new Runnable(){\r
299                                         public void run() {\r
300                                                 parent.getSelectionAdapter().updateSelection(new StructuredResourceSelection(r));\r
301                                         }\r
302                                 });\r
303                         }\r
304                 };\r
305                 differenceAction.setText("Difference");\r
306                 differenceAction.setToolTipText("Difference");\r
307                 differenceAction.setImageDescriptor(DIFFERENCE_IMAGE);\r
308 \r
309                 intersectionAction = new WriteAction(parent,false) {\r
310                         Resource r;\r
311                         @Override\r
312                         public boolean usable(Graph graph,List<Resource> resources) {\r
313                                 if (resources.size() >= 2)\r
314                                         return true;\r
315                                 return false;\r
316                         }\r
317 \r
318                         public GraphRequestStatus doChanges(Graph graph) {\r
319                                 List<IGraphicsNode> list = parent.getSelectionAdapter()\r
320                                                 .getSelectedObjects();\r
321                                 if (list.size() < 2) {\r
322                                         showMessage("Intersection works between two objects");\r
323                                         return GraphRequestStatus.transactionCancel();\r
324                                 }\r
325                                 CSGShape shape1 = new CSGShape(graph,list.get(0).getResource());\r
326                                 G3DNode parent = shape1.getParent();\r
327                                 if (parent == null) {\r
328                                         showMessage("Primary shape has no parent, don't know what to do");\r
329                                         return GraphRequestStatus.transactionCancel();\r
330                                 }\r
331                                 BooleanOperation op = Intersection.createDefault(graph).toBooleanOperation(); //FIXME : stubcast\r
332                                 r = op.getResource();\r
333                                 if (createBooleanOp(op, parent, shape1, list))\r
334                                         return GraphRequestStatus.transactionComplete();\r
335                                 else\r
336                                         return GraphRequestStatus.transactionCancel();\r
337                         }\r
338                         \r
339                         @Override\r
340                         public void afterChanges(GraphRequestStatus status) {\r
341                                 parent.getRenderingComposite().getDisplay().asyncExec(new Runnable(){\r
342                                         public void run() {\r
343                                                 parent.getSelectionAdapter().updateSelection(new StructuredResourceSelection(r));\r
344                                         }\r
345                                 });\r
346                                 \r
347                         }\r
348                 };\r
349                 intersectionAction.setText("Intersection");\r
350                 intersectionAction.setToolTipText("Intersection");\r
351                 intersectionAction.setImageDescriptor(INTERSECTION_IMAGE);\r
352 \r
353                 splitAction = new WriteAction(parent,false) {\r
354 \r
355                         @Override\r
356                         public boolean usable(Graph graph,List<Resource> resources) {\r
357                                 if (resources.size() == 1) {\r
358                                         Resource r = resources.iterator().next();\r
359                                         IEntity t = EntityFactory.create(graph,r);\r
360                                         if (t.isInstanceOf(ShapeEditorResources.csgResource.BooleanOperation)) {\r
361                                                 return true;\r
362                                         }\r
363                                 }\r
364 \r
365                                 return false;\r
366                         }\r
367                         \r
368                         \r
369                         \r
370                         public GraphRequestStatus doChanges(Graph graph) {\r
371                                 List<IGraphicsNode> list = parent.getSelectionAdapter().getSelectedObjects();\r
372                                 if (list.size() != 1) {\r
373                                         showMessage("Split requires one object");\r
374                                         return GraphRequestStatus.transactionCancel();\r
375                                 }\r
376                                 Resource deletedResource = list.get(0).getResource();\r
377                                 IEntity deletedEntity = EntityFactory.create(graph,deletedResource);\r
378                                 if (!deletedEntity.isInstanceOf(ShapeEditorResources.csgResource.BooleanOperation)) {\r
379                                         showMessage("Split requires boolean operation");\r
380                                         return GraphRequestStatus.transactionCancel();\r
381                                 }\r
382                                 Collection<IEntity> parents = deletedEntity.getRelatedObjects(ShapeEditorResources.g3dResource.HasParent);\r
383                                 if (parents.size() != 1) {\r
384                                         showMessage("Shape has " + parents.size()\r
385                                                         + " parents, don't know what to do");\r
386                                         return GraphRequestStatus.transactionCancel();\r
387                                 }\r
388                                 IEntity parent = parents.iterator().next();\r
389                                 // find all shapes and their positions and orientations relative to world coordinates\r
390                                 BooleanOperation op = new BooleanOperation(deletedEntity);\r
391                                 CSGShape shape1 = op.getMainShape();\r
392                                 Point3d shape1WorldPos = G3DTools.getPoint(shape1.getWorldPosition());\r
393                                 AxisAngle4d shape1WorldRot = G3DTools.getOrientation(shape1.getWorldOrientation());\r
394                                 //System.out.println(shape1WorldPos + " " + shape1WorldRot);\r
395                                 Collection<CSGShape> shape2s = op.getSecondaryShape();\r
396 \r
397                                 ArrayList<Point3d> shape2WorldPos = new ArrayList<Point3d>();\r
398                                 ArrayList<AxisAngle4d> shape2WorldRot = new ArrayList<AxisAngle4d>();\r
399                                 for (CSGShape shape : shape2s) {\r
400                                         Point3d pos = G3DTools.getPoint(shape.getWorldPosition());\r
401                                         AxisAngle4d rot = G3DTools.getOrientation(shape.getWorldOrientation());\r
402                                         shape2WorldPos.add(pos);\r
403                                         shape2WorldRot.add(rot);\r
404                                         //System.out.println(pos + " " + rot);\r
405                                 }\r
406 \r
407                                 // removed boolean operation is either connected to model or another boolean operation.\r
408                                 CSGModel m = new CSGModel(graph,CSGModellingContribution.this.parent.getModelResource());\r
409                                 if (parent.getResource().equals(CSGModellingContribution.this.parent.getModelResource())) {\r
410                                         // if deleted boolean operation is connected to the model,\r
411                                         // all its children are added to the model\r
412 \r
413                                         m.removeStatement(ShapeEditorResources.g3dResource.HasChild, op);\r
414                                         m.addStatement(ShapeEditorResources.g3dResource.HasChild, shape1);\r
415                                         for (CSGShape shape2 : shape2s) {\r
416                                                 m.addStatement(ShapeEditorResources.g3dResource.HasChild, shape2);\r
417                                         }\r
418 \r
419                                 } else {\r
420                                         // deleted boolean operation is connected to another boolean\r
421                                         // operation\r
422                                         // if the deleted boolean operation is primary child, we'll\r
423                                         // must replace it with deleted boolean operations\r
424                                         // primary child\r
425                                         if (!parent.isInstanceOf(ShapeEditorResources.csgResource.BooleanOperation)) {\r
426                                                 ErrorLogger.defaultLogError("Parent shape is not a boolean operation nor model ?!", null);\r
427                                                 return GraphRequestStatus.transactionCancel();\r
428                                         }\r
429                                         BooleanOperation parentOp = new BooleanOperation(parent);\r
430                                         // we'll have to list all secondary shapes in parent boolean\r
431                                         // op so that we can find the correct relatio\r
432                                         Collection<IEntity> parentShape2s = parentOp.getRelatedObjects(ShapeEditorResources.csgResource.HasSecondaryShape);\r
433 \r
434                                         if (parentOp.getMainShape().getResource().equals(deletedResource)) {\r
435                                                 // split boolean operation is the primary child in the\r
436                                                 // parent boolean operation\r
437                                                 parent.removeStatement(ShapeEditorResources.csgResource.HasMainShape,deletedResource);\r
438                                                 // graph.commitChanges(ShapeEditorView.this);\r
439                                                 parent.addStatement(ShapeEditorResources.csgResource.HasMainShape, shape1);\r
440                                                 // graph.commitChanges(ShapeEditorView.this);\r
441                                                 for (CSGShape shape2 : shape2s) {\r
442                                                         m.addStatement(ShapeEditorResources.g3dResource.HasChild, shape2);\r
443                                                 }\r
444                                         } else if (contains(parentShape2s, deletedResource)) {\r
445                                                 // split boolean operation is one of the secondary\r
446                                                 // shapes in the parent boolean operation\r
447                                                 parent.removeStatement(ShapeEditorResources.csgResource.HasSecondaryShape,deletedResource);\r
448                                                 // graph.commitChanges(ShapeEditorView.this);\r
449                                                 parent.addStatement(ShapeEditorResources.csgResource.HasSecondaryShape,shape1);\r
450                                                 // graph.commitChanges(ShapeEditorView.this);\r
451 \r
452                                                 // model.getConsistOfShapeSet().add(shape2);\r
453                                                 for (CSGShape shape2 : shape2s) {\r
454                                                         m.addStatement(ShapeEditorResources.g3dResource.HasChild, shape2);\r
455                                                 }\r
456                                         } else {\r
457                                                 ErrorLogger.defaultLogError("Parent shape is not a boolean operation nor model ?!", null);\r
458                                                 return GraphRequestStatus.transactionCancel();\r
459                                         }\r
460                                 }\r
461                                 deletedEntity.removeStatement(ShapeEditorResources.csgResource.HasMainShape, shape1);\r
462                                 for (CSGShape shape2 : shape2s)\r
463                                         deletedEntity.removeStatement(ShapeEditorResources.csgResource.HasSecondaryShape, shape2);\r
464                                 //graph.commit();\r
465                                 //System.out.println("Setting original transformations");\r
466                                 //G3DTools.setTuple3(shape1.getWorldPosition(), shape1WorldPos);\r
467                                 //G3DTools.setOrientation(shape1.getWorldOrientation(), shape1WorldRot);\r
468                                 G3DAPI.setWorldTransformation(shape1, shape1WorldPos,shape1WorldRot);\r
469                                 \r
470                                 int i = 0;\r
471                                 for (CSGShape shape : shape2s) {\r
472                                         G3DAPI.setWorldTransformation(shape, shape2WorldPos.get(i),shape2WorldRot.get(i));\r
473                                         //G3DTools.setTuple3(shape.getWorldPosition(), shape2WorldPos.get(i));\r
474                                         //G3DTools.setOrientation(shape.getWorldOrientation(),shape2WorldRot.get(i));\r
475                                         i++;\r
476                                 }\r
477                                 return GraphRequestStatus.transactionComplete();\r
478 \r
479                         }\r
480                 };\r
481                 splitAction.setText("Split");\r
482                 splitAction.setToolTipText("Split");\r
483                 splitAction.setImageDescriptor(PlatformUI.getWorkbench()\r
484                                 .getSharedImages().getImageDescriptor(\r
485                                                 ISharedImages.IMG_OBJS_INFO_TSK));\r
486 \r
487                 linkAction = new WriteAction(parent,false) {\r
488                         Resource r;\r
489                         @Override\r
490                         public boolean usable(Graph graph,List<Resource> resources) {\r
491                                 if (resources.size() == 2) {\r
492                                         Iterator<Resource> i = resources.iterator();\r
493                                         Shape s1 = new Shape(graph,i.next());\r
494                                         Shape s2 = new Shape(graph,i.next());\r
495                                         if (s1.getRelatedObjects(ShapeEditorResources.g3dResource.GeometryDefinitionOf).size() == 0 &&\r
496                                                 s2.getRelatedObjects(ShapeEditorResources.g3dResource.GeometryDefinitionOf).size() == 0)\r
497                                                 return true;\r
498 \r
499                                 }\r
500                                 return false;\r
501                         }\r
502 \r
503                         public GraphRequestStatus doChanges(Graph graph) {\r
504                                 List<IGraphicsNode> list = parent.getSelectionAdapter().getSelectedObjects();\r
505                                 if (list.size() != 2) {\r
506                                         showMessage("Link works between two objects");\r
507                                         return GraphRequestStatus.transactionCancel();\r
508                                 }\r
509                                 Resource r1 = list.get(0).getResource();\r
510                                 Resource r2 = list.get(1).getResource();\r
511 \r
512                                 CSGShape shape1 = new CSGShape(graph,r1);\r
513                                 CSGShape shape2 = new CSGShape(graph,r2);\r
514                                 \r
515                                 Point3d p = G3DTools.getPoint(shape2.getWorldPosition());\r
516                                 AxisAngle4d aa = G3DTools.getOrientation(shape2.getWorldOrientation());\r
517                                 //System.out.println(p + " " + aa);\r
518                                 shape2.removeRelatedStatements(ShapeEditorResources.g3dResource.HasParent);\r
519                                 r = shape2.getResource();\r
520                                 //System.out.println("Link remove commit");\r
521                                 //graph.commitChanges(ShapeEditorView.this);\r
522                                 //shape1.getChild().add(shape2.toG3DNode()); //FIXME : stubcast\r
523                                 shape1.addStatement(ShapeEditorResources.g3dResource.HasChild, shape2);\r
524                                 // FIXME : this is needed\r
525                                 //System.out.println("Link add commit");\r
526                                 //graph.commitChanges(ShapeEditorView.this);\r
527                                 //G3DTools.setTuple3(shape2.getWorldPosition(), p);\r
528                                 //G3DTools.setOrientation(shape2.getWorldOrientation(), aa);\r
529                                 G3DAPI.setWorldTransformation(shape2, p, aa);\r
530                                 return GraphRequestStatus.transactionComplete();\r
531                         }\r
532                         \r
533                         @Override\r
534                         public void afterChanges(GraphRequestStatus status) {\r
535                                 parent.getRenderingComposite().getDisplay().asyncExec(new Runnable(){\r
536                                         public void run() {\r
537                                                 parent.getSelectionAdapter().updateSelection(new StructuredResourceSelection(r));\r
538                                         }\r
539                                 });\r
540                         }\r
541                 };\r
542                 linkAction.setText("Link");\r
543                 linkAction.setToolTipText("Link");\r
544                 linkAction.setImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/link.png"));\r
545 \r
546                 unlinkAction = new WriteAction(parent,false) {\r
547                         Resource r;\r
548                         @Override\r
549                         public boolean usable(Graph graph,List<Resource> resources) {\r
550                                 if (resources.size() == 1) {\r
551                                         Iterator<Resource> i = resources.iterator();\r
552                                         Shape s1 = new Shape(graph,i.next());\r
553                                         return (s1.getRelatedObjects(ShapeEditorResources.g3dResource.GeometryDefinitionOf).size() == 0\r
554                                                         && s1.getParent() != null && !s1.getParent()\r
555                                                         .getResource().equals(CSGModellingContribution.this.parent.getModelResource()));\r
556 \r
557                                 }\r
558                                 return false;\r
559                         }\r
560 \r
561                         public GraphRequestStatus doChanges(Graph graph) {\r
562                                 List<IGraphicsNode> list = parent.getSelectionAdapter().getSelectedObjects();\r
563                                 if (list.size() != 1) {\r
564                                         showMessage("Unlink works with one object");\r
565                                         return GraphRequestStatus.transactionCancel();\r
566                                 }\r
567                                 Resource r1 = list.get(0).getResource();\r
568 \r
569                                 CSGShape shape1 = new CSGShape(graph,r1);\r
570                                 CSGModel m = new CSGModel(graph,CSGModellingContribution.this.parent.getModelResource());\r
571                                 Point3d p = G3DTools.getPoint(shape1.getWorldPosition());\r
572                                 AxisAngle4d aa = G3DTools.getOrientation(shape1.getWorldOrientation());\r
573                                 shape1.removeRelatedStatements(ShapeEditorResources.g3dResource.HasParent);\r
574                                 //graph.commitChanges(ShapeEditorView.this);\r
575                                 m.addStatement(ShapeEditorResources.g3dResource.HasChild, shape1);\r
576                                 // FIXME : this is needed\r
577                                 //graph.commitChanges(ShapeEditorView.this);\r
578                                 //G3DTools.setTuple3(shape1.getWorldPosition(), p);\r
579                                 //G3DTools.setOrientation(shape1.getWorldOrientation(), aa);\r
580                                 G3DAPI.setWorldTransformation(shape1, p, aa);\r
581                                 r = shape1.getResource();\r
582                                 return GraphRequestStatus.transactionComplete();\r
583                         }\r
584                         \r
585                         @Override\r
586                         public void afterChanges(GraphRequestStatus status) {\r
587                                 parent.getRenderingComposite().getDisplay().asyncExec(new Runnable(){\r
588                                         public void run() {\r
589                                                 parent.getSelectionAdapter().updateSelection(new StructuredResourceSelection(r));\r
590                                         }\r
591                                 });\r
592                         }\r
593                 };\r
594                 unlinkAction.setText("Unlink");\r
595                 unlinkAction.setToolTipText("Unlink");\r
596                 unlinkAction.setImageDescriptor(Activator.imageDescriptorFromPlugin(\r
597                                 Activator.PLUGIN_ID, "icons/unlink.png"));\r
598 \r
599                 actions.add(unionAction);\r
600                 actions.add(intersectionAction);\r
601                 actions.add(differenceAction);\r
602                 actions.add(splitAction);\r
603                 actions.add(linkAction);\r
604                 actions.add(unlinkAction);\r
605         }\r
606         \r
607         boolean contains(ArrayList<Resource> parentShape2sIds, Resource id) {\r
608                 for (int i = 0; i < parentShape2sIds.size(); i++) {\r
609                         if (parentShape2sIds.get(i).equals(id))\r
610                                 return true;\r
611 \r
612                 }\r
613                 return false;\r
614         }\r
615         \r
616         boolean contains(Collection<IEntity> parentShape2sIds, Resource id) {\r
617                 for (IEntity e : parentShape2sIds) {\r
618                         if (e.getResource().equals(id))\r
619                                 return true;\r
620 \r
621                 }\r
622                 return false;\r
623         }\r
624 \r
625         private boolean createBooleanOp(BooleanOperation op, G3DNode parent,\r
626                         CSGShape shape1, List<IGraphicsNode> list) {\r
627 \r
628                 resetShape(op.toShape()); //FIXME : stubcast\r
629                 // new boolean operation is added to the first shape's parent\r
630                 // the parent is the model\r
631 \r
632                 Point3d refPos = G3DTools.getPoint(shape1.getLocalPosition());\r
633                 G3DTools.setTuple3(op.getLocalPosition(), refPos);\r
634                 refPos.negate();\r
635                 G3DTools.addTuple3(shape1.getLocalPosition(), refPos);\r
636                 op.removeRelatedStatements(ShapeEditorResources.csgResource.HasMainShape);\r
637                 op.addStatement(ShapeEditorResources.csgResource.HasMainShape, shape1);\r
638                 \r
639                 if (!replaceShape(parent, shape1.toShape(), op.toShape())) { //FIXME : stubcast\r
640                         return false;\r
641                 }\r
642                 //model.getConsistOfSet().remove(shape1);\r
643                 for (int i = 1; i < list.size(); i++) {\r
644                         CSGShape shape2 = new CSGShape(op.getGraph(),list.get(i).getResource());\r
645                         G3DTools.addTuple3(shape2.getLocalPosition(), refPos);\r
646                         G3DNode shape2parent = shape2.getParent();\r
647                         if (shape2parent != null) {\r
648                                 // we'll must link before removing or shape will be deleted\r
649                                 //op.addStatement(ShapeEditorResources.csgResource.HasSecondaryShape,shape2);                   \r
650                                 //if (!replaceShape(shape2parent, shape2, null)) {\r
651                                 //      op.removeStatement(ShapeEditorResources.csgResource.HasSecondaryShape, shape2);\r
652                                 //      // shape couldn't be removed so we'll remove the link\r
653                                 //}\r
654                                 \r
655                                 if (replaceShape(shape2parent, shape2.toShape(), null)) { //FIXME : stubcast\r
656                                         op.addStatement(ShapeEditorResources.csgResource.HasSecondaryShape,shape2);\r
657                                 }\r
658                         }\r
659                 }\r
660                 // Commit is not needed because this is final call in all transactions\r
661                 //graph.commitChanges(ShapeEditorView.this);\r
662                 return true;\r
663         }\r
664 \r
665         /**\r
666          * Replaces or removes parent from shape\r
667          * @param parent parent containing shape\r
668          * @param removed the shape\r
669          * @param added the replacing shape or null\r
670          * @return true if replacing or removing was successful\r
671          * @throws TransactionException\r
672          */\r
673         private boolean replaceShape(G3DNode parent, Shape removed, Shape added) {\r
674                 assert (parent != null);\r
675                 assert (removed != null);\r
676 \r
677                 \r
678                 //CSGModel m = CSGModelFactory.create(parent.getGraph(),model);\r
679                 if (parent.getResource().equals(this.parent.getModelResource())) {\r
680                         // parent is model (rootnode). \r
681                         // shape is connected to it with "Has Child" relation\r
682                         parent.removeStatement(ShapeEditorResources.g3dResource.HasChild, removed);\r
683                         if (added != null) {\r
684                                 parent.addStatement(ShapeEditorResources.g3dResource.HasChild, added);\r
685                         }\r
686                 } else {\r
687                         // the first shape's parent is boolean operation\r
688                         // so we must know if its connected as a primary shape or as a secondary shape\r
689                         if (!parent.isInstanceOf(ShapeEditorResources.csgResource.BooleanOperation)) {\r
690                                 ErrorLogger.defaultLogError("Parent shape is not a boolean operation nor model ?!",null);\r
691                                 return false;\r
692                         }\r
693                         BooleanOperation parentOp = new BooleanOperation(parent);\r
694                         // listing all secondary shapes in the parent boolean operation\r
695                         Collection<CSGShape> parentShape2s = parentOp.getSecondaryShape();\r
696                         ArrayList<Resource> parentShape2sIds = new ArrayList<Resource>();\r
697                         for (CSGShape shape2 : parentShape2s)\r
698                                 parentShape2sIds.add(shape2.getResource());\r
699                         if (parentOp.getMainShape().getResource().equals(removed.getResource())) {\r
700                                 if (added == null) {\r
701                                         return false;\r
702                                 }\r
703                                 parent.removeStatement(ShapeEditorResources.csgResource.HasMainShape, removed);\r
704                                 parent.addStatement(ShapeEditorResources.csgResource.HasMainShape, added);\r
705                         \r
706                         } else if (contains(parentShape2sIds, removed.getResource())) {\r
707 \r
708                                 parent.removeStatement(ShapeEditorResources.csgResource.HasSecondaryShape, removed);\r
709                                 parent.addStatement(ShapeEditorResources.csgResource.HasSecondaryShape, added); \r
710                 \r
711                         } else {\r
712                                 ErrorLogger.defaultLogError("Parent shape is not a boolean operation nor model ?!",null);\r
713                                 //coreTC.cancelTransaction();\r
714                                 return false;\r
715                         }\r
716                 }\r
717                 return true;\r
718         }\r
719 \r
720         /**\r
721          * Resets shape to identity rotation and zero translation\r
722          * \r
723          * @param shape\r
724          */\r
725         private void resetShape(Shape shape) {\r
726                 G3DTools.resetTransformation(shape);\r
727                 Graph graph = shape.getGraph();\r
728                 if (shape.isInstanceOf(ShapeEditorResources.csgResource.Primitive)) {\r
729                         Primitive prim = new Primitive(shape);\r
730                         Collection<Property> c = prim.getSizingProperty();\r
731                         if (c.size() == 0)\r
732                                 ErrorLogger.getDefault().logWarning("Shape does not contain sizing properties.", null);\r
733                         \r
734                         for (Property p : c) {\r
735                                 if (p.isInstanceOf(graph.getBuiltins().Double)) {\r
736                                         graph.setScalarDouble(p.getResource(), 1.0);\r
737                                 } else if (p.isInstanceOf(graph.getBuiltins().Integer)) {\r
738                                         graph.setScalarInteger(p.getResource(), 1);\r
739                                 } else {\r
740                                         ErrorLogger.getDefault().logWarning("Cannot handle sizing property " + p.getName() , null);\r
741                                 }\r
742                         }\r
743                 }\r
744                 \r
745         }\r
746         \r
747         protected void showMessage(String s) {\r
748                 parent.showMessage(s);\r
749         }\r
750         \r
751         @Override\r
752         public Collection<ContextAction> getActions() {\r
753                 return actions;\r
754         }\r
755         \r
756         \r
757         @Override\r
758         public void fillLocalToolBar(IToolBarManager manager) {\r
759 \r
760         }\r
761         \r
762         @Override\r
763         public void fillLocalPullDown(IMenuManager manager) {\r
764                 \r
765         }\r
766         \r
767         @Override\r
768         public void dispose() {\r
769                 \r
770         }\r
771         \r
772         @Override\r
773         public void run() {\r
774 \r
775         }\r
776 \r
777 }\r