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