]> gerrit.simantics Code Review - simantics/3d.git/commitdiff
3D framework (Simca 2012)
authorluukkainen <luukkainen@ac1ea38d-2e2b-0410-8846-a27921b304fc>
Fri, 5 Jul 2013 10:39:33 +0000 (10:39 +0000)
committerluukkainen <luukkainen@ac1ea38d-2e2b-0410-8846-a27921b304fc>
Fri, 5 Jul 2013 10:39:33 +0000 (10:39 +0000)
refs #4378

git-svn-id: https://www.simantics.org/svn/simantics/3d/trunk@27689 ac1ea38d-2e2b-0410-8846-a27921b304fc

366 files changed:
org.simantics.g3d.csg.ontology/.classpath [new file with mode: 0644]
org.simantics.g3d.csg.ontology/.project [new file with mode: 0644]
org.simantics.g3d.csg.ontology/.settings/org.eclipse.jdt.core.prefs [new file with mode: 0644]
org.simantics.g3d.csg.ontology/META-INF/MANIFEST.MF [new file with mode: 0644]
org.simantics.g3d.csg.ontology/build.properties [new file with mode: 0644]
org.simantics.g3d.csg.ontology/graph.tg [new file with mode: 0644]
org.simantics.g3d.csg.ontology/graph/csg.pgraph [new file with mode: 0644]
org.simantics.g3d.csg.ontology/graph/csgViewpoint.pgraph [new file with mode: 0644]
org.simantics.g3d.csg.ontology/graph/images/difference.png [new file with mode: 0644]
org.simantics.g3d.csg.ontology/graph/images/intersection.png [new file with mode: 0644]
org.simantics.g3d.csg.ontology/graph/images/ruby.png [new file with mode: 0644]
org.simantics.g3d.csg.ontology/graph/images/union.png [new file with mode: 0644]
org.simantics.g3d.csg.ontology/src/org/simantics/g3d/csg/ontology/CSG.java [new file with mode: 0644]
org.simantics.g3d.csg/.classpath [new file with mode: 0644]
org.simantics.g3d.csg/.project [new file with mode: 0644]
org.simantics.g3d.csg/.settings/org.eclipse.jdt.core.prefs [new file with mode: 0644]
org.simantics.g3d.csg/META-INF/MANIFEST.MF [new file with mode: 0644]
org.simantics.g3d.csg/adapters.xml [new file with mode: 0644]
org.simantics.g3d.csg/build.properties [new file with mode: 0644]
org.simantics.g3d.csg/plugin.xml [new file with mode: 0644]
org.simantics.g3d.csg/src/org/simantics/g3d/csg/Activator.java [new file with mode: 0644]
org.simantics.g3d.csg/src/org/simantics/g3d/csg/actions/AddBooleanOpAction2.java [new file with mode: 0644]
org.simantics.g3d.csg/src/org/simantics/g3d/csg/actions/AddPrimitiveAction2.java [new file with mode: 0644]
org.simantics.g3d.csg/src/org/simantics/g3d/csg/actions/SplitBooleanOpAction2.java [new file with mode: 0644]
org.simantics.g3d.csg/src/org/simantics/g3d/csg/adapters/CSGSolidModelAdapter.java [new file with mode: 0644]
org.simantics.g3d.csg/src/org/simantics/g3d/csg/adapters/NodeRemover.java [new file with mode: 0644]
org.simantics.g3d.csg/src/org/simantics/g3d/csg/editor/CSGEditor2.java [new file with mode: 0644]
org.simantics.g3d.csg/src/org/simantics/g3d/csg/editor/CSGNodeMap.java [new file with mode: 0644]
org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/BarrelNode.java [new file with mode: 0644]
org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/BoxNode.java [new file with mode: 0644]
org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/CSGnode.java [new file with mode: 0644]
org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/CSGparentNode.java [new file with mode: 0644]
org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/CSGrootNode.java [new file with mode: 0644]
org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/ConeNode.java [new file with mode: 0644]
org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/CylinderNode.java [new file with mode: 0644]
org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/DifferenceNode.java [new file with mode: 0644]
org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/EllipticCylinderNode.java [new file with mode: 0644]
org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/ICSGnode.java [new file with mode: 0644]
org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/IntersectionNode.java [new file with mode: 0644]
org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/RectangularSolidNode.java [new file with mode: 0644]
org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/RegularPrismNode.java [new file with mode: 0644]
org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/SchemaBuilder.java [new file with mode: 0644]
org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/SphereNode.java [new file with mode: 0644]
org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/TorusNode.java [new file with mode: 0644]
org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/UnionNode.java [new file with mode: 0644]
org.simantics.g3d.csg/src/org/simantics/g3d/csg/wizard/CSGBRepExportWizard.java [new file with mode: 0644]
org.simantics.g3d.csg/src/org/simantics/g3d/csg/wizard/CSGBrepModelExporter.java [new file with mode: 0644]
org.simantics.g3d.csg/src/org/simantics/g3d/csg/wizard/CSGExportModel.java [new file with mode: 0644]
org.simantics.g3d.csg/src/org/simantics/g3d/csg/wizard/CSGExportPage.java [new file with mode: 0644]
org.simantics.g3d.ontology/.classpath [new file with mode: 0644]
org.simantics.g3d.ontology/.project [new file with mode: 0644]
org.simantics.g3d.ontology/.settings/org.eclipse.jdt.core.prefs [new file with mode: 0644]
org.simantics.g3d.ontology/META-INF/MANIFEST.MF [new file with mode: 0644]
org.simantics.g3d.ontology/build.properties [new file with mode: 0644]
org.simantics.g3d.ontology/graph.tg [new file with mode: 0644]
org.simantics.g3d.ontology/graph/g3d.pgraph [new file with mode: 0644]
org.simantics.g3d.ontology/src/org/simantics/g3d/ontology/G3D.java [new file with mode: 0644]
org.simantics.g3d.vtk/.classpath [new file with mode: 0644]
org.simantics.g3d.vtk/.project [new file with mode: 0644]
org.simantics.g3d.vtk/.settings/org.eclipse.jdt.core.prefs [new file with mode: 0644]
org.simantics.g3d.vtk/META-INF/MANIFEST.MF [new file with mode: 0644]
org.simantics.g3d.vtk/build.properties [new file with mode: 0644]
org.simantics.g3d.vtk/plugin.xml [new file with mode: 0644]
org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/Activator.java [new file with mode: 0644]
org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/action/RemoveAction.java [new file with mode: 0644]
org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/action/RotateAction.java [new file with mode: 0644]
org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/action/TranslateAction.java [new file with mode: 0644]
org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/action/vtkAction.java [new file with mode: 0644]
org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/action/vtkCameraAndSelectorAction.java [new file with mode: 0644]
org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/AbstractVTKNodeMap.java [new file with mode: 0644]
org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/ActorHighlighter.java [new file with mode: 0644]
org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/HoverHighlighter.java [new file with mode: 0644]
org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/InteractiveVtkPanel.java [new file with mode: 0644]
org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/NodeSelectionProvider2.java [new file with mode: 0644]
org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/SelectionHighlighter.java [new file with mode: 0644]
org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/VTKContentOutlinePage.java [new file with mode: 0644]
org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/VTKNodeMap.java [new file with mode: 0644]
org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/VTKSelectionItem.java [new file with mode: 0644]
org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/gizmo/RotateAxisGizmo.java [new file with mode: 0644]
org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/gizmo/TranslateAxisGizmo.java [new file with mode: 0644]
org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/gizmo/TranslateGizmo.java [new file with mode: 0644]
org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/gizmo/vtkGizmo.java [new file with mode: 0644]
org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/handlers/CameraPositionHandler.java [new file with mode: 0644]
org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/handlers/ParallelPerspectiveHandler.java [new file with mode: 0644]
org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/preferences/CloseMethod.java [new file with mode: 0644]
org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/preferences/PreferenceConstants.java [new file with mode: 0644]
org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/preferences/PreferenceInitializer.java [new file with mode: 0644]
org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/preferences/VTKPreferencePage.java [new file with mode: 0644]
org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/property/VTKPropertyTabContributor.java [new file with mode: 0644]
org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/shape/DualHeadArrowActor.java [new file with mode: 0644]
org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/shape/IvtkVisualObject.java [new file with mode: 0644]
org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/shape/MeshActor.java [new file with mode: 0644]
org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/shape/axesActor.java [new file with mode: 0644]
org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/shape/axesSphereActor.java [new file with mode: 0644]
org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/shape/axesSphereActor2.java [new file with mode: 0644]
org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/shape/axisActor.java [new file with mode: 0644]
org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/shape/vtkShape.java [new file with mode: 0644]
org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/utils/vtkEffect.java [new file with mode: 0644]
org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/utils/vtkPanelUtil.java [new file with mode: 0644]
org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/utils/vtkUtil.java [new file with mode: 0644]
org.simantics.g3d/.classpath [new file with mode: 0644]
org.simantics.g3d/.project [new file with mode: 0644]
org.simantics.g3d/.settings/org.eclipse.jdt.core.prefs [new file with mode: 0644]
org.simantics.g3d/META-INF/MANIFEST.MF [new file with mode: 0644]
org.simantics.g3d/adapters.xml [new file with mode: 0644]
org.simantics.g3d/build.properties [new file with mode: 0644]
org.simantics.g3d/help-isv/arrow.png [new file with mode: 0644]
org.simantics.g3d/help-isv/introduction.mediawiki [new file with mode: 0644]
org.simantics.g3d/help-isv/print-style.css [new file with mode: 0644]
org.simantics.g3d/help-isv/style.css [new file with mode: 0644]
org.simantics.g3d/help-isv/toc.xml [new file with mode: 0644]
org.simantics.g3d/plugin.xml [new file with mode: 0644]
org.simantics.g3d/schema/toolbarCommand.exsd [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/Activator.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/adapters/NodeRemover.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/gizmo/Gizmo.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/math/EulerTools.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/math/MathTools.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/math/Ray.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/HasCollectionAdder.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/HasCollectionRemover.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/HasCollectionRuleFactory.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/HasGetSetRuleFactory.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/HasSetter.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/RelatedElementsAdd.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/RelatedElementsGet.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/RelatedElementsRem.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/RelatedGetObj.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/RelatedGetValue.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/RelatedSetObj.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/RelatedSetValue.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/factories/RelatedElementsRuleFactory.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/factories/RelatedGetSetObjRuleFactory.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/factories/RelatedGetSetValueRuleFactory.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/objmap/rules/factory/ICollectionRuleFactory.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/objmap/rules/factory/IGetSetRuleFactory.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/objmap/rules/range/CollectionAccessor.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/objmap/rules/range/GetSetObjectAccessor.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/objmap/rules/range/GetSetValueAccessor.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/objmap/schema/AdaptedLinkType.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/objmap/schema/DefaultSchema.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/objmap/schema/MappingSchemas.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/preferences/G3DPreferencePage.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/preferences/PreferenceConstants.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/preferences/PreferenceInitializer.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/property/AnnotatedPropertyTabContributorFactory.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/property/BooleanPropertyManipulator.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/property/DefaultPropertyManipulatorFactory.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/property/DoublePropertyManipulator.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/property/IntegerPropertyManipulator.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/property/MethodValueProvider.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/property/MethodWithMapValueProvider.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/property/PropertyManipulator.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/property/PropertyManipulatorFactory.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/property/PropertyTabContributor.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/property/PropertyTabContributorFactory.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/property/PropertyTabUtil.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/property/QuatPropertyManipulator.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/property/StringPropertyManipulator.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/property/ValueProvider.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/property/VectorPropertyManipulator.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/property/annotations/CompoundGetPropertyValue.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/property/annotations/CompoundSetPropertyValue.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/property/annotations/GetPropertyValue.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/property/annotations/PropertyContributor.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/property/annotations/PropertyTabBlacklist.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/property/annotations/SetPropertyValue.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/scenegraph/G3DNode.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/scenegraph/G3DparentNode.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/scenegraph/IG3DNode.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/scenegraph/NodeHighlighter.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/scenegraph/NodeMap.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/scenegraph/NodeMapProvider.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/scenegraph/RenderListener.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/scenegraph/base/INode.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/scenegraph/base/Node.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/scenegraph/base/NodeException.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/scenegraph/base/NodeListener.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/scenegraph/base/ParentNode.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/scenegraph/structural/ComponentNode.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/scenegraph/structural/Connection.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/scenegraph/structural/G3DComponentNode.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/scenegraph/structural/G3DStructuralParentNode.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/scenegraph/structural/IComponentNode.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/scenegraph/structural/IStructuralNode.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/scenegraph/structural/IStructuralRootNode.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/scenegraph/structural/StructuralParentNode.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/shape/Color4d.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/shape/Cone.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/shape/Cylinder.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/shape/Mesh.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/shape/Sphere.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/shape/Tube.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/toolbar/CommandStateRegistry.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/toolbar/ToolBarCommandRegistry.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/toolbar/ToolbarContributor.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/tools/AdaptationUtils.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/tools/Constraint.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/tools/ConstraintDetector.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/tools/DummyConstraintDetector.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/tools/NodeTools.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/tools/PluginTools.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/ui/SceneGraphDebugger.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/ui/ScenegraphOutlinePage.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/wizard/IExportModel.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/wizard/ModelExportWizard.java [new file with mode: 0644]
org.simantics.g3d/src/org/simantics/g3d/wizard/ModelExportWizardPage.java [new file with mode: 0644]
org.simantics.objmap2/.classpath [new file with mode: 0644]
org.simantics.objmap2/.project [new file with mode: 0644]
org.simantics.objmap2/.settings/org.eclipse.jdt.core.prefs [new file with mode: 0644]
org.simantics.objmap2/META-INF/MANIFEST.MF [new file with mode: 0644]
org.simantics.objmap2/build.properties [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/backward/IBackwardLinkType.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/backward/IBackwardMapping.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/backward/IBackwardMappingRule.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/backward/IBackwardMappingSchema.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/bidirectional/IBidirectionalLinkType.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/bidirectional/IBidirectionalMapping.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/bidirectional/IBidirectionalMappingRule.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/bidirectional/IBidirectionalMappingSchema.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/exceptions/MappingException.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/forward/IForwardLinkType.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/forward/IForwardMapping.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/forward/IForwardMappingRule.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/forward/IForwardMappingSchema.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/IMapping.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/IMappingListener.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/Mappings.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/Composition.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/CompoundRelatedGetValue.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/CompoundRelatedSetValue.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/DynamicGraphType.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/GetType.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/GraphType.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/HasCollectionAdder.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/HasCollectionRemover.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/HasSetter.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/OptionalRelatedElements.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedElement.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedElements.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedElementsAdd.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedElementsGet.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedElementsRem.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedGetObj.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedGetValue.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedOrderedSetElements.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedSetObj.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedSetValue.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedValue.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/SetType.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/UpdateMethod.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/CompoundRelatedGetSetValueRuleFactory.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/DataTypeUtils.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/OptionalRelatedElementsRuleFactory.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/RelatedElementRuleFactory.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/RelatedElementsRuleFactory.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/RelatedElementsRuleFactory2.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/RelatedGetSetObjRuleFactory.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/RelatedGetSetValueRuleFactory.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/RelatedOrderedSetElementsRuleFactory.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/RelatedValueRuleFactory.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/UpdateMethodFactory.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/meta/IsClassRule.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/meta/IsCollectionRule.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/meta/IsFieldRule.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/meta/IsGetSetRule.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/meta/IsMethodRule.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/impl/Link.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/impl/Mapping.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/impl/RangeUpdateRequest.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/rules/MappedElementRule.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/rules/MappedElementsRule.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/rules/ValueRule.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/rules/adapters/IdentityAdapter.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/rules/adapters/ValueAdapter.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/rules/domain/CompoundValueAccessor.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/rules/domain/IDomainAccessor.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/rules/domain/MappingUtils.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/rules/domain/RelatedObjectAccessor.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/rules/domain/RelatedObjectsAccessor.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/rules/domain/RelatedOrderedSetElementsAccessor.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/rules/domain/RelatedValueAccessor.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/rules/factory/IClassRuleFactory.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/rules/factory/ICollectionRuleFactory.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/rules/factory/IFieldRuleFactory.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/rules/factory/IGetSetRuleFactory.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/rules/factory/IMethodRuleFactory.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/rules/range/AdaptedRangeAccessor.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/rules/range/CollectionAccessor.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/rules/range/CompoundGetSetValueAccessor.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/rules/range/FieldAccessor.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/rules/range/FieldAccessorWithDefault.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/rules/range/GetSetObjectAccessor.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/rules/range/GetSetValueAccessor.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/rules/range/IRangeAccessor.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/schema/AdaptedLinkType.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/schema/DefaultSchema.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/schema/DynamicSimpleLinkType.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/schema/ILinkType.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/schema/IMappingSchema.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/schema/MappingSchemas.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/schema/SimpleLinkType.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/graph/schema/SimpleSchema.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/internal/BidirectionalLink.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/internal/BidirectionalMapping.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/internal/MonotoneBackwardMapping.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/internal/MonotoneForwardMapping.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/structural/IStructuralObject.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/structural/StructuralResource.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/StructuralRelatedElementsAdd.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/StructuralRelatedElementsGet.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/StructuralRelatedElementsRem.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/StructuralRelatedGetObj.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/StructuralRelatedSetObj.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/TypeRelatedElementsAdd.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/TypeRelatedElementsGet.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/TypeRelatedElementsRem.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/TypeRelatedGetObj.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/TypeRelatedGetValue.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/TypeRelatedSetObj.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/TypeRelatedSetValue.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/DataTypeUtils.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/OptionalRelatedElementsRuleFactory.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/RelatedElementRuleFactory.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/RelatedElementsRuleFactory.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/RelatedElementsRuleFactory2.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/RelatedGetSetObjRuleFactory.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/RelatedGetSetValueRuleFactory.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/RelatedOrderedSetElementsRuleFactory.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/RelatedValueRuleFactory.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/StructuralRelatedElementsRuleFactory2.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/StructuralRelatedGetSetObjRuleFactory.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/TypeRelatedElementsRuleFactory2.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/TypeRelatedGetSetObjRuleFactory.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/TypeRelatedGetSetValueRuleFactory.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/UpdateMethodFactory.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/structural/rules/domain/RelatedObjectAccessor.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/structural/rules/domain/RelatedObjectsAccessor.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/structural/rules/domain/RelatedOrderedSetElementsAccessor.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/structural/rules/domain/RelatedValueAccessor.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/structural/rules/domain/StructuralRelatedObjectAccessor.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/structural/rules/domain/StructuralRelatedObjectsAccessor.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/structural/rules/domain/StructuralUtils.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/structural/schema/AdaptedLinkType.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/structural/schema/DefaultSchema.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/structural/schema/MappingSchemas.java [new file with mode: 0644]
org.simantics.objmap2/src/org/simantics/objmap/structural/schema/SimpleLinkType.java [new file with mode: 0644]
org.simantics.opencascade.vtk/.classpath [new file with mode: 0644]
org.simantics.opencascade.vtk/.project [new file with mode: 0644]
org.simantics.opencascade.vtk/.settings/org.eclipse.jdt.core.prefs [new file with mode: 0644]
org.simantics.opencascade.vtk/META-INF/MANIFEST.MF [new file with mode: 0644]
org.simantics.opencascade.vtk/build.properties [new file with mode: 0644]
org.simantics.opencascade.vtk/src/org/simantics/opencascade/vtk/Activator.java [new file with mode: 0644]
org.simantics.opencascade.vtk/src/org/simantics/opencascade/vtk/EdgePointsFilter.java [new file with mode: 0644]
org.simantics.opencascade.vtk/src/org/simantics/opencascade/vtk/VTKOCCTool.java [new file with mode: 0644]
org.simantics.opencascade.vtk/src/org/simantics/opencascade/vtk/vtkSolidObject.java [new file with mode: 0644]
org.simantics.opencascade/.classpath [new file with mode: 0644]
org.simantics.opencascade/.project [new file with mode: 0644]
org.simantics.opencascade/.settings/org.eclipse.jdt.core.prefs [new file with mode: 0644]
org.simantics.opencascade/META-INF/MANIFEST.MF [new file with mode: 0644]
org.simantics.opencascade/build.properties [new file with mode: 0644]
org.simantics.opencascade/src/org/simantics/opencascade/Activator.java [new file with mode: 0644]
org.simantics.opencascade/src/org/simantics/opencascade/OCCTTool.java [new file with mode: 0644]
org.simantics.opencascade/src/org/simantics/opencascade/OccTriangulator.java [new file with mode: 0644]
org.simantics.opencascade/src/org/simantics/opencascade/ParametricSolidModelProvider.java [new file with mode: 0644]
org.simantics.opencascade/src/org/simantics/opencascade/SolidModelProvider.java [new file with mode: 0644]

diff --git a/org.simantics.g3d.csg.ontology/.classpath b/org.simantics.g3d.csg.ontology/.classpath
new file mode 100644 (file)
index 0000000..8a8f166
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<classpath>\r
+       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>\r
+       <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>\r
+       <classpathentry kind="src" path="src"/>\r
+       <classpathentry kind="output" path="bin"/>\r
+</classpath>\r
diff --git a/org.simantics.g3d.csg.ontology/.project b/org.simantics.g3d.csg.ontology/.project
new file mode 100644 (file)
index 0000000..75a8dd1
--- /dev/null
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<projectDescription>\r
+       <name>org.simantics.g3d.csg.ontology</name>\r
+       <comment></comment>\r
+       <projects>\r
+       </projects>\r
+       <buildSpec>\r
+               <buildCommand>\r
+                       <name>org.simantics.graph.builder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+               <buildCommand>\r
+                       <name>org.eclipse.jdt.core.javabuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+               <buildCommand>\r
+                       <name>org.eclipse.pde.ManifestBuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+               <buildCommand>\r
+                       <name>org.eclipse.pde.SchemaBuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+       </buildSpec>\r
+       <natures>\r
+               <nature>org.eclipse.pde.PluginNature</nature>\r
+               <nature>org.eclipse.jdt.core.javanature</nature>\r
+               <nature>org.simantics.graph.nature</nature>\r
+       </natures>\r
+</projectDescription>\r
diff --git a/org.simantics.g3d.csg.ontology/.settings/org.eclipse.jdt.core.prefs b/org.simantics.g3d.csg.ontology/.settings/org.eclipse.jdt.core.prefs
new file mode 100644 (file)
index 0000000..da2e960
--- /dev/null
@@ -0,0 +1,8 @@
+#Tue Dec 13 11:35:42 EET 2011\r
+eclipse.preferences.version=1\r
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled\r
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6\r
+org.eclipse.jdt.core.compiler.compliance=1.6\r
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error\r
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error\r
+org.eclipse.jdt.core.compiler.source=1.6\r
diff --git a/org.simantics.g3d.csg.ontology/META-INF/MANIFEST.MF b/org.simantics.g3d.csg.ontology/META-INF/MANIFEST.MF
new file mode 100644 (file)
index 0000000..7fdef4a
--- /dev/null
@@ -0,0 +1,17 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: CSG Ontology
+Bundle-SymbolicName: org.simantics.g3d.csg.ontology
+Bundle-Version: 1.0.0.qualifier
+Bundle-Vendor: VTT
+Require-Bundle: org.eclipse.core.runtime,
+ org.simantics.g3d.ontology;bundle-version="1.0.0",
+ org.simantics.layer0;bundle-version="1.0.0",
+ org.simantics.viewpoint.ontology;bundle-version="1.0.0",
+ org.simantics.project.ontology;bundle-version="1.0.0",
+ org.simantics.image2.ontology;bundle-version="1.0.0",
+ org.simantics.action.ontology;bundle-version="1.0.0",
+ org.simantics.selectionview.ontology;bundle-version="1.0.0",
+ org.simantics.simulation.ontology;bundle-version="1.0.0"
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6
+Export-Package: org.simantics.g3d.csg.ontology
diff --git a/org.simantics.g3d.csg.ontology/build.properties b/org.simantics.g3d.csg.ontology/build.properties
new file mode 100644 (file)
index 0000000..ecdc7c3
--- /dev/null
@@ -0,0 +1,5 @@
+source.. = src/\r
+output.. = bin/\r
+bin.includes = META-INF/,\\r
+               .,\\r
+               graph.tg\r
diff --git a/org.simantics.g3d.csg.ontology/graph.tg b/org.simantics.g3d.csg.ontology/graph.tg
new file mode 100644 (file)
index 0000000..5c532de
Binary files /dev/null and b/org.simantics.g3d.csg.ontology/graph.tg differ
diff --git a/org.simantics.g3d.csg.ontology/graph/csg.pgraph b/org.simantics.g3d.csg.ontology/graph/csg.pgraph
new file mode 100644 (file)
index 0000000..1a0f67c
--- /dev/null
@@ -0,0 +1,91 @@
+L0 = <http://www.simantics.org/Layer0-1.1>\r
+G3D = <http://www.simantics.org/G3D-0.1>\r
+\r
+CSG = <http://www.simantics.org/CSG-0.1> : L0.Ontology\r
+    @L0.new\r
+    L0.HasResourceClass "org.simantics.g3d.csg.ontology.CSG"\r
+\r
+CSG.Shape <T G3D.Node\r
+CSG.Model <T G3D.RootNode\r
+CSG.Primitive <T CSG.Shape\r
+    @L0.property CSG.HasSizingProperty\r
+\r
+CSG.hasPrimaryShape <R G3D.geometryDefinition\r
+    L0.HasDomain CSG.BooleanOperation\r
+    L0.HasRange CSG.Shape\r
+CSG.hasSecondaryShape <R G3D.geometryDefinition\r
+    L0.HasDomain CSG.BooleanOperation\r
+    L0.HasRange CSG.Shape\r
+CSG.hasChildShape <R G3D.children\r
+    L0.HasDomain CSG.Shape\r
+    L0.HasRange CSG.Shape\r
+CSG.BooleanOperation <T CSG.Shape\r
+    @L0.optionalProperty CSG.hasPrimaryShape\r
+    @L0.property CSG.hasSecondaryShape\r
+CSG.Difference <T CSG.BooleanOperation\r
+CSG.Intersection <T CSG.BooleanOperation\r
+CSG.Union <T CSG.BooleanOperation\r
+\r
+CSG.HasSizingProperty <R G3D.hasNonTransformation \r
+CSG.HasXAxisSize <R CSG.HasSizingProperty : L0.FunctionalRelation\r
+    L0.HasRange L0.Double\r
+CSG.HasYAxisSize <R CSG.HasSizingProperty : L0.FunctionalRelation\r
+    L0.HasRange L0.Double\r
+CSG.HasZAxisSize <R CSG.HasSizingProperty : L0.FunctionalRelation\r
+    L0.HasRange L0.Double\r
+CSG.HasXAxisMinimumSize <R CSG.HasSizingProperty : L0.FunctionalRelation\r
+    L0.HasRange L0.Double\r
+CSG.HasZAxisMinimumSize <R CSG.HasSizingProperty : L0.FunctionalRelation\r
+    L0.HasRange L0.Double\r
+CSG.HasXAxisMaximumSize <R CSG.HasSizingProperty : L0.FunctionalRelation\r
+    L0.HasRange L0.Double\r
+CSG.HasZAxisMaximumSize <R CSG.HasSizingProperty : L0.FunctionalRelation\r
+    L0.HasRange L0.Double\r
+CSG.HasRadius <R CSG.HasSizingProperty : L0.FunctionalRelation\r
+    L0.HasRange L0.Double\r
+CSG.HasMajorRadius <R CSG.HasSizingProperty : L0.FunctionalRelation\r
+    L0.HasRange L0.Double\r
+CSG.HasMinorRadius <R CSG.HasSizingProperty : L0.FunctionalRelation\r
+    L0.HasRange L0.Double\r
+CSG.HasTopRadius <R CSG.HasSizingProperty : L0.FunctionalRelation\r
+    L0.HasRange L0.Double\r
+CSG.HasBottomRadius <R CSG.HasSizingProperty : L0.FunctionalRelation\r
+    L0.HasRange L0.Double\r
+CSG.HasHeight <R CSG.HasSizingProperty : L0.FunctionalRelation\r
+    L0.HasRange L0.Double\r
+CSG.HasCorners <R CSG.HasSizingProperty : L0.FunctionalRelation\r
+    L0.HasRange L0.Integer\r
+CSG.Box <T CSG.Primitive\r
+    @L0.assert CSG.HasXAxisSize 1.0\r
+    @L0.assert CSG.HasYAxisSize 1.0\r
+    @L0.assert CSG.HasZAxisSize 1.0\r
+CSG.Sphere <T CSG.Primitive\r
+    @L0.assert CSG.HasRadius 1.0\r
+CSG.Cone <T CSG.Primitive\r
+    @L0.assert CSG.HasTopRadius 0.5\r
+    @L0.assert CSG.HasBottomRadius 1.0\r
+    @L0.assert CSG.HasHeight 1.0\r
+CSG.Cylinder <T CSG.Primitive\r
+    @L0.assert CSG.HasRadius 1.0\r
+    @L0.assert CSG.HasHeight 1.0\r
+CSG.Barrel <T CSG.Primitive\r
+    @L0.assert CSG.HasMinorRadius 0.9\r
+    @L0.assert CSG.HasMajorRadius 1.0\r
+    @L0.assert CSG.HasHeight 1.0\r
+CSG.EllipticCylinder <T CSG.Primitive\r
+    @L0.assert CSG.HasMinorRadius 0.5\r
+    @L0.assert CSG.HasMajorRadius 1.0\r
+    @L0.assert CSG.HasHeight 1.0\r
+CSG.RegularPrism <T CSG.Primitive\r
+    @L0.assert CSG.HasHeight 1.0\r
+    @L0.assert CSG.HasRadius 1.0\r
+    @L0.assert CSG.HasCorners 3\r
+CSG.Torus <T CSG.Primitive\r
+    @L0.assert CSG.HasMinorRadius 0.5\r
+    @L0.assert CSG.HasMajorRadius 1.0\r
+CSG.RectangularSolid <T CSG.Primitive\r
+    @L0.assert CSG.HasXAxisMinimumSize 0.5\r
+    @L0.assert CSG.HasXAxisMaximumSize 1.0\r
+    @L0.assert CSG.HasYAxisSize 1.0\r
+    @L0.assert CSG.HasZAxisMinimumSize 0.5\r
+    @L0.assert CSG.HasZAxisMaximumSize 1.0\r
diff --git a/org.simantics.g3d.csg.ontology/graph/csgViewpoint.pgraph b/org.simantics.g3d.csg.ontology/graph/csgViewpoint.pgraph
new file mode 100644 (file)
index 0000000..656d8cd
--- /dev/null
@@ -0,0 +1,47 @@
+L0 = <http://www.simantics.org/Layer0-1.1>\r
+VP = <http://www.simantics.org/Viewpoint-1.2>\r
+CSG = <http://www.simantics.org/CSG-0.1>\r
+PROJ = <http://www.simantics.org/Project-1.2>\r
+SIM = <http://www.simantics.org/Simulation-1.1>\r
+IMAGE = <http://www.simantics.org/Image2-1.2>\r
+ACT = <http://www.simantics.org/Action-1.1>\r
+G3D = <http://www.simantics.org/G3D-0.1>\r
+SEL = <http://www.simantics.org/SelectionView-1.2>\r
+\r
+CBC = CSG.CSGBrowseContext : VP.BrowseContext\r
+    //VP.BrowseContext.IsIncludedIn PROJ.ProjectBrowseContext\r
+    @VP.constantImageRule CSG.Union IMAGES.Union\r
+    @VP.constantImageRule CSG.Difference IMAGES.Difference\r
+    @VP.constantImageRule CSG.Intersection IMAGES.Intersection\r
+    @VP.constantImageRule CSG.Primitive IMAGES.Ruby\r
+    @VP.constantImageRule CSG.Model IMAGES.Ruby\r
+    @VP.relationChildRule CSG.Model G3D.nodes CSG.Shape\r
+    @VP.relationChildRule CSG.Shape G3D.nodes CSG.Shape\r
+    @VP.relationChildRule PROJ.Project L0.ConsistsOf CSG.Model\r
+    \r
+IMAGES = CSG.Images : L0.Library\r
+IMAGES.Union : IMAGE.PngImage\r
+    @L0.loadBytes "images/union.png"\r
+IMAGES.Difference : IMAGE.PngImage\r
+    @L0.loadBytes "images/difference.png"\r
+IMAGES.Intersection : IMAGE.PngImage\r
+    @L0.loadBytes "images/intersection.png"\r
+IMAGES.Ruby : IMAGE.PngImage\r
+    @L0.loadBytes "images/ruby.png"\r
\r
+CBC.ShapeTabContribution <T SEL.TypedVariableTabContribution\r
+    SEL.TypedVariableTabContribution.HasType CSG.Shape\r
+    \r
+    \r
+// Labels\r
+CBC.RunLabelRule : VP.LabelRule\r
+CBC\r
+    VP.BrowseContext.HasVisualsContribution _ : VP.VisualsContribution\r
+        VP.VisualsContribution.HasNodeType L0.Entity\r
+        VP.VisualsContribution.HasRule VP.ResourceLabelLabelRule\r
+        VP.VisualsContribution.HasRule VP.ResourceNameModifierRule\r
+                \r
+// Decorations\r
+CBC.ActiveLabelDecorationRule : VP.ConstantLabelDecorationRule\r
+    VP.ConstantLabelDecorationRule.HasFormat "%s [ACTIVE]"\r
+    VP.ConstantLabelDecorationRule.HasStyle "B"   
\ No newline at end of file
diff --git a/org.simantics.g3d.csg.ontology/graph/images/difference.png b/org.simantics.g3d.csg.ontology/graph/images/difference.png
new file mode 100644 (file)
index 0000000..d7b2747
Binary files /dev/null and b/org.simantics.g3d.csg.ontology/graph/images/difference.png differ
diff --git a/org.simantics.g3d.csg.ontology/graph/images/intersection.png b/org.simantics.g3d.csg.ontology/graph/images/intersection.png
new file mode 100644 (file)
index 0000000..95915d3
Binary files /dev/null and b/org.simantics.g3d.csg.ontology/graph/images/intersection.png differ
diff --git a/org.simantics.g3d.csg.ontology/graph/images/ruby.png b/org.simantics.g3d.csg.ontology/graph/images/ruby.png
new file mode 100644 (file)
index 0000000..f763a16
Binary files /dev/null and b/org.simantics.g3d.csg.ontology/graph/images/ruby.png differ
diff --git a/org.simantics.g3d.csg.ontology/graph/images/union.png b/org.simantics.g3d.csg.ontology/graph/images/union.png
new file mode 100644 (file)
index 0000000..7ffeedb
Binary files /dev/null and b/org.simantics.g3d.csg.ontology/graph/images/union.png differ
diff --git a/org.simantics.g3d.csg.ontology/src/org/simantics/g3d/csg/ontology/CSG.java b/org.simantics.g3d.csg.ontology/src/org/simantics/g3d/csg/ontology/CSG.java
new file mode 100644 (file)
index 0000000..9619f15
--- /dev/null
@@ -0,0 +1,237 @@
+package org.simantics.g3d.csg.ontology;\r
+\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.request.Read;\r
+import org.simantics.db.Session;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.service.QueryControl;\r
+\r
+public class CSG {\r
+    \r
+    public final Resource Barrel;\r
+    public final Resource BooleanOperation;\r
+    public final Resource Box;\r
+    public final Resource CSGBrowseContext;\r
+    public final Resource CSGBrowseContext_ActiveLabelDecorationRule;\r
+    public final Resource CSGBrowseContext_RunLabelRule;\r
+    public final Resource CSGBrowseContext_ShapeTabContribution;\r
+    public final Resource Cone;\r
+    public final Resource Cylinder;\r
+    public final Resource Difference;\r
+    public final Resource EllipticCylinder;\r
+    public final Resource HasBottomRadius;\r
+    public final Resource HasBottomRadius_Inverse;\r
+    public final Resource HasCorners;\r
+    public final Resource HasCorners_Inverse;\r
+    public final Resource HasHeight;\r
+    public final Resource HasHeight_Inverse;\r
+    public final Resource HasMajorRadius;\r
+    public final Resource HasMajorRadius_Inverse;\r
+    public final Resource HasMinorRadius;\r
+    public final Resource HasMinorRadius_Inverse;\r
+    public final Resource HasRadius;\r
+    public final Resource HasRadius_Inverse;\r
+    public final Resource HasSizingProperty;\r
+    public final Resource HasSizingProperty_Inverse;\r
+    public final Resource HasTopRadius;\r
+    public final Resource HasTopRadius_Inverse;\r
+    public final Resource HasXAxisMaximumSize;\r
+    public final Resource HasXAxisMaximumSize_Inverse;\r
+    public final Resource HasXAxisMinimumSize;\r
+    public final Resource HasXAxisMinimumSize_Inverse;\r
+    public final Resource HasXAxisSize;\r
+    public final Resource HasXAxisSize_Inverse;\r
+    public final Resource HasYAxisSize;\r
+    public final Resource HasYAxisSize_Inverse;\r
+    public final Resource HasZAxisMaximumSize;\r
+    public final Resource HasZAxisMaximumSize_Inverse;\r
+    public final Resource HasZAxisMinimumSize;\r
+    public final Resource HasZAxisMinimumSize_Inverse;\r
+    public final Resource HasZAxisSize;\r
+    public final Resource HasZAxisSize_Inverse;\r
+    public final Resource Images;\r
+    public final Resource Images_Difference;\r
+    public final Resource Images_Intersection;\r
+    public final Resource Images_Ruby;\r
+    public final Resource Images_Union;\r
+    public final Resource Intersection;\r
+    public final Resource Model;\r
+    public final Resource Primitive;\r
+    public final Resource RectangularSolid;\r
+    public final Resource RegularPrism;\r
+    public final Resource Shape;\r
+    public final Resource Sphere;\r
+    public final Resource Torus;\r
+    public final Resource Union;\r
+    public final Resource hasChildShape;\r
+    public final Resource hasChildShape_Inverse;\r
+    public final Resource hasPrimaryShape;\r
+    public final Resource hasPrimaryShape_Inverse;\r
+    public final Resource hasSecondaryShape;\r
+    public final Resource hasSecondaryShape_Inverse;\r
+        \r
+    public static class URIs {\r
+        public static final String Barrel = "http://www.simantics.org/CSG-0.1/Barrel";\r
+        public static final String BooleanOperation = "http://www.simantics.org/CSG-0.1/BooleanOperation";\r
+        public static final String Box = "http://www.simantics.org/CSG-0.1/Box";\r
+        public static final String CSGBrowseContext = "http://www.simantics.org/CSG-0.1/CSGBrowseContext";\r
+        public static final String CSGBrowseContext_ActiveLabelDecorationRule = "http://www.simantics.org/CSG-0.1/CSGBrowseContext/ActiveLabelDecorationRule";\r
+        public static final String CSGBrowseContext_RunLabelRule = "http://www.simantics.org/CSG-0.1/CSGBrowseContext/RunLabelRule";\r
+        public static final String CSGBrowseContext_ShapeTabContribution = "http://www.simantics.org/CSG-0.1/CSGBrowseContext/ShapeTabContribution";\r
+        public static final String Cone = "http://www.simantics.org/CSG-0.1/Cone";\r
+        public static final String Cylinder = "http://www.simantics.org/CSG-0.1/Cylinder";\r
+        public static final String Difference = "http://www.simantics.org/CSG-0.1/Difference";\r
+        public static final String EllipticCylinder = "http://www.simantics.org/CSG-0.1/EllipticCylinder";\r
+        public static final String HasBottomRadius = "http://www.simantics.org/CSG-0.1/HasBottomRadius";\r
+        public static final String HasBottomRadius_Inverse = "http://www.simantics.org/CSG-0.1/HasBottomRadius/Inverse";\r
+        public static final String HasCorners = "http://www.simantics.org/CSG-0.1/HasCorners";\r
+        public static final String HasCorners_Inverse = "http://www.simantics.org/CSG-0.1/HasCorners/Inverse";\r
+        public static final String HasHeight = "http://www.simantics.org/CSG-0.1/HasHeight";\r
+        public static final String HasHeight_Inverse = "http://www.simantics.org/CSG-0.1/HasHeight/Inverse";\r
+        public static final String HasMajorRadius = "http://www.simantics.org/CSG-0.1/HasMajorRadius";\r
+        public static final String HasMajorRadius_Inverse = "http://www.simantics.org/CSG-0.1/HasMajorRadius/Inverse";\r
+        public static final String HasMinorRadius = "http://www.simantics.org/CSG-0.1/HasMinorRadius";\r
+        public static final String HasMinorRadius_Inverse = "http://www.simantics.org/CSG-0.1/HasMinorRadius/Inverse";\r
+        public static final String HasRadius = "http://www.simantics.org/CSG-0.1/HasRadius";\r
+        public static final String HasRadius_Inverse = "http://www.simantics.org/CSG-0.1/HasRadius/Inverse";\r
+        public static final String HasSizingProperty = "http://www.simantics.org/CSG-0.1/HasSizingProperty";\r
+        public static final String HasSizingProperty_Inverse = "http://www.simantics.org/CSG-0.1/HasSizingProperty/Inverse";\r
+        public static final String HasTopRadius = "http://www.simantics.org/CSG-0.1/HasTopRadius";\r
+        public static final String HasTopRadius_Inverse = "http://www.simantics.org/CSG-0.1/HasTopRadius/Inverse";\r
+        public static final String HasXAxisMaximumSize = "http://www.simantics.org/CSG-0.1/HasXAxisMaximumSize";\r
+        public static final String HasXAxisMaximumSize_Inverse = "http://www.simantics.org/CSG-0.1/HasXAxisMaximumSize/Inverse";\r
+        public static final String HasXAxisMinimumSize = "http://www.simantics.org/CSG-0.1/HasXAxisMinimumSize";\r
+        public static final String HasXAxisMinimumSize_Inverse = "http://www.simantics.org/CSG-0.1/HasXAxisMinimumSize/Inverse";\r
+        public static final String HasXAxisSize = "http://www.simantics.org/CSG-0.1/HasXAxisSize";\r
+        public static final String HasXAxisSize_Inverse = "http://www.simantics.org/CSG-0.1/HasXAxisSize/Inverse";\r
+        public static final String HasYAxisSize = "http://www.simantics.org/CSG-0.1/HasYAxisSize";\r
+        public static final String HasYAxisSize_Inverse = "http://www.simantics.org/CSG-0.1/HasYAxisSize/Inverse";\r
+        public static final String HasZAxisMaximumSize = "http://www.simantics.org/CSG-0.1/HasZAxisMaximumSize";\r
+        public static final String HasZAxisMaximumSize_Inverse = "http://www.simantics.org/CSG-0.1/HasZAxisMaximumSize/Inverse";\r
+        public static final String HasZAxisMinimumSize = "http://www.simantics.org/CSG-0.1/HasZAxisMinimumSize";\r
+        public static final String HasZAxisMinimumSize_Inverse = "http://www.simantics.org/CSG-0.1/HasZAxisMinimumSize/Inverse";\r
+        public static final String HasZAxisSize = "http://www.simantics.org/CSG-0.1/HasZAxisSize";\r
+        public static final String HasZAxisSize_Inverse = "http://www.simantics.org/CSG-0.1/HasZAxisSize/Inverse";\r
+        public static final String Images = "http://www.simantics.org/CSG-0.1/Images";\r
+        public static final String Images_Difference = "http://www.simantics.org/CSG-0.1/Images/Difference";\r
+        public static final String Images_Intersection = "http://www.simantics.org/CSG-0.1/Images/Intersection";\r
+        public static final String Images_Ruby = "http://www.simantics.org/CSG-0.1/Images/Ruby";\r
+        public static final String Images_Union = "http://www.simantics.org/CSG-0.1/Images/Union";\r
+        public static final String Intersection = "http://www.simantics.org/CSG-0.1/Intersection";\r
+        public static final String Model = "http://www.simantics.org/CSG-0.1/Model";\r
+        public static final String Primitive = "http://www.simantics.org/CSG-0.1/Primitive";\r
+        public static final String RectangularSolid = "http://www.simantics.org/CSG-0.1/RectangularSolid";\r
+        public static final String RegularPrism = "http://www.simantics.org/CSG-0.1/RegularPrism";\r
+        public static final String Shape = "http://www.simantics.org/CSG-0.1/Shape";\r
+        public static final String Sphere = "http://www.simantics.org/CSG-0.1/Sphere";\r
+        public static final String Torus = "http://www.simantics.org/CSG-0.1/Torus";\r
+        public static final String Union = "http://www.simantics.org/CSG-0.1/Union";\r
+        public static final String hasChildShape = "http://www.simantics.org/CSG-0.1/hasChildShape";\r
+        public static final String hasChildShape_Inverse = "http://www.simantics.org/CSG-0.1/hasChildShape/Inverse";\r
+        public static final String hasPrimaryShape = "http://www.simantics.org/CSG-0.1/hasPrimaryShape";\r
+        public static final String hasPrimaryShape_Inverse = "http://www.simantics.org/CSG-0.1/hasPrimaryShape/Inverse";\r
+        public static final String hasSecondaryShape = "http://www.simantics.org/CSG-0.1/hasSecondaryShape";\r
+        public static final String hasSecondaryShape_Inverse = "http://www.simantics.org/CSG-0.1/hasSecondaryShape/Inverse";\r
+    }\r
+    \r
+    public static Resource getResourceOrNull(ReadGraph graph, String uri) {\r
+        try {\r
+            return graph.getResource(uri);\r
+        } catch(DatabaseException e) {\r
+            System.err.println(e.getMessage());\r
+            return null;\r
+        }\r
+    }\r
+    \r
+    public CSG(ReadGraph graph) {\r
+        Barrel = getResourceOrNull(graph, URIs.Barrel);\r
+        BooleanOperation = getResourceOrNull(graph, URIs.BooleanOperation);\r
+        Box = getResourceOrNull(graph, URIs.Box);\r
+        CSGBrowseContext = getResourceOrNull(graph, URIs.CSGBrowseContext);\r
+        CSGBrowseContext_ActiveLabelDecorationRule = getResourceOrNull(graph, URIs.CSGBrowseContext_ActiveLabelDecorationRule);\r
+        CSGBrowseContext_RunLabelRule = getResourceOrNull(graph, URIs.CSGBrowseContext_RunLabelRule);\r
+        CSGBrowseContext_ShapeTabContribution = getResourceOrNull(graph, URIs.CSGBrowseContext_ShapeTabContribution);\r
+        Cone = getResourceOrNull(graph, URIs.Cone);\r
+        Cylinder = getResourceOrNull(graph, URIs.Cylinder);\r
+        Difference = getResourceOrNull(graph, URIs.Difference);\r
+        EllipticCylinder = getResourceOrNull(graph, URIs.EllipticCylinder);\r
+        HasBottomRadius = getResourceOrNull(graph, URIs.HasBottomRadius);\r
+        HasBottomRadius_Inverse = getResourceOrNull(graph, URIs.HasBottomRadius_Inverse);\r
+        HasCorners = getResourceOrNull(graph, URIs.HasCorners);\r
+        HasCorners_Inverse = getResourceOrNull(graph, URIs.HasCorners_Inverse);\r
+        HasHeight = getResourceOrNull(graph, URIs.HasHeight);\r
+        HasHeight_Inverse = getResourceOrNull(graph, URIs.HasHeight_Inverse);\r
+        HasMajorRadius = getResourceOrNull(graph, URIs.HasMajorRadius);\r
+        HasMajorRadius_Inverse = getResourceOrNull(graph, URIs.HasMajorRadius_Inverse);\r
+        HasMinorRadius = getResourceOrNull(graph, URIs.HasMinorRadius);\r
+        HasMinorRadius_Inverse = getResourceOrNull(graph, URIs.HasMinorRadius_Inverse);\r
+        HasRadius = getResourceOrNull(graph, URIs.HasRadius);\r
+        HasRadius_Inverse = getResourceOrNull(graph, URIs.HasRadius_Inverse);\r
+        HasSizingProperty = getResourceOrNull(graph, URIs.HasSizingProperty);\r
+        HasSizingProperty_Inverse = getResourceOrNull(graph, URIs.HasSizingProperty_Inverse);\r
+        HasTopRadius = getResourceOrNull(graph, URIs.HasTopRadius);\r
+        HasTopRadius_Inverse = getResourceOrNull(graph, URIs.HasTopRadius_Inverse);\r
+        HasXAxisMaximumSize = getResourceOrNull(graph, URIs.HasXAxisMaximumSize);\r
+        HasXAxisMaximumSize_Inverse = getResourceOrNull(graph, URIs.HasXAxisMaximumSize_Inverse);\r
+        HasXAxisMinimumSize = getResourceOrNull(graph, URIs.HasXAxisMinimumSize);\r
+        HasXAxisMinimumSize_Inverse = getResourceOrNull(graph, URIs.HasXAxisMinimumSize_Inverse);\r
+        HasXAxisSize = getResourceOrNull(graph, URIs.HasXAxisSize);\r
+        HasXAxisSize_Inverse = getResourceOrNull(graph, URIs.HasXAxisSize_Inverse);\r
+        HasYAxisSize = getResourceOrNull(graph, URIs.HasYAxisSize);\r
+        HasYAxisSize_Inverse = getResourceOrNull(graph, URIs.HasYAxisSize_Inverse);\r
+        HasZAxisMaximumSize = getResourceOrNull(graph, URIs.HasZAxisMaximumSize);\r
+        HasZAxisMaximumSize_Inverse = getResourceOrNull(graph, URIs.HasZAxisMaximumSize_Inverse);\r
+        HasZAxisMinimumSize = getResourceOrNull(graph, URIs.HasZAxisMinimumSize);\r
+        HasZAxisMinimumSize_Inverse = getResourceOrNull(graph, URIs.HasZAxisMinimumSize_Inverse);\r
+        HasZAxisSize = getResourceOrNull(graph, URIs.HasZAxisSize);\r
+        HasZAxisSize_Inverse = getResourceOrNull(graph, URIs.HasZAxisSize_Inverse);\r
+        Images = getResourceOrNull(graph, URIs.Images);\r
+        Images_Difference = getResourceOrNull(graph, URIs.Images_Difference);\r
+        Images_Intersection = getResourceOrNull(graph, URIs.Images_Intersection);\r
+        Images_Ruby = getResourceOrNull(graph, URIs.Images_Ruby);\r
+        Images_Union = getResourceOrNull(graph, URIs.Images_Union);\r
+        Intersection = getResourceOrNull(graph, URIs.Intersection);\r
+        Model = getResourceOrNull(graph, URIs.Model);\r
+        Primitive = getResourceOrNull(graph, URIs.Primitive);\r
+        RectangularSolid = getResourceOrNull(graph, URIs.RectangularSolid);\r
+        RegularPrism = getResourceOrNull(graph, URIs.RegularPrism);\r
+        Shape = getResourceOrNull(graph, URIs.Shape);\r
+        Sphere = getResourceOrNull(graph, URIs.Sphere);\r
+        Torus = getResourceOrNull(graph, URIs.Torus);\r
+        Union = getResourceOrNull(graph, URIs.Union);\r
+        hasChildShape = getResourceOrNull(graph, URIs.hasChildShape);\r
+        hasChildShape_Inverse = getResourceOrNull(graph, URIs.hasChildShape_Inverse);\r
+        hasPrimaryShape = getResourceOrNull(graph, URIs.hasPrimaryShape);\r
+        hasPrimaryShape_Inverse = getResourceOrNull(graph, URIs.hasPrimaryShape_Inverse);\r
+        hasSecondaryShape = getResourceOrNull(graph, URIs.hasSecondaryShape);\r
+        hasSecondaryShape_Inverse = getResourceOrNull(graph, URIs.hasSecondaryShape_Inverse);\r
+    }\r
+    \r
+    public static CSG getInstance(ReadGraph graph) {\r
+        Session session = graph.getSession();\r
+        CSG ret = session.peekService(CSG.class);\r
+        if(ret == null) {\r
+            QueryControl qc = graph.getService(QueryControl.class);\r
+            ret = new CSG(qc.getIndependentGraph(graph));\r
+            session.registerService(CSG.class, ret);\r
+        }\r
+        return ret;\r
+    }\r
+    \r
+    public static CSG getInstance(Session session) throws DatabaseException {\r
+        CSG ret = session.peekService(CSG.class);\r
+        if(ret == null) {\r
+            ret = session.syncRequest(new Read<CSG>() {\r
+                public CSG perform(ReadGraph graph) throws DatabaseException {\r
+                    QueryControl qc = graph.getService(QueryControl.class);\r
+                    return new CSG(qc.getIndependentGraph(graph));\r
+                }\r
+            });\r
+            session.registerService(CSG.class, ret);\r
+        }\r
+        return ret;\r
+    }\r
+    \r
+}\r
+\r
diff --git a/org.simantics.g3d.csg/.classpath b/org.simantics.g3d.csg/.classpath
new file mode 100644 (file)
index 0000000..8a8f166
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<classpath>\r
+       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>\r
+       <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>\r
+       <classpathentry kind="src" path="src"/>\r
+       <classpathentry kind="output" path="bin"/>\r
+</classpath>\r
diff --git a/org.simantics.g3d.csg/.project b/org.simantics.g3d.csg/.project
new file mode 100644 (file)
index 0000000..ab3f164
--- /dev/null
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<projectDescription>\r
+       <name>org.simantics.g3d.csg</name>\r
+       <comment></comment>\r
+       <projects>\r
+       </projects>\r
+       <buildSpec>\r
+               <buildCommand>\r
+                       <name>org.eclipse.jdt.core.javabuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+               <buildCommand>\r
+                       <name>org.eclipse.pde.ManifestBuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+               <buildCommand>\r
+                       <name>org.eclipse.pde.SchemaBuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+       </buildSpec>\r
+       <natures>\r
+               <nature>org.eclipse.pde.PluginNature</nature>\r
+               <nature>org.eclipse.jdt.core.javanature</nature>\r
+       </natures>\r
+</projectDescription>\r
diff --git a/org.simantics.g3d.csg/.settings/org.eclipse.jdt.core.prefs b/org.simantics.g3d.csg/.settings/org.eclipse.jdt.core.prefs
new file mode 100644 (file)
index 0000000..56c2dc8
--- /dev/null
@@ -0,0 +1,8 @@
+#Mon Dec 12 16:51:11 EET 2011\r
+eclipse.preferences.version=1\r
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled\r
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6\r
+org.eclipse.jdt.core.compiler.compliance=1.6\r
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error\r
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error\r
+org.eclipse.jdt.core.compiler.source=1.6\r
diff --git a/org.simantics.g3d.csg/META-INF/MANIFEST.MF b/org.simantics.g3d.csg/META-INF/MANIFEST.MF
new file mode 100644 (file)
index 0000000..a0a1c81
--- /dev/null
@@ -0,0 +1,26 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Csg
+Bundle-SymbolicName: org.simantics.g3d.csg;singleton:=true
+Bundle-Version: 1.0.0.qualifier
+Bundle-Activator: org.simantics.g3d.csg.Activator
+Bundle-Vendor: VTT
+Require-Bundle: org.eclipse.core.runtime,
+ org.simantics.g3d;bundle-version="1.0.0",
+ org.simantics.g3d.ontology;bundle-version="1.0.0",
+ org.simantics.db.layer0;bundle-version="1.1.0",
+ javax.vecmath;bundle-version="1.5.2",
+ org.simantics.opencascade;bundle-version="1.0.0",
+ org.simantics.ui;bundle-version="1.0.0",
+ vtk;bundle-version="1.0.0",
+ org.eclipse.ui,
+ org.simantics.g3d.csg.ontology;bundle-version="1.0.0",
+ org.simantics.selectionview;bundle-version="1.0.0",
+ org.eclipse.ui.views;bundle-version="3.5.1",
+ org.jcae.opencascade;bundle-version="1.0.0",
+ org.simantics.g3d.vtk;bundle-version="1.0.0",
+ org.simantics.browsing.ui.common;bundle-version="1.1.0",
+ org.simantics.objmap2;bundle-version="1.0.0",
+ org.simantics.opencascade.vtk;bundle-version="1.0.0"
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6
+Bundle-ActivationPolicy: lazy
diff --git a/org.simantics.g3d.csg/adapters.xml b/org.simantics.g3d.csg/adapters.xml
new file mode 100644 (file)
index 0000000..cfa703b
--- /dev/null
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<adapters>\r
+<target interface="org.simantics.opencascade.SolidModelProvider">\r
+ <type uri="http://www.simantics.org/CSG-0.1/Model"\r
+  class="org.simantics.g3d.csg.adapters.CSGSolidModelAdapter">\r
+  <this />\r
+ </type>\r
+</target>\r
+<target interface="org.simantics.db.layer0.adapter.Remover">\r
+   <type uri="http://www.simantics.org/CSG-0.1/Shape"\r
+               class="org.simantics.g3d.csg.adapters.NodeRemover">\r
+               <this />\r
+       </type>\r
+       </target>\r
+</adapters>
\ No newline at end of file
diff --git a/org.simantics.g3d.csg/build.properties b/org.simantics.g3d.csg/build.properties
new file mode 100644 (file)
index 0000000..95ac1cc
--- /dev/null
@@ -0,0 +1,6 @@
+source.. = src/\r
+output.. = bin/\r
+bin.includes = META-INF/,\\r
+               .,\\r
+               plugin.xml,\\r
+               adapters.xml\r
diff --git a/org.simantics.g3d.csg/plugin.xml b/org.simantics.g3d.csg/plugin.xml
new file mode 100644 (file)
index 0000000..d167ef3
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<?eclipse version="3.4"?>\r
+<plugin>\r
+   <extension\r
+         point="org.eclipse.ui.editors">\r
+      <editor\r
+            class="org.simantics.g3d.csg.editor.CSGEditor2"\r
+            default="false"\r
+            icon="platform:/plugin/com.famfamfam.silk/icons/ruby.png"\r
+            id="org.simantics.g3d.csg.editor2"\r
+            name="CSG Editor">\r
+      </editor>\r
+   </extension>\r
+   <extension\r
+         point="org.simantics.ui.resourceEditorAdapter">\r
+      <adapter\r
+            editorId="org.simantics.g3d.csg.editor2"\r
+            image="platform:/plugin/com.famfamfam.silk/icons/ruby.png"\r
+            label="CSG Editor"\r
+            priority="1"\r
+            type_uris="http://www.simantics.org/CSG-0.1/Model">\r
+      </adapter>\r
+   </extension>\r
+   <extension\r
+         point="org.eclipse.ui.exportWizards">\r
+      <category\r
+            id="org.simantics.g3d.csg.category"\r
+            name="CSG Exports">\r
+      </category>\r
+      <wizard\r
+            category="org.simantics.g3d.csg.category"\r
+            class="org.simantics.g3d.csg.wizard.CSGBRepExportWizard"\r
+            id="org.simantics.g3d.csg.brepexportwizard"\r
+            name="CSG BREP Export Wizard">\r
+      </wizard>\r
+   </extension>\r
+\r
+</plugin>\r
diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/Activator.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/Activator.java
new file mode 100644 (file)
index 0000000..e2a0651
--- /dev/null
@@ -0,0 +1,46 @@
+package org.simantics.g3d.csg;\r
+\r
+import org.eclipse.ui.plugin.AbstractUIPlugin;\r
+import org.osgi.framework.BundleContext;\r
+\r
+public class Activator extends AbstractUIPlugin  {\r
+\r
+       // The plug-in ID\r
+               public static final String PLUGIN_ID = "org.simantics.g3d.csg"; //$NON-NLS-1$\r
+\r
+               // The shared instance\r
+               private static Activator plugin;\r
+               \r
+               /**\r
+                * The constructor\r
+                */\r
+               public Activator() {\r
+               }\r
+\r
+               /*\r
+                * (non-Javadoc)\r
+                * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)\r
+                */\r
+               public void start(BundleContext context) throws Exception {\r
+                       super.start(context);\r
+                       plugin = this;\r
+               }\r
+\r
+               /*\r
+                * (non-Javadoc)\r
+                * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)\r
+                */\r
+               public void stop(BundleContext context) throws Exception {\r
+                       plugin = null;\r
+                       super.stop(context);\r
+               }\r
+\r
+               /**\r
+                * Returns the shared instance\r
+                *\r
+                * @return the shared instance\r
+                */\r
+               public static Activator getDefault() {\r
+                       return plugin;\r
+               }\r
+}\r
diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/actions/AddBooleanOpAction2.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/actions/AddBooleanOpAction2.java
new file mode 100644 (file)
index 0000000..6d6cff9
--- /dev/null
@@ -0,0 +1,69 @@
+package org.simantics.g3d.csg.actions;\r
+\r
+import java.util.Collection;\r
+import java.util.HashMap;\r
+import java.util.Iterator;\r
+import java.util.Map;\r
+\r
+import javax.vecmath.Quat4d;\r
+import javax.vecmath.Vector3d;\r
+\r
+import org.eclipse.jface.action.Action;\r
+import org.simantics.g3d.csg.scenegraph2.CSGparentNode;\r
+import org.simantics.g3d.csg.scenegraph2.CSGrootNode;\r
+import org.simantics.g3d.csg.scenegraph2.ICSGnode;\r
+import org.simantics.utils.ui.ExceptionUtils;\r
+\r
+public class AddBooleanOpAction2 extends Action {\r
+       CSGrootNode root;\r
+       Class<? extends CSGparentNode> booleanClass;\r
+       Collection<ICSGnode> nodes;\r
+       \r
+       public AddBooleanOpAction2(CSGrootNode root, Class<? extends CSGparentNode> booleanClass, Collection<ICSGnode> nodes) {\r
+               super();\r
+               String name = booleanClass.getSimpleName();\r
+               if (name.endsWith("Node"))\r
+                       name = name.substring(0,name.length()-4);\r
+               setText(name);\r
+               this.booleanClass = booleanClass;\r
+               this.nodes = nodes;\r
+               this.root = root;\r
+               if (nodes.size() != 2)\r
+                       setEnabled(false);\r
+               for (ICSGnode node : nodes) {\r
+                       if (!node.getParent().equals(root))\r
+                               setEnabled(false);\r
+               }\r
+       }\r
+       \r
+       @Override\r
+       public void run() {\r
+               try {\r
+                       CSGparentNode booleanNode = booleanClass.newInstance();\r
+                       Map<ICSGnode,Vector3d> positions = new HashMap<ICSGnode, Vector3d>();\r
+                       Map<ICSGnode,Quat4d> orientations = new HashMap<ICSGnode, Quat4d>();\r
+                       for (ICSGnode node : nodes) {\r
+                               positions.put(node, node.getWorldPosition());\r
+                               orientations.put(node, node.getWorldOrientation());\r
+                               //root.remChild(node);\r
+                               node.deattach();\r
+                       }\r
+                       Iterator<ICSGnode> iter = nodes.iterator();\r
+                       booleanNode.addPrimaryChild(iter.next());\r
+                       booleanNode.addSecondaryChild(iter.next());\r
+                       \r
+                       String name = root.getUniqueName(booleanNode.getClass().getSimpleName());\r
+                       booleanNode.setName(name);\r
+                       \r
+                       root.addChild(booleanNode);\r
+                       for (ICSGnode node : nodes) {\r
+                               node.setWorldPosition(positions.get(node));\r
+                               node.setWorldOrientation(orientations.get(node));\r
+                       }\r
+                       root.getNodeMap().commit();\r
+               } catch (Exception e) {\r
+                       ExceptionUtils.logAndShowError("Cannot create boolean operation.", e);\r
+               }\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/actions/AddPrimitiveAction2.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/actions/AddPrimitiveAction2.java
new file mode 100644 (file)
index 0000000..b3687f3
--- /dev/null
@@ -0,0 +1,35 @@
+package org.simantics.g3d.csg.actions;\r
+\r
+import org.eclipse.jface.action.Action;\r
+import org.simantics.g3d.csg.scenegraph2.CSGnode;\r
+import org.simantics.g3d.csg.scenegraph2.CSGrootNode;\r
+import org.simantics.utils.ui.ExceptionUtils;\r
+\r
+public class AddPrimitiveAction2 extends Action {\r
+       \r
+       CSGrootNode root;\r
+       Class<? extends CSGnode> primitiveClass;\r
+       public AddPrimitiveAction2(CSGrootNode root, Class<? extends CSGnode> primitiveClass)  {\r
+               super();\r
+               String name = primitiveClass.getSimpleName();\r
+               if (name.endsWith("Node"))\r
+                       name = name.substring(0,name.length()-4);\r
+               setText(name);\r
+               this.primitiveClass = primitiveClass;\r
+               this.root = root;\r
+       }\r
+       \r
+       @Override\r
+       public void run() {\r
+               try {\r
+                       CSGnode node = primitiveClass.newInstance();\r
+                       String name = root.getUniqueName(node.getClass().getSimpleName());\r
+                       node.setName(name);\r
+                       root.addChild(node);\r
+                       root.getNodeMap().commit();\r
+               } catch (Exception e) {\r
+                       ExceptionUtils.logAndShowError("Cannot create primitive.", e);\r
+               }\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/actions/SplitBooleanOpAction2.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/actions/SplitBooleanOpAction2.java
new file mode 100644 (file)
index 0000000..57e7d03
--- /dev/null
@@ -0,0 +1,49 @@
+package org.simantics.g3d.csg.actions;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.HashMap;\r
+import java.util.Map;\r
+\r
+import javax.vecmath.Quat4d;\r
+import javax.vecmath.Vector3d;\r
+\r
+import org.eclipse.jface.action.Action;\r
+import org.simantics.g3d.csg.scenegraph2.CSGparentNode;\r
+import org.simantics.g3d.csg.scenegraph2.CSGrootNode;\r
+import org.simantics.g3d.csg.scenegraph2.ICSGnode;\r
+\r
+public class SplitBooleanOpAction2 extends Action {\r
+       private CSGrootNode root;\r
+       private CSGparentNode booleanOp;\r
+       \r
+       public SplitBooleanOpAction2(CSGrootNode root, CSGparentNode booleanOp)  {\r
+               super();\r
+               setText("Split");\r
+               this.booleanOp = booleanOp;\r
+               this.root = root;\r
+       }\r
+       \r
+       @Override\r
+       public void run() {\r
+               Collection<ICSGnode> nodes = new ArrayList<ICSGnode>();\r
+               nodes.addAll(booleanOp.getPrimaryChild());\r
+               nodes.addAll(booleanOp.getSecondaryChild());\r
+               Map<ICSGnode,Vector3d> positions = new HashMap<ICSGnode, Vector3d>();\r
+               Map<ICSGnode,Quat4d> orientations = new HashMap<ICSGnode, Quat4d>();\r
+               for (ICSGnode node : nodes) {\r
+                       positions.put(node, node.getWorldPosition());\r
+                       orientations.put(node, node.getWorldOrientation());\r
+                       node.deattach();\r
+               }\r
+               for (ICSGnode node : nodes) {\r
+                       root.addChild(node);\r
+                       node.setWorldPosition(positions.get(node));\r
+                       node.setWorldOrientation(orientations.get(node));\r
+               }\r
+               root.remChild(booleanOp);\r
+               root.getNodeMap().commit();\r
+\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/adapters/CSGSolidModelAdapter.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/adapters/CSGSolidModelAdapter.java
new file mode 100644 (file)
index 0000000..30e4991
--- /dev/null
@@ -0,0 +1,83 @@
+package org.simantics.g3d.csg.adapters;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.Collections;\r
+import java.util.List;\r
+\r
+import org.eclipse.core.runtime.IAdaptable;\r
+import org.jcae.opencascade.jni.TopoDS_Shape;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.request.Read;\r
+import org.simantics.g3d.csg.scenegraph2.CSGrootNode;\r
+import org.simantics.g3d.csg.scenegraph2.ICSGnode;\r
+import org.simantics.g3d.csg.scenegraph2.SchemaBuilder;\r
+import org.simantics.objmap.graph.IMapping;\r
+import org.simantics.objmap.graph.Mappings;\r
+import org.simantics.objmap.graph.schema.IMappingSchema;\r
+import org.simantics.objmap.structural.IStructuralObject;\r
+import org.simantics.opencascade.SolidModelProvider;\r
+import org.simantics.ui.SimanticsUI;\r
+\r
+public class CSGSolidModelAdapter implements SolidModelProvider, IAdaptable, IStructuralObject {\r
+       \r
+       private Resource model;\r
+       \r
+       public CSGSolidModelAdapter(Resource model) {\r
+               this.model = model;\r
+       }\r
+       \r
+       @Override\r
+       public Collection<TopoDS_Shape> getModel() throws Exception {\r
+               return SimanticsUI.getSession().syncRequest(new Read<Collection<TopoDS_Shape>>() {\r
+                       @Override\r
+                       public Collection<TopoDS_Shape> perform(ReadGraph graph)\r
+                                       throws DatabaseException {\r
+                               Collection<TopoDS_Shape> shapes = new ArrayList<TopoDS_Shape>();\r
+                               IMappingSchema<Resource,Object> schema = SchemaBuilder.getSchema(graph);\r
+                               IMapping<Resource,Object> mapping = Mappings.createWithoutListening(schema);\r
+                               CSGrootNode rootNode = (CSGrootNode)mapping.map(graph, model);\r
+                               for (ICSGnode node : rootNode.getNodes("child")) {\r
+                                       TopoDS_Shape shape = node.getGeometry();\r
+                                       if (shape != null)\r
+                                               shapes.add(shape);\r
+                               }\r
+                               // FIXME: clear CSG scene-graph\r
+                               return shapes;\r
+                       }\r
+               });\r
+       \r
+       }\r
+       \r
+       @SuppressWarnings("rawtypes")\r
+       @Override\r
+       public Object getAdapter(Class adapter) {\r
+               if (Resource.class.equals(adapter))\r
+                       return model;\r
+               return null;\r
+       }\r
+       \r
+       @SuppressWarnings("unchecked")\r
+       @Override\r
+       public List<IStructuralObject> getContext() {\r
+               return Collections.EMPTY_LIST;\r
+       }\r
+       \r
+       @Override\r
+       public Resource getType() {\r
+               return null;\r
+       }\r
+       \r
+       @Override\r
+       public void setContext(List<IStructuralObject> object) {\r
+               throw new RuntimeException();\r
+       }\r
+       \r
+       @Override\r
+       public void setType(Resource type) {\r
+               throw new RuntimeException();   \r
+       }\r
+\r
+}\r
diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/adapters/NodeRemover.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/adapters/NodeRemover.java
new file mode 100644 (file)
index 0000000..73ce055
--- /dev/null
@@ -0,0 +1,30 @@
+package org.simantics.g3d.csg.adapters;\r
+\r
+import java.util.Map;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.layer0.adapter.Remover;\r
+\r
+public class NodeRemover implements Remover {\r
+       \r
+       //private Resource node;\r
+       \r
+       public NodeRemover(Resource node) {\r
+               //this.node = node;\r
+       }\r
+       \r
+       @Override\r
+       public String canRemove(ReadGraph graph, Map<Object, Object> aux)\r
+                       throws DatabaseException {\r
+               return "Removing scene-graph nodes from model browser is not supported.";\r
+       }\r
+       \r
+       @Override\r
+       public void remove(WriteGraph graph) throws DatabaseException {\r
+               \r
+       }\r
+\r
+}\r
diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/editor/CSGEditor2.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/editor/CSGEditor2.java
new file mode 100644 (file)
index 0000000..c1f7c51
--- /dev/null
@@ -0,0 +1,429 @@
+package org.simantics.g3d.csg.editor;\r
+\r
+import java.awt.Component;\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.HashSet;\r
+import java.util.List;\r
+import java.util.Set;\r
+\r
+import org.eclipse.jface.action.IMenuListener;\r
+import org.eclipse.jface.action.IMenuManager;\r
+import org.eclipse.jface.action.MenuManager;\r
+import org.eclipse.jface.viewers.ISelectionChangedListener;\r
+import org.eclipse.jface.viewers.SelectionChangedEvent;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.events.DisposeEvent;\r
+import org.eclipse.swt.events.DisposeListener;\r
+import org.eclipse.swt.layout.FillLayout;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.swt.widgets.Display;\r
+import org.eclipse.swt.widgets.Menu;\r
+import org.eclipse.ui.views.contentoutline.IContentOutlinePage;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.common.request.ReadRequest;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.g3d.csg.actions.AddBooleanOpAction2;\r
+import org.simantics.g3d.csg.actions.AddPrimitiveAction2;\r
+import org.simantics.g3d.csg.actions.SplitBooleanOpAction2;\r
+import org.simantics.g3d.csg.scenegraph2.BarrelNode;\r
+import org.simantics.g3d.csg.scenegraph2.BoxNode;\r
+import org.simantics.g3d.csg.scenegraph2.CSGparentNode;\r
+import org.simantics.g3d.csg.scenegraph2.CSGrootNode;\r
+import org.simantics.g3d.csg.scenegraph2.ConeNode;\r
+import org.simantics.g3d.csg.scenegraph2.CylinderNode;\r
+import org.simantics.g3d.csg.scenegraph2.DifferenceNode;\r
+import org.simantics.g3d.csg.scenegraph2.EllipticCylinderNode;\r
+import org.simantics.g3d.csg.scenegraph2.ICSGnode;\r
+import org.simantics.g3d.csg.scenegraph2.IntersectionNode;\r
+import org.simantics.g3d.csg.scenegraph2.RectangularSolidNode;\r
+import org.simantics.g3d.csg.scenegraph2.RegularPrismNode;\r
+import org.simantics.g3d.csg.scenegraph2.SchemaBuilder;\r
+import org.simantics.g3d.csg.scenegraph2.SphereNode;\r
+import org.simantics.g3d.csg.scenegraph2.TorusNode;\r
+import org.simantics.g3d.csg.scenegraph2.UnionNode;\r
+import org.simantics.g3d.scenegraph.IG3DNode;\r
+import org.simantics.g3d.scenegraph.NodeMap;\r
+import org.simantics.g3d.scenegraph.base.INode;\r
+import org.simantics.g3d.vtk.action.RemoveAction;\r
+import org.simantics.g3d.vtk.action.RotateAction;\r
+import org.simantics.g3d.vtk.action.TranslateAction;\r
+import org.simantics.g3d.vtk.action.vtkCameraAndSelectorAction;\r
+import org.simantics.g3d.vtk.common.HoverHighlighter;\r
+import org.simantics.g3d.vtk.common.InteractiveVtkPanel;\r
+import org.simantics.g3d.vtk.common.NodeSelectionProvider2;\r
+import org.simantics.g3d.vtk.common.SelectionHighlighter;\r
+import org.simantics.g3d.vtk.common.VTKContentOutlinePage;\r
+import org.simantics.g3d.vtk.shape.vtkShape;\r
+import org.simantics.g3d.vtk.utils.vtkPanelUtil;\r
+import org.simantics.objmap.graph.IMapping;\r
+import org.simantics.objmap.graph.Mappings;\r
+import org.simantics.objmap.graph.schema.IMappingSchema;\r
+import org.simantics.selectionview.StandardPropertyPage;\r
+import org.simantics.ui.workbench.IPropertyPage;\r
+import org.simantics.ui.workbench.IResourceEditorInput;\r
+import org.simantics.ui.workbench.ResourceEditorPart;\r
+import org.simantics.utils.threads.AWTThread;\r
+import org.simantics.utils.threads.ThreadUtils;\r
+import org.simantics.utils.ui.ExceptionUtils;\r
+import org.simantics.utils.ui.SWTAWTComponent;\r
+\r
+import vtk.vtkActor;\r
+import vtk.vtkCameraPass;\r
+import vtk.vtkDefaultPass;\r
+import vtk.vtkLightsPass;\r
+import vtk.vtkRenderPassCollection;\r
+import vtk.vtkRenderer;\r
+import vtk.vtkSequencePass;\r
+\r
+public class CSGEditor2  extends ResourceEditorPart {\r
+       private Composite parent;\r
+       private Resource input;\r
+       private InteractiveVtkPanel panel;\r
+       private SWTAWTComponent component;\r
+       \r
+       private CSGrootNode rootNode;\r
+       private IMapping<Resource,Object> mapping;\r
+       \r
+       private NodeSelectionProvider2<Resource,Object> selectionProvider;\r
+       \r
+       private vtkCameraAndSelectorAction cameraAction;\r
+       private TranslateAction translateAction;\r
+       private RotateAction rotateAction;\r
+       private RemoveAction removeAction;\r
+       \r
+       //private  ScenegraphOutlinePage outlinePage;\r
+       \r
+       private CSGNodeMap nodeMap;\r
+\r
+\r
+\r
+       @Override\r
+       public void createPartControl(Composite parent) {\r
+               this.parent = parent;\r
+               parent.setLayout (new FillLayout ());\r
+               component = new SWTAWTComponent(parent,SWT.NONE) {\r
+                       \r
+                       @Override\r
+                       protected Component createSwingComponent() {\r
+                               if (panel == null) {\r
+                                       panel = new InteractiveVtkPanel();\r
+                                       vtkPanelUtil.registerPanel(panel);\r
+                                       createScene();\r
+                               }\r
+                               return panel;\r
+                       }\r
+               };\r
+\r
+               IResourceEditorInput rei = (IResourceEditorInput)getEditorInput();\r
+               input = rei.getResource();\r
+               \r
+               \r
+               //IActionBars actionBars = getEditorSite().getActionBars();\r
+\r
+               hookContextMenu();\r
+               \r
+               component.syncPopulate();\r
+               \r
+               panel.addMouseListener(new java.awt.event.MouseAdapter() {\r
+                       @Override\r
+                       public void mouseClicked(final java.awt.event.MouseEvent e) {\r
+                               if (e.getButton() == java.awt.event.MouseEvent.BUTTON3) {\r
+                                       Display.getDefault().asyncExec(new Runnable() {\r
+                                               public void run() {\r
+                                                       contextMenu.setLocation(e.getXOnScreen(), e.getYOnScreen());\r
+                                                       contextMenu.setVisible(true);\r
+                                               }\r
+                                       });\r
+                               }\r
+                       }\r
+               });\r
+               \r
+\r
+               cameraAction = new vtkCameraAndSelectorAction(panel);   \r
+               panel.setDefaultAction(cameraAction);\r
+               panel.useDefaultAction();\r
+               \r
+               try {\r
+                       getSession().syncRequest(new ReadRequest() {\r
+                               \r
+                               @SuppressWarnings({ "rawtypes", "unchecked" })\r
+                               @Override\r
+                               public void run(ReadGraph graph) throws DatabaseException {\r
+                                       IMappingSchema schema = SchemaBuilder.getSchema(graph);\r
+                                       mapping = Mappings.createWithListening(schema);\r
+                                       rootNode = (CSGrootNode)mapping.map(graph, input);\r
+                                       nodeMap = new CSGNodeMap(getSession(), mapping, panel,(CSGrootNode)rootNode);\r
+                               }\r
+                       });\r
+                       \r
+                       if (rootNode == null)\r
+                               throw new RuntimeException("Scenegraph loading failed.");\r
+                       populate();\r
+                       \r
+                       selectionProvider = new NodeSelectionProvider2<Resource,Object>(this,mapping,nodeMap);\r
+\r
+                       cameraAction.addSelectionChangedListener(selectionProvider);\r
+\r
+                       cameraAction.addHoverChangedListener(new HoverHighlighter(panel,nodeMap));\r
+                       selectionProvider.addSelectionChangedListener(new SelectionHighlighter(panel,nodeMap));\r
+                       \r
+                       getSite().setSelectionProvider(selectionProvider);\r
+                       getSite().getPage().addPostSelectionListener(selectionProvider);\r
+                       \r
+                       //outlinePage = new ScenegraphOutlinePage(rootNode);\r
+                       \r
+                       \r
+                       parent.addDisposeListener(new DisposeListener() {\r
+                               \r
+                               @Override\r
+                               public void widgetDisposed(DisposeEvent e) {\r
+                                       getSite().getPage().removePostSelectionListener(selectionProvider);\r
+                                       ThreadUtils.asyncExec(AWTThread.getThreadAccess(), new Runnable() {\r
+                                               \r
+                                               @Override\r
+                                               public void run() {\r
+                                                       nodeMap.delete();\r
+                                                       vtkPanelUtil.unregisterPanel(panel);\r
+\r
+                                               }\r
+                                       });\r
+                                       mapping.dispose();\r
+                                       component.dispose();\r
+                                       \r
+                                       \r
+                               }\r
+                       });\r
+               } catch (DatabaseException e1) {\r
+                       ExceptionUtils.logAndShowError("Cannot open CSG editor",e1);\r
+                       return;\r
+               }\r
+               \r
+               translateAction = new TranslateAction(panel,nodeMap);\r
+               rotateAction = new RotateAction(panel,nodeMap);\r
+               removeAction = new RemoveAction(nodeMap) {\r
+                       public void setNode(IG3DNode node) {\r
+                               super.setNode(node);\r
+                               if (node.getParent() instanceof CSGparentNode)\r
+                                       setEnabled(false);\r
+                               \r
+                       }\r
+               };\r
+               \r
+               \r
+       }\r
+       \r
+       \r
+\r
+       \r
+       public void populate() {\r
+               ThreadUtils.asyncExec(AWTThread.getThreadAccess(), new Runnable() {\r
+                       \r
+                       @Override\r
+                       public void run() {\r
+                               nodeMap.populate();\r
+                       }\r
+               });\r
+               \r
+       }\r
+       \r
+       \r
+       \r
+       @Override\r
+       public void setFocus() {\r
+               component.setFocus();\r
+       }\r
+       \r
+       private void createScene() {\r
+               vtkRenderer ren1 = panel.GetRenderer();\r
+               \r
+               boolean multiPass = false;\r
+               if (multiPass) {\r
+                       \r
+                       vtkLightsPass lightsPass = new vtkLightsPass();\r
+                       vtkDefaultPass defaultPass = new vtkDefaultPass();\r
+                       \r
+                       \r
+                       vtkRenderPassCollection passes = new vtkRenderPassCollection();\r
+                       passes.AddItem(lightsPass);\r
+                       passes.AddItem(defaultPass);\r
+                       \r
+                       vtkSequencePass seq = new vtkSequencePass();\r
+                       seq.SetPasses(passes);\r
+                       \r
+               \r
+                       \r
+                       vtkCameraPass cameraPass = new vtkCameraPass();\r
+                       cameraPass.SetDelegatePass(seq);\r
+                       \r
+                       ren1.SetPass(cameraPass);\r
+                       \r
+               }\r
+//             ren1.GetRenderWindow().LineSmoothingOn();\r
+//             ren1.GetRenderWindow().PointSmoothingOn();\r
+//             ren1.GetRenderWindow().PolygonSmoothingOn();\r
+//             ren1.GetRenderWindow().SetMultiSamples(2);\r
+\r
+               \r
+\r
+               ren1.SetBackground2(1,1,1); // background color white\r
+               ren1.SetBackground(0.9,0.9,0.9);\r
+               ren1.SetGradientBackground(true);\r
+\r
+          // vtkActor grid = vtkShape.createGridActor(8,1.0,1|2|4);\r
+           vtkActor grid = vtkShape.createGridActor(8,1.0, 2 );\r
+           grid.SetPickable(0);\r
+           ren1.AddActor(grid);\r
+           panel.addDeletable(grid);\r
+           \r
+\r
+               \r
+       }\r
+       \r
+       protected Menu contextMenu;\r
+       \r
+       protected void hookContextMenu() {\r
+        MenuManager menuMgr = new MenuManager("#PopupMenu");\r
+        menuMgr.setRemoveAllWhenShown(true);\r
+        menuMgr.addMenuListener(new IMenuListener() {\r
+            public void menuAboutToShow(IMenuManager manager) {\r
+               final IMenuManager m = manager;\r
+                       List<IG3DNode> selected = selectionProvider.getSelectedNodes();\r
+                       if (selected.size() == 0) {\r
+                               m.add(new AddPrimitiveAction2(rootNode, BarrelNode.class));\r
+                               m.add(new AddPrimitiveAction2(rootNode, BoxNode.class));\r
+                               m.add(new AddPrimitiveAction2(rootNode, ConeNode.class));\r
+                               m.add(new AddPrimitiveAction2(rootNode, CylinderNode.class));\r
+                               m.add(new AddPrimitiveAction2(rootNode, EllipticCylinderNode.class));\r
+                               m.add(new AddPrimitiveAction2(rootNode, RectangularSolidNode.class));\r
+                               m.add(new AddPrimitiveAction2(rootNode, RegularPrismNode.class));\r
+                               m.add(new AddPrimitiveAction2(rootNode, SphereNode.class));\r
+                               m.add(new AddPrimitiveAction2(rootNode, TorusNode.class));\r
+                       } else if (selected.size() == 1) {\r
+                               m.add(translateAction);\r
+                                       m.add(rotateAction);\r
+                                       m.add(removeAction);\r
+                                       ICSGnode node = (ICSGnode)selected.get(0);\r
+                                       translateAction.setNode(node);\r
+                                       rotateAction.setNode(node);\r
+                                       removeAction.setNode(node);\r
+                                       if (node instanceof CSGparentNode) {\r
+                                               m.add(new SplitBooleanOpAction2(rootNode,(CSGparentNode)node));\r
+                                       }\r
+                       } else if (selected.size() == 2) {\r
+                               if (selected.get(0).getParent().equals(rootNode) && selected.get(1).getParent().equals(rootNode)) {\r
+                                       Collection<ICSGnode> nodes = new ArrayList<ICSGnode>();\r
+                                       for (IG3DNode n : selected)\r
+                                               nodes.add((ICSGnode)n);\r
+                                       m.add(new AddBooleanOpAction2(rootNode, DifferenceNode.class, nodes));\r
+                                       m.add(new AddBooleanOpAction2(rootNode, IntersectionNode.class, nodes));\r
+                                       m.add(new AddBooleanOpAction2(rootNode, UnionNode.class, nodes));\r
+                               }\r
+                       }\r
+//             try {\r
+//                                     SimanticsUI.getSession().syncRequest(new ReadRequest() {\r
+//                                             \r
+//                                             @Override\r
+//                                             public void run(ReadGraph graph) throws DatabaseException {\r
+//                                                     Layer0 l0 = Layer0.getInstance(graph);\r
+//                                                     CSG csg = CSG.getInstance(graph);\r
+//                                                     Resource ontology = graph.getResource("http://www.simantics.org/CSG-0.1");\r
+//                                                     \r
+//                                                     if (selectionProvider.getSelectedResources().size() == 0) {\r
+//                                                             List<NamedResource> primitives = new ArrayList<NamedResource>();\r
+//                                                             for (Resource r : graph.getObjects(ontology, l0.ConsistsOf)) {\r
+//                                                                     if (graph.isInheritedFrom(r, csg.Primitive) && !r.equals(csg.Primitive)) {\r
+//                                                                             primitives.add(new NamedResource((String)graph.getRelatedValue(r, l0.HasName), r));\r
+//                                                                     }\r
+//                                                             }\r
+//                                                             \r
+//                                                             Collections.sort(primitives);\r
+//                                                             for (NamedResource n : primitives) {\r
+//                                                                     m.add(new AddPrimitiveAction(graph, n.getResource(),input));\r
+//                                                             }\r
+//                                                     }\r
+//                                                     if (selectionProvider.getSelectedResources().size() == 2) {\r
+//                                                             List<NamedResource> booleanOps = new ArrayList<NamedResource>();\r
+//                                                             for (Resource r : graph.getObjects(ontology, l0.ConsistsOf)) {\r
+//                                                                     if (graph.isInheritedFrom(r, csg.BooleanOperation) && !r.equals(csg.BooleanOperation)) {\r
+//                                                                             booleanOps.add(new NamedResource((String)graph.getRelatedValue(r, l0.HasName), r));\r
+//                                                                     }\r
+//                                                             }\r
+//                                                             \r
+//                                                             Collections.sort(booleanOps);\r
+//                                                             for (NamedResource n : booleanOps) {\r
+//                                                                     m.add(new AddBooleanOpAction(graph, n.getResource(), input, selectionProvider.getSelectedResources()));\r
+//                                                             }\r
+//                                                     }\r
+//                                                     if (selectionProvider.getSelectedResources().size() == 1) {\r
+//                                                             m.add(translateAction);\r
+//                                                             m.add(rotateAction);\r
+//                                                             m.add(removeAction);\r
+//                                                             Resource selected = selectionProvider.getSelectedResources().get(0);\r
+//                                                             translateAction.setNode((IG3DNode2)mapping.get(selected));\r
+//                                                             rotateAction.setNode((IG3DNode2)mapping.get(selected));\r
+//                                                             removeAction.setNode((IG3DNode2)mapping.get(selected));\r
+//                                                             if (graph.isInstanceOf(selected, csg.BooleanOperation)) {\r
+//                                                                     m.add(new SplitBooleanOpAction(input,selected));\r
+//                                                             }\r
+//                                                             \r
+//                                                             \r
+//                                                     }\r
+//                                                     \r
+//                                             }\r
+//                                     });\r
+//                             } catch (DatabaseException e) {\r
+//                                     // TODO Auto-generated catch block\r
+//                                     e.printStackTrace();\r
+//                             }\r
+                \r
+            }\r
+        });\r
+\r
+        contextMenu = menuMgr.createContextMenu(parent);\r
+    }\r
+       \r
+       private IContentOutlinePage createOutline() {\r
+               if (rootNode == null || selectionProvider == null)\r
+                       return null;\r
+               IContentOutlinePage outlinePage = new VTKContentOutlinePage<Resource,Object>(rootNode, selectionProvider);\r
+               outlinePage.addSelectionChangedListener(new ISelectionChangedListener() {\r
+                       \r
+                       @Override\r
+                       public void selectionChanged(SelectionChangedEvent event) {\r
+                               selectionProvider.selectionChanged(event);\r
+                       }\r
+               });\r
+               return outlinePage;\r
+       }\r
+\r
+       @SuppressWarnings("rawtypes")\r
+       @Override\r
+       public Object getAdapter(Class adapter) {\r
+               if (IPropertyPage.class.equals(adapter))\r
+                       return new StandardPropertyPage(getSite(),getPropertyContexts());\r
+               if (IContentOutlinePage.class.equals(adapter)) {\r
+                       return createOutline();\r
+               }\r
+               if (NodeMap.class.equals(adapter)) {\r
+                       return nodeMap;\r
+               }\r
+               if (INode.class.equals(adapter)) {\r
+                       return rootNode;\r
+               }\r
+               if (IMapping.class.equals(adapter)) {\r
+                       return mapping;\r
+               }\r
+               if (InteractiveVtkPanel.class.equals(adapter)) {\r
+                       return panel;\r
+               }\r
+               return super.getAdapter(adapter);\r
+       }\r
+       \r
+       public Set<String> getPropertyContexts() {\r
+               Set<String> result = new HashSet<String>();\r
+               result.add("http://www.simantics.org/Project-1.0/ProjectBrowseContext");\r
+               return result;\r
+       }\r
+}\r
diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/editor/CSGNodeMap.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/editor/CSGNodeMap.java
new file mode 100644 (file)
index 0000000..1776694
--- /dev/null
@@ -0,0 +1,119 @@
+package org.simantics.g3d.csg.editor;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.List;\r
+import java.util.Set;\r
+\r
+import org.simantics.db.Session;\r
+import org.simantics.g3d.csg.scenegraph2.CSGrootNode;\r
+import org.simantics.g3d.csg.scenegraph2.ICSGnode;\r
+import org.simantics.g3d.scenegraph.base.ParentNode;\r
+import org.simantics.g3d.vtk.common.AbstractVTKNodeMap;\r
+import org.simantics.g3d.vtk.common.InteractiveVtkPanel;\r
+import org.simantics.objmap.graph.IMapping;\r
+import org.simantics.utils.threads.AWTThread;\r
+\r
+import vtk.vtkProp;\r
+import vtk.vtkProp3D;\r
+import vtk.vtkRenderer;\r
+\r
+public class CSGNodeMap extends AbstractVTKNodeMap<ICSGnode> {\r
+       \r
+\r
+       \r
+       public CSGNodeMap(Session session, IMapping mapping, InteractiveVtkPanel panel, CSGrootNode rootNode) {\r
+               super(session, mapping, panel, rootNode);\r
+               rootNode.setNodeMap(this);\r
+       }\r
+       \r
+\r
+       @SuppressWarnings("unchecked")\r
+       protected void updateActor(ICSGnode node, Set<String> ids) {\r
+               //System.out.println("CSGNodeMap.updateActor " + node);\r
+               if (node.getParent() instanceof ICSGnode) {\r
+                       ICSGnode parent = (ICSGnode) node.getParent();\r
+                       if (!"child".equals(node.getParentRel())) {\r
+                               updateActor(parent,null);\r
+                               return;\r
+                       }\r
+               }\r
+               \r
+               if (node instanceof ParentNode<?>) {\r
+                       ParentNode<ICSGnode> p = (ParentNode<ICSGnode>)node;\r
+                       for (ICSGnode n : p.getNodes())\r
+                               remActor(n);\r
+               }\r
+               \r
+               remActor(node);\r
+               addActor(node);\r
+\r
+       }\r
+\r
+       @Override\r
+       protected Collection<vtkProp> getActors(ICSGnode node) {\r
+               List<vtkProp> props = new ArrayList<vtkProp>();\r
+               for (vtkProp3D p : ((ICSGnode)node).getActors())\r
+                       props.add(p);\r
+               return props;\r
+       }\r
+       \r
+       protected void removeActor(ICSGnode node) {\r
+               //System.out.println("CSGNodeMap.removeActor " + node);\r
+               remActor(node);\r
+               \r
+               if (!"child".equals(node.getParentRel())) {\r
+                       if (node.getParent() instanceof ICSGnode)\r
+                               updateActor((ICSGnode)node.getParent(),null);\r
+               }\r
+       }\r
+       \r
+       protected void addActor(ICSGnode node) {\r
+               //System.out.println("CSGNodeMap.addActor " + node);\r
+               if (hasActor(node))\r
+                       return;\r
+               if (Thread.currentThread() != AWTThread.getThreadAccess().getThread())\r
+                       throw new RuntimeException("Illegal thread.");\r
+               \r
+               panel.lock();\r
+               \r
+               node.visualize(panel);\r
+\r
+               for (vtkProp3D act : node.getActors()) {\r
+                       nodeToActor.add(node, act);\r
+            actorToNode.put(act, node);\r
+               }\r
+\r
+        panel.unlock();\r
+\r
+       }\r
+       \r
+       \r
+       \r
+       private boolean hasActor(ICSGnode node) {\r
+               List<vtkProp> list = nodeToActor.getValues(node);\r
+               if (list == null || list.size() == 0)\r
+                       return false;\r
+               return true;\r
+       }\r
+       \r
+       private void remActor(ICSGnode node) {\r
+               if (Thread.currentThread() != AWTThread.getThreadAccess().getThread())\r
+                       throw new RuntimeException("Illegal thread.");\r
+\r
+               List<vtkProp> list = nodeToActor.getValues(node);\r
+               if (list != null) {\r
+                       for (vtkProp obj : list) {\r
+                               actorToNode.remove(obj);        \r
+                       }\r
+                       nodeToActor.remove(node);\r
+                       panel.lock();\r
+                       \r
+                       node.stopVisualize();\r
+                       \r
+                       panel.unlock();\r
+               }\r
+       }\r
+       \r
+\r
+}\r
diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/BarrelNode.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/BarrelNode.java
new file mode 100644 (file)
index 0000000..a6c3334
--- /dev/null
@@ -0,0 +1,116 @@
+package org.simantics.g3d.csg.scenegraph2;\r
+\r
+import org.jcae.opencascade.jni.BRepBuilderAPI_MakeEdge;\r
+import org.jcae.opencascade.jni.BRepBuilderAPI_MakeFace;\r
+import org.jcae.opencascade.jni.BRepBuilderAPI_MakeWire;\r
+import org.jcae.opencascade.jni.BRepPrimAPI_MakeRevol;\r
+import org.jcae.opencascade.jni.GC_MakeArcOfCircle;\r
+import org.jcae.opencascade.jni.GC_MakeSegment;\r
+import org.jcae.opencascade.jni.TopoDS_Edge;\r
+import org.jcae.opencascade.jni.TopoDS_Face;\r
+import org.jcae.opencascade.jni.TopoDS_Shape;\r
+import org.jcae.opencascade.jni.TopoDS_Wire;\r
+import org.simantics.g3d.csg.ontology.CSG;\r
+import org.simantics.g3d.property.annotations.GetPropertyValue;\r
+import org.simantics.g3d.property.annotations.SetPropertyValue;\r
+import org.simantics.objmap.graph.annotations.GraphType;\r
+import org.simantics.objmap.graph.annotations.RelatedGetValue;\r
+import org.simantics.objmap.graph.annotations.RelatedSetValue;\r
+\r
+@GraphType(CSG.URIs.Barrel)\r
+public class BarrelNode extends CSGnode {\r
+\r
+       private double r1 = 1.0;\r
+       private double r2 = 1.1;\r
+       private double h = 1.0;\r
+       \r
+       \r
+\r
+       @RelatedSetValue(CSG.URIs.HasMinorRadius)\r
+       @SetPropertyValue(CSG.URIs.HasMinorRadius)\r
+       public void setR1(double r1) {\r
+               this.r1 = r1;\r
+               firePropertyChanged(CSG.URIs.HasMinorRadius);\r
+       }\r
+       \r
+       @RelatedSetValue(CSG.URIs.HasMajorRadius)\r
+       @SetPropertyValue(CSG.URIs.HasMajorRadius)\r
+       public void setR2(double r2) {\r
+               this.r2 = r2;\r
+               firePropertyChanged(CSG.URIs.HasMajorRadius);\r
+       }\r
+       \r
+       @RelatedSetValue(CSG.URIs.HasHeight)\r
+       @SetPropertyValue(CSG.URIs.HasHeight)\r
+       public void setH(double h) {\r
+               this.h = h;\r
+               firePropertyChanged(CSG.URIs.HasHeight);\r
+       }\r
+       \r
+       @RelatedGetValue(CSG.URIs.HasHeight)\r
+       @GetPropertyValue(value=CSG.URIs.HasHeight, name = "Height")\r
+       public double getH() {\r
+               return h;\r
+       }\r
+       \r
+       @RelatedGetValue(CSG.URIs.HasMinorRadius)\r
+       @GetPropertyValue(value=CSG.URIs.HasMinorRadius, name = "Minor Radius")\r
+       public double getR1() {\r
+               return r1;\r
+       }\r
+       \r
+       @RelatedGetValue(CSG.URIs.HasMajorRadius)\r
+       @GetPropertyValue(value=CSG.URIs.HasMajorRadius, name = "Major Radius")\r
+       public double getR2() {\r
+               return r2;\r
+       }\r
+       \r
+       @Override\r
+       public TopoDS_Shape getBaseGeometry() {\r
+               if (Math.abs(r1 -r2)< MIN_VALUE)\r
+               r2 = r1 + MIN_VALUE;\r
+               double p0[] = new double[]{0.0,-h*0.5,0.0};\r
+               double p1[] = new double[]{0.0,-h*0.5,r1};\r
+               double p2[] = new double[]{0.0, 0.0  ,r2};\r
+               double p3[] = new double[]{0.0, h*0.5,r1};\r
+               double p4[] = new double[]{0.0, h*0.5,0.0};\r
+               GC_MakeArcOfCircle m = new GC_MakeArcOfCircle(p1,p2,p3);\r
+               GC_MakeSegment s1 = new GC_MakeSegment(p0,p1);\r
+               GC_MakeSegment s2 = new GC_MakeSegment(p3,p4);\r
+               \r
+               BRepBuilderAPI_MakeEdge edge = new BRepBuilderAPI_MakeEdge(s1.value());\r
+               TopoDS_Edge e1 = (TopoDS_Edge)edge.shape();\r
+               edge.delete();\r
+               \r
+               edge = new BRepBuilderAPI_MakeEdge(m.value());\r
+               TopoDS_Edge e2 = (TopoDS_Edge)edge.shape();\r
+               edge.delete();\r
+               \r
+               edge = new BRepBuilderAPI_MakeEdge(s2.value());\r
+               TopoDS_Edge e3 = (TopoDS_Edge)edge.shape();\r
+               edge.delete();\r
+               \r
+               BRepBuilderAPI_MakeWire wire =  new BRepBuilderAPI_MakeWire(e1,e2,e3);\r
+               TopoDS_Wire w = (TopoDS_Wire)wire.shape();\r
+               wire.delete();\r
+               \r
+               BRepBuilderAPI_MakeFace face = new BRepBuilderAPI_MakeFace(w);\r
+               TopoDS_Face F = (TopoDS_Face) face.shape();\r
+               face.delete();\r
+               \r
+               BRepPrimAPI_MakeRevol revol = new BRepPrimAPI_MakeRevol(F,new double[]{0.0,0.0,0.0,0.0,1.0,0.0}); \r
+               TopoDS_Shape shape = revol.shape();\r
+               revol.delete();\r
+               \r
+               m.delete();\r
+               s1.delete();\r
+               s2.delete();\r
+               e1.delete();\r
+               e2.delete();\r
+               e3.delete();\r
+               w.delete();\r
+               F.delete();\r
+               return shape;\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/BoxNode.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/BoxNode.java
new file mode 100644 (file)
index 0000000..b158137
--- /dev/null
@@ -0,0 +1,69 @@
+package org.simantics.g3d.csg.scenegraph2;\r
+\r
+import org.jcae.opencascade.jni.TopoDS_Shape;\r
+import org.simantics.g3d.csg.ontology.CSG;\r
+import org.simantics.g3d.property.annotations.GetPropertyValue;\r
+import org.simantics.g3d.property.annotations.SetPropertyValue;\r
+import org.simantics.objmap.graph.annotations.GraphType;\r
+import org.simantics.objmap.graph.annotations.RelatedGetValue;\r
+import org.simantics.objmap.graph.annotations.RelatedSetValue;\r
+import org.simantics.opencascade.OccTriangulator;\r
+\r
+@GraphType(CSG.URIs.Box)\r
+public class BoxNode extends CSGnode {\r
+\r
+       private double sx = 1.0;\r
+       private double sy = 1.0;\r
+       private double sz = 1.0;\r
+       \r
+       public BoxNode() {\r
+               System.out.println();\r
+       }\r
+       \r
+       @RelatedSetValue(CSG.URIs.HasXAxisSize)\r
+       @SetPropertyValue(CSG.URIs.HasXAxisSize)\r
+       public void setSX(double d) {\r
+               this.sx = d;\r
+               firePropertyChanged(CSG.URIs.HasXAxisSize);\r
+       }\r
+       \r
+       @RelatedSetValue(CSG.URIs.HasYAxisSize)\r
+       @SetPropertyValue(CSG.URIs.HasYAxisSize)\r
+       public void setSY(double d) {\r
+               this.sy = d;\r
+               firePropertyChanged(CSG.URIs.HasYAxisSize);\r
+       }\r
+       \r
+       @RelatedSetValue(CSG.URIs.HasZAxisSize)\r
+       @SetPropertyValue(CSG.URIs.HasZAxisSize)\r
+       public void setSZ(double d) {\r
+               this.sz = d;\r
+               firePropertyChanged(CSG.URIs.HasZAxisSize);\r
+       }\r
+       \r
+       @RelatedGetValue(CSG.URIs.HasXAxisSize)\r
+       @GetPropertyValue(value=CSG.URIs.HasXAxisSize, name = "X Size")\r
+       public double getSx() {\r
+               return sx;\r
+       }\r
+       \r
+       @RelatedGetValue(CSG.URIs.HasYAxisSize)\r
+       @GetPropertyValue(value=CSG.URIs.HasYAxisSize, name = "Y Size")\r
+       public double getSy() {\r
+               return sy;\r
+       }\r
+       \r
+       @RelatedGetValue(CSG.URIs.HasZAxisSize)\r
+       @GetPropertyValue(value=CSG.URIs.HasZAxisSize, name = "Z Size")\r
+       public double getSz() {\r
+               return sz;\r
+       }\r
+       \r
+       \r
+       @Override\r
+       public TopoDS_Shape getBaseGeometry() {\r
+               return OccTriangulator.makeBox(-sx * 0.5, -sy * 0.5, -sz * 0.5, sx * 0.5, sy * 0.5, sz * 0.5);\r
+       }\r
+\r
+\r
+}\r
diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/CSGnode.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/CSGnode.java
new file mode 100644 (file)
index 0000000..f783d4e
--- /dev/null
@@ -0,0 +1,109 @@
+package org.simantics.g3d.csg.scenegraph2;\r
+\r
+import java.util.Collection;\r
+import java.util.Collections;\r
+\r
+import javax.vecmath.AxisAngle4d;\r
+import javax.vecmath.Quat4d;\r
+import javax.vecmath.Vector3d;\r
+\r
+import org.jcae.opencascade.jni.TopoDS_Shape;\r
+import org.simantics.g3d.property.annotations.GetPropertyValue;\r
+import org.simantics.g3d.property.annotations.SetPropertyValue;\r
+import org.simantics.g3d.scenegraph.G3DNode;\r
+import org.simantics.layer0.Layer0;\r
+import org.simantics.objmap.graph.annotations.RelatedGetValue;\r
+import org.simantics.objmap.graph.annotations.RelatedSetValue;\r
+import org.simantics.opencascade.OccTriangulator;\r
+import org.simantics.opencascade.vtk.vtkSolidObject;\r
+import org.simantics.utils.threads.AWTThread;\r
+\r
+import vtk.vtkPanel;\r
+import vtk.vtkProp3D;\r
+import vtk.vtkRenderer;\r
+\r
+public abstract class CSGnode extends G3DNode implements ICSGnode {\r
+\r
+       public static final double MIN_VALUE = 0.001;\r
+       \r
+       private String name;\r
+       \r
+\r
+       @RelatedGetValue(Layer0.URIs.HasName)\r
+       @GetPropertyValue(value = Layer0.URIs.HasName, tabId = "Default", name = "Name")\r
+       public String getName() {\r
+               return name;\r
+       }\r
+       \r
+       @RelatedSetValue(Layer0.URIs.HasName)\r
+       @SetPropertyValue(Layer0.URIs.HasName)\r
+       public void setName(String name) {\r
+               if (name == null)\r
+                       return;\r
+               this.name = name;\r
+               firePropertyChanged(Layer0.URIs.HasName);\r
+       }\r
+       \r
+       @Override\r
+       public String toString() {\r
+               return getName();\r
+       }\r
+       \r
+       \r
+       private vtkSolidObject solidObject;\r
+       \r
+       @Override\r
+       public TopoDS_Shape getGeometry() {\r
+               TopoDS_Shape shape = getBaseGeometry();\r
+               if (shape == null)\r
+                       return null;\r
+               Quat4d q = getOrientation();\r
+               AxisAngle4d r = new AxisAngle4d();\r
+               r.set(q);\r
+               TopoDS_Shape tshape = OccTriangulator.makeRotation(shape, new double[] { 0.0, 0.0, 0.0, r.x, r.y, r.z }, r.angle);\r
+               shape.delete();\r
+               shape = tshape;\r
+               Vector3d p = getPosition();\r
+               tshape = OccTriangulator.makeTranslation(shape, p.x, p.y, p.z);\r
+               shape.delete();\r
+               return tshape;  \r
+       }\r
+       \r
+       public void visualize(vtkPanel panel) {\r
+               if (solidObject != null) {\r
+                       solidObject.delete();\r
+                       solidObject = null;\r
+               }\r
+               TopoDS_Shape shape = getGeometry();\r
+               if (shape == null)\r
+                       return;\r
+               solidObject = new vtkSolidObject(panel, shape);\r
+               solidObject.visualizeSolid(true, false);\r
+       }\r
+       \r
+       @SuppressWarnings("unchecked")\r
+       public Collection<vtkProp3D> getActors() {\r
+               if (solidObject == null)\r
+                       return Collections.EMPTY_LIST;\r
+               return solidObject.getActors();\r
+       }\r
+       \r
+       public void stopVisualize() {\r
+               if (solidObject != null) {\r
+                       if (Thread.currentThread() == AWTThread.getThreadAccess().getThread())\r
+                               solidObject.delete();\r
+                       else\r
+                               solidObject.dispose();\r
+                       solidObject = null;\r
+               }\r
+       }\r
+       \r
+       @Override\r
+       public void cleanup() {\r
+               stopVisualize();\r
+               super.cleanup();\r
+       }\r
+       \r
+       \r
+\r
+}\r
diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/CSGparentNode.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/CSGparentNode.java
new file mode 100644 (file)
index 0000000..dcc564a
--- /dev/null
@@ -0,0 +1,308 @@
+package org.simantics.g3d.csg.scenegraph2;\r
+\r
+import java.util.Collection;\r
+import java.util.Collections;\r
+\r
+import javax.vecmath.AxisAngle4d;\r
+import javax.vecmath.Quat4d;\r
+import javax.vecmath.Vector3d;\r
+\r
+import org.jcae.opencascade.jni.TopoDS_Shape;\r
+import org.simantics.g3d.csg.ontology.CSG;\r
+import org.simantics.g3d.math.MathTools;\r
+import org.simantics.g3d.ontology.G3D;\r
+import org.simantics.g3d.property.annotations.GetPropertyValue;\r
+import org.simantics.g3d.property.annotations.PropertyContributor;\r
+import org.simantics.g3d.property.annotations.SetPropertyValue;\r
+import org.simantics.g3d.scenegraph.IG3DNode;\r
+import org.simantics.g3d.scenegraph.base.ParentNode;\r
+import org.simantics.g3d.tools.NodeTools;\r
+import org.simantics.layer0.Layer0;\r
+import org.simantics.objmap.graph.annotations.RelatedElementsAdd;\r
+import org.simantics.objmap.graph.annotations.RelatedElementsGet;\r
+import org.simantics.objmap.graph.annotations.RelatedElementsRem;\r
+import org.simantics.objmap.graph.annotations.RelatedGetValue;\r
+import org.simantics.objmap.graph.annotations.RelatedSetValue;\r
+import org.simantics.opencascade.OccTriangulator;\r
+import org.simantics.opencascade.vtk.vtkSolidObject;\r
+import org.simantics.utils.threads.AWTThread;\r
+\r
+import vtk.vtkPanel;\r
+import vtk.vtkProp3D;\r
+\r
+@PropertyContributor\r
+public abstract class CSGparentNode extends ParentNode<ICSGnode> implements ICSGnode {\r
+\r
+       private String name;\r
+       \r
+\r
+       @RelatedGetValue(Layer0.URIs.HasName)\r
+       @GetPropertyValue(value = Layer0.URIs.HasName, tabId = "Default", name = "Name")\r
+       public String getName() {\r
+               return name;\r
+       }\r
+       \r
+       @RelatedSetValue(Layer0.URIs.HasName)\r
+       @SetPropertyValue(Layer0.URIs.HasName)\r
+       public void setName(String name) {\r
+               if (name == null)\r
+                       return;\r
+               this.name = name;\r
+               firePropertyChanged(Layer0.URIs.HasName);\r
+       }\r
+       \r
+       @Override\r
+       public String toString() {\r
+               return getName();\r
+       }\r
+       \r
+       private Vector3d position = new Vector3d();\r
+       private Quat4d orientation = MathTools.getIdentityQuat();\r
+       \r
+       @Override\r
+       @GetPropertyValue(value = G3D.URIs.hasOrientation, tabId = "Transform", name = "Orientation")\r
+       public Quat4d getOrientation() {\r
+               return orientation;\r
+       }\r
+       \r
+       @RelatedGetValue(G3D.URIs.hasOrientation)\r
+       public double[] getOrientationArr() {\r
+               double arr[] = new double[4];\r
+               orientation.get(arr);\r
+               return arr;\r
+               \r
+       }\r
+       \r
+       @Override\r
+       @GetPropertyValue(value = G3D.URIs.hasPosition, tabId = "Transform", name = "Position")\r
+       public Vector3d getPosition() {\r
+               return position;\r
+       }\r
+       \r
+       @RelatedGetValue(G3D.URIs.hasPosition)\r
+       public double[] getPositionArr() {\r
+               double arr[] = new double[3];\r
+               position.get(arr);\r
+               return arr;\r
+       }\r
+       \r
+       @RelatedElementsAdd(CSG.URIs.hasPrimaryShape)\r
+       public void addPrimaryChild(ICSGnode node) {\r
+               addNode("primary",node);\r
+       }\r
+       \r
+       @RelatedElementsGet(CSG.URIs.hasPrimaryShape)\r
+       public Collection<ICSGnode> getPrimaryChild() {\r
+               return getNodes("primary");\r
+       }\r
+       \r
+       @RelatedElementsRem(CSG.URIs.hasPrimaryShape)\r
+       public void remPrimaryChild(ICSGnode node) {\r
+               removeNode("primary", node);\r
+       }\r
+       \r
+       @RelatedElementsAdd(CSG.URIs.hasSecondaryShape)\r
+       public void addSecondaryChild(ICSGnode node) {\r
+               addNode("secondary",node);\r
+       }\r
+       \r
+       @RelatedElementsGet(CSG.URIs.hasSecondaryShape)\r
+       public Collection<ICSGnode> getSecondaryChild() {\r
+               return getNodes("secondary");\r
+       }\r
+       \r
+       @RelatedElementsRem(CSG.URIs.hasSecondaryShape)\r
+       public void remSecondaryChild(ICSGnode node) {\r
+               removeNode("secondary", node);\r
+       }\r
+       \r
+\r
+       @RelatedElementsAdd(CSG.URIs.hasChildShape)\r
+       public void addChild(ICSGnode node) {\r
+               addNode("child",node);\r
+       }\r
+       \r
+       @RelatedElementsGet(CSG.URIs.hasChildShape)\r
+       public Collection<ICSGnode> getChild() {\r
+               return getNodes("child");\r
+       }\r
+       \r
+       @RelatedElementsRem(CSG.URIs.hasChildShape)\r
+       public void remChild(ICSGnode node) {\r
+               removeNode("child", node);\r
+       }\r
+       \r
+       \r
+       \r
+       protected TopoDS_Shape getPrimary() {\r
+               for (ICSGnode node : getNodes("primary"))\r
+                       return node.getGeometry();\r
+               return null;\r
+       }\r
+       \r
+       protected TopoDS_Shape getSecondary() {\r
+               for (ICSGnode node : getNodes("secondary"))\r
+                       return node.getGeometry();\r
+               return null;\r
+       }\r
+       \r
+       @Override\r
+       public TopoDS_Shape getGeometry() {\r
+               TopoDS_Shape shape = getBaseGeometry();\r
+               if (shape == null)\r
+                       return null;\r
+               Quat4d q = getOrientation();\r
+               AxisAngle4d r = new AxisAngle4d();\r
+               r.set(q);\r
+               TopoDS_Shape tshape = OccTriangulator.makeRotation(shape, new double[] { 0.0, 0.0, 0.0, r.x, r.y, r.z }, r.angle);\r
+               shape.delete();\r
+               shape = tshape;\r
+               Vector3d p = getPosition();\r
+               tshape = OccTriangulator.makeTranslation(shape, p.x, p.y, p.z);\r
+               shape.delete();\r
+               return tshape;\r
+                       \r
+       }\r
+       \r
+\r
+       \r
+       @Override\r
+       @SetPropertyValue(G3D.URIs.hasOrientation)\r
+       public void setOrientation(Quat4d orientation) {\r
+               assert(orientation != null);\r
+               this.orientation = orientation;\r
+               \r
+               firePropertyChanged(G3D.URIs.hasOrientation);\r
+       }\r
+       \r
+       @Override\r
+       @SetPropertyValue(G3D.URIs.hasPosition)\r
+       public void setPosition(Vector3d position) {\r
+               assert(position != null);\r
+               this.position = position;\r
+               \r
+               firePropertyChanged(G3D.URIs.hasPosition);\r
+       }\r
+       \r
+       @RelatedSetValue(G3D.URIs.hasOrientation)\r
+       public void setOrientation(double[] arr) {\r
+               if (arr == null)\r
+                       return;\r
+               setOrientation(new Quat4d(arr));\r
+       }\r
+       \r
+       @RelatedSetValue(G3D.URIs.hasPosition)\r
+       public void setPosition(double[] arr) {\r
+               if (arr == null)\r
+                       return;\r
+               setPosition(new Vector3d(arr));\r
+       }\r
+       \r
+       @Override\r
+       @GetPropertyValue(value = G3D.URIs.hasWorldPosition, tabId = "Transform", name = "World Position")\r
+       public Vector3d getWorldPosition() {\r
+               IG3DNode parent = (IG3DNode) getParent();\r
+               if (parent == null)\r
+                       return position;\r
+               return NodeTools.getWorldPosition(parent, new Vector3d(position));\r
+       }\r
+\r
+       public Vector3d getWorldPosition(Vector3d localPosition) {\r
+               return NodeTools.getWorldPosition(this, localPosition);\r
+       }\r
+\r
+       \r
+       @Override\r
+       @GetPropertyValue(value = G3D.URIs.hasWorldOrientation, tabId = "Transform", name = "World Orientation")\r
+       public Quat4d getWorldOrientation() {\r
+               return getWorldOrientation(new Quat4d(orientation));\r
+       }\r
+       \r
+       public Quat4d getWorldOrientation(Quat4d localOrientation) {\r
+               IG3DNode parent = (IG3DNode)getParent();\r
+               if (parent == null)\r
+                       return localOrientation;\r
+               return NodeTools.getWorldOrientation(parent, localOrientation);\r
+       }\r
+       \r
+       @Override\r
+       public Vector3d getLocalPosition(Vector3d worldPosition) {\r
+               IG3DNode parent = (IG3DNode)getParent();\r
+               if (parent == null)\r
+                       return worldPosition;\r
+               return NodeTools.getLocalPosition(parent,new Vector3d(worldPosition));\r
+       }\r
+       \r
+       @Override\r
+       public Quat4d getLocalOrientation(Quat4d worldOrientation) {\r
+               IG3DNode parent = (IG3DNode)getParent();\r
+               if (parent == null)\r
+                       return worldOrientation;\r
+               return NodeTools.getLocalOrientation(parent, new Quat4d(worldOrientation));\r
+       }\r
+       \r
+       @Override\r
+       @SetPropertyValue(G3D.URIs.hasWorldPosition)\r
+       public void setWorldPosition(Vector3d position) {\r
+               Vector3d localPos = getLocalPosition(position);\r
+               setPosition(localPos);\r
+       }\r
+       \r
+       @Override\r
+       @SetPropertyValue(G3D.URIs.hasWorldOrientation)\r
+       public void setWorldOrientation(Quat4d orientation) {\r
+               Quat4d localOr = getLocalOrientation(orientation);\r
+               setOrientation(localOr);\r
+       }\r
+\r
+\r
+       private vtkSolidObject solidObject;\r
+       \r
+       \r
+       public void visualize(vtkPanel panel) {\r
+               if (solidObject != null) {\r
+                       solidObject.delete();\r
+                       solidObject = null;\r
+               }\r
+               TopoDS_Shape shape = getGeometry();\r
+               if (shape == null)\r
+                       return;\r
+               solidObject = new vtkSolidObject(panel, shape);\r
+               solidObject.visualizeSolid(true, false);\r
+       }\r
+       \r
+       @SuppressWarnings("unchecked")\r
+       public Collection<vtkProp3D> getActors() {\r
+               if (solidObject == null)\r
+                       return Collections.EMPTY_LIST;\r
+               return solidObject.getActors();\r
+       }\r
+       \r
+       public void stopVisualize() {\r
+               if (solidObject != null) {\r
+                       if (Thread.currentThread() == AWTThread.getThreadAccess().getThread())\r
+                               solidObject.delete();\r
+                       else\r
+                               solidObject.dispose();\r
+                       solidObject = null;\r
+               }\r
+       }\r
+       \r
+       @Override\r
+       public void cleanup() {\r
+               stopVisualize();\r
+               super.cleanup();\r
+       }\r
+       \r
+       \r
+       @Override\r
+       public void remove() {\r
+               //FIXME: creating boolean shapes (removing nodes from parent and attaching under boolean shape would destroy the existing hierarchy, if default implementation is used.\r
+               super.remove();\r
+       }\r
+\r
+       @Override\r
+       public Object getAdapter(Class adapter) {\r
+               return null;\r
+       }\r
+}\r
diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/CSGrootNode.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/CSGrootNode.java
new file mode 100644 (file)
index 0000000..ac7a515
--- /dev/null
@@ -0,0 +1,157 @@
+package org.simantics.g3d.csg.scenegraph2;\r
+\r
+import java.util.Collection;\r
+import java.util.HashSet;\r
+import java.util.Set;\r
+import java.util.Stack;\r
+\r
+import javax.vecmath.Quat4d;\r
+import javax.vecmath.Vector3d;\r
+\r
+import org.simantics.g3d.csg.editor.CSGNodeMap;\r
+import org.simantics.g3d.csg.ontology.CSG;\r
+import org.simantics.g3d.math.MathTools;\r
+import org.simantics.g3d.scenegraph.IG3DNode;\r
+import org.simantics.g3d.scenegraph.NodeMap;\r
+import org.simantics.g3d.scenegraph.NodeMapProvider;\r
+import org.simantics.g3d.scenegraph.base.NodeException;\r
+import org.simantics.g3d.scenegraph.base.ParentNode;\r
+import org.simantics.objmap.graph.annotations.GraphType;\r
+import org.simantics.objmap.graph.annotations.RelatedElementsAdd;\r
+import org.simantics.objmap.graph.annotations.RelatedElementsGet;\r
+import org.simantics.objmap.graph.annotations.RelatedElementsRem;\r
+\r
+import vtk.vtkProp;\r
+\r
+\r
+@GraphType(CSG.URIs.Model)\r
+public class CSGrootNode extends ParentNode<ICSGnode> implements IG3DNode, NodeMapProvider<vtkProp> {\r
+       \r
+       \r
+       private CSGNodeMap nodeMap;\r
+       \r
+       public void setNodeMap(CSGNodeMap nodeMap) {\r
+               this.nodeMap = nodeMap;\r
+       }\r
+       \r
+       @Override\r
+       public NodeMap<vtkProp> getNodeMap() {\r
+               return nodeMap;\r
+       }\r
+       \r
+       @Override\r
+       public ParentNode<?> getParent() {\r
+               return null;\r
+       }\r
+       \r
+       @Override\r
+       public ParentNode<?> getRootNode() {\r
+               return this;\r
+       }\r
+       \r
+       @RelatedElementsAdd(CSG.URIs.hasChildShape)\r
+       public void addChild(ICSGnode node) {\r
+               addNode("child",node);\r
+       }\r
+       \r
+       @RelatedElementsGet(CSG.URIs.hasChildShape)\r
+       public Collection<ICSGnode> getChild() {\r
+               return getNodes("child");\r
+       }\r
+       \r
+       @RelatedElementsRem(CSG.URIs.hasChildShape)\r
+       public void remChild(ICSGnode node) {\r
+               removeNode("child", node);\r
+       }\r
+       \r
+       public javax.vecmath.Quat4d getOrientation() {\r
+               return MathTools.getIdentityQuat();\r
+       };\r
+       \r
+       @Override\r
+       public Vector3d getPosition() {\r
+               return new Vector3d();\r
+       }\r
+       \r
+       @Override\r
+       public Quat4d getWorldOrientation() {\r
+               return MathTools.getIdentityQuat();\r
+       }\r
+       \r
+       @Override\r
+       public Vector3d getWorldPosition() {\r
+               return new Vector3d();\r
+       }\r
+       \r
+       @Override\r
+       public Quat4d getWorldOrientation(Quat4d localOrientation) {\r
+               return localOrientation;\r
+       }\r
+       \r
+       @Override\r
+       public Vector3d getWorldPosition(Vector3d localPosition) {\r
+               return localPosition;\r
+       }\r
+       \r
+       @Override\r
+       public Quat4d getLocalOrientation(Quat4d worldOrientation) {\r
+               return worldOrientation;\r
+       }\r
+       \r
+       @Override\r
+       public Vector3d getLocalPosition(Vector3d worldPosition) {\r
+               return worldPosition;\r
+       }\r
+       \r
+       @Override\r
+       public void setPosition(Vector3d position) {\r
+               throw new NodeException("Cannot set root node position");\r
+       }\r
+       \r
+       @Override\r
+       public void setOrientation(Quat4d orientation) {\r
+               throw new NodeException("Cannot set root node orientation");\r
+       }\r
+       \r
+       @Override\r
+       public void setWorldOrientation(Quat4d orientation) {\r
+               throw new NodeException("Cannot set root node orientation");\r
+       }\r
+       \r
+       @Override\r
+       public void setWorldPosition(Vector3d position) {\r
+               throw new NodeException("Cannot set root node orientation");\r
+       }\r
+       \r
+       public String getUniqueName(String prefix) {\r
+               Set<String> names = new HashSet<String>();\r
+               Stack<ICSGnode> nodes = new Stack<ICSGnode>();\r
+               nodes.addAll(getChild());\r
+               while (!nodes.isEmpty()) {\r
+                       ICSGnode n = nodes.pop();\r
+                       names.add(((ICSGnode)n).getName());\r
+                       if (n instanceof CSGparentNode) {\r
+                               nodes.addAll(((CSGparentNode)n).getChild());\r
+                               nodes.addAll(((CSGparentNode)n).getPrimaryChild());\r
+                               nodes.addAll(((CSGparentNode)n).getSecondaryChild());\r
+                       }\r
+               }\r
+               int i = 1;\r
+               while (true) {\r
+                       String genName = prefix + "_" + i;\r
+                       if (!names.contains(genName))\r
+                               return genName;\r
+                       i++;\r
+               }\r
+       }\r
+       \r
+\r
+       @Override\r
+       public Object getAdapter(Class adapter) {\r
+               if (NodeMap.class == adapter)\r
+                       return nodeMap;\r
+               return null;\r
+       }\r
+       \r
+\r
+}\r
diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/ConeNode.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/ConeNode.java
new file mode 100644 (file)
index 0000000..e392be6
--- /dev/null
@@ -0,0 +1,70 @@
+package org.simantics.g3d.csg.scenegraph2;\r
+\r
+import org.jcae.opencascade.jni.TopoDS_Shape;\r
+import org.simantics.g3d.csg.ontology.CSG;\r
+import org.simantics.g3d.property.annotations.GetPropertyValue;\r
+import org.simantics.g3d.property.annotations.SetPropertyValue;\r
+import org.simantics.objmap.graph.annotations.GraphType;\r
+import org.simantics.objmap.graph.annotations.RelatedGetValue;\r
+import org.simantics.objmap.graph.annotations.RelatedSetValue;\r
+import org.simantics.opencascade.OccTriangulator;\r
+\r
+@GraphType(CSG.URIs.Cone)\r
+public class ConeNode extends CSGnode {\r
+\r
+       private double r1 = 1.0;\r
+       private double r2 = 0.5;\r
+       private double h = 1.0;\r
+       \r
+       \r
+       @RelatedSetValue(CSG.URIs.HasBottomRadius)\r
+       @SetPropertyValue(CSG.URIs.HasBottomRadius)\r
+       public void setR1(double r1) {\r
+               this.r1 = r1;\r
+               firePropertyChanged(CSG.URIs.HasBottomRadius);\r
+       }\r
+       \r
+       @RelatedSetValue(CSG.URIs.HasTopRadius)\r
+       @SetPropertyValue(CSG.URIs.HasTopRadius)\r
+       public void setR2(double r2) {\r
+               this.r2 = r2;\r
+               firePropertyChanged(CSG.URIs.HasTopRadius);\r
+       }\r
+       \r
+       @RelatedSetValue(CSG.URIs.HasHeight)\r
+       @SetPropertyValue(CSG.URIs.HasHeight)\r
+       public void setH(double h) {\r
+               this.h = h;\r
+               firePropertyChanged(CSG.URIs.HasHeight);\r
+       }\r
+       \r
+       @RelatedGetValue(CSG.URIs.HasHeight)\r
+       @GetPropertyValue(value=CSG.URIs.HasHeight, name = "Height")\r
+       public double getH() {\r
+               return h;\r
+       }\r
+       \r
+       @RelatedGetValue(CSG.URIs.HasBottomRadius)\r
+       @GetPropertyValue(value=CSG.URIs.HasBottomRadius, name = "Bottom Radius")\r
+       public double getR1() {\r
+               return r1;\r
+       }\r
+       \r
+       @RelatedGetValue(CSG.URIs.HasTopRadius)\r
+       @GetPropertyValue(value=CSG.URIs.HasTopRadius, name = "Top Radius")\r
+       public double getR2() {\r
+               return r2;\r
+       }\r
+       \r
+       @Override\r
+       public TopoDS_Shape getBaseGeometry() {\r
+               if (Math.abs(r1-r2) > MIN_VALUE) {\r
+//                     if (r1 < MIN_VALUE)\r
+//                             return null;\r
+                       return OccTriangulator.makeCone(new double[] { 0.0, -h * 0.5, 0.0 }, new double[] { 0.0, 1.0, 0.0 }, r1,r2, h);\r
+               } else\r
+                       return OccTriangulator.makeCylinder(new double[] { 0.0, -h * 0.5, 0.0 }, new double[] { 0.0, 1.0, 0.0 }, r1, h);\r
+       }\r
+\r
+\r
+}\r
diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/CylinderNode.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/CylinderNode.java
new file mode 100644 (file)
index 0000000..d4a3f70
--- /dev/null
@@ -0,0 +1,49 @@
+package org.simantics.g3d.csg.scenegraph2;\r
+\r
+import org.jcae.opencascade.jni.TopoDS_Shape;\r
+import org.simantics.g3d.csg.ontology.CSG;\r
+import org.simantics.g3d.property.annotations.GetPropertyValue;\r
+import org.simantics.g3d.property.annotations.SetPropertyValue;\r
+import org.simantics.objmap.graph.annotations.GraphType;\r
+import org.simantics.objmap.graph.annotations.RelatedGetValue;\r
+import org.simantics.objmap.graph.annotations.RelatedSetValue;\r
+import org.simantics.opencascade.OccTriangulator;\r
+\r
+@GraphType(CSG.URIs.Cylinder)\r
+public class CylinderNode extends CSGnode {\r
+\r
+       private double r = 1.0;\r
+       private double h = 1.0;\r
+       \r
+       @RelatedSetValue(CSG.URIs.HasRadius)\r
+       @SetPropertyValue(CSG.URIs.HasRadius)\r
+       public void setR(double r) {\r
+               this.r = r;\r
+               firePropertyChanged(CSG.URIs.HasRadius);\r
+       }\r
+\r
+       @RelatedSetValue(CSG.URIs.HasHeight)\r
+       @SetPropertyValue(CSG.URIs.HasHeight)\r
+       public void setH(double h) {\r
+               this.h = h;\r
+               firePropertyChanged(CSG.URIs.HasHeight);\r
+       }\r
+       \r
+       @RelatedGetValue(CSG.URIs.HasHeight)\r
+       @GetPropertyValue(value=CSG.URIs.HasHeight, name = "Height")\r
+       public double getH() {\r
+               return h;\r
+       }\r
+       \r
+       @RelatedGetValue(CSG.URIs.HasRadius)\r
+       @GetPropertyValue(value=CSG.URIs.HasRadius, name = "Radius")\r
+       public double getR() {\r
+               return r;\r
+       }\r
+       \r
+       @Override\r
+       public TopoDS_Shape getBaseGeometry() {\r
+               return OccTriangulator.makeCylinder(new double[] { 0.0, -h * 0.5, 0.0 }, new double[] { 0.0, 1.0, 0.0 }, r, h);\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/DifferenceNode.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/DifferenceNode.java
new file mode 100644 (file)
index 0000000..9dce709
--- /dev/null
@@ -0,0 +1,29 @@
+package org.simantics.g3d.csg.scenegraph2;\r
+\r
+import org.jcae.opencascade.jni.TopoDS_Shape;\r
+import org.simantics.g3d.csg.ontology.CSG;\r
+import org.simantics.objmap.graph.annotations.GraphType;\r
+import org.simantics.opencascade.OccTriangulator;\r
+\r
+@GraphType(CSG.URIs.Difference)\r
+public class DifferenceNode extends CSGparentNode {\r
+\r
+       @Override\r
+       public TopoDS_Shape getBaseGeometry() {\r
+               TopoDS_Shape prim = getPrimary();\r
+               TopoDS_Shape sec = getSecondary();\r
+               if (prim != null && sec != null) {\r
+                       TopoDS_Shape res = OccTriangulator.makeCut(prim, sec);\r
+                       prim.delete();\r
+                       sec.delete();\r
+                       return res;\r
+               }\r
+               if (prim != null)\r
+                       prim.delete();\r
+               if (sec != null)\r
+                       sec.delete();\r
+               return null;\r
+       }\r
+\r
+       \r
+}\r
diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/EllipticCylinderNode.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/EllipticCylinderNode.java
new file mode 100644 (file)
index 0000000..5abecc2
--- /dev/null
@@ -0,0 +1,63 @@
+package org.simantics.g3d.csg.scenegraph2;\r
+\r
+import org.jcae.opencascade.jni.TopoDS_Shape;\r
+import org.simantics.g3d.csg.ontology.CSG;\r
+import org.simantics.g3d.property.annotations.GetPropertyValue;\r
+import org.simantics.g3d.property.annotations.SetPropertyValue;\r
+import org.simantics.objmap.graph.annotations.GraphType;\r
+import org.simantics.objmap.graph.annotations.RelatedGetValue;\r
+import org.simantics.objmap.graph.annotations.RelatedSetValue;\r
+import org.simantics.opencascade.OccTriangulator;\r
+\r
+@GraphType(CSG.URIs.EllipticCylinder)\r
+public class EllipticCylinderNode extends CSGnode {\r
+\r
+       private double r1 = 0.5;\r
+       private double r2 = 1.0;\r
+       private double h = 1.0;\r
+       \r
+       @RelatedSetValue(CSG.URIs.HasMinorRadius)\r
+       @SetPropertyValue(CSG.URIs.HasMinorRadius)\r
+       public void setR1(double r1) {\r
+               this.r1 = r1;\r
+               firePropertyChanged(CSG.URIs.HasMinorRadius);\r
+       }\r
+       \r
+       @RelatedSetValue(CSG.URIs.HasMajorRadius)\r
+       @SetPropertyValue(CSG.URIs.HasMajorRadius)\r
+       public void setR2(double r2) {\r
+               this.r2 = r2;\r
+               firePropertyChanged(CSG.URIs.HasMajorRadius);\r
+       }\r
+       \r
+       @RelatedSetValue(CSG.URIs.HasHeight)\r
+       @SetPropertyValue(CSG.URIs.HasHeight)\r
+       public void setH(double h) {\r
+               this.h = h;\r
+               firePropertyChanged(CSG.URIs.HasHeight);\r
+       }\r
+       \r
+       @RelatedGetValue(CSG.URIs.HasHeight)\r
+       @GetPropertyValue(value=CSG.URIs.HasHeight, name = "Height")\r
+       public double getH() {\r
+               return h;\r
+       }\r
+       \r
+       @RelatedGetValue(CSG.URIs.HasMinorRadius)\r
+       @GetPropertyValue(value=CSG.URIs.HasMinorRadius, name = "Minor Radius")\r
+       public double getR1() {\r
+               return r1;\r
+       }\r
+       \r
+       @RelatedGetValue(CSG.URIs.HasMajorRadius)\r
+       @GetPropertyValue(value=CSG.URIs.HasMajorRadius, name = "Major Radius")\r
+       public double getR2() {\r
+               return r2;\r
+       }\r
+       \r
+       @Override\r
+       public TopoDS_Shape getBaseGeometry() {\r
+               return OccTriangulator.makeEllipticCylinder(h, r1, r2);\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/ICSGnode.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/ICSGnode.java
new file mode 100644 (file)
index 0000000..76873e8
--- /dev/null
@@ -0,0 +1,28 @@
+package org.simantics.g3d.csg.scenegraph2;\r
+\r
+import java.util.Collection;\r
+\r
+import org.jcae.opencascade.jni.TopoDS_Shape;\r
+import org.simantics.g3d.scenegraph.IG3DNode;\r
+\r
+import vtk.vtkPanel;\r
+import vtk.vtkProp3D;\r
+\r
+public interface ICSGnode extends IG3DNode {\r
+       \r
+       \r
+       public String getName();\r
+       public void setName(String name);\r
+       \r
+       public TopoDS_Shape getBaseGeometry();\r
+       \r
+       public TopoDS_Shape getGeometry();\r
+       \r
+       \r
+       public void visualize(vtkPanel panel);\r
+       public void stopVisualize();\r
+       \r
+       public Collection<vtkProp3D> getActors();\r
+       \r
+       public void deattach();\r
+}\r
diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/IntersectionNode.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/IntersectionNode.java
new file mode 100644 (file)
index 0000000..738ff0f
--- /dev/null
@@ -0,0 +1,28 @@
+package org.simantics.g3d.csg.scenegraph2;\r
+\r
+import org.jcae.opencascade.jni.TopoDS_Shape;\r
+import org.simantics.g3d.csg.ontology.CSG;\r
+import org.simantics.objmap.graph.annotations.GraphType;\r
+import org.simantics.opencascade.OccTriangulator;\r
+\r
+@GraphType(CSG.URIs.Intersection)\r
+public class IntersectionNode extends CSGparentNode {\r
+\r
+       @Override\r
+       public TopoDS_Shape getBaseGeometry() {\r
+               TopoDS_Shape prim = getPrimary();\r
+               TopoDS_Shape sec = getSecondary();\r
+               if (prim != null && sec != null) {\r
+                       TopoDS_Shape res =OccTriangulator.makeCommon(prim, sec);\r
+                       prim.delete();\r
+                       sec.delete();\r
+                       return res;\r
+               }\r
+               if (prim != null)\r
+                       prim.delete();\r
+               if (sec != null)\r
+                       sec.delete();\r
+               return null;\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/RectangularSolidNode.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/RectangularSolidNode.java
new file mode 100644 (file)
index 0000000..6fb7f10
--- /dev/null
@@ -0,0 +1,171 @@
+package org.simantics.g3d.csg.scenegraph2;\r
+\r
+import org.jcae.opencascade.jni.BRepBuilderAPI_MakeEdge;\r
+import org.jcae.opencascade.jni.BRepBuilderAPI_MakeWire;\r
+import org.jcae.opencascade.jni.BRepOffsetAPI_ThruSections;\r
+import org.jcae.opencascade.jni.TopoDS_Edge;\r
+import org.jcae.opencascade.jni.TopoDS_Shape;\r
+import org.jcae.opencascade.jni.TopoDS_Wire;\r
+import org.simantics.g3d.csg.ontology.CSG;\r
+import org.simantics.g3d.property.annotations.GetPropertyValue;\r
+import org.simantics.g3d.property.annotations.SetPropertyValue;\r
+import org.simantics.objmap.graph.annotations.GraphType;\r
+import org.simantics.objmap.graph.annotations.RelatedGetValue;\r
+import org.simantics.objmap.graph.annotations.RelatedSetValue;\r
+\r
+\r
+@GraphType(CSG.URIs.RectangularSolid)\r
+public class RectangularSolidNode extends CSGnode {\r
+\r
+       double x1 = 0.5;\r
+       double x2 = 1.0;\r
+       double y = 1.0;\r
+       double z1 = 0.5;\r
+       double z2 = 1.0;\r
+       \r
+       \r
+       @RelatedSetValue(CSG.URIs.HasXAxisMinimumSize)\r
+       @SetPropertyValue(CSG.URIs.HasXAxisMinimumSize)\r
+       public void setX1(double d) {\r
+               this.x1 = d;\r
+               firePropertyChanged(CSG.URIs.HasXAxisMinimumSize);\r
+       }\r
+       \r
+       @RelatedSetValue(CSG.URIs.HasXAxisMaximumSize)\r
+       @SetPropertyValue(CSG.URIs.HasXAxisMaximumSize)\r
+       public void setX2(double d) {\r
+               this.x2 = d;\r
+               firePropertyChanged(CSG.URIs.HasXAxisMaximumSize);\r
+       }\r
+       \r
+       @RelatedSetValue(CSG.URIs.HasYAxisSize)\r
+       @SetPropertyValue(CSG.URIs.HasYAxisSize)\r
+       public void setSY(double d) {\r
+               this.y = d;\r
+               firePropertyChanged(CSG.URIs.HasYAxisSize);\r
+       }\r
+       \r
+       @RelatedSetValue(CSG.URIs.HasZAxisMinimumSize)\r
+       @SetPropertyValue(CSG.URIs.HasZAxisMinimumSize)\r
+       public void setZ1(double d) {\r
+               this.z1 = d;\r
+               firePropertyChanged(CSG.URIs.HasZAxisMinimumSize);\r
+       }\r
+       \r
+       @RelatedSetValue(CSG.URIs.HasZAxisMaximumSize)\r
+       @SetPropertyValue(CSG.URIs.HasZAxisMaximumSize)\r
+       public void setZ2(double d) {\r
+               this.z2 = d;\r
+               firePropertyChanged(CSG.URIs.HasZAxisMaximumSize);\r
+       }\r
+       \r
+       @RelatedGetValue(CSG.URIs.HasXAxisMinimumSize)\r
+       @GetPropertyValue(value=CSG.URIs.HasXAxisMinimumSize, name = "X Min Size")\r
+       public double getX1() {\r
+               return x1;\r
+       }\r
+       \r
+       @RelatedGetValue(CSG.URIs.HasXAxisMaximumSize)\r
+       @GetPropertyValue(value=CSG.URIs.HasXAxisMaximumSize, name = "X Max Size")\r
+       public double getX2() {\r
+               return x2;\r
+       }\r
+       \r
+       @RelatedGetValue(CSG.URIs.HasYAxisSize)\r
+       @GetPropertyValue(value=CSG.URIs.HasYAxisSize, name = "Y Size")\r
+       public double getY() {\r
+               return y;\r
+       }\r
+       \r
+       @RelatedGetValue(CSG.URIs.HasZAxisMinimumSize)\r
+       @GetPropertyValue(value=CSG.URIs.HasZAxisMinimumSize, name = "Z Min Size")\r
+       public double getZ1() {\r
+               return z1;\r
+       }\r
+       \r
+       @RelatedGetValue(CSG.URIs.HasZAxisMaximumSize)\r
+       @GetPropertyValue(value=CSG.URIs.HasZAxisMaximumSize, name = "Z Max Size")\r
+       public double getZ2() {\r
+               return z2;\r
+       }\r
+       \r
+       @Override\r
+       public TopoDS_Shape getBaseGeometry() {\r
+               double x1 = this.x1 *0.5;\r
+               double x2 = this.x2 *0.5;\r
+               double z1 = this.z1 *0.5;\r
+               double z2 = this.z2 *0.5;\r
+               double y = this.y * 0.5;\r
+               \r
+               BRepBuilderAPI_MakeWire wire = new BRepBuilderAPI_MakeWire();\r
+               BRepBuilderAPI_MakeEdge edge = new BRepBuilderAPI_MakeEdge(new double[]{x1,-y,z1},new double[]{x1,-y,-z1});\r
+               TopoDS_Edge top_edge = (TopoDS_Edge)edge.shape();\r
+               wire.add(top_edge);\r
+               edge.delete();\r
+               top_edge.delete();\r
+               \r
+               edge = new BRepBuilderAPI_MakeEdge(new double[]{x1,-y,-z1},new double[]{-x1,-y,-z1});\r
+               top_edge = (TopoDS_Edge)edge.shape();\r
+               wire.add(top_edge);\r
+               edge.delete();\r
+               top_edge.delete();\r
+               \r
+               edge = new BRepBuilderAPI_MakeEdge(new double[]{-x1,-y,-z1},new double[]{-x1,-y,z1});\r
+               top_edge = (TopoDS_Edge)edge.shape();\r
+               wire.add(top_edge);\r
+               edge.delete();\r
+               top_edge.delete();\r
+               \r
+               edge = new BRepBuilderAPI_MakeEdge(new double[]{-x1,-y,z1},new double[]{x1,-y,z1});\r
+               top_edge = (TopoDS_Edge)edge.shape();\r
+               wire.add(top_edge);\r
+               edge.delete();\r
+               top_edge.delete();\r
+               \r
+               TopoDS_Wire w1 = (TopoDS_Wire)wire.shape();\r
+               wire.delete();\r
+               wire = new BRepBuilderAPI_MakeWire();\r
+               \r
+               \r
+               edge = new BRepBuilderAPI_MakeEdge(new double[]{x2, y,z2},new double[]{x2, y,-z2});\r
+               top_edge = (TopoDS_Edge)edge.shape();\r
+               wire.add(top_edge);\r
+               edge.delete();\r
+               top_edge.delete();\r
+               \r
+               edge = new BRepBuilderAPI_MakeEdge(new double[]{x2, y,-z2},new double[]{-x2, y,-z2});\r
+               top_edge = (TopoDS_Edge)edge.shape();\r
+               wire.add(top_edge);\r
+               edge.delete();\r
+               top_edge.delete();\r
+               \r
+               edge = new BRepBuilderAPI_MakeEdge(new double[]{-x2, y,-z2},new double[]{-x2, y,z2});\r
+               top_edge = (TopoDS_Edge)edge.shape();\r
+               wire.add(top_edge);\r
+               edge.delete();\r
+               top_edge.delete();\r
+               \r
+               edge = new BRepBuilderAPI_MakeEdge(new double[]{-x2, y,z2},new double[]{x2, y,z2});\r
+               top_edge = (TopoDS_Edge)edge.shape();\r
+               wire.add(top_edge);\r
+               edge.delete();\r
+               top_edge.delete();\r
+               \r
+               TopoDS_Wire w2 = (TopoDS_Wire)wire.shape();\r
+               wire.delete();\r
+               \r
+               BRepOffsetAPI_ThruSections generatorb = new BRepOffsetAPI_ThruSections(true, true);\r
+               generatorb.addWire(w1);\r
+               generatorb.addWire(w2);\r
+               generatorb.build();\r
+               w1.delete();\r
+               w2.delete();\r
+               \r
+               TopoDS_Shape shape = generatorb.shape();\r
+               generatorb.delete();\r
+               \r
+               return shape;\r
+       }\r
+\r
+\r
+}\r
diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/RegularPrismNode.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/RegularPrismNode.java
new file mode 100644 (file)
index 0000000..ebb9345
--- /dev/null
@@ -0,0 +1,67 @@
+package org.simantics.g3d.csg.scenegraph2;\r
+\r
+import org.jcae.opencascade.jni.TopoDS_Shape;\r
+import org.simantics.g3d.csg.ontology.CSG;\r
+import org.simantics.g3d.property.annotations.GetPropertyValue;\r
+import org.simantics.g3d.property.annotations.SetPropertyValue;\r
+import org.simantics.objmap.graph.annotations.GraphType;\r
+import org.simantics.objmap.graph.annotations.RelatedGetValue;\r
+import org.simantics.objmap.graph.annotations.RelatedSetValue;\r
+import org.simantics.opencascade.OccTriangulator;\r
+\r
+@GraphType(CSG.URIs.RegularPrism)\r
+public class RegularPrismNode extends CSGnode {\r
+\r
+       private double r = 1.0;\r
+       private double h = 1.0;\r
+       private int n = 3;\r
+       \r
+       @RelatedSetValue(CSG.URIs.HasRadius)\r
+       @SetPropertyValue(CSG.URIs.HasRadius)\r
+       public void setR(double r) {\r
+               this.r = r;\r
+               firePropertyChanged(CSG.URIs.HasRadius);\r
+       }\r
+\r
+       \r
+       @RelatedSetValue(CSG.URIs.HasHeight)\r
+       @SetPropertyValue(CSG.URIs.HasHeight)\r
+       public void setH(double h) {\r
+               this.h = h;\r
+               firePropertyChanged(CSG.URIs.HasHeight);\r
+       }\r
+       \r
+       @RelatedSetValue(CSG.URIs.HasCorners)\r
+       @SetPropertyValue(CSG.URIs.HasCorners)\r
+       public void setN(int n) {\r
+               if (n < 3)\r
+                       n = 3;\r
+               this.n = n;\r
+               firePropertyChanged(CSG.URIs.HasCorners);\r
+       }\r
+       \r
+       @RelatedGetValue(CSG.URIs.HasHeight)\r
+       @GetPropertyValue(value=CSG.URIs.HasHeight, name="Height")\r
+       public double getH() {\r
+               return h;\r
+       }\r
+       \r
+       @RelatedGetValue(CSG.URIs.HasCorners)\r
+       @GetPropertyValue(value=CSG.URIs.HasCorners, name="Corners")\r
+       public int getN() {\r
+               return n;\r
+       }\r
+       \r
+       @RelatedGetValue(CSG.URIs.HasRadius)\r
+       @GetPropertyValue(value=CSG.URIs.HasRadius, name="Radius")\r
+       public double getR() {\r
+               return r;\r
+       }\r
+       \r
+       @Override\r
+       public TopoDS_Shape getBaseGeometry() {\r
+               return OccTriangulator.makeReqularPrism(h, r, n);\r
+       }\r
+\r
+\r
+}\r
diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/SchemaBuilder.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/SchemaBuilder.java
new file mode 100644 (file)
index 0000000..90999a0
--- /dev/null
@@ -0,0 +1,48 @@
+package org.simantics.g3d.csg.scenegraph2;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.request.Read;\r
+import org.simantics.objmap.graph.schema.IMappingSchema;\r
+import org.simantics.objmap.graph.schema.MappingSchemas;\r
+import org.simantics.objmap.graph.schema.SimpleSchema;\r
+import org.simantics.ui.SimanticsUI;\r
+\r
+public class SchemaBuilder {\r
+       \r
+       public static IMappingSchema<Resource,Object> getSchema() throws DatabaseException{\r
+               return SimanticsUI.getSession().syncRequest(new Read<IMappingSchema<Resource,Object>>() {\r
+                       @Override\r
+                       public IMappingSchema<Resource,Object> perform(ReadGraph g)\r
+                                       throws DatabaseException {\r
+                               return getSchema(g);\r
+                       }\r
+               });\r
+       }\r
+       \r
+       public static IMappingSchema<Resource,Object> getSchema(ReadGraph g) throws DatabaseException{\r
+               try {\r
+                       SimpleSchema schema = new SimpleSchema();\r
+                       schema.addLinkType(MappingSchemas.fromAnnotations(g, BarrelNode.class));\r
+                       schema.addLinkType(MappingSchemas.fromAnnotations(g, BoxNode.class));\r
+                       schema.addLinkType(MappingSchemas.fromAnnotations(g, ConeNode.class));\r
+                       schema.addLinkType(MappingSchemas.fromAnnotations(g, CylinderNode.class));\r
+                       schema.addLinkType(MappingSchemas.fromAnnotations(g, DifferenceNode.class));\r
+                       schema.addLinkType(MappingSchemas.fromAnnotations(g, EllipticCylinderNode.class));\r
+                       schema.addLinkType(MappingSchemas.fromAnnotations(g, IntersectionNode.class));\r
+                       schema.addLinkType(MappingSchemas.fromAnnotations(g, RectangularSolidNode.class));\r
+                       schema.addLinkType(MappingSchemas.fromAnnotations(g, RegularPrismNode.class));\r
+                       schema.addLinkType(MappingSchemas.fromAnnotations(g, SphereNode.class));\r
+                       schema.addLinkType(MappingSchemas.fromAnnotations(g, TorusNode.class));\r
+                       schema.addLinkType(MappingSchemas.fromAnnotations(g, UnionNode.class));\r
+                       schema.addLinkType(MappingSchemas.fromAnnotations(g, CSGrootNode.class));\r
+                       return schema;\r
+               } catch (IllegalAccessException e) {\r
+                       throw new DatabaseException(e);\r
+               } catch (InstantiationException e) {\r
+                       throw new DatabaseException(e);\r
+               }\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/SphereNode.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/SphereNode.java
new file mode 100644 (file)
index 0000000..a2cc658
--- /dev/null
@@ -0,0 +1,35 @@
+package org.simantics.g3d.csg.scenegraph2;\r
+\r
+import org.jcae.opencascade.jni.TopoDS_Shape;\r
+import org.simantics.g3d.csg.ontology.CSG;\r
+import org.simantics.g3d.property.annotations.GetPropertyValue;\r
+import org.simantics.g3d.property.annotations.SetPropertyValue;\r
+import org.simantics.objmap.graph.annotations.GraphType;\r
+import org.simantics.objmap.graph.annotations.RelatedGetValue;\r
+import org.simantics.objmap.graph.annotations.RelatedSetValue;\r
+import org.simantics.opencascade.OccTriangulator;\r
+\r
+@GraphType(CSG.URIs.Sphere)\r
+public class SphereNode extends CSGnode {\r
+\r
+       private double r = 1.0;\r
+       \r
+       @RelatedSetValue(CSG.URIs.HasRadius)\r
+       @SetPropertyValue(CSG.URIs.HasRadius)\r
+       public void setR(double r) {\r
+               this.r = r;\r
+               firePropertyChanged(CSG.URIs.HasRadius);\r
+       }\r
+       \r
+       @RelatedGetValue(CSG.URIs.HasRadius)\r
+       @GetPropertyValue(value=CSG.URIs.HasRadius, name="Radius")\r
+       public double getR() {\r
+               return r;\r
+       }\r
+       \r
+       @Override\r
+       public TopoDS_Shape getBaseGeometry() {\r
+               return OccTriangulator.makeSphere(0, 0, 0, r);\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/TorusNode.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/TorusNode.java
new file mode 100644 (file)
index 0000000..a76a504
--- /dev/null
@@ -0,0 +1,50 @@
+package org.simantics.g3d.csg.scenegraph2;\r
+\r
+import org.jcae.opencascade.jni.TopoDS_Shape;\r
+import org.simantics.g3d.csg.ontology.CSG;\r
+import org.simantics.g3d.property.annotations.GetPropertyValue;\r
+import org.simantics.g3d.property.annotations.SetPropertyValue;\r
+import org.simantics.objmap.graph.annotations.GraphType;\r
+import org.simantics.objmap.graph.annotations.RelatedGetValue;\r
+import org.simantics.objmap.graph.annotations.RelatedSetValue;\r
+import org.simantics.opencascade.OccTriangulator;\r
+\r
+@GraphType(CSG.URIs.Torus)\r
+public class TorusNode extends CSGnode {\r
+\r
+       private double r1 = 1.0;\r
+       private double r2 = 1.0;\r
+       \r
+       \r
+       @RelatedSetValue(CSG.URIs.HasMinorRadius)\r
+       @SetPropertyValue(CSG.URIs.HasMinorRadius)\r
+       public void setR1(double r1) {\r
+               this.r1 = r1;\r
+               firePropertyChanged(CSG.URIs.HasMinorRadius);\r
+       }\r
+       \r
+       @RelatedSetValue(CSG.URIs.HasMajorRadius)\r
+       @SetPropertyValue(CSG.URIs.HasMajorRadius)\r
+       public void setR2(double r2) {\r
+               this.r2 = r2;\r
+               firePropertyChanged(CSG.URIs.HasMajorRadius);\r
+       }\r
+       \r
+       @RelatedGetValue(CSG.URIs.HasMinorRadius)\r
+       @GetPropertyValue(value=CSG.URIs.HasMinorRadius, name="Minor Radius")\r
+       public double getR1() {\r
+               return r1;\r
+       }\r
+       \r
+       @RelatedGetValue(CSG.URIs.HasMajorRadius)\r
+       @GetPropertyValue(value=CSG.URIs.HasMajorRadius, name="Major Radius")   \r
+       public double getR2() {\r
+               return r2;\r
+       }\r
+       \r
+       @Override\r
+       public TopoDS_Shape getBaseGeometry() {\r
+               return OccTriangulator.makeTorus(new double[] { 0.0, 0.0, 0.0 }, new double[] { 0.0, 1.0, 0.0 }, r2, r1);\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/UnionNode.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/UnionNode.java
new file mode 100644 (file)
index 0000000..2e9aa2e
--- /dev/null
@@ -0,0 +1,29 @@
+package org.simantics.g3d.csg.scenegraph2;\r
+\r
+import org.jcae.opencascade.jni.TopoDS_Shape;\r
+import org.simantics.g3d.csg.ontology.CSG;\r
+\r
+import org.simantics.objmap.graph.annotations.GraphType;\r
+import org.simantics.opencascade.OccTriangulator;\r
+\r
+@GraphType(CSG.URIs.Union)\r
+public class UnionNode extends CSGparentNode {\r
+\r
+       @Override\r
+       public TopoDS_Shape getBaseGeometry() {\r
+               TopoDS_Shape prim = getPrimary();\r
+               TopoDS_Shape sec = getSecondary();\r
+               if (prim != null && sec != null) {\r
+                       TopoDS_Shape res =OccTriangulator.makeFuse(prim, sec);\r
+                       prim.delete();\r
+                       sec.delete();\r
+                       return res;\r
+               }\r
+               if (prim != null)\r
+                       prim.delete();\r
+               if (sec != null)\r
+                       sec.delete();\r
+               return null;\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/wizard/CSGBRepExportWizard.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/wizard/CSGBRepExportWizard.java
new file mode 100644 (file)
index 0000000..44a227a
--- /dev/null
@@ -0,0 +1,56 @@
+package org.simantics.g3d.csg.wizard;\r
+\r
+import java.util.Deque;\r
+\r
+import org.eclipse.core.runtime.preferences.InstanceScope;\r
+import org.eclipse.jface.operation.IRunnableWithProgress;\r
+import org.eclipse.jface.preference.IPersistentPreferenceStore;\r
+import org.eclipse.ui.preferences.ScopedPreferenceStore;\r
+import org.simantics.g3d.csg.Activator;\r
+import org.simantics.g3d.wizard.ModelExportWizard;\r
+import org.simantics.g3d.wizard.ModelExportWizardPage;\r
+\r
+public class CSGBRepExportWizard extends ModelExportWizard<CSGExportModel> {\r
+\r
+       public static final String RECENT_CSG_EXPORT_LOCATIONS = "RECENT_CSG_EXPORT_LOCATIONS";\r
+       public static final String CSG_EXPORT_OVERWRITE = "CSG_EXPORT_OVERWRITE";\r
+    \r
+       public CSGBRepExportWizard() {\r
+               setWindowTitle("Export CSG Model to Brep");\r
+               setNeedsProgressMonitor(true);\r
+       }\r
+       \r
+       @Override\r
+       protected CSGExportModel createExportModel(Deque<String> recentExportPaths) {\r
+               return new CSGExportModel(recentExportPaths);\r
+       }\r
+       \r
+       @Override\r
+       protected ModelExportWizardPage<CSGExportModel> createExportPage(CSGExportModel exportModel) {\r
+               return new CSGExportPage(exportModel);\r
+       }\r
+       \r
+       @Override\r
+       protected IRunnableWithProgress createExportRunnable(CSGExportModel exportModel) {\r
+               return new CSGBrepModelExporter(exportModel);\r
+       }\r
+       \r
+       @Override\r
+       protected String getExportLocationId() {\r
+               return RECENT_CSG_EXPORT_LOCATIONS;\r
+       }\r
+       \r
+       @Override\r
+       protected String getExportOverwriteId() {\r
+               return CSG_EXPORT_OVERWRITE;\r
+       }\r
+       \r
+\r
+       @Override\r
+       protected IPersistentPreferenceStore getPreferenceStore() {\r
+               return new ScopedPreferenceStore(InstanceScope.INSTANCE, Activator.PLUGIN_ID);\r
+       }\r
+       \r
+\r
+\r
+}\r
diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/wizard/CSGBrepModelExporter.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/wizard/CSGBrepModelExporter.java
new file mode 100644 (file)
index 0000000..8e00a3d
--- /dev/null
@@ -0,0 +1,98 @@
+package org.simantics.g3d.csg.wizard;\r
+\r
+import java.io.IOException;\r
+import java.lang.reflect.InvocationTargetException;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import org.eclipse.core.runtime.IProgressMonitor;\r
+import org.eclipse.core.runtime.SubMonitor;\r
+import org.eclipse.jface.operation.IRunnableWithProgress;\r
+import org.jcae.opencascade.jni.TopoDS_Shape;\r
+import org.simantics.Simantics;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.request.Read;\r
+import org.simantics.g3d.csg.scenegraph2.CSGrootNode;\r
+import org.simantics.g3d.csg.scenegraph2.ICSGnode;\r
+import org.simantics.g3d.csg.scenegraph2.SchemaBuilder;\r
+import org.simantics.objmap.graph.IMapping;\r
+import org.simantics.objmap.graph.Mappings;\r
+import org.simantics.objmap.graph.schema.IMappingSchema;\r
+import org.simantics.opencascade.OccTriangulator;\r
+\r
+public class CSGBrepModelExporter implements IRunnableWithProgress {\r
+\r
+               CSGExportModel exportModel;\r
+               public CSGBrepModelExporter(CSGExportModel exportModel) {\r
+                       this.exportModel = exportModel;\r
+               }\r
+               \r
+               @Override\r
+               public void run(IProgressMonitor monitor) throws InvocationTargetException,\r
+                               InterruptedException {\r
+                        SubMonitor progress = SubMonitor.convert(monitor, 50);\r
+                        SubMonitor mon = progress.newChild(50, SubMonitor.SUPPRESS_NONE);\r
+                       try {\r
+                           exportModel(mon);\r
+                       } catch (IOException e) {\r
+                               mon.setCanceled(true);\r
+                           throw new InvocationTargetException(e);\r
+                       } catch (DatabaseException e) {\r
+                               mon.setCanceled(true);\r
+                           throw new InvocationTargetException(e);\r
+                       }  finally {\r
+                           monitor.done();\r
+                       }\r
+                       \r
+               }\r
+\r
+               void exportModel(SubMonitor mon) throws IOException, DatabaseException {\r
+                       int taskSize = 50;\r
+                       mon.beginTask("Exporting model...", taskSize);\r
+                       mon.setTaskName("Initializing CSG model...");\r
+                       \r
+                       CSGrootNode rootNode = Simantics.getSessionContext().getSession().syncRequest(new Read<CSGrootNode>() {\r
+                               @Override\r
+                               public CSGrootNode perform(ReadGraph graph)\r
+                                               throws DatabaseException {\r
+                                       IMappingSchema<Resource, Object> schema = SchemaBuilder.getSchema(graph);\r
+                                       IMapping<Resource, Object> mapping = Mappings.createWithoutListening(schema);\r
+                                       CSGrootNode rootNode = (CSGrootNode) mapping.map(graph,exportModel.getModel().getResource());\r
+                                       mapping.dispose();\r
+                                       return rootNode;\r
+                               }\r
+                       });\r
+                       mon.worked(40);\r
+                       \r
+                       mon.setTaskName("Creating solid geometry...");\r
+                       List<TopoDS_Shape> shapes = new ArrayList<TopoDS_Shape>();\r
+                       for (ICSGnode node : rootNode.getChild()) {\r
+                               TopoDS_Shape shape = node.getGeometry();\r
+                               if (shape != null)\r
+                                       shapes.add(shape);\r
+                       }\r
+                       if (shapes.size() == 0) {\r
+                               mon.setTaskName("Nothing to export.");\r
+                               mon.setCanceled(true);\r
+                               return;\r
+                       }\r
+                       TopoDS_Shape compound = null;\r
+                       if (shapes.size() > 1) {\r
+                               OccTriangulator.makeCompound(shapes.toArray(new TopoDS_Shape[shapes.size()]));\r
+                               for (TopoDS_Shape shape : shapes)\r
+                                       shape.delete();\r
+                       } else {\r
+                               compound = shapes.get(0);\r
+                       }\r
+                       \r
+                       mon.worked(50);\r
+                       \r
+                       mon.setTaskName("Writing file...");\r
+                       OccTriangulator.exportBREP(compound, exportModel.getExportLocation().getAbsolutePath());\r
+                       compound.delete();\r
+                       \r
+                       mon.setWorkRemaining(0);\r
+               }\r
+}\r
diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/wizard/CSGExportModel.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/wizard/CSGExportModel.java
new file mode 100644 (file)
index 0000000..6690a62
--- /dev/null
@@ -0,0 +1,21 @@
+package org.simantics.g3d.csg.wizard;\r
+\r
+import java.util.Deque;\r
+\r
+import org.simantics.g3d.wizard.IExportModel;\r
+\r
+public class CSGExportModel extends IExportModel{\r
+\r
+    \r
+    \r
+    public CSGExportModel(Deque<String> recentLocations) {\r
+        super();\r
+        setRecentLocations(recentLocations);\r
+    }\r
+    \r
+    @Override\r
+    public boolean usesFile() {\r
+       return true;\r
+    }\r
+\r
+}\r
diff --git a/org.simantics.g3d.csg/src/org/simantics/g3d/csg/wizard/CSGExportPage.java b/org.simantics.g3d.csg/src/org/simantics/g3d/csg/wizard/CSGExportPage.java
new file mode 100644 (file)
index 0000000..c9354d3
--- /dev/null
@@ -0,0 +1,51 @@
+package org.simantics.g3d.csg.wizard;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.common.NamedResource;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.g3d.csg.ontology.CSG;\r
+import org.simantics.g3d.wizard.ModelExportWizardPage;\r
+import org.simantics.layer0.Layer0;\r
+\r
+public class CSGExportPage extends ModelExportWizardPage<CSGExportModel> {\r
+       \r
+\r
+    \r
+       public CSGExportPage(CSGExportModel model) {\r
+               super("Export CSG Model","Define Export Location",null,model);\r
+       }\r
+       \r
+       @Override\r
+       public String[] getFilterExtensions() {\r
+               return new String[]{"*.brep"};\r
+       }\r
+       \r
+       @Override\r
+       public String[] getFilterNames() {\r
+               return new String[]{"OpenCASCADE Brep file"};\r
+       }\r
+       \r
+       \r
+       @Override\r
+       protected List<NamedResource> getSupportedModels(ReadGraph graph, Resource project) throws DatabaseException {\r
+               List<NamedResource> models = new ArrayList<NamedResource>();\r
+               Layer0 L0 = Layer0.getInstance(graph);\r
+        CSG csg = CSG.getInstance(graph);\r
+        \r
+        for (Resource r : graph.getObjects(project, L0.ConsistsOf)) {\r
+                if (graph.isInstanceOf(r, csg.Model)) {\r
+                        models.add(new NamedResource((String)graph.getRelatedValue(r, L0.HasName), r));\r
+                }\r
+        }\r
+        return models;\r
+       }\r
+   \r
+\r
\r
+\r
+\r
+}\r
diff --git a/org.simantics.g3d.ontology/.classpath b/org.simantics.g3d.ontology/.classpath
new file mode 100644 (file)
index 0000000..8a8f166
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<classpath>\r
+       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>\r
+       <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>\r
+       <classpathentry kind="src" path="src"/>\r
+       <classpathentry kind="output" path="bin"/>\r
+</classpath>\r
diff --git a/org.simantics.g3d.ontology/.project b/org.simantics.g3d.ontology/.project
new file mode 100644 (file)
index 0000000..43fd987
--- /dev/null
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<projectDescription>\r
+       <name>org.simantics.g3d.ontology</name>\r
+       <comment></comment>\r
+       <projects>\r
+       </projects>\r
+       <buildSpec>\r
+               <buildCommand>\r
+                       <name>org.simantics.graph.builder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+               <buildCommand>\r
+                       <name>org.eclipse.jdt.core.javabuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+               <buildCommand>\r
+                       <name>org.eclipse.pde.ManifestBuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+               <buildCommand>\r
+                       <name>org.eclipse.pde.SchemaBuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+       </buildSpec>\r
+       <natures>\r
+               <nature>org.eclipse.pde.PluginNature</nature>\r
+               <nature>org.eclipse.jdt.core.javanature</nature>\r
+               <nature>org.simantics.graph.nature</nature>\r
+       </natures>\r
+</projectDescription>\r
diff --git a/org.simantics.g3d.ontology/.settings/org.eclipse.jdt.core.prefs b/org.simantics.g3d.ontology/.settings/org.eclipse.jdt.core.prefs
new file mode 100644 (file)
index 0000000..5c42125
--- /dev/null
@@ -0,0 +1,8 @@
+#Mon Dec 12 12:36:09 EET 2011\r
+eclipse.preferences.version=1\r
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled\r
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6\r
+org.eclipse.jdt.core.compiler.compliance=1.6\r
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error\r
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error\r
+org.eclipse.jdt.core.compiler.source=1.6\r
diff --git a/org.simantics.g3d.ontology/META-INF/MANIFEST.MF b/org.simantics.g3d.ontology/META-INF/MANIFEST.MF
new file mode 100644 (file)
index 0000000..2ce6eaf
--- /dev/null
@@ -0,0 +1,10 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: G3D Ontology
+Bundle-SymbolicName: org.simantics.g3d.ontology
+Bundle-Version: 1.0.0.qualifier
+Bundle-Vendor: VTT
+Require-Bundle: org.eclipse.core.runtime,
+ org.simantics.layer0;bundle-version="1.0.0"
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6
+Export-Package: org.simantics.g3d.ontology
diff --git a/org.simantics.g3d.ontology/build.properties b/org.simantics.g3d.ontology/build.properties
new file mode 100644 (file)
index 0000000..ecdc7c3
--- /dev/null
@@ -0,0 +1,5 @@
+source.. = src/\r
+output.. = bin/\r
+bin.includes = META-INF/,\\r
+               .,\\r
+               graph.tg\r
diff --git a/org.simantics.g3d.ontology/graph.tg b/org.simantics.g3d.ontology/graph.tg
new file mode 100644 (file)
index 0000000..8c6bb84
Binary files /dev/null and b/org.simantics.g3d.ontology/graph.tg differ
diff --git a/org.simantics.g3d.ontology/graph/g3d.pgraph b/org.simantics.g3d.ontology/graph/g3d.pgraph
new file mode 100644 (file)
index 0000000..fb33af8
--- /dev/null
@@ -0,0 +1,63 @@
+L0 = <http://www.simantics.org/Layer0-1.1>\r
+\r
+G3D = <http://www.simantics.org/G3D-0.1> : L0.Ontology\r
+    @L0.new\r
+    L0.HasResourceClass "org.simantics.g3d.ontology.G3D"\r
+\r
+\r
+G3D.Tuple3D <T L0.Literal\r
+   @L0.assert L0.HasDataType $(Double[3])\r
+   \r
+G3D.Tuple4D <T L0.Literal\r
+   @L0.assert L0.HasDataType $(Double[4])\r
+\r
+\r
+G3D.Position <T G3D.Tuple3D\r
+\r
+G3D.Orientation <T G3D.Tuple4D\r
+\r
+G3D.hasNodeProperty <R L0.HasProperty\r
+\r
+G3D.hasNonTransformation <R G3D.hasNodeProperty\r
+G3D.hasTransformation <R G3D.hasNodeProperty\r
+\r
+\r
+G3D.hasOrientation <R G3D.hasTransformation\r
+  --> G3D.Orientation\r
+  \r
+G3D.hasPosition <R G3D.hasTransformation\r
+  --> G3D.Position\r
+  \r
+G3D.hasWorldOrientation <R G3D.hasTransformation\r
+  --> G3D.Orientation\r
+  @L0.tag L0.Abstract\r
+  \r
+G3D.hasWorldPosition <R G3D.hasTransformation\r
+  --> G3D.Position\r
+  @L0.tag L0.Abstract\r
+\r
+G3D.nodes <R L0.IsComposedOf\r
+   @L0.tag L0.Abstract\r
+   L0.InverseOf G3D.parentNode <R L0.IsWeaklyRelatedTo\r
+   L0.HasDomain G3D.BaseNode\r
+   L0.HasRange G3D.BaseNode\r
+   \r
+G3D.geometryDefinition <R G3D.nodes\r
+   L0.InverseOf G3D.geometryDefinitionOf\r
+\r
+G3D.children <R G3D.nodes\r
+   L0.InverseOf G3D.parent\r
+\r
+G3D.BaseNode <T L0.Entity\r
+   @L0.tag L0.Abstract\r
+   @L0.singleProperty G3D.hasPosition\r
+   @L0.singleProperty G3D.hasOrientation\r
+\r
+G3D.RootNode <T G3D.BaseNode\r
+\r
+G3D.Node <T G3D.BaseNode\r
+\r
+\r
+// Structural modelling\r
+\r
+G3D.publishes <R L0.DomainOf
\ No newline at end of file
diff --git a/org.simantics.g3d.ontology/src/org/simantics/g3d/ontology/G3D.java b/org.simantics.g3d.ontology/src/org/simantics/g3d/ontology/G3D.java
new file mode 100644 (file)
index 0000000..08c6a5d
--- /dev/null
@@ -0,0 +1,141 @@
+package org.simantics.g3d.ontology;\r
+\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.request.Read;\r
+import org.simantics.db.Session;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.service.QueryControl;\r
+\r
+public class G3D {\r
+    \r
+    public final Resource BaseNode;\r
+    public final Resource Node;\r
+    public final Resource Orientation;\r
+    public final Resource Position;\r
+    public final Resource RootNode;\r
+    public final Resource Tuple3D;\r
+    public final Resource Tuple4D;\r
+    public final Resource children;\r
+    public final Resource geometryDefinition;\r
+    public final Resource geometryDefinitionOf;\r
+    public final Resource hasNodeProperty;\r
+    public final Resource hasNodeProperty_Inverse;\r
+    public final Resource hasNonTransformation;\r
+    public final Resource hasNonTransformation_Inverse;\r
+    public final Resource hasOrientation;\r
+    public final Resource hasOrientation_Inverse;\r
+    public final Resource hasPosition;\r
+    public final Resource hasPosition_Inverse;\r
+    public final Resource hasTransformation;\r
+    public final Resource hasTransformation_Inverse;\r
+    public final Resource hasWorldOrientation;\r
+    public final Resource hasWorldOrientation_Inverse;\r
+    public final Resource hasWorldPosition;\r
+    public final Resource hasWorldPosition_Inverse;\r
+    public final Resource nodes;\r
+    public final Resource parent;\r
+    public final Resource parentNode;\r
+    public final Resource publishes;\r
+    public final Resource publishes_Inverse;\r
+        \r
+    public static class URIs {\r
+        public static final String BaseNode = "http://www.simantics.org/G3D-0.1/BaseNode";\r
+        public static final String Node = "http://www.simantics.org/G3D-0.1/Node";\r
+        public static final String Orientation = "http://www.simantics.org/G3D-0.1/Orientation";\r
+        public static final String Position = "http://www.simantics.org/G3D-0.1/Position";\r
+        public static final String RootNode = "http://www.simantics.org/G3D-0.1/RootNode";\r
+        public static final String Tuple3D = "http://www.simantics.org/G3D-0.1/Tuple3D";\r
+        public static final String Tuple4D = "http://www.simantics.org/G3D-0.1/Tuple4D";\r
+        public static final String children = "http://www.simantics.org/G3D-0.1/children";\r
+        public static final String geometryDefinition = "http://www.simantics.org/G3D-0.1/geometryDefinition";\r
+        public static final String geometryDefinitionOf = "http://www.simantics.org/G3D-0.1/geometryDefinitionOf";\r
+        public static final String hasNodeProperty = "http://www.simantics.org/G3D-0.1/hasNodeProperty";\r
+        public static final String hasNodeProperty_Inverse = "http://www.simantics.org/G3D-0.1/hasNodeProperty/Inverse";\r
+        public static final String hasNonTransformation = "http://www.simantics.org/G3D-0.1/hasNonTransformation";\r
+        public static final String hasNonTransformation_Inverse = "http://www.simantics.org/G3D-0.1/hasNonTransformation/Inverse";\r
+        public static final String hasOrientation = "http://www.simantics.org/G3D-0.1/hasOrientation";\r
+        public static final String hasOrientation_Inverse = "http://www.simantics.org/G3D-0.1/hasOrientation/Inverse";\r
+        public static final String hasPosition = "http://www.simantics.org/G3D-0.1/hasPosition";\r
+        public static final String hasPosition_Inverse = "http://www.simantics.org/G3D-0.1/hasPosition/Inverse";\r
+        public static final String hasTransformation = "http://www.simantics.org/G3D-0.1/hasTransformation";\r
+        public static final String hasTransformation_Inverse = "http://www.simantics.org/G3D-0.1/hasTransformation/Inverse";\r
+        public static final String hasWorldOrientation = "http://www.simantics.org/G3D-0.1/hasWorldOrientation";\r
+        public static final String hasWorldOrientation_Inverse = "http://www.simantics.org/G3D-0.1/hasWorldOrientation/Inverse";\r
+        public static final String hasWorldPosition = "http://www.simantics.org/G3D-0.1/hasWorldPosition";\r
+        public static final String hasWorldPosition_Inverse = "http://www.simantics.org/G3D-0.1/hasWorldPosition/Inverse";\r
+        public static final String nodes = "http://www.simantics.org/G3D-0.1/nodes";\r
+        public static final String parent = "http://www.simantics.org/G3D-0.1/parent";\r
+        public static final String parentNode = "http://www.simantics.org/G3D-0.1/parentNode";\r
+        public static final String publishes = "http://www.simantics.org/G3D-0.1/publishes";\r
+        public static final String publishes_Inverse = "http://www.simantics.org/G3D-0.1/publishes/Inverse";\r
+    }\r
+    \r
+    public static Resource getResourceOrNull(ReadGraph graph, String uri) {\r
+        try {\r
+            return graph.getResource(uri);\r
+        } catch(DatabaseException e) {\r
+            System.err.println(e.getMessage());\r
+            return null;\r
+        }\r
+    }\r
+    \r
+    public G3D(ReadGraph graph) {\r
+        BaseNode = getResourceOrNull(graph, URIs.BaseNode);\r
+        Node = getResourceOrNull(graph, URIs.Node);\r
+        Orientation = getResourceOrNull(graph, URIs.Orientation);\r
+        Position = getResourceOrNull(graph, URIs.Position);\r
+        RootNode = getResourceOrNull(graph, URIs.RootNode);\r
+        Tuple3D = getResourceOrNull(graph, URIs.Tuple3D);\r
+        Tuple4D = getResourceOrNull(graph, URIs.Tuple4D);\r
+        children = getResourceOrNull(graph, URIs.children);\r
+        geometryDefinition = getResourceOrNull(graph, URIs.geometryDefinition);\r
+        geometryDefinitionOf = getResourceOrNull(graph, URIs.geometryDefinitionOf);\r
+        hasNodeProperty = getResourceOrNull(graph, URIs.hasNodeProperty);\r
+        hasNodeProperty_Inverse = getResourceOrNull(graph, URIs.hasNodeProperty_Inverse);\r
+        hasNonTransformation = getResourceOrNull(graph, URIs.hasNonTransformation);\r
+        hasNonTransformation_Inverse = getResourceOrNull(graph, URIs.hasNonTransformation_Inverse);\r
+        hasOrientation = getResourceOrNull(graph, URIs.hasOrientation);\r
+        hasOrientation_Inverse = getResourceOrNull(graph, URIs.hasOrientation_Inverse);\r
+        hasPosition = getResourceOrNull(graph, URIs.hasPosition);\r
+        hasPosition_Inverse = getResourceOrNull(graph, URIs.hasPosition_Inverse);\r
+        hasTransformation = getResourceOrNull(graph, URIs.hasTransformation);\r
+        hasTransformation_Inverse = getResourceOrNull(graph, URIs.hasTransformation_Inverse);\r
+        hasWorldOrientation = getResourceOrNull(graph, URIs.hasWorldOrientation);\r
+        hasWorldOrientation_Inverse = getResourceOrNull(graph, URIs.hasWorldOrientation_Inverse);\r
+        hasWorldPosition = getResourceOrNull(graph, URIs.hasWorldPosition);\r
+        hasWorldPosition_Inverse = getResourceOrNull(graph, URIs.hasWorldPosition_Inverse);\r
+        nodes = getResourceOrNull(graph, URIs.nodes);\r
+        parent = getResourceOrNull(graph, URIs.parent);\r
+        parentNode = getResourceOrNull(graph, URIs.parentNode);\r
+        publishes = getResourceOrNull(graph, URIs.publishes);\r
+        publishes_Inverse = getResourceOrNull(graph, URIs.publishes_Inverse);\r
+    }\r
+    \r
+    public static G3D getInstance(ReadGraph graph) {\r
+        Session session = graph.getSession();\r
+        G3D ret = session.peekService(G3D.class);\r
+        if(ret == null) {\r
+            QueryControl qc = graph.getService(QueryControl.class);\r
+            ret = new G3D(qc.getIndependentGraph(graph));\r
+            session.registerService(G3D.class, ret);\r
+        }\r
+        return ret;\r
+    }\r
+    \r
+    public static G3D getInstance(Session session) throws DatabaseException {\r
+        G3D ret = session.peekService(G3D.class);\r
+        if(ret == null) {\r
+            ret = session.syncRequest(new Read<G3D>() {\r
+                public G3D perform(ReadGraph graph) throws DatabaseException {\r
+                    QueryControl qc = graph.getService(QueryControl.class);\r
+                    return new G3D(qc.getIndependentGraph(graph));\r
+                }\r
+            });\r
+            session.registerService(G3D.class, ret);\r
+        }\r
+        return ret;\r
+    }\r
+    \r
+}\r
+\r
diff --git a/org.simantics.g3d.vtk/.classpath b/org.simantics.g3d.vtk/.classpath
new file mode 100644 (file)
index 0000000..8a8f166
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<classpath>\r
+       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>\r
+       <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>\r
+       <classpathentry kind="src" path="src"/>\r
+       <classpathentry kind="output" path="bin"/>\r
+</classpath>\r
diff --git a/org.simantics.g3d.vtk/.project b/org.simantics.g3d.vtk/.project
new file mode 100644 (file)
index 0000000..2940db6
--- /dev/null
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<projectDescription>\r
+       <name>org.simantics.g3d.vtk</name>\r
+       <comment></comment>\r
+       <projects>\r
+       </projects>\r
+       <buildSpec>\r
+               <buildCommand>\r
+                       <name>org.eclipse.jdt.core.javabuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+               <buildCommand>\r
+                       <name>org.eclipse.pde.ManifestBuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+               <buildCommand>\r
+                       <name>org.eclipse.pde.SchemaBuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+       </buildSpec>\r
+       <natures>\r
+               <nature>org.eclipse.pde.PluginNature</nature>\r
+               <nature>org.eclipse.jdt.core.javanature</nature>\r
+       </natures>\r
+</projectDescription>\r
diff --git a/org.simantics.g3d.vtk/.settings/org.eclipse.jdt.core.prefs b/org.simantics.g3d.vtk/.settings/org.eclipse.jdt.core.prefs
new file mode 100644 (file)
index 0000000..2bbbf69
--- /dev/null
@@ -0,0 +1,8 @@
+#Thu Mar 29 15:34:08 EEST 2012\r
+eclipse.preferences.version=1\r
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled\r
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6\r
+org.eclipse.jdt.core.compiler.compliance=1.6\r
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error\r
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error\r
+org.eclipse.jdt.core.compiler.source=1.6\r
diff --git a/org.simantics.g3d.vtk/META-INF/MANIFEST.MF b/org.simantics.g3d.vtk/META-INF/MANIFEST.MF
new file mode 100644 (file)
index 0000000..a375776
--- /dev/null
@@ -0,0 +1,29 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: G3D Vtk integration
+Bundle-SymbolicName: org.simantics.g3d.vtk;singleton:=true
+Bundle-Version: 1.0.0.qualifier
+Bundle-Activator: org.simantics.g3d.vtk.Activator
+Bundle-Vendor: VTT
+Require-Bundle: org.eclipse.core.runtime,
+ javax.vecmath;bundle-version="1.5.2",
+ org.simantics.g3d;bundle-version="1.0.0",
+ org.eclipse.ui;bundle-version="3.6.2",
+ org.simantics.db;bundle-version="1.1.0",
+ org.simantics.selectionview;bundle-version="1.0.0",
+ org.simantics.db.management;bundle-version="1.1.0",
+ org.eclipse.ui.views;bundle-version="3.5.1",
+ org.simantics.objmap2;bundle-version="1.0.0",
+ org.simantics.db.common;bundle-version="1.1.0",
+ org.simantics.g3d.ontology;bundle-version="1.0.0",
+ vtk;bundle-version="5.10.0",
+ org.simantics.utils.ui;bundle-version="1.1.0"
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6
+Bundle-ActivationPolicy: lazy
+Export-Package: org.simantics.g3d.vtk.action,
+ org.simantics.g3d.vtk.common,
+ org.simantics.g3d.vtk.gizmo,
+ org.simantics.g3d.vtk.handlers,
+ org.simantics.g3d.vtk.property,
+ org.simantics.g3d.vtk.shape,
+ org.simantics.g3d.vtk.utils
diff --git a/org.simantics.g3d.vtk/build.properties b/org.simantics.g3d.vtk/build.properties
new file mode 100644 (file)
index 0000000..6f20375
--- /dev/null
@@ -0,0 +1,5 @@
+source.. = src/\r
+output.. = bin/\r
+bin.includes = META-INF/,\\r
+               .,\\r
+               plugin.xml\r
diff --git a/org.simantics.g3d.vtk/plugin.xml b/org.simantics.g3d.vtk/plugin.xml
new file mode 100644 (file)
index 0000000..28e65b6
--- /dev/null
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<?eclipse version="3.4"?>\r
+<plugin>\r
+   <extension\r
+         point="org.eclipse.ui.preferencePages">\r
+      <page\r
+            class="org.simantics.g3d.vtk.preferences.VTKPreferencePage"\r
+            id="org.simantics.g3d.vtk.preferences.VTKPreferencePage"\r
+            name="VTK Preferences">\r
+      </page>\r
+   </extension>\r
+   <extension\r
+         point="org.eclipse.core.runtime.preferences">\r
+      <initializer\r
+            class="org.simantics.g3d.vtk.preferences.PreferenceInitializer">\r
+      </initializer>\r
+   </extension>\r
+   <extension\r
+         point="org.eclipse.ui.commands">\r
+   </extension>\r
+\r
+</plugin>\r
diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/Activator.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/Activator.java
new file mode 100644 (file)
index 0000000..c827085
--- /dev/null
@@ -0,0 +1,40 @@
+package org.simantics.g3d.vtk;\r
+\r
+import org.eclipse.ui.plugin.AbstractUIPlugin;\r
+import org.osgi.framework.BundleContext;\r
+\r
+public class Activator extends AbstractUIPlugin  {\r
+\r
+       public static final String PLUGIN_ID = "org.simantics.g3d.vtk"; //$NON-NLS-1$\r
+       \r
+       private static Activator plugin;\r
+       \r
+       \r
+       /*\r
+        * (non-Javadoc)\r
+        * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)\r
+        */\r
+       public void start(BundleContext context) throws Exception {\r
+               super.start(context);\r
+               plugin = this;\r
+       }\r
+\r
+       /*\r
+        * (non-Javadoc)\r
+        * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)\r
+        */\r
+       public void stop(BundleContext context) throws Exception {\r
+               plugin = null;\r
+               super.stop(context);\r
+       }\r
+\r
+       /**\r
+        * Returns the shared instance\r
+        *\r
+        * @return the shared instance\r
+        */\r
+       public static Activator getDefault() {\r
+               return plugin;\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/action/RemoveAction.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/action/RemoveAction.java
new file mode 100644 (file)
index 0000000..9bbce07
--- /dev/null
@@ -0,0 +1,42 @@
+package org.simantics.g3d.vtk.action;\r
+\r
+import org.eclipse.jface.action.Action;\r
+import org.simantics.g3d.scenegraph.IG3DNode;\r
+import org.simantics.g3d.scenegraph.structural.IStructuralNode;\r
+import org.simantics.g3d.vtk.Activator;\r
+import org.simantics.g3d.vtk.common.VTKNodeMap;\r
+\r
+public class RemoveAction extends Action {\r
+\r
+       private VTKNodeMap nodeMap;\r
+       protected IG3DNode node;\r
+       \r
+       public RemoveAction(VTKNodeMap nodeMap) {\r
+               setText("Remove");\r
+               setImageDescriptor(Activator.imageDescriptorFromPlugin("com.famfamfam.silk", "icons/delete.png"));\r
+               this.nodeMap = nodeMap;\r
+       }\r
+       \r
+       public void setNode(IG3DNode node) {\r
+               this.node = node;\r
+               setEnabled(isRemovable(node));\r
+       }\r
+       \r
+       public boolean isRemovable(IG3DNode node) {\r
+               if ((node instanceof IStructuralNode) && ((IStructuralNode)node).isPartOfInstantiatedModel() && !((IStructuralNode)node).isInstantiatedModelRoot())\r
+                       return false;\r
+               return true;\r
+       }\r
+       \r
+       @Override\r
+       public void run() {\r
+               \r
+               doRemove(node);\r
+               nodeMap.commit();\r
+               node = null;\r
+       }\r
+       \r
+       protected void doRemove(IG3DNode node) {\r
+               node.remove();\r
+       }\r
+}\r
diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/action/RotateAction.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/action/RotateAction.java
new file mode 100644 (file)
index 0000000..b2752c4
--- /dev/null
@@ -0,0 +1,647 @@
+package org.simantics.g3d.vtk.action;\r
+\r
+import java.awt.Cursor;\r
+import java.awt.event.KeyEvent;\r
+import java.awt.event.MouseEvent;\r
+\r
+import javax.vecmath.AxisAngle4d;\r
+import javax.vecmath.Point3d;\r
+import javax.vecmath.Quat4d;\r
+import javax.vecmath.Vector3d;\r
+\r
+import org.simantics.g3d.math.EulerTools;\r
+import org.simantics.g3d.math.MathTools;\r
+import org.simantics.g3d.math.Ray;\r
+import org.simantics.g3d.math.EulerTools.Order;\r
+import org.simantics.g3d.preferences.PreferenceConstants;\r
+import org.simantics.g3d.scenegraph.IG3DNode;\r
+import org.simantics.g3d.scenegraph.structural.IStructuralNode;\r
+import org.simantics.g3d.vtk.Activator;\r
+import org.simantics.g3d.vtk.common.InteractiveVtkPanel;\r
+import org.simantics.g3d.vtk.common.VTKNodeMap;\r
+import org.simantics.g3d.vtk.gizmo.RotateAxisGizmo;\r
+import org.simantics.g3d.vtk.utils.vtkUtil;\r
+import org.simantics.utils.threads.AWTThread;\r
+import org.simantics.utils.threads.ThreadUtils;\r
+\r
+import vtk.vtkProp;\r
+/**\r
+ * FIXME: complete rewrite.\r
+ * \r
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>\r
+ *\r
+ */\r
+public class RotateAction extends vtkAction{\r
+       \r
+       public static final int X = 0;\r
+    public static final int Y = 1;\r
+    public static final int Z = 2;\r
+    public static final int P = 3;\r
+\r
+       private VTKNodeMap nodeMap;\r
+       //private TranslateGizmo  gizmo = new TranslateGizmo();\r
+       private RotateAxisGizmo gizmo = new RotateAxisGizmo();\r
+       private IG3DNode node;\r
+       \r
+       \r
+       \r
+       private Cursor activeCursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);\r
+       private Cursor dragCursor = Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR);\r
+       \r
+       \r
+       int stepMethod = 1;\r
+       Order order = Order.YXZ;\r
+       \r
+    private int steps; \r
+    private double angles[];\r
+       \r
+       int index = P;\r
+       boolean valid = false;\r
+       private boolean worldCoord = true;\r
+       //private AxisAngle4d aa = null;\r
+       private Quat4d parentWorldOrientation = null;\r
+       \r
+       //AxisAngle4d rotation = new AxisAngle4d();\r
+       Quat4d worldOrientation = new Quat4d();\r
+       \r
+       public void setNode(IG3DNode node) {\r
+               this.node = node;\r
+               if ((node instanceof IStructuralNode) && ((IStructuralNode)node).isPartOfInstantiatedModel() && !((IStructuralNode)node).isInstantiatedModelRoot()) {\r
+                       setEnabled(false);\r
+               } else {\r
+                       setEnabled(true);\r
+               }\r
+               \r
+               String set = org.simantics.g3d.Activator.getDefault().getPreferenceStore().getString(PreferenceConstants.ORIENTATION_PRESENTATION);\r
+               if (set.equals("aa")) {\r
+                       stepMethod = 0;\r
+               } else if (set.equals("euler")){\r
+                       stepMethod = 1;\r
+                       String eulerOrder = org.simantics.g3d.Activator.getDefault().getPreferenceStore().getString(PreferenceConstants.EULER_ANGLE_ORDER);\r
+                       try {\r
+                               order = Order.valueOf(eulerOrder);\r
+                       } catch (Exception e) {\r
+                               order = Order.YXZ;\r
+                       }\r
+               } else {\r
+                       stepMethod = 2;\r
+               }\r
+       }\r
+       \r
+       public IG3DNode getNode() {\r
+               return node;\r
+       }\r
+       \r
+       public RotateAction(InteractiveVtkPanel panel, VTKNodeMap nodeMap) {\r
+               super(panel);\r
+               setImageDescriptor(Activator.imageDescriptorFromPlugin("com.famfamfam.silk", "icons/arrow_rotate_clockwise.png"));\r
+               setText("Rotate");\r
+               this.nodeMap = nodeMap;\r
+               \r
+               \r
+               steps = 36;\r
+        angles = new double[steps+1];\r
+        for (int i = 0; i < angles.length; i++) {\r
+            angles[i] = - Math.PI + (Math.PI * i * 2.0 / steps);\r
+        }\r
+       }\r
+       \r
+       public void attach() {\r
+               if (node == null)\r
+                       return;\r
+               \r
+               super.attach();\r
+               ThreadUtils.asyncExec(AWTThread.getThreadAccess(), new Runnable() {\r
+                       public void run() {\r
+                               attachUI();\r
+                               update();\r
+                       }\r
+               });\r
+               \r
+               \r
+               \r
+       }\r
+       \r
+       public void deattach() {\r
+               \r
+               node = null;\r
+               nodeMap.commit();\r
+               deattachUI();\r
+               super.deattach();\r
+               panel.repaint();\r
+       }\r
+       \r
+       private void attachUI() {\r
+               panel.setCursor(activeCursor);\r
+               gizmo.attach(panel.GetRenderer());\r
+       }\r
+       \r
+       private void deattachUI() {\r
+               panel.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));\r
+               gizmo.deattach();\r
+       }\r
+       \r
+       @Override\r
+       public void keyPressed(KeyEvent e) {\r
+               if (e.getKeyCode() == KeyEvent.VK_ESCAPE)\r
+                       panel.useDefaultAction();\r
+               if (valid)\r
+                       return;\r
+               if (e.getKeyCode() == KeyEvent.VK_X) {\r
+                       if (index != X)\r
+                               index = X;\r
+                       else\r
+                               index = P;\r
+               }\r
+               if (e.getKeyCode() == KeyEvent.VK_Y) {\r
+                       if (index != Y)\r
+                               index = Y;\r
+                       else\r
+                               index = P;\r
+               }\r
+               if (e.getKeyCode() == KeyEvent.VK_Z) {\r
+                       if (index != Z)\r
+                               index = Z;\r
+                       else\r
+                               index = P;\r
+               }\r
+               if (e.getKeyCode() == KeyEvent.VK_G) {\r
+                       worldCoord = !worldCoord;\r
+               }\r
+               gizmo.setType(index);\r
+               panel.repaint();\r
+       }\r
+       \r
+       @Override\r
+       public void keyReleased(KeyEvent e) {\r
+               \r
+       }\r
+       \r
+       \r
+       \r
+       @Override\r
+       public void mouseClicked(MouseEvent e) {\r
+               if (e.getClickCount() > 1) {\r
+                       if (isOverNode(e)) {\r
+                               return;\r
+                       }\r
+                       panel.useDefaultAction();\r
+                       //if(!gizmo.isPartOf(actor))\r
+                       //      panel.useDefaultAction();\r
+                       \r
+               }\r
+       }\r
+       \r
+       @Override\r
+       public void mouseEntered(MouseEvent e) {\r
+               \r
+       }\r
+       \r
+       @Override\r
+       public void mouseExited(MouseEvent e) {\r
+               \r
+       }\r
+       \r
+       \r
+\r
+       \r
+       \r
+       public void setWorldCoord(boolean b) {\r
+               if (worldCoord == b)\r
+                       return;\r
+               worldCoord = b;\r
+               update();\r
+                                       \r
+       }\r
+       \r
+       \r
+       private void update() {\r
+               Vector3d nodePos = node.getWorldPosition();\r
+               System.out.println(nodePos);\r
+               gizmo.setPosition(nodePos);\r
+               if (worldCoord) {\r
+                       gizmo.setRotation(new AxisAngle4d());\r
+                       parentWorldOrientation = null;\r
+               } else {\r
+                       AxisAngle4d aa = new AxisAngle4d();\r
+                       parentWorldOrientation = ((IG3DNode)node.getParent()).getWorldOrientation();\r
+                       aa.set(parentWorldOrientation);\r
+                       gizmo.setRotation(aa);\r
+               }\r
+\r
+               Point3d camPos = new Point3d(panel.GetRenderer().GetActiveCamera().GetPosition());\r
+               Vector3d p = new Vector3d(nodePos);\r
+               p.sub(camPos);\r
+               \r
+               if (parentWorldOrientation != null) {\r
+                       Quat4d qi = new Quat4d(parentWorldOrientation);\r
+                       qi.inverse();\r
+                       MathTools.rotate(parentWorldOrientation, p, p);\r
+               }\r
+               if (panel.GetRenderer().GetActiveCamera().GetParallelProjection() == 0) {\r
+                       double distance = p.length();\r
+                       p.negate();\r
+            double fov = panel.GetRenderer().GetActiveCamera().GetViewAngle();\r
+            float s = (float) (Math.sin(fov) * distance * 0.1); \r
+\r
+            Vector3d scale = new Vector3d(1., 1., 1.);\r
+            \r
+//            if (p.x > 0.f)\r
+//                scale.x = -1.;\r
+//            if (p.y > 0.f)\r
+//                scale.y = -1.;\r
+//            if (p.z > 0.f)\r
+//                scale.z = -1.;\r
+            scale.scale(s);\r
+            gizmo.setScale(scale);\r
+                       \r
+               } else {\r
+                       Vector3d scale = new Vector3d(1.f, 1.f, 1.f);\r
+            double s = panel.GetRenderer().GetActiveCamera().GetParallelScale() / 5.;\r
+//            if (p.x > 0.f)\r
+//                scale.x = -1.;\r
+//            if (p.y > 0.f)\r
+//                scale.y = -1.;\r
+//            if (p.z > 0.f)\r
+//                scale.z = -1.;\r
+            scale.scale(s);\r
+            gizmo.setScale(scale);\r
+               }\r
+               \r
+               panel.Render();\r
+       }\r
+       \r
+       private boolean isOverNode(MouseEvent e) {\r
+               vtkProp picked[] = panel.pick(e.getX(), e.getY());\r
+               if (picked !=null) {\r
+                       for (int i = 0; i < picked.length; i++) {\r
+                               if (node.equals(nodeMap.getNode(picked[i])))\r
+                                       return true;\r
+                       }\r
+               }\r
+               return false;\r
+       }\r
+       \r
+\r
+       \r
+       @Override\r
+       public void mousePressed(MouseEvent e) {\r
+               if (e.getButton() == MouseEvent.BUTTON1) {\r
+       \r
+       \r
+                       if (isOverNode(e)) {\r
+                               valid = true;\r
+                               if ((e.getModifiers() & MouseEvent.CTRL_MASK) > 0) {\r
+                                       useStep = true;\r
+                   } else {\r
+                       useStep = false;\r
+                   }\r
+                               worldOrientation = node.getWorldOrientation();\r
+                               doChanges(true, e.getX(), e.getY());\r
+                               \r
+                               panel.setCursor(dragCursor);\r
+                       } else {\r
+                               valid = false;\r
+                               panel.getDefaultAction().mousePressed(e);\r
+                               panel.setCursor(activeCursor);\r
+                       }\r
+               } else {\r
+                       panel.getDefaultAction().mousePressed(e);\r
+               }\r
+       }\r
+       \r
+       \r
+       \r
+       @Override\r
+       public void mouseReleased(MouseEvent e) {\r
+               if (e.getButton() == MouseEvent.BUTTON1) {\r
+                       valid = false;\r
+                       worldOrientation = null;\r
+                       panel.setCursor(activeCursor);\r
+               } else {\r
+                       panel.getDefaultAction().mouseReleased(e);\r
+               }\r
+       }\r
+       \r
+       @Override\r
+       public void mouseDragged(MouseEvent e) {\r
+               if ((e.getModifiersEx() & MouseEvent.BUTTON1_DOWN_MASK) > 0 && valid) { \r
+                       if ((e.getModifiers() & MouseEvent.CTRL_MASK) > 0) {\r
+                               useStep = true;\r
+            } else {\r
+                useStep = false;\r
+            }\r
+                       doChanges(false, e.getX(), e.getY());\r
+                       \r
+                       //nodeMap.modified(node);\r
+                       update();\r
+               } else {\r
+                       panel.getDefaultAction().mouseDragged(e);\r
+                       update();\r
+               }\r
+       }\r
+       \r
+        Vector3d axis = null;\r
+       \r
+       @Override\r
+       public void keyTyped(KeyEvent e) {\r
+                if (e.getKeyCode() == KeyEvent.VK_LEFT) {\r
+               inputType = InputType.KEY;\r
+               axis = new Vector3d(0.0,1.0,0.0);\r
+            } else if (e.getKeyCode() == KeyEvent.VK_RIGHT) {\r
+                       inputType = InputType.KEY;\r
+                       axis = new Vector3d(0.0,-1.0,0.0);\r
+            } else if (e.getKeyCode() ==KeyEvent.VK_UP) {\r
+                       inputType = InputType.KEY;\r
+                       axis = new Vector3d(1.0,0.0,0.0);\r
+            } else if (e.getKeyCode() == KeyEvent.VK_DOWN) {\r
+                       inputType = InputType.KEY;\r
+                       axis = new Vector3d(-1.0,0.0,0.0);\r
+            } \r
+       }\r
+       \r
+    public void doChanges(boolean pressed, int x, int y) {\r
+       Ray ray = vtkUtil.createMouseRay(panel.GetRenderer(),x, y);\r
+       Vector3d p = node.getWorldPosition();\r
+        \r
+       if (pressed) {\r
+            Vector3d axis = getRotationAxis();\r
+            if (axis != null) {\r
+               if (!worldCoord) {\r
+                       MathTools.rotate(parentWorldOrientation, axis, axis);\r
+               }\r
+\r
+               \r
+                double s[] = new double[2];\r
+                Vector3d i2 = new Vector3d();\r
+               \r
+                boolean intersect = MathTools.intersectStraightPlane(ray.pos, ray.dir, p, axis, i2, s);\r
+                double dot = Math.abs(ray.dir.dot(axis));\r
+                if (intersect &&  dot > 0.4)\r
+                       inputType = InputType.INTERSECT;\r
+                else\r
+                       inputType = InputType.NONINTERSECT;\r
+                       \r
+                \r
+                if (inputType == InputType.INTERSECT) {\r
+                    // picking ray and plane defined by gizmo's center point and\r
+                    // rotation axis can intersect\r
+                    // vector from center point to intersection point\r
+                    i2.sub(p);\r
+                    // creating vectors i and j that are lying on the plane and\r
+                    // are perpendicular\r
+                    // vectors are used to calculate polar coordinate for\r
+                    // intersection point\r
+                    j.set(i2);\r
+                    i.cross(j, axis);\r
+                    System.out.println("I,J " + i + " " + j);\r
+                    double angleI = i2.angle(i);\r
+                    double angleJ = i2.angle(j);\r
+                    prevAngle = Math.atan2(Math.cos(angleJ), Math.cos(angleI));\r
+                } else {\r
+                    // picking ray and plane defined by gizmo's center point and\r
+                    // rotation axis are parallel,\r
+                    // so we'll use cross product of rotation axis and picking\r
+                    // ray to detect amount of rotation\r
+                    i.cross(ray.dir, axis);\r
+                    MathTools.intersectStraightStraight(ray.pos, ray.dir, p, i, new Vector3d(), new Vector3d(), s);\r
+                    prevS = s[1];\r
+                }\r
+            }\r
+           \r
+            \r
+        }\r
+\r
+        if (inputType != InputType.KEY)\r
+               axis = getRotationAxis();\r
+        if (axis == null) {\r
+            return;   \r
+        }\r
+        Vector3d taxis = null;\r
+        if (!worldCoord) {\r
+               taxis = new Vector3d(axis);\r
+               MathTools.rotate(parentWorldOrientation, axis, axis);\r
+       }\r
+        System.out.println(inputType);\r
+        if (inputType == InputType.INTERSECT) {\r
+\r
+            double s[] = new double[2];\r
+            Vector3d i2 = new Vector3d();\r
+            MathTools.intersectStraightPlane(ray.pos, ray.dir, p, axis, i2, s);\r
+            i2.sub(p);\r
+            double angleI = i2.angle(i);\r
+            double angleJ = i2.angle(j);\r
+            double angle = Math.atan2(Math.cos(angleJ), Math.cos(angleI));\r
+            System.out.println("Angle " + angle + " i " + angleI + " j " + angleJ + " prev " + prevAngle);\r
+            if(!worldCoord)\r
+               axis = taxis;\r
+            if (useStep) {\r
+\r
+               //setOrientation(MathTools.getQuat(rotation));\r
+               AxisAngle4d rot = new AxisAngle4d(axis,angle-prevAngle);\r
+               Quat4d qrot = new Quat4d();\r
+               MathTools.getQuat(rot, qrot);\r
+               //prevAngle = angle;\r
+               qrot.mulInverse(worldOrientation);\r
+               \r
+          \r
+               if (stepMethod == 0) {\r
+                       rot.set(qrot);\r
+                       rot.angle = roundAngle(rot.angle);\r
+                       //qrot.set(rot);\r
+                       MathTools.getQuat(rot,qrot);\r
+                       setOrientation(qrot);\r
+               } else if (stepMethod == 1){\r
+                         \r
+                       //Vector3d euler = MathTools.getEuler(qrot);\r
+                       Vector3d euler = EulerTools.getEulerFromQuat(order, qrot);\r
+                       euler.x = roundAngle(euler.x);\r
+                       euler.y = roundAngle(euler.y);\r
+                       euler.z = roundAngle(euler.z);\r
+                       //Quat4d q = MathTools.getQuat(euler);\r
+                       Quat4d q = EulerTools.getQuatFromEuler(order, euler);\r
+                       setOrientation(q);\r
+                       System.out.println(" (" + MathTools.radToDeg(euler.x) + " " + MathTools.radToDeg(euler.y) + " " + MathTools.radToDeg(euler.z) +  ") " + qrot + " "+ q);\r
+               } else {\r
+                       setOrientation(qrot);\r
+               }\r
+               \r
+            } else {\r
+                if (worldCoord) {\r
+                       //G3DTools.multiplyOrientation(mo.getG3DNode(graph).getWorldOrientation(), new AxisAngle4d(axis,angle-prevAngle));\r
+                       AxisAngle4d aa = MathTools.getAxisAngle(node.getWorldOrientation());\r
+                       AxisAngle4d rot = new AxisAngle4d(axis,angle-prevAngle);\r
+                       MathTools.multiplyOrientation(aa, rot);\r
+                       setWorldOrientation(MathTools.getQuat(rot));\r
+                } else {\r
+                       AxisAngle4d aa = MathTools.getAxisAngle(node.getOrientation());\r
+                       AxisAngle4d rot = new AxisAngle4d(axis,angle-prevAngle);\r
+                       MathTools.multiplyOrientation(aa, rot);\r
+                       setOrientation(MathTools.getQuat(rot));\r
+                       //G3DTools.multiplyOrientation(mo.getG3DNode(graph).getLocalOrientation(), new AxisAngle4d(axis,angle-prevAngle));\r
+                }\r
+                prevAngle = angle;\r
+            }\r
+            \r
+        } else if (inputType == InputType.NONINTERSECT){\r
+\r
+            double s[] = new double[2];\r
+            MathTools.intersectStraightStraight(ray.pos, ray.dir, p, i, new Vector3d(), new Vector3d(), s);\r
+            if(!worldCoord)\r
+               axis = taxis;\r
+            if (useStep) {\r
+               //setOrientation(MathTools.getQuat(rotation));\r
+               AxisAngle4d rot = new AxisAngle4d(axis,s[1] - prevS);\r
+                \r
+               Quat4d qrot = new Quat4d();\r
+               //qrot.set(rot);\r
+               MathTools.getQuat(rot, qrot);\r
+               //prevAngle = angle;\r
+               qrot.mulInverse(worldOrientation);\r
+               \r
+          \r
+               if (stepMethod == 0) {\r
+                       rot.set(qrot);\r
+                       rot.angle = roundAngle(rot.angle);\r
+                       //qrot.set(rot);\r
+                       MathTools.getQuat(rot,qrot);\r
+                       setOrientation(qrot);\r
+               } else if (stepMethod == 1){\r
+                         \r
+                       //Vector3d euler = MathTools.getEuler(qrot);\r
+                       Vector3d euler = EulerTools.getEulerFromQuat(order, qrot);\r
+                       euler.x = roundAngle(euler.x);\r
+                       euler.y = roundAngle(euler.y);\r
+                       euler.z = roundAngle(euler.z);\r
+                       //Quat4d q = MathTools.getQuat(euler);\r
+                       Quat4d q = EulerTools.getQuatFromEuler(order, euler);\r
+                       setOrientation(q);\r
+                       System.out.println(" (" + MathTools.radToDeg(euler.x) + " " + MathTools.radToDeg(euler.y) + " " + MathTools.radToDeg(euler.z) +  ") " + qrot + " "+ q);\r
+               } else {\r
+                       setOrientation(qrot);\r
+               }\r
+                prevS = s[1];\r
+               \r
+//                    G3DTools.setOrientation(mo.getG3DNode(graph).getLocalOrientation(), rotations.get(mo));\r
+//                    G3DTools.multiplyOrientation(mo.getG3DNode(graph).getWorldOrientation(), new AxisAngle4d(axis,s[1] - prevS));\r
+//                    AxisAngle4d aa = G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation());\r
+//                    rotations.put(mo, aa);\r
+//                    Vector3d euler = MathTools.getEuler(aa);\r
+//                    euler.x = roundAngle(euler.x);\r
+//                    euler.y = roundAngle(euler.y);\r
+//                    euler.z = roundAngle(euler.z);\r
+//                    aa = MathTools.getFromEuler2(euler);\r
+//                    prevS = s[1];\r
+//                    G3DTools.setOrientation(mo.getG3DNode(graph).getLocalOrientation(), aa);\r
+//                    Vector3d e = MathTools.getEuler(G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation()));\r
+//                    e.scale(180.0/Math.PI);\r
+//                    text += G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation()) + " " + e + " ";\r
+               \r
+               \r
+            } else {\r
+                       if (worldCoord) {\r
+                               AxisAngle4d aa =  MathTools.getAxisAngle(node.getWorldOrientation());\r
+                       AxisAngle4d rot = new AxisAngle4d(axis,s[1] - prevS);\r
+                       MathTools.multiplyOrientation(aa, rot);\r
+                       setWorldOrientation(MathTools.getQuat(rot));\r
+                               //G3DTools.multiplyOrientation(mo.getG3DNode(graph).getWorldOrientation(), new AxisAngle4d(axis,s[1] - prevS));\r
+                       } else {\r
+                               AxisAngle4d aa =  MathTools.getAxisAngle(node.getOrientation());\r
+                       AxisAngle4d rot = new AxisAngle4d(axis,s[1] - prevS);\r
+                       MathTools.multiplyOrientation(aa, rot);\r
+                       setOrientation(MathTools.getQuat(rot));\r
+                               //G3DTools.multiplyOrientation(mo.getG3DNode(graph).getLocalOrientation(), new AxisAngle4d(axis,s[1] - prevS));\r
+                       }\r
+                       //text += G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation()) + " " + MathTools.getEuler(G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation())) + " ";\r
+                prevS = s[1];\r
+                \r
+            }\r
+           \r
+        } else {\r
+               if (worldCoord) {\r
+                       AxisAngle4d aa = MathTools.getAxisAngle(node.getWorldOrientation());\r
+               AxisAngle4d rot = new AxisAngle4d(axis,Math.PI * 0.5);\r
+               MathTools.multiplyOrientation(aa, rot);\r
+               setWorldOrientation(MathTools.getQuat(rot));\r
+                       //G3DTools.multiplyOrientation(mo.getG3DNode(graph).getWorldOrientation(), new AxisAngle4d(axis,Math.PI * 0.5));\r
+               } else {\r
+                       AxisAngle4d aa = MathTools.getAxisAngle(node.getOrientation());\r
+               AxisAngle4d rot = new AxisAngle4d(axis,Math.PI * 0.5);\r
+               MathTools.multiplyOrientation(aa, rot);\r
+               setOrientation(MathTools.getQuat(rot));\r
+                       //G3DTools.multiplyOrientation(mo.getG3DNode(graph).getLocalOrientation(), new AxisAngle4d(axis,Math.PI * 0.5));\r
+               }\r
+             //   text += G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation()) + " " + MathTools.getEuler(G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation())) + " ";\r
+            \r
+        }\r
+        //setInfoText(text);\r
\r
+    }\r
+    \r
+    protected void setOrientation(Quat4d q) {\r
+       node.setOrientation(q);\r
+    }\r
+    \r
+    protected void setWorldOrientation(Quat4d q) {\r
+       node.setWorldOrientation(q);\r
+    }\r
+       \r
+       @Override\r
+       public void mouseMoved(MouseEvent e) {\r
+               panel.getDefaultAction().mouseMoved(e);\r
+       }\r
+       \r
+       private Vector3d getRotationAxis() {\r
+               switch (index) {\r
+               case X:\r
+                       return new Vector3d(1.0, 0.0, 0.0);\r
+               case Y:\r
+                       return new Vector3d(0.0, 1.0, 0.0);\r
+               case Z:\r
+                       return new Vector3d(0.0, 0.0, 1.0);\r
+               case P:\r
+                       Vector3d axis = new Vector3d(panel.GetRenderer().GetActiveCamera()\r
+                                       .GetDirectionOfProjection());\r
+                       axis.normalize();\r
+                       return axis;\r
+               default:\r
+                       return null;\r
+               }\r
+       }\r
+       \r
+        private double prevS = 0.0;\r
+           \r
+    private Vector3d i = new Vector3d();\r
+    private Vector3d j = new Vector3d();\r
+    private double prevAngle = 0;\r
+\r
+    enum InputType{INTERSECT,NONINTERSECT,KEY,NONE};\r
+    InputType inputType;\r
+    private boolean useStep = false;\r
+    \r
+    \r
+    \r
+    private double roundAngle(double angle) {\r
+        while (angle < - Math.PI)\r
+            angle += Math.PI*2.0;\r
+        while (angle > Math.PI)\r
+            angle -= Math.PI*2.0;\r
+        \r
+        \r
+        int index = 0;\r
+        while (angle > angles[index])\r
+            index++;\r
+        if (index == 0) {\r
+            angle = angles[0];\r
+        } else {\r
+            double d = angle - angles[index - 1];\r
+            double d2 = angles[index] - angle;\r
+            if (d < d2)\r
+                angle = angles[index - 1];\r
+            else\r
+                angle = angles[index];\r
+        }\r
+        return angle;\r
+    }\r
+       \r
+}\r
diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/action/TranslateAction.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/action/TranslateAction.java
new file mode 100644 (file)
index 0000000..785e549
--- /dev/null
@@ -0,0 +1,475 @@
+package org.simantics.g3d.vtk.action;\r
+\r
+import java.awt.Cursor;\r
+import java.awt.event.KeyEvent;\r
+import java.awt.event.MouseEvent;\r
+import java.math.BigDecimal;\r
+\r
+import javax.vecmath.AxisAngle4d;\r
+import javax.vecmath.Point3d;\r
+import javax.vecmath.Quat4d;\r
+import javax.vecmath.Vector3d;\r
+\r
+import org.simantics.g3d.math.MathTools;\r
+import org.simantics.g3d.math.Ray;\r
+import org.simantics.g3d.scenegraph.IG3DNode;\r
+import org.simantics.g3d.scenegraph.structural.IStructuralNode;\r
+import org.simantics.g3d.vtk.Activator;\r
+import org.simantics.g3d.vtk.common.InteractiveVtkPanel;\r
+import org.simantics.g3d.vtk.common.VTKNodeMap;\r
+import org.simantics.g3d.vtk.gizmo.TranslateAxisGizmo;\r
+import org.simantics.g3d.vtk.utils.vtkUtil;\r
+import org.simantics.utils.threads.AWTThread;\r
+import org.simantics.utils.threads.ThreadUtils;\r
+\r
+import vtk.vtkProp;\r
+\r
+public class TranslateAction extends vtkAction{\r
+       \r
+       public static final int X = 0;\r
+    public static final int Y = 1;\r
+    public static final int Z = 2;\r
+    public static final int XY = 3;\r
+    public static final int XZ = 4;\r
+    public static final int YZ = 5;\r
+    public static final int P = 6;\r
+\r
+       private VTKNodeMap nodeMap;\r
+       //private TranslateGizmo  gizmo = new TranslateGizmo();\r
+       private TranslateAxisGizmo gizmo = new TranslateAxisGizmo();\r
+       private IG3DNode node;\r
+       \r
+       \r
+       \r
+       private Cursor activeCursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);\r
+       private Cursor dragCursor = Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR);\r
+       \r
+       public void setNode(IG3DNode node) {\r
+               this.node = node;\r
+               if ((node instanceof IStructuralNode) && ((IStructuralNode)node).isPartOfInstantiatedModel() && !((IStructuralNode)node).isInstantiatedModelRoot()) {\r
+                       setEnabled(false);\r
+               } else {\r
+                       setEnabled(true);\r
+               }\r
+       }\r
+       \r
+       public IG3DNode getNode() {\r
+               return node;\r
+       }\r
+       \r
+       public TranslateAction(InteractiveVtkPanel panel, VTKNodeMap nodeMap) {\r
+               super(panel);\r
+               setImageDescriptor(Activator.imageDescriptorFromPlugin("com.famfamfam.silk", "icons/arrow_out.png"));\r
+               setText("Translate");\r
+               this.nodeMap = nodeMap;\r
+       }\r
+       \r
+       public void attach() {\r
+               if (node == null)\r
+                       return;\r
+               \r
+               super.attach();\r
+               ThreadUtils.asyncExec(AWTThread.getThreadAccess(), new Runnable() {\r
+                       public void run() {\r
+                               attachUI();\r
+                               update();\r
+                       }\r
+               });\r
+               \r
+               \r
+               \r
+       }\r
+       \r
+       public void deattach() {\r
+               \r
+               node = null;\r
+               nodeMap.commit();\r
+               deattachUI();\r
+               super.deattach();\r
+               panel.repaint();\r
+       }\r
+       \r
+       private void attachUI() {\r
+               panel.setCursor(activeCursor);\r
+               gizmo.attach(panel.GetRenderer());\r
+       }\r
+       \r
+       private void deattachUI() {\r
+               panel.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));\r
+               gizmo.deattach();\r
+       }\r
+       \r
+       @Override\r
+       public void keyPressed(KeyEvent e) {\r
+               if (e.getKeyCode() == KeyEvent.VK_ESCAPE)\r
+                       panel.useDefaultAction();\r
+               if (valid)\r
+                       return;\r
+               if (e.getKeyCode() == KeyEvent.VK_X) {\r
+                       if (index != X)\r
+                               index = X;\r
+                       else\r
+                               index = P;\r
+               }\r
+               if (e.getKeyCode() == KeyEvent.VK_Y) {\r
+                       if (index != Y)\r
+                               index = Y;\r
+                       else\r
+                               index = P;\r
+               }\r
+               if (e.getKeyCode() == KeyEvent.VK_Z) {\r
+                       if (index != Z)\r
+                               index = Z;\r
+                       else\r
+                               index = P;\r
+               }\r
+               if (e.getKeyCode() == KeyEvent.VK_G) {\r
+                       worldCoord = !worldCoord;\r
+               }\r
+               gizmo.setType(index);\r
+               \r
+               update();\r
+               //panel.repaint();\r
+       }\r
+       \r
+       @Override\r
+       public void keyReleased(KeyEvent e) {\r
+               \r
+       }\r
+       \r
+       @Override\r
+       public void keyTyped(KeyEvent e) {\r
+               \r
+       }\r
+       \r
+       @Override\r
+       public void mouseClicked(MouseEvent e) {\r
+               if (e.getClickCount() > 1) {\r
+                       if (isOverNode(e)) {\r
+                               return;\r
+                       } else {\r
+                               panel.useDefaultAction();\r
+                       }\r
+                       //if(!gizmo.isPartOf(actor))\r
+                       //      panel.useDefaultAction();\r
+                       \r
+               }\r
+       }\r
+       \r
+       private boolean isOverNode(MouseEvent e) {\r
+               vtkProp picked[] = panel.pick(e.getX(), e.getY());\r
+               if (picked !=null) {\r
+                       for (int i = 0; i < picked.length; i++) {\r
+                               if (node.equals(nodeMap.getNode(picked[i])))\r
+                                       return true;\r
+                       }\r
+               }\r
+               return false;\r
+       }\r
+       \r
+       @Override\r
+       public void mouseEntered(MouseEvent e) {\r
+               \r
+       }\r
+       \r
+       @Override\r
+       public void mouseExited(MouseEvent e) {\r
+               \r
+       }\r
+       \r
+       int index = P;\r
+       boolean valid = false;\r
+       private boolean worldCoord = true;\r
+       private AxisAngle4d aa = null;\r
+       private Quat4d q = null;\r
+       \r
+       \r
+       public void setWorldCoord(boolean b) {\r
+               if (worldCoord == b)\r
+                       return;\r
+               worldCoord = b;\r
+               update();\r
+                                       \r
+       }\r
+       \r
+       \r
+       private void update() {\r
+               if (node == null)\r
+                       return;\r
+               if (worldCoord) {\r
+                       gizmo.setRotation(new AxisAngle4d());\r
+                       aa = null;\r
+                       q = null;\r
+               } else {\r
+                       aa = new AxisAngle4d();\r
+                       aa.set(((IG3DNode)node.getParent()).getWorldOrientation());\r
+                       gizmo.setRotation(aa);\r
+                       q = new Quat4d();\r
+                       MathTools.getQuat(aa, q);\r
+               }\r
+               \r
+               Vector3d nodePos = node.getWorldPosition();\r
+               //System.out.println(nodePos);\r
+               gizmo.setPosition(nodePos);\r
+\r
+               \r
+               Point3d camPos = new Point3d(panel.GetRenderer().GetActiveCamera().GetPosition());\r
+               Vector3d p = new Vector3d(nodePos);\r
+               p.sub(camPos);\r
+               \r
+               if (q != null) {\r
+                       Quat4d qi = new Quat4d(q);\r
+                       qi.inverse();\r
+                       MathTools.rotate(q, p, p);\r
+               }\r
+               if (panel.GetRenderer().GetActiveCamera().GetParallelProjection() == 0) {\r
+                       double distance = p.length();\r
+                       p.negate();\r
+            double fov = panel.GetRenderer().GetActiveCamera().GetViewAngle();\r
+            float s = (float) (Math.sin(fov) * distance * 0.1); \r
+\r
+            Vector3d scale = new Vector3d(1., 1., 1.);\r
+            \r
+//            if (p.x > 0.f)\r
+//                scale.x = -1.;\r
+//            if (p.y > 0.f)\r
+//                scale.y = -1.;\r
+//            if (p.z > 0.f)\r
+//                scale.z = -1.;\r
+            scale.scale(s);\r
+            gizmo.setScale(scale);\r
+                       \r
+               } else {\r
+                       Vector3d scale = new Vector3d(1.f, 1.f, 1.f);\r
+            double s = panel.GetRenderer().GetActiveCamera().GetParallelScale() / 5.;\r
+//            if (p.x > 0.f)\r
+//                scale.x = -1.;\r
+//            if (p.y > 0.f)\r
+//                scale.y = -1.;\r
+//            if (p.z > 0.f)\r
+//                scale.z = -1.;\r
+            scale.scale(s);\r
+            gizmo.setScale(scale);\r
+               }\r
+               \r
+               //panel.Render();\r
+               panel.repaint();\r
+       }\r
+       \r
+       Vector3d prevTranslate = null;\r
+       \r
+       @Override\r
+       public void mousePressed(MouseEvent e) {\r
+               if (e.getButton() == MouseEvent.BUTTON1) {\r
+\r
+                       if (isOverNode(e)) {\r
+                               prevTranslate = getTranslate(e.getX(), e.getY());\r
+                               valid = true;\r
+                               panel.setCursor(dragCursor);\r
+                       } else {\r
+                               valid = false;\r
+                               panel.getDefaultAction().mousePressed(e);\r
+                               panel.setCursor(activeCursor);\r
+                       }\r
+               } else {\r
+                       panel.getDefaultAction().mousePressed(e);\r
+               }\r
+               //index = gizmo.getTranslateAxis(actor);\r
+               //if (index == -1) {\r
+               //  valid = false;\r
+               //      panel.getDefaultAction().mousePressed(e);\r
+               //      return;\r
+               //}\r
+               //valid = true; \r
+               //prevTranslate = getTranslate(e.getX(), e.getY());\r
+               //System.out.println("start translate " + prevTranslate);\r
+       }\r
+       \r
+       \r
+       \r
+       @Override\r
+       public void mouseReleased(MouseEvent e) {\r
+               if (e.getButton() == MouseEvent.BUTTON1) {\r
+                       valid = false;\r
+                       prevTranslate = null;\r
+                       panel.setCursor(activeCursor);\r
+               } else {\r
+                       panel.getDefaultAction().mouseReleased(e);\r
+               }\r
+       }\r
+       \r
+       @Override\r
+       public void mouseDragged(MouseEvent e) {\r
+               if ((e.getModifiersEx() & MouseEvent.BUTTON1_DOWN_MASK) > 0 && valid) { \r
+                       \r
+                       Vector3d translate = getTranslate(e.getX(), e.getY(), prevTranslate);\r
+                       //System.out.println("translate " + translate);\r
+                       if (translate == null)\r
+                               return;\r
+                       boolean step = ((e.getModifiers() & MouseEvent.CTRL_MASK) > 0);\r
+                       if (worldCoord) {\r
+                               Vector3d pos = new Vector3d(node.getWorldPosition());\r
+                               pos.add(translate);\r
+                               pos = constaints(pos, step);\r
+                               setWorldPos(pos);\r
+                       } else {\r
+                               Vector3d pos = new Vector3d(node.getPosition());\r
+                               pos.add(translate);\r
+                               pos = constaints(pos, step);\r
+                               setPos(pos);\r
+                       }\r
+                       //mapping.rangeModified(node);\r
+                       \r
+                       //nodeMap.modified(node);\r
+                       update();\r
+               } else {\r
+                       panel.getDefaultAction().mouseDragged(e);\r
+                       update();\r
+               }\r
+       }\r
+       \r
+       protected void setPos(Vector3d pos) {\r
+               node.setPosition(pos);\r
+       }\r
+       \r
+       protected void setWorldPos(Vector3d pos) {\r
+               node.setWorldPosition(pos);\r
+       }\r
+       \r
+        private double istep = 10.0;\r
+        private int decimals = 2;\r
+       \r
+       private Vector3d constaints(Vector3d p, boolean step) {\r
+               if(!step)\r
+                       return p;\r
+               switch (index) {\r
+               case X:\r
+                        p.x = Math.round(istep * p.x) / istep;\r
+             BigDecimal bx = new BigDecimal(p.x);\r
+             bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);\r
+             p.x = bx.doubleValue();\r
+                       break;\r
+               case Y:\r
+                        p.y = Math.round(istep * p.y) / istep;\r
+             BigDecimal by = new BigDecimal(p.y);\r
+             by.setScale(decimals, BigDecimal.ROUND_HALF_UP);\r
+             p.y = by.doubleValue();\r
+                       break;\r
+                       \r
+               case Z:\r
+                        p.z = Math.round(istep * p.z) / istep;\r
+             BigDecimal bz = new BigDecimal(p.z);\r
+             bz.setScale(decimals, BigDecimal.ROUND_HALF_UP);\r
+             p.z = bz.doubleValue();\r
+                       break;\r
+               }\r
+               return p;\r
+       }\r
+       \r
+       @Override\r
+       public void mouseMoved(MouseEvent e) {\r
+               panel.getDefaultAction().mouseMoved(e);\r
+       }\r
+       \r
+       Vector3d getTranslate(double x, double y) {\r
+               return getTranslate(x, y, new Vector3d());\r
+       }\r
+       \r
+       Vector3d getTranslate(double x, double y, Vector3d offset) {\r
+               Vector3d translate = new Vector3d();\r
+               \r
+               Ray ray = vtkUtil.createMouseRay(panel.GetRenderer(),x, y);\r
+               \r
+               Vector3d p = node.getWorldPosition();\r
+               Vector3d dir = null;\r
+               \r
+               switch (index) {\r
+               case P:\r
+                       Vector3d normal = new Vector3d(panel.GetRenderer().GetActiveCamera().GetDirectionOfProjection());\r
+                       if (!worldCoord) {\r
+                               MathTools.rotate(q, normal, normal);\r
+                       }\r
+                       normal.normalize();\r
+                       double s[] = new double[1];\r
+            Vector3d r = new Vector3d();\r
+            if (MathTools.intersectStraightPlane(ray.pos, ray.dir, p, normal, r)) {\r
+                r.sub(p);\r
+                translate.x = r.x;\r
+                translate.y = r.y;\r
+                translate.z = r.z;\r
+            }\r
+            break;\r
+\r
+                case X :\r
+                   dir = new Vector3d(1.0,0.0,0.0);\r
+                   if(!worldCoord)\r
+                       MathTools.rotate(q, dir, dir);\r
+                   Vector3d i1 = new Vector3d();\r
+                   Vector3d i2 = new Vector3d();\r
+                   s = new double[2];\r
+                   MathTools.intersectStraightStraight( p, dir,ray.pos, ray.dir, i2, i1,s);\r
+                   translate.x = s[0];\r
+                   \r
+                   break;\r
+               case Y :\r
+                   dir = new Vector3d(0.0,1.0,0.0);\r
+                   if(!worldCoord)\r
+                       MathTools.rotate(q, dir, dir);\r
+                   i1 = new Vector3d();\r
+                   i2 = new Vector3d();\r
+                   s = new double[2];\r
+                   MathTools.intersectStraightStraight( p, dir,ray.pos, ray.dir, i2, i1,s);\r
+                   translate.y = s[0];\r
+                   break;\r
+               case Z :\r
+                   dir = new Vector3d(0.0,0.0,1.0);\r
+                   if(!worldCoord)\r
+                       MathTools.rotate(q, dir, dir);\r
+                   i1 = new Vector3d();\r
+                   i2 = new Vector3d();\r
+                   s = new double[2];\r
+                   MathTools.intersectStraightStraight( p, dir,ray.pos, ray.dir, i2, i1,s);\r
+                   translate.z = s[0];\r
+                   break;\r
+               case XY :\r
+                   normal = new Vector3d(0.0,0.0,1.0);\r
+                   if(!worldCoord)\r
+                       MathTools.rotate(q, normal, normal);\r
+                   r = new Vector3d();\r
+                   if (MathTools.intersectStraightPlane(ray.pos, ray.dir, p, normal, r)) {\r
+                       r.sub(p);\r
+                       translate.x = r.x;\r
+                       translate.y = r.y;\r
+                   }\r
+                   break;\r
+               case XZ :\r
+                   normal = new Vector3d(0.0,1.0,0.0);\r
+                   if(!worldCoord)\r
+                       MathTools.rotate(q, normal, normal);\r
+                   r = new Vector3d();\r
+                   if (MathTools.intersectStraightPlane(ray.pos, ray.dir, p, normal, r)) {\r
+                       r.sub(p);\r
+                       translate.x = r.x;\r
+                       translate.z = r.z;\r
+                   }\r
+                   break;\r
+               case YZ :\r
+                   normal = new Vector3d(1.0,0.0,0.0);\r
+                   if(!worldCoord)\r
+                       MathTools.rotate(q, normal, normal);\r
+                   r = new Vector3d();\r
+                   if (MathTools.intersectStraightPlane(ray.pos, ray.dir, p, normal, r)) {\r
+                       r.sub(p);\r
+                       translate.y = r.y;\r
+                       translate.z = r.z;\r
+                   }\r
+                   break;\r
+               default :\r
+                   \r
+                   return null;\r
+               }\r
+               translate.sub(offset);\r
+               return translate;\r
+       }\r
+       \r
+}\r
diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/action/vtkAction.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/action/vtkAction.java
new file mode 100644 (file)
index 0000000..d4c127b
--- /dev/null
@@ -0,0 +1,88 @@
+package org.simantics.g3d.vtk.action;\r
+\r
+import java.awt.event.KeyEvent;\r
+import java.awt.event.KeyListener;\r
+import java.awt.event.MouseEvent;\r
+import java.awt.event.MouseListener;\r
+import java.awt.event.MouseMotionListener;\r
+\r
+import org.eclipse.jface.action.Action;\r
+import org.simantics.g3d.vtk.common.InteractiveVtkPanel;\r
+\r
+public abstract class vtkAction extends Action implements KeyListener, MouseListener, MouseMotionListener {\r
+\r
+       protected InteractiveVtkPanel panel;\r
+       \r
+       public vtkAction(InteractiveVtkPanel panel) {\r
+               this.panel = panel;\r
+       }\r
+       \r
+       @Override\r
+       public void run() {\r
+               panel.setActiveAction(this);\r
+       }\r
+       \r
+       \r
+       public void attach() {\r
+\r
+               panel.addKeyListener(this);\r
+               panel.addMouseListener(this);\r
+               panel.addMouseMotionListener(this);\r
+\r
+       }\r
+       \r
+       public void deattach() {\r
+               panel.removeKeyListener(this);\r
+               panel.removeMouseListener(this);\r
+               panel.removeMouseMotionListener(this);\r
+       }\r
+       \r
+       @Override\r
+       public void keyPressed(KeyEvent e) {\r
+               \r
+       }\r
+       \r
+       @Override\r
+       public void keyReleased(KeyEvent e) {\r
+               \r
+       }\r
+       \r
+       @Override\r
+       public void keyTyped(KeyEvent e) {\r
+               \r
+       }\r
+       \r
+       public void mouseClicked(java.awt.event.MouseEvent e) {\r
+               \r
+       };\r
+       \r
+       @Override\r
+       public void mouseDragged(MouseEvent e) {\r
+               \r
+       }\r
+       \r
+       @Override\r
+       public void mouseEntered(MouseEvent e) {\r
+               \r
+       }\r
+       \r
+       @Override\r
+       public void mouseExited(MouseEvent e) {\r
+               \r
+       }\r
+       \r
+       @Override\r
+       public void mouseMoved(MouseEvent e) {\r
+               \r
+       }\r
+       \r
+       @Override\r
+       public void mousePressed(MouseEvent e) {\r
+               \r
+       }\r
+       \r
+       @Override\r
+       public void mouseReleased(MouseEvent e) {\r
+       \r
+       }\r
+}\r
diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/action/vtkCameraAndSelectorAction.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/action/vtkCameraAndSelectorAction.java
new file mode 100644 (file)
index 0000000..f6cf732
--- /dev/null
@@ -0,0 +1,371 @@
+package org.simantics.g3d.vtk.action;\r
+\r
+import java.awt.event.InputEvent;\r
+import java.awt.event.MouseEvent;\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.HashSet;\r
+import java.util.List;\r
+import java.util.Set;\r
+\r
+import org.eclipse.jface.viewers.ISelection;\r
+import org.eclipse.jface.viewers.ISelectionChangedListener;\r
+import org.eclipse.jface.viewers.ISelectionProvider;\r
+import org.eclipse.jface.viewers.SelectionChangedEvent;\r
+import org.eclipse.jface.viewers.StructuredSelection;\r
+import org.eclipse.swt.widgets.Display;\r
+import org.simantics.g3d.tools.AdaptationUtils;\r
+import org.simantics.g3d.vtk.common.InteractiveVtkPanel;\r
+\r
+import vtk.vtkActor;\r
+import vtk.vtkCamera;\r
+import vtk.vtkProp;\r
+import vtk.vtkRenderWindow;\r
+import vtk.vtkRenderer;\r
+\r
+public class vtkCameraAndSelectorAction extends vtkAction implements ISelectionProvider {\r
+       \r
+       protected vtkRenderer ren;\r
+       protected int lastX;\r
+       protected int lastY;\r
+       protected vtkRenderWindow rw;\r
+       protected vtkCamera cam;\r
+       protected int InteractionMode = 1;\r
+       \r
+       public vtkCameraAndSelectorAction(InteractiveVtkPanel panel) {\r
+               super(panel);\r
+               this.ren = panel.GetRenderer();\r
+               this.rw = panel.GetRenderWindow();\r
+               this.cam = ren.GetActiveCamera();\r
+       }\r
+       \r
+       public void Lock() {\r
+               panel.lock();\r
+       }\r
+       \r
+       public void UnLock() {\r
+               panel.unlock();\r
+       }\r
+       \r
+       public void InteractionModeRotate()\r
+         {\r
+           this.InteractionMode = 1;\r
+         }\r
+         \r
+         public void InteractionModeTranslate()\r
+         {\r
+           this.InteractionMode = 2;\r
+         }\r
+         \r
+         public void InteractionModeZoom()\r
+         {\r
+           this.InteractionMode = 3;\r
+         }\r
+         \r
+       public void resetCameraClippingRange() {\r
+           Lock();\r
+           ren.ResetCameraClippingRange();\r
+           UnLock();\r
+         }\r
+\r
+         public void resetCamera() {\r
+           Lock();\r
+           ren.ResetCamera();\r
+           UnLock();\r
+         }\r
+         \r
+        public void mousePressed(MouseEvent e)\r
+         {\r
+             \r
+           if (ren.VisibleActorCount() == 0) return;\r
+           rw.SetDesiredUpdateRate(5.0);\r
+           lastX = e.getX();\r
+           lastY = e.getY();\r
+           if ((e.getModifiers()==InputEvent.BUTTON2_MASK) ||\r
+               (e.getModifiers()==(InputEvent.BUTTON1_MASK | InputEvent.SHIFT_MASK)))\r
+             {\r
+               InteractionModeTranslate();\r
+             }\r
+           else if (e.getModifiers()==InputEvent.BUTTON3_MASK)\r
+             {\r
+               InteractionModeZoom();\r
+             }\r
+           else \r
+             {\r
+               InteractionModeRotate();\r
+             }\r
+         }\r
+        \r
+        public void mouseReleased(MouseEvent e)\r
+         {\r
+           rw.SetDesiredUpdateRate(0.01);\r
+         }\r
+        \r
+\r
+        \r
+        public void mouseDragged(MouseEvent e)\r
+         {\r
+           if (ren.VisibleActorCount() == 0) return;\r
+           int x = e.getX();\r
+           int y = e.getY();\r
+           // rotate\r
+           if (this.InteractionMode == 1)\r
+             {\r
+               cam.Azimuth(lastX - x);\r
+               cam.Elevation(y - lastY);\r
+               cam.OrthogonalizeViewUp();\r
+               resetCameraClippingRange();\r
+               panel.UpdateLight();\r
+             }\r
+           // translate\r
+           if (this.InteractionMode == 2)\r
+             {\r
+               double  FPoint[];\r
+               double  PPoint[];\r
+               double  APoint[] = new double[3];\r
+               double  RPoint[];\r
+               double focalDepth;\r
+               \r
+               // get the current focal point and position\r
+               FPoint = cam.GetFocalPoint();\r
+               PPoint = cam.GetPosition();\r
+               \r
+               // calculate the focal depth since we'll be using it a lot\r
+               ren.SetWorldPoint(FPoint[0],FPoint[1],FPoint[2],1.0);\r
+               ren.WorldToDisplay();\r
+               focalDepth = ren.GetDisplayPoint()[2];\r
+               \r
+               APoint[0] = rw.GetSize()[0]/2.0 + (x - lastX);\r
+               APoint[1] = rw.GetSize()[1]/2.0 - (y - lastY);\r
+               APoint[2] = focalDepth;\r
+               ren.SetDisplayPoint(APoint);\r
+               ren.DisplayToWorld();\r
+               RPoint = ren.GetWorldPoint();\r
+               if (RPoint[3] != 0.0)\r
+                 {\r
+                   RPoint[0] = RPoint[0]/RPoint[3];\r
+                   RPoint[1] = RPoint[1]/RPoint[3];\r
+                   RPoint[2] = RPoint[2]/RPoint[3];\r
+                 }\r
+               \r
+               /*\r
+                * Compute a translation vector, moving everything 1/2 \r
+                * the distance to the cursor. (Arbitrary scale factor)\r
+                */\r
+               cam.SetFocalPoint(\r
+                                 (FPoint[0]-RPoint[0])/2.0 + FPoint[0],\r
+                                 (FPoint[1]-RPoint[1])/2.0 + FPoint[1],\r
+                                 (FPoint[2]-RPoint[2])/2.0 + FPoint[2]);\r
+               cam.SetPosition(\r
+                               (FPoint[0]-RPoint[0])/2.0 + PPoint[0],\r
+                               (FPoint[1]-RPoint[1])/2.0 + PPoint[1],\r
+                               (FPoint[2]-RPoint[2])/2.0 + PPoint[2]);\r
+               resetCameraClippingRange();\r
+             }\r
+           // zoom\r
+           if (this.InteractionMode == 3)\r
+             {\r
+               double zoomFactor;\r
+               //double clippingRange[];\r
+               \r
+               zoomFactor = Math.pow(1.02,(y - lastY));\r
+               if (cam.GetParallelProjection() == 1)\r
+                 {\r
+                   cam.SetParallelScale(cam.GetParallelScale()/zoomFactor);\r
+                 }\r
+               else\r
+                 {\r
+                   cam.Dolly(zoomFactor);\r
+                   resetCameraClippingRange();\r
+                 }\r
+             }\r
+           lastX = x;\r
+           lastY = y;\r
+           panel.Render();\r
+         }\r
+\r
+        \r
+               private List<vtkProp> selectActors = new ArrayList<vtkProp>();\r
+               private List<vtkProp> hoverActor = new ArrayList<vtkProp>();\r
+        \r
+               @Override\r
+               public void mouseClicked(MouseEvent e) {\r
+                       if (!panel.isFocusOwner())\r
+                               return;\r
+                       if (e.getButton() != MouseEvent.BUTTON1)\r
+                               return;\r
+                       vtkProp spick[] = panel.pick(e.getX(), e.getY());\r
+                       if (spick != null && spick.length > 0) {\r
+                               for (vtkProp selectActor : spick) {\r
+                                       if (!e.isControlDown()) {\r
+                                               selectActors.clear();\r
+                                               selectActors.add(selectActor);\r
+                                       } else {\r
+                                               if (selectActors.contains(selectActor))\r
+                                                       selectActors.remove(selectActor);\r
+                                               else\r
+                                                       selectActors.add(selectActor);\r
+                                       }\r
+                               }\r
+                               fireSelectionChanged();\r
+                       } else if (!e.isControlDown()) {\r
+                               selectActors.clear();\r
+                               fireSelectionChanged();\r
+                       }\r
+                       \r
+//                     if (e.getClickCount() > 1)\r
+//                             updatePickRay(e.getX(), e.getY());\r
+                       \r
+               }\r
+               \r
+//             private void updatePickRay(double x , double y) {\r
+//                     Ray ray = vtkUtil.createMouseRay(panel.GetRenderer(), x, y);\r
+//                     \r
+//                     \r
+//                     System.out.println(ray.pos + " " + ray.dir);\r
+//                     vtkPoints linePoints = new vtkPoints();\r
+//                     linePoints.InsertPoint(0,ray.pos.x, ray.pos.y, ray.pos.z);\r
+//                     linePoints.InsertPoint(1, ray.pos.x + ray.dir.x, ray.pos.y + ray.dir.y, ray.pos.z + ray.dir.z);\r
+//                     vtkLine aLine = new vtkLine();\r
+//                     aLine.GetPointIds().SetId(0, 0);\r
+//                     aLine.GetPointIds().SetId(1, 1);\r
+//                     vtkUnstructuredGrid aLineGrid = new vtkUnstructuredGrid();\r
+//                     aLineGrid.Allocate(1, 1);\r
+//                     aLineGrid.InsertNextCell(aLine.GetCellType(), aLine.GetPointIds());\r
+//                     aLineGrid.SetPoints(linePoints);\r
+//                     vtkDataSetMapper aLineMapper = new vtkDataSetMapper();\r
+//                     aLineMapper.SetInput(aLineGrid);\r
+//                     vtkActor aLineActor = new vtkActor();\r
+//                     aLineActor.SetMapper(aLineMapper);\r
+//                     aLineActor.GetProperty().SetDiffuseColor(.2, 1, 1);\r
+//                     \r
+//                 if (rayActor != null) {\r
+//                     panel.GetRenderer().RemoveActor(rayActor);\r
+//                     rayActor.Delete();\r
+//                 }\r
+//                 rayActor = aLineActor;\r
+//                 panel.GetRenderer().AddActor(rayActor);\r
+//                 \r
+//                 linePoints.Delete();\r
+//                 aLine.Delete();\r
+//                 aLineGrid.Delete();\r
+//                 aLineMapper.Delete();\r
+//                 panel.repaint();\r
+//             }\r
+//             \r
+//             private vtkActor rayActor;\r
+               \r
+               @Override\r
+               public void mouseMoved(MouseEvent e) {\r
+                       lastX = e.getX();\r
+                   lastY = e.getY();\r
+                   \r
+                       if (!panel.isFocusOwner())\r
+                               return;\r
+                       List<vtkProp> prevHover = new ArrayList<vtkProp>();\r
+                       prevHover.addAll(hoverActor);\r
+                       hoverActor.clear();\r
+                       vtkProp pick[] =  panel.pick(e.getX(),e.getY());\r
+                       if (pick != null) {\r
+                               for (vtkProp p : pick)\r
+                                       hoverActor.add(p);\r
+                       }\r
+                               \r
+                       if (!prevHover.containsAll(hoverActor) || !hoverActor.containsAll(prevHover)) {\r
+                               fireHoverChanged();\r
+                       }\r
+               }\r
+               \r
+               public List<vtkProp> getSelectActor() {\r
+                       return selectActors;\r
+               }\r
+               \r
+               public List<vtkProp> getHoverActor() {\r
+                       return hoverActor;\r
+               }\r
+               \r
+               private List<ISelectionChangedListener> selectionListeners = new ArrayList<ISelectionChangedListener>();\r
+                \r
+               @Override\r
+               public void addSelectionChangedListener(ISelectionChangedListener listener) {\r
+                       selectionListeners.add(listener);\r
+               }\r
+               \r
+               @Override\r
+               public ISelection getSelection() {\r
+                       return new StructuredSelection(selectActors);\r
+               }\r
+               \r
+               @Override\r
+               public void removeSelectionChangedListener(\r
+                               ISelectionChangedListener listener) {\r
+                       selectionListeners.remove(listener);\r
+               }\r
+               \r
+               @Override\r
+               public void setSelection(ISelection selection) {\r
+                       setSelection(selection, false);\r
+\r
+               }\r
+               \r
+               public void setSelection(ISelection selection, boolean fire) {\r
+                       Collection<vtkProp> selectedProps = AdaptationUtils.adaptToCollection(selection, vtkProp.class);\r
+                       \r
+                       selectActors.clear();\r
+                       selectActors.addAll(selectedProps);\r
+                       if (fire)\r
+                               fireSelectionChanged();\r
+               }\r
+               \r
+               private void fireSelectionChanged() {\r
+                       Display.getDefault().asyncExec(new Runnable() {\r
+                               @Override\r
+                               public void run() {\r
+                                       \r
+                                       SelectionChangedEvent evt = new SelectionChangedEvent(vtkCameraAndSelectorAction.this, new StructuredSelection(selectActors));\r
+                                       for (ISelectionChangedListener l :selectionListeners) {\r
+                                               l.selectionChanged(evt);\r
+                                       }\r
+                                       \r
+                               }\r
+                       });\r
+               }\r
+               \r
+               \r
+               private List<ISelectionChangedListener> hoverListeners = new ArrayList<ISelectionChangedListener>();\r
+                \r
+       \r
+               public void addHoverChangedListener(ISelectionChangedListener listener) {\r
+                       hoverListeners.add(listener);\r
+               }\r
+               \r
+               \r
+               public ISelection getHoverSelection() {\r
+                       return new StructuredSelection(hoverActor);\r
+               }\r
+               \r
+               public void removeHoverChangedListener(\r
+                               ISelectionChangedListener listener) {\r
+                       hoverListeners.remove(listener);\r
+               }\r
+\r
+               private void fireHoverChanged() {\r
+                       Display.getDefault().asyncExec(new Runnable() {\r
+                               @Override\r
+                               public void run() {\r
+                                       StructuredSelection sel = null;\r
+                                       if (hoverActor == null)\r
+                                               sel = new StructuredSelection();\r
+                                       else\r
+                                               sel = new StructuredSelection(hoverActor);\r
+                                       SelectionChangedEvent evt = new SelectionChangedEvent(vtkCameraAndSelectorAction.this, sel);\r
+                                       for (ISelectionChangedListener l :hoverListeners) {\r
+                                               l.selectionChanged(evt);\r
+                                       }\r
+                                       \r
+                               }\r
+                       });\r
+               }\r
+               \r
+               \r
+}\r
diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/AbstractVTKNodeMap.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/AbstractVTKNodeMap.java
new file mode 100644 (file)
index 0000000..144138a
--- /dev/null
@@ -0,0 +1,490 @@
+package org.simantics.g3d.vtk.common;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.HashMap;\r
+import java.util.HashSet;\r
+import java.util.List;\r
+import java.util.Map;\r
+import java.util.Set;\r
+import java.util.Stack;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.Session;\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.db.common.request.ReadRequest;\r
+import org.simantics.db.common.request.WriteRequest;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.g3d.ontology.G3D;\r
+import org.simantics.g3d.scenegraph.IG3DNode;\r
+import org.simantics.g3d.scenegraph.RenderListener;\r
+import org.simantics.g3d.scenegraph.base.INode;\r
+import org.simantics.g3d.scenegraph.base.NodeListener;\r
+import org.simantics.g3d.scenegraph.base.ParentNode;\r
+import org.simantics.objmap.graph.IMapping;\r
+import org.simantics.objmap.graph.IMappingListener;\r
+import org.simantics.utils.datastructures.Callback;\r
+import org.simantics.utils.datastructures.MapList;\r
+import org.simantics.utils.datastructures.MapSet;\r
+import org.simantics.utils.datastructures.Pair;\r
+import org.simantics.utils.ui.ExceptionUtils;\r
+\r
+import vtk.vtkProp;\r
+\r
+public abstract class AbstractVTKNodeMap<E extends INode> implements VTKNodeMap, IMappingListener, RenderListener, NodeListener{\r
+\r
+       private static final boolean DEBUG = false;\r
+       \r
+       protected Session session;\r
+       protected IMapping<Object,E> mapping;\r
+       protected InteractiveVtkPanel panel;\r
+       \r
+       protected MapList<E, vtkProp> nodeToActor = new MapList<E, vtkProp>();\r
+       protected Map<vtkProp,E> actorToNode = new HashMap<vtkProp, E>();\r
+\r
+       protected ParentNode<E> rootNode;\r
+       \r
+       public AbstractVTKNodeMap(Session session, IMapping<Object,E> mapping, InteractiveVtkPanel panel, ParentNode<E> rootNode) {\r
+               this.session = session;\r
+               this.mapping = mapping;\r
+               this.panel = panel;\r
+               this.rootNode = rootNode;\r
+               panel.addListener(this);\r
+               mapping.addMappingListener(this);\r
+               rootNode.addListener(this);\r
+       }\r
+       \r
+       \r
+       protected abstract void addActor(E node);\r
+       protected abstract void removeActor(E node);\r
+       protected abstract void updateActor(E node,Set<String> ids);\r
+       \r
+       public void repaint() {\r
+               panel.repaint();\r
+       }\r
+       \r
+       public void populate() {\r
+               for (E node : rootNode.getNodes()) {\r
+                       receiveAdd(node, node.getParentRel(),true);\r
+               }\r
+               repaint();\r
+       }\r
+       \r
+       @Override\r
+       public INode getNode(vtkProp prop) {\r
+               return actorToNode.get(prop);\r
+       }\r
+       \r
+       @SuppressWarnings("unchecked")\r
+       @Override\r
+       public Collection<vtkProp> getRenderObjects(INode node) {\r
+               return nodeToActor.getValues((E)node);\r
+       }\r
+       \r
+       @SuppressWarnings("unchecked")\r
+       @Override\r
+       public ParentNode<IG3DNode> getRootNode() {\r
+               return (ParentNode<IG3DNode>)rootNode;\r
+       }\r
+       \r
+       \r
+       \r
+       @Override\r
+       public boolean isChangeTracking() {\r
+               return changeTracking;\r
+       }\r
+       \r
+       @Override\r
+       public void setChangeTracking(boolean enabled) {\r
+               changeTracking = enabled;\r
+       }\r
+       \r
+       private boolean changeTracking = true;\r
+       \r
+       protected Object syncMutex = new Object(); \r
+       \r
+\r
+       private List<Pair<E,String>> added = new ArrayList<Pair<E,String>>();\r
+       private List<Pair<E,String>> removed = new ArrayList<Pair<E,String>>();\r
+       //private List<Pair<E,String>> updated = new ArrayList<Pair<E,String>>();\r
+       private MapSet<E, String> updated = new MapSet.Hash<E, String>();\r
+\r
+       private boolean rangeModified = false;\r
+       \r
+       @SuppressWarnings("unchecked")\r
+       @Override\r
+       public void updateRenderObjectsFor(INode node) {\r
+               List<vtkProp> toDelete = new ArrayList<vtkProp>();\r
+               for (vtkProp prop : nodeToActor.getValues((E)node)) {\r
+                       if (prop.GetVTKId() != 0) {\r
+                               panel.GetRenderer().RemoveActor(prop);\r
+                               //prop.Delete();\r
+                               toDelete.add(prop);\r
+                       }\r
+                       actorToNode.remove(prop);\r
+               }\r
+               nodeToActor.remove((E)node);\r
+               Collection<vtkProp> coll = getActors((E)node);\r
+               if (coll == null)\r
+                       return;\r
+               for (vtkProp prop : coll) {\r
+                       nodeToActor.add((E)node,prop);\r
+                       actorToNode.put(prop, (E)node);\r
+                       toDelete.remove(prop);\r
+               }\r
+               for (vtkProp p : toDelete)\r
+                       p.Delete();\r
+       }\r
+       \r
+       protected abstract  Collection<vtkProp> getActors(E node);\r
+       \r
+       @SuppressWarnings("unchecked")\r
+       private void receiveAdd(E node, String id, boolean db) {\r
+               if (DEBUG) System.out.println("receiveAdd " + node  + " " + id + " " + db);\r
+               synchronized (syncMutex) {\r
+                       for (Pair<E, String> n : added) {\r
+                               if (n.first.equals(node))\r
+                                       return;\r
+                       }\r
+                       if (changeTracking) {\r
+                               mapping.rangeModified((E)node.getParent());\r
+                       }\r
+                       added.add(new Pair<E, String>(node, id));\r
+                       rangeModified = true;\r
+               }\r
+               panel.repaint();\r
+       }\r
+       \r
+       @SuppressWarnings("unchecked")\r
+       private void receiveRemove(E node, String id, boolean db) {\r
+               if (DEBUG) System.out.println("receiveRemove " + node  + " " + id + " " + db);\r
+               synchronized (syncMutex) {\r
+                       for (Pair<E, String> n : removed) {\r
+                               if (n.first.equals(node))\r
+                                       return;\r
+                       }\r
+                       if (changeTracking && !db)\r
+                               mapping.rangeModified((E)node.getParent());\r
+                       removed.add(new Pair<E, String>(node, id));\r
+                       rangeModified = true;\r
+               }\r
+               panel.repaint();\r
+       }\r
+       \r
+       @SuppressWarnings("unchecked")\r
+       private void receiveUpdate(E node, String id, boolean db) {\r
+               if (DEBUG) System.out.println("receiveUpdate " + node  + " " + id + " " + db);\r
+               synchronized (syncMutex) {\r
+//                     for (Pair<E, String> n : updated) {\r
+//                             if (n.first.equals(node))\r
+//                                     return;\r
+//                     }\r
+                       if (changeTracking && !db)\r
+                               mapping.rangeModified(node);\r
+                       //updated.add(new Pair<E, String>(node, id));\r
+                       updated.add(node, id);\r
+                       rangeModified = true;\r
+               }\r
+               panel.repaint();\r
+       }\r
+       \r
+       private boolean graphUpdates = false;\r
+       private Set<E> graphModified = new HashSet<E>();\r
+       \r
+       private boolean requestCommit = false;\r
+       \r
+       @Override\r
+       public void commit() {\r
+               requestCommit = true;\r
+       }\r
+       \r
+       protected void doCommit() {\r
+               session.asyncRequest(new WriteRequest() {\r
+                       \r
+                       @Override\r
+                       public void perform(WriteGraph graph) throws DatabaseException {\r
+                               commit(graph);\r
+                       }\r
+                       \r
+               }, new Callback<DatabaseException>() {\r
+                       \r
+                       @Override\r
+                       public void run(DatabaseException parameter) {\r
+                               if (parameter != null)\r
+                                       ExceptionUtils.logAndShowError("Cannot commit editor changes", parameter);\r
+                       }\r
+               });\r
+       }\r
+       \r
+       protected void commit(WriteGraph graph) throws DatabaseException {\r
+               synchronized(syncMutex) {\r
+                       if (DEBUG) System.out.println("Commit");\r
+                       graphUpdates = true;\r
+                       mapping.updateDomain(graph);\r
+                       graphUpdates = false;\r
+               }\r
+       }\r
+       \r
+       @Override\r
+       public void domainModified() {\r
+               if (graphUpdates)\r
+                       return;\r
+               if (DEBUG)System.out.println("domainModified");\r
+               session.asyncRequest(new ReadRequest() {\r
+                       \r
+                       @SuppressWarnings("unchecked")\r
+                       @Override\r
+                       public void run(ReadGraph graph) throws DatabaseException {\r
+                               update(graph);\r
+                       }\r
+               });\r
+               \r
+       }\r
+       \r
+       protected void update(ReadGraph graph) throws DatabaseException {\r
+               synchronized (syncMutex) {\r
+                       graphUpdates = true;\r
+                       for (Object domainObject : mapping.getDomainModified()) {\r
+                               E rangeObject = mapping.get(domainObject);\r
+                               if (rangeObject != null)\r
+                                       graphModified.add(rangeObject);\r
+                       }\r
+                       mapping.updateRange(graph);\r
+                       graphModified.clear();\r
+                       graphUpdates = false;\r
+               }\r
+               \r
+               if (mapping.isRangeModified())\r
+                       commit();\r
+       }\r
+       \r
+       @Override\r
+       public void rangeModified() {\r
+               //System.out.println("rangeModified");\r
+\r
+       }\r
+       \r
+       @Override\r
+       public void postRender() {\r
+               // Commit changes if\r
+               // 1. Commit has been requested\r
+               // 2. There are no pending changes that should be processed in preRender() \r
+               if (requestCommit && !rangeModified) { // FIXME : not thread safe.\r
+                       requestCommit = false;\r
+                       doCommit();\r
+               }\r
+       }\r
+       \r
+       List<Pair<E, String>> rem = new ArrayList<Pair<E,String>>();\r
+       List<Pair<E, String>> add = new ArrayList<Pair<E,String>>();\r
+       MapSet<E, String> mod = new MapSet.Hash<E, String>();\r
+       Set<E> propagation = new HashSet<E>();\r
+       Stack<E> stack = new Stack<E>();\r
+       \r
+       \r
+       @Override\r
+       public synchronized void preRender() {\r
+               updateCycle();\r
+       }\r
+       \r
+       @SuppressWarnings("unchecked")\r
+       protected void updateCycle() {\r
+               rem.clear();\r
+               add.clear();\r
+               mod.clear();\r
+               propagation.clear();\r
+               \r
+               synchronized (syncMutex) {\r
+                       rem.addAll(removed);\r
+                       add.addAll(added);\r
+                       for (E e : updated.getKeys()) {\r
+                               for (String s : updated.getValues(e)) {\r
+                                       mod.add(e, s);\r
+                               }\r
+                       }\r
+                       \r
+                       removed.clear();\r
+                       added.clear();\r
+                       updated.clear();\r
+               }\r
+               \r
+               for (Pair<E, String> n : rem) {\r
+                       stopListening(n.first);\r
+                       removeActor(n.first);\r
+               \r
+               }\r
+               \r
+               for (Pair<E, String> n : add) {\r
+                       addActor(n.first);\r
+                       listen(n.first);\r
+               }\r
+               \r
+               for (E e : mod.getKeys()) {\r
+                       Set<String> ids = mod.getValues(e);\r
+                       if (ids.contains(G3D.URIs.hasPosition) || ids.contains(G3D.URIs.hasOrientation)) {\r
+                               if (!propagation.contains(e))\r
+                                       propagation.add(e);\r
+                       }\r
+               }\r
+\r
+               if (propagation.size() > 0) {\r
+                       stack.clear();\r
+                       stack.addAll(propagation);\r
+                       propagation.clear();\r
+                       while (!stack.isEmpty()) {\r
+                               E node = stack.pop();\r
+                               if (propagation.contains(node))\r
+                                       continue;\r
+                               propagation.add(node);\r
+                               for (NodeListener l : node.getListeners()) {\r
+                                       if (l == this) {\r
+                                               //changeTracking = false;\r
+                                               //l.propertyChanged(node, G3D.URIs.hasPosition);\r
+                                               //changeTracking = true;\r
+                                       } else {\r
+                                               l.propertyChanged(node, G3D.URIs.hasWorldPosition);\r
+                                       }\r
+                               }\r
+                               if (node instanceof ParentNode) {\r
+                                       stack.addAll(((ParentNode<E>)node).getNodes());\r
+                               }\r
+                       }\r
+               }\r
+               \r
+//             synchronized (syncMutex) {\r
+//                     rem.addAll(removed);\r
+//                     add.addAll(added);\r
+//                     //mod.addAll(updated);\r
+//                     for (E e : updated.getKeys()) {\r
+//                             for (String s : updated.getValues(e))\r
+//                                     mod.add(e, s);\r
+//                     }\r
+//                     \r
+//                     removed.clear();\r
+//                     added.clear();\r
+//                     updated.clear();\r
+//             }\r
+               \r
+               for (E e : mod.getKeys()) {\r
+                       Set<String> ids = mod.getValues(e);\r
+                       updateActor(e,ids);\r
+               }\r
+               \r
+               \r
+               for (Pair<E, String> n : rem) {\r
+                       for (NodeListener l : nodeListeners)\r
+                               l.nodeRemoved(null, n.first, n.second);\r
+               }\r
+               for (Pair<E, String> n : add) {\r
+                       for (NodeListener l : nodeListeners)\r
+                               l.nodeAdded(n.first.getParent(), n.first, n.second);\r
+               }\r
+//             for (Pair<E, String> n : mod) {\r
+//                     for (NodeListener l : nodeListeners)\r
+//                             l.propertyChanged(n.first, n.second);\r
+//             }\r
+               for (E e : mod.getKeys()) {\r
+                       for (NodeListener l : nodeListeners)\r
+                               for (String s : mod.getValues(e))\r
+                                       l.propertyChanged(e, s);\r
+               }\r
+               synchronized (syncMutex) {\r
+                       if (added.isEmpty() && removed.isEmpty() && updated.getKeys().size() == 0)\r
+                               rangeModified = false;\r
+               }\r
+       }\r
+       \r
+       @SuppressWarnings("unchecked")\r
+       private void listen(INode node) {\r
+               node.addListener(this);\r
+               if (node instanceof ParentNode<?>) {\r
+                       ParentNode<INode> parentNode = (ParentNode<INode>)node;\r
+                       for (INode n : parentNode.getNodes())\r
+                               listen(n);\r
+               }\r
+       }\r
+       \r
+       private void stopListening(INode node) {\r
+               node.removeListener(this);\r
+               if (node instanceof ParentNode<?>) {\r
+                       @SuppressWarnings("unchecked")\r
+                       ParentNode<INode> parentNode = (ParentNode<INode>)node;\r
+                       for (INode n : parentNode.getNodes())\r
+                               stopListening(n);\r
+               }\r
+       }\r
+       \r
+       @SuppressWarnings("unchecked")\r
+       @Override\r
+       public void propertyChanged(INode node, String id) {\r
+               //receiveUpdate((E)node, id, graphUpdates);\r
+               receiveUpdate((E)node, id, graphModified.contains(node));\r
+               \r
+       }\r
+       \r
+       @SuppressWarnings("unchecked")\r
+       @Override\r
+       public <T extends INode> void nodeAdded(ParentNode<T> node, INode child,\r
+                       String rel) {\r
+               if (DEBUG) System.out.println("Node added " + child + " parent " + node);\r
+               //receiveAdd((E)child, rel ,graphUpdates);\r
+               receiveAdd((E)child, rel ,graphModified.contains(node));\r
+               \r
+       }\r
+       \r
+       @SuppressWarnings("unchecked")\r
+       @Override\r
+       public <T extends INode> void nodeRemoved(ParentNode<T> node, INode child,\r
+                       String rel) {\r
+               if (DEBUG) System.out.println("Node removed " + child + " parent " + node);\r
+               //receiveRemove((E)child, rel, graphUpdates);\r
+               receiveRemove((E)child, rel, graphModified.contains(node));\r
+               \r
+               //FIXME : sometimes removed structural models cause ObjMap to add their children again.\r
+               //        removing the listener here prevents corruption of visual model, but better fix is needed.\r
+               stopListening(child);\r
+       }\r
+       \r
+       @Override\r
+       public void delete() {\r
+               changeTracking = false;\r
+               panel.removeListener(this);\r
+               mapping.removeMappingListener(this);\r
+\r
+               List<E> nodes = new ArrayList<E>(nodeToActor.getKeySize());\r
+               nodes.addAll(nodeToActor.getKeys());\r
+               for (E node : nodes) {\r
+                       node.removeListener(this);\r
+                       removeActor(node);\r
+                       node.cleanup();\r
+               }\r
+               for (vtkProp prop : actorToNode.keySet()) {\r
+                       if (prop.GetVTKId() != 0) \r
+                               prop.Delete();\r
+               }\r
+               actorToNode.clear();\r
+               nodeToActor.clear();\r
+               \r
+       }\r
+       \r
+       \r
+       private List<NodeListener> nodeListeners = new ArrayList<NodeListener>();\r
+       @Override\r
+       public void addListener(NodeListener listener) {\r
+               nodeListeners.add(listener);\r
+               \r
+       }\r
+       \r
+       @Override\r
+       public void removeListener(NodeListener listener) {\r
+               nodeListeners.remove(listener);\r
+               \r
+       }\r
+       \r
+       public IMapping<Object,E> getMapping() {\r
+               return mapping;\r
+       }\r
+       \r
+       \r
+}\r
diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/ActorHighlighter.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/ActorHighlighter.java
new file mode 100644 (file)
index 0000000..92473f7
--- /dev/null
@@ -0,0 +1,10 @@
+package org.simantics.g3d.vtk.common;\r
+\r
+import org.simantics.g3d.scenegraph.NodeHighlighter.HighlightEventType;\r
+\r
+import vtk.vtkProp;\r
+\r
+public interface ActorHighlighter {\r
+\r
+       public void highlightActor(vtkProp prop, HighlightEventType type);\r
+}\r
diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/HoverHighlighter.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/HoverHighlighter.java
new file mode 100644 (file)
index 0000000..832a3b0
--- /dev/null
@@ -0,0 +1,44 @@
+package org.simantics.g3d.vtk.common;\r
+\r
+import org.eclipse.jface.viewers.ISelection;\r
+import org.simantics.g3d.scenegraph.IG3DNode;\r
+import org.simantics.g3d.scenegraph.NodeHighlighter;\r
+import org.simantics.g3d.scenegraph.NodeHighlighter.HighlightEventType;\r
+\r
+import vtk.vtkPanel;\r
+\r
+public class HoverHighlighter extends SelectionHighlighter {\r
+\r
+\r
+       public HoverHighlighter(vtkPanel panel, VTKNodeMap nodeMap) {\r
+               super(panel, nodeMap);\r
+               \r
+       }\r
+       \r
+       protected void highlight(ISelection s) {\r
+               highlight(s, HighlightEventType.Hover, HighlightEventType.ClearHover);\r
+       }\r
+       \r
+       protected void hilight(IG3DNode node, HighlightEventType type) {\r
+               if (node instanceof NodeHighlighter) {\r
+                       ((NodeHighlighter)node).highlight(type);\r
+                       return;\r
+               }\r
+               if (type == HighlightEventType.Hover) {\r
+                       setSelectedColor(node);\r
+               } else if (type == HighlightEventType.ClearHover) {\r
+                       setDefaultColor(node);\r
+               }\r
+       }\r
+\r
+       protected void setDefaultColor(IG3DNode node) {\r
+               double color[] = new double[]{0,0,0};\r
+               setColor(node, true, color);\r
+       }\r
+       \r
+       protected void setSelectedColor(IG3DNode node) {\r
+               double color[] = new double[]{1,0,1};\r
+               setColor(node, true, color);\r
+       }\r
+       \r
+}\r
diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/InteractiveVtkPanel.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/InteractiveVtkPanel.java
new file mode 100644 (file)
index 0000000..40fe6c6
--- /dev/null
@@ -0,0 +1,402 @@
+package org.simantics.g3d.vtk.common;\r
+\r
+import java.awt.event.KeyEvent;\r
+import java.awt.event.MouseEvent;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import org.simantics.g3d.scenegraph.RenderListener;\r
+import org.simantics.g3d.vtk.action.vtkAction;\r
+\r
+import vtk.vtkAbstractPicker;\r
+import vtk.vtkAreaPicker;\r
+import vtk.vtkAssemblyNode;\r
+import vtk.vtkAssemblyPath;\r
+import vtk.vtkCellPicker;\r
+import vtk.vtkGenericRenderWindowInteractor;\r
+import vtk.vtkInteractorStyleTrackballCamera;\r
+import vtk.vtkObjectBase;\r
+import vtk.vtkPanel;\r
+import vtk.vtkPointPicker;\r
+import vtk.vtkProp;\r
+import vtk.vtkProp3DCollection;\r
+import vtk.vtkPropCollection;\r
+import vtk.vtkPropPicker;\r
+import vtk.vtkScenePicker;\r
+\r
+public class InteractiveVtkPanel extends vtkPanel {\r
+       \r
+       protected vtkGenericRenderWindowInteractor iren;\r
+    \r
+\r
+       public vtkGenericRenderWindowInteractor getRenderWindowInteractor() {\r
+        return this.iren;\r
+    }\r
+       private static final long serialVersionUID = 2815073937537950615L;\r
+       \r
+       \r
+       public InteractiveVtkPanel() {\r
+               super();\r
+               iren = new vtkGenericRenderWindowInteractor();\r
+               iren.SetRenderWindow(rw);\r
+        iren.TimerEventResetsTimerOff();\r
+        iren.SetSize(200, 200);\r
+        iren.ConfigureEvent();\r
+        vtkInteractorStyleTrackballCamera style = new vtkInteractorStyleTrackballCamera();\r
+        iren.SetInteractorStyle(style);\r
+        addDeletable(style);\r
+        addDeletable(iren);\r
+       }\r
+       \r
+       @Override\r
+       public void mouseClicked(MouseEvent e) {\r
+\r
+       }\r
+       \r
+       @Override\r
+       public void mouseMoved(MouseEvent e) {\r
+\r
+       }\r
+       \r
+       @Override\r
+       public void mouseEntered(MouseEvent e) {\r
+               super.mouseEntered(e);\r
+       }\r
+       \r
+       @Override\r
+       public void mouseExited(MouseEvent e) {\r
+       \r
+       }\r
+       \r
+       @Override\r
+       public void mousePressed(MouseEvent e) {\r
+               \r
+       }\r
+       \r
+       @Override\r
+       public void mouseDragged(MouseEvent e) {\r
+               \r
+       }\r
+       \r
+       @Override\r
+       public void mouseReleased(MouseEvent e) {\r
+       \r
+       }\r
+       \r
+       @Override\r
+       public void keyPressed(KeyEvent e) {\r
+\r
+       }\r
+       \r
+       @Override\r
+       public void keyTyped(KeyEvent e) {\r
+               \r
+       }\r
+       \r
+       public void setSize(int x, int y) {\r
+        if (windowset == 1) {\r
+            Lock();\r
+            rw.SetSize(x, y);\r
+            iren.SetSize(x, y);\r
+            iren.ConfigureEvent();\r
+            UnLock();\r
+        }\r
+    }\r
+\r
+       private vtkScenePicker scenePicker;\r
+       \r
+       int pickType = 4;\r
+       \r
+       public int getPickType() {\r
+               return pickType;\r
+       }\r
+       \r
+       public void setPickType(int pickType) {\r
+               this.pickType = pickType;\r
+       }\r
+       \r
+       public vtkProp[] pick(int x, int y) {\r
+               \r
+               \r
+//             vtkPicker picker = new vtkPicker();\r
+//             vtkAbstractPicker picker = new vtkAbstractPicker();\r
+//             picker.Pick(x, rw.GetSize()[1] - y, ren);\r
+//             // see page 60 of VTK user's guide\r
+//\r
+               if (pickType == 0) {\r
+       \r
+                       vtkPropPicker picker = new vtkPropPicker();\r
+                       Lock();\r
+                       picker.PickProp(x, rw.GetSize()[1] - y, ren);\r
+       \r
+                       UnLock();\r
+       \r
+                       vtkAssemblyPath apath = picker.GetPath();\r
+                       return processPick(picker, apath);\r
+                       \r
+               } else if (pickType == 1) {\r
+                       if (scenePicker == null) {\r
+                               scenePicker = new vtkScenePicker();\r
+                               scenePicker.SetRenderer(ren);\r
+                               scenePicker.EnableVertexPickingOn();\r
+                               \r
+                       }\r
+                       Lock();\r
+\r
+                       vtkAssemblyPath apath = ren.PickProp(x, rw.GetSize()[1] - y);\r
+                       //int vertexId = scenePicker.GetVertexId(new int[]{x, rw.GetSize()[1] - y});\r
+                       \r
+                       UnLock();\r
+                       \r
+                       if (apath != null) {\r
+                               apath.InitTraversal();\r
+//                             System.out.println("Pick, actors " + apath.GetNumberOfItems() );\r
+//                             for (int i = 0; i < apath.GetNumberOfItems(); i++) {\r
+//                                     vtkAssemblyNode node = apath.GetNextNode();\r
+//                                     vtkProp test = (vtkProp) node.GetViewProp();\r
+//                                     System.out.println(test.GetClassName());\r
+//                             }\r
+                               \r
+                               vtkAssemblyNode node = apath.GetLastNode();\r
+                               vtkProp test = (vtkProp) node.GetViewProp();\r
+                               apath.Delete();\r
+                               node.Delete();\r
+                               return new vtkProp[]{test};\r
+       \r
+                       }\r
+                       \r
+               } else if (pickType == 2) {\r
+                       vtkPointPicker picker = new vtkPointPicker();\r
+                       picker.SetTolerance(2.0/(double)rw.GetSize()[0]);\r
+                       Lock();\r
+                       picker.Pick(new double[]{x, rw.GetSize()[1] - y,0}, ren);\r
+                       UnLock();\r
+                       \r
+                       vtkAssemblyPath apath = picker.GetPath();\r
+                       return processPick(picker, apath);\r
+               } else if (pickType == 3) {\r
+                       vtkAreaPicker picker = new vtkAreaPicker();\r
+                       Lock();\r
+                       picker.Pick(new double[]{x, rw.GetSize()[1] - y,0}, ren);\r
+                       //picker.AreaPick(x-1, rw.GetSize()[1] - y-1,x+1,rw.GetSize()[1] - y+1, ren);\r
+                       UnLock();\r
+                       vtkAssemblyPath apath = picker.GetPath();\r
+                       return processPick(picker, apath);\r
+               } else if (pickType == 4) {\r
+                       vtkCellPicker picker = new vtkCellPicker();\r
+                       picker.SetTolerance(2.0/(double)rw.GetSize()[0]);\r
+                       Lock();\r
+                       picker.Pick(new double[]{x, rw.GetSize()[1] - y,0}, ren);\r
+                       UnLock();       \r
+                       vtkAssemblyPath apath = picker.GetPath();\r
+                       return processPick(picker, apath);\r
+               }\r
+\r
+               return null;\r
+       }\r
+       \r
+       public vtkProp[] pick2(int x, int y) {\r
+               \r
+               \r
+//             vtkPicker picker = new vtkPicker();\r
+//             vtkAbstractPicker picker = new vtkAbstractPicker();\r
+//             picker.Pick(x, rw.GetSize()[1] - y, ren);\r
+//             // see page 60 of VTK user's guide\r
+//\r
+               if (pickType == 0) {\r
+       \r
+                       vtkPropPicker picker = new vtkPropPicker();\r
+                       Lock();\r
+                       picker.PickProp(x, rw.GetSize()[1] - y, ren);\r
+       \r
+                       UnLock();\r
+                       vtkPropCollection coll = picker.GetPickList();\r
+                       return processPick(picker, coll);\r
+                       \r
+               } else if (pickType == 1) {\r
+                       if (scenePicker == null) {\r
+                               scenePicker = new vtkScenePicker();\r
+                               scenePicker.SetRenderer(ren);\r
+                               scenePicker.EnableVertexPickingOn();\r
+                               \r
+                       }\r
+                       Lock();\r
+\r
+                       \r
+                       vtkAssemblyPath apath = ren.PickProp(x, rw.GetSize()[1] - y);\r
+                       \r
+                       UnLock();\r
+                       \r
+                       if (apath != null) {\r
+                               apath.InitTraversal();\r
+\r
+                               \r
+                               vtkAssemblyNode node = apath.GetLastNode();\r
+                               vtkProp test = (vtkProp) node.GetViewProp();\r
+                               apath.Delete();\r
+                               node.Delete();\r
+                               return new vtkProp[]{test};\r
+       \r
+                       }\r
+                       \r
+               } else if (pickType == 2) {\r
+                       vtkPointPicker picker = new vtkPointPicker();\r
+                       picker.SetTolerance(2.0/(double)rw.GetSize()[0]);\r
+                       Lock();\r
+                       picker.Pick(new double[]{x, rw.GetSize()[1] - y,0}, ren);\r
+                       UnLock();\r
+                       vtkProp3DCollection coll = picker.GetProp3Ds();\r
+                       return processPick(picker, coll);\r
+               } else if (pickType == 3) {\r
+                       vtkAreaPicker picker = new vtkAreaPicker();\r
+                       Lock();\r
+                       picker.Pick(new double[]{x, rw.GetSize()[1] - y,0}, ren);\r
+                       //picker.AreaPick(x-1, rw.GetSize()[1] - y-1,x+1,rw.GetSize()[1] - y+1, ren);\r
+                       UnLock();\r
+                       vtkProp3DCollection coll = picker.GetProp3Ds();\r
+                       return processPick(picker, coll);\r
+               } else if (pickType == 4) {\r
+                       vtkCellPicker picker = new vtkCellPicker();\r
+                       picker.SetTolerance(2.0/(double)rw.GetSize()[0]);\r
+                       Lock();\r
+                       picker.Pick(new double[]{x, rw.GetSize()[1] - y,0}, ren);\r
+                       UnLock();       \r
+                       vtkProp3DCollection coll = picker.GetProp3Ds();\r
+                       return processPick(picker, coll);\r
+               }\r
+\r
+               return null;\r
+       }\r
+       \r
+       private vtkProp[] processPick(vtkAbstractPicker picker, vtkAssemblyPath apath) {\r
+//             double[] pickPos = picker.GetPickPosition();\r
+               picker.Delete();\r
+               if (apath != null) {\r
+                       apath.InitTraversal();\r
+                       vtkProp result[] = new vtkProp[apath.GetNumberOfItems()];\r
+                       for (int i = apath.GetNumberOfItems()-1; i >= 0; i--) {\r
+                               vtkAssemblyNode node = apath.GetNextNode();\r
+                               vtkProp test = (vtkProp) node.GetViewProp();\r
+//                             System.out.println("Picked: " + test.GetClassName() + " " + test.GetVTKId());\r
+                               result[i] = test;\r
+                               node.Delete();\r
+                       }\r
+                       apath.Delete();\r
+                       return result;\r
+\r
+               }\r
+               return null;\r
+       }\r
+       \r
+       private vtkProp[] processPick(vtkAbstractPicker picker, vtkPropCollection coll) {\r
+//             double[] pickPos = picker.GetPickPosition();\r
+               picker.Delete();\r
+               if (coll != null) {\r
+                       coll.InitTraversal();\r
+                       vtkProp result[] = new vtkProp[coll.GetNumberOfItems()];\r
+                       for (int i = coll.GetNumberOfItems()-1; i >= 0; i--) {\r
+                               vtkProp test = coll.GetNextProp();\r
+                               \r
+//                             System.out.println("Picked: " + test.GetClassName() + " " + test.GetVTKId());\r
+                               result[i] = test;\r
+                               \r
+                       }\r
+                       coll.Delete();\r
+                       return result;\r
+\r
+               }\r
+               return null;\r
+       }\r
+       \r
+       \r
+       private vtkAction defaultAction;\r
+       private vtkAction currentAction;\r
+       \r
+       public void setActiveAction(vtkAction action) {\r
+               if (action.equals(currentAction))\r
+                       return;\r
+               if (currentAction != null)\r
+                       currentAction.deattach();\r
+               currentAction = action;\r
+               if (action != null)\r
+                       action.attach();\r
+       }\r
+       \r
+       public void setDefaultAction(vtkAction defaultAction) {\r
+               this.defaultAction = defaultAction;\r
+       }\r
+       \r
+       public void useDefaultAction() {\r
+               setActiveAction(defaultAction);\r
+       }\r
+       \r
+       public vtkAction getDefaultAction() {\r
+               return defaultAction;\r
+       }\r
+       \r
+       \r
+       @Override\r
+       public synchronized void Render() {\r
+               //System.out.println("Render " + rendering);\r
+               if (rendering)\r
+                       return;\r
+               \r
+               firePreRender();\r
+               super.Render();\r
+               firePostRender();\r
+       }\r
+       \r
+       \r
+       public void addListener(RenderListener l) {\r
+               listeners.add(l);\r
+       }\r
+       \r
+       public void removeListener(RenderListener l) {\r
+               listeners.remove(l);\r
+       }\r
+       \r
+       private List<RenderListener> listeners = new ArrayList<RenderListener>();\r
+       \r
+       List<RenderListener> list = new ArrayList<RenderListener>();\r
+       \r
+       private void firePreRender() {\r
+               if (listeners.size() > 0) {\r
+                       list.addAll(listeners);\r
+                       for (RenderListener l : list)\r
+                               l.preRender();\r
+                       list.clear();\r
+               }\r
+       }\r
+       \r
+       private void firePostRender() {\r
+               if (listeners.size() > 0) {\r
+                       list.addAll(listeners);\r
+                       for (RenderListener l : list)\r
+                               l.postRender();\r
+                       list.clear();\r
+               }\r
+       }\r
+\r
+       \r
+       private List<vtkObjectBase> deletable = new ArrayList<vtkObjectBase>();\r
+       \r
+       public void addDeletable(vtkObjectBase o) {\r
+               deletable.add(o);\r
+       }\r
+       \r
+       public void removeDeletable (vtkObjectBase o) {\r
+               deletable.remove(o);\r
+       }\r
+       \r
+       @Override\r
+       public void Delete() {\r
+               for (vtkObjectBase o : deletable) {\r
+                       if (o.GetVTKId() != 0) {\r
+                               o.Delete();\r
+                       }\r
+               }\r
+               deletable.clear();\r
+               \r
+               super.Delete();\r
+       }\r
+}\r
diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/NodeSelectionProvider2.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/NodeSelectionProvider2.java
new file mode 100644 (file)
index 0000000..8c9347c
--- /dev/null
@@ -0,0 +1,144 @@
+package org.simantics.g3d.vtk.common;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.List;\r
+\r
+import org.eclipse.jface.viewers.ISelection;\r
+import org.eclipse.jface.viewers.ISelectionChangedListener;\r
+import org.eclipse.jface.viewers.ISelectionProvider;\r
+import org.eclipse.jface.viewers.SelectionChangedEvent;\r
+import org.eclipse.jface.viewers.StructuredSelection;\r
+import org.eclipse.ui.IEditorPart;\r
+import org.eclipse.ui.ISelectionListener;\r
+import org.eclipse.ui.IWorkbenchPart;\r
+import org.simantics.db.Resource;\r
+import org.simantics.g3d.scenegraph.IG3DNode;\r
+import org.simantics.g3d.scenegraph.base.INode;\r
+import org.simantics.g3d.tools.AdaptationUtils;\r
+import org.simantics.objmap.graph.IMapping;\r
+import org.simantics.objmap.structural.StructuralResource;\r
+\r
+import vtk.vtkProp;\r
+\r
+public class NodeSelectionProvider2<DBObject,JavaObject> implements ISelectionProvider, ISelectionChangedListener, ISelectionListener{\r
+       private ISelection selection = new StructuredSelection();\r
+       private List<ISelectionChangedListener> listeners = new ArrayList<ISelectionChangedListener>();\r
+       \r
+       List<IG3DNode> selectedNodes = new ArrayList<IG3DNode>(); // selection is ordered\r
+       //List<Resource> selectedResources = new ArrayList<Resource>();\r
+       List<VTKSelectionItem<DBObject>> selectedItems = new ArrayList<VTKSelectionItem<DBObject>>();\r
+       \r
+       IEditorPart part;\r
+       IMapping<DBObject,JavaObject> mapping;\r
+       VTKNodeMap nodeMap;\r
+       \r
+       public NodeSelectionProvider2(IEditorPart part, IMapping<DBObject,JavaObject> mapping, VTKNodeMap nodeMap) {\r
+               this.part = part;\r
+               this.mapping = mapping;\r
+               this.nodeMap = nodeMap;\r
+       }\r
+       \r
+       @Override\r
+       public void addSelectionChangedListener(\r
+                       ISelectionChangedListener listener) {\r
+               listeners.add(listener);\r
+       }\r
+       \r
+       @Override\r
+       public void removeSelectionChangedListener(\r
+                       ISelectionChangedListener listener) {\r
+               listeners.remove(listener);\r
+       }\r
+       \r
+       @Override\r
+       public ISelection getSelection() {\r
+               return selection;\r
+       }\r
+       \r
+       @Override\r
+       public void setSelection(ISelection selection) {\r
+               \r
+       }\r
+       \r
+       // events coming from vtk       \r
+       @Override\r
+       public void selectionChanged(SelectionChangedEvent event) {\r
+               ISelection s = event.getSelection();\r
+               \r
+               processSelection(s);\r
+               fireSelectionChanged(event.getSource());\r
+       }\r
+       \r
+       @SuppressWarnings("unchecked")\r
+       private void processSelection(ISelection s) {\r
+               selectedNodes.clear();\r
+               selectedItems.clear();\r
+               \r
+               Collection<vtkProp> selectedActors = AdaptationUtils.adaptToCollection(s, vtkProp.class);\r
+               if (selectedActors.size() > 0) {\r
+                       for (vtkProp a : selectedActors) {\r
+                               IG3DNode node = (IG3DNode)nodeMap.getNode((vtkProp)a);\r
+                               if (node == null)\r
+                                       continue;\r
+                               if (!selectedNodes.contains(node))\r
+                                       selectedNodes.add(node);\r
+                               DBObject r = mapping.inverseGet((JavaObject)node);\r
+                               selectedItems.add(new VTKSelectionItem<DBObject>(a, node,r));\r
+                       }\r
+               } else {\r
+                       Collection<IG3DNode> selectedNds = AdaptationUtils.adaptToCollection(s, IG3DNode.class);\r
+                       for (INode node : selectedNds) {\r
+                               if (!selectedNodes.contains(node))\r
+                                       selectedNodes.add((IG3DNode)node);\r
+                               DBObject r = mapping.inverseGet((JavaObject)node);\r
+                               selectedItems.add(new VTKSelectionItem<DBObject>(null, (IG3DNode)node,r));\r
+                       }\r
+               }\r
+               \r
+               \r
+               selection = new StructuredSelection(selectedItems);\r
+       }\r
+       \r
+       private void fireSelectionChanged(Object source) {\r
+               SelectionChangedEvent evt = new SelectionChangedEvent((ISelectionProvider)source, selection);\r
+               for (ISelectionChangedListener l : listeners) {\r
+                       l.selectionChanged(evt);\r
+               }\r
+       }\r
+       \r
+       \r
+       \r
+       // events coming from workbench\r
+       @Override\r
+       public void selectionChanged(IWorkbenchPart part, ISelection selection) {\r
+               if (part == this.part)\r
+                       return;\r
+               processSelection(selection);\r
+               \r
+       }\r
+       \r
+       public List<IG3DNode> getSelectedNodes() {\r
+               return selectedNodes;\r
+       }\r
+       \r
+       @SuppressWarnings("unchecked")\r
+       public List<DBObject> getSelectedResources() {\r
+               \r
+               List<DBObject> list = new ArrayList<DBObject>();\r
+               for (VTKSelectionItem<DBObject> i : selectedItems) {\r
+                       DBObject r = (DBObject)i.getAdapter(Resource.class);\r
+                       if (r == null)\r
+                               r = (DBObject)i.getAdapter(StructuralResource.class);\r
+                       if (r == null)\r
+                               continue;\r
+                       if (!list.contains(r))\r
+                               list.add(r);\r
+               }\r
+               return list;\r
+       }\r
+       \r
+       protected INode getNode(DBObject r) {\r
+               return (INode)mapping.get(r);\r
+       }\r
+}\r
diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/SelectionHighlighter.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/SelectionHighlighter.java
new file mode 100644 (file)
index 0000000..0cbcac2
--- /dev/null
@@ -0,0 +1,188 @@
+package org.simantics.g3d.vtk.common;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.List;\r
+\r
+import org.eclipse.jface.viewers.ISelection;\r
+import org.eclipse.jface.viewers.ISelectionChangedListener;\r
+import org.eclipse.jface.viewers.SelectionChangedEvent;\r
+import org.simantics.g3d.scenegraph.IG3DNode;\r
+import org.simantics.g3d.scenegraph.NodeHighlighter;\r
+import org.simantics.g3d.scenegraph.NodeHighlighter.HighlightEventType;\r
+import org.simantics.g3d.scenegraph.NodeHighlighter.HighlightObjectType;\r
+import org.simantics.g3d.scenegraph.base.INode;\r
+import org.simantics.g3d.tools.AdaptationUtils;\r
+import org.simantics.utils.threads.AWTThread;\r
+import org.simantics.utils.threads.ThreadUtils;\r
+\r
+import vtk.vtkActor;\r
+import vtk.vtkAlgorithm;\r
+import vtk.vtkAlgorithmOutput;\r
+import vtk.vtkFeatureEdges;\r
+import vtk.vtkMapper;\r
+import vtk.vtkPanel;\r
+import vtk.vtkProp;\r
+import vtk.vtkProperty;\r
+\r
+public class SelectionHighlighter implements ISelectionChangedListener{\r
+\r
+       \r
+       \r
+       vtkPanel panel;\r
+       VTKNodeMap nodeMap;\r
+       \r
+       List<IG3DNode> selectedNodes = new ArrayList<IG3DNode>();\r
+       List<vtkActor> selectedActors = new ArrayList<vtkActor>();\r
+       \r
+       HighlightObjectType type = HighlightObjectType.Node;\r
+       \r
+       public SelectionHighlighter(vtkPanel panel, VTKNodeMap nodeMap) {\r
+               this.panel = panel;\r
+               this.nodeMap = nodeMap;\r
+       }\r
+       \r
+       @Override\r
+       public void selectionChanged(SelectionChangedEvent event) {\r
+               final ISelection s = event.getSelection();\r
+               \r
+               if (Thread.currentThread().equals(AWTThread.getThreadAccess().getThread()))\r
+                       highlight(s);\r
+               else {\r
+                       ThreadUtils.asyncExec(AWTThread.getThreadAccess(), new Runnable() {\r
+                               @Override\r
+                               public void run() {\r
+                                       highlight(s);\r
+                                       //System.out.println(this.getClass().getName() + " highlight ");\r
+                                       panel.Render();\r
+                                       //panel.repaint();\r
+                               }\r
+                       });\r
+               }\r
+                       \r
+       }\r
+       \r
+       protected void hilight(IG3DNode node, HighlightEventType type) {\r
+               if (node instanceof NodeHighlighter) {\r
+                       ((NodeHighlighter)node).highlight(type);\r
+                       return;\r
+               }\r
+               if (type == HighlightEventType.Selection) {\r
+                       setSelectedColor(node); \r
+               } else if (type == HighlightEventType.ClearSelection) {\r
+                       setDefaultColor(node);\r
+               }\r
+       }\r
+       \r
+       protected void hilight(vtkActor actor, HighlightEventType type) {\r
+               if (type == HighlightEventType.Selection) {\r
+                       setColor(actor,false,new double[]{1,0,0});\r
+                       setColor(actor,true,new double[]{1,0,1});\r
+               } else if (type == HighlightEventType.ClearSelection) {\r
+                       setColor(actor,false,new double[]{1,1,0});\r
+                       setColor(actor,true,new double[]{0,0,0});\r
+               }\r
+       }\r
+       \r
+       protected void highlight(ISelection s) {\r
+               highlight(s, HighlightEventType.Selection, HighlightEventType.ClearSelection);\r
+       }\r
+       \r
+       protected void highlight(ISelection s, HighlightEventType apply, HighlightEventType clear) {\r
+       \r
+               boolean changed = false;\r
+               if (type == HighlightObjectType.Node) {\r
+                       Collection<IG3DNode> currentSelectedNodes = AdaptationUtils.adaptToCollection(s,IG3DNode.class);//getSelectedNodes(currentSelectedActors);\r
+                       if (currentSelectedNodes.size() == 0) {\r
+                               Collection<vtkProp> currentSelectedActors = AdaptationUtils.adaptToCollection(s, vtkProp.class);\r
+                               currentSelectedNodes = getSelectedNodes(currentSelectedActors);\r
+                       }\r
+                       for (IG3DNode node : selectedNodes) {\r
+                               if (!currentSelectedNodes.contains(node)) {\r
+                                       hilight(node, clear);\r
+                                       changed = true;\r
+                               }\r
+                       }\r
+                       for (IG3DNode node : currentSelectedNodes) {\r
+                               if (!selectedNodes.contains(node)) {\r
+                                       hilight(node, apply);\r
+                                       changed = true;\r
+                               }\r
+                       }\r
+                       selectedNodes.clear();\r
+                       selectedNodes.addAll(currentSelectedNodes);\r
+                       //selectedNodes = currentSelectedNodes;\r
+                       \r
+               } else {\r
+                       \r
+                       Collection<vtkActor> currentSelectedActors = AdaptationUtils.adaptToCollection(s, vtkActor.class);\r
+                       \r
+                       for (vtkActor act : selectedActors) {\r
+                               if (!currentSelectedActors.contains(act)) {\r
+                                       hilight(act,clear);\r
+                                       changed = true;\r
+                               }\r
+                       }\r
+                       for (vtkActor act : currentSelectedActors) {\r
+                               if (!selectedActors.contains(act)) {\r
+                                       hilight(act,apply);\r
+                                       changed = true;\r
+                               }\r
+                       }\r
+                       selectedActors.clear();\r
+                       selectedActors.addAll(currentSelectedActors);\r
+               }\r
+               if (changed) {\r
+                       panel.repaint();\r
+               }\r
+       }\r
+       \r
+       protected List<IG3DNode> getSelectedNodes(Collection<vtkProp> selectedActors) {\r
+               List<IG3DNode> currentSelectedNodes = new ArrayList<IG3DNode>();\r
+               \r
+               for (vtkProp a : selectedActors) {\r
+                       INode node = nodeMap.getNode((vtkProp)a);\r
+                       if (node == null || !(node instanceof IG3DNode))\r
+                               continue;\r
+                       if (!currentSelectedNodes.contains(node))\r
+                               currentSelectedNodes.add((IG3DNode)node);\r
+               }\r
+               return currentSelectedNodes;\r
+       }\r
+       \r
+       protected void setDefaultColor(IG3DNode node) {\r
+               double color[] = new double[]{1,1,0};\r
+               setColor(node, false, color);\r
+       }\r
+       \r
+       protected void setSelectedColor(IG3DNode node) {\r
+               double color[] = new double[]{1,0,0};\r
+               setColor(node, false, color);\r
+       }\r
+       \r
+       \r
+       protected void setColor(IG3DNode node, boolean edge, double color[]) {\r
+               for (vtkProp prop : nodeMap.getRenderObjects(node)) {\r
+                       if (prop instanceof vtkActor) {\r
+                               vtkActor act = (vtkActor)prop;\r
+                               setColor(act, edge, color);\r
+                       }\r
+               }\r
+       }\r
+       \r
+       protected void setColor(vtkActor act, boolean edge, double color[]) {\r
+               \r
+               vtkMapper mapper = act.GetMapper();\r
+               vtkAlgorithmOutput out = mapper.GetInputConnection(0, 0);\r
+               vtkAlgorithm producer = out.GetProducer();\r
+               boolean isEdge = (producer instanceof vtkFeatureEdges);\r
+               producer.Delete();\r
+               if (isEdge == edge) {\r
+                       vtkProperty property = act.GetProperty();\r
+                       property.SetColor(color);\r
+                       property.Delete();\r
+               }\r
+               out.Delete();\r
+               mapper.Delete();\r
+       }\r
+}\r
diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/VTKContentOutlinePage.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/VTKContentOutlinePage.java
new file mode 100644 (file)
index 0000000..7c64fec
--- /dev/null
@@ -0,0 +1,81 @@
+package org.simantics.g3d.vtk.common;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.List;\r
+\r
+import org.eclipse.jface.viewers.ISelection;\r
+import org.eclipse.jface.viewers.ISelectionChangedListener;\r
+import org.eclipse.jface.viewers.SelectionChangedEvent;\r
+import org.eclipse.jface.viewers.StructuredSelection;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.simantics.g3d.scenegraph.IG3DNode;\r
+import org.simantics.g3d.scenegraph.base.INode;\r
+import org.simantics.g3d.scenegraph.base.ParentNode;\r
+import org.simantics.g3d.tools.AdaptationUtils;\r
+import org.simantics.g3d.ui.ScenegraphOutlinePage;\r
+\r
+public class VTKContentOutlinePage<DBObject,JavaObject> extends ScenegraphOutlinePage{\r
+       private NodeSelectionProvider2<DBObject,JavaObject> provider;\r
+       \r
+       public VTKContentOutlinePage(ParentNode<? extends INode> rootNode, NodeSelectionProvider2<DBObject,JavaObject> provider) {\r
+               super(rootNode);\r
+               this.provider = provider;\r
+       }\r
+       \r
+       private boolean outsideSelection = false;\r
+       \r
+       @Override\r
+       public void createControl(Composite parent) {\r
+\r
+               super.createControl(parent);\r
+\r
+               provider.addSelectionChangedListener(new ISelectionChangedListener() {\r
+                       \r
+                       @Override\r
+                       public void selectionChanged(SelectionChangedEvent event) {\r
+                               Object source = event.getSource();\r
+                               if (source == VTKContentOutlinePage.this)\r
+                                       return;\r
+                               ISelection s = event.getSelection();\r
+                               Collection<INode> nodes = AdaptationUtils.adaptToCollection(s, INode.class);\r
+                               outsideSelection = true;\r
+                               getTreeViewer().setSelection(new StructuredSelection(nodes.toArray()),true);\r
+                               outsideSelection = false;\r
+                               \r
+                       }\r
+               });\r
+       }\r
+       \r
+       List<INode> selectedNodes = new ArrayList<INode>();\r
+       \r
+       @SuppressWarnings("unchecked")\r
+       @Override\r
+       protected void fireSelectionChanged(ISelection selection) {\r
+               if (outsideSelection)\r
+                       return;\r
+               // TreeViewer provides selected object in tree order, not in selected order.\r
+               Collection<INode> selectedUnsortedNodes = AdaptationUtils.adaptToCollection(selection, INode.class);\r
+               List<INode> toRemove = new ArrayList<INode>();\r
+               for (INode node : selectedNodes) {\r
+                       if (!selectedUnsortedNodes.contains(node))\r
+                               toRemove.add(node);\r
+               }\r
+               for (INode node : toRemove)\r
+                       selectedNodes.remove(node);\r
+               for (INode node : selectedUnsortedNodes) {\r
+                       if (!selectedNodes.contains(node))\r
+                               selectedNodes.add(node);\r
+               }\r
+               \r
+               List<VTKSelectionItem<DBObject>> selectedItems = new ArrayList<VTKSelectionItem<DBObject>>();\r
+               for (INode node : selectedNodes) {\r
+                       DBObject r = provider.mapping.inverseGet((JavaObject)node);\r
+                       selectedItems.add(new VTKSelectionItem<DBObject>(null, (IG3DNode)node, r));\r
+               }\r
+               \r
+               super.fireSelectionChanged(new StructuredSelection(selectedItems));\r
+       }\r
+       \r
+\r
+}\r
diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/VTKNodeMap.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/VTKNodeMap.java
new file mode 100644 (file)
index 0000000..055d037
--- /dev/null
@@ -0,0 +1,11 @@
+package org.simantics.g3d.vtk.common;\r
+\r
+import org.simantics.g3d.scenegraph.NodeMap;\r
+\r
+import vtk.vtkProp;\r
+\r
+public interface VTKNodeMap extends NodeMap<vtkProp>{\r
+\r
+       \r
+\r
+}\r
diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/VTKSelectionItem.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/VTKSelectionItem.java
new file mode 100644 (file)
index 0000000..5bbbebc
--- /dev/null
@@ -0,0 +1,95 @@
+package org.simantics.g3d.vtk.common;\r
+\r
+import org.eclipse.core.runtime.IAdaptable;\r
+import org.simantics.db.Resource;\r
+import org.simantics.g3d.scenegraph.IG3DNode;\r
+import org.simantics.g3d.scenegraph.base.INode;\r
+import org.simantics.objmap.structural.StructuralResource;\r
+\r
+import vtk.vtkProp;\r
+\r
+public class VTKSelectionItem<DBObject> implements IAdaptable{\r
+\r
+       private vtkProp prop;\r
+       private IG3DNode node;\r
+       private DBObject resource;\r
+\r
+       //private VTKpropSet actors;\r
+       \r
+       \r
+       public VTKSelectionItem(vtkProp prop, IG3DNode node, DBObject res) {\r
+               this.prop = prop;\r
+               this.node = node;\r
+               this.resource = res;\r
+       }\r
+       \r
+//     public VTKSelectionItem(Resource res, Collection<vtkProp> actors) {\r
+//             this.resource = res;\r
+//             this.actors = new VTKpropSet();\r
+//             this.actors.addAll(actors);\r
+//     }\r
+//     \r
+//     public VTKSelectionItem(Resource res, vtkProp... actors) {\r
+//             this.resource = res;\r
+//             this.actors = new VTKpropSet();\r
+//             for (vtkProp a : actors)\r
+//                     this.actors.add(a);\r
+//     }\r
+\r
+       @SuppressWarnings("rawtypes")\r
+       @Override\r
+       public Object getAdapter(Class adapter) {\r
+               if (adapter == Resource.class)\r
+                       if (resource instanceof Resource)\r
+                               return resource;\r
+                       else\r
+                               return null;\r
+               if (adapter == StructuralResource.class)\r
+                       if (resource instanceof StructuralResource)\r
+                               return resource;\r
+                       else\r
+                               return null;\r
+               if (adapter == vtkProp.class)\r
+                       return prop;\r
+               if (adapter == IG3DNode.class)\r
+                       return node;\r
+               if (adapter == INode.class)\r
+                       return node;\r
+               return null;\r
+       }\r
+       \r
+//     @SuppressWarnings("rawtypes")\r
+//     @Override\r
+//     public Object getAdapter(Class adapter) {\r
+//             if (adapter == Resource.class)\r
+//                     return resource;\r
+//             if (adapter == VTKpropSet.class)\r
+//                     return actors;\r
+//             return null;\r
+//     }\r
+       \r
+//     public Resource getResource() {\r
+//             return resource;\r
+//     }\r
+//     \r
+//     public VTKpropSet getActors() {\r
+//             return actors;\r
+//     }\r
+       \r
+       @SuppressWarnings("rawtypes")\r
+       @Override\r
+       public boolean equals(Object obj) {\r
+               if (obj == null)\r
+                       return false;\r
+               if (obj.getClass() != this.getClass())\r
+                       return false;\r
+               VTKSelectionItem other = (VTKSelectionItem)obj;\r
+               if (prop != null)\r
+                       return prop.equals(other.prop);\r
+               if (node != null)\r
+                       return node.equals(other.node);\r
+               return resource.equals(other.resource);\r
+               //return resource.equals(other.resource);\r
+                       \r
+       }\r
+}\r
diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/gizmo/RotateAxisGizmo.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/gizmo/RotateAxisGizmo.java
new file mode 100644 (file)
index 0000000..266a73c
--- /dev/null
@@ -0,0 +1,69 @@
+package org.simantics.g3d.vtk.gizmo;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.List;\r
+\r
+import javax.vecmath.Point3d;\r
+\r
+import org.simantics.g3d.vtk.action.RotateAction;\r
+import org.simantics.g3d.vtk.shape.vtkShape;\r
+\r
+import vtk.vtkActor;\r
+import vtk.vtkProp;\r
+\r
+public class RotateAxisGizmo extends vtkGizmo{\r
+       \r
+       private List<vtkProp> parts = new ArrayList<vtkProp>();\r
+       int type = -1;\r
+\r
+       \r
+       @Override\r
+       public Collection<vtkProp> getGizmo() {\r
+               for (vtkProp p : parts)\r
+                       p.Delete();\r
+               parts.clear();\r
+               double l = 100;\r
+               double w = 3;\r
+               switch (type) {\r
+               case RotateAction.X:{\r
+                       vtkActor lineActorX = vtkShape.createLineActor(new Point3d(-l,0,0), new Point3d(l,0,0));\r
+                       lineActorX.GetProperty().SetColor(1, 0, 0);\r
+                       lineActorX.GetProperty().SetLineWidth(w);\r
+                       lineActorX.GetProperty().Delete();\r
+                       parts.add(lineActorX);\r
+                       break;\r
+               }\r
+               case RotateAction.Y: {\r
+                       vtkActor lineActorY = vtkShape.createLineActor(new Point3d(0,-l,0), new Point3d(0,l,0));\r
+                       lineActorY.GetProperty().SetColor(0, 1, 0);\r
+                       lineActorY.GetProperty().SetLineWidth(w);\r
+                       lineActorY.GetProperty().Delete();\r
+                       parts.add(lineActorY);\r
+                       break;\r
+               }\r
+               case RotateAction.Z: {\r
+                       vtkActor lineActorZ = vtkShape.createLineActor(new Point3d(0,0,-l), new Point3d(0,0,l));\r
+                       lineActorZ.GetProperty().SetColor(0, 0, 1);\r
+                       lineActorZ.GetProperty().SetLineWidth(w);\r
+                       lineActorZ.GetProperty().Delete();\r
+                       parts.add(lineActorZ);\r
+                       break;\r
+               }\r
+               default: {\r
+                       \r
+               }\r
+               }\r
+               return parts;\r
+       }\r
+       \r
+       public void setType(int type) {\r
+               if (this.type == type)\r
+                       return;\r
+               this.type = type;\r
+               deattachActors();\r
+               attachActors();\r
+       }\r
+       \r
+\r
+}\r
diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/gizmo/TranslateAxisGizmo.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/gizmo/TranslateAxisGizmo.java
new file mode 100644 (file)
index 0000000..d563290
--- /dev/null
@@ -0,0 +1,108 @@
+package org.simantics.g3d.vtk.gizmo;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.List;\r
+\r
+import javax.vecmath.Point3d;\r
+\r
+import org.simantics.g3d.vtk.action.TranslateAction;\r
+import org.simantics.g3d.vtk.shape.vtkShape;\r
+\r
+import vtk.vtkActor;\r
+import vtk.vtkProp;\r
+\r
+public class TranslateAxisGizmo extends vtkGizmo{\r
+       \r
+       private List<vtkProp> parts = new ArrayList<vtkProp>();\r
+       int type = -1;\r
+\r
+       \r
+       @Override\r
+       public Collection<vtkProp> getGizmo() {\r
+               for (vtkProp p : parts)\r
+                       p.Delete();\r
+               parts.clear();\r
+               double l = 100;\r
+               double w = 3;\r
+               switch (type) {\r
+               case TranslateAction.X:{\r
+                       vtkActor lineActorX = vtkShape.createLineActor(new Point3d(-l,0,0), new Point3d(l,0,0));\r
+                       lineActorX.GetProperty().SetColor(1, 0, 0);\r
+                       lineActorX.GetProperty().SetLineWidth(w);\r
+                       lineActorX.GetProperty().Delete();\r
+                       parts.add(lineActorX);\r
+                       break;\r
+               }\r
+               case TranslateAction.Y: {\r
+                       vtkActor lineActorY = vtkShape.createLineActor(new Point3d(0,-l,0), new Point3d(0,l,0));\r
+                       lineActorY.GetProperty().SetColor(0, 1, 0);\r
+                       lineActorY.GetProperty().SetLineWidth(w);\r
+                       lineActorY.GetProperty().Delete();\r
+                       parts.add(lineActorY);\r
+                       break;\r
+               }\r
+               case TranslateAction.Z: {\r
+                       vtkActor lineActorZ = vtkShape.createLineActor(new Point3d(0,0,-l), new Point3d(0,0,l));\r
+                       lineActorZ.GetProperty().SetColor(0, 0, 1);\r
+                       lineActorZ.GetProperty().SetLineWidth(w);\r
+                       lineActorZ.GetProperty().Delete();\r
+                       parts.add(lineActorZ);\r
+                       break;\r
+               }\r
+               case TranslateAction.XY: {\r
+                       vtkActor lineActorX = vtkShape.createLineActor(new Point3d(-l,0,0), new Point3d(l,0,0));\r
+                       lineActorX.GetProperty().SetColor(1, 0, 0);\r
+                       lineActorX.GetProperty().SetLineWidth(w);\r
+                       lineActorX.GetProperty().Delete();\r
+                       parts.add(lineActorX);\r
+                       vtkActor lineActorY = vtkShape.createLineActor(new Point3d(0,-l,0), new Point3d(0,l,0));\r
+                       lineActorY.GetProperty().SetColor(0, 1, 0);\r
+                       lineActorY.GetProperty().SetLineWidth(w);\r
+                       lineActorY.GetProperty().Delete();\r
+                       parts.add(lineActorY);\r
+                       break;\r
+               }\r
+               case TranslateAction.XZ: {\r
+                       vtkActor lineActorX = vtkShape.createLineActor(new Point3d(-l,0,0), new Point3d(l,0,0));\r
+                       lineActorX.GetProperty().SetColor(1, 0, 0);\r
+                       lineActorX.GetProperty().Delete();\r
+                       parts.add(lineActorX);\r
+                       vtkActor lineActorZ = vtkShape.createLineActor(new Point3d(0,0,-l), new Point3d(0,0,l));\r
+                       lineActorZ.GetProperty().SetColor(0, 0, 1);\r
+                       lineActorZ.GetProperty().Delete();\r
+                       parts.add(lineActorZ);\r
+                       break;\r
+               }\r
+               case TranslateAction.YZ: {\r
+                       vtkActor lineActorY = vtkShape.createLineActor(new Point3d(0,-l,0), new Point3d(0,l,0));\r
+                       lineActorY.GetProperty().SetColor(0, 1, 0);\r
+                       lineActorY.GetProperty().SetLineWidth(w);\r
+                       lineActorY.GetProperty().Delete();\r
+                       parts.add(lineActorY);\r
+                       vtkActor lineActorZ = vtkShape.createLineActor(new Point3d(0,0,-l), new Point3d(0,0,l));\r
+                       lineActorZ.GetProperty().SetColor(0, 0, 1);\r
+                       lineActorZ.GetProperty().SetLineWidth(w);\r
+                       lineActorZ.GetProperty().Delete();\r
+                       parts.add(lineActorZ);\r
+                       break;\r
+               }\r
+               default: {\r
+                       \r
+               }\r
+               }\r
+               return parts;\r
+       }\r
+       \r
+       public void setType(int type) {\r
+               if (this.type == type)\r
+                       return;\r
+               this.type = type;\r
+               if (getRenderer() != null) {\r
+                       deattachActors();\r
+                       attachActors();\r
+               }\r
+       }\r
+       \r
+       \r
+}\r
diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/gizmo/TranslateGizmo.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/gizmo/TranslateGizmo.java
new file mode 100644 (file)
index 0000000..724452f
--- /dev/null
@@ -0,0 +1,372 @@
+package org.simantics.g3d.vtk.gizmo;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.List;\r
+\r
+import vtk.vtkActor;\r
+import vtk.vtkDataSetMapper;\r
+import vtk.vtkPoints;\r
+import vtk.vtkPolyData;\r
+import vtk.vtkProp;\r
+import vtk.vtkTriangle;\r
+\r
+public class TranslateGizmo extends vtkGizmo {\r
+       \r
+       \r
+       \r
+       private List<vtkProp> parts;\r
+       \r
+       @Override\r
+       public Collection<vtkProp> getGizmo() {\r
+               if (parts == null) {\r
+                       parts = new ArrayList<vtkProp>();\r
+               \r
+               \r
+                       float size = 2.f;               \r
+               float sizeD2 = 1.f;\r
+               float offset = 0.2f;\r
+                       \r
+               double[] colorX = new double[]{0.5,0.0,0.0};\r
+               double[] colorY = new double[]{0.0,0.5,0.0};\r
+               double[] colorZ = new double[]{0.0,0.0,0.5};\r
+               \r
+               double[] colorXY = add(colorX, colorY);\r
+               double[] colorXZ = add(colorX, colorZ);\r
+               double[] colorYZ = add(colorY, colorZ);\r
+               double[] colorP =  add(colorX,colorY,colorZ);\r
+               \r
+                       vtkActor actorX = new vtkActor();\r
+                       vtkActor actorY = new vtkActor();\r
+                       vtkActor actorZ = new vtkActor();\r
+                       vtkActor actorXY = new vtkActor();\r
+                       vtkActor actorXZ = new vtkActor();\r
+                       vtkActor actorYZ = new vtkActor();\r
+                       vtkActor actorP = new vtkActor();\r
+                       \r
+                       actorX.GetProperty().SetColor(colorX);\r
+                       actorY.GetProperty().SetColor(colorY);\r
+                       actorZ.GetProperty().SetColor(colorZ);\r
+                       actorXY.GetProperty().SetColor(colorXY);\r
+                       actorXZ.GetProperty().SetColor(colorXZ);\r
+                       actorYZ.GetProperty().SetColor(colorYZ);\r
+                       actorP.GetProperty().SetColor(colorP);\r
+                       \r
+                       actorX.GetProperty().SetOpacity(0.5);\r
+                       actorY.GetProperty().SetOpacity(0.5);\r
+                       actorZ.GetProperty().SetOpacity(0.5);\r
+                       actorXY.GetProperty().SetOpacity(0.5);\r
+                       actorXZ.GetProperty().SetOpacity(0.5);\r
+                       actorYZ.GetProperty().SetOpacity(0.5);\r
+                       actorP.GetProperty().SetOpacity(0.5);\r
+                       \r
+                       actorX.GetProperty().BackfaceCullingOff();\r
+                       actorY.GetProperty().BackfaceCullingOff();\r
+                       actorZ.GetProperty().BackfaceCullingOff();\r
+                       actorXY.GetProperty().BackfaceCullingOff();\r
+                       actorXZ.GetProperty().BackfaceCullingOff();\r
+                       actorYZ.GetProperty().BackfaceCullingOff();\r
+                       actorP.GetProperty().BackfaceCullingOff();\r
+                       \r
+                       actorX.SetPickable(1);\r
+                       actorY.SetPickable(1);\r
+                       actorZ.SetPickable(1);\r
+                       actorXY.SetPickable(1);\r
+                       actorXZ.SetPickable(1);\r
+                       actorYZ.SetPickable(1);\r
+                       actorP.SetPickable(1);\r
+                       \r
+                       \r
+                       actorX.GetProperty().LightingOff();\r
+                       actorY.GetProperty().LightingOff();\r
+                       actorZ.GetProperty().LightingOff();\r
+                       actorXY.GetProperty().LightingOff();\r
+                       actorXZ.GetProperty().LightingOff();\r
+                       actorYZ.GetProperty().LightingOff();\r
+                       actorP.GetProperty().LightingOff();\r
+                       \r
+\r
+                       vtkTriangle triangle = new vtkTriangle();\r
+                       \r
+                       // X\r
+                       vtkPolyData actorXData = new vtkPolyData();\r
+                       actorXData.Allocate(6, 6);\r
+                       \r
+                       triangle.GetPointIds().SetId(0, 0);\r
+                       triangle.GetPointIds().SetId(1, 1);\r
+                       triangle.GetPointIds().SetId(2, 3);\r
+                       actorXData.InsertNextCell(triangle.GetCellType(), triangle.GetPointIds());\r
+                       triangle.GetPointIds().SetId(0, 1);\r
+                       triangle.GetPointIds().SetId(1, 2);\r
+                       triangle.GetPointIds().SetId(2, 3);\r
+                       actorXData.InsertNextCell(triangle.GetCellType(), triangle.GetPointIds());\r
+                       triangle.GetPointIds().SetId(0, 0);\r
+                       triangle.GetPointIds().SetId(1, 3);\r
+                       triangle.GetPointIds().SetId(2, 5);\r
+                       actorXData.InsertNextCell(triangle.GetCellType(), triangle.GetPointIds());\r
+                       triangle.GetPointIds().SetId(0, 3);\r
+                       triangle.GetPointIds().SetId(1, 4);\r
+                       triangle.GetPointIds().SetId(2, 5);\r
+                       actorXData.InsertNextCell(triangle.GetCellType(), triangle.GetPointIds());\r
+                       \r
+                       vtkPoints partPoints = new vtkPoints();\r
+                       partPoints.InsertPoint(0, new double[]{size,0.,0.});\r
+                       partPoints.InsertPoint(1, new double[]{size-offset,offset,0.});\r
+                       partPoints.InsertPoint(2, new double[]{sizeD2-offset,offset,0.});\r
+                       partPoints.InsertPoint(3, new double[]{sizeD2,0.,0.});\r
+                       partPoints.InsertPoint(4, new double[]{sizeD2-offset,0.,offset});\r
+                       partPoints.InsertPoint(5, new double[]{size-offset,0.,offset});\r
+                       actorXData.SetPoints(partPoints);\r
+                       partPoints.Delete();\r
+                       \r
+                       // Y\r
+                       vtkPolyData actorYData = new vtkPolyData();\r
+                       actorYData.Allocate(6, 6);\r
+                       \r
+                       triangle.GetPointIds().SetId(0, 0);\r
+                       triangle.GetPointIds().SetId(1, 1);\r
+                       triangle.GetPointIds().SetId(2, 3);\r
+                       actorYData.InsertNextCell(triangle.GetCellType(), triangle.GetPointIds());\r
+                       triangle.GetPointIds().SetId(0, 1);\r
+                       triangle.GetPointIds().SetId(1, 2);\r
+                       triangle.GetPointIds().SetId(2, 3);\r
+                       actorYData.InsertNextCell(triangle.GetCellType(), triangle.GetPointIds());\r
+                       triangle.GetPointIds().SetId(0, 0);\r
+                       triangle.GetPointIds().SetId(1, 3);\r
+                       triangle.GetPointIds().SetId(2, 5);\r
+                       actorYData.InsertNextCell(triangle.GetCellType(), triangle.GetPointIds());\r
+                       triangle.GetPointIds().SetId(0, 3);\r
+                       triangle.GetPointIds().SetId(1, 4);\r
+                       triangle.GetPointIds().SetId(2, 5);\r
+                       actorYData.InsertNextCell(triangle.GetCellType(), triangle.GetPointIds());\r
+                       \r
+                       partPoints = new vtkPoints();\r
+                       partPoints.InsertPoint(0, new double[]{0., size, 0.});\r
+                       partPoints.InsertPoint(1, new double[]{offset, size - offset, 0.});\r
+                       partPoints.InsertPoint(2, new double[]{offset, sizeD2 - offset, 0.});\r
+                       partPoints.InsertPoint(3, new double[]{0., sizeD2, 0.});\r
+                       partPoints.InsertPoint(4, new double[]{0., sizeD2 - offset, offset});\r
+                       partPoints.InsertPoint(5, new double[]{0., size - offset, offset});\r
+                       actorYData.SetPoints(partPoints);\r
+                       partPoints.Delete();\r
+                       \r
+                       // Z\r
+                       vtkPolyData actorZData = new vtkPolyData();\r
+                       actorZData.Allocate(6, 6);\r
+                       \r
+                       triangle.GetPointIds().SetId(0, 0);\r
+                       triangle.GetPointIds().SetId(1, 1);\r
+                       triangle.GetPointIds().SetId(2, 3);\r
+                       actorZData.InsertNextCell(triangle.GetCellType(), triangle.GetPointIds());\r
+                       triangle.GetPointIds().SetId(0, 1);\r
+                       triangle.GetPointIds().SetId(1, 2);\r
+                       triangle.GetPointIds().SetId(2, 3);\r
+                       actorZData.InsertNextCell(triangle.GetCellType(), triangle.GetPointIds());\r
+                       triangle.GetPointIds().SetId(0, 0);\r
+                       triangle.GetPointIds().SetId(1, 3);\r
+                       triangle.GetPointIds().SetId(2, 5);\r
+                       actorZData.InsertNextCell(triangle.GetCellType(), triangle.GetPointIds());\r
+                       triangle.GetPointIds().SetId(0, 3);\r
+                       triangle.GetPointIds().SetId(1, 4);\r
+                       triangle.GetPointIds().SetId(2, 5);\r
+                       actorZData.InsertNextCell(triangle.GetCellType(), triangle.GetPointIds());\r
+                       \r
+                       partPoints = new vtkPoints();\r
+                       partPoints.InsertPoint(0, new double[]{0., 0.,size});\r
+                       partPoints.InsertPoint(1, new double[]{offset, 0., size - offset});\r
+                       partPoints.InsertPoint(2, new double[]{offset, 0., sizeD2 - offset});\r
+                       partPoints.InsertPoint(3, new double[]{0., 0., sizeD2});\r
+                       partPoints.InsertPoint(4, new double[]{0., offset, sizeD2 - offset});\r
+                       partPoints.InsertPoint(5, new double[]{0., offset, size - offset});\r
+                       actorZData.SetPoints(partPoints);\r
+                       partPoints.Delete();\r
+                       \r
+                       // XY\r
+                       vtkPolyData actorXYData = new vtkPolyData();\r
+                       actorXYData.Allocate(4, 4);\r
+                       \r
+                       triangle.GetPointIds().SetId(0, 2);\r
+                       triangle.GetPointIds().SetId(1, 1);\r
+                       triangle.GetPointIds().SetId(2, 3);\r
+                       actorXYData.InsertNextCell(triangle.GetCellType(), triangle.GetPointIds());\r
+                       triangle.GetPointIds().SetId(0, 0);\r
+                       triangle.GetPointIds().SetId(1, 1);\r
+                       triangle.GetPointIds().SetId(2, 3);\r
+                       actorXYData.InsertNextCell(triangle.GetCellType(), triangle.GetPointIds());\r
+                       \r
+                       partPoints = new vtkPoints();\r
+                       partPoints.InsertPoint(0, new double[]{offset, size-offset, 0.f});\r
+                       partPoints.InsertPoint(1, new double[]{offset, sizeD2 - offset, 0.f});\r
+                       partPoints.InsertPoint(2, new double[]{sizeD2 - offset, offset, 0.f});\r
+                       partPoints.InsertPoint(3, new double[]{size-offset, offset, 0.f});\r
+                       actorXYData.SetPoints(partPoints);\r
+                       partPoints.Delete();\r
+                       \r
+                       // XZ\r
+                       vtkPolyData actorXZData = new vtkPolyData();\r
+                       actorXZData.Allocate(4, 4);\r
+                       \r
+                       triangle.GetPointIds().SetId(0, 2);\r
+                       triangle.GetPointIds().SetId(1, 1);\r
+                       triangle.GetPointIds().SetId(2, 3);\r
+                       actorXZData.InsertNextCell(triangle.GetCellType(), triangle.GetPointIds());\r
+                       triangle.GetPointIds().SetId(0, 0);\r
+                       triangle.GetPointIds().SetId(1, 1);\r
+                       triangle.GetPointIds().SetId(2, 3);\r
+                       actorXZData.InsertNextCell(triangle.GetCellType(), triangle.GetPointIds());\r
+                       \r
+                       partPoints = new vtkPoints();\r
+                       partPoints.InsertPoint(0, new double[]{offset, 0.f, size-offset});\r
+                       partPoints.InsertPoint(1, new double[]{offset, 0.f, sizeD2 - offset});\r
+                       partPoints.InsertPoint(2, new double[]{sizeD2 - offset, 0.f, offset});\r
+                       partPoints.InsertPoint(3, new double[]{size-offset, 0.f, offset});\r
+                       actorXZData.SetPoints(partPoints);\r
+                       partPoints.Delete();\r
+                       \r
+                       // YZ\r
+                       vtkPolyData actorYZData = new vtkPolyData();\r
+                       actorYZData.Allocate(4, 4);\r
+                       \r
+                       triangle.GetPointIds().SetId(0, 2);\r
+                       triangle.GetPointIds().SetId(1, 1);\r
+                       triangle.GetPointIds().SetId(2, 3);\r
+                       actorYZData.InsertNextCell(triangle.GetCellType(), triangle.GetPointIds());\r
+                       triangle.GetPointIds().SetId(0, 0);\r
+                       triangle.GetPointIds().SetId(1, 1);\r
+                       triangle.GetPointIds().SetId(2, 3);\r
+                       actorYZData.InsertNextCell(triangle.GetCellType(), triangle.GetPointIds());\r
+                       \r
+                       partPoints = new vtkPoints();\r
+                       partPoints.InsertPoint(0, new double[]{0.f,offset, size-offset});\r
+                       partPoints.InsertPoint(1, new double[]{0.f,offset, sizeD2 - offset});\r
+                       partPoints.InsertPoint(2, new double[]{0.f,sizeD2 - offset, offset});\r
+                       partPoints.InsertPoint(3, new double[]{0.f,size-offset, offset});\r
+                       \r
+                       actorYZData.SetPoints(partPoints);\r
+                       partPoints.Delete();\r
+                       \r
+                       vtkPolyData actorPData = new vtkPolyData();\r
+                       actorPData.Allocate(10, 10);\r
+                       \r
+                       triangle.GetPointIds().SetId(0, 0);\r
+                       triangle.GetPointIds().SetId(1, 1);\r
+                       triangle.GetPointIds().SetId(2, 2);\r
+                       actorPData.InsertNextCell(triangle.GetCellType(), triangle.GetPointIds());\r
+                       triangle.GetPointIds().SetId(0, 0);\r
+                       triangle.GetPointIds().SetId(1, 2);\r
+                       triangle.GetPointIds().SetId(2, 3);\r
+                       actorPData.InsertNextCell(triangle.GetCellType(), triangle.GetPointIds());\r
+                       triangle.GetPointIds().SetId(0, 0);\r
+                       triangle.GetPointIds().SetId(1, 3);\r
+                       triangle.GetPointIds().SetId(2, 4);\r
+                       actorPData.InsertNextCell(triangle.GetCellType(), triangle.GetPointIds());\r
+                       triangle.GetPointIds().SetId(0, 0);\r
+                       triangle.GetPointIds().SetId(1, 4);\r
+                       triangle.GetPointIds().SetId(2, 5);\r
+                       actorPData.InsertNextCell(triangle.GetCellType(), triangle.GetPointIds());\r
+                       triangle.GetPointIds().SetId(0, 0);\r
+                       triangle.GetPointIds().SetId(1, 5);\r
+                       triangle.GetPointIds().SetId(2, 6);\r
+                       actorPData.InsertNextCell(triangle.GetCellType(), triangle.GetPointIds());\r
+                       triangle.GetPointIds().SetId(0, 0);\r
+                       triangle.GetPointIds().SetId(1, 6);\r
+                       triangle.GetPointIds().SetId(2, 7);\r
+                       actorPData.InsertNextCell(triangle.GetCellType(), triangle.GetPointIds());\r
+                       triangle.GetPointIds().SetId(0, 0);\r
+                       triangle.GetPointIds().SetId(1, 7);\r
+                       triangle.GetPointIds().SetId(2, 8);\r
+                       actorPData.InsertNextCell(triangle.GetCellType(), triangle.GetPointIds());\r
+                       triangle.GetPointIds().SetId(0, 0);\r
+                       triangle.GetPointIds().SetId(1, 8);\r
+                       triangle.GetPointIds().SetId(2, 9);\r
+                       actorPData.InsertNextCell(triangle.GetCellType(), triangle.GetPointIds());\r
+                       triangle.GetPointIds().SetId(0, 0);\r
+                       triangle.GetPointIds().SetId(1, 9);\r
+                       triangle.GetPointIds().SetId(2, 1);\r
+                       actorPData.InsertNextCell(triangle.GetCellType(), triangle.GetPointIds());\r
+                       \r
+                       partPoints = new vtkPoints();\r
+                       partPoints.InsertPoint(0, new double[]{0.f, 0.f, 0.f});\r
+                       partPoints.InsertPoint(1, new double[]{sizeD2, 0.f, 0.f});\r
+                       partPoints.InsertPoint(2, new double[]{sizeD2 - offset, offset, 0.f});\r
+                       partPoints.InsertPoint(3, new double[]{offset, sizeD2 - offset, 0.f});\r
+                       partPoints.InsertPoint(4, new double[]{0.f, sizeD2, 0.f});\r
+                       partPoints.InsertPoint(5, new double[]{0.f, sizeD2 - offset, offset});\r
+                       partPoints.InsertPoint(6, new double[]{0.f, offset, sizeD2-offset});\r
+                       partPoints.InsertPoint(7, new double[]{0.f, 0.f, sizeD2});\r
+                       partPoints.InsertPoint(8, new double[]{offset, 0.f, sizeD2-offset});\r
+                       partPoints.InsertPoint(9, new double[]{sizeD2-offset, 0.f, offset});\r
+                       actorPData.SetPoints(partPoints);\r
+                       partPoints.Delete();\r
+                       \r
+                       \r
+                       vtkDataSetMapper partMapper = new vtkDataSetMapper();\r
+                       partMapper.SetInput(actorXData);\r
+                       partMapper.ScalarVisibilityOn();\r
+                       actorX.SetMapper(partMapper);\r
+                       partMapper.Delete();\r
+                       \r
+                       partMapper = new vtkDataSetMapper();\r
+                       partMapper.SetInput(actorYData);\r
+                       partMapper.ScalarVisibilityOn();\r
+                       actorY.SetMapper(partMapper);\r
+                       partMapper.Delete();\r
+                       \r
+                       partMapper = new vtkDataSetMapper();\r
+                       partMapper.SetInput(actorZData);\r
+                       partMapper.ScalarVisibilityOn();\r
+                       actorZ.SetMapper(partMapper);\r
+                       partMapper.Delete();\r
+                       \r
+                       partMapper = new vtkDataSetMapper();\r
+                       partMapper.SetInput(actorXYData);\r
+                       partMapper.ScalarVisibilityOn();\r
+                       actorXY.SetMapper(partMapper);\r
+                       partMapper.Delete();\r
+                       \r
+                       partMapper = new vtkDataSetMapper();\r
+                       partMapper.SetInput(actorXZData);\r
+                       partMapper.ScalarVisibilityOn();\r
+                       actorXZ.SetMapper(partMapper);\r
+                       partMapper.Delete();\r
+                       \r
+                       partMapper = new vtkDataSetMapper();\r
+                       partMapper.SetInput(actorYZData);\r
+                       partMapper.ScalarVisibilityOn();\r
+                       actorYZ.SetMapper(partMapper);\r
+                       partMapper.Delete();\r
+                       \r
+                       partMapper = new vtkDataSetMapper();\r
+                       partMapper.SetInput(actorPData);\r
+                       partMapper.ScalarVisibilityOn();\r
+                       actorP.SetMapper(partMapper);\r
+                       partMapper.Delete();\r
+                       \r
+                       \r
+                       actorXData.Delete();\r
+                       actorYData.Delete();\r
+                       actorZData.Delete();\r
+                       actorXYData.Delete();\r
+                       actorXZData.Delete();\r
+                       actorYZData.Delete();\r
+                       actorPData.Delete();\r
+                       \r
+                       parts.add(actorX);\r
+                       parts.add(actorY);\r
+                       parts.add(actorZ);\r
+                       parts.add(actorXY);\r
+                       parts.add(actorXZ);\r
+                       parts.add(actorYZ);\r
+                       parts.add(actorP);\r
+               }\r
+               return parts;\r
+       }\r
+       \r
+       public int getTranslateAxis(vtkActor actor) {\r
+               if (actor == null)\r
+                       return -1;\r
+               return parts.indexOf(actor);\r
+       }\r
+       \r
+\r
+}\r
diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/gizmo/vtkGizmo.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/gizmo/vtkGizmo.java
new file mode 100644 (file)
index 0000000..e559a71
--- /dev/null
@@ -0,0 +1,132 @@
+package org.simantics.g3d.vtk.gizmo;\r
+\r
+import java.util.Collection;\r
+\r
+import javax.vecmath.AxisAngle4d;\r
+import javax.vecmath.Tuple3d;\r
+import javax.vecmath.Vector3d;\r
+\r
+import org.simantics.g3d.gizmo.Gizmo;\r
+import org.simantics.g3d.math.MathTools;\r
+\r
+import vtk.vtkProp;\r
+import vtk.vtkProp3D;\r
+import vtk.vtkRenderer;\r
+\r
+public abstract class vtkGizmo implements Gizmo<vtkProp> {\r
+\r
+       private vtkRenderer ren1;\r
+       private Collection<vtkProp> gizmo;\r
+       \r
+       private Tuple3d position;\r
+       private AxisAngle4d orientation;\r
+       private Tuple3d scale;\r
+       \r
+       @Override\r
+       public void attach(Object renderingPart) {\r
+               if (ren1 != null)\r
+                       throw new RuntimeException("Gizmo is attached");\r
+               ren1 = (vtkRenderer)renderingPart;\r
+               attachActors();\r
+       }\r
+       \r
+       @Override\r
+       public void deattach() {\r
+               if (ren1 == null)\r
+                       throw new RuntimeException("Gizmo is not attached");\r
+               deattachActors();\r
+               ren1 = null;\r
+       }\r
+       \r
+       public boolean isAttached() {\r
+               return (ren1 != null);\r
+       }\r
+       \r
+       protected void attachActors() {\r
+               gizmo = getGizmo();\r
+               for (vtkProp p : gizmo) {\r
+                       ren1.AddActor(p);\r
+               }\r
+               if (position != null)\r
+                       setPosition(position);\r
+               if (orientation != null)\r
+                       setRotation(orientation);\r
+               if (scale != null)\r
+                       setScale(scale);\r
+       }\r
+       \r
+       protected void deattachActors() {\r
+               for (vtkProp p : gizmo) {\r
+                       ren1.RemoveActor(p);\r
+               }\r
+       }\r
+       \r
+       @Override\r
+       public boolean isPartOf(vtkProp pickedObject) {\r
+               for (vtkProp prop : gizmo) {\r
+                       if (prop.equals(pickedObject))\r
+                               return true;\r
+               }\r
+               return false;\r
+       }\r
+       \r
+        public void setPosition(Tuple3d position) {\r
+                this.position = position;\r
+                for (vtkProp p : gizmo) {\r
+                        ((vtkProp3D)p).SetPosition(position.x, position.y, position.z);\r
+                }\r
+        }\r
+        \r
+        public void setRotation(AxisAngle4d q) {\r
+                this.orientation = q;\r
+                for (vtkProp p : gizmo) {\r
+                        ((vtkProp3D)p).SetOrientation(0,0,0);\r
+                        ((vtkProp3D)p).RotateWXYZ(MathTools.radToDeg(q.angle), q.x, q.y, q.z);\r
+                }\r
+        }\r
+       \r
+        \r
+        public void setScale(Tuple3d s) {\r
+                this.scale = s;\r
+                for (vtkProp p : gizmo) {\r
+                        ((vtkProp3D)p).SetScale(s.x, s.y, s.z);\r
+                }\r
+        }\r
+        \r
+        public void setScale(double s) {\r
+                this.scale = new Vector3d(s,s,s);\r
+                for (vtkProp p : gizmo) {\r
+                        ((vtkProp3D)p).SetScale(s, s, s);\r
+                }\r
+        }\r
+       \r
+       public abstract Collection<vtkProp> getGizmo();\r
+       \r
+//     public double[] add(double[] color1, double[] color2) {\r
+//             double[] result = new double[]{color1[0]+color2[0],color1[1],+color2[1],color1[2]+color2[2]};\r
+//             return result;\r
+//     }\r
+//     \r
+//     public double[] add(double[] color1, double[] color2, double[] color3) {\r
+//             double[] result = new double[]{color1[0]+color2[0]+color3[0],color1[1],+color2[1]+color3[1],color1[2]+color2[2]+color3[2]};\r
+//             return result;\r
+//     }\r
+       \r
+       public double[] add(double[]... color) {\r
+               double result[] = new double[]{0,0,0};\r
+               for (double c[] : color) {\r
+                       for (int i = 0; i < 3; i++)\r
+                               result[i] += c[i];\r
+               }\r
+               \r
+               return result;\r
+       }\r
+       \r
+       \r
+       public vtkRenderer getRenderer() {\r
+               return ren1;\r
+       }\r
+       \r
+       \r
+       \r
+}\r
diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/handlers/CameraPositionHandler.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/handlers/CameraPositionHandler.java
new file mode 100644 (file)
index 0000000..da31a24
--- /dev/null
@@ -0,0 +1,66 @@
+package org.simantics.g3d.vtk.handlers;\r
+\r
+import java.util.HashMap;\r
+import java.util.Map;\r
+\r
+import javax.vecmath.Vector3d;\r
+\r
+import org.eclipse.core.commands.AbstractHandler;\r
+import org.eclipse.core.commands.ExecutionEvent;\r
+import org.eclipse.core.commands.ExecutionException;\r
+import org.eclipse.ui.IWorkbenchPart;\r
+import org.eclipse.ui.handlers.HandlerUtil;\r
+import org.simantics.g3d.vtk.common.InteractiveVtkPanel;\r
+import org.simantics.utils.threads.AWTThread;\r
+import org.simantics.utils.threads.ThreadUtils;\r
+\r
+public class CameraPositionHandler extends AbstractHandler {\r
+\r
+       \r
+       private Map<InteractiveVtkPanel,Vector3d> cameraPos = new HashMap<InteractiveVtkPanel, Vector3d>();\r
+       \r
+       @Override\r
+       public Object execute(ExecutionEvent event) throws ExecutionException {\r
+            \r
+            final IWorkbenchPart ap = HandlerUtil.getActiveEditor(event);\r
+            final InteractiveVtkPanel panel = (InteractiveVtkPanel)ap.getAdapter(InteractiveVtkPanel.class);\r
+            \r
+            String param = event.getParameter("org.simantics.g3d.viewDirection");\r
+            String vals[] = param.split(",");\r
+            final Vector3d direction = new Vector3d(Double.parseDouble(vals[0]),Double.parseDouble(vals[1]),Double.parseDouble(vals[2]));\r
+\r
+            \r
+            ThreadUtils.asyncExec(AWTThread.getThreadAccess(), new Runnable() {\r
+                       \r
+                       @Override\r
+                       public void run() {\r
+\r
+                               Vector3d focal = new Vector3d(panel.GetRenderer().GetActiveCamera().GetFocalPoint());\r
+                               Vector3d pos = new Vector3d(panel.GetRenderer().GetActiveCamera().GetPosition());\r
+                               cameraPos.put(panel, pos);\r
+                               Vector3d dir = new Vector3d(pos);\r
+                               dir.sub(focal);\r
+                               double distance = dir.length();\r
+                               \r
+                               dir.set(direction);\r
+                               dir.scale(distance);\r
+                               dir.add(focal);\r
+                               panel.GetRenderer().GetActiveCamera().SetPosition(dir.x, dir.y, dir.z);\r
+                               if (Math.abs(direction.dot(new Vector3d(0,1,0))) < 0.95)\r
+                                       panel.GetRenderer().GetActiveCamera().SetViewUp(0, 1, 0);\r
+                               else\r
+                                       panel.GetRenderer().GetActiveCamera().SetViewUp(1, 0, 0);\r
+                               \r
+                               panel.GetRenderer().ResetCameraClippingRange();\r
+                               \r
+                               panel.UpdateLight();\r
+                               panel.repaint();\r
+                       }\r
+                });\r
+           \r
+            return null;\r
+            \r
+       }\r
+       \r
+       \r
+}\r
diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/handlers/ParallelPerspectiveHandler.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/handlers/ParallelPerspectiveHandler.java
new file mode 100644 (file)
index 0000000..7400308
--- /dev/null
@@ -0,0 +1,71 @@
+package org.simantics.g3d.vtk.handlers;\r
+\r
+import java.util.HashMap;\r
+import java.util.Map;\r
+\r
+import javax.vecmath.Vector3d;\r
+\r
+import org.eclipse.core.commands.AbstractHandler;\r
+import org.eclipse.core.commands.Command;\r
+import org.eclipse.core.commands.ExecutionEvent;\r
+import org.eclipse.core.commands.ExecutionException;\r
+import org.eclipse.ui.IWorkbenchPart;\r
+import org.eclipse.ui.handlers.HandlerUtil;\r
+import org.simantics.g3d.vtk.common.InteractiveVtkPanel;\r
+import org.simantics.utils.threads.AWTThread;\r
+import org.simantics.utils.threads.ThreadUtils;\r
+\r
+public class ParallelPerspectiveHandler extends AbstractHandler {\r
+\r
+       \r
+       private Map<InteractiveVtkPanel,Vector3d> cameraPos = new HashMap<InteractiveVtkPanel, Vector3d>();\r
+       \r
+       @Override\r
+       public Object execute(ExecutionEvent event) throws ExecutionException {\r
+                Command command = event.getCommand();\r
+            boolean oldValue = HandlerUtil.toggleCommandState(command);\r
+            final boolean activate = !oldValue;\r
+            \r
+            final IWorkbenchPart ap = HandlerUtil.getActiveEditor(event);\r
+            final InteractiveVtkPanel panel = (InteractiveVtkPanel)ap.getAdapter(InteractiveVtkPanel.class);\r
+            \r
+            ThreadUtils.asyncExec(AWTThread.getThreadAccess(), new Runnable() {\r
+                       \r
+                       @Override\r
+                       public void run() {\r
+                               if (activate){\r
+                                       Vector3d focal = new Vector3d(panel.GetRenderer().GetActiveCamera().GetFocalPoint());\r
+                                       Vector3d pos = new Vector3d(panel.GetRenderer().GetActiveCamera().GetPosition());\r
+                                       cameraPos.put(panel, pos);\r
+                                       Vector3d dir = new Vector3d(pos);\r
+                                       dir.sub(focal);\r
+                                       dir.normalize();\r
+                                       dir.scale(100);\r
+                                       dir.add(focal);\r
+                                       panel.GetRenderer().GetActiveCamera().SetPosition(dir.x, dir.y, dir.z);\r
+                                       \r
+                                       \r
+                                       panel.GetRenderer().GetActiveCamera().SetParallelProjection(1);\r
+                                       panel.GetRenderer().ResetCameraClippingRange();\r
+                               } else {\r
+                                       panel.GetRenderer().GetActiveCamera().SetParallelProjection(0);\r
+                                       Vector3d pos = cameraPos.get(panel);\r
+                                       if (pos != null) {\r
+                                               panel.GetRenderer().GetActiveCamera().SetPosition(pos.x, pos.y, pos.z);\r
+                                       }\r
+                                       panel.GetRenderer().ResetCameraClippingRange();\r
+                                       \r
+                               }\r
+                               panel.UpdateLight();\r
+                               panel.repaint();\r
+\r
+                       }\r
+                });\r
+           \r
+            return null;\r
+            \r
+       }\r
+       \r
+       \r
+       \r
+}\r
diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/preferences/CloseMethod.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/preferences/CloseMethod.java
new file mode 100644 (file)
index 0000000..e360bef
--- /dev/null
@@ -0,0 +1,7 @@
+package org.simantics.g3d.vtk.preferences;\r
+\r
+public enum CloseMethod {\r
+       ON_CLOSE,\r
+       ON_LAST_CLOSE,\r
+       NO_CLOSE\r
+}\r
diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/preferences/PreferenceConstants.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/preferences/PreferenceConstants.java
new file mode 100644 (file)
index 0000000..c172d54
--- /dev/null
@@ -0,0 +1,10 @@
+package org.simantics.g3d.vtk.preferences;
+
+/**
+ * Constant definitions for plug-in preferences
+ */
+public class PreferenceConstants {
+
+       public static final String CLOSE_METHOD = "closeMethod";
+       
+}
diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/preferences/PreferenceInitializer.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/preferences/PreferenceInitializer.java
new file mode 100644 (file)
index 0000000..24b27ca
--- /dev/null
@@ -0,0 +1,23 @@
+package org.simantics.g3d.vtk.preferences;
+
+import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer;
+import org.eclipse.jface.preference.IPreferenceStore;
+
+import org.simantics.g3d.vtk.Activator;
+
+/**
+ * Class used to initialize default preference values.
+ */
+public class PreferenceInitializer extends AbstractPreferenceInitializer {
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer#initializeDefaultPreferences()
+        */
+       public void initializeDefaultPreferences() {
+               IPreferenceStore store = Activator.getDefault().getPreferenceStore();
+               store.setDefault(PreferenceConstants.CLOSE_METHOD, CloseMethod.ON_LAST_CLOSE.toString());
+       }
+
+}
diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/preferences/VTKPreferencePage.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/preferences/VTKPreferencePage.java
new file mode 100644 (file)
index 0000000..0639b88
--- /dev/null
@@ -0,0 +1,56 @@
+package org.simantics.g3d.vtk.preferences;
+
+import org.eclipse.jface.preference.*;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+import org.eclipse.ui.IWorkbench;
+import org.simantics.g3d.vtk.Activator;
+
+/**
+ * This class represents a preference page that
+ * is contributed to the Preferences dialog. By 
+ * subclassing <samp>FieldEditorPreferencePage</samp>, we
+ * can use the field support built into JFace that allows
+ * us to create a page that is small and knows how to 
+ * save, restore and apply itself.
+ * <p>
+ * This page is used to modify preferences only. They
+ * are stored in the preference store that belongs to
+ * the main plug-in class. That way, preferences can
+ * be accessed directly via the preference store.
+ */
+
+public class VTKPreferencePage
+       extends FieldEditorPreferencePage
+       implements IWorkbenchPreferencePage {
+
+       public VTKPreferencePage() {
+               super(GRID);
+               setPreferenceStore(Activator.getDefault().getPreferenceStore());
+               setDescription("VTK Preferences (DEBUG)");
+       }
+       
+       /**
+        * Creates the field editors. Field editors are abstractions of
+        * the common GUI blocks needed to manipulate various types
+        * of preferences. Each field editor knows how to save and
+        * restore itself.
+        */
+       public void createFieldEditors() {
+               addField(new RadioGroupFieldEditor(
+                               PreferenceConstants.CLOSE_METHOD,
+                       "When to close VTK",
+                       1,
+                       new String[][] { { "On &Editor Close", CloseMethod.ON_CLOSE.toString() }, 
+                                                    { "On &Last Editor Close", CloseMethod.ON_LAST_CLOSE.toString() },
+                                                    { "&Closing Disabled", CloseMethod.NO_CLOSE.toString() }
+               }, getFieldEditorParent()));
+               
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.ui.IWorkbenchPreferencePage#init(org.eclipse.ui.IWorkbench)
+        */
+       public void init(IWorkbench workbench) {
+       }
+       
+}
\ No newline at end of file
diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/property/VTKPropertyTabContributor.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/property/VTKPropertyTabContributor.java
new file mode 100644 (file)
index 0000000..32e2635
--- /dev/null
@@ -0,0 +1,110 @@
+package org.simantics.g3d.vtk.property;\r
+\r
+import org.eclipse.jface.viewers.ISelection;\r
+import org.eclipse.jface.viewers.ISelectionProvider;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.layout.FillLayout;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.swt.widgets.Control;\r
+import org.eclipse.swt.widgets.Display;\r
+import org.eclipse.swt.widgets.Text;\r
+import org.eclipse.ui.IWorkbenchSite;\r
+import org.simantics.db.management.ISessionContext;\r
+import org.simantics.selectionview.IPropertyTab;\r
+import org.simantics.selectionview.PropertyTabContributor;\r
+import org.simantics.utils.threads.AWTThread;\r
+import org.simantics.utils.threads.ThreadUtils;\r
+\r
+import vtk.vtkActor;\r
+import vtk.vtkAlgorithm;\r
+import vtk.vtkAlgorithmOutput;\r
+import vtk.vtkMapper;\r
+import vtk.vtkProp;\r
+\r
+public class VTKPropertyTabContributor implements PropertyTabContributor{\r
+       \r
+       public org.simantics.selectionview.IPropertyTab create(Composite parent, IWorkbenchSite site, ISessionContext context, Object input) {\r
+               IPropertyTab tab = new VTKPropertyTab((vtkProp)input);\r
+               tab.createControl(parent, context);\r
+               return tab;\r
+       };\r
+       \r
+       \r
+       public class VTKPropertyTab implements IPropertyTab {\r
+               private Composite composite;\r
+               private Text text;\r
+               private vtkProp prop;\r
+               \r
+               public VTKPropertyTab(vtkProp prop) {\r
+                       this.prop = prop;\r
+               }\r
+               \r
+               @Override\r
+               public void createControl(Composite parent, ISessionContext context) {\r
+                       \r
+                       composite = new Composite(parent, SWT.NONE);\r
+                       composite.setLayout(new FillLayout());\r
+                       text = new Text(composite, SWT.MULTI | SWT.V_SCROLL | SWT.H_SCROLL | SWT.READ_ONLY);\r
+                       ThreadUtils.asyncExec(AWTThread.getThreadAccess(), new Runnable() {\r
+                               \r
+                               @Override\r
+                               public void run() {\r
+                                       String string = "";\r
+                                       if (prop instanceof vtkActor) {\r
+                                               vtkActor act = (vtkActor)prop;\r
+                                               vtkMapper mapper = act.GetMapper();\r
+                                               vtkAlgorithmOutput out = mapper.GetInputConnection(0, 0);\r
+                                               vtkAlgorithm producer = out.GetProducer();\r
+                                               string += producer.GetClassName() +"\n";\r
+                                               out.Delete();\r
+                                               mapper.Delete();\r
+                                               producer.Delete();\r
+                                       }\r
+                                       string += prop.Print();\r
+                                       final String s = string;\r
+                                       Display.getDefault().asyncExec(new Runnable() {\r
+                                               @Override\r
+                                               public void run() {\r
+                                                       if (!text.isDisposed())\r
+                                                               text.setText(s);\r
+                                               }\r
+                                       });\r
+                               }\r
+                       });;\r
+                       \r
+                       \r
+               }\r
+               \r
+               @Override\r
+               public void requestFocus() {\r
+                       composite.setFocus();\r
+               }\r
+               \r
+               @Override\r
+               public void dispose() {\r
+                       composite.dispose();\r
+               }\r
+               \r
+               @Override\r
+               public boolean isDisposed() {\r
+                       return composite.isDisposed();\r
+               }\r
+               \r
+               @Override\r
+               public Control getControl() {\r
+                       return composite;\r
+               }\r
+               \r
+               @Override\r
+               public void setInput(ISessionContext context, ISelection selection,\r
+                               boolean force) {\r
+                       \r
+               }\r
+               \r
+               @Override\r
+               public ISelectionProvider getSelectionProvider() {\r
+                       return null;\r
+               }\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/shape/DualHeadArrowActor.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/shape/DualHeadArrowActor.java
new file mode 100644 (file)
index 0000000..518eb51
--- /dev/null
@@ -0,0 +1,297 @@
+package org.simantics.g3d.vtk.shape;\r
+\r
+import javax.vecmath.AxisAngle4d;\r
+import javax.vecmath.Matrix4d;\r
+import javax.vecmath.Point3d;\r
+import javax.vecmath.Vector3d;\r
+\r
+import org.simantics.g3d.math.MathTools;\r
+import org.simantics.utils.threads.AWTThread;\r
+import org.simantics.utils.threads.ThreadUtils;\r
+\r
+import vtk.vtkActor;\r
+import vtk.vtkAssembly;\r
+import vtk.vtkConeSource;\r
+import vtk.vtkLineSource;\r
+import vtk.vtkLinearTransform;\r
+import vtk.vtkMatrix4x4;\r
+import vtk.vtkPolyDataMapper;\r
+import vtk.vtkProp3D;\r
+import vtk.vtkRenderer;\r
+import vtk.vtkTextActor;\r
+import vtk.vtkTubeFilter;\r
+\r
+public class DualHeadArrowActor extends vtkAssembly implements IvtkVisualObject{\r
+\r
+       private vtkRenderer ren;\r
+       private Vector3d axisDir = new Vector3d(1,0,0);\r
+       private vtkTextActor tactor;\r
+       private vtkActor tubeActor;\r
+       private vtkActor coneActor;\r
+       private vtkActor coneActor2;\r
+       private boolean rendered = false;\r
+\r
+       public DualHeadArrowActor(vtkRenderer _ren, String label) {\r
+               super();\r
+               ren = _ren;\r
+               createAxis(label);\r
+       }\r
+       \r
+       public DualHeadArrowActor(vtkRenderer _ren, String label, Vector3d dir) {\r
+               super();\r
+               ren = _ren;\r
+               this.axisDir = dir;\r
+               if (dir.lengthSquared() < MathTools.NEAR_ZERO)\r
+                       throw new IllegalArgumentException("Direction vector length must mer larger than zero");\r
+               createAxis(label);\r
+       }\r
+\r
+       public void createAxis(String label) {\r
+               double coneScale = 0.3 * axisDir.length();\r
+               Vector3d coneOffset = new Vector3d(axisDir);\r
+               coneOffset.normalize();\r
+               coneOffset.scale(coneScale*0.5);\r
+               \r
+               vtkLineSource line = new vtkLineSource();\r
+               //line.SetPoint1(0.0,0.0,0.0);\r
+               line.SetPoint1(coneOffset.x,coneOffset.y,coneOffset.z);\r
+               line.SetPoint2(axisDir.x-coneOffset.x,axisDir.y-coneOffset.y,axisDir.z-coneOffset.z);\r
+               \r
+               tactor = new vtkTextActor();\r
+               \r
+               tactor.SetInput(label);\r
+               \r
+               tactor.SetTextScaleModeToNone();\r
+               tactor.GetTextProperty().SetColor(0.0, 0.0, 0.0);\r
+               tactor.GetTextProperty().ShadowOff();\r
+               tactor.GetTextProperty().ItalicOff();\r
+               tactor.GetTextProperty().BoldOff();\r
+               \r
+               tactor.GetTextProperty().Delete();\r
+               \r
+               tactor.SetMaximumLineHeight(0.25);\r
+               \r
+               tactor.SetPickable(0);\r
+               \r
+               vtkTubeFilter tube = new vtkTubeFilter();\r
+               tube.SetInput(line.GetOutput());\r
+               tube.SetRadius(0.05 * axisDir.length());\r
+               tube.SetNumberOfSides(8);\r
+\r
+               vtkPolyDataMapper tubeMapper = new vtkPolyDataMapper();\r
+               tubeMapper.SetInput(tube.GetOutput());\r
+\r
+               tubeActor = new vtkActor();\r
+               tubeActor.SetMapper(tubeMapper);\r
+               tubeActor.PickableOff();\r
+\r
+               int coneRes = 12;\r
+               \r
+\r
+               \r
+               \r
+               // --- x-Cone\r
+               vtkConeSource cone = new vtkConeSource();\r
+               cone.SetResolution(coneRes);\r
+               vtkPolyDataMapper coneMapper = new vtkPolyDataMapper();\r
+               coneMapper.SetInput(cone.GetOutput());\r
+               coneActor = new vtkActor();\r
+               coneActor.SetMapper(coneMapper);\r
+               coneActor.GetProperty().SetColor(1, 0, 0);\r
+               coneActor.SetScale(coneScale, coneScale, coneScale);\r
+               coneActor.SetPosition(axisDir.x-coneOffset.x,axisDir.y-coneOffset.y,axisDir.z-coneOffset.z);\r
+               coneActor.SetPickable(0);\r
+               \r
+               AxisAngle4d aa = MathTools.createRotation(new Vector3d(1,0,0), axisDir);\r
+               if (aa != null)\r
+                       coneActor.RotateWXYZ(MathTools.radToDeg(aa.angle), aa.x, aa.y, aa.z);\r
+               \r
+               \r
+               coneActor2 = new vtkActor();\r
+               coneActor2.SetMapper(coneMapper);\r
+               coneActor2.GetProperty().SetColor(1, 0, 0);\r
+               coneActor2.SetScale(coneScale, coneScale, coneScale);\r
+               coneActor2.SetPosition(coneOffset.x,coneOffset.y,coneOffset.z);\r
+               coneActor2.SetPickable(0);\r
+               \r
+               aa = MathTools.createRotation(new Vector3d(-1,0,0), axisDir);\r
+               if (aa != null)\r
+                       coneActor2.RotateWXYZ(MathTools.radToDeg(aa.angle), aa.x, aa.y, aa.z);\r
+               \r
+               this.AddPart(tubeActor);\r
+               this.AddPart(coneActor);\r
+               this.AddPart(coneActor2);\r
+               \r
+               tube.GetOutput().Delete();\r
+               cone.GetOutput().Delete();\r
+               line.GetOutput().Delete();\r
+               \r
+               tubeMapper.Delete();\r
+               tube.Delete();\r
+               cone.Delete();\r
+               line.Delete();\r
+\r
+               coneMapper.Delete();\r
+               \r
+               coneActor.GetProperty().Delete();\r
+               coneActor2.GetProperty().Delete();\r
+       }\r
+       \r
+       public void addToRenderer() {\r
+               if (rendered)\r
+                       return;\r
+               rendered = true;\r
+               \r
+               ren.AddActor2D(tactor);\r
+               \r
+               ren.AddActor(this);\r
+       }\r
+       \r
+       public void removeFromRenderer() {\r
+               if (!rendered)\r
+                       return;\r
+               rendered = false;\r
+               ren.RemoveActor2D(tactor);\r
+               ren.RemoveActor(this);\r
+       }\r
+       \r
+       public boolean isRendered() {\r
+               return rendered;\r
+       }\r
+\r
+       public void setAxesVisibility(boolean ison) {\r
+               this.SetVisibility(ison ? 1 : 0);\r
+               tactor.SetVisibility(ison ? 1 : 0);\r
+       }\r
+       \r
+       public void setLabelVisibility(boolean ison) {\r
+               tactor.SetVisibility(ison ? 1 : 0);\r
+       }\r
+       \r
+       double mat[] = new double[16];\r
+       Matrix4d m = new Matrix4d();\r
+       private void updateTextLoc() {\r
+               tactor.GetPositionCoordinate().SetCoordinateSystemToWorld();\r
+               \r
+               \r
+               GetMatrix(mat);\r
+               MathTools.set(m,mat);\r
+               Point3d p = new Point3d(axisDir.x*0.5, axisDir.y*0.5,axisDir.z*0.5);\r
+               m.transform(p);\r
+               tactor.GetPositionCoordinate().SetValue(p.x, p.y, p.z);\r
+               \r
+               tactor.GetPositionCoordinate().Delete();\r
+       }\r
+       \r
+       @Override\r
+       public void SetPickable(int id0) {\r
+               super.SetPickable(id0);\r
+               tubeActor.SetPickable(id0);\r
+               coneActor.SetPickable(id0);\r
+               coneActor2.SetPickable(id0);\r
+       }\r
+       \r
+       @Override\r
+       public void SetOrientation(double id0, double id1, double id2) {\r
+               super.SetOrientation(id0, id1, id2);\r
+               updateTextLoc();\r
+       }\r
+       \r
+       @Override\r
+       public void RotateWXYZ(double id0, double id1, double id2, double id3) {\r
+               super.RotateWXYZ(id0, id1, id2, id3);\r
+               updateTextLoc();\r
+       }\r
+       \r
+       @Override\r
+       public void SetPosition(double[] id0) {\r
+               super.SetPosition(id0);\r
+               updateTextLoc();\r
+       }\r
+       \r
+       @Override\r
+       public void SetPosition(double id0, double id1, double id2) {\r
+               super.SetPosition(id0, id1, id2);\r
+               updateTextLoc();\r
+       }\r
+       \r
+       @Override\r
+       public void SetOrientation(double[] id0) {\r
+               super.SetOrientation(id0);\r
+               updateTextLoc();\r
+       }\r
+       \r
+       @Override\r
+       public void SetScale(double id0) {\r
+               super.SetScale(id0);\r
+               updateTextLoc();\r
+       }\r
+       \r
+       @Override\r
+       public void SetScale(double id0, double id1, double id2) {\r
+               super.SetScale(id0, id1, id2);\r
+               updateTextLoc();\r
+       }\r
+       \r
+       @Override\r
+       public void SetScale(double[] id0) {\r
+               super.SetScale(id0);\r
+               updateTextLoc();\r
+       }\r
+       \r
+       public void SetColor(double r, double g, double b) {\r
+               coneActor.GetProperty().SetColor(r, g, b);\r
+               coneActor2.GetProperty().SetColor(r, g, b);\r
+               tubeActor.GetProperty().SetColor(r, g, b);\r
+               coneActor.GetProperty().Delete();\r
+               coneActor2.GetProperty().Delete();\r
+               tubeActor.GetProperty().Delete();\r
+       }\r
+       \r
+       public void SetTextColor(double r, double g, double b) {\r
+               tactor.GetTextProperty().SetColor(r, g, b);\r
+               tactor.GetTextProperty().Delete();\r
+       }\r
+       \r
+       @Override\r
+       public void SetUserMatrix(vtkMatrix4x4 id0) {\r
+               super.SetUserMatrix(id0);\r
+               updateTextLoc();\r
+       }\r
+       \r
+       @Override\r
+       public void SetUserTransform(vtkLinearTransform id0) {\r
+               super.SetUserTransform(id0);\r
+               updateTextLoc();\r
+       }\r
+       \r
+       @Override\r
+       public void Delete() {\r
+               ren.RemoveActor(tactor);\r
+               ren.RemoveActor(tubeActor);\r
+               ren.RemoveActor(coneActor);\r
+               ren.RemoveActor(coneActor2);\r
+               tactor.Delete();\r
+               tubeActor.Delete();\r
+               coneActor.Delete();\r
+               coneActor2.Delete();\r
+               super.Delete();\r
+       }\r
+\r
+       public void dispose() {\r
+               ThreadUtils.asyncExec(AWTThread.getThreadAccess(), new Runnable() {\r
+                       \r
+                       @Override\r
+                       public void run() {\r
+                               removeFromRenderer();\r
+                               Delete();\r
+                       }\r
+               });\r
+       }\r
+       \r
+       @Override\r
+       public vtkProp3D getVtkProp() {\r
+               return this;\r
+       }\r
+       \r
+}\r
diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/shape/IvtkVisualObject.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/shape/IvtkVisualObject.java
new file mode 100644 (file)
index 0000000..148435c
--- /dev/null
@@ -0,0 +1,12 @@
+package org.simantics.g3d.vtk.shape;\r
+\r
+import vtk.vtkProp3D;\r
+\r
+public interface IvtkVisualObject {\r
+\r
+       \r
+       public void addToRenderer() ;\r
+       public void removeFromRenderer();\r
+       public boolean isRendered();\r
+       public vtkProp3D getVtkProp();\r
+}\r
diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/shape/MeshActor.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/shape/MeshActor.java
new file mode 100644 (file)
index 0000000..f756411
--- /dev/null
@@ -0,0 +1,86 @@
+package org.simantics.g3d.vtk.shape;\r
+\r
+import javax.vecmath.Vector3d;\r
+\r
+import org.simantics.g3d.shape.Color4d;\r
+import org.simantics.g3d.shape.Mesh;\r
+\r
+import vtk.vtkActor;\r
+import vtk.vtkDataSetMapper;\r
+import vtk.vtkIdList;\r
+import vtk.vtkPoints;\r
+import vtk.vtkPolyData;\r
+import vtk.vtkPolyDataMapper;\r
+import vtk.vtkPolyDataNormals;\r
+import vtk.vtkTriangle;\r
+import vtk.vtkUnsignedCharArray;\r
+\r
+public class MeshActor extends vtkActor {\r
+       \r
+       public void setMesh(Mesh mesh) {\r
+               \r
+               vtkPolyDataMapper mapper = new vtkPolyDataMapper();\r
+               \r
+               vtkPolyData polyData = new vtkPolyData();\r
+               polyData.Allocate(mesh.getIndices().size()/3, mesh.getIndices().size()/3);\r
+               \r
+               vtkTriangle triangle = new vtkTriangle();\r
+        vtkIdList list = triangle.GetPointIds();\r
+        for (int i = 0; i < mesh.getIndices().size(); i+=3) {\r
+               list.SetId(0, mesh.getIndices().get(i));\r
+               list.SetId(1, mesh.getIndices().get(i+1));\r
+               list.SetId(2, mesh.getIndices().get(i+2));\r
+               polyData.InsertNextCell(triangle.GetCellType(), list);\r
+        }\r
+        list.Delete();\r
+        triangle.Delete();\r
+               \r
+        \r
+        vtkPoints points = new vtkPoints();\r
+        for (int i = 0; i < mesh.getVertices().size(); i++) {\r
+               Vector3d p = mesh.getVertices().get(i);\r
+               points.InsertPoint(i, p.x, p.y, p.z);\r
+        }\r
+        \r
+        polyData.SetPoints(points);\r
+        points.Delete();\r
+        \r
+        if (mesh.getColors() != null) {\r
+               vtkUnsignedCharArray colors = new vtkUnsignedCharArray();\r
+               colors.SetName("Colors");\r
+               colors.SetNumberOfComponents(3);\r
+               colors.SetNumberOfTuples(mesh.getColors().size());\r
+               for (int i = 0; i < mesh.getColors().size(); i++) {\r
+                       Color4d c = mesh.getColors().get(i);\r
+                       colors.InsertTuple3(i, 255.0* c.x, 255.0 * c.y, 255.0 * c.z);\r
+               }\r
+               polyData.GetPointData().AddArray(colors);\r
+               colors.Delete();\r
+               \r
+        }\r
+        \r
+        boolean computeNormals = true;\r
+        if (computeNormals) {\r
+               vtkPolyDataNormals normals = new vtkPolyDataNormals();\r
+               normals.SetInput(polyData);\r
+               mapper.SetInputConnection(normals.GetOutputPort());\r
+               normals.GetOutputPort().Delete();\r
+               normals.Delete();\r
+        } else {\r
+               mapper.SetInput(polyData);\r
+        }\r
+        \r
+        if (mesh.getColors() != null) {\r
+                mapper.ScalarVisibilityOn();\r
+                mapper.SetScalarModeToUsePointFieldData();\r
+                mapper.SelectColorArray("Colors");\r
+        }\r
+        \r
+        SetMapper(mapper);\r
+        mapper.Delete();\r
+        polyData.GetPointData().Delete();\r
+        polyData.Delete();\r
+        \r
+       }\r
+\r
+}\r
diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/shape/axesActor.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/shape/axesActor.java
new file mode 100644 (file)
index 0000000..8a95751
--- /dev/null
@@ -0,0 +1,353 @@
+package org.simantics.g3d.vtk.shape;\r
+\r
+import javax.vecmath.Matrix4d;\r
+import javax.vecmath.Point3d;\r
+\r
+import org.simantics.g3d.math.MathTools;\r
+import org.simantics.utils.threads.AWTThread;\r
+import org.simantics.utils.threads.ThreadUtils;\r
+\r
+import vtk.vtkActor;\r
+import vtk.vtkAssembly;\r
+import vtk.vtkAxes;\r
+import vtk.vtkConeSource;\r
+import vtk.vtkLinearTransform;\r
+import vtk.vtkMatrix4x4;\r
+import vtk.vtkPolyDataMapper;\r
+import vtk.vtkProp3D;\r
+import vtk.vtkRenderer;\r
+import vtk.vtkTextActor;\r
+import vtk.vtkTubeFilter;\r
+\r
+public class axesActor extends vtkAssembly implements IvtkVisualObject{\r
+\r
+       private vtkRenderer ren;\r
+       private double axisLength = 0.8;\r
+       private vtkTextActor xactor, yactor, zactor;\r
+       private vtkActor tubeActor;\r
+       private vtkActor xconeActor;\r
+       private vtkActor yconeActor;\r
+       private vtkActor zconeActor;\r
+       private boolean rendered = false;\r
+\r
+       public axesActor(vtkRenderer _ren) {\r
+               super();\r
+               ren = _ren;\r
+               createAxes();\r
+       }\r
+       \r
+       public axesActor(vtkRenderer _ren, double axisLength) {\r
+               super();\r
+               ren = _ren;\r
+               this.axisLength = axisLength;\r
+               createAxes();\r
+       }\r
+\r
+       public void createAxes() {\r
+               vtkAxes axes = new vtkAxes();\r
+               axes.SetOrigin(0, 0, 0);\r
+               axes.SetScaleFactor(axisLength);\r
+\r
+               xactor = new vtkTextActor();\r
+               yactor = new vtkTextActor();\r
+               zactor = new vtkTextActor();\r
+\r
+               xactor.SetInput("X");\r
+               yactor.SetInput("Y");\r
+               zactor.SetInput("Z");\r
+\r
+//             xactor.SetTextScaleModeToViewport();\r
+//             yactor.SetTextScaleModeToViewport();\r
+//             zactor.SetTextScaleModeToViewport();\r
+               xactor.SetTextScaleModeToNone();\r
+               yactor.SetTextScaleModeToNone();\r
+               zactor.SetTextScaleModeToNone();\r
+               \r
+               xactor.GetTextProperty().SetColor(0.0, 0.0, 0.0);\r
+               xactor.GetTextProperty().ShadowOff();\r
+               xactor.GetTextProperty().ItalicOff();\r
+               xactor.GetTextProperty().BoldOff();\r
+\r
+               yactor.GetTextProperty().SetColor(0.0, 0.0, 0.0);\r
+               yactor.GetTextProperty().ShadowOff();\r
+               yactor.GetTextProperty().ItalicOff();\r
+               yactor.GetTextProperty().BoldOff();\r
+\r
+               zactor.GetTextProperty().SetColor(0.0, 0.0, 0.0);\r
+               zactor.GetTextProperty().ShadowOff();\r
+               zactor.GetTextProperty().ItalicOff();\r
+               zactor.GetTextProperty().BoldOff();\r
+               \r
+               xactor.GetTextProperty().Delete();\r
+               yactor.GetTextProperty().Delete();\r
+               zactor.GetTextProperty().Delete();\r
+\r
+               xactor.SetMaximumLineHeight(0.25);\r
+               yactor.SetMaximumLineHeight(0.25);\r
+               zactor.SetMaximumLineHeight(0.25);\r
+               \r
+               xactor.SetPickable(0);\r
+               yactor.SetPickable(0);\r
+               zactor.SetPickable(0);\r
+\r
+               vtkTubeFilter tube = new vtkTubeFilter();\r
+               tube.SetInput(axes.GetOutput());\r
+               tube.SetRadius(0.05 * axisLength);\r
+               tube.SetNumberOfSides(8);\r
+\r
+               vtkPolyDataMapper tubeMapper = new vtkPolyDataMapper();\r
+               tubeMapper.SetInput(tube.GetOutput());\r
+\r
+               tubeActor = new vtkActor();\r
+               tubeActor.SetMapper(tubeMapper);\r
+               tubeActor.PickableOff();\r
+\r
+               int coneRes = 12;\r
+               double coneScale = 0.3 * axisLength;\r
+\r
+               // --- x-Cone\r
+               vtkConeSource xcone = new vtkConeSource();\r
+               xcone.SetResolution(coneRes);\r
+               vtkPolyDataMapper xconeMapper = new vtkPolyDataMapper();\r
+               xconeMapper.SetInput(xcone.GetOutput());\r
+               xconeActor = new vtkActor();\r
+               xconeActor.SetMapper(xconeMapper);\r
+               xconeActor.GetProperty().SetColor(1, 0, 0);\r
+               xconeActor.SetScale(coneScale, coneScale, coneScale);\r
+               xconeActor.SetPosition(axisLength, 0.0, 0.0);\r
+               xconeActor.SetPickable(0);\r
+\r
+               // --- y-Cone\r
+               vtkConeSource ycone = new vtkConeSource();\r
+               ycone.SetResolution(coneRes);\r
+               vtkPolyDataMapper yconeMapper = new vtkPolyDataMapper();\r
+               yconeMapper.SetInput(ycone.GetOutput());\r
+               yconeActor = new vtkActor();\r
+               yconeActor.SetMapper(yconeMapper);\r
+               yconeActor.GetProperty().SetColor(1, 1, 0);\r
+               yconeActor.RotateZ(90);\r
+               yconeActor.SetScale(coneScale, coneScale, coneScale);\r
+               yconeActor.SetPosition(0.0, axisLength, 0.0);\r
+               yconeActor.SetPickable(0);\r
+\r
+               // --- z-Cone\r
+               vtkConeSource zcone = new vtkConeSource();\r
+               zcone.SetResolution(coneRes);\r
+               vtkPolyDataMapper zconeMapper = new vtkPolyDataMapper();\r
+               zconeMapper.SetInput(zcone.GetOutput());\r
+               zconeActor = new vtkActor();\r
+               zconeActor.SetMapper(zconeMapper);\r
+               zconeActor.GetProperty().SetColor(0, 1, 0);\r
+               zconeActor.RotateY(-90);\r
+               zconeActor.SetScale(coneScale, coneScale, coneScale);\r
+               zconeActor.SetPosition(0.0, 0.0, axisLength);\r
+               zconeActor.SetPickable(0);\r
+\r
+               \r
+               this.AddPart(tubeActor);\r
+               this.AddPart(xconeActor);\r
+               this.AddPart(yconeActor);\r
+               this.AddPart(zconeActor);\r
+               \r
+               tube.GetOutput().Delete();\r
+               xcone.GetOutput().Delete();\r
+               ycone.GetOutput().Delete();\r
+               zcone.GetOutput().Delete();\r
+               axes.GetOutput().Delete();\r
+               axes.Delete();\r
+               tubeMapper.Delete();\r
+               tube.Delete();\r
+               xcone.Delete();\r
+               ycone.Delete();\r
+               zcone.Delete();\r
+               xconeMapper.Delete();\r
+               yconeMapper.Delete();\r
+               zconeMapper.Delete();\r
+               \r
+               xconeActor.GetProperty().Delete();\r
+               yconeActor.GetProperty().Delete();\r
+               zconeActor.GetProperty().Delete();\r
+       }\r
+       \r
+       public void addToRenderer() {\r
+               if (rendered)\r
+                       return;\r
+               rendered = true;\r
+               \r
+               ren.AddActor2D(xactor);\r
+               ren.AddActor2D(yactor);\r
+               ren.AddActor2D(zactor);\r
+               \r
+               \r
+               ren.AddActor(this);\r
+       }\r
+       \r
+       public void removeFromRenderer() {\r
+               if (!rendered)\r
+                       return;\r
+               rendered = false;\r
+               ren.RemoveActor2D(xactor);\r
+               ren.RemoveActor2D(yactor);\r
+               ren.RemoveActor2D(zactor);\r
+               ren.RemoveActor(this);\r
+       }\r
+       \r
+       public boolean isRendered() {\r
+               return rendered;\r
+       }\r
+\r
+       public void setAxesVisibility(boolean ison) {\r
+               this.SetVisibility(ison ? 1 : 0);\r
+               xactor.SetVisibility(ison ? 1 : 0);\r
+               yactor.SetVisibility(ison ? 1 : 0);\r
+               zactor.SetVisibility(ison ? 1 : 0);\r
+       }\r
+       \r
+       private boolean labelVisible = true;\r
+       \r
+       public void setLabelVisibility(boolean ison) {\r
+               xactor.SetVisibility(ison ? 1 : 0);\r
+               yactor.SetVisibility(ison ? 1 : 0);\r
+               zactor.SetVisibility(ison ? 1 : 0);\r
+               labelVisible = ison;\r
+               if (labelVisible)\r
+                       updateTextLoc();\r
+       }\r
+       \r
+       Matrix4d m = new Matrix4d();\r
+       double mat[] = new double[16];\r
+       Point3d x = new Point3d();\r
+       Point3d y = new Point3d();\r
+       Point3d z = new Point3d();\r
+       \r
+       private void updateTextLoc() {\r
+               if (!labelVisible)\r
+                       return;\r
+               xactor.GetPositionCoordinate().SetCoordinateSystemToWorld();\r
+               yactor.GetPositionCoordinate().SetCoordinateSystemToWorld();\r
+               zactor.GetPositionCoordinate().SetCoordinateSystemToWorld();\r
+               \r
+               GetMatrix(mat);\r
+               MathTools.set(m, mat);\r
+               x.set(axisLength, 0,0);\r
+               y.set(0,axisLength, 0);\r
+               z.set(0,0,axisLength);\r
+               \r
+               m.transform(x);\r
+               m.transform(y);\r
+               m.transform(z);\r
+               xactor.GetPositionCoordinate().SetValue(x.x, x.y, x.z);\r
+               yactor.GetPositionCoordinate().SetValue(y.x, y.y, y.z);\r
+               zactor.GetPositionCoordinate().SetValue(z.x, z.y, z.z);\r
+               \r
+               xactor.GetPositionCoordinate().Delete();\r
+               yactor.GetPositionCoordinate().Delete();\r
+               zactor.GetPositionCoordinate().Delete();\r
+       }\r
+       \r
+       @Override\r
+       public void SetPickable(int id0) {\r
+               super.SetPickable(id0);\r
+               tubeActor.SetPickable(id0);\r
+               xconeActor.SetPickable(id0);\r
+               yconeActor.SetPickable(id0);\r
+               zconeActor.SetPickable(id0);\r
+\r
+       }\r
+       \r
+       @Override\r
+       public void SetOrientation(double id0, double id1, double id2) {\r
+               super.SetOrientation(id0, id1, id2);\r
+               updateTextLoc();\r
+       }\r
+       \r
+       @Override\r
+       public void RotateWXYZ(double id0, double id1, double id2, double id3) {\r
+               super.RotateWXYZ(id0, id1, id2, id3);\r
+               updateTextLoc();\r
+       }\r
+       \r
+       @Override\r
+       public void SetPosition(double[] id0) {\r
+               super.SetPosition(id0);\r
+               updateTextLoc();\r
+       }\r
+       \r
+       @Override\r
+       public void SetPosition(double id0, double id1, double id2) {\r
+               super.SetPosition(id0, id1, id2);\r
+               updateTextLoc();\r
+       }\r
+       \r
+       @Override\r
+       public void SetOrientation(double[] id0) {\r
+               super.SetOrientation(id0);\r
+               updateTextLoc();\r
+       }\r
+       \r
+       @Override\r
+       public void SetScale(double id0) {\r
+               super.SetScale(id0);\r
+               updateTextLoc();\r
+       }\r
+       \r
+       @Override\r
+       public void SetScale(double id0, double id1, double id2) {\r
+               super.SetScale(id0, id1, id2);\r
+               updateTextLoc();\r
+       }\r
+       \r
+       @Override\r
+       public void SetScale(double[] id0) {\r
+               super.SetScale(id0);\r
+               updateTextLoc();\r
+       }\r
+       \r
+       @Override\r
+       public void SetUserMatrix(vtkMatrix4x4 id0) {\r
+               super.SetUserMatrix(id0);\r
+               updateTextLoc();\r
+       }\r
+       \r
+       @Override\r
+       public void SetUserTransform(vtkLinearTransform id0) {\r
+               super.SetUserTransform(id0);\r
+               updateTextLoc();\r
+       }\r
+       \r
+       @Override\r
+       public void Delete() {\r
+               ren.RemoveActor(xactor);\r
+               ren.RemoveActor(yactor);\r
+               ren.RemoveActor(zactor);\r
+               ren.RemoveActor(tubeActor);\r
+               ren.RemoveActor(xconeActor);\r
+               ren.RemoveActor(yconeActor);\r
+               ren.RemoveActor(xconeActor);\r
+               xactor.Delete();\r
+               yactor.Delete();\r
+               zactor.Delete();\r
+               tubeActor.Delete();\r
+               xconeActor.Delete();\r
+               yconeActor.Delete();\r
+               zconeActor.Delete();\r
+               super.Delete();\r
+       }\r
+\r
+       public void dispose() {\r
+               ThreadUtils.asyncExec(AWTThread.getThreadAccess(), new Runnable() {\r
+                       \r
+                       @Override\r
+                       public void run() {\r
+                               removeFromRenderer();\r
+                               Delete();\r
+                       }\r
+               });\r
+       }\r
+       \r
+       @Override\r
+       public vtkProp3D getVtkProp() {\r
+               return this;\r
+       }\r
+       \r
+}\r
diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/shape/axesSphereActor.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/shape/axesSphereActor.java
new file mode 100644 (file)
index 0000000..2fc50d5
--- /dev/null
@@ -0,0 +1,374 @@
+package org.simantics.g3d.vtk.shape;\r
+\r
+import javax.vecmath.Matrix4d;\r
+import javax.vecmath.Point3d;\r
+\r
+import org.simantics.g3d.math.MathTools;\r
+import org.simantics.utils.threads.AWTThread;\r
+import org.simantics.utils.threads.ThreadUtils;\r
+\r
+import vtk.vtkActor;\r
+import vtk.vtkAssembly;\r
+import vtk.vtkAxes;\r
+import vtk.vtkConeSource;\r
+import vtk.vtkLinearTransform;\r
+import vtk.vtkMatrix4x4;\r
+import vtk.vtkPolyDataMapper;\r
+import vtk.vtkProp3D;\r
+import vtk.vtkRenderer;\r
+import vtk.vtkSphereSource;\r
+import vtk.vtkTextActor;\r
+import vtk.vtkTubeFilter;\r
+\r
+public class axesSphereActor extends vtkAssembly implements IvtkVisualObject{\r
+\r
+       private vtkRenderer ren;\r
+       private double axisLength = 0.8;\r
+       private vtkTextActor xactor, yactor, zactor;\r
+       private vtkActor tubeActor;\r
+       private vtkActor xconeActor;\r
+       private vtkActor yconeActor;\r
+       private vtkActor zconeActor;\r
+       private vtkActor oBallActor;\r
+       private boolean rendered = false;\r
+\r
+       public axesSphereActor(vtkRenderer _ren) {\r
+               super();\r
+               ren = _ren;\r
+               createAxes();\r
+       }\r
+       \r
+       public axesSphereActor(vtkRenderer _ren, double axisLength) {\r
+               super();\r
+               ren = _ren;\r
+               this.axisLength = axisLength;\r
+               createAxes();\r
+       }\r
+\r
+       public void createAxes() {\r
+               vtkAxes axes = new vtkAxes();\r
+               axes.SetOrigin(0, 0, 0);\r
+               axes.SetScaleFactor(axisLength);\r
+\r
+\r
+\r
+               vtkTubeFilter tube = new vtkTubeFilter();\r
+               tube.SetInput(axes.GetOutput());\r
+               tube.SetRadius(0.05 * axisLength);\r
+               tube.SetNumberOfSides(8);\r
+\r
+               vtkPolyDataMapper tubeMapper = new vtkPolyDataMapper();\r
+               tubeMapper.SetInput(tube.GetOutput());\r
+\r
+               tubeActor = new vtkActor();\r
+               tubeActor.SetMapper(tubeMapper);\r
+               tubeActor.PickableOff();\r
+\r
+               int coneRes = 12;\r
+               double coneScale = 0.3 * axisLength;\r
+\r
+               // --- x-Cone\r
+               vtkConeSource xcone = new vtkConeSource();\r
+               xcone.SetResolution(coneRes);\r
+               vtkPolyDataMapper xconeMapper = new vtkPolyDataMapper();\r
+               xconeMapper.SetInput(xcone.GetOutput());\r
+               xconeActor = new vtkActor();\r
+               xconeActor.SetMapper(xconeMapper);\r
+               xconeActor.GetProperty().SetColor(1, 0, 0);\r
+               xconeActor.SetScale(coneScale, coneScale, coneScale);\r
+               xconeActor.SetPosition(axisLength, 0.0, 0.0);\r
+               xconeActor.SetPickable(0);\r
+\r
+               // --- y-Cone\r
+               vtkConeSource ycone = new vtkConeSource();\r
+               ycone.SetResolution(coneRes);\r
+               vtkPolyDataMapper yconeMapper = new vtkPolyDataMapper();\r
+               yconeMapper.SetInput(ycone.GetOutput());\r
+               yconeActor = new vtkActor();\r
+               yconeActor.SetMapper(yconeMapper);\r
+               yconeActor.GetProperty().SetColor(1, 1, 0);\r
+               yconeActor.RotateZ(90);\r
+               yconeActor.SetScale(coneScale, coneScale, coneScale);\r
+               yconeActor.SetPosition(0.0, axisLength, 0.0);\r
+               yconeActor.SetPickable(0);\r
+\r
+               // --- z-Cone\r
+               vtkConeSource zcone = new vtkConeSource();\r
+               zcone.SetResolution(coneRes);\r
+               vtkPolyDataMapper zconeMapper = new vtkPolyDataMapper();\r
+               zconeMapper.SetInput(zcone.GetOutput());\r
+               zconeActor = new vtkActor();\r
+               zconeActor.SetMapper(zconeMapper);\r
+               zconeActor.GetProperty().SetColor(0, 1, 0);\r
+               zconeActor.RotateY(-90);\r
+               zconeActor.SetScale(coneScale, coneScale, coneScale);\r
+               zconeActor.SetPosition(0.0, 0.0, axisLength);\r
+               zconeActor.SetPickable(0);\r
+\r
+               vtkSphereSource ball = new vtkSphereSource();\r
+               ball.SetRadius(axisLength * 0.3);\r
+               ball.SetPhiResolution(6);\r
+               ball.SetThetaResolution(8);\r
+               vtkPolyDataMapper ballMapper = new vtkPolyDataMapper();\r
+               ballMapper.SetInput(ball.GetOutput());\r
+               oBallActor = new vtkActor();\r
+               oBallActor.SetMapper(ballMapper);\r
+               oBallActor.GetProperty().SetColor(0, 0, 1);\r
+               oBallActor.SetPickable(0);\r
+               \r
+               \r
+               this.AddPart(tubeActor);\r
+               this.AddPart(xconeActor);\r
+               this.AddPart(yconeActor);\r
+               this.AddPart(zconeActor);\r
+               this.AddPart(oBallActor);\r
+               \r
+               tube.GetOutput().Delete();\r
+               xcone.GetOutput().Delete();\r
+               ycone.GetOutput().Delete();\r
+               zcone.GetOutput().Delete();\r
+               axes.GetOutput().Delete();\r
+               ball.GetOutput().Delete();\r
+               axes.Delete();\r
+               tube.Delete();\r
+               xcone.Delete();\r
+               ycone.Delete();\r
+               zcone.Delete();\r
+               ball.Delete();\r
+               tubeMapper.Delete();\r
+               xconeMapper.Delete();\r
+               yconeMapper.Delete();\r
+               zconeMapper.Delete();\r
+               ballMapper.Delete();\r
+               \r
+               xconeActor.GetProperty().Delete();\r
+               yconeActor.GetProperty().Delete();\r
+               zconeActor.GetProperty().Delete();\r
+               oBallActor.GetProperty().Delete();\r
+               \r
+               \r
+               xactor = new vtkTextActor();\r
+               yactor = new vtkTextActor();\r
+               zactor = new vtkTextActor();\r
+\r
+               xactor.SetInput("X");\r
+               yactor.SetInput("Y");\r
+               zactor.SetInput("Z");\r
+\r
+//             xactor.SetTextScaleModeToViewport();\r
+//             yactor.SetTextScaleModeToViewport();\r
+//             zactor.SetTextScaleModeToViewport();\r
+               xactor.SetTextScaleModeToNone();\r
+               yactor.SetTextScaleModeToNone();\r
+               zactor.SetTextScaleModeToNone();\r
+               \r
+               xactor.GetTextProperty().SetColor(0.0, 0.0, 0.0);\r
+               xactor.GetTextProperty().ShadowOff();\r
+               xactor.GetTextProperty().ItalicOff();\r
+               xactor.GetTextProperty().BoldOff();\r
+\r
+               yactor.GetTextProperty().SetColor(0.0, 0.0, 0.0);\r
+               yactor.GetTextProperty().ShadowOff();\r
+               yactor.GetTextProperty().ItalicOff();\r
+               yactor.GetTextProperty().BoldOff();\r
+\r
+               zactor.GetTextProperty().SetColor(0.0, 0.0, 0.0);\r
+               zactor.GetTextProperty().ShadowOff();\r
+               zactor.GetTextProperty().ItalicOff();\r
+               zactor.GetTextProperty().BoldOff();\r
+               \r
+               xactor.GetTextProperty().Delete();\r
+               yactor.GetTextProperty().Delete();\r
+               zactor.GetTextProperty().Delete();\r
+\r
+               xactor.SetMaximumLineHeight(0.25);\r
+               yactor.SetMaximumLineHeight(0.25);\r
+               zactor.SetMaximumLineHeight(0.25);\r
+               \r
+               xactor.SetPickable(0);\r
+               yactor.SetPickable(0);\r
+               zactor.SetPickable(0);\r
+       }\r
+       \r
+       public void addToRenderer() {\r
+               if (rendered)\r
+                       return;\r
+               rendered = true;\r
+               \r
+               ren.AddActor2D(xactor);\r
+               ren.AddActor2D(yactor);\r
+               ren.AddActor2D(zactor);\r
+               \r
+               \r
+               ren.AddActor(this);\r
+       }\r
+       \r
+       public void removeFromRenderer() {\r
+               if (!rendered)\r
+                       return;\r
+               rendered = false;\r
+               ren.RemoveActor2D(xactor);\r
+               ren.RemoveActor2D(yactor);\r
+               ren.RemoveActor2D(zactor);\r
+               ren.RemoveActor(this);\r
+       }\r
+       \r
+       public boolean isRendered() {\r
+               return rendered;\r
+       }\r
+\r
+       public void setAxesVisibility(boolean ison) {\r
+               this.SetVisibility(ison ? 1 : 0);\r
+               xactor.SetVisibility(ison ? 1 : 0);\r
+               yactor.SetVisibility(ison ? 1 : 0);\r
+               zactor.SetVisibility(ison ? 1 : 0);\r
+       }\r
+       \r
+       private boolean labelVisible = true;\r
+       public void setLabelVisibility(boolean ison) {\r
+               xactor.SetVisibility(ison ? 1 : 0);\r
+               yactor.SetVisibility(ison ? 1 : 0);\r
+               zactor.SetVisibility(ison ? 1 : 0);\r
+               labelVisible = ison;\r
+               if (labelVisible)\r
+                       updateTextLoc();\r
+       }\r
+       \r
+       Matrix4d m = new Matrix4d();\r
+       double mat[] = new double[16];\r
+       Point3d x = new Point3d();\r
+       Point3d y = new Point3d();\r
+       Point3d z = new Point3d();\r
+       \r
+       private void updateTextLoc() {\r
+               if (!labelVisible)\r
+                       return;\r
+               xactor.GetPositionCoordinate().SetCoordinateSystemToWorld();\r
+               yactor.GetPositionCoordinate().SetCoordinateSystemToWorld();\r
+               zactor.GetPositionCoordinate().SetCoordinateSystemToWorld();\r
+\r
+               GetMatrix(mat);\r
+               MathTools.set(m, mat);\r
+               x.set(axisLength, 0,0);\r
+               y.set(0,axisLength, 0);\r
+               z.set(0,0,axisLength);\r
+               \r
+               m.transform(x);\r
+               m.transform(y);\r
+               m.transform(z);\r
+               xactor.GetPositionCoordinate().SetValue(x.x, x.y, x.z);\r
+               yactor.GetPositionCoordinate().SetValue(y.x, y.y, y.z);\r
+               zactor.GetPositionCoordinate().SetValue(z.x, z.y, z.z);\r
+               \r
+               xactor.GetPositionCoordinate().Delete();\r
+               yactor.GetPositionCoordinate().Delete();\r
+               zactor.GetPositionCoordinate().Delete();\r
+       }\r
+       \r
+       @Override\r
+       public void SetPickable(int id0) {\r
+               super.SetPickable(id0);\r
+               tubeActor.SetPickable(id0);\r
+               xconeActor.SetPickable(id0);\r
+               yconeActor.SetPickable(id0);\r
+               zconeActor.SetPickable(id0);\r
+               oBallActor.SetPickable(id0);\r
+\r
+       }\r
+       \r
+       @Override\r
+       public void SetOrientation(double id0, double id1, double id2) {\r
+               super.SetOrientation(id0, id1, id2);\r
+               updateTextLoc();\r
+       }\r
+       \r
+       @Override\r
+       public void RotateWXYZ(double id0, double id1, double id2, double id3) {\r
+               super.RotateWXYZ(id0, id1, id2, id3);\r
+               updateTextLoc();\r
+       }\r
+       \r
+       @Override\r
+       public void SetPosition(double[] id0) {\r
+               super.SetPosition(id0);\r
+               updateTextLoc();\r
+       }\r
+       \r
+       @Override\r
+       public void SetPosition(double id0, double id1, double id2) {\r
+               super.SetPosition(id0, id1, id2);\r
+               updateTextLoc();\r
+       }\r
+       \r
+       @Override\r
+       public void SetOrientation(double[] id0) {\r
+               super.SetOrientation(id0);\r
+               updateTextLoc();\r
+       }\r
+       \r
+       @Override\r
+       public void SetScale(double id0) {\r
+               super.SetScale(id0);\r
+               updateTextLoc();\r
+       }\r
+       \r
+       @Override\r
+       public void SetScale(double id0, double id1, double id2) {\r
+               super.SetScale(id0, id1, id2);\r
+               updateTextLoc();\r
+       }\r
+       \r
+       @Override\r
+       public void SetScale(double[] id0) {\r
+               super.SetScale(id0);\r
+               updateTextLoc();\r
+       }\r
+       \r
+       @Override\r
+       public void SetUserMatrix(vtkMatrix4x4 id0) {\r
+               super.SetUserMatrix(id0);\r
+               updateTextLoc();\r
+       }\r
+       \r
+       @Override\r
+       public void SetUserTransform(vtkLinearTransform id0) {\r
+               super.SetUserTransform(id0);\r
+               updateTextLoc();\r
+       }\r
+       \r
+       @Override\r
+       public void Delete() {\r
+               ren.RemoveActor(xactor);\r
+               ren.RemoveActor(yactor);\r
+               ren.RemoveActor(zactor);\r
+               ren.RemoveActor(tubeActor);\r
+               ren.RemoveActor(xconeActor);\r
+               ren.RemoveActor(yconeActor);\r
+               ren.RemoveActor(xconeActor);\r
+               xactor.Delete();\r
+               yactor.Delete();\r
+               zactor.Delete();\r
+               tubeActor.Delete();\r
+               xconeActor.Delete();\r
+               yconeActor.Delete();\r
+               zconeActor.Delete();\r
+               super.Delete();\r
+       }\r
+\r
+       public void dispose() {\r
+               ThreadUtils.asyncExec(AWTThread.getThreadAccess(), new Runnable() {\r
+                       \r
+                       @Override\r
+                       public void run() {\r
+                               removeFromRenderer();\r
+                               Delete();\r
+                       }\r
+               });\r
+       }\r
+       \r
+       @Override\r
+       public vtkProp3D getVtkProp() {\r
+               return this;\r
+       }\r
+       \r
+}\r
diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/shape/axesSphereActor2.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/shape/axesSphereActor2.java
new file mode 100644 (file)
index 0000000..84f4cf9
--- /dev/null
@@ -0,0 +1,228 @@
+package org.simantics.g3d.vtk.shape;\r
+\r
+import javax.vecmath.AxisAngle4d;\r
+import javax.vecmath.Matrix4d;\r
+import javax.vecmath.Point3d;\r
+import javax.vecmath.Vector3d;\r
+\r
+import org.simantics.g3d.math.MathTools;\r
+import org.simantics.g3d.shape.Color4d;\r
+import org.simantics.g3d.shape.Cone;\r
+import org.simantics.g3d.shape.Cylinder;\r
+import org.simantics.g3d.shape.Mesh;\r
+import org.simantics.g3d.shape.Sphere;\r
+\r
+import vtk.vtkLinearTransform;\r
+import vtk.vtkMatrix4x4;\r
+import vtk.vtkRenderer;\r
+import vtk.vtkTextActor;\r
+\r
+public class axesSphereActor2 extends MeshActor{\r
+       \r
+       private double axisLength;\r
+       private vtkRenderer ren;\r
+       private vtkTextActor xactor, yactor, zactor;\r
+       \r
+       public axesSphereActor2(vtkRenderer ren, double size) {\r
+               int res = 16;\r
+               axisLength = size;\r
+               this.ren = ren;\r
+               Mesh cone_x = Cone.create(size*0.3, res);\r
+               Mesh cone_y = Cone.create(size*0.3, res);\r
+               Mesh cone_z = Cone.create(size*0.3, res);\r
+               cone_x.rotate(MathTools.getQuat(new AxisAngle4d(0,0,-1,Math.PI*0.5)));\r
+               cone_z.rotate(MathTools.getQuat(new AxisAngle4d(1,0,0,Math.PI*0.5)));\r
+               cone_x.translate(new Vector3d(size,0,0));\r
+               cone_y.translate(new Vector3d(0,size,0));\r
+               cone_z.translate(new Vector3d(0,0,size));\r
+               \r
+               Mesh tube_x = Cylinder.create(MathTools.ORIGIN, new Vector3d(size,0,0), size*0.1, res);\r
+               Mesh tube_y = Cylinder.create(MathTools.ORIGIN, new Vector3d(0,size,0), size*0.1, res);\r
+               Mesh tube_z = Cylinder.create(MathTools.ORIGIN, new Vector3d(0,0,size), size*0.1, res);\r
+               \r
+               Mesh sphere = Sphere.create(size*0.3, res, res*2/3);\r
+               \r
+               Color4d x_col = new Color4d(1,0,0,1);\r
+               Color4d y_col = new Color4d(1,1,0,1);\r
+               Color4d z_col = new Color4d(0,1,0,1);\r
+               Color4d o_col = new Color4d(0,0,1,1);\r
+               \r
+               cone_x.setColor(x_col);\r
+               tube_x.setColor(x_col);\r
+               cone_y.setColor(y_col);\r
+               tube_y.setColor(y_col);\r
+               cone_z.setColor(z_col);\r
+               tube_z.setColor(z_col);\r
+               sphere.setColor(o_col);\r
+               \r
+               sphere.add(cone_x);\r
+               sphere.add(tube_x);\r
+               sphere.add(cone_y);\r
+               sphere.add(tube_y);\r
+               sphere.add(cone_z);\r
+               sphere.add(tube_z);\r
+               \r
+               setMesh(sphere);\r
+               \r
+               \r
+               \r
+               xactor = new vtkTextActor();\r
+               yactor = new vtkTextActor();\r
+               zactor = new vtkTextActor();\r
+\r
+               xactor.SetInput("X");\r
+               yactor.SetInput("Y");\r
+               zactor.SetInput("Z");\r
+               \r
+               xactor.SetTextScaleModeToNone();\r
+               yactor.SetTextScaleModeToNone();\r
+               zactor.SetTextScaleModeToNone();\r
+               \r
+               xactor.GetTextProperty().SetColor(0.0, 0.0, 0.0);\r
+               xactor.GetTextProperty().ShadowOff();\r
+               xactor.GetTextProperty().ItalicOff();\r
+               xactor.GetTextProperty().BoldOff();\r
+\r
+               yactor.GetTextProperty().SetColor(0.0, 0.0, 0.0);\r
+               yactor.GetTextProperty().ShadowOff();\r
+               yactor.GetTextProperty().ItalicOff();\r
+               yactor.GetTextProperty().BoldOff();\r
+\r
+               zactor.GetTextProperty().SetColor(0.0, 0.0, 0.0);\r
+               zactor.GetTextProperty().ShadowOff();\r
+               zactor.GetTextProperty().ItalicOff();\r
+               zactor.GetTextProperty().BoldOff();\r
+               \r
+               xactor.GetTextProperty().Delete();\r
+               yactor.GetTextProperty().Delete();\r
+               zactor.GetTextProperty().Delete();\r
+\r
+               xactor.SetMaximumLineHeight(0.25);\r
+               yactor.SetMaximumLineHeight(0.25);\r
+               zactor.SetMaximumLineHeight(0.25);\r
+               \r
+               xactor.SetPickable(0);\r
+               yactor.SetPickable(0);\r
+               zactor.SetPickable(0);\r
+       }\r
+       \r
+       private boolean labelVisible = false;\r
+       public void setLabelVisibility(boolean ison) {\r
+               if (ison == labelVisible)\r
+                       return;\r
+               labelVisible = ison;\r
+               if (labelVisible) {\r
+                       ren.AddActor2D(xactor);\r
+                       ren.AddActor2D(yactor);\r
+                       ren.AddActor2D(zactor);\r
+                       updateTextLoc();\r
+               } else {\r
+                       ren.RemoveActor2D(xactor);\r
+                       ren.RemoveActor2D(yactor);\r
+                       ren.RemoveActor2D(zactor);\r
+               }\r
+       \r
+       }\r
+       \r
+       Matrix4d m = new Matrix4d();\r
+       double mat[] = new double[16];\r
+       Point3d x = new Point3d();\r
+       Point3d y = new Point3d();\r
+       Point3d z = new Point3d();\r
+       \r
+       private void updateTextLoc() {\r
+               if (!labelVisible)\r
+                       return;\r
+               xactor.GetPositionCoordinate().SetCoordinateSystemToWorld();\r
+               yactor.GetPositionCoordinate().SetCoordinateSystemToWorld();\r
+               zactor.GetPositionCoordinate().SetCoordinateSystemToWorld();\r
+\r
+               GetMatrix(mat);\r
+               MathTools.set(m, mat);\r
+               x.set(axisLength, 0,0);\r
+               y.set(0,axisLength, 0);\r
+               z.set(0,0,axisLength);\r
+               \r
+               m.transform(x);\r
+               m.transform(y);\r
+               m.transform(z);\r
+               xactor.GetPositionCoordinate().SetValue(x.x, x.y, x.z);\r
+               yactor.GetPositionCoordinate().SetValue(y.x, y.y, y.z);\r
+               zactor.GetPositionCoordinate().SetValue(z.x, z.y, z.z);\r
+               \r
+               xactor.GetPositionCoordinate().Delete();\r
+               yactor.GetPositionCoordinate().Delete();\r
+               zactor.GetPositionCoordinate().Delete();\r
+       }\r
+       \r
+       @Override\r
+       public void SetOrientation(double id0, double id1, double id2) {\r
+               super.SetOrientation(id0, id1, id2);\r
+               updateTextLoc();\r
+       }\r
+       \r
+       @Override\r
+       public void RotateWXYZ(double id0, double id1, double id2, double id3) {\r
+               super.RotateWXYZ(id0, id1, id2, id3);\r
+               updateTextLoc();\r
+       }\r
+       \r
+       @Override\r
+       public void SetPosition(double[] id0) {\r
+               super.SetPosition(id0);\r
+               updateTextLoc();\r
+       }\r
+       \r
+       @Override\r
+       public void SetPosition(double id0, double id1, double id2) {\r
+               super.SetPosition(id0, id1, id2);\r
+               updateTextLoc();\r
+       }\r
+       \r
+       @Override\r
+       public void SetOrientation(double[] id0) {\r
+               super.SetOrientation(id0);\r
+               updateTextLoc();\r
+       }\r
+       \r
+       @Override\r
+       public void SetScale(double id0) {\r
+               super.SetScale(id0);\r
+               updateTextLoc();\r
+       }\r
+       \r
+       @Override\r
+       public void SetScale(double id0, double id1, double id2) {\r
+               super.SetScale(id0, id1, id2);\r
+               updateTextLoc();\r
+       }\r
+       \r
+       @Override\r
+       public void SetScale(double[] id0) {\r
+               super.SetScale(id0);\r
+               updateTextLoc();\r
+       }\r
+       \r
+       @Override\r
+       public void SetUserMatrix(vtkMatrix4x4 id0) {\r
+               super.SetUserMatrix(id0);\r
+               updateTextLoc();\r
+       }\r
+       \r
+       @Override\r
+       public void SetUserTransform(vtkLinearTransform id0) {\r
+               super.SetUserTransform(id0);\r
+               updateTextLoc();\r
+       }\r
+       \r
+       @Override\r
+       public void Delete() {\r
+               ren.RemoveActor(xactor);\r
+               ren.RemoveActor(yactor);\r
+               ren.RemoveActor(zactor);\r
+               xactor.Delete();\r
+               yactor.Delete();\r
+               zactor.Delete();\r
+               super.Delete();\r
+       }\r
+}\r
diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/shape/axisActor.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/shape/axisActor.java
new file mode 100644 (file)
index 0000000..caf48d4
--- /dev/null
@@ -0,0 +1,268 @@
+package org.simantics.g3d.vtk.shape;\r
+\r
+import javax.vecmath.AxisAngle4d;\r
+import javax.vecmath.Matrix4d;\r
+import javax.vecmath.Point3d;\r
+import javax.vecmath.Vector3d;\r
+\r
+import org.simantics.g3d.math.MathTools;\r
+import org.simantics.utils.threads.AWTThread;\r
+import org.simantics.utils.threads.ThreadUtils;\r
+\r
+import vtk.vtkActor;\r
+import vtk.vtkAssembly;\r
+import vtk.vtkConeSource;\r
+import vtk.vtkLineSource;\r
+import vtk.vtkLinearTransform;\r
+import vtk.vtkMatrix4x4;\r
+import vtk.vtkPolyDataMapper;\r
+import vtk.vtkProp3D;\r
+import vtk.vtkRenderer;\r
+import vtk.vtkTextActor;\r
+import vtk.vtkTubeFilter;\r
+\r
+public class axisActor extends vtkAssembly implements IvtkVisualObject{\r
+\r
+       private vtkRenderer ren;\r
+       private Vector3d axisDir = new Vector3d(1,0,0);\r
+       private vtkTextActor tactor;\r
+       private vtkActor tubeActor;\r
+       private vtkActor coneActor;\r
+       private boolean rendered = false;\r
+\r
+       public axisActor(vtkRenderer _ren, String label) {\r
+               super();\r
+               ren = _ren;\r
+               createAxis(label);\r
+       }\r
+       \r
+       public axisActor(vtkRenderer _ren, String label, Vector3d dir) {\r
+               super();\r
+               ren = _ren;\r
+               this.axisDir = dir;\r
+               createAxis(label);\r
+       }\r
+\r
+       public void createAxis(String label) {\r
+               vtkLineSource line = new vtkLineSource();\r
+               line.SetPoint1(0.0,0.0,0.0);\r
+               line.SetPoint2(axisDir.x,axisDir.y,axisDir.z);\r
+               \r
+               tactor = new vtkTextActor();\r
+               \r
+               tactor.SetInput(label);\r
+               \r
+               tactor.SetTextScaleModeToNone();\r
+               tactor.GetTextProperty().SetColor(0.0, 0.0, 0.0);\r
+               tactor.GetTextProperty().ShadowOff();\r
+               tactor.GetTextProperty().ItalicOff();\r
+               tactor.GetTextProperty().BoldOff();\r
+               \r
+               tactor.GetTextProperty().Delete();\r
+               \r
+               tactor.SetMaximumLineHeight(0.25);\r
+               \r
+               tactor.SetPickable(0);\r
+               \r
+               vtkTubeFilter tube = new vtkTubeFilter();\r
+               tube.SetInput(line.GetOutput());\r
+               tube.SetRadius(0.05 * axisDir.length());\r
+               tube.SetNumberOfSides(8);\r
+\r
+               vtkPolyDataMapper tubeMapper = new vtkPolyDataMapper();\r
+               tubeMapper.SetInput(tube.GetOutput());\r
+\r
+               tubeActor = new vtkActor();\r
+               tubeActor.SetMapper(tubeMapper);\r
+               tubeActor.PickableOff();\r
+\r
+               int coneRes = 12;\r
+               double coneScale = 0.3 * axisDir.length();\r
+\r
+               // --- x-Cone\r
+               vtkConeSource cone = new vtkConeSource();\r
+               cone.SetResolution(coneRes);\r
+               vtkPolyDataMapper coneMapper = new vtkPolyDataMapper();\r
+               coneMapper.SetInput(cone.GetOutput());\r
+               coneActor = new vtkActor();\r
+               coneActor.SetMapper(coneMapper);\r
+               coneActor.GetProperty().SetColor(1, 0, 0);\r
+               coneActor.SetScale(coneScale, coneScale, coneScale);\r
+               coneActor.SetPosition(axisDir.x,axisDir.y,axisDir.z);\r
+               coneActor.SetPickable(0);\r
+               \r
+               AxisAngle4d aa = MathTools.createRotation(new Vector3d(1,0,0), new Vector3d(axisDir));\r
+               if (aa != null)\r
+                       coneActor.RotateWXYZ(MathTools.radToDeg(aa.angle), aa.x, aa.y, aa.z);\r
+               \r
+               this.AddPart(tubeActor);\r
+               this.AddPart(coneActor);\r
+               \r
+               tube.GetOutput().Delete();\r
+               cone.GetOutput().Delete();\r
+               line.GetOutput().Delete();\r
+               \r
+               tubeMapper.Delete();\r
+               tube.Delete();\r
+               cone.Delete();\r
+               line.Delete();\r
+\r
+               coneMapper.Delete();\r
+               \r
+               coneActor.GetProperty().Delete();\r
+       }\r
+       \r
+       public void addToRenderer() {\r
+               if (rendered)\r
+                       return;\r
+               rendered = true;\r
+               \r
+               ren.AddActor2D(tactor);\r
+               \r
+               ren.AddActor(this);\r
+       }\r
+       \r
+       public void removeFromRenderer() {\r
+               if (!rendered)\r
+                       return;\r
+               rendered = false;\r
+               ren.RemoveActor2D(tactor);\r
+               ren.RemoveActor(this);\r
+       }\r
+       \r
+       public boolean isRendered() {\r
+               return rendered;\r
+       }\r
+\r
+       public void setAxesVisibility(boolean ison) {\r
+               this.SetVisibility(ison ? 1 : 0);\r
+               tactor.SetVisibility(ison ? 1 : 0);\r
+       }\r
+       \r
+       public void setLabelVisibility(boolean ison) {\r
+               tactor.SetVisibility(ison ? 1 : 0);\r
+       }\r
+       \r
+       double mat[] = new double[16];\r
+       Matrix4d m = new Matrix4d();\r
+       Point3d p = new Point3d();\r
+       private void updateTextLoc() {\r
+               tactor.GetPositionCoordinate().SetCoordinateSystemToWorld();\r
+               \r
+               \r
+               GetMatrix(mat);\r
+               MathTools.set(m, mat);\r
+               p.set(axisDir.x, axisDir.y,axisDir.z);\r
+               m.transform(p);\r
+               tactor.GetPositionCoordinate().SetValue(p.x, p.y, p.z);\r
+               \r
+               tactor.GetPositionCoordinate().Delete();\r
+       }\r
+       \r
+       @Override\r
+       public void SetPickable(int id0) {\r
+               super.SetPickable(id0);\r
+               tubeActor.SetPickable(id0);\r
+               coneActor.SetPickable(id0);\r
+       }\r
+       \r
+       @Override\r
+       public void SetOrientation(double id0, double id1, double id2) {\r
+               super.SetOrientation(id0, id1, id2);\r
+               updateTextLoc();\r
+       }\r
+       \r
+       @Override\r
+       public void RotateWXYZ(double id0, double id1, double id2, double id3) {\r
+               super.RotateWXYZ(id0, id1, id2, id3);\r
+               updateTextLoc();\r
+       }\r
+       \r
+       @Override\r
+       public void SetPosition(double[] id0) {\r
+               super.SetPosition(id0);\r
+               updateTextLoc();\r
+       }\r
+       \r
+       @Override\r
+       public void SetPosition(double id0, double id1, double id2) {\r
+               super.SetPosition(id0, id1, id2);\r
+               updateTextLoc();\r
+       }\r
+       \r
+       @Override\r
+       public void SetOrientation(double[] id0) {\r
+               super.SetOrientation(id0);\r
+               updateTextLoc();\r
+       }\r
+       \r
+       @Override\r
+       public void SetScale(double id0) {\r
+               super.SetScale(id0);\r
+               updateTextLoc();\r
+       }\r
+       \r
+       @Override\r
+       public void SetScale(double id0, double id1, double id2) {\r
+               super.SetScale(id0, id1, id2);\r
+               updateTextLoc();\r
+       }\r
+       \r
+       @Override\r
+       public void SetScale(double[] id0) {\r
+               super.SetScale(id0);\r
+               updateTextLoc();\r
+       }\r
+       \r
+       public void SetColor(double r, double g, double b) {\r
+               coneActor.GetProperty().SetColor(r, g, b);\r
+               tubeActor.GetProperty().SetColor(r, g, b);\r
+               coneActor.GetProperty().Delete();\r
+               tubeActor.GetProperty().Delete();\r
+       }\r
+       \r
+       public void SetTextColor(double r, double g, double b) {\r
+               tactor.GetTextProperty().SetColor(r, g, b);\r
+               tactor.GetTextProperty().Delete();\r
+       }\r
+       \r
+       @Override\r
+       public void SetUserMatrix(vtkMatrix4x4 id0) {\r
+               super.SetUserMatrix(id0);\r
+               updateTextLoc();\r
+       }\r
+       \r
+       @Override\r
+       public void SetUserTransform(vtkLinearTransform id0) {\r
+               super.SetUserTransform(id0);\r
+               updateTextLoc();\r
+       }\r
+       \r
+       @Override\r
+       public void Delete() {\r
+               ren.RemoveActor(tactor);\r
+               ren.RemoveActor(tubeActor);\r
+               ren.RemoveActor(coneActor);\r
+               tactor.Delete();\r
+               tubeActor.Delete();\r
+               coneActor.Delete();\r
+               super.Delete();\r
+       }\r
+\r
+       public void dispose() {\r
+               ThreadUtils.asyncExec(AWTThread.getThreadAccess(), new Runnable() {\r
+                       \r
+                       @Override\r
+                       public void run() {\r
+                               removeFromRenderer();\r
+                               Delete();\r
+                       }\r
+               });\r
+       }\r
+       \r
+       @Override\r
+       public vtkProp3D getVtkProp() {\r
+               return this;\r
+       }\r
+       \r
+}\r
diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/shape/vtkShape.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/shape/vtkShape.java
new file mode 100644 (file)
index 0000000..636fb8f
--- /dev/null
@@ -0,0 +1,184 @@
+package org.simantics.g3d.vtk.shape;\r
+\r
+import javax.vecmath.Tuple3d;\r
+\r
+import vtk.vtkActor;\r
+import vtk.vtkDataSetMapper;\r
+import vtk.vtkLine;\r
+import vtk.vtkPoints;\r
+import vtk.vtkPolyLine;\r
+import vtk.vtkUnstructuredGrid;\r
+\r
+public class vtkShape {\r
+       \r
+       /**\r
+        * Creates a grid shaped actor.\r
+        * \r
+        * @param size number of grid lines\r
+        * @param space distance between grid lines\r
+        * @param axes bitmask of axes: 1:x, 2:y, 4:z\r
+        * @return vtkActor representing a grid.\r
+        */\r
+       public static vtkActor createGridActor(int size, double space, int axes) {\r
+               int gridCount = 0;\r
+               if ((axes & 0x1) > 0) {\r
+                       gridCount++;\r
+               }\r
+               if ((axes & 0x2) > 0) {\r
+                       gridCount++;\r
+               }\r
+               if ((axes & 0x4) > 0) {\r
+                       gridCount++;\r
+               }\r
+               int pointCount = (size+1) * 2 * 2 * gridCount;\r
+               vtkPoints linePoints = new vtkPoints();\r
+               linePoints.SetNumberOfPoints(pointCount);\r
+               \r
+               \r
+               double max = space * (double)size * 0.5;\r
+               double min = -max;\r
+               int base = 0;\r
+               if ((axes & 0x1) > 0) {\r
+                       for (int i = 0; i <= size; i++) {\r
+                               double s = min + ((double)i) * space;\r
+                               linePoints.InsertPoint(base + i*2  ,0.0, s, min);\r
+                               linePoints.InsertPoint(base + i*2+1,0.0, s, max);\r
+                               i++;\r
+                               if (i > size)\r
+                                       break;\r
+                               s = min + ((double)i) * space;\r
+                               linePoints.InsertPoint(base + i*2  ,0.0, s, max);\r
+                               linePoints.InsertPoint(base + i*2+1,0.0, s, min);\r
+                       }\r
+                       base += (size+1)*2;\r
+                       for (int i = 0; i <= size; i++) {\r
+                               double s = min + ((double)i) * space;\r
+                               linePoints.InsertPoint(base + i*2  , 0.0, max, s);\r
+                               linePoints.InsertPoint(base + i*2+1, 0.0, min, s);\r
+                               i++;\r
+                               if (i > size)\r
+                                       break;\r
+                               s = min + ((double)i) * space;\r
+                               linePoints.InsertPoint(base + i*2  , 0.0, min, s);\r
+                               linePoints.InsertPoint(base + i*2+1, 0.0, max, s);\r
+                       }\r
+                       base += (size+1)*2;\r
+               } \r
+               if ((axes & 0x4) > 0) {\r
+                       for (int i = 0; i <= size; i++) {\r
+                               double s = min + ((double)i) * space;\r
+                               linePoints.InsertPoint(base + i*2  ,s, min, 0.0);\r
+                               linePoints.InsertPoint(base + i*2+1,s, max, 0.0);\r
+                               i++;\r
+                               if (i > size)\r
+                                       break;\r
+                               s = min + ((double)i) * space;\r
+                               linePoints.InsertPoint(base + i*2  ,s, max, 0.0);\r
+                               linePoints.InsertPoint(base + i*2+1,s, min, 0.0);\r
+                       }\r
+                       base += (size+1)*2;\r
+                       for (int i = 0; i <= size; i++) {\r
+                               double s = min + ((double)i) * space;\r
+                               linePoints.InsertPoint(base + i*2  ,max, s, 0.0);\r
+                               linePoints.InsertPoint(base + i*2+1,min, s, 0.0);\r
+                               i++;\r
+                               if (i > size)\r
+                                       break;\r
+                               s = min + ((double)i) * space;\r
+                               linePoints.InsertPoint(base + i*2  ,min, s, 0.0);\r
+                               linePoints.InsertPoint(base + i*2+1,max, s, 0.0);\r
+                       }\r
+                       base += (size+1)*2;\r
+               } \r
+               if ((axes & 0x2) > 0) {\r
+                       for (int i = 0; i <= size; i++) {\r
+                               double s = min + ((double)i) * space;\r
+                               linePoints.InsertPoint(base + i*2  ,s, 0.0, min);\r
+                               linePoints.InsertPoint(base + i*2+1,s, 0.0, max);\r
+                               i++;\r
+                               if (i > size)\r
+                                       break;\r
+                               s = min + ((double)i) * space;\r
+                               linePoints.InsertPoint(base + i*2  ,s, 0.0, max);\r
+                               linePoints.InsertPoint(base + i*2+1,s, 0.0, min);\r
+                       }\r
+                       base += (size+1)*2;\r
+                       for (int i = 0; i <= size; i++) {\r
+                               double s = min + ((double)i) * space;\r
+                               linePoints.InsertPoint(base + i*2  ,max, 0.0, s);\r
+                               linePoints.InsertPoint(base + i*2+1,min, 0.0, s);\r
+                               i++;\r
+                               if (i > size)\r
+                                       break;\r
+                               s = min + ((double)i) * space;\r
+                               linePoints.InsertPoint(base + i*2  ,min, 0.0, s);\r
+                               linePoints.InsertPoint(base + i*2+1,max, 0.0, s);\r
+                       }\r
+                       base += (size+1)*2;\r
+               }\r
+                       \r
+               \r
+               //vtkLine aLine = new vtkLine();\r
+               vtkPolyLine aLine = new vtkPolyLine();\r
+               aLine.GetPointIds().SetNumberOfIds(pointCount);\r
+               for (int i = 0; i < pointCount; i++) {\r
+                       aLine.GetPointIds().SetId(i, i);\r
+               }\r
+               \r
+               \r
+               vtkUnstructuredGrid aLineGrid = new vtkUnstructuredGrid();\r
+               aLineGrid.Allocate(pointCount, pointCount);\r
+               aLineGrid.InsertNextCell(aLine.GetCellType(), aLine.GetPointIds());\r
+               aLineGrid.SetPoints(linePoints);\r
+               vtkDataSetMapper aLineMapper = new vtkDataSetMapper();\r
+               aLineMapper.SetInput(aLineGrid);\r
+               vtkActor aLineActor = new vtkActor();\r
+               aLineActor.SetMapper(aLineMapper);\r
+               \r
+               linePoints.Delete();\r
+               aLine.GetPointIds().Delete();\r
+           aLine.Delete();\r
+           aLineGrid.Delete();\r
+           aLineMapper.Delete();\r
+           \r
+           aLineActor.GetProperty().SetColor(0, 0, 0);\r
+           aLineActor.GetProperty().Delete();\r
+           \r
+           return aLineActor;\r
+       }\r
+       \r
+       /**\r
+        * Creates a line.\r
+        * \r
+        * @param p1\r
+        * @param p2\r
+        * @return\r
+        */\r
+       public static vtkActor createLineActor(Tuple3d p1, Tuple3d p2) {\r
+               vtkPoints linePoints = new vtkPoints();\r
+               linePoints.SetNumberOfPoints(2);\r
+               linePoints.InsertPoint(0,p1.x, p1.y, p1.z);\r
+               linePoints.InsertPoint(1,p2.x, p2.y, p2.z);\r
+               vtkLine aLine = new vtkLine();\r
+               aLine.GetPointIds().SetId(0, 0);\r
+               aLine.GetPointIds().SetId(1, 1);\r
+               vtkUnstructuredGrid aLineGrid = new vtkUnstructuredGrid();\r
+               aLineGrid.Allocate(1, 1);\r
+               aLineGrid.InsertNextCell(aLine.GetCellType(), aLine.GetPointIds());\r
+               aLineGrid.SetPoints(linePoints);\r
+               vtkDataSetMapper aLineMapper = new vtkDataSetMapper();\r
+               aLineMapper.SetInput(aLineGrid);\r
+               vtkActor aLineActor = new vtkActor();\r
+               aLineActor.SetMapper(aLineMapper);\r
+               //aLineActor.GetProperty().SetDiffuseColor(.2, 1, 1);\r
+           \r
+           linePoints.Delete();\r
+           aLine.GetPointIds().Delete();\r
+           aLine.Delete();\r
+           aLineGrid.Delete();\r
+           aLineMapper.Delete();\r
+           \r
+           return aLineActor;\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/utils/vtkEffect.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/utils/vtkEffect.java
new file mode 100644 (file)
index 0000000..0d00c2a
--- /dev/null
@@ -0,0 +1,362 @@
+package org.simantics.g3d.vtk.utils;\r
+\r
+import javax.vecmath.AxisAngle4d;\r
+import javax.vecmath.Vector3d;\r
+\r
+import org.simantics.g3d.math.MathTools;\r
+import org.simantics.g3d.vtk.shape.IvtkVisualObject;\r
+\r
+import vtk.vtkActor;\r
+import vtk.vtkCamera;\r
+import vtk.vtkContourFilter;\r
+import vtk.vtkDataObject;\r
+import vtk.vtkOutlineFilter;\r
+import vtk.vtkOutlineSource;\r
+import vtk.vtkPolyData;\r
+import vtk.vtkPolyDataMapper;\r
+import vtk.vtkPolyDataSilhouette;\r
+import vtk.vtkProp3D;\r
+import vtk.vtkRenderWindow;\r
+import vtk.vtkRenderer;\r
+import vtk.vtkTransform;\r
+import vtk.vtkTransformPolyDataFilter;\r
+import vtk.vtkWindowToImageFilter;\r
+\r
+public class vtkEffect {\r
+\r
+       private static vtkRenderer tmpRenderer;\r
+       \r
+       public static vtkRenderer getRenderer() {\r
+               if (tmpRenderer == null)\r
+                       tmpRenderer = new vtkRenderer();\r
+               return tmpRenderer;\r
+       }\r
+       public static vtkActor createContour(vtkProp3D tmpProp) {\r
+               \r
+               vtkRenderer tmpRenderer = getRenderer();\r
+               tmpRenderer.SetBackground(1,1,1);\r
+               \r
+               \r
+               if (tmpProp instanceof IvtkVisualObject) {\r
+                       ((IvtkVisualObject)tmpProp).addToRenderer();\r
+               } else {\r
+                       tmpRenderer.AddActor(tmpProp);\r
+               }\r
+               \r
+               if (tmpProp instanceof vtkActor) {\r
+                       ((vtkActor)tmpProp).GetProperty().SetColor(0, 0, 0);\r
+               }\r
+               \r
+               \r
+               double bounds_data[] = tmpProp.GetBounds();\r
+               double center_data[] = tmpProp.GetCenter();\r
+               \r
+               tmpRenderer.ResetCamera();\r
+               tmpRenderer.GetActiveCamera().SetParallelProjection(1);\r
+               \r
+               vtkRenderWindow tmpRenderWindow = new vtkRenderWindow();\r
+               tmpRenderWindow.SetOffScreenRendering(1);\r
+               tmpRenderWindow.AddRenderer(tmpRenderer);\r
+               tmpRenderWindow.Render();\r
+               \r
+               vtkWindowToImageFilter windowToImageFilter = new vtkWindowToImageFilter();\r
+               windowToImageFilter.SetInput(tmpRenderWindow);\r
+               windowToImageFilter.SetMagnification(2);\r
+               windowToImageFilter.Update();\r
+               \r
+               vtkContourFilter contourFilter = new vtkContourFilter();\r
+               contourFilter.SetInputConnection(windowToImageFilter.GetOutputPort());\r
+               \r
+               contourFilter.SetValue(0, 255);\r
+               contourFilter.Update();\r
+               \r
+               vtkPolyData contour = contourFilter.GetOutput();\r
+               \r
+               double bounds_contour[] = new double[6]; \r
+               double center_contour[] = new double[3];\r
+               double trans_x=0., trans_y=0., trans_z=0., ratio_x=0., ratio_y=0.;\r
+               contour.GetBounds(bounds_contour);\r
+        \r
+               ratio_x = (bounds_data[1]-bounds_data[0])/(bounds_contour[1]-bounds_contour[0]);\r
+               ratio_y = (bounds_data[3]-bounds_data[2])/(bounds_contour[3]-bounds_contour[2]);\r
+               \r
+               vtkTransform transform1 = new vtkTransform();\r
+               transform1.Scale(ratio_x,ratio_y,1);\r
+               \r
+               vtkTransformPolyDataFilter tFilter1 = new vtkTransformPolyDataFilter();\r
+               tFilter1.SetInput(contour);\r
+               tFilter1.SetTransform(transform1);\r
+               tFilter1.Update();\r
+               \r
+               contour = tFilter1.GetOutput();\r
+               \r
+               contour.GetCenter(center_contour);\r
+               trans_x = center_data[0]-center_contour[0];\r
+               trans_y = center_data[1]-center_contour[1];\r
+               trans_z = center_data[2]-center_contour[2];\r
+\r
+               vtkTransform transform2 = new vtkTransform();\r
+               transform2.Translate( trans_x, trans_y, trans_z);\r
+               \r
+               vtkTransformPolyDataFilter tFilter2 = new vtkTransformPolyDataFilter();\r
+               tFilter2.SetInput(contour);\r
+               tFilter2.SetTransform(transform2);\r
+               tFilter2.Update();\r
+               \r
+               contour = tFilter2.GetOutput();\r
+               \r
+               vtkPolyDataMapper mapper = new vtkPolyDataMapper();\r
+               mapper.SetInput(contour);\r
+               \r
+                \r
+               vtkActor actor =new vtkActor();\r
+               actor.SetMapper(mapper);\r
+               actor.GetProperty().SetLineWidth(2.);\r
+               \r
+               tmpRenderer.RemoveActor(tmpProp);\r
+               \r
+               tFilter1.Delete();\r
+               tFilter2.Delete();\r
+               contour.Delete();\r
+               contourFilter.Delete();\r
+               mapper.Delete();\r
+               tmpRenderWindow.Delete();\r
+               transform1.Delete();\r
+               transform2.Delete();\r
+               windowToImageFilter.Delete();\r
+               \r
+               return actor;\r
+       }\r
+       \r
+       public static vtkActor createContour(vtkProp3D tmpProp, vtkRenderer ren) {\r
+               \r
+               vtkRenderer tmpRenderer = getRenderer();\r
+               tmpRenderer.SetBackground(1,1,1);\r
+               \r
+               \r
+               if (tmpProp instanceof IvtkVisualObject) {\r
+                       ((IvtkVisualObject)tmpProp).addToRenderer();\r
+               } else {\r
+                       tmpRenderer.AddActor(tmpProp);\r
+               }\r
+               \r
+               if (tmpProp instanceof vtkActor) {\r
+                       ((vtkActor)tmpProp).GetProperty().SetColor(0, 0, 0);\r
+               }\r
+               \r
+               \r
+               //double bounds_data[] = tmpProp.GetBounds();\r
+               double center_data[] = tmpProp.GetCenter();\r
+               \r
+               tmpRenderer.ResetCamera();\r
+               \r
+               vtkCamera camera = ren.GetActiveCamera();\r
+               \r
+               vtkCamera tmpCamera = tmpRenderer.GetActiveCamera(); \r
+               tmpCamera.SetParallelProjection(camera.GetParallelProjection());\r
+               \r
+               \r
+               Vector3d pos = new Vector3d(camera.GetPosition());\r
+               Vector3d foc = new Vector3d(camera.GetFocalPoint());\r
+               Vector3d dir = new Vector3d();\r
+               dir.sub(pos,foc);\r
+               double l = dir.length();\r
+//             dir.scale(1.0/l);\r
+//             \r
+//             \r
+//\r
+//             \r
+//             dir.scale(2.0);\r
+//             Vector3d tmpFoc = new Vector3d(tmpCamera.GetFocalPoint());\r
+//             tmpFoc.add(dir);\r
+//             tmpCamera.SetPosition(tmpFoc.x,tmpFoc.y,tmpFoc.z);\r
+//             tmpCamera.SetRoll(camera.GetRoll());\r
+               \r
+               tmpCamera.DeepCopy(camera);\r
+               //tmpCamera.SetModelTransformMatrix(camera.GetModelTransformMatrix());\r
+               tmpCamera.UpdateViewport(tmpRenderer);\r
+               \r
+               vtkRenderWindow tmpRenderWindow = new vtkRenderWindow();\r
+               tmpRenderWindow.SetOffScreenRendering(1);\r
+               tmpRenderWindow.AddRenderer(tmpRenderer);\r
+               tmpRenderWindow.Render();\r
+               \r
+               vtkWindowToImageFilter windowToImageFilter = new vtkWindowToImageFilter();\r
+               windowToImageFilter.SetInput(tmpRenderWindow);\r
+               windowToImageFilter.SetMagnification(2);\r
+               windowToImageFilter.Update();\r
+               \r
+               vtkContourFilter contourFilter = new vtkContourFilter();\r
+               contourFilter.SetInputConnection(windowToImageFilter.GetOutputPort());\r
+               \r
+               contourFilter.SetValue(0, 255);\r
+               contourFilter.Update();\r
+               \r
+               vtkPolyData contour = contourFilter.GetOutput();\r
+               \r
+               \r
+               double or[] = camera.GetOrientationWXYZ();\r
+               AxisAngle4d aa = new AxisAngle4d();\r
+               aa.angle = -MathTools.degToRad(or[0]);\r
+               aa.x = or[1];\r
+               aa.y = or[2];\r
+               aa.z = or[3];\r
+               \r
+               vtkTransform transform0 = new vtkTransform();\r
+               transform0.RotateWXYZ(MathTools.radToDeg(aa.angle), aa.x, aa.y, aa.z);\r
+               \r
+               vtkTransformPolyDataFilter tFilter0 = new vtkTransformPolyDataFilter();\r
+               tFilter0.SetInput(contour);\r
+               tFilter0.SetTransform(transform0);\r
+               tFilter0.Update();\r
+               \r
+               contour.Delete();\r
+               contour = tFilter0.GetOutput();\r
+               \r
+               double bounds_contour[] = new double[6]; \r
+               \r
+               double trans_x=0., trans_y=0., trans_z=0., ratio_x=0.002, ratio_y=0.002, ratio_z=0.002;\r
+               contour.GetBounds(bounds_contour);\r
+//      \r
+//             ratio_x = (bounds_data[1]-bounds_data[0])/(bounds_contour[1]-bounds_contour[0]);\r
+//             ratio_y = (bounds_data[3]-bounds_data[2])/(bounds_contour[3]-bounds_contour[2]);\r
+//             ratio_z = (bounds_data[5]-bounds_data[4])/(bounds_contour[5]-bounds_contour[4]);\r
+               ratio_x = l*0.0008;\r
+               ratio_y = l*0.0008;\r
+               ratio_z = l*0.0008;\r
+               \r
+               \r
+               System.out.println(ratio_x + " " + ratio_y);\r
+               \r
+               \r
+//             \r
+               vtkTransform transform1 = new vtkTransform();\r
+               transform1.Scale(ratio_x,ratio_y,ratio_z);\r
+               \r
+               vtkTransformPolyDataFilter tFilter1 = new vtkTransformPolyDataFilter();\r
+               tFilter1.SetInput(contour);\r
+               tFilter1.SetTransform(transform1);\r
+               tFilter1.Update();\r
+               \r
+               contour.Delete();\r
+               contour = tFilter1.GetOutput();\r
+               \r
+               double center_contour[] = new double[3];\r
+               contour.GetCenter(center_contour);\r
+               trans_x = center_data[0]-center_contour[0];\r
+               trans_y = center_data[1]-center_contour[1];\r
+               trans_z = center_data[2]-center_contour[2];\r
+//             \r
+               System.out.println(trans_x + " " + trans_y + " " + trans_z);\r
+//\r
+               vtkTransform transform2 = new vtkTransform();\r
+               transform2.Translate( trans_x, trans_y, trans_z);\r
+               \r
+               vtkTransformPolyDataFilter tFilter2 = new vtkTransformPolyDataFilter();\r
+               tFilter2.SetInput(contour);\r
+               tFilter2.SetTransform(transform2);\r
+               tFilter2.Update();\r
+               \r
+               contour.Delete();\r
+               contour = tFilter2.GetOutput();\r
+               \r
+               vtkPolyDataMapper mapper = new vtkPolyDataMapper();\r
+               mapper.SetInput(contour);\r
+               \r
+                \r
+               vtkActor actor =new vtkActor();\r
+               actor.SetMapper(mapper);\r
+               actor.GetProperty().SetLineWidth(2.);\r
+               actor.GetProperty().SetColor(0,0,1);\r
+               actor.GetProperty().Delete();\r
+               \r
+               tmpRenderer.RemoveActor(tmpProp);\r
+               \r
+               tFilter0.Delete();\r
+               tFilter1.Delete();\r
+               tFilter2.Delete();\r
+               contour.Delete();\r
+               contourFilter.Delete();\r
+               mapper.Delete();\r
+               tmpRenderWindow.Delete();\r
+               transform0.Delete();\r
+               transform1.Delete();\r
+               transform2.Delete();\r
+               windowToImageFilter.GetOutputPort().Delete();\r
+               windowToImageFilter.Delete();\r
+               \r
+               ren.AddActor(actor);\r
+               \r
+//             vtkMatrix4x4 m = camera.GetModelTransformMatrix();\r
+//             m.Invert();\r
+//             actor.SetUserMatrix(m);\r
+               //m.Delete();\r
+               //actor.SetPosition(trans_x,trans_y, trans_z);\r
+               //actor.RotateWXYZ(MathTools.radToDeg(aa.angle), aa.x, aa.y, aa.z);\r
+               //\r
+               return actor;\r
+       }\r
+       \r
+       public static vtkActor createSilhouette(vtkRenderer ren, vtkDataObject data) {\r
+               \r
+               \r
+               vtkPolyDataSilhouette silhouette = new vtkPolyDataSilhouette();\r
+               \r
+               silhouette.SetInput(data);\r
+               silhouette.SetCamera(ren.GetActiveCamera());\r
+               silhouette.SetEnableFeatureAngle(0);\r
+               vtkPolyDataMapper mapper = new vtkPolyDataMapper();\r
+               \r
+               mapper.SetInputConnection(silhouette.GetOutputPort());\r
+               \r
+               vtkActor actor = new vtkActor();\r
+               actor.SetMapper(mapper);\r
+               \r
+               silhouette.GetOutputPort().Delete();\r
+               silhouette.Delete();\r
+               mapper.Delete();\r
+               \r
+               return actor;\r
+       }\r
+       \r
+       public static vtkActor createOutline(vtkDataObject data) {\r
+               vtkOutlineFilter filter = new vtkOutlineFilter();\r
+               filter.SetInput(data);\r
+               vtkPolyDataMapper mapper = new vtkPolyDataMapper();\r
+               mapper.SetInputConnection(filter.GetOutputPort());\r
+               \r
+               vtkActor actor = new vtkActor();\r
+               actor.SetMapper(mapper);\r
+               \r
+               filter.GetOutputPort().Delete();\r
+               filter.Delete();\r
+               mapper.Delete();\r
+               \r
+               return actor;\r
+       }\r
+       \r
+       public static vtkActor createOutline(vtkProp3D prop) {\r
+\r
+               double bounds[] = prop.GetBounds();\r
+\r
+               vtkOutlineSource source = new vtkOutlineSource();\r
+               source.SetBounds(bounds);\r
+               \r
+               vtkOutlineFilter filter = new vtkOutlineFilter();\r
+               filter.SetInput(source.GetOutput());\r
+               vtkPolyDataMapper mapper = new vtkPolyDataMapper();\r
+               mapper.SetInputConnection(filter.GetOutputPort());\r
+               \r
+               vtkActor actor = new vtkActor();\r
+               actor.SetMapper(mapper);\r
+               \r
+               source.GetOutput().Delete();\r
+               source.Delete();\r
+               filter.GetOutputPort().Delete();\r
+               filter.Delete();\r
+               mapper.Delete();\r
+               \r
+               actor.SetPickable(0);\r
+               return actor;\r
+       }\r
+}\r
diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/utils/vtkPanelUtil.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/utils/vtkPanelUtil.java
new file mode 100644 (file)
index 0000000..eb0e727
--- /dev/null
@@ -0,0 +1,79 @@
+package org.simantics.g3d.vtk.utils;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import org.simantics.g3d.vtk.Activator;\r
+import org.simantics.g3d.vtk.preferences.CloseMethod;\r
+import org.simantics.g3d.vtk.preferences.PreferenceConstants;\r
+import org.simantics.utils.threads.AWTThread;\r
+\r
+import vtk.vtkCamera;\r
+import vtk.vtkObject;\r
+import vtk.vtkPanel;\r
+import vtk.vtkReferenceInformation;\r
+import vtk.vtkRenderWindow;\r
+import vtk.vtkRenderer;\r
+\r
+public class vtkPanelUtil {\r
+       \r
+       private static List<vtkPanel> activePanels = new ArrayList<vtkPanel>();\r
+       private static List<vtkPanel> waitingToDeletePanels = new ArrayList<vtkPanel>();\r
+       \r
+       public static void registerPanel(vtkPanel panel) {\r
+               activePanels.add(panel);\r
+       }\r
+       \r
+       public static void unregisterPanel(vtkPanel panel) {\r
+               assert (Thread.currentThread() == AWTThread.getThreadAccess().getThread());\r
+               if (!activePanels.remove(panel))\r
+                       return;\r
+               CloseMethod method = getCloseMethod();\r
+               if (method == CloseMethod.ON_LAST_CLOSE) {\r
+                       waitingToDeletePanels.add(panel);\r
+               \r
+                       if (activePanels.size() == 0) {\r
+                               cleanup();\r
+                       }\r
+               } else if (method == CloseMethod.ON_CLOSE) {\r
+                       dPanel(panel);\r
+                       vtkGC();\r
+               } else if (method == CloseMethod.NO_CLOSE) {\r
+                       waitingToDeletePanels.add(panel);                       \r
+               }\r
+       }\r
+       \r
+       public static CloseMethod getCloseMethod() {\r
+               return CloseMethod.valueOf(Activator.getDefault().getPreferenceStore().getString(PreferenceConstants.CLOSE_METHOD));\r
+       }\r
+       \r
+       private static void cleanup() {\r
+               \r
+               for (vtkPanel p : waitingToDeletePanels) {\r
+                       dPanel(p);\r
+               }\r
+               waitingToDeletePanels.clear();\r
+               vtkGC();\r
+       }\r
+       \r
+       private static void vtkGC() {\r
+               vtkReferenceInformation info = vtkObject.JAVA_OBJECT_MANAGER.gc(true);\r
+               System.out.println("Referenced objects when closing editor: " + info.getTotalNumberOfObjects() + "\n");\r
+               System.out.println(info.listRemovedReferenceToString());\r
+               System.out.println(info.listKeptReferenceToString());\r
+       }\r
+\r
+       \r
+       private static void dPanel(vtkPanel panel) {\r
+               panel.lock();\r
+               vtkCamera camera = panel.GetRenderer().GetActiveCamera();\r
+               vtkRenderer ren = panel.GetRenderer();\r
+               vtkRenderWindow win = panel.GetRenderWindow();\r
+               win.SetForceMakeCurrent();\r
+               panel.Delete();\r
+               panel = null;\r
+               camera.Delete();\r
+               ren.Delete();\r
+               win.Delete();\r
+       }\r
+}\r
diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/utils/vtkUtil.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/utils/vtkUtil.java
new file mode 100644 (file)
index 0000000..639d894
--- /dev/null
@@ -0,0 +1,119 @@
+package org.simantics.g3d.vtk.utils;\r
+\r
+import java.util.Collection;\r
+\r
+import javax.vecmath.AxisAngle4d;\r
+import javax.vecmath.Matrix4d;\r
+import javax.vecmath.Point2d;\r
+import javax.vecmath.Point3d;\r
+import javax.vecmath.Quat4d;\r
+import javax.vecmath.Tuple3d;\r
+import javax.vecmath.Vector3d;\r
+\r
+import org.simantics.g3d.math.MathTools;\r
+import org.simantics.g3d.math.Ray;\r
+\r
+import vtk.vtkMatrix4x4;\r
+import vtk.vtkProp3D;\r
+import vtk.vtkRenderer;\r
+\r
+public class vtkUtil {\r
+\r
+       public static Ray createMouseRay(vtkRenderer ren1, double x, double y) {\r
+               Point2d screenPos = new Point2d(x,y);\r
+               Point3d worldCoords = getWorldCoordinates(ren1, screenPos, 0);\r
+               Point3d worldCoords2 = getWorldCoordinates(ren1, screenPos, 1);\r
+               Vector3d dir = new Vector3d(worldCoords2);\r
+               dir.sub(worldCoords);\r
+               return new Ray(worldCoords, dir);\r
+       }\r
+       \r
+       public static Point3d getWorldCoordinates(vtkRenderer ren1, Point2d screenPosition, double zPos) {\r
+                               \r
+                ren1.SetDisplayPoint(screenPosition.x, ren1.GetSize()[1]-screenPosition.y, zPos);\r
+                ren1.DisplayToWorld();\r
+                double world[] = ren1.GetWorldPoint();  \r
+\r
+               return new Point3d(world);\r
+                \r
+       }\r
+       \r
+       public static Point2d getScreenCoordinates(vtkRenderer ren1, Tuple3d worldPos) {\r
+                ren1.SetWorldPoint(worldPos.x, worldPos.y, worldPos.z, 0.0);\r
+                ren1.WorldToDisplay();\r
+                double screen[] = ren1.GetDisplayPoint();\r
+                \r
+                return new Point2d(screen);\r
+                \r
+       }\r
+\r
+       public static Matrix4d getMatrix(vtkMatrix4x4 ptm) {\r
+               Matrix4d mat = new Matrix4d();\r
+               for (int i = 0; i < 4; i++) {\r
+                       for (int j = 0; j < 4; j++) {\r
+                               mat.setElement(i, j, ptm.GetElement(i, j));\r
+                       }\r
+               }\r
+\r
+               return mat;\r
+       }\r
+       \r
+       public static vtkMatrix4x4 getMatrix(Matrix4d m) {\r
+               vtkMatrix4x4 mat= new vtkMatrix4x4();\r
+               for (int i = 0; i < 4; i++) {\r
+                       for (int j = 0; j < 4; j++) {\r
+                               mat.SetElement(i, j, m.getElement(i, j));\r
+                       }\r
+               }\r
+               return mat;\r
+       }\r
+       \r
+       public static void updateTransform(Collection<vtkProp3D> props, Vector3d pos, Quat4d q) {\r
+               AxisAngle4d aa = new AxisAngle4d();\r
+               aa.set(q);\r
+               updateTransform(props, pos, aa);\r
+       }\r
+       \r
+       public static void updateTransform(vtkProp3D actor, double pos[], AxisAngle4d aa) {\r
+               actor.SetOrientation(0, 0, 0);\r
+               actor.RotateWXYZ(MathTools.radToDeg(aa.angle), aa.x, aa.y, aa.z);\r
+               actor.SetPosition(pos);\r
+       }\r
+       \r
+       public static void updateTransform(vtkProp3D actor, AxisAngle4d aa) {\r
+               actor.SetOrientation(0, 0, 0);\r
+               actor.RotateWXYZ(MathTools.radToDeg(aa.angle), aa.x, aa.y, aa.z);\r
+       }\r
+       \r
+       \r
+       public static void updateTransform(Collection<vtkProp3D> props, Vector3d pos, AxisAngle4d aa) {\r
+               for (vtkProp3D actor : props) {\r
+                       actor.SetOrientation(0, 0, 0);\r
+                       actor.RotateWXYZ(MathTools.radToDeg(aa.angle), aa.x, aa.y, aa.z);\r
+                       actor.SetPosition(pos.x, pos.y, pos.z);\r
+               }\r
+       }\r
+       \r
+       public static void updateTransform(Collection<vtkProp3D> props, Vector3d pos, AxisAngle4d aa, double scale) {\r
+               for (vtkProp3D actor : props) {\r
+                       actor.SetOrientation(0, 0, 0);\r
+                       actor.RotateWXYZ(MathTools.radToDeg(aa.angle), aa.x, aa.y, aa.z);\r
+                       actor.SetScale(scale);\r
+                       actor.SetPosition(pos.x,pos.y,pos.z);\r
+               }\r
+       }\r
+       \r
+       public static void updateTransform(vtkProp3D actor, Vector3d pos, AxisAngle4d aa, double scale) {\r
+               actor.SetOrientation(0, 0, 0);\r
+               actor.RotateWXYZ(MathTools.radToDeg(aa.angle), aa.x, aa.y, aa.z);\r
+               actor.SetScale(scale);\r
+               actor.SetPosition(pos.x,pos.y,pos.z);\r
+       }\r
+       \r
+       public static void updateTransform(vtkProp3D actor, Vector3d pos, AxisAngle4d aa, double scalex, double scaley, double scalez) {\r
+               actor.SetOrientation(0, 0, 0);\r
+               actor.RotateWXYZ(MathTools.radToDeg(aa.angle), aa.x, aa.y, aa.z);\r
+               actor.SetScale(scalex,scaley, scalez);\r
+               actor.SetPosition(pos.x,pos.y,pos.z);\r
+       }\r
+}\r
diff --git a/org.simantics.g3d/.classpath b/org.simantics.g3d/.classpath
new file mode 100644 (file)
index 0000000..b07aadd
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<classpath>\r
+       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>\r
+       <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>\r
+       <classpathentry excluding="org/simantics/g3d/objmap/" kind="src" path="src"/>\r
+       <classpathentry kind="output" path="bin"/>\r
+</classpath>\r
diff --git a/org.simantics.g3d/.project b/org.simantics.g3d/.project
new file mode 100644 (file)
index 0000000..1345a9f
--- /dev/null
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<projectDescription>\r
+       <name>org.simantics.g3d</name>\r
+       <comment></comment>\r
+       <projects>\r
+       </projects>\r
+       <buildSpec>\r
+               <buildCommand>\r
+                       <name>org.eclipse.jdt.core.javabuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+               <buildCommand>\r
+                       <name>org.eclipse.pde.ManifestBuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+               <buildCommand>\r
+                       <name>org.eclipse.pde.SchemaBuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+       </buildSpec>\r
+       <natures>\r
+               <nature>org.eclipse.pde.PluginNature</nature>\r
+               <nature>org.eclipse.jdt.core.javanature</nature>\r
+       </natures>\r
+</projectDescription>\r
diff --git a/org.simantics.g3d/.settings/org.eclipse.jdt.core.prefs b/org.simantics.g3d/.settings/org.eclipse.jdt.core.prefs
new file mode 100644 (file)
index 0000000..76b52a1
--- /dev/null
@@ -0,0 +1,8 @@
+#Mon Dec 12 12:35:07 EET 2011\r
+eclipse.preferences.version=1\r
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled\r
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6\r
+org.eclipse.jdt.core.compiler.compliance=1.6\r
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error\r
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error\r
+org.eclipse.jdt.core.compiler.source=1.6\r
diff --git a/org.simantics.g3d/META-INF/MANIFEST.MF b/org.simantics.g3d/META-INF/MANIFEST.MF
new file mode 100644 (file)
index 0000000..48e2983
--- /dev/null
@@ -0,0 +1,37 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: G3D
+Bundle-SymbolicName: org.simantics.g3d;singleton:=true
+Bundle-Version: 1.0.0.qualifier
+Bundle-Activator: org.simantics.g3d.Activator
+Bundle-Vendor: VTT
+Require-Bundle: org.eclipse.core.runtime,
+ javax.vecmath;bundle-version="1.5.2",
+ org.simantics.g3d.ontology;bundle-version="1.0.0",
+ org.simantics.db.layer0;bundle-version="1.1.0",
+ org.eclipse.jface;bundle-version="3.6.2",
+ org.eclipse.ui;bundle-version="3.6.2",
+ org.eclipse.ui.views;bundle-version="3.5.1",
+ org.simantics.browsing.ui.swt;bundle-version="1.1.0",
+ org.simantics.db.management;bundle-version="1.1.0",
+ org.simantics.selectionview;bundle-version="1.0.0",
+ gnu.trove2;bundle-version="2.0.4",
+ org.simantics.objmap2;bundle-version="1.0.0",
+ org.eclipse.nebula.widgets.tablecombo;bundle-version="1.0.0",
+ org.simantics.ui;bundle-version="1.0.0"
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6
+Bundle-ActivationPolicy: lazy
+Export-Package: org.simantics.g3d,
+ org.simantics.g3d.gizmo,
+ org.simantics.g3d.math,
+ org.simantics.g3d.preferences,
+ org.simantics.g3d.property,
+ org.simantics.g3d.property.annotations,
+ org.simantics.g3d.scenegraph,
+ org.simantics.g3d.scenegraph.base,
+ org.simantics.g3d.scenegraph.structural,
+ org.simantics.g3d.shape,
+ org.simantics.g3d.toolbar,
+ org.simantics.g3d.tools,
+ org.simantics.g3d.ui,
+ org.simantics.g3d.wizard
diff --git a/org.simantics.g3d/adapters.xml b/org.simantics.g3d/adapters.xml
new file mode 100644 (file)
index 0000000..5194e72
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<adapters>\r
+   \r
+</adapters>
\ No newline at end of file
diff --git a/org.simantics.g3d/build.properties b/org.simantics.g3d/build.properties
new file mode 100644 (file)
index 0000000..6f20375
--- /dev/null
@@ -0,0 +1,5 @@
+source.. = src/\r
+output.. = bin/\r
+bin.includes = META-INF/,\\r
+               .,\\r
+               plugin.xml\r
diff --git a/org.simantics.g3d/help-isv/arrow.png b/org.simantics.g3d/help-isv/arrow.png
new file mode 100644 (file)
index 0000000..464e75f
Binary files /dev/null and b/org.simantics.g3d/help-isv/arrow.png differ
diff --git a/org.simantics.g3d/help-isv/introduction.mediawiki b/org.simantics.g3d/help-isv/introduction.mediawiki
new file mode 100644 (file)
index 0000000..40d5ad8
--- /dev/null
@@ -0,0 +1,6 @@
+=Introduction=\r
+Simantics 3D framework (G3D) provides a set of tools for developing 3D modelling environment on top of Simantics.\r
+\r
+The framework is rendering library neutral. Currently supported are:\r
+* [http://www.vtk.org|VTK]\r
+* [http://www.jmonkeyengine.org|jMonkeyEngine]
\ No newline at end of file
diff --git a/org.simantics.g3d/help-isv/print-style.css b/org.simantics.g3d/help-isv/print-style.css
new file mode 100644 (file)
index 0000000..a77c1e1
--- /dev/null
@@ -0,0 +1,7 @@
+@media screen {\r
+  body { width: 780px; }\r
+}\r
+\r
+@media print {\r
+       html { font-size: 10pt; }\r
+}\r
diff --git a/org.simantics.g3d/help-isv/style.css b/org.simantics.g3d/help-isv/style.css
new file mode 100644 (file)
index 0000000..d86b54b
--- /dev/null
@@ -0,0 +1,37 @@
+\r
+       /* following font face declarations need to be removed for DBCS */\r
+       body, h1, h2, h3, h4, h5, h6, p, table, td, caption, th, ul, ol, dl, li, dd, dt {font-family: Arial, Helvetica, sans-serif; color: #000000 }\r
+       pre, code, tt   { font-family: "Courier New", Courier, monospace;}\r
+       /* end font face declarations */\r
+\r
+       body { font-size: 83%; background: #FFFFFF; margin-bottom: 1em }\r
+       h1           { font-size: 180%; margin-top: 5px; margin-bottom: 1px }   \r
+       h2           { font-size: 140%; margin-top: 25px; margin-bottom: 3px }\r
+       h3           { font-size: 110%; margin-top: 20px; margin-bottom: 3px }\r
+       h4           { font-size: 100%; margin-top: 20px; margin-bottom: 3px; font-style: italic }\r
+       p            { margin-top: 10px; margin-bottom: 10px }\r
+       pre          { font-size: 93%; margin-left: 6; color: #4444CC }\r
+       img.border   { border:1px dashed }\r
+       pre.solid    { border:1px solid #333; background: #eee; padding: 3px; margin: 3px; }\r
+       pre.dotted   { font-size: 93%; margin-left: 6; padding: 1em;border: 1px dashed #2f6fab;color: black;background-color: #f9f9f9;line-height: 1.1em; }\r
+       code, tt     { font-size: 93%; } \r
+       table        { font-size: 100% } /* needed for quirks mode */\r
+       a:link       { color: #0000FF }\r
+       a:hover      { color: #000080 }\r
+       a:visited    { text-decoration: underline }\r
+       \r
+       \r
+       ul               { margin-top: 4px; margin-bottom: 4px; list-style-image: url("arrow.png"); margin-left: 25px; }\r
+       li               { margin-left: 0; margin-bottom: 4px; padding: 0; /* margin between bullet and content */ } \r
+       ol               { margin-top: 10px; margin-bottom: 10px; }\r
+       \r
+       \r
+       dl               { margin-top: 10px; margin-bottom: 10px; }\r
+       dt               { margin-top: 5px; margin-bottom: 5px; font-weight: bold; }\r
+       dd               { margin-top: 5px; margin-bottom: 5px; }\r
+       strong       { font-weight: bold}\r
+       em               { font-style: italic}\r
+       var              { font-style: italic}\r
+       div.revision { border-left-style: solid; border-left-width: thin; \r
+                                          border-left-color: #7B68EE; padding-left:5 }\r
+       th               { font-weight: bold }\r
diff --git a/org.simantics.g3d/help-isv/toc.xml b/org.simantics.g3d/help-isv/toc.xml
new file mode 100644 (file)
index 0000000..9147ca1
--- /dev/null
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<toc label="Simantics 3D framework guide">\r
+   <topic href="introduction.mediawiki" label="Introduction">\r
+   </topic>\r
+</toc>\r
diff --git a/org.simantics.g3d/plugin.xml b/org.simantics.g3d/plugin.xml
new file mode 100644 (file)
index 0000000..fe6ae1f
--- /dev/null
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<?eclipse version="3.4"?>\r
+<plugin>\r
+   <extension-point id="toolbarCommand" name="toolbarCommand" schema="schema/toolbarCommand.exsd"/>\r
+   <extension\r
+         point="org.eclipse.ui.views">\r
+      <view\r
+            allowMultiple="false"\r
+            category="org.simantics.debug.ui"\r
+            class="org.simantics.g3d.ui.SceneGraphDebugger"\r
+            icon="platform:/plugin/com.famfamfam.silk/icons/car.png"\r
+            id="org.simantics.g3d.debug"\r
+            name="Scene-graph Debugger"\r
+            restorable="true">\r
+      </view>\r
+   </extension>\r
+   <extension\r
+         point="org.eclipse.ui.preferencePages">\r
+      <page\r
+            class="org.simantics.g3d.preferences.G3DPreferencePage"\r
+            id="org.simantics.g3d.preferences.G3DPreferencePage"\r
+            name="3D Modelling Preferences">\r
+      </page>\r
+   </extension>\r
+   <extension\r
+         point="org.eclipse.core.runtime.preferences">\r
+      <initializer\r
+            class="org.simantics.g3d.preferences.PreferenceInitializer">\r
+      </initializer>\r
+   </extension>\r
+   <extension\r
+         point="org.eclipse.ui.commands">\r
+      <category\r
+            id="org.simantics.g3d.category"\r
+            name="3D Modelling Commands">\r
+      </category>\r
+      <command\r
+            categoryId="org.simantics.g3d.category"\r
+            id="org.simantics.g3d.parallelperspective"\r
+            name="Parallel perspective">\r
+         <state\r
+               id="org.eclipse.ui.commands.toggleState">\r
+            <class\r
+                  class="org.eclipse.ui.handlers.RegistryToggleState">\r
+               <parameter\r
+                     name="persisted"\r
+                     value="false">\r
+               </parameter>\r
+               <parameter\r
+                     name="default"\r
+                     value="false">\r
+               </parameter>\r
+            </class>\r
+         </state>\r
+      </command>\r
+      <command\r
+            categoryId="org.simantics.g3d.category"\r
+            id="org.simantics.g3d.viewdir"\r
+            name="View Dir">\r
+         <commandParameter\r
+               id="org.simantics.g3d.viewDirection"\r
+               name="direction"\r
+               optional="true">\r
+         </commandParameter>\r
+      </command>\r
+   </extension>\r
+\r
+</plugin>\r
diff --git a/org.simantics.g3d/schema/toolbarCommand.exsd b/org.simantics.g3d/schema/toolbarCommand.exsd
new file mode 100644 (file)
index 0000000..ef45789
--- /dev/null
@@ -0,0 +1,149 @@
+<?xml version='1.0' encoding='UTF-8'?>\r
+<!-- Schema file written by PDE -->\r
+<schema targetNamespace="org.simantics.g3d" xmlns="http://www.w3.org/2001/XMLSchema">\r
+<annotation>\r
+      <appinfo>\r
+         <meta.schema plugin="org.simantics.g3d" id="toolbarCommand" name="toolbarCommand"/>\r
+      </appinfo>\r
+      <documentation>\r
+         [Enter description of this extension point.]\r
+      </documentation>\r
+   </annotation>\r
+\r
+   <element name="extension">\r
+      <annotation>\r
+         <appinfo>\r
+            <meta.element />\r
+         </appinfo>\r
+      </annotation>\r
+      <complexType>\r
+         <sequence>\r
+            <element ref="command" minOccurs="0" maxOccurs="unbounded"/>\r
+         </sequence>\r
+         <attribute name="point" type="string" use="required">\r
+            <annotation>\r
+               <documentation>\r
+                  \r
+               </documentation>\r
+            </annotation>\r
+         </attribute>\r
+         <attribute name="id" type="string">\r
+            <annotation>\r
+               <documentation>\r
+                  \r
+               </documentation>\r
+            </annotation>\r
+         </attribute>\r
+         <attribute name="name" type="string">\r
+            <annotation>\r
+               <documentation>\r
+                  \r
+               </documentation>\r
+               <appinfo>\r
+                  <meta.attribute translatable="true"/>\r
+               </appinfo>\r
+            </annotation>\r
+         </attribute>\r
+      </complexType>\r
+   </element>\r
+\r
+   <element name="command">\r
+      <complexType>\r
+         <attribute name="commandId" type="string" use="required">\r
+            <annotation>\r
+               <documentation>\r
+                  \r
+               </documentation>\r
+            </annotation>\r
+         </attribute>\r
+         <attribute name="toolbarId" type="string" use="required">\r
+            <annotation>\r
+               <documentation>\r
+                  \r
+               </documentation>\r
+            </annotation>\r
+         </attribute>\r
+         <attribute name="name" type="string" use="required">\r
+            <annotation>\r
+               <documentation>\r
+                  \r
+               </documentation>\r
+            </annotation>\r
+         </attribute>\r
+         <attribute name="type" use="required">\r
+            <annotation>\r
+               <documentation>\r
+                  \r
+               </documentation>\r
+            </annotation>\r
+            <simpleType>\r
+               <restriction base="string">\r
+                  <enumeration value="push">\r
+                  </enumeration>\r
+                  <enumeration value="toggle">\r
+                  </enumeration>\r
+                  <enumeration value="radio">\r
+                  </enumeration>\r
+                  <enumeration value="combo">\r
+                  </enumeration>\r
+               </restriction>\r
+            </simpleType>\r
+         </attribute>\r
+         <attribute name="value" type="string">\r
+            <annotation>\r
+               <documentation>\r
+                  Used with radio buttons.\r
+               </documentation>\r
+            </annotation>\r
+         </attribute>\r
+         <attribute name="image" type="string">\r
+            <annotation>\r
+               <documentation>\r
+                  \r
+               </documentation>\r
+               <appinfo>\r
+                  <meta.attribute kind="resource"/>\r
+               </appinfo>\r
+            </annotation>\r
+         </attribute>\r
+      </complexType>\r
+   </element>\r
+\r
+   <annotation>\r
+      <appinfo>\r
+         <meta.section type="since"/>\r
+      </appinfo>\r
+      <documentation>\r
+         [Enter the first release in which this extension point appears.]\r
+      </documentation>\r
+   </annotation>\r
+\r
+   <annotation>\r
+      <appinfo>\r
+         <meta.section type="examples"/>\r
+      </appinfo>\r
+      <documentation>\r
+         [Enter extension point usage example here.]\r
+      </documentation>\r
+   </annotation>\r
+\r
+   <annotation>\r
+      <appinfo>\r
+         <meta.section type="apiinfo"/>\r
+      </appinfo>\r
+      <documentation>\r
+         [Enter API information here.]\r
+      </documentation>\r
+   </annotation>\r
+\r
+   <annotation>\r
+      <appinfo>\r
+         <meta.section type="implementation"/>\r
+      </appinfo>\r
+      <documentation>\r
+         [Enter information about supplied implementation of this extension point.]\r
+      </documentation>\r
+   </annotation>\r
+\r
+\r
+</schema>\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/Activator.java b/org.simantics.g3d/src/org/simantics/g3d/Activator.java
new file mode 100644 (file)
index 0000000..d485b71
--- /dev/null
@@ -0,0 +1,47 @@
+package org.simantics.g3d;\r
+\r
+import org.eclipse.ui.plugin.AbstractUIPlugin;\r
+import org.osgi.framework.BundleContext;\r
+\r
+public class Activator extends AbstractUIPlugin {\r
+\r
+       // The plug-in ID\r
+       public static final String PLUGIN_ID = "org.simantics.g3d"; //$NON-NLS-1$\r
+\r
+       // The shared instance\r
+       private static Activator plugin;\r
+       \r
+       /**\r
+        * The constructor\r
+        */\r
+       public Activator() {\r
+       }\r
+\r
+       /*\r
+        * (non-Javadoc)\r
+        * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)\r
+        */\r
+       public void start(BundleContext context) throws Exception {\r
+               super.start(context);\r
+               plugin = this;\r
+       }\r
+\r
+       /*\r
+        * (non-Javadoc)\r
+        * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)\r
+        */\r
+       public void stop(BundleContext context) throws Exception {\r
+               plugin = null;\r
+               super.stop(context);\r
+       }\r
+\r
+       /**\r
+        * Returns the shared instance\r
+        *\r
+        * @return the shared instance\r
+        */\r
+       public static Activator getDefault() {\r
+               return plugin;\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/adapters/NodeRemover.java b/org.simantics.g3d/src/org/simantics/g3d/adapters/NodeRemover.java
new file mode 100644 (file)
index 0000000..ce2453b
--- /dev/null
@@ -0,0 +1,30 @@
+package org.simantics.g3d.adapters;\r
+\r
+import java.util.Map;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.layer0.adapter.Remover;\r
+\r
+public class NodeRemover implements Remover {\r
+       \r
+       //private Resource node;\r
+       \r
+       public NodeRemover(Resource node) {\r
+               //this.node = node;\r
+       }\r
+       \r
+       @Override\r
+       public String canRemove(ReadGraph graph, Map<Object, Object> aux)\r
+                       throws DatabaseException {\r
+               return "Removing scene-graph nodes from model browser is not supported.";\r
+       }\r
+       \r
+       @Override\r
+       public void remove(WriteGraph graph) throws DatabaseException {\r
+               \r
+       }\r
+\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/gizmo/Gizmo.java b/org.simantics.g3d/src/org/simantics/g3d/gizmo/Gizmo.java
new file mode 100644 (file)
index 0000000..6fc5720
--- /dev/null
@@ -0,0 +1,17 @@
+package org.simantics.g3d.gizmo;\r
+\r
+import javax.vecmath.AxisAngle4d;\r
+import javax.vecmath.Tuple3d;\r
+\r
+public interface Gizmo<T> {\r
+       \r
+       \r
+       public boolean isPartOf(T pickedObject);\r
+       \r
+       \r
+       public void attach(Object renderingPart);\r
+       public void deattach();\r
+       \r
+        public void setPosition(Tuple3d position);\r
+        public void setRotation(AxisAngle4d q);\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/math/EulerTools.java b/org.simantics.g3d/src/org/simantics/g3d/math/EulerTools.java
new file mode 100644 (file)
index 0000000..4545ccb
--- /dev/null
@@ -0,0 +1,394 @@
+package org.simantics.g3d.math;\r
+\r
+import javax.vecmath.AxisAngle4d;\r
+import javax.vecmath.Quat4d;\r
+import javax.vecmath.Vector3d;\r
+\r
+public class EulerTools {\r
+\r
+       public enum Order {\r
+               XYX, XYZ, XZX, XZY, YXY, YXZ, YZX, YZY, ZXY, ZXZ, ZYX, ZYZ\r
+       };\r
+\r
+       public static Quat4d getQuatFromEuler(Order order, Vector3d a) {\r
+               return getQuatFromEuler(order, a.x, a.y, a.z);\r
+       }\r
+       \r
+       public static Quat4d getQuatFromEuler(Order order, double a1, double a2, double a3) {\r
+               Quat4d q1 = new Quat4d();\r
+               Quat4d q2 = new Quat4d();\r
+               Quat4d q3 = new Quat4d();\r
+               switch (order) {\r
+               case XYX:\r
+                       q1.set(new AxisAngle4d(1.0, 0.0, 0.0, a1));\r
+                       q2.set(new AxisAngle4d(0.0, 1.0, 0.0, a2));\r
+                       q3.set(new AxisAngle4d(1.0, 0.0, 0.0, a3));\r
+                       break;\r
+               case XYZ:\r
+                       q1.set(new AxisAngle4d(1.0, 0.0, 0.0, a1));\r
+                       q2.set(new AxisAngle4d(0.0, 1.0, 0.0, a2));\r
+                       q3.set(new AxisAngle4d(0.0, 0.0, 1.0, a3));\r
+                       break;\r
+               case XZX:\r
+                       q1.set(new AxisAngle4d(1.0, 0.0, 0.0, a1));\r
+                       q2.set(new AxisAngle4d(0.0, 0.0, 1.0, a2));\r
+                       q3.set(new AxisAngle4d(1.0, 0.0, 0.0, a3));\r
+                       break;\r
+               case XZY:\r
+                       q1.set(new AxisAngle4d(1.0, 0.0, 0.0, a1));\r
+                       q2.set(new AxisAngle4d(0.0, 0.0, 1.0, a2));\r
+                       q3.set(new AxisAngle4d(0.0, 1.0, 0.0, a3));\r
+                       break;\r
+               case YXY:\r
+                       q1.set(new AxisAngle4d(0.0, 1.0, 0.0, a1));\r
+                       q2.set(new AxisAngle4d(1.0, 0.0, 0.0, a2));\r
+                       q3.set(new AxisAngle4d(0.0, 1.0, 0.0, a3));\r
+                       break;\r
+               case YXZ:\r
+                       q1.set(new AxisAngle4d(0.0, 1.0, 0.0, a1));\r
+                       q2.set(new AxisAngle4d(1.0, 0.0, 0.0, a2));\r
+                       q3.set(new AxisAngle4d(0.0, 0.0, 1.0, a3));\r
+                       break;\r
+               case YZX:\r
+                       q1.set(new AxisAngle4d(0.0, 1.0, 0.0, a1));\r
+                       q2.set(new AxisAngle4d(0.0, 0.0, 1.0, a2));\r
+                       q3.set(new AxisAngle4d(1.0, 0.0, 0.0, a3));\r
+                       break;\r
+               case YZY:\r
+                       q1.set(new AxisAngle4d(0.0, 1.0, 0.0, a1));\r
+                       q2.set(new AxisAngle4d(0.0, 0.0, 1.0, a2));\r
+                       q3.set(new AxisAngle4d(0.0, 1.0, 0.0, a3));\r
+                       break;\r
+               case ZXY:\r
+                       q1.set(new AxisAngle4d(0.0, 0.0, 1.0, a1));\r
+                       q2.set(new AxisAngle4d(1.0, 0.0, 0.0, a2));\r
+                       q3.set(new AxisAngle4d(0.0, 1.0, 0.0, a3));\r
+                       break;\r
+               case ZXZ:\r
+                       q1.set(new AxisAngle4d(0.0, 0.0, 1.0, a1));\r
+                       q2.set(new AxisAngle4d(1.0, 0.0, 0.0, a2));\r
+                       q3.set(new AxisAngle4d(0.0, 0.0, 1.0, a3));\r
+                       break;\r
+               case ZYX:\r
+                       q1.set(new AxisAngle4d(0.0, 0.0, 1.0, a1));\r
+                       q2.set(new AxisAngle4d(0.0, 1.0, 0.0, a2));\r
+                       q3.set(new AxisAngle4d(1.0, 0.0, 0.0, a3));\r
+                       break;\r
+               case ZYZ:\r
+                       q1.set(new AxisAngle4d(0.0, 0.0, 1.0, a1));\r
+                       q2.set(new AxisAngle4d(0.0, 1.0, 0.0, a2));\r
+                       q3.set(new AxisAngle4d(0.0, 0.0, 1.0, a3));\r
+                       break;\r
+               }\r
+               q1.mul(q2);\r
+               q1.mul(q3);\r
+               return q1;\r
+       }\r
+       \r
+       /**\r
+        * See http://noelhughes.net/uploads/quat_2_euler_paper_ver3.pdf\r
+        * @param order\r
+        * @param q\r
+        * @return\r
+        */\r
+       public static Vector3d getEulerFromQuat(Order order, Quat4d q) {\r
+               Vector3d euler = new Vector3d();\r
+               \r
+//             Vector3d v1 = new Vector3d();\r
+//             Vector3d v2 = new Vector3d();\r
+               Vector3d v3 = new Vector3d();\r
+               Vector3d v3n = new Vector3d();\r
+               \r
+               switch (order) {\r
+               case XYX:\r
+//                     v1.x = 1.0;\r
+//                     v2.y = 1.0;\r
+                       v3.x = 1.0;\r
+                       v3n.y = 1.0;\r
+                       break;\r
+               case XYZ:\r
+//                     v1.x = 1.0;\r
+//                     v2.y = 1.0;\r
+                       v3.z = 1.0;\r
+                       v3n.x = 1.0;\r
+                       break;\r
+               case XZX:\r
+//                     v1.x = 1.0;\r
+//                     v2.z = 1.0;\r
+                       v3.x = 1.0;\r
+                       v3n.y = 1.0;\r
+                       break;\r
+               case XZY:\r
+//                     v1.x = 1.0;\r
+//                     v2.z = 1.0;\r
+                       v3.y = 1.0;\r
+                       v3n.z = 1.0;\r
+                       break;\r
+               case YXY:\r
+//                     v1.y = 1.0;\r
+//                     v2.x = 1.0;\r
+                       v3.y = 1.0;\r
+                       v3n.z = 1.0;\r
+                       break;\r
+               case YXZ:\r
+//                     v1.y = 1.0;\r
+//                     v2.x = 1.0;\r
+                       v3.z = 1.0;\r
+                       v3n.x = 1.0;\r
+                       break;\r
+               case YZX:\r
+//                     v1.y = 1.0;\r
+//                     v2.z = 1.0;\r
+                       v3.x = 1.0;\r
+                       v3n.y = 1.0;\r
+                       break;\r
+               case YZY:\r
+//                     v1.y = 1.0;\r
+//                     v2.z = 1.0;\r
+                       v3.y = 1.0;\r
+                       v3n.z = 1.0;\r
+                       break;\r
+               case ZXY:\r
+//                     v1.z = 1.0;\r
+//                     v2.x = 1.0;\r
+                       v3.y = 1.0;\r
+                       v3n.z = 1.0;\r
+                       break;\r
+               case ZXZ:\r
+//                     v1.z = 1.0;\r
+//                     v2.x = 1.0;\r
+                       v3.z = 1.0;\r
+                       v3n.x = 1.0;\r
+                       break;\r
+               case ZYX:\r
+//                     v1.z = 1.0;\r
+//                     v2.y = 1.0;\r
+                       v3.x = 1.0;\r
+                       v3n.y = 1.0;\r
+                       break;\r
+               case ZYZ:\r
+//                     v1.z = 1.0;\r
+//                     v2.y = 1.0;\r
+                       v3.z = 1.0;\r
+                       v3n.x = 1.0;\r
+                       break;\r
+               }\r
+               Vector3d v3r = new Vector3d();\r
+               MathTools.rotate(q, v3, v3r);\r
+               v3r.normalize();\r
+               \r
+               switch (order) {\r
+\r
+               case XZX:\r
+                       euler.x = Math.atan2(v3r.z, v3r.y);\r
+                       euler.y = Math.acos(v3r.x);\r
+                       break;\r
+               case YXY:\r
+                       euler.x = Math.atan2(v3r.x, v3r.z);\r
+                       euler.y = Math.acos(v3r.y);\r
+                       break;\r
+               case ZYZ:\r
+                       euler.x = Math.atan2(v3r.y, v3r.x);\r
+                       euler.y = Math.acos(v3r.z);\r
+                       break;\r
+                       \r
+               case XZY:\r
+                       euler.x = Math.atan2(v3r.z, v3r.y);\r
+                       euler.y = -Math.asin(v3r.x);\r
+                       break;\r
+               case YXZ:\r
+                       euler.x = Math.atan2(v3r.x, v3r.z);\r
+                       euler.y = -Math.asin(v3r.y);\r
+                       break;\r
+               case ZYX:\r
+                       euler.x = Math.atan2(v3r.y, v3r.x);\r
+                       euler.y = -Math.asin(v3r.z);\r
+                       break;\r
+                       \r
+               case XYX:\r
+                       euler.x = Math.atan2(v3r.y, -v3r.z);\r
+                       //euler.x = Math.atan2(v3r.y, -v3r.x);\r
+                       euler.y = Math.acos(v3r.x);\r
+                       break;\r
+               case YZY:\r
+                       euler.x = Math.atan2(v3r.z, -v3r.x);\r
+                       //euler.x = Math.atan2(v3r.z, -v3r.y);\r
+                       euler.y = Math.acos(v3r.y);\r
+                       break;\r
+               case ZXZ:\r
+                       euler.x = Math.atan2(v3r.x, -v3r.y);\r
+                       //euler.x = Math.atan2(v3r.x, -v3r.z);\r
+                       euler.y = Math.acos(v3r.z);\r
+                       break;\r
+                       \r
+               case XYZ:\r
+                       euler.x = Math.atan2(-v3r.y, v3r.z);\r
+                       euler.y = Math.asin(v3r.x);\r
+                       break;\r
+               case YZX:\r
+                       euler.x = Math.atan2(-v3r.z, v3r.x);\r
+                       euler.y = Math.asin(v3r.y);\r
+                       break;\r
+               case ZXY:\r
+                       euler.x = Math.atan2(-v3r.x, v3r.y);\r
+                       euler.y = Math.asin(v3r.z);\r
+                       break;\r
+               }\r
+               \r
+               Quat4d q1 = new Quat4d();\r
+               q1.w = Math.cos(euler.x*0.5);\r
+               Quat4d q2 = new Quat4d();\r
+               q2.w = Math.cos(euler.y*0.5);\r
+               \r
+               switch (order) {\r
+               case XYX:\r
+               case XYZ:\r
+               case XZX:\r
+               case XZY:\r
+                       q1.x = Math.sin(euler.x*0.5);\r
+                       break;\r
+               case YXY:\r
+               case YXZ:\r
+               case YZX:\r
+               case YZY:\r
+                       q1.y = Math.sin(euler.x*0.5);\r
+                       break;\r
+               case ZXY:\r
+               case ZXZ:\r
+               case ZYX:\r
+               case ZYZ:\r
+                       q1.z = Math.sin(euler.x*0.5);\r
+                       break;\r
+               }\r
+               \r
+               switch (order) {\r
+               case YXY:\r
+               case YXZ:\r
+               case ZXY:\r
+               case ZXZ:\r
+                       q2.x = Math.sin(euler.y*0.5);\r
+                       break;\r
+               case XYX:\r
+               case XYZ:\r
+               case ZYX:\r
+               case ZYZ:\r
+                       q2.y = Math.sin(euler.y*0.5);\r
+                       break;\r
+               case XZX:\r
+               case XZY:\r
+               case YZX:\r
+               case YZY:\r
+                       q2.z = Math.sin(euler.y*0.5);\r
+                       break;\r
+               }\r
+               \r
+               Quat4d q12 = new Quat4d();\r
+               q12.mul(q1, q2);\r
+               \r
+               Vector3d v3n12 = new Vector3d();\r
+               Vector3d v3ng = new Vector3d();\r
+               MathTools.rotate(q12, v3n, v3n12);\r
+               MathTools.rotate(q, v3n, v3ng);\r
+               \r
+               double dot = v3n12.dot(v3ng);\r
+               dot = MathTools.clamp(-1.0, 1.0, dot);\r
+               euler.z = Math.abs(Math.acos(dot));\r
+               Vector3d vc = new Vector3d();\r
+               vc.cross(v3n12, v3ng);\r
+               euler.z *= Math.signum(vc.dot(v3r));\r
+               \r
+               return euler;\r
+       }\r
+\r
+       \r
+       public static void main(String args[]) {\r
+               \r
+               boolean all = false;\r
+               boolean allOrder = false;\r
+               if (all) {\r
+                       testAll();\r
+               } else if (allOrder) {\r
+                       test(Order.YXZ);\r
+               } else {\r
+                       //test(Order.ZXY,30,60,45);\r
+                       //test(Order.YXZ,30,0,0);\r
+                       //test(Order.YXZ,30,90,60);\r
+                       test(Order.YXZ,300,240,360);\r
+               }\r
+       }\r
+       \r
+       private static void testAll() {\r
+               double start = 0.0;\r
+               double end = 90.0;\r
+               double step = 30.0;\r
+               for (double a1 = start;  a1 <= end; a1+= step) {\r
+                       double r1 = MathTools.degToRad(a1);\r
+                       for (double a2 = start;  a2 <= end; a2+= step) {\r
+                               double r2 = MathTools.degToRad(a2);\r
+                               for (double a3 = start;  a3 <= end; a3+= step) {\r
+                                       double r3 = MathTools.degToRad(a3);\r
+                                       for (Order order : Order.values()) {\r
+                                               Quat4d q = EulerTools.getQuatFromEuler(order, r1, r2, r3);\r
+                                               Vector3d a = EulerTools.getEulerFromQuat(order, q);\r
+                                               Quat4d q2 = EulerTools.getQuatFromEuler(order, a.x,a.y,a.z);\r
+                                               a.x = MathTools.radToDeg(a.x);\r
+                                               a.y = MathTools.radToDeg(a.y);\r
+                                               a.z = MathTools.radToDeg(a.z);\r
+                                               System.out.println(toString(a1) +" " + toString(a2) + " " + toString(a3) + " " + order + "\t" + toString(a) + "\t" + toString(q) + "\t" + toString(q2));\r
+                                       }\r
+                               }       \r
+                       }       \r
+               }\r
+       }\r
+       \r
+       private static void test(Order order) {\r
+               double start = 0.0;\r
+               double end = 360.0;\r
+               double step = 30.0;\r
+               for (double a1 = start;  a1 <= end; a1+= step) {\r
+                       double r1 = MathTools.degToRad(a1);\r
+                       for (double a2 = start;  a2 <= end; a2+= step) {\r
+                               double r2 = MathTools.degToRad(a2);\r
+                               for (double a3 = start;  a3 <= end; a3+= step) {\r
+                                       double r3 = MathTools.degToRad(a3);\r
+                                       \r
+                                       Quat4d q = EulerTools.getQuatFromEuler(order, r1, r2, r3);\r
+                                       Vector3d a = EulerTools.getEulerFromQuat(order, q);\r
+                                       Quat4d q2 = EulerTools.getQuatFromEuler(order, a.x,a.y,a.z);\r
+                                       a.x = MathTools.radToDeg(a.x);\r
+                                       a.y = MathTools.radToDeg(a.y);\r
+                                       a.z = MathTools.radToDeg(a.z);\r
+                                       \r
+                                       System.out.println(toString(a1) +" " + toString(a2) + " " + toString(a3) + " " + order + "\t" + toString(a) + "\t" + toString(q) + "\t" + toString(q2));\r
+                               }       \r
+                       }       \r
+               }\r
+       }\r
+       \r
+       private static String toString(double d) {\r
+               return String.format("%1$6.2f", d);\r
+       }\r
+       \r
+       private static String toString(Vector3d v) {\r
+               return "("+toString(v.x) +", "+ toString(v.y) + ", " + toString(v.z) +")";\r
+       }\r
+       \r
+       private static String toString(Quat4d v) {\r
+               return "("+toString(v.x) +", "+ toString(v.y) + ", " + toString(v.z) + ", " + toString(v.w) +")";\r
+       }\r
+       \r
+       private static void test(Order order, double deg1, double deg2, double deg3) {\r
+               double r1 = MathTools.degToRad(deg1);\r
+               double r2 = MathTools.degToRad(deg2);\r
+               double r3 = MathTools.degToRad(deg3);\r
+               \r
+               Quat4d q = EulerTools.getQuatFromEuler(order, r1, r2, r3);\r
+               Vector3d a = EulerTools.getEulerFromQuat(order, q);\r
+               Quat4d q2 = EulerTools.getQuatFromEuler(order, a.x,a.y,a.z);\r
+               a.x = MathTools.radToDeg(a.x);\r
+               a.y = MathTools.radToDeg(a.y);\r
+               a.z = MathTools.radToDeg(a.z);\r
+               System.out.println(toString(deg1) +" " + toString(deg2) + " " + toString(deg3) + " " + order + "\t" + toString(a) + "\t" + toString(q) + "\t" + toString(q2));\r
+\r
+       }\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/math/MathTools.java b/org.simantics.g3d/src/org/simantics/g3d/math/MathTools.java
new file mode 100644 (file)
index 0000000..0bfac8f
--- /dev/null
@@ -0,0 +1,849 @@
+package org.simantics.g3d.math;\r
+\r
+import javax.vecmath.AxisAngle4d;\r
+import javax.vecmath.Matrix3d;\r
+import javax.vecmath.Matrix4d;\r
+import javax.vecmath.Quat4d;\r
+import javax.vecmath.Tuple3d;\r
+import javax.vecmath.Tuple4d;\r
+import javax.vecmath.Vector2f;\r
+import javax.vecmath.Vector3d;\r
+\r
+import org.simantics.g3d.math.EulerTools.Order;\r
+\r
+\r
+/**\r
+ * Some useful geometry related math functions. Beware, methods may modify their input parameters!\r
+ * \r
+ * @author Marko Luukkainen\r
+ *\r
+ */\r
+public class MathTools {\r
+    \r
+    public static double NEAR_ZERO = 0.0000001;\r
+    public static double NEAR_HALF = 0.4999999;\r
+    \r
+    public static final Vector3d Z_AXIS = new Vector3d(0.0,0.0,1.0);\r
+       public static final Vector3d Y_AXIS = new Vector3d(0.0,1.0,0.0);\r
+       public static final Vector3d X_AXIS = new Vector3d(1.0,0.0,0.0);\r
+       public static final Vector3d ORIGIN = new Vector3d(0.0,0.0,0.0);\r
+       \r
+       final static double EPS = 1.0e-12;\r
+       \r
+       \r
+       public static boolean equals(double d1, double d2) {\r
+               return Math.abs(d1-d2) < EPS;\r
+       }\r
+       \r
+       public static boolean equals(Tuple3d p1, Tuple3d p2) {\r
+               return distanceSquared(p1, p2) < NEAR_ZERO;\r
+       }\r
+       \r
+       public static boolean equals(Tuple4d p1, Tuple4d p2) {\r
+               return distanceSquared(p1, p2) < NEAR_ZERO;\r
+       }\r
+       \r
+       public static double distance(Tuple3d p1, Tuple3d p2) {\r
+               double dx, dy, dz;\r
+\r
+               dx = p2.x - p1.x;\r
+               dy = p2.y - p1.y;\r
+               dz = p2.z - p1.z;\r
+               return Math.sqrt(dx*dx+dy*dy+dz*dz);\r
+       }\r
+       \r
+       public static double distance(Tuple4d p1, Tuple4d p2) {\r
+               double dx, dy, dz, dw;\r
+\r
+               dx = p2.x - p1.x;\r
+               dy = p2.y - p1.y;\r
+               dz = p2.z - p1.z;\r
+               dw = p2.w - p1.w;\r
+               return Math.sqrt(dx*dx+dy*dy+dz*dz+dw*dw);\r
+       }\r
+       \r
+       public static double distanceSquared(Tuple3d p1, Tuple3d p2) {\r
+               double dx, dy, dz;\r
+\r
+               dx = p2.x - p1.x;\r
+               dy = p2.y - p1.y;\r
+               dz = p2.z - p1.z;\r
+               return dx*dx+dy*dy+dz*dz;\r
+       }\r
+       \r
+       public static double distanceSquared(Tuple4d p1, Tuple4d p2) {\r
+               double dx, dy, dz, dw;\r
+\r
+               dx = p2.x - p1.x;\r
+               dy = p2.y - p1.y;\r
+               dz = p2.z - p1.z;\r
+               dw = p2.w - p1.w;\r
+               return dx*dx+dy*dy+dz*dz+dw*dw;\r
+       }\r
+       \r
+       public static boolean isValid(Tuple3d t) {\r
+               return !(Double.isInfinite(t.x) || Double.isNaN(t.x) ||\r
+                                Double.isInfinite(t.y) || Double.isNaN(t.y) ||\r
+                                Double.isInfinite(t.z) || Double.isNaN(t.z));\r
+       }\r
+    \r
+    public static Vector3d closestPointOnEdge(Vector3d point, Vector3d edgePoint1, Vector3d edgePoint2) {\r
+        point.sub(edgePoint1);\r
+        Vector3d v = new Vector3d(edgePoint2);\r
+        v.sub(edgePoint1);\r
+        double t = v.dot(point);\r
+        t /= v.lengthSquared();\r
+        if (t <= 0.0f)\r
+          return edgePoint1;\r
+        if (t >= 1.0f)\r
+          return edgePoint2;\r
+        v.scale(t);\r
+        v.add(edgePoint1);\r
+        return v;   \r
+    }\r
+    \r
+    public static Vector3d closestPointOnStraight(Tuple3d point, Tuple3d straightPoint, Vector3d straightDir) {\r
+        Vector3d v = new Vector3d(point);\r
+        v.sub(straightPoint);\r
+        double t = straightDir.dot(v);\r
+        t /= straightDir.lengthSquared();\r
+        v.set(straightDir);\r
+        v.scale(t);\r
+        v.add(straightPoint);\r
+        return v;   \r
+    }\r
+    \r
+    public static Vector3d closestPointOnStraight(Tuple3d point, Tuple3d straightPoint, Vector3d straightDir, double u[]) {\r
+        Vector3d v = new Vector3d(point);\r
+        v.sub(straightPoint);\r
+        u[0] = straightDir.dot(v);\r
+        u[0] /= straightDir.lengthSquared();\r
+        v.set(straightDir);\r
+        v.scale(u[0]);\r
+        v.add(straightPoint);\r
+        return v;   \r
+    }\r
+    \r
+    public static double distanceFromPlane(Vector3d point, Vector3d planeNormal, Tuple3d planePoint) {\r
+        point.sub(planePoint);\r
+        \r
+        return planeNormal.dot(point);\r
+    }\r
+      \r
+    public static double distanceFromPlane(Vector3d point, Vector3d planeNormal, float d) {\r
+        return (planeNormal.dot(point) + d);\r
+    }\r
+    \r
+    public static boolean intersectStraightPlane(Tuple3d linePoint, Vector3d lineDir, Tuple3d planePoint, Vector3d planeNormal, Tuple3d intersectPoint) {\r
+        intersectPoint.set(planePoint);\r
+        intersectPoint.sub(linePoint);\r
+        double u = planeNormal.dot(new Vector3d(intersectPoint));\r
+        double v = planeNormal.dot(lineDir);\r
+        if (Math.abs(v) < NEAR_ZERO)\r
+            return false;\r
+        u /= v;\r
+        intersectPoint.set(lineDir);\r
+        intersectPoint.scale(u);\r
+        intersectPoint.add(linePoint);\r
+        return true;\r
+    }\r
+    \r
+    public static boolean intersectStraightPlane(Tuple3d linePoint, Vector3d lineDir, Tuple3d planePoint, Vector3d planeNormal, Vector3d intersectPoint, double[] u) {\r
+        intersectPoint.set(planePoint);\r
+        intersectPoint.sub(linePoint);\r
+        u[0] = planeNormal.dot(intersectPoint);\r
+        double v = planeNormal.dot(lineDir);\r
+        if (Math.abs(v) < NEAR_ZERO)\r
+            return false;\r
+        u[0] /= v;\r
+        intersectPoint.set(lineDir);\r
+        intersectPoint.scale(u[0]);\r
+        intersectPoint.add(linePoint);\r
+        return true;\r
+    }\r
+    \r
+    public static boolean intersectLineLine(Tuple3d l1_start,Tuple3d l1_end,Tuple3d l2_start,Tuple3d l2_end,Tuple3d l1_pos, Tuple3d l2_pos) {\r
+            Vector3d p13 = new Vector3d();\r
+            Vector3d p43 = new Vector3d();\r
+            Vector3d p21 = new Vector3d();\r
+            double d1343,d4321,d1321,d4343,d2121;\r
+            double numer,denom;\r
+            p13.sub(l1_start, l2_start);\r
+            p43.sub(l2_end,l2_start);\r
+            if (Math.abs(p43.x)  < NEAR_ZERO && Math.abs(p43.y)  < NEAR_ZERO && Math.abs(p43.z)  < NEAR_ZERO)\r
+               return false;\r
+            p21.sub(l1_end,l1_start);\r
+            if (Math.abs(p21.x)  < NEAR_ZERO && Math.abs(p21.y)  < NEAR_ZERO && Math.abs(p21.z)  < NEAR_ZERO)\r
+               return false;\r
+\r
+            d1343 = p13.dot(p43);\r
+            d4321 = p43.dot(p21);\r
+            d1321 = p13.dot(p21);\r
+            d4343 = p43.lengthSquared();\r
+            d2121 = p21.lengthSquared();\r
+\r
+            denom = d2121 * d4343 - d4321 * d4321;\r
+            if (Math.abs(denom) < NEAR_ZERO)\r
+               return false;\r
+            numer = d1343 * d4321 - d1321 * d4343;\r
+\r
+            double mua = numer / denom;\r
+            double mub = (d1343 + d4321 * mua) / d4343;\r
\r
+            l1_pos.x = l1_start.x + mua * p21.x;\r
+            l1_pos.y = l1_start.y + mua * p21.y;\r
+            l1_pos.z = l1_start.z + mua * p21.z;\r
+            l2_pos.x = l2_start.x + mub * p43.x;\r
+            l2_pos.y = l2_start.y + mub * p43.y;\r
+            l2_pos.z = l2_start.z + mub * p43.z;\r
+\r
+            return true;\r
+    }\r
+    \r
+    public static boolean intersectStraightStraight(Tuple3d p1,Vector3d p21,Tuple3d p3,Vector3d p43,Tuple3d pa,Tuple3d pb) {\r
+        Vector3d p13 = new Vector3d();\r
+\r
+        double d1343,d4321,d1321,d4343,d2121;\r
+        double numer,denom;\r
+        \r
+        p13.sub(p1, p3);\r
+        if (Math.abs(p43.x)  < NEAR_ZERO && Math.abs(p43.y)  < NEAR_ZERO && Math.abs(p43.z)  < NEAR_ZERO)\r
+           return false;\r
+        if (Math.abs(p21.x)  < NEAR_ZERO && Math.abs(p21.y)  < NEAR_ZERO && Math.abs(p21.z)  < NEAR_ZERO)\r
+           return false;\r
+\r
+        d1343 = p13.dot(p43);\r
+        d4321 = p43.dot(p21);\r
+        d1321 = p13.dot(p21);\r
+        d4343 = p43.lengthSquared();\r
+        d2121 = p21.lengthSquared();\r
+\r
+        denom = d2121 * d4343 - d4321 * d4321;\r
+        if (Math.abs(denom) < NEAR_ZERO)\r
+           return false;\r
+        numer = d1343 * d4321 - d1321 * d4343;\r
+\r
+        double mua = numer / denom;\r
+        double mub = (d1343 + d4321 * mua) / d4343;\r
+\r
+        pa.x = p1.x + mua * p21.x;\r
+        pa.y = p1.y + mua * p21.y;\r
+        pa.z = p1.z + mua * p21.z;\r
+        pb.x = p3.x + mub * p43.x;\r
+        pb.y = p3.y + mub * p43.y;\r
+        pb.z = p3.z + mub * p43.z;\r
+\r
+        return true;\r
+   }\r
+    \r
+    /**\r
+     * Calculate the line segment PaPb that is the shortest route between\r
+     *  two lines P1P2 and P3P4. Calculate also the values of mua and mub where\r
+     *  Pa = P1 + mua (P2 - P1)\r
+     *  Pb = P3 + mub (P4 - P3)\r
+     * @param p1\r
+     * @param p21\r
+     * @param p3\r
+     * @param p43\r
+     * @param pa\r
+     * @param pb\r
+     * @param mu\r
+     * @return\r
+     */\r
+    public static boolean intersectStraightStraight(Tuple3d p1,Vector3d p21,Tuple3d p3,Vector3d p43,Tuple3d pa,Tuple3d pb, double mu[]) {\r
+        Vector3d p13 = new Vector3d();\r
+\r
+        double d1343,d4321,d1321,d4343,d2121;\r
+        double numer,denom;\r
+        double EPS = 0.001;\r
+        p13.sub(p1, p3);\r
+        if (Math.abs(p43.x)  < EPS && Math.abs(p43.y)  < EPS && Math.abs(p43.z)  < EPS)\r
+           return false;\r
+        if (Math.abs(p21.x)  < EPS && Math.abs(p21.y)  < EPS && Math.abs(p21.z)  < EPS)\r
+           return false;\r
+\r
+        d1343 = p13.dot(p43);\r
+        d4321 = p43.dot(p21);\r
+        d1321 = p13.dot(p21);\r
+        d4343 = p43.lengthSquared();\r
+        d2121 = p21.lengthSquared();\r
+\r
+        denom = d2121 * d4343 - d4321 * d4321;\r
+        if (Math.abs(denom) < EPS)\r
+           return false;\r
+        numer = d1343 * d4321 - d1321 * d4343;\r
+\r
+        mu[0] = numer / denom;\r
+        mu[1] = (d1343 + d4321 * mu[0]) / d4343;\r
+\r
+        pa.x = p1.x + mu[0] * p21.x;\r
+        pa.y = p1.y + mu[0] * p21.y;\r
+        pa.z = p1.z + mu[0] * p21.z;\r
+        pb.x = p3.x + mu[1] * p43.x;\r
+        pb.y = p3.y + mu[1] * p43.y;\r
+        pb.z = p3.z + mu[1] * p43.z;\r
+\r
+        return true;\r
+   }\r
+   \r
+  \r
+   \r
+   public static void rotate(Quat4d q, Tuple3d in, Tuple3d out) {\r
+       // p' = q * p * q'\r
+       double tw =           - q.x*in.x - q.y*in.y - q.z*in.z;\r
+       double tx =  q.w*in.x            + q.y*in.z - q.z*in.y;\r
+       double ty =  q.w*in.y - q.x*in.z            + q.z*in.x;\r
+       double tz =  q.w*in.z + q.x*in.y - q.y*in.x           ;\r
+       \r
+       //temp * q' -> x = -x, y = -y z = -z\r
+       //out.w = tw*q.w + tx*q.x + ty*q.y + tz*q.z;\r
+       out.x =  -tw*q.x + tx*q.w - ty*q.z + tz*q.y;\r
+       out.y =  -tw*q.y + tx*q.z + ty*q.w - tz*q.x;\r
+       out.z =  -tw*q.z - tx*q.y + ty*q.x + tz*q.w;  \r
+   }\r
+   \r
+   public static void getMatrix(Quat4d quat, Matrix3d m) {\r
+                  m.m00 = 1.0f - 2.0 * (quat.y * quat.y + quat.z * quat.z);\r
+                  m.m01 = 2.0 * (quat.x * quat.y + quat.w * quat.z);\r
+                  m.m02 = 2.0 * (quat.x * quat.z - quat.w * quat.y);\r
+                  m.m10 = 2.0 * (quat.x * quat.y - quat.w * quat.z);\r
+                  m.m11 = 1.0 - 2.0f * (quat.x * quat.x + quat.z * quat.z);\r
+                  m.m12 = 2.0 * (quat.y * quat.z + quat.w * quat.x);\r
+                  m.m20 = 2.0 * (quat.x * quat.z + quat.w * quat.y);\r
+                  m.m21 = 2.0 * (quat.y * quat.z - quat.w * quat.x);\r
+                  m.m22 = 1.0 - 2.0f * (quat.x * quat.x + quat.y * quat.y);\r
+\r
+   }\r
+   \r
+   \r
+   private static double q[] = new double[3];\r
+   private static int nxt[] = { 1, 2, 0 };\r
+   /**\r
+    * Converts Matrix to Quaternion\r
+    * \r
+    * Note: non-thread safe.\r
+    * \r
+    * @param mat\r
+    * @param quat\r
+    */\r
+   public static void getQuat(Matrix3d mat, Quat4d quat) {\r
+          double tr = mat.m00 + mat.m11 + mat.m22;\r
+               if (tr > 0.0) {\r
+                       double s = Math.sqrt(tr + 1.0);\r
+                       quat.w = 0.5 * s;\r
+                       s = 0.5 / s;\r
+                       quat.x = (mat.m21 - mat.m12) * s;\r
+                       quat.y = (mat.m02 - mat.m20) * s;\r
+                       quat.z = (mat.m10 - mat.m01) * s;\r
+               } else {\r
+                       int i = 0, j, k;\r
+                       if (mat.m11 > mat.m00)\r
+                               i = 1;\r
+                       if (mat.m22 > mat.getElement(i, i))\r
+                               i = 2;\r
+                       \r
+\r
+                       j = nxt[i];\r
+                       k = nxt[j];\r
+\r
+                       double s = Math.sqrt((mat.getElement(i, i) - (mat.getElement(j, j) + mat.getElement(k, k))) + 1.0);\r
+\r
+                       q[i] = s * 0.5;\r
+\r
+                       if (Math.abs(s) > 0.001)\r
+                               s = 0.5 / s;\r
+\r
+                       quat.w = (mat.getElement(k, j) - mat.getElement(j, k)) * s;\r
+                       q[j] = (mat.getElement(j, i) + mat.getElement(i, j)) * s;\r
+                       q[k] = (mat.getElement(k, i) + mat.getElement(i, k)) * s;\r
+\r
+                       quat.x = q[0];\r
+                       quat.y = q[1];\r
+                       quat.z = q[2];\r
+               }\r
+       }\r
+   \r
+   public static Quat4d getQuat(Matrix3d mat) {\r
+          Quat4d q = new Quat4d();\r
+          getQuat(mat, q);\r
+          return q;\r
+   }\r
+   \r
+   public static AxisAngle4d getFromPseudoEuler(Vector3d euler) {\r
+       AxisAngle4d aa = new AxisAngle4d();\r
+       aa.angle = euler.length();\r
+       Vector3d normal = new Vector3d(euler);\r
+       if (aa.angle > NEAR_ZERO) {\r
+           normal.normalize();\r
+           aa.x = normal.x;\r
+           aa.y = normal.y;\r
+           aa.z = normal.z;\r
+       } else {\r
+           aa.x = 1.0;\r
+           aa.y = 0.0;\r
+           aa.z = 0.0;\r
+       }\r
+       \r
+       return aa;\r
+   }\r
+   \r
+   public static Vector3d getPseudoEuler(AxisAngle4d aa) {\r
+       Vector3d euler = new Vector3d(aa.x,aa.y,aa.z);\r
+       euler.scale(aa.angle);\r
+       return euler;\r
+   }\r
+   \r
+   \r
+   public static void getQuat(Vector3d euler, Quat4d quat)  {\r
+          Quat4d q = EulerTools.getQuatFromEuler(Order.YXZ, euler.y,euler.x,euler.z);\r
+          quat.set(q);\r
+       // http://en.wikipedia.org/wiki/Rotation_formalisms_in_three_dimensions#Conversion_formulae_between_formalisms\r
+       // Using the x-convention, the 3-1-3 Euler angles phi, theta and psi (around the Z, X and again the Z-axis)   \r
+//        quat.x = -Math.cos((euler.x - euler.z)*0.5)*Math.sin(euler.y*0.5);\r
+//        quat.y = -Math.sin((euler.x - euler.z)*0.5)*Math.sin(euler.y*0.5);\r
+//        quat.z = -Math.sin((euler.x + euler.z)*0.5)*Math.cos(euler.y*0.5);\r
+//        quat.w = Math.sin((euler.x + euler.z)*0.5)*Math.cos(euler.y*0.5);\r
+          \r
+          // http://www.euclideanspace.com/maths/geometry/rotations/conversions/eulerToQuaternion/index.htm\r
+          // Y, Z, X order\r
+//         double c1 = Math.cos(euler.y*0.5);\r
+//         double s1 = Math.sin(euler.y*0.5);\r
+//         double c2 = Math.cos(euler.z*0.5);\r
+//         double s2 = Math.sin(euler.z*0.5);\r
+//         double c3 = Math.cos(euler.x*0.5);\r
+//         double s3 = Math.sin(euler.x*0.5);\r
+//         double c1c2 = c1*c2;\r
+//         double s1s2 = s1*s2;\r
+//         quat.w =c1c2*c3 - s1s2*s3;\r
+//         quat.x =c1c2*s3 + s1s2*c3;\r
+//         quat.y =s1*c2*c3 + c1*s2*s3;\r
+//         quat.z =c1*s2*c3 - s1*c2*s3;\r
+\r
+//         Quat4d q2 = EulerTools.getQuatFromEuler(Order.YZX, euler.y,euler.z,euler.x);\r
+//         System.out.println("Q " + quat + " Q2 " + q2);\r
+//        double c1 = Math.cos(euler.y);\r
+//         double s1 = Math.sin(euler.y);\r
+//         double c2 = Math.cos(euler.z);\r
+//         double s2 = Math.sin(euler.z);\r
+//         double c3 = Math.cos(euler.x);\r
+//         double s3 = Math.sin(euler.x);\r
+//         quat.w = Math.sqrt(1.0 + c1 * c2 + c1*c3 - s1 * s2 * s3 + c2*c3) / 2.0;\r
+//         double w4 = (4.0 * quat.w);\r
+//         quat.x = (c2 * s3 + c1 * s3 + s1 * s2 * c3) / w4 ;\r
+//         quat.y = (s1 * c2 + s1 * c3 + c1 * s2 * s3) / w4 ;\r
+//         quat.z = (-s1 * s3 + c1 * s2 * c3 +s2) / w4 ;\r
+   }\r
+   \r
+   \r
+  \r
+   \r
+   public static void getEuler(Quat4d quat,Vector3d euler)  {\r
+          Vector3d e = EulerTools.getEulerFromQuat(Order.YXZ, quat);\r
+          euler.x = e.y;\r
+          euler.y = e.x;\r
+          euler.z = e.z;\r
+          \r
+          // http://en.wikipedia.org/wiki/Rotation_formalisms_in_three_dimensions#Conversion_formulae_between_formalisms\r
+//        euler.x = Math.atan2(quat.x * quat.z + quat.y* quat.w, quat.y*quat.z - quat.x * quat.w);\r
+//        euler.y = Math.acos(-square(quat.x) - square(quat.y) + square(quat.z) + square(quat.w));\r
+//        euler.z = -Math.atan2(quat.x * quat.z - quat.y* quat.w, quat.y*quat.z + quat.x * quat.w);\r
+          \r
+          // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToEuler/index.htm\r
+         // Y, Z, X order\r
+//        double test = quat.x * quat.y + quat.z * quat.w;\r
+//        if (test > NEAR_HALF) {\r
+//                euler.y = 2.0 * Math.atan2(quat.x,quat.w);\r
+//                euler.z = Math.PI * 0.5;\r
+//                euler.x = 0.0;\r
+//        } else if (test < -NEAR_HALF) {\r
+//                euler.y = -2.0 * Math.atan2(quat.x,quat.w);\r
+//                euler.z = -Math.PI * 0.5;\r
+//                euler.x = 0.0;\r
+//        } else {\r
+//                double sqx = square(quat.x);\r
+//                double sqy = square(quat.y);\r
+//                double sqz = square(quat.z);\r
+//                euler.y = Math.atan2(2.0*(quat.y*quat.w-quat.x*quat.z), 1.0 - 2.0*(sqy-sqz));\r
+//                euler.z = Math.asin(2.0*test);\r
+//                euler.x = Math.atan2(2.0*(quat.x*quat.w-quat.y*quat.z), 1.0 - 2.0*(sqx-sqz));\r
+//                System.out.println(euler + " " + EulerTools.getEulerFromQuat(Order.YXZ, quat) +  " " + quat);\r
+//        }\r
+//        double sqw = quat.w*quat.w;\r
+//         double sqx = quat.x*quat.x;\r
+//         double sqy = quat.y*quat.y;\r
+//         double sqz = quat.z*quat.z;\r
+//             double unit = sqx + sqy + sqz + sqw; // if normalised is one, otherwise is correction factor\r
+//             double test = quat.x*quat.y + quat.z*quat.w;\r
+//             if (test > 0.499*unit) { // singularity at north pole\r
+//                     euler.y = 2 * Math.atan2(quat.x,quat.w);\r
+//                     euler.z = Math.PI/2;\r
+//                     euler.x = 0;\r
+//                     return;\r
+//             }\r
+//             if (test < -0.499*unit) { // singularity at south pole\r
+//                     euler.y = -2 * Math.atan2(quat.x,quat.w);\r
+//                     euler.z = -Math.PI/2;\r
+//                     euler.x = 0;\r
+//                     return;\r
+//             }\r
+//             euler.y = Math.atan2(2*quat.y*quat.w-2*quat.x*quat.z , sqx - sqy - sqz + sqw);\r
+//             euler.z = Math.asin(2*test/unit);\r
+//             euler.x = Math.atan2(2*quat.x*quat.w-2*quat.y*quat.z , -sqx + sqy - sqz + sqw);\r
+   }\r
+   \r
+   public static Quat4d getQuat(Vector3d euler) {\r
+          Quat4d q = new Quat4d();\r
+          getQuat(euler,q);\r
+          return q;\r
+   }\r
+   \r
+   \r
+   public static Vector3d getEuler(Quat4d quat) {\r
+          Vector3d v = new Vector3d();\r
+          getEuler(quat, v);\r
+          return v;\r
+   }\r
+   \r
+   public static Quat4d getQuat(AxisAngle4d aa) {\r
+          Quat4d q = new Quat4d();\r
+          getQuat(aa, q);\r
+          return q;\r
+   }\r
+   \r
+   public static AxisAngle4d getAxisAngle(Quat4d q) {\r
+          AxisAngle4d aa = new AxisAngle4d();\r
+          aa.set(q);\r
+          return aa;\r
+   }\r
+   \r
+   public static Quat4d getIdentityQuat() {\r
+          return new Quat4d(0, 0, 0, 1);\r
+   }\r
+   \r
+   public static void getQuat(AxisAngle4d aa, Quat4d q) {\r
+          double mag,amag;\r
+               // Quat = cos(theta/2) + sin(theta/2)(roation_axis) \r
+               \r
+               amag = Math.sqrt( aa.x*aa.x + aa.y*aa.y + aa.z*aa.z);\r
+               if( amag < NEAR_ZERO ) {\r
+                   q.w = 1.0;\r
+                   q.x = 0.0;\r
+                   q.y = 0.0;\r
+                   q.z = 0.0;\r
+               } else {  \r
+                  amag = 1.0/amag; \r
+                  double a2 = aa.angle * 0.5;\r
+                  mag = Math.sin(a2);\r
+                  q.w = Math.cos(a2);\r
+              q.x = aa.x*amag*mag;\r
+              q.y = aa.y*amag*mag;\r
+              q.z = aa.z*amag*mag;\r
+               }\r
+   }\r
+   \r
+   \r
+       /*\r
+        * Cohen-Sutherland\r
+        */\r
+       \r
+       private static final int IN = 0;\r
+       private static final int LEFT = 1;\r
+       private static final int RIGHT = 2;\r
+       private static final int BOTTOM = 4;\r
+       private static final int TOP = 8;\r
+       \r
+       \r
+       private static int bitcode(Vector2f p1, Vector2f min, Vector2f max) {\r
+               int code = IN;\r
+               if (p1.x < min.x)\r
+                       code |= LEFT;\r
+               else if (p1.x > max.x)\r
+                       code |= RIGHT;\r
+               if (p1.y < min.y)\r
+                       code |= BOTTOM;\r
+               else if (p1.y > max.y)\r
+                       code |= TOP;\r
+               return code;\r
+       }\r
+       \r
+       public static boolean clipLineRectangle(Vector2f p1,Vector2f p2, Vector2f min, Vector2f max, Vector2f r1, Vector2f r2) {\r
+               while (true) {\r
+                       int o1 = bitcode(p1, min, max);\r
+                       int o2 = bitcode(p2, min, max);\r
+                       int and = o1 & o2;\r
+                       int or = o1 | o2;\r
+                       if (and != IN) {\r
+                               return false;\r
+                       }\r
+                       if (or == IN) {\r
+                               r1.set(p1);\r
+                               r2.set(p2);\r
+                               return true;\r
+                       }\r
+                       if (o1 == IN) {\r
+                               Vector2f t = p1;\r
+                               p1 = p2;\r
+                               p2 = t;\r
+                               int t2 = o1;\r
+                               o1 = o2;\r
+                               o2 = t2;\r
+                       }\r
+                       if ((o1 & TOP) != IN) {\r
+                               float t = (max.y - p1.y) / (p2.y - p1.y);\r
+                               p1.x += t * (p2.x - p1.x);\r
+                               p1.y = max.y;\r
+                       } else if ((o1 & BOTTOM) != IN) {\r
+                               float t = (min.y - p1.y) / (p2.y - p1.y);\r
+                               p1.x += t * (p2.x - p1.x);\r
+                               p1.y = min.y;\r
+                       } else if ((o1 & LEFT) != IN) {\r
+                               float t = (min.x - p1.x) / (p2.x - p1.x);\r
+                               p1.y += t * (p2.y - p1.y);\r
+                               p1.x = min.x;\r
+                       } else if ((o1 & RIGHT) != IN) {\r
+                               float t = (max.x - p1.x) / (p2.x - p1.x);\r
+                               p1.y += t * (p2.y - p1.y);\r
+                               p1.x = max.x;\r
+                       } else {\r
+                               throw new RuntimeException("Error in clipping code");\r
+                       }\r
+               }\r
+               \r
+       }\r
+       \r
+       public static double square(double d) {\r
+               return d * d;\r
+       }\r
+       \r
+       \r
+        public static void multiplyOrientation(AxisAngle4d aa, AxisAngle4d rot)  {\r
+               Quat4d q1 = new Quat4d();\r
+               getQuat(aa, q1);\r
+               Quat4d q2 = new Quat4d();\r
+               getQuat(rot, q2);\r
+               q2.mul(q1);\r
+               rot.set(q2);\r
+        }\r
+        \r
+        public static double radToDeg(double rad) {\r
+                return (rad / Math.PI) * 180.0;\r
+        }\r
+        \r
+        public static double degToRad(double deg) {\r
+                return (deg / 180.0) * Math.PI;\r
+        }\r
+        \r
+        public static double clamp(double min, double max,double v) {\r
+                if (v < min)\r
+                        return min;\r
+                if (v > max)\r
+                        return max;\r
+                return v;\r
+        }\r
+        \r
+        public static AxisAngle4d createRotation(Vector3d original, Vector3d rotated) { \r
+               AxisAngle4d result = new AxisAngle4d();\r
+               if (createRotation(original, rotated, result))\r
+                       return result;\r
+               return null;\r
+        }\r
+        \r
+        \r
+        public static void setIdentity(Quat4d q) {\r
+               q.w = 1.0;\r
+               q.x = 0.0;\r
+               q.y = 0.0;\r
+               q.z = 0.0;\r
+        }\r
+        \r
+       public static void setIdentity(AxisAngle4d aa) {\r
+               aa.angle = 0.0;\r
+               aa.x = 0.0;\r
+               aa.y = 1.0;\r
+               aa.z = 0.0;\r
+       }\r
+       \r
+       public static void set(Matrix3d mat, double m00, double m01, double m02,\r
+                       double m10, double m11, double m12, double m20, double m21,\r
+                       double m22) {\r
+               mat.m00 = m00;\r
+               mat.m01 = m01;\r
+               mat.m02 = m02;\r
+\r
+               mat.m10 = m10;\r
+               mat.m11 = m11;\r
+               mat.m12 = m12;\r
+\r
+               mat.m20 = m20;\r
+               mat.m21 = m21;\r
+               mat.m22 = m22;\r
+       }\r
+       \r
+       public static void set(Matrix4d mat, double[] v) {\r
+               mat.m00 = v[0];\r
+               mat.m01 = v[1];\r
+               mat.m02 = v[2];\r
+               mat.m03 = v[3];\r
+\r
+               mat.m10 = v[4];\r
+               mat.m11 = v[5];\r
+               mat.m12 = v[6];\r
+               mat.m13 = v[7];\r
+\r
+               mat.m20 = v[8];\r
+               mat.m21 = v[9];\r
+               mat.m22 = v[10];\r
+               mat.m23 = v[11];\r
+\r
+               mat.m30 = v[12];\r
+               mat.m31 = v[13];\r
+               mat.m32 = v[14];\r
+               mat.m33 = v[15];\r
+\r
+       }\r
+        \r
+        public static boolean createRotation(Vector3d original, Vector3d rotated, AxisAngle4d result) {\r
+                \r
+                       if (rotated.lengthSquared() > 0.01)\r
+                               rotated.normalize();\r
+                       else\r
+                               return false;\r
+                       double d = original.dot(rotated);\r
+                       if (d > 0.9999) {\r
+                               // original and rotated are parallel, pointing at the same direction\r
+                               result.angle = 0.0;\r
+                               result.x = 0.0;\r
+                               result.y = 1.0;\r
+                               result.z = 0.0;\r
+                       } else if (d < -0.9999) {\r
+                               // original and rotated are parallel, pointing at the opposite direction \r
+                               Vector3d a = Z_AXIS;\r
+                               if (Math.abs(a.dot(original)) > 0.8 )\r
+                                       a = Y_AXIS;\r
+                               result.set(a, Math.PI);\r
+                       } else {\r
+                               double angle = original.angle(rotated);\r
+                               Vector3d axis = new Vector3d();\r
+                               axis.cross(original, rotated);\r
+                               result.set(axis,angle);\r
+                       }\r
+                       return true;\r
+                }\r
+        \r
+        public static boolean createRotation(Vector3d original, Vector3d rotated, Quat4d result) {\r
+                \r
+                       if (rotated.lengthSquared() > 0.01)\r
+                               rotated.normalize();\r
+                       else\r
+                               return false;\r
+                       double d = original.dot(rotated);\r
+                       if (d > 0.9999) {\r
+                               // original and rotated are parallel, pointing at the same direction\r
+                               result.w = 1.0;\r
+                               result.x = 0.0;\r
+                               result.y = 0.0;\r
+                               result.z = 0.0;\r
+                       } else if (d < -0.9999) {\r
+                               // original and rotated are parallel, pointing at the opposite direction \r
+                               Vector3d a = Z_AXIS;\r
+                               if (Math.abs(a.dot(original)) > 0.8 )\r
+                                       a = Y_AXIS;\r
+                               getQuat(a, Math.PI, result);\r
+                               \r
+                       } else {\r
+                               double angle = original.angle(rotated);\r
+                               Vector3d axis = new Vector3d();\r
+                               axis.cross(original, rotated);\r
+                               getQuat(axis, angle, result);\r
+                       }\r
+                       return true;\r
+                }\r
+        \r
+        public static void getQuat(Vector3d axis, double angle, Quat4d q)\r
+    {\r
+               double mag,amag;\r
+               // Quat = cos(theta/2) + sin(theta/2)(roation_axis) \r
+               \r
+               amag = Math.sqrt( axis.x*axis.x + axis.y*axis.y + axis.z*axis.z);\r
+               if( amag < EPS ) {\r
+                   q.w = 1.0;\r
+                   q.x = 0.0;\r
+                   q.y = 0.0;\r
+                   q.z = 0.0;\r
+               } else {  \r
+                   amag = 1.0/amag; \r
+                   double a2 = angle*0.5;\r
+                   mag = Math.sin(a2);\r
+                   q.w = Math.cos(a2);\r
+                   q.x = axis.x*amag*mag;\r
+                   q.y = axis.y*amag*mag;\r
+                   q.z = axis.z*amag*mag;\r
+               }\r
+       \r
+    }\r
+        \r
+        /**\r
+         * Linear interpolation of quaternions. Result IS set to q1.\r
+         * @param q1\r
+         * @param q2\r
+         * @param alpha\r
+         */\r
+        public static void lip(Quat4d q1, Quat4d q2, double alpha) {\r
+                double s1 = 1.0 - alpha;\r
+                double s2 = alpha;\r
+                q1.scale(s1);\r
+                mad(q1,q2,s2);\r
+                q1.normalize();\r
+        }\r
+        \r
+        public static double dot(Quat4d q1, Quat4d q2) {\r
+                return q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w;\r
+        }\r
+        \r
+        public static void mad(Tuple3d q1, Tuple3d q2, double s2) {\r
+                q1.x += q2.x * s2;\r
+                q1.y += q2.y * s2;\r
+                q1.z += q2.z * s2;\r
+        }\r
+        \r
+        public static void mad(Quat4d q1, Quat4d q2, double s2) {\r
+                q1.x += q2.x * s2;\r
+                q1.y += q2.y * s2;\r
+                q1.z += q2.z * s2;\r
+                q1.w += q2.w * s2;\r
+        }\r
+        \r
+        /**\r
+         * Slerp\r
+         * \r
+         * Sets results to q1. Modifies q2.\r
+         * \r
+         * @param q1\r
+         * @param q2\r
+         * @param alpha\r
+         */\r
+        public static void sip(Quat4d q1, Quat4d q2, double alpha) {\r
+                double cosom = dot(q1,q2);\r
+                if (cosom < 0.0) {\r
+                        cosom = -cosom;\r
+                        q2.negate();\r
+                }\r
+                \r
+                if (cosom > 0.9999) {\r
+                        q2.sub(q1);\r
+                        q2.scale(alpha);\r
+                        q1.add(q2);\r
+                        q1.normalize();\r
+                        return;\r
+                }\r
+                double theta_0 = Math.acos(cosom);\r
+                double theta = theta_0 * alpha;\r
+                Quat4d t = new Quat4d(q1);\r
+                t.scale(-cosom);\r
+                t.add(q2);\r
+                t.normalize();\r
+                t.scale(Math.sin(theta));\r
+                q1.scale(Math.cos(theta));\r
+                q1.add(t);\r
+        }\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/math/Ray.java b/org.simantics.g3d/src/org/simantics/g3d/math/Ray.java
new file mode 100644 (file)
index 0000000..10d8f4a
--- /dev/null
@@ -0,0 +1,15 @@
+package org.simantics.g3d.math;\r
+\r
+import javax.vecmath.Point3d;\r
+import javax.vecmath.Vector3d;\r
+\r
+public class Ray {\r
+       public Point3d pos;\r
+       public Vector3d dir;\r
+       \r
+       public Ray(Point3d pos, Vector3d dir) {\r
+               this.pos = pos;\r
+               this.dir = dir;\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/HasCollectionAdder.java b/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/HasCollectionAdder.java
new file mode 100644 (file)
index 0000000..3646082
--- /dev/null
@@ -0,0 +1,13 @@
+package org.simantics.g3d.objmap.annotations;\r
+\r
+import java.lang.annotation.Annotation;\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target(ElementType.ANNOTATION_TYPE)\r
+public @interface HasCollectionAdder {\r
+        Class<? extends Annotation> value();\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/HasCollectionRemover.java b/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/HasCollectionRemover.java
new file mode 100644 (file)
index 0000000..1e66907
--- /dev/null
@@ -0,0 +1,13 @@
+package org.simantics.g3d.objmap.annotations;\r
+\r
+import java.lang.annotation.Annotation;\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target(ElementType.ANNOTATION_TYPE)\r
+public @interface HasCollectionRemover {\r
+        Class<? extends Annotation> value();\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/HasCollectionRuleFactory.java b/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/HasCollectionRuleFactory.java
new file mode 100644 (file)
index 0000000..9943ee8
--- /dev/null
@@ -0,0 +1,14 @@
+package org.simantics.g3d.objmap.annotations;\r
+\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+import org.simantics.g3d.objmap.rules.factory.ICollectionRuleFactory;\r
+\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target(ElementType.ANNOTATION_TYPE) \r
+public @interface HasCollectionRuleFactory {\r
+       Class<? extends ICollectionRuleFactory> value();\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/HasGetSetRuleFactory.java b/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/HasGetSetRuleFactory.java
new file mode 100644 (file)
index 0000000..fa38fad
--- /dev/null
@@ -0,0 +1,14 @@
+package org.simantics.g3d.objmap.annotations;\r
+\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+import org.simantics.g3d.objmap.rules.factory.IGetSetRuleFactory;\r
+\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target(ElementType.ANNOTATION_TYPE) \r
+public @interface HasGetSetRuleFactory {\r
+       Class<? extends IGetSetRuleFactory> value();\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/HasSetter.java b/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/HasSetter.java
new file mode 100644 (file)
index 0000000..2967cc7
--- /dev/null
@@ -0,0 +1,13 @@
+package org.simantics.g3d.objmap.annotations;\r
+\r
+import java.lang.annotation.Annotation;\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target(ElementType.ANNOTATION_TYPE)\r
+public @interface HasSetter {\r
+        Class<? extends Annotation> value();\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/RelatedElementsAdd.java b/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/RelatedElementsAdd.java
new file mode 100644 (file)
index 0000000..b796aea
--- /dev/null
@@ -0,0 +1,12 @@
+package org.simantics.g3d.objmap.annotations;\r
+\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target(ElementType.METHOD)\r
+public @interface RelatedElementsAdd {\r
+       String value();\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/RelatedElementsGet.java b/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/RelatedElementsGet.java
new file mode 100644 (file)
index 0000000..eb33e0d
--- /dev/null
@@ -0,0 +1,18 @@
+package org.simantics.g3d.objmap.annotations;\r
+\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+import org.simantics.g3d.objmap.annotations.factories.RelatedElementsRuleFactory;\r
+\r
+\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target(ElementType.METHOD)\r
+@HasCollectionRuleFactory(RelatedElementsRuleFactory.class)\r
+@HasCollectionAdder(RelatedElementsAdd.class)\r
+@HasCollectionRemover(RelatedElementsRem.class)\r
+public @interface RelatedElementsGet {\r
+       String value();\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/RelatedElementsRem.java b/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/RelatedElementsRem.java
new file mode 100644 (file)
index 0000000..921ddaf
--- /dev/null
@@ -0,0 +1,13 @@
+package org.simantics.g3d.objmap.annotations;\r
+\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target(ElementType.METHOD)\r
+public @interface RelatedElementsRem {\r
+       String value();\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/RelatedGetObj.java b/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/RelatedGetObj.java
new file mode 100644 (file)
index 0000000..0b1c61d
--- /dev/null
@@ -0,0 +1,17 @@
+package org.simantics.g3d.objmap.annotations;\r
+\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+import org.simantics.g3d.objmap.annotations.factories.RelatedGetSetObjRuleFactory;\r
+\r
+\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target(ElementType.METHOD)\r
+@HasGetSetRuleFactory(RelatedGetSetObjRuleFactory.class)\r
+@HasSetter(RelatedSetObj.class)\r
+public @interface RelatedGetObj {\r
+       String value();\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/RelatedGetValue.java b/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/RelatedGetValue.java
new file mode 100644 (file)
index 0000000..1f39513
--- /dev/null
@@ -0,0 +1,20 @@
+package org.simantics.g3d.objmap.annotations;\r
+\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+import org.simantics.g3d.objmap.annotations.factories.RelatedGetSetValueRuleFactory;\r
+import org.simantics.objmap.rules.adapters.IdentityAdapter;\r
+import org.simantics.objmap.rules.adapters.ValueAdapter;\r
+\r
+\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target(ElementType.METHOD)\r
+@HasGetSetRuleFactory(RelatedGetSetValueRuleFactory.class)\r
+@HasSetter(RelatedSetValue.class)\r
+public @interface RelatedGetValue {\r
+       String value();\r
+        Class<? extends ValueAdapter> adapter() default IdentityAdapter.class;\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/RelatedSetObj.java b/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/RelatedSetObj.java
new file mode 100644 (file)
index 0000000..440985b
--- /dev/null
@@ -0,0 +1,13 @@
+package org.simantics.g3d.objmap.annotations;\r
+\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target(ElementType.METHOD)\r
+public @interface RelatedSetObj {\r
+       String value();\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/RelatedSetValue.java b/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/RelatedSetValue.java
new file mode 100644 (file)
index 0000000..e152018
--- /dev/null
@@ -0,0 +1,13 @@
+package org.simantics.g3d.objmap.annotations;\r
+\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target(ElementType.METHOD)\r
+public @interface RelatedSetValue {\r
+       String value();\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/factories/RelatedElementsRuleFactory.java b/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/factories/RelatedElementsRuleFactory.java
new file mode 100644 (file)
index 0000000..1f535ad
--- /dev/null
@@ -0,0 +1,42 @@
+package org.simantics.g3d.objmap.annotations.factories;\r
+\r
+import java.lang.annotation.Annotation;\r
+import java.lang.reflect.Method;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.g3d.objmap.annotations.RelatedElementsAdd;\r
+import org.simantics.g3d.objmap.annotations.RelatedElementsGet;\r
+import org.simantics.g3d.objmap.annotations.RelatedElementsRem;\r
+import org.simantics.g3d.objmap.rules.factory.ICollectionRuleFactory;\r
+import org.simantics.g3d.objmap.rules.range.CollectionAccessor;\r
+import org.simantics.objmap.IMappingRule;\r
+import org.simantics.objmap.rules.MappedElementsRule;\r
+import org.simantics.objmap.rules.domain.RelatedObjectsAccessor;\r
+\r
+public class RelatedElementsRuleFactory implements ICollectionRuleFactory {\r
+       \r
+       @Override\r
+       public IMappingRule create(ReadGraph g, Annotation annotation,\r
+                       Method getter, Method adder, Method remover)\r
+                       throws DatabaseException {\r
+               RelatedElementsGet getterAnn = (RelatedElementsGet)annotation;\r
+               return new MappedElementsRule(new RelatedObjectsAccessor(g.getResource(getterAnn.value()),true),\r
+                                       new CollectionAccessor<Object>(getter, adder, remover));\r
+       }\r
+       \r
+       @Override\r
+       public boolean isAdder(Annotation getterAnnotation, Annotation annotation) {\r
+               RelatedElementsGet getterAnn = (RelatedElementsGet)getterAnnotation;\r
+               RelatedElementsAdd adderAnn = (RelatedElementsAdd)annotation;\r
+               return getterAnn.value().equals(adderAnn.value());\r
+       }\r
+       \r
+       @Override\r
+       public boolean isRemover(Annotation getterAnnotation, Annotation annotation) {\r
+               RelatedElementsGet getterAnn = (RelatedElementsGet)getterAnnotation;\r
+               RelatedElementsRem adderAnn = (RelatedElementsRem)annotation;\r
+               return getterAnn.value().equals(adderAnn.value());\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/factories/RelatedGetSetObjRuleFactory.java b/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/factories/RelatedGetSetObjRuleFactory.java
new file mode 100644 (file)
index 0000000..3f75b03
--- /dev/null
@@ -0,0 +1,44 @@
+package org.simantics.g3d.objmap.annotations.factories;\r
+\r
+import java.lang.annotation.Annotation;\r
+import java.lang.reflect.Method;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.g3d.objmap.annotations.RelatedGetObj;\r
+import org.simantics.g3d.objmap.annotations.RelatedGetValue;\r
+import org.simantics.g3d.objmap.annotations.RelatedSetObj;\r
+import org.simantics.g3d.objmap.annotations.RelatedSetValue;\r
+import org.simantics.g3d.objmap.rules.factory.IGetSetRuleFactory;\r
+import org.simantics.g3d.objmap.rules.range.GetSetObjectAccessor;\r
+import org.simantics.objmap.IMappingRule;\r
+import org.simantics.objmap.rules.MappedElementRule;\r
+import org.simantics.objmap.rules.domain.RelatedObjectAccessor;\r
+\r
+/**\r
+ * Rule factory for mapped object using Getter/Setter-methods.\r
+ * \r
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>\r
+ *\r
+ */\r
+public class RelatedGetSetObjRuleFactory implements IGetSetRuleFactory {\r
+       \r
+       @Override\r
+       public IMappingRule create(ReadGraph g, Annotation annotation,\r
+                       Method getter, Method setter)\r
+                       throws DatabaseException {\r
+               RelatedGetObj getterAnn = (RelatedGetObj)annotation;\r
+               return new MappedElementRule(new RelatedObjectAccessor(g.getResource(getterAnn.value())),\r
+                                       new GetSetObjectAccessor<Object>(getter, setter));\r
+       }\r
+       \r
+       @Override\r
+       public boolean isSetter(Annotation getterAnnotation, Annotation annotation) {\r
+               RelatedGetObj getterAnn = (RelatedGetObj)getterAnnotation;\r
+               RelatedSetObj setterAnn = (RelatedSetObj)annotation;\r
+               return getterAnn.value().equals(setterAnn.value());\r
+       }\r
+       \r
+       \r
+\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/factories/RelatedGetSetValueRuleFactory.java b/org.simantics.g3d/src/org/simantics/g3d/objmap/annotations/factories/RelatedGetSetValueRuleFactory.java
new file mode 100644 (file)
index 0000000..273f2b9
--- /dev/null
@@ -0,0 +1,100 @@
+package org.simantics.g3d.objmap.annotations.factories;\r
+\r
+import java.lang.annotation.Annotation;\r
+import java.lang.reflect.Method;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.g3d.objmap.annotations.RelatedGetValue;\r
+import org.simantics.g3d.objmap.annotations.RelatedSetValue;\r
+import org.simantics.g3d.objmap.rules.factory.IGetSetRuleFactory;\r
+import org.simantics.g3d.objmap.rules.range.GetSetValueAccessor;\r
+import org.simantics.layer0.Layer0;\r
+import org.simantics.objmap.IMappingRule;\r
+import org.simantics.objmap.rules.ValueRule;\r
+import org.simantics.objmap.rules.adapters.IdentityAdapter;\r
+import org.simantics.objmap.rules.adapters.ValueAdapter;\r
+import org.simantics.objmap.rules.domain.RelatedValueAccessor;\r
+import org.simantics.objmap.rules.range.AdaptedRangeAccessor;\r
+import org.simantics.objmap.rules.range.IRangeAccessor;\r
+\r
+/**\r
+ * Rule factory for mapped value using Getter/Setter-methods.\r
+ * \r
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>\r
+ *\r
+ */\r
+public class RelatedGetSetValueRuleFactory implements IGetSetRuleFactory {\r
+       \r
+       @Override\r
+       public IMappingRule create(ReadGraph g, Annotation annotation,\r
+                       Method getter, Method setter)\r
+                       throws DatabaseException {\r
+               RelatedGetValue getterAnn = (RelatedGetValue)annotation;\r
+               \r
+               Class<? extends ValueAdapter> adapterClass = getterAnn.adapter();\r
+                IRangeAccessor<Object> rangeAccessor = new GetSetValueAccessor<Object>(getter, setter);\r
+        Resource valueType;\r
+        if (adapterClass == IdentityAdapter.class) {\r
+            valueType = dataTypeOfClass(g, getter.getReturnType());\r
+        } else {\r
+               try{\r
+                        ValueAdapter adapter = adapterClass.newInstance();\r
+                 rangeAccessor = new AdaptedRangeAccessor(rangeAccessor, adapter);\r
+                 valueType = adapter.rangeTypeToDomainType(g, getter.getReturnType());\r
+             } catch (InstantiationException e) {\r
+                 throw new RuntimeException(e);\r
+             } catch (IllegalAccessException e) {\r
+                 throw new RuntimeException(e);\r
+             }\r
+        }\r
+               return new ValueRule(new RelatedValueAccessor(g.getResource(getterAnn.value()), valueType),\r
+                                       rangeAccessor);\r
+       }\r
+       \r
+       @Override\r
+       public boolean isSetter(Annotation getterAnnotation, Annotation annotation) {\r
+               RelatedGetValue getterAnn = (RelatedGetValue)getterAnnotation;\r
+               RelatedSetValue setterAnn = (RelatedSetValue)annotation;\r
+               return getterAnn.value().equals(setterAnn.value());\r
+       }\r
+       \r
+       public static Resource dataTypeOfClass(ReadGraph g, Class<?> clazz) {\r
+        Layer0 b = Layer0.getInstance(g);\r
+        if(clazz.equals(Double.class) || clazz.equals(double.class))\r
+            return b.Double;\r
+        else if(clazz.equals(String.class))\r
+            return b.String;\r
+        else if(clazz.equals(Integer.class) || clazz.equals(int.class))\r
+            return b.Integer;\r
+        else if(clazz.equals(Float.class) || clazz.equals(float.class))\r
+            return b.Float;\r
+        else if(clazz.equals(Boolean.class) || clazz.equals(boolean.class))\r
+            return b.Boolean;\r
+        else if(clazz.equals(Long.class) || clazz.equals(long.class))\r
+            return b.Long;\r
+        else if(clazz.equals(Byte.class) || clazz.equals(byte.class))\r
+            return b.Byte;\r
+        \r
+        else if(clazz.equals(double[].class))\r
+            return b.DoubleArray;\r
+        else if(clazz.equals(int[].class))\r
+            return b.IntegerArray;\r
+        else if(clazz.equals(byte[].class))\r
+            return b.ByteArray;\r
+        else if(clazz.equals(float[].class))\r
+            return b.FloatArray;\r
+        else if(clazz.equals(boolean[].class))\r
+            return b.BooleanArray;\r
+        else if(clazz.equals(String[].class))\r
+            return b.StringArray;\r
+        else if(clazz.equals(long[].class))\r
+            return b.LongArray;\r
+        else {\r
+               System.out.println("Couldn't find a data type for " + clazz);\r
+            return null;\r
+        }\r
+    }\r
+\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/objmap/rules/factory/ICollectionRuleFactory.java b/org.simantics.g3d/src/org/simantics/g3d/objmap/rules/factory/ICollectionRuleFactory.java
new file mode 100644 (file)
index 0000000..d7176f1
--- /dev/null
@@ -0,0 +1,14 @@
+package org.simantics.g3d.objmap.rules.factory;\r
+\r
+import java.lang.annotation.Annotation;\r
+import java.lang.reflect.Method;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.objmap.IMappingRule;\r
+\r
+public interface ICollectionRuleFactory {\r
+       IMappingRule create(ReadGraph g, Annotation annotation, Method getter, Method adder, Method remover) throws DatabaseException;\r
+       boolean isAdder(Annotation getterAnnotation, Annotation annotation);\r
+       boolean isRemover(Annotation getterAnnotation, Annotation annotation);\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/objmap/rules/factory/IGetSetRuleFactory.java b/org.simantics.g3d/src/org/simantics/g3d/objmap/rules/factory/IGetSetRuleFactory.java
new file mode 100644 (file)
index 0000000..f5218cd
--- /dev/null
@@ -0,0 +1,13 @@
+package org.simantics.g3d.objmap.rules.factory;\r
+\r
+import java.lang.annotation.Annotation;\r
+import java.lang.reflect.Method;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.objmap.IMappingRule;\r
+\r
+public interface IGetSetRuleFactory {\r
+       IMappingRule create(ReadGraph g, Annotation annotation, Method getter, Method setter) throws DatabaseException;\r
+       boolean isSetter(Annotation getterAnnotation, Annotation annotation);\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/objmap/rules/range/CollectionAccessor.java b/org.simantics.g3d/src/org/simantics/g3d/objmap/rules/range/CollectionAccessor.java
new file mode 100644 (file)
index 0000000..896b697
--- /dev/null
@@ -0,0 +1,80 @@
+package org.simantics.g3d.objmap.rules.range;\r
+\r
+import java.lang.reflect.InvocationTargetException;\r
+import java.lang.reflect.Method;\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+\r
+import org.simantics.objmap.MappingException;\r
+import org.simantics.objmap.rules.range.IRangeAccessor;\r
+\r
+/**\r
+ * Accessor for mapped collections. \r
+ * Uses three methods:\r
+ * - Getter: returns the collection.\r
+ * - Adder: adds one item into the collection.\r
+ * - Remover: removes one item from the collection. \r
+ * \r
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>\r
+ *\r
+ * @param <T>\r
+ */\r
+public class CollectionAccessor<T>  implements IRangeAccessor<Collection<T>> {\r
+       \r
+       private Method getter;\r
+       private Method adder;\r
+       private Method remover;\r
+       \r
+       public CollectionAccessor(Method getter, Method adder, Method remover) {\r
+               this.getter = getter;\r
+               this.adder = adder;\r
+               this.remover = remover;\r
+       }\r
+       \r
+       @SuppressWarnings("unchecked")\r
+       public java.util.Collection<T> get(Object element) throws org.simantics.objmap.MappingException {\r
+               try {\r
+                       return (Collection<T>) getter.invoke(element);\r
+               } catch (IllegalArgumentException e) {\r
+                       throw new MappingException(e);\r
+               } catch (IllegalAccessException e) {\r
+                       throw new MappingException(e);\r
+               } catch (InvocationTargetException e) {\r
+                       throw new MappingException(e);\r
+               }\r
+       };\r
+\r
+       @Override\r
+       public boolean set(Object element, Collection<T> value)\r
+                       throws MappingException {\r
+               java.util.Collection<T> current = get(element);\r
+               Collection<T> adding = new ArrayList<T>();\r
+               Collection<T> removing = new ArrayList<T>();\r
+               for (T e : current) {\r
+                       if (!value.contains(e))\r
+                               removing.add(e);\r
+               }\r
+               for (T e : value) {\r
+                       if (!current.contains(e))\r
+                               adding.add(e);\r
+               }\r
+               \r
+               try {\r
+                       for (T e : removing) {\r
+                               remover.invoke(element, e);\r
+                       }\r
+                       \r
+                       for (T e : adding) {\r
+                               adder.invoke(element, e);\r
+                       }\r
+               } catch (IllegalArgumentException e) {\r
+                       throw new MappingException(e);\r
+               } catch (IllegalAccessException e) {\r
+                       throw new MappingException(e);\r
+               } catch (InvocationTargetException e) {\r
+                       throw new MappingException(e);\r
+               }\r
+               return true;\r
+               \r
+       }\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/objmap/rules/range/GetSetObjectAccessor.java b/org.simantics.g3d/src/org/simantics/g3d/objmap/rules/range/GetSetObjectAccessor.java
new file mode 100644 (file)
index 0000000..8ceda89
--- /dev/null
@@ -0,0 +1,58 @@
+package org.simantics.g3d.objmap.rules.range;\r
+\r
+import java.lang.reflect.InvocationTargetException;\r
+import java.lang.reflect.Method;\r
+\r
+import org.simantics.objmap.MappingException;\r
+import org.simantics.objmap.rules.range.IRangeAccessor;\r
+\r
+/**\r
+ * Accessor for mapped objects. Uses two methods:\r
+ * - Getter: returns the current object.\r
+ * - Setter: sets the current object. The object may be null.\r
+ * \r
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>\r
+ *\r
+ * @param <T>\r
+ */\r
+public class GetSetObjectAccessor<T>  implements IRangeAccessor<T> {\r
+       \r
+       private Method getter;\r
+       private Method setter;\r
+       \r
+       \r
+       public GetSetObjectAccessor(Method getter, Method setter) {\r
+               this.getter = getter;\r
+               this.setter = setter;\r
+               \r
+       }\r
+       \r
+       @SuppressWarnings("unchecked")\r
+       public T get(Object element) throws org.simantics.objmap.MappingException {\r
+               try {\r
+                       return (T) getter.invoke(element);\r
+               } catch (IllegalArgumentException e) {\r
+                       throw new MappingException(e);\r
+               } catch (IllegalAccessException e) {\r
+                       throw new MappingException(e);\r
+               } catch (InvocationTargetException e) {\r
+                       throw new MappingException(e);\r
+               }\r
+       };\r
+\r
+       @Override\r
+       public boolean set(Object element, T value)\r
+                       throws MappingException {       \r
+               try {\r
+                       setter.invoke(element, value);\r
+               } catch (IllegalArgumentException e) {\r
+                       throw new MappingException(e);\r
+               } catch (IllegalAccessException e) {\r
+                       throw new MappingException(e);\r
+               } catch (InvocationTargetException e) {\r
+                       throw new MappingException(e);\r
+               }\r
+               return true;\r
+               \r
+       }\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/objmap/rules/range/GetSetValueAccessor.java b/org.simantics.g3d/src/org/simantics/g3d/objmap/rules/range/GetSetValueAccessor.java
new file mode 100644 (file)
index 0000000..f7da653
--- /dev/null
@@ -0,0 +1,73 @@
+package org.simantics.g3d.objmap.rules.range;\r
+\r
+import java.lang.reflect.InvocationTargetException;\r
+import java.lang.reflect.Method;\r
+\r
+import org.simantics.objmap.MappingException;\r
+import org.simantics.objmap.rules.range.IRangeAccessor;\r
+\r
+/**\r
+ * Accessor for mapped value. Uses two methods:\r
+ * - Getter: returns the current value.\r
+ * - Setter: sets the current value. The value may be null. (if setter parameter is primitive, null value is not mapped).\r
+ * \r
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>\r
+ *\r
+ * @param <T>\r
+ */\r
+public class GetSetValueAccessor<T>  implements IRangeAccessor<T> {\r
+       \r
+       private Method getter;\r
+       private Method setter;\r
+       private boolean primitive;\r
+       \r
+       public GetSetValueAccessor(Method getter, Method setter) {\r
+               this.getter = getter;\r
+               this.setter = setter;\r
+               this.primitive = setter.getParameterTypes()[0].isPrimitive();\r
+       }\r
+       \r
+       @SuppressWarnings("unchecked")\r
+       public T get(Object element) throws org.simantics.objmap.MappingException {\r
+               try {\r
+                       return (T) getter.invoke(element);\r
+               } catch (IllegalArgumentException e) {\r
+                       throw new MappingException(e);\r
+               } catch (IllegalAccessException e) {\r
+                       throw new MappingException(e);\r
+               } catch (InvocationTargetException e) {\r
+                       throw new MappingException(e);\r
+               }\r
+       };\r
+\r
+       @Override\r
+       public boolean set(Object element, T value)\r
+                       throws MappingException {\r
+               if (value == null && primitive)\r
+                       return false;\r
+               if (equal(get(element),value))\r
+                       return false;\r
+               try {\r
+                       setter.invoke(element, value);\r
+               } catch (IllegalArgumentException e) {\r
+                       throw new MappingException(e);\r
+               } catch (IllegalAccessException e) {\r
+                       throw new MappingException(e);\r
+               } catch (InvocationTargetException e) {\r
+                       throw new MappingException(e);\r
+               }\r
+               return true;\r
+               \r
+       }\r
+       \r
+       private boolean equal(Object v1, Object v2) {\r
+               if (v1 == null) {\r
+                       if (v2 == null)\r
+                               return true;\r
+                       return false;\r
+               } else if (v2 == null) {\r
+                       return false;\r
+               }\r
+               return v1.equals(v2);\r
+       }\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/objmap/schema/AdaptedLinkType.java b/org.simantics.g3d/src/org/simantics/g3d/objmap/schema/AdaptedLinkType.java
new file mode 100644 (file)
index 0000000..8a580f0
--- /dev/null
@@ -0,0 +1,71 @@
+package org.simantics.g3d.objmap.schema;\r
+\r
+//import org.apache.log4j.Logger;\r
+import org.eclipse.core.runtime.IAdaptable;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.objmap.IFunction;\r
+import org.simantics.objmap.ILinkType;\r
+import org.simantics.objmap.MappingException;\r
+\r
+/**\r
+ * A link type that is associated with adaptable resource (ReadGraph.getAdapter(Resource,Class)). \r
+ * The adapted object must implement IAdaptable interface for returning the original Resource. \r
+ * \r
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>\r
+ *\r
+ */\r
+public class AdaptedLinkType implements ILinkType {\r
+\r
+       \r
+       //static Logger LOGGER = Logger.getLogger("org.simantics.objmap");\r
+    \r
+    Resource domainType;\r
+    Class<?> rangeType;\r
+    \r
+    \r
+    public AdaptedLinkType(Resource domainType, Class<?> rangeType) {\r
+        this.domainType = domainType;\r
+        this.rangeType = rangeType;\r
+    }\r
+    \r
+    @Override\r
+    public Resource createDomainElement(WriteGraph g, Object rangeElement)\r
+               throws MappingException {\r
+       try {\r
+               IAdaptable adaptable = (IAdaptable)rangeElement;\r
+               Resource res = (Resource)adaptable.getAdapter(Resource.class);\r
+               if (res == null)\r
+                       throw new NullPointerException();\r
+               return res;\r
+       } catch (Exception e) {\r
+               throw new MappingException("Adapted object must implement IAdaptable interface to return the source Resource.", e);\r
+       }\r
+       \r
+    }\r
+    \r
+    @Override\r
+    public Object createRangeElement(ReadGraph g, Resource domainElement)\r
+               throws MappingException {\r
+       try {\r
+               return g.adapt(domainElement, rangeType);\r
+       } catch (DatabaseException e) {\r
+               throw new MappingException(e);\r
+       }\r
+    }\r
+    \r
+    @Override\r
+    public boolean updateDomain(WriteGraph g, IFunction<Object, Resource> map,\r
+               Resource domainElement, Object rangeElement)\r
+               throws MappingException {\r
+       return false;\r
+    }\r
+    @Override\r
+    public boolean updateRange(ReadGraph g, IFunction<Resource, Object> map,\r
+               Resource domainElement, Object rangeElement)\r
+               throws MappingException {\r
+       return false;\r
+    }\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/objmap/schema/DefaultSchema.java b/org.simantics.g3d/src/org/simantics/g3d/objmap/schema/DefaultSchema.java
new file mode 100644 (file)
index 0000000..43ed22f
--- /dev/null
@@ -0,0 +1,96 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.g3d.objmap.schema;\r
+\r
+import gnu.trove.THashMap;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.common.utils.NameUtils;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.objmap.ILinkType;\r
+import org.simantics.objmap.IMappingSchema;\r
+import org.simantics.objmap.MappingException;\r
+import org.simantics.objmap.schema.SimpleLinkType;\r
+\r
+/**\r
+ * \r
+ */\r
+public class DefaultSchema implements IMappingSchema {\r
+\r
+    THashMap<Resource, ILinkType> domainLinkTypes = \r
+        new THashMap<Resource, ILinkType>();\r
+    THashMap<Class<?>, ILinkType> rangeLinkTypes = \r
+        new THashMap<Class<?>, ILinkType>();\r
+    \r
+    public void addLinkType(SimpleLinkType linkType) {\r
+        domainLinkTypes.put(linkType.domainType, linkType);\r
+        rangeLinkTypes.put(linkType.rangeType, linkType);\r
+    }\r
+    \r
+    public void addLinkType(AdaptedLinkType linkType) {\r
+        domainLinkTypes.put(linkType.domainType, linkType);\r
+        rangeLinkTypes.put(linkType.rangeType, linkType);\r
+    }\r
+    \r
+    @Override\r
+    public ILinkType linkTypeOfDomainElement(ReadGraph g, Resource element) throws MappingException {        \r
+        try {\r
+               \r
+               for(Resource type : g.getTypes(element)) {\r
+\r
+                       ILinkType linkType = domainLinkTypes.get(type);\r
+                       if(linkType != null) return linkType;\r
+                       \r
+               }\r
+               \r
+               throw new MappingException("Didn't find a link type for " +\r
+                               NameUtils.getSafeName(g, element) + ".");\r
+                               \r
+        } catch (DatabaseException e) {\r
+            throw new MappingException(e);\r
+        }\r
+    }\r
+\r
+    @Override\r
+    public ILinkType linkTypeOfRangeElement(Object element) throws MappingException {\r
+       ILinkType type = rangeLinkTypes.get(element.getClass());\r
+               if(type == null)  {\r
+                       for (Class<?> clazz : element.getClass().getInterfaces()) {\r
+                               type = rangeLinkTypes.get(clazz);\r
+                               if (type != null)\r
+                                       return type;\r
+                               \r
+                       }\r
+                       throw new MappingException("Didn't find a link type for " +     element + ".");\r
+               }\r
+               return type;\r
+    }\r
+\r
+    \r
+    public ILinkType linkTypeOfDomainType(ReadGraph g, Resource type)  {        \r
+       return domainLinkTypes.get(type);\r
+    }\r
+    \r
+    public ILinkType linkTypeOfRangeType(Class<?> clazz) {\r
+       ILinkType type = rangeLinkTypes.get(clazz);\r
+       if(type == null)  {\r
+                       for (Class<?> c : clazz.getInterfaces()) {\r
+                               type = rangeLinkTypes.get(clazz);\r
+                               if (type != null)\r
+                                       return type;\r
+                               \r
+                       }\r
+               }\r
+       return null;\r
+    }\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/objmap/schema/MappingSchemas.java b/org.simantics.g3d/src/org/simantics/g3d/objmap/schema/MappingSchemas.java
new file mode 100644 (file)
index 0000000..0b69d59
--- /dev/null
@@ -0,0 +1,166 @@
+package org.simantics.g3d.objmap.schema;\r
+\r
+import java.lang.annotation.Annotation;\r
+import java.lang.reflect.Field;\r
+import java.lang.reflect.Method;\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.g3d.objmap.annotations.HasCollectionAdder;\r
+import org.simantics.g3d.objmap.annotations.HasCollectionRemover;\r
+import org.simantics.g3d.objmap.annotations.HasCollectionRuleFactory;\r
+import org.simantics.g3d.objmap.annotations.HasGetSetRuleFactory;\r
+import org.simantics.g3d.objmap.annotations.HasSetter;\r
+import org.simantics.g3d.objmap.rules.factory.ICollectionRuleFactory;\r
+import org.simantics.g3d.objmap.rules.factory.IGetSetRuleFactory;\r
+import org.simantics.objmap.ILinkType;\r
+import org.simantics.objmap.IMappingRule;\r
+import org.simantics.objmap.annotations.GraphType;\r
+import org.simantics.objmap.annotations.RelatedValue;\r
+import org.simantics.objmap.annotations.meta.HasClassRuleFactory;\r
+import org.simantics.objmap.annotations.meta.HasFieldRuleFactory;\r
+import org.simantics.objmap.annotations.meta.HasMethodRuleFactory;\r
+import org.simantics.objmap.schema.SimpleLinkType;\r
+\r
+public class MappingSchemas {\r
+       /**\r
+     * Creates a new SimpleLinkType based on the annotations in the given class.\r
+     * @throws IllegalAccessException \r
+     * @throws InstantiationException \r
+     * @see GraphType\r
+     * @see RelatedValue\r
+     */\r
+       public static SimpleLinkType fromAnnotations(ReadGraph g, Class<?> clazz) throws DatabaseException, InstantiationException, IllegalAccessException {\r
+           GraphType graphType = clazz.getAnnotation(GraphType.class);\r
+           \r
+           ArrayList<IMappingRule> rules = new ArrayList<IMappingRule>();\r
+           collectRulesFromAnnotations(g, clazz, rules);\r
+           \r
+           return new SimpleLinkType(\r
+                   g.getResource(graphType.value()), \r
+                clazz, rules);    \r
+       }\r
+       \r
+       public static void collectRulesFromAnnotations(ReadGraph g, Class<?> clazz, Collection<IMappingRule> rules) throws DatabaseException, InstantiationException, IllegalAccessException {\r
+           Class<?> superclass = clazz.getSuperclass();\r
+           if(superclass != null)\r
+               collectRulesFromAnnotations(g, superclass, rules);\r
+               \r
+        for(Annotation annotation : clazz.getAnnotations()) {\r
+            HasClassRuleFactory factory = \r
+                annotation.annotationType().getAnnotation(HasClassRuleFactory.class);\r
+            if(factory != null) {\r
+                rules.add(factory.value().newInstance()\r
+                        .create(g, annotation, clazz));\r
+            }\r
+        }\r
+\r
+        for(Field f : clazz.getDeclaredFields()) {\r
+            f.setAccessible(true);\r
+\r
+            for(Annotation annotation : f.getAnnotations()) {\r
+                HasFieldRuleFactory factory = \r
+                    annotation.annotationType().getAnnotation(HasFieldRuleFactory.class);\r
+                if(factory != null) {\r
+                    rules.add(factory.value().newInstance()\r
+                            .create(g, annotation, f));\r
+                }\r
+            }\r
+        }\r
+\r
+        for(Method m : clazz.getDeclaredMethods()) {\r
+            m.setAccessible(true);\r
+\r
+            for(Annotation annotation : m.getAnnotations()) {\r
+                HasMethodRuleFactory factory = \r
+                    annotation.annotationType().getAnnotation(HasMethodRuleFactory.class);\r
+                if(factory != null) {\r
+                       rules.add(factory.value().newInstance().create(g, annotation, m));\r
+                }\r
+            }\r
+        }\r
+        \r
+        for (Method m : clazz.getDeclaredMethods()) {\r
+               m.setAccessible(true);\r
+               for (Annotation annotation : m.getAnnotations()) {\r
+                       Class<? extends Annotation> annotationType = annotation.annotationType();\r
+                        HasGetSetRuleFactory factory = \r
+                         annotationType.getAnnotation(HasGetSetRuleFactory.class);\r
+                        if (factory != null) {\r
+                                \r
+                                HasSetter setterAnnType = annotationType.getAnnotation(HasSetter.class);\r
+                                \r
+                                Class<? extends Annotation> setterAnn = setterAnnType.value();\r
+                                \r
+                                IGetSetRuleFactory ruleFactory = factory.value().newInstance();\r
+                                \r
+                                Method getter = m;\r
+                                Method setter = null;\r
+                                \r
+                                for (Method m2 : clazz.getDeclaredMethods()) {\r
+                                        Annotation set = m2.getAnnotation(setterAnn);\r
+                                        if (set != null && ruleFactory.isSetter(annotation, set))\r
+                                                setter = m2;\r
+                                }\r
+\r
+                                rules.add(ruleFactory.create(g, annotation, getter, setter));\r
+                        }\r
+                \r
+               }\r
+        }\r
+        \r
+        for (Method m : clazz.getDeclaredMethods()) {\r
+               m.setAccessible(true);\r
+               for (Annotation annotation : m.getAnnotations()) {\r
+                       Class<? extends Annotation> annotationType = annotation.annotationType();\r
+                        HasCollectionRuleFactory factory = \r
+                         annotationType.getAnnotation(HasCollectionRuleFactory.class);\r
+                        if (factory != null) {\r
+                                \r
+                                HasCollectionAdder adderAnnType = annotationType.getAnnotation(HasCollectionAdder.class);\r
+                                HasCollectionRemover removerAnnType = annotationType.getAnnotation(HasCollectionRemover.class);\r
+                \r
+                                Class<? extends Annotation> adderAnn = adderAnnType.value();\r
+                                Class<? extends Annotation> removerAnn = removerAnnType.value();\r
+                                \r
+                                ICollectionRuleFactory ruleFactory = factory.value().newInstance();\r
+                                \r
+                                Method getter = m;\r
+                                Method adder = null;\r
+                                Method remover = null;\r
+                                \r
+                                for (Method m2 : clazz.getDeclaredMethods()) {\r
+                                        Annotation add = m2.getAnnotation(adderAnn);\r
+                                        Annotation rem = m2.getAnnotation(removerAnn);\r
+                                        if (add != null && ruleFactory.isAdder(annotation, add))\r
+                                                adder = m2;\r
+                                        if (rem != null && ruleFactory.isRemover(annotation, rem))\r
+                                                remover = m2;\r
+                                }\r
+                                \r
+                                \r
+                                \r
+                                rules.add(ruleFactory.create(g, annotation, getter,adder,remover));\r
+                        }\r
+                \r
+               }\r
+        }\r
+    }\r
+       \r
+       /**\r
+     * Creates a new SimpleLinkType based on the annotations in the given class.\r
+     * @throws IllegalAccessException \r
+     * @throws InstantiationException \r
+     * @see GraphType\r
+     * @see RelatedValue\r
+     */\r
+       public static AdaptedLinkType fromAdaptable(ReadGraph g, String type, Class<?> clazz) throws DatabaseException, InstantiationException, IllegalAccessException {\r
+           \r
+           \r
+           return new AdaptedLinkType(g.getResource(type), clazz);    \r
+       }\r
+       \r
+       \r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/preferences/G3DPreferencePage.java b/org.simantics.g3d/src/org/simantics/g3d/preferences/G3DPreferencePage.java
new file mode 100644 (file)
index 0000000..7f90aeb
--- /dev/null
@@ -0,0 +1,79 @@
+package org.simantics.g3d.preferences;
+
+import org.eclipse.jface.preference.*;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+import org.eclipse.ui.IWorkbench;
+import org.simantics.g3d.Activator;
+import org.simantics.g3d.math.EulerTools.Order;
+
+/**
+ * This class represents a preference page that
+ * is contributed to the Preferences dialog. By 
+ * subclassing <samp>FieldEditorPreferencePage</samp>, we
+ * can use the field support built into JFace that allows
+ * us to create a page that is small and knows how to 
+ * save, restore and apply itself.
+ * <p>
+ * This page is used to modify preferences only. They
+ * are stored in the preference store that belongs to
+ * the main plug-in class. That way, preferences can
+ * be accessed directly via the preference store.
+ */
+
+public class G3DPreferencePage
+       extends FieldEditorPreferencePage
+       implements IWorkbenchPreferencePage {
+
+       public G3DPreferencePage() {
+               super(GRID);
+               setPreferenceStore(Activator.getDefault().getPreferenceStore());
+               setDescription("3D modelling prederences");
+       }
+       
+       /**
+        * Creates the field editors. Field editors are abstractions of
+        * the common GUI blocks needed to manipulate various types
+        * of preferences. Each field editor knows how to save and
+        * restore itself.
+        */
+       public void createFieldEditors() {
+               addField(new RadioGroupFieldEditor(
+                               PreferenceConstants.ORIENTATION_PRESENTATION,
+                               "OrientationPresentation", 1,
+                               new String[][] { { "&Quaternion", "quat" },
+                                               { "&Axis-Angle", "aa" },{ "&Euler", "euler" } }, getFieldEditorParent()));
+               String[][] eulerOrders = new String[Order.values().length][2];
+               for (int i = 0; i < Order.values().length; i++) {
+                       eulerOrders[i][0] = Order.values()[i].toString();
+                       eulerOrders[i][1] = Order.values()[i].name();
+               }
+               addField(new RadioGroupFieldEditor(
+                               PreferenceConstants.EULER_ANGLE_ORDER,
+                               "Euler Angle Order", 1,
+                               eulerOrders, getFieldEditorParent()));
+//             addField(new DirectoryFieldEditor(PreferenceConstants.P_PATH, 
+//                             "&Directory preference:", getFieldEditorParent()));
+//             addField(
+//                     new BooleanFieldEditor(
+//                             PreferenceConstants.P_BOOLEAN,
+//                             "&An example of a boolean preference",
+//                             getFieldEditorParent()));
+//
+//             addField(new RadioGroupFieldEditor(
+//                             PreferenceConstants.P_CHOICE,
+//                     "An example of a multiple-choice preference",
+//                     1,
+//                     new String[][] { { "&Choice 1", "choice1" }, {
+//                             "C&hoice 2", "choice2" }
+//             }, getFieldEditorParent()));
+//             addField(
+//                     new StringFieldEditor(PreferenceConstants.P_STRING, "A &text preference:", getFieldEditorParent()));
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.ui.IWorkbenchPreferencePage#init(org.eclipse.ui.IWorkbench)
+        */
+       public void init(IWorkbench workbench) {
+       }
+       
+}
\ No newline at end of file
diff --git a/org.simantics.g3d/src/org/simantics/g3d/preferences/PreferenceConstants.java b/org.simantics.g3d/src/org/simantics/g3d/preferences/PreferenceConstants.java
new file mode 100644 (file)
index 0000000..92eda41
--- /dev/null
@@ -0,0 +1,19 @@
+package org.simantics.g3d.preferences;
+
+/**
+ * Constant definitions for plug-in preferences
+ */
+public class PreferenceConstants {
+
+       public static final String ORIENTATION_PRESENTATION = "orientationPresentationPreference";
+       public static final String EULER_ANGLE_ORDER = "eulerAngleOrderPreference";
+       
+//     public static final String P_PATH = "pathPreference";
+//
+//     public static final String P_BOOLEAN = "booleanPreference";
+//
+//     public static final String P_CHOICE = "choicePreference";
+//
+//     public static final String P_STRING = "stringPreference";
+       
+}
diff --git a/org.simantics.g3d/src/org/simantics/g3d/preferences/PreferenceInitializer.java b/org.simantics.g3d/src/org/simantics/g3d/preferences/PreferenceInitializer.java
new file mode 100644 (file)
index 0000000..7f1743a
--- /dev/null
@@ -0,0 +1,28 @@
+package org.simantics.g3d.preferences;
+
+import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer;
+import org.eclipse.jface.preference.IPreferenceStore;
+
+import org.simantics.g3d.Activator;
+import org.simantics.g3d.math.EulerTools.Order;
+
+/**
+ * Class used to initialize default preference values.
+ */
+public class PreferenceInitializer extends AbstractPreferenceInitializer {
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer#initializeDefaultPreferences()
+        */
+       public void initializeDefaultPreferences() {
+               IPreferenceStore store = Activator.getDefault().getPreferenceStore();
+               store.setDefault(PreferenceConstants.ORIENTATION_PRESENTATION, "aa");
+               store.setDefault(PreferenceConstants.EULER_ANGLE_ORDER, Order.YXZ.toString());
+//             store.setDefault(PreferenceConstants.P_BOOLEAN, true);
+//             store.setDefault(PreferenceConstants.P_CHOICE, "choice2");
+//             store.setDefault(PreferenceConstants.P_STRING,"Default value");
+       }
+
+}
diff --git a/org.simantics.g3d/src/org/simantics/g3d/property/AnnotatedPropertyTabContributorFactory.java b/org.simantics.g3d/src/org/simantics/g3d/property/AnnotatedPropertyTabContributorFactory.java
new file mode 100644 (file)
index 0000000..461319e
--- /dev/null
@@ -0,0 +1,1297 @@
+package org.simantics.g3d.property;\r
+\r
+import java.lang.annotation.Annotation;\r
+import java.lang.reflect.Field;\r
+import java.lang.reflect.InvocationTargetException;\r
+import java.lang.reflect.Method;\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.Collections;\r
+import java.util.HashMap;\r
+import java.util.HashSet;\r
+import java.util.LinkedHashMap;\r
+import java.util.List;\r
+import java.util.Map;\r
+import java.util.Set;\r
+\r
+import org.eclipse.jface.layout.GridDataFactory;\r
+import org.eclipse.jface.viewers.AbstractTableViewer;\r
+import org.eclipse.jface.viewers.CellEditor;\r
+import org.eclipse.jface.viewers.CellEditor.LayoutData;\r
+import org.eclipse.jface.viewers.CellLabelProvider;\r
+import org.eclipse.jface.viewers.CellNavigationStrategy;\r
+import org.eclipse.jface.viewers.ColumnViewer;\r
+import org.eclipse.jface.viewers.ColumnViewerEditor;\r
+import org.eclipse.jface.viewers.ColumnViewerEditorActivationEvent;\r
+import org.eclipse.jface.viewers.ColumnViewerEditorActivationListener;\r
+import org.eclipse.jface.viewers.ColumnViewerEditorActivationStrategy;\r
+import org.eclipse.jface.viewers.ColumnViewerEditorDeactivationEvent;\r
+import org.eclipse.jface.viewers.EditingSupport;\r
+import org.eclipse.jface.viewers.FocusCellOwnerDrawHighlighter;\r
+import org.eclipse.jface.viewers.ISelection;\r
+import org.eclipse.jface.viewers.ISelectionChangedListener;\r
+import org.eclipse.jface.viewers.ISelectionProvider;\r
+import org.eclipse.jface.viewers.IStructuredContentProvider;\r
+import org.eclipse.jface.viewers.SelectionChangedEvent;\r
+import org.eclipse.jface.viewers.StructuredSelection;\r
+import org.eclipse.jface.viewers.TableViewer;\r
+import org.eclipse.jface.viewers.TableViewerColumn;\r
+import org.eclipse.jface.viewers.TableViewerFocusCellManager;\r
+import org.eclipse.jface.viewers.TextCellEditor;\r
+import org.eclipse.jface.viewers.Viewer;\r
+import org.eclipse.jface.viewers.ViewerCell;\r
+import org.eclipse.jface.viewers.ViewerColumn;\r
+import org.eclipse.jface.viewers.ViewerRow;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.custom.TableEditor;\r
+import org.eclipse.swt.events.TraverseEvent;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.swt.widgets.Control;\r
+import org.eclipse.swt.widgets.Display;\r
+import org.eclipse.swt.widgets.Event;\r
+import org.eclipse.swt.widgets.Item;\r
+import org.eclipse.swt.widgets.TableColumn;\r
+import org.eclipse.swt.widgets.TableItem;\r
+import org.eclipse.ui.IWorkbenchSite;\r
+import org.simantics.db.management.ISessionContext;\r
+import org.simantics.g3d.property.annotations.CompoundGetPropertyValue;\r
+import org.simantics.g3d.property.annotations.CompoundSetPropertyValue;\r
+import org.simantics.g3d.property.annotations.GetPropertyValue;\r
+import org.simantics.g3d.property.annotations.PropertyTabBlacklist;\r
+import org.simantics.g3d.property.annotations.SetPropertyValue;\r
+import org.simantics.g3d.scenegraph.IG3DNode;\r
+import org.simantics.g3d.scenegraph.NodeMap;\r
+import org.simantics.g3d.scenegraph.NodeMapProvider;\r
+import org.simantics.g3d.scenegraph.base.INode;\r
+import org.simantics.g3d.scenegraph.base.NodeListener;\r
+import org.simantics.g3d.scenegraph.base.ParentNode;\r
+import org.simantics.g3d.scenegraph.structural.IStructuralNode;\r
+import org.simantics.g3d.tools.AdaptationUtils;\r
+import org.simantics.selectionview.IPropertyTab;\r
+import org.simantics.selectionview.IPropertyTab2;\r
+import org.simantics.utils.datastructures.Callback;\r
+import org.simantics.utils.datastructures.MapList;\r
+\r
+public class AnnotatedPropertyTabContributorFactory implements PropertyTabContributorFactory {\r
+\r
+       private static final boolean DEBUG = false;\r
+       \r
+       @SuppressWarnings("unchecked")\r
+       @Override\r
+       public List<PropertyTabContributor> getContributors(Object input) {\r
+               Map<String,IPropertyItem> items = new LinkedHashMap<String, IPropertyItem>();\r
+               List<String> blacklist = new ArrayList<String>();\r
+               try {\r
+                       collectItems(input.getClass(), items);\r
+                       collectBlacklist(input.getClass(), blacklist);\r
+               } catch (InstantiationException e) {\r
+                       // TODO Auto-generated catch block\r
+                       e.printStackTrace();\r
+               } catch (IllegalAccessException e) {\r
+                       // TODO Auto-generated catch block\r
+                       e.printStackTrace();\r
+               }\r
+               \r
+               if (items.size() == 0)\r
+                       return Collections.EMPTY_LIST;\r
+               \r
+               MapList<String, IPropertyItem> tabMap = new MapList<String, IPropertyItem>();\r
+               List<String> tabs = new ArrayList<String>();\r
+               for (String id : items.keySet()) {\r
+                       IPropertyItem item = items.get(id);\r
+                       tabMap.add(item.getTabId(), item);\r
+                       if (!tabs.contains(item.getTabId())) {\r
+                               tabs.add(item.getTabId());\r
+                               //System.out.println(item.tabId + " " + item.name + " " + item.id);\r
+                       }\r
+               }\r
+               for (String s : blacklist) {\r
+                       tabs.remove(s);\r
+               }\r
+               \r
+               List<PropertyTabContributor> contributors = new ArrayList<PropertyTabContributor>(tabs.size());\r
+               for (String tabId : tabs) {\r
+                       contributors.add(new AnnotatedPropertyTabContributor(tabId, tabMap.getValues(tabId)));\r
+               }\r
+               \r
+               return contributors;\r
+       }\r
+       \r
+       \r
+       private static void collectItems(Class<?> clazz, Map<String, IPropertyItem> items) throws InstantiationException, IllegalAccessException {\r
+                Class<?> superclass = clazz.getSuperclass();\r
+                if(superclass != null)\r
+                        collectItems(superclass, items);\r
+                \r
+                for (Method m : clazz.getDeclaredMethods()) {\r
+                        m.setAccessible(true);\r
+               for (Annotation annotation : m.getAnnotations()) {\r
+                       if (annotation.annotationType().equals(GetPropertyValue.class)) {\r
+                               GetPropertyValue get = (GetPropertyValue)annotation;\r
+                               PropertyItem item = (PropertyItem)items.get(get.value());\r
+                               if (item == null) {\r
+                                       item = new PropertyItem(get.value());\r
+                                       items.put(item.id, item);\r
+                               }\r
+\r
+                               item.getter = m;\r
+                               item.manipulatorClass = get.manipulator().newInstance().get(m,null);\r
+\r
+                               item.tabId = get.tabId();\r
+\r
+                               item.name = get.name();\r
+                               \r
+                               \r
+                       } else if (annotation.annotationType().equals(SetPropertyValue.class)) {\r
+                               SetPropertyValue set = (SetPropertyValue)annotation;\r
+                               PropertyItem item = (PropertyItem)items.get(set.value());\r
+                               if (item == null) {\r
+                                       item = new PropertyItem(set.value());\r
+                                       items.put(item.id, item);\r
+                               }\r
+                               \r
+                               item.setter = m;\r
+                       } else if (annotation.annotationType().equals(CompoundGetPropertyValue.class)) {\r
+                               CompoundGetPropertyValue get = (CompoundGetPropertyValue)annotation;\r
+                               CompoundPropertyItem item = (CompoundPropertyItem)items.get(get.value());\r
+                               if (item == null) {\r
+                                       item = new CompoundPropertyItem(get.value());\r
+                                       items.put(item.id, item);\r
+                               }\r
+\r
+                               item.getter = m;\r
+                               item.manipulatorFactory = get.manipulator().newInstance();\r
+\r
+                               item.tabId = get.tabId();\r
+\r
+                               item.name = get.name();\r
+                       } else if (annotation.annotationType().equals(CompoundSetPropertyValue.class)) {\r
+                               CompoundSetPropertyValue set = (CompoundSetPropertyValue)annotation;\r
+                               CompoundPropertyItem item = (CompoundPropertyItem)items.get(set.value());\r
+                               if (item == null) {\r
+                                       item = new CompoundPropertyItem(set.value());\r
+                                       items.put(item.id, item);\r
+                               }\r
+                               \r
+                               item.setter = m;\r
+                       }\r
+               }\r
+                }\r
+               \r
+               \r
+       }\r
+       \r
+       private static void collectBlacklist(Class<?> clazz, List<String> blacklist) throws InstantiationException, IllegalAccessException {\r
+                Class<?> superclass = clazz.getSuperclass();\r
+                if(superclass != null)\r
+                        collectBlacklist(superclass, blacklist);\r
+                \r
+                PropertyTabBlacklist ann = clazz.getAnnotation(PropertyTabBlacklist.class);\r
+                if (ann == null)\r
+                        return;\r
+                String s = ann.value();\r
+                if (s == null)\r
+                        return;\r
+                if (s.length() == 0)\r
+                        return;\r
+                for (String item : s.split(";")) {\r
+                        blacklist.add(item);\r
+                }\r
+                \r
+               \r
+       }\r
+       \r
+       private static Map<PropertyItem, PropertyManipulator> createManipulators(CompoundPropertyItem item, Object obj) {\r
+               try {\r
+                       \r
+                       Map<String,Object> map = (Map<String, Object>)item.getter.invoke(obj);\r
+                       Map<PropertyItem, PropertyManipulator> result = new HashMap<AnnotatedPropertyTabContributorFactory.PropertyItem, PropertyManipulator>();\r
+                       for (String key : map.keySet()) {\r
+                               MethodWithMapValueProvider provider = new MethodWithMapValueProvider(item.getter, item.setter, key);\r
+                               Class<? extends PropertyManipulator> clazz = item.manipulatorFactory.get(null,map.get(key));\r
+                               PropertyManipulator manipulator = clazz.getConstructor(ValueProvider.class,Object.class).newInstance(provider,obj);\r
+                               PropertyItem i = new PropertyItem(item.id+"."+key);\r
+                               i.getter = item.getter;\r
+                               i.setter = item.setter;\r
+                               i.name = key;\r
+                               i.tabId = item.tabId;\r
+                               result.put(i,manipulator);\r
+                       }\r
+                       return result;\r
+               } catch (Exception e) {\r
+                       e.printStackTrace();\r
+                       return Collections.EMPTY_MAP;\r
+               } \r
+               \r
+       }\r
+       \r
+       private static PropertyManipulator createManipulator(PropertyItem item, Object obj) {\r
+               try {\r
+                       MethodValueProvider provider = new MethodValueProvider(item.getter, item.setter);\r
+                       PropertyManipulator manipulator = item.manipulatorClass.getConstructor(ValueProvider.class,Object.class).newInstance(provider,obj);\r
+                       return manipulator;\r
+               } catch (Exception e) {\r
+                       e.printStackTrace();\r
+                       return null;\r
+               } \r
+       }\r
+       \r
+       private static interface IPropertyItem {\r
+               public String getTabId();\r
+       }\r
+       \r
+       private static class PropertyItem implements IPropertyItem{\r
+               private String id;\r
+               private String name;\r
+               private String tabId;\r
+               private Method getter;\r
+               private Method setter;\r
+               private Class<? extends PropertyManipulator> manipulatorClass;\r
+               \r
+               \r
+               public PropertyItem(String id) {\r
+                       if (id == null)\r
+                               throw new NullPointerException();\r
+                       this.id = id;\r
+               }\r
+               \r
+               @Override\r
+               public int hashCode() {\r
+                       return id.hashCode();\r
+               }\r
+               \r
+               @Override\r
+               public String getTabId() {\r
+                       return tabId;\r
+               }\r
+       }\r
+       \r
+       private static class CompoundPropertyItem implements IPropertyItem{\r
+               private String id;\r
+               private String name;\r
+               private String tabId;\r
+               private Method getter;\r
+               private Method setter;\r
+               private PropertyManipulatorFactory manipulatorFactory;\r
+               \r
+               \r
+               public CompoundPropertyItem(String id) {\r
+                       if (id == null)\r
+                               throw new NullPointerException();\r
+                       this.id = id;\r
+               }\r
+               \r
+               @Override\r
+               public int hashCode() {\r
+                       return id.hashCode();\r
+               }\r
+               \r
+               @Override\r
+               public String getTabId() {\r
+                       return tabId;\r
+               }\r
+       }\r
+       \r
+       private static class AnnotatedPropertyTabContributor implements PropertyTabContributor {\r
+               private String id; \r
+               List<IPropertyItem> items;\r
+               \r
+               public AnnotatedPropertyTabContributor(String id, List<IPropertyItem> items) {\r
+                       if (id == null)\r
+                               throw new NullPointerException();\r
+                       this.id = id;\r
+                       this.items = items;\r
+               }\r
+               \r
+               @Override\r
+               public IPropertyTab create(Composite parent, IWorkbenchSite site,\r
+                               ISessionContext context, Object input) {\r
+                       AnnotatedPropertyTab tab = new AnnotatedPropertyTab(id, items);\r
+                       tab.createControl(parent, context);\r
+                       return tab;\r
+               }\r
+               \r
+               @Override\r
+               public String getId() {\r
+                       return id;\r
+               }\r
+               \r
+       }\r
+       \r
+       private static class AnnotatedPropertyTab implements IPropertyTab2, NodeListener {\r
+               //private String id; \r
+               List<IPropertyItem> contibutedItems;\r
+               List<PropertyItem> resolvedItems = new ArrayList<PropertyItem>();\r
+               private Map<PropertyItem,PropertyManipulator> manipulators = new HashMap<PropertyItem, PropertyManipulator>();\r
+               \r
+               private TableViewer viewer;\r
+               \r
+               private IG3DNode node;\r
+               private NodeMap<?> nodeMap;\r
+               \r
+               private List<TableViewerColumn> valueColumns = new ArrayList<TableViewerColumn>();\r
+               \r
+               public AnnotatedPropertyTab(String id, List<IPropertyItem> items) {\r
+                       //this.id = id;\r
+                       this.contibutedItems = items;\r
+                       \r
+                                       \r
+               }\r
+               \r
+               @Override\r
+               public void createControl(Composite parent, ISessionContext context) {\r
+                       //parent.setLayout(new FillLayout());\r
+                       viewer = new TableViewer(parent, SWT.FULL_SELECTION | SWT.SINGLE);\r
+                       \r
+                       GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, true).applyTo(viewer.getTable());\r
+                       \r
+                       //viewer.setLabelProvider(new AnnotatedTableLabelProvider(object))\r
+                       \r
+                       viewer.setContentProvider(new PropertyItemContentsProvider());\r
+                       \r
+                       TableViewerColumn name = new TableViewerColumn(viewer, SWT.LEFT);\r
+                       //TableViewerColumn value = new TableViewerColumn(viewer, SWT.LEFT);\r
+                       name.setLabelProvider(new PropertyItemNameProvider());\r
+                       //value.setLabelProvider(new PropertyValueLabelProvider(null));\r
+                       name.getColumn().setText("Property");\r
+                       //value.getColumn().setText("Value");\r
+                       name.getColumn().setWidth(200);\r
+                       //value.getColumn().setWidth(200);\r
+                       name.getViewer().addSelectionChangedListener(new ISelectionChangedListener() {\r
+                               \r
+                               @Override\r
+                               public void selectionChanged(SelectionChangedEvent event) {\r
+                                       PropertyItem item = AdaptationUtils.adaptToSingle(event.getSelection(),PropertyItem.class);\r
+                                       if (item != null) {\r
+                                               PropertyManipulator manipulator = manipulators.get(item);//createManipulator(item, null);\r
+                                               for (int i = 0; i < valueColumns.size(); i++) {\r
+                                                       TableViewerColumn c = valueColumns.get(i);\r
+                                                       if (i < manipulator.getValueCount()) {\r
+                                                               c.getColumn().setText(manipulator.getDescription(i));\r
+                                                       } else {\r
+                                                               c.getColumn().setText("");\r
+                                                       }\r
+                                               }\r
+                                       }\r
+                                       \r
+                               }\r
+                       });\r
+                       \r
+                       int valueCount = 0;\r
+                       for (IPropertyItem item : contibutedItems) {\r
+                               if (item instanceof PropertyItem) {\r
+                                       PropertyManipulator manipulator = createManipulator((PropertyItem)item, null);\r
+                                       if (manipulator == null)\r
+                                               continue;\r
+                                       if (valueCount < manipulator.getValueCount())\r
+                                               valueCount = manipulator.getValueCount();\r
+                               } else if (item instanceof CompoundPropertyItem) {\r
+                                       if (valueCount < 1)\r
+                                               valueCount = 1;\r
+                               }\r
+                       }\r
+                       for (int i = 0; i < valueCount; i++) {\r
+                               TableViewerColumn value = new TableViewerColumn(viewer, SWT.LEFT);\r
+                               //value.getColumn().setText("Value " + (i+1));\r
+                               value.getColumn().setText("");\r
+                               value.getColumn().setWidth(200);\r
+                               valueColumns.add(value);\r
+                               //value.setEditingSupport(new )\r
+                       }\r
+                       viewer.getTable().setHeaderVisible(true);\r
+                       viewer.getTable().setLinesVisible(true);\r
+                       viewer.addSelectionChangedListener(new ISelectionChangedListener() {\r
+                               \r
+                               @Override\r
+                               public void selectionChanged(SelectionChangedEvent event) {\r
+                                       PropertyItem item = AdaptationUtils.adaptToSingle(event.getSelection(), PropertyItem.class);\r
+                                       selectedItem = item;\r
+                                       if (!manipulators.get(selectedItem).getEditMode())\r
+                                               manipulators.get(selectedItem).setEditMode(true);\r
+                                       \r
+\r
+                                       for (IPropertyItem i : delayedUpdate) {\r
+                                               if (!i.equals(selectedItem)) {\r
+                                                       manipulators.get(i).setEditMode(false);\r
+                                                       viewer.update(i,null);\r
+                                               }\r
+                                       }\r
+                                       if (delayedUpdate.contains(selectedItem)) {\r
+                                               delayedUpdate.clear();\r
+                                               delayedUpdate.add(selectedItem);\r
+                                       } else {\r
+                                               delayedUpdate.clear();\r
+                                       }\r
+                               }\r
+                       });\r
+                       \r
+                       CellNavigationStrategy nStrategy = new CellNavigationStrategy() {\r
+                               private ViewerCell internalFindSelectedCell(\r
+                                               ColumnViewer viewer, ViewerCell currentSelectedCell,\r
+                                               Event event) {\r
+                                       switch (event.keyCode) {\r
+                                       case SWT.ARROW_UP:\r
+                                               if (currentSelectedCell != null) {\r
+                                                       return getNeighbor(currentSelectedCell,\r
+                                                                       ViewerCell.ABOVE, false);\r
+                                               }\r
+                                               break;\r
+                                       case SWT.ARROW_DOWN:\r
+                                               if (currentSelectedCell != null) {\r
+                                                       return getNeighbor(currentSelectedCell,\r
+                                                                       ViewerCell.BELOW, false);\r
+                                               }\r
+                                               break;\r
+                                       case SWT.ARROW_LEFT:\r
+                                               if (currentSelectedCell != null) {\r
+                                                       return getNeighbor(currentSelectedCell,\r
+                                                                       ViewerCell.LEFT, true);\r
+                                               }\r
+                                               break;\r
+                                       case SWT.ARROW_RIGHT:\r
+                                               if (currentSelectedCell != null) {\r
+                                                       return getNeighbor(currentSelectedCell,\r
+                                                                       ViewerCell.RIGHT, true);\r
+                                               }\r
+                                               break;\r
+                                       }\r
+                                       return null;\r
+                               }\r
+                               \r
+                               public ViewerCell findSelectedCell(ColumnViewer viewer,\r
+                                               ViewerCell currentSelectedCell, Event event) {\r
+                                       ViewerCell cell = internalFindSelectedCell(viewer,\r
+                                                       currentSelectedCell, event);\r
+                                       if (cell != null) {\r
+                                               TableColumn t = AnnotatedPropertyTab.this.viewer.getTable().getColumn(\r
+                                                               cell.getColumnIndex());\r
+                                               AnnotatedPropertyTab.this.viewer.getTable().showColumn(t);\r
+                                       }\r
+                                       return cell;\r
+                               }\r
+                       };\r
+                       \r
+                       TableViewerFocusCellManager focusCellManager = new TableViewerFocusCellManager(\r
+                                       viewer, new FocusCellOwnerDrawHighlighter(viewer));\r
+                       try {\r
+                               Field f = focusCellManager.getClass().getSuperclass()\r
+                                               .getDeclaredField("navigationStrategy");\r
+                               f.setAccessible(true);\r
+                               f.set(focusCellManager, nStrategy);\r
+                       } catch (SecurityException e) {\r
+                               e.printStackTrace();\r
+                       } catch (NoSuchFieldException e) {\r
+                               e.printStackTrace();\r
+                       } catch (IllegalArgumentException e) {\r
+                               e.printStackTrace();\r
+                       } catch (IllegalAccessException e) {\r
+                               e.printStackTrace();\r
+                       }\r
+                       ColumnViewerEditorActivationStrategy actSupport = new ColumnViewerEditorActivationStrategy(\r
+                                       viewer) {\r
+                               protected boolean isEditorActivationEvent(\r
+                                               ColumnViewerEditorActivationEvent event) {\r
+                                       return event.eventType == ColumnViewerEditorActivationEvent.TRAVERSAL\r
+                                                       || event.eventType == ColumnViewerEditorActivationEvent.MOUSE_DOUBLE_CLICK_SELECTION\r
+                                                       || (event.eventType == ColumnViewerEditorActivationEvent.KEY_PRESSED && event.keyCode == SWT.CR)\r
+                                                       || event.eventType == ColumnViewerEditorActivationEvent.PROGRAMMATIC;\r
+                               }\r
+                       };\r
+                       TableViewerEditor.create(viewer, focusCellManager, actSupport,\r
+                                       ColumnViewerEditor.TABBING_HORIZONTAL\r
+                                                       | ColumnViewerEditor.TABBING_MOVE_TO_ROW_NEIGHBOR\r
+                                                       | ColumnViewerEditor.TABBING_VERTICAL\r
+                                                       | ColumnViewerEditor.KEYBOARD_ACTIVATION);\r
+                       viewer.getColumnViewerEditor().addEditorActivationListener(\r
+                                       new ColumnViewerEditorActivationListener() {\r
+                                               public void afterEditorActivated(\r
+                                                               ColumnViewerEditorActivationEvent event) {\r
+                                               }\r
+\r
+                                               public void afterEditorDeactivated(\r
+                                                               ColumnViewerEditorDeactivationEvent event) {\r
+                                               }\r
+\r
+                                               public void beforeEditorActivated(\r
+                                                               ColumnViewerEditorActivationEvent event) {\r
+                                                       ViewerCell cell = (ViewerCell) event.getSource();\r
+                                                       viewer.getTable().showColumn(\r
+                                                                       viewer.getTable().getColumn(cell.getColumnIndex()));\r
+                                               }\r
+\r
+                                               public void beforeEditorDeactivated(\r
+                                                               ColumnViewerEditorDeactivationEvent event) {\r
+                                               }\r
+                                       });\r
+               }\r
+               \r
+               \r
+               \r
+               \r
+               private IPropertyItem selectedItem = null;\r
+               private Set<IPropertyItem> delayedUpdate = new HashSet<IPropertyItem>();\r
+               \r
+               \r
+               @Override\r
+               public void setInput(ISessionContext context, ISelection selection,\r
+                               boolean force) {\r
+                       Collection<IG3DNode> nodes = AdaptationUtils.adaptToCollection(selection, IG3DNode.class);\r
+                       if (nodes.size() != 1) {\r
+                               if (node != null) {\r
+                                       node.removeListener(this);\r
+                                       node = null;\r
+                               }\r
+                               return;\r
+                       }\r
+                       IG3DNode n = nodes.iterator().next();\r
+                       if (node != null) {\r
+                               if (!node.equals(n)) {\r
+                                       node.removeListener(this);\r
+                                       setInput(n);\r
+                               }\r
+                       } else {\r
+                               setInput(n);\r
+                       }\r
+               }\r
+               \r
+               \r
+               \r
+               private void setInput(IG3DNode node) {\r
+                       this.node = node;\r
+                       this.node.addListener(this);\r
+                       // resolve nodemap\r
+                       IG3DNode n = node;\r
+                       while (true) {\r
+                               if (n == null) {\r
+                                       nodeMap = null;\r
+                                       break;\r
+                               }\r
+                               if (n instanceof NodeMapProvider<?>) {\r
+                                       nodeMap = ((NodeMapProvider<?>) n).getNodeMap();\r
+                                       if (nodeMap != null)\r
+                                               break;\r
+                               }\r
+                               n = (IG3DNode)n.getParent();\r
+                       }\r
+                       boolean readOnly =  (node instanceof IStructuralNode && ((IStructuralNode)node).isPartOfInstantiatedModel() && !((IStructuralNode)node).isInstantiatedModelRoot());\r
+                       // create label providers\r
+                       PropertyValueLabelProvider2 p = new PropertyValueLabelProvider2(this);\r
+                       int index = 0;\r
+                       for (TableViewerColumn c : valueColumns) {\r
+                               c.setLabelProvider(p);\r
+                               if (!readOnly) {\r
+                                       PropertyEditingSupport support = new PropertyEditingSupport(this, viewer, index++, nodeMap);\r
+                                       c.setEditingSupport(support);\r
+                               }\r
+                       }\r
+                       resolvedItems.clear();\r
+                       manipulators.clear();\r
+                       for (IPropertyItem item : contibutedItems) {\r
+                               if (item instanceof PropertyItem) {\r
+                                       resolvedItems.add((PropertyItem)item);\r
+                                       manipulators.put((PropertyItem)item, createManipulator((PropertyItem)item, node));\r
+                               }\r
+                               else {\r
+                                       CompoundPropertyItem compound = (CompoundPropertyItem)item;\r
+                                       Map<PropertyItem, PropertyManipulator> manipulators = createManipulators(compound, node);\r
+                                       for (PropertyItem i : manipulators.keySet()) {\r
+                                               resolvedItems.add(i);\r
+                                               this.manipulators.put(i, manipulators.get(i));\r
+                                       }\r
+                               }\r
+                       }\r
+                       \r
+                       viewer.getTable().setEnabled(!readOnly);\r
+                       viewer.setInput(resolvedItems);\r
+               }\r
+               \r
+               @Override\r
+               public void requestFocus() {\r
+                       viewer.getTable().forceFocus();\r
+               }\r
+               \r
+               @Override\r
+               public void dispose() {\r
+                       if (node != null) {\r
+                               node.removeListener(this);\r
+                               node = null;\r
+                       }\r
+                       \r
+               }\r
+               \r
+               @Override\r
+               public Control getControl() {\r
+                       return viewer.getTable();\r
+               }\r
+               \r
+               @Override\r
+               public ISelectionProvider getSelectionProvider() {\r
+                       return null;\r
+               }\r
+               \r
+               @Override\r
+               public boolean isDisposed() {\r
+                       return viewer.getTable().isDisposed();\r
+               }\r
+               \r
+               @Override\r
+               public <T extends INode> void nodeAdded(ParentNode<T> node,\r
+                               INode child, String rel) {\r
+                       \r
+               }\r
+               \r
+               @Override\r
+               public <T extends INode> void nodeRemoved(ParentNode<T> node,\r
+                               INode child, String rel) {\r
+                       \r
+               }\r
+               \r
+               @Override\r
+               public void propertyChanged(INode node, final String id) {\r
+//                     for (final PropertyItem item : items) {\r
+//                             if (item.id.equals(id)) {\r
+//                                     Display.getDefault().asyncExec(new Runnable() {\r
+//                                             \r
+//                                             @Override\r
+//                                             public void run() {\r
+//                                                     viewer.update(item, null);\r
+//                                                     \r
+//                                             }\r
+//                                     });\r
+//                             }\r
+//                     }\r
+                       if (Thread.currentThread() == Display.getDefault().getThread()) {\r
+                               if (DEBUG)System.out.println("Viewer refresh " + id);\r
+                               for (PropertyItem item : resolvedItems)\r
+                                       if (!item.equals(selectedItem))\r
+                                               viewer.refresh(item);\r
+                               if (selectedItem != null)\r
+                                       delayedUpdate.add(selectedItem);\r
+                       } else if (!editing){\r
+                               // running delayed refresh when a cell editor is active would cancel cell editing.\r
+                               Display.getDefault().asyncExec(new Runnable() {\r
+                                       @Override\r
+                                       public void run() {\r
+                                               if (viewer.getTable().isDisposed()) {\r
+                                                       if (AnnotatedPropertyTab.this.node != null)\r
+                                                               AnnotatedPropertyTab.this.node.removeListener(AnnotatedPropertyTab.this);\r
+                                                       return;\r
+                                               }\r
+                                               if (DEBUG) System.out.println("Viewer threaded refresh " + id);\r
+                                               for (PropertyItem item : resolvedItems)\r
+                                                       if (!item.equals(selectedItem))\r
+                                                               viewer.refresh(item);\r
+                                               if (selectedItem != null)\r
+                                                       delayedUpdate.add(selectedItem);\r
+                                               \r
+                                       }\r
+                               });\r
+                       } else {\r
+                               for (PropertyItem item : resolvedItems) {\r
+                                       delayedUpdate.add(item);\r
+                               }\r
+                       }\r
+                       \r
+               }\r
+               \r
+\r
+               \r
+               \r
+               \r
+               @Override\r
+               public void updatePartName(Callback<String> updateCallback) {\r
+                       if (node != null)\r
+                               updateCallback.run(node.toString()); \r
+                       \r
+               }\r
+               \r
+               public PropertyManipulator getManipulator(PropertyItem item) {\r
+                       return manipulators.get(item);\r
+               }\r
+               \r
+               private boolean editing = false;\r
+               \r
+               public void setEditing(boolean editing) {\r
+                       this.editing = editing;\r
+               }\r
+       }\r
+       \r
+       \r
+       \r
+       private static class PropertyEditingSupport extends EditingSupport {\r
+               AnnotatedPropertyTab tab;\r
+               int index;\r
+               NodeMap<?> nodeMap;\r
+               TableViewer viewer;\r
+               CellEditor editor;\r
+\r
+               public PropertyEditingSupport(AnnotatedPropertyTab tab, TableViewer viewer, int index, NodeMap<?> nodeMap) {\r
+                       super(viewer);\r
+                       this.tab = tab;\r
+                       this.index = index;\r
+                       this.viewer = viewer;\r
+                       this.nodeMap = nodeMap;\r
+               }\r
+               \r
+               @Override\r
+               protected boolean canEdit(Object element) {\r
+                       PropertyItem item = (PropertyItem)element;\r
+                       if (tab.getManipulator(item).getValueCount() <= index)\r
+                               return false;\r
+                       return (item.setter != null);\r
+               }\r
+               \r
+               @Override\r
+               protected CellEditor getCellEditor(Object element) {\r
+                       \r
+                       if (tab.getManipulator((PropertyItem)element).getValueCount() <= index)\r
+                               return null;\r
+                       if (editor == null)\r
+                               editor = new TextCellEditor(viewer.getTable(),SWT.NONE) {\r
+                               @Override\r
+                               public void activate() {\r
+                                       tab.setEditing(true);\r
+                               }\r
+                               \r
+                               @Override\r
+                               public void deactivate() {\r
+                                       super.deactivate();\r
+                                       tab.setEditing(false);\r
+                               }\r
+                       };\r
+                       if (DEBUG)System.err.println("CELL EDITOR: " + element);\r
+                       return editor;\r
+               }\r
+               \r
+               @Override\r
+               protected Object getValue(Object element) {\r
+                       PropertyItem item = (PropertyItem)element;\r
+                       PropertyManipulator manipulator = tab.getManipulator(item);//createManipulator(item, obj);\r
+                       if (manipulator.getValueCount() <= index)\r
+                               return null;\r
+                       Object value = manipulator.getValue(index);\r
+                       return value;\r
+               }\r
+               \r
+               @Override\r
+               protected void setValue(Object element, Object value) {\r
+                       \r
+                       PropertyItem item = (PropertyItem)element;\r
+                       PropertyManipulator manipulator = tab.getManipulator(item);//createManipulator(item, obj);\r
+                       if (manipulator.getValueCount() <= index)\r
+                               throw new IllegalAccessError("Editing value in index " + index + " is not allowed.");\r
+                       if (DEBUG)System.err.println("CELL SET VALUE: " + element + " " + value);\r
+                       manipulator.setValue((String)value,index);\r
+                       viewer.refresh(item);\r
+                       nodeMap.commit();\r
+                       \r
+               }\r
+               \r
+               \r
+\r
+       }\r
+       \r
+       private static class PropertyItemNameProvider extends CellLabelProvider {\r
+\r
+               \r
+               @Override\r
+               public void update(ViewerCell cell) {\r
+                       PropertyItem item = (PropertyItem)cell.getElement();\r
+\r
+                       if (item.name.length() > 0)\r
+                               cell.setText(item.name);\r
+                       else\r
+                               cell.setText(item.id);\r
+                       \r
+                       \r
+               }\r
+       }\r
+       \r
+       private static class PropertyValueLabelProvider2 extends CellLabelProvider {\r
+               AnnotatedPropertyTab tab;\r
+               //private Object object;\r
+               \r
+               public PropertyValueLabelProvider2(AnnotatedPropertyTab tab) {\r
+                       this.tab = tab;\r
+               }\r
+               \r
+               @Override\r
+               public void update(ViewerCell cell) {\r
+                       PropertyItem item = (PropertyItem)cell.getElement();\r
+                       int index = cell.getColumnIndex() -1;\r
+                       PropertyManipulator manipulator = tab.getManipulator(item);//createManipulator(item, object);\r
+                       if (manipulator.getValueCount() <= index)\r
+                               return;\r
+                       cell.setText(manipulator.getValue(index));\r
+               }\r
+       }\r
+       \r
+       private static class PropertyItemContentsProvider implements IStructuredContentProvider {\r
+               @SuppressWarnings("unchecked")\r
+               @Override\r
+               public Object[] getElements(Object inputElement) {\r
+                       List<PropertyItem> items = (List<PropertyItem>)inputElement;\r
+                       return items.toArray();\r
+               }\r
+               \r
+               @Override\r
+               public void dispose() {\r
+                       \r
+               }\r
+               \r
+               @Override\r
+               public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {\r
+                       \r
+               }\r
+       }\r
+       \r
+       \r
+       \r
+       private static ViewerCell getNeighbor(ViewerCell currentCell,\r
+                       int directionMask, boolean sameLevel) {\r
+               ViewerRow row;\r
+               if ((directionMask & ViewerCell.ABOVE) == ViewerCell.ABOVE) {\r
+                       row = currentCell.getViewerRow().getNeighbor(ViewerRow.ABOVE,\r
+                                       sameLevel);\r
+               } else if ((directionMask & ViewerCell.BELOW) == ViewerCell.BELOW) {\r
+                       row = currentCell.getViewerRow().getNeighbor(ViewerRow.BELOW,\r
+                                       sameLevel);\r
+               } else {\r
+                       row = currentCell.getViewerRow();\r
+               }\r
+               if (row != null) {\r
+                       int columnIndex;\r
+                       columnIndex = getVisualIndex(row, currentCell.getColumnIndex());\r
+                       int modifier = 0;\r
+                       if ((directionMask & ViewerCell.LEFT) == ViewerCell.LEFT) {\r
+                               modifier = -1;\r
+                       } else if ((directionMask & ViewerCell.RIGHT) == ViewerCell.RIGHT) {\r
+                               modifier = 1;\r
+                       }\r
+                       columnIndex += modifier;\r
+                       if (columnIndex >= 0 && columnIndex < row.getColumnCount()) {\r
+                               ViewerCell cell = getCellAtVisualIndex(row, columnIndex);\r
+                               if (cell != null) {\r
+                                       while (cell != null\r
+                                                       && columnIndex < row.getColumnCount() - 1\r
+                                                       && columnIndex > 0) {\r
+                                               if (isVisible(cell)) {\r
+                                                       break;\r
+                                               }\r
+                                               columnIndex += modifier;\r
+                                               cell = getCellAtVisualIndex(row, columnIndex);\r
+                                               if (cell == null) {\r
+                                                       break;\r
+                                               }\r
+                                       }\r
+                               }\r
+                               return cell;\r
+                       }\r
+               }\r
+               return null;\r
+       }\r
+       \r
+       \r
+       \r
+       public static class TableViewerEditor extends ColumnViewerEditor {\r
+               /**\r
+                * This viewer's table editor.\r
+                */\r
+               private TableEditor tableEditor;\r
+               private TableViewerFocusCellManager focusCellManager;\r
+               private int feature;\r
+\r
+               /**\r
+                * @param viewer\r
+                *            the viewer the editor is attached to\r
+                * @param focusCellManager\r
+                *            the cell focus manager if one used or <code>null</code>\r
+                * @param editorActivationStrategy\r
+                *            the strategy used to decide about the editor activation\r
+                * @param feature\r
+                *            the feature mask\r
+                */\r
+               TableViewerEditor(TableViewer viewer,\r
+                               TableViewerFocusCellManager focusCellManager,\r
+                               ColumnViewerEditorActivationStrategy editorActivationStrategy,\r
+                               int feature) {\r
+                       super(viewer, editorActivationStrategy, feature);\r
+                       this.feature = feature;\r
+                       tableEditor = new TableEditor(viewer.getTable());\r
+                       this.focusCellManager = focusCellManager;\r
+               }\r
+\r
+               /**\r
+                * Create a customized editor with focusable cells\r
+                * \r
+                * @param viewer\r
+                *            the viewer the editor is created for\r
+                * @param focusCellManager\r
+                *            the cell focus manager if one needed else\r
+                *            <code>null</code>\r
+                * @param editorActivationStrategy\r
+                *            activation strategy to control if an editor activated\r
+                * @param feature\r
+                *            bit mask controlling the editor\r
+                *            <ul>\r
+                *            <li>{@link ColumnViewerEditor#DEFAULT}</li>\r
+                *            <li>{@link ColumnViewerEditor#TABBING_CYCLE_IN_ROW}</li>\r
+                *            <li>{@link ColumnViewerEditor#TABBING_HORIZONTAL}</li>\r
+                *            <li>\r
+                *            {@link ColumnViewerEditor#TABBING_MOVE_TO_ROW_NEIGHBOR}</li>\r
+                *            <li>{@link ColumnViewerEditor#TABBING_VERTICAL}</li>\r
+                *            </ul>\r
+                * @see #create(TableViewer, ColumnViewerEditorActivationStrategy, int)\r
+                */\r
+               public static void create(TableViewer viewer,\r
+                               TableViewerFocusCellManager focusCellManager,\r
+                               ColumnViewerEditorActivationStrategy editorActivationStrategy,\r
+                               int feature) {\r
+                       TableViewerEditor editor = new TableViewerEditor(viewer,\r
+                                       focusCellManager, editorActivationStrategy, feature);\r
+                       viewer.setColumnViewerEditor(editor);\r
+                       if (focusCellManager != null) {\r
+                               try {\r
+                                       Method m = focusCellManager.getClass().getSuperclass()\r
+                                                       .getDeclaredMethod("init", null);\r
+                                       m.setAccessible(true);\r
+                                       m.invoke(focusCellManager, null);\r
+                               } catch (SecurityException e) {\r
+                                       e.printStackTrace();\r
+                               } catch (IllegalArgumentException e) {\r
+                                       e.printStackTrace();\r
+                               } catch (IllegalAccessException e) {\r
+                                       e.printStackTrace();\r
+                               } catch (NoSuchMethodException e) {\r
+                                       e.printStackTrace();\r
+                               } catch (InvocationTargetException e) {\r
+                                       e.printStackTrace();\r
+                               }\r
+                               // focusCellManager.init();\r
+                       }\r
+               }\r
+\r
+               /**\r
+                * Create a customized editor whose activation process is customized\r
+                * \r
+                * @param viewer\r
+                *            the viewer the editor is created for\r
+                * @param editorActivationStrategy\r
+                *            activation strategy to control if an editor activated\r
+                * @param feature\r
+                *            bit mask controlling the editor\r
+                *            <ul>\r
+                *            <li>{@link ColumnViewerEditor#DEFAULT}</li>\r
+                *            <li>{@link ColumnViewerEditor#TABBING_CYCLE_IN_ROW}</li>\r
+                *            <li>{@link ColumnViewerEditor#TABBING_HORIZONTAL}</li>\r
+                *            <li>\r
+                *            {@link ColumnViewerEditor#TABBING_MOVE_TO_ROW_NEIGHBOR}</li>\r
+                *            <li>{@link ColumnViewerEditor#TABBING_VERTICAL}</li>\r
+                *            </ul>\r
+                */\r
+               public static void create(TableViewer viewer,\r
+                               ColumnViewerEditorActivationStrategy editorActivationStrategy,\r
+                               int feature) {\r
+                       create(viewer, null, editorActivationStrategy, feature);\r
+               }\r
+\r
+               protected void setEditor(Control w, Item item, int columnNumber) {\r
+                       tableEditor.setEditor(w, (TableItem) item, columnNumber);\r
+               }\r
+\r
+               protected void setLayoutData(LayoutData layoutData) {\r
+                       tableEditor.grabHorizontal = layoutData.grabHorizontal;\r
+                       tableEditor.horizontalAlignment = layoutData.horizontalAlignment;\r
+                       tableEditor.minimumWidth = layoutData.minimumWidth;\r
+               }\r
+\r
+               public ViewerCell getFocusCell() {\r
+                       if (focusCellManager != null) {\r
+                               return focusCellManager.getFocusCell();\r
+                       }\r
+                       return super.getFocusCell();\r
+               }\r
+\r
+               protected void updateFocusCell(ViewerCell focusCell,\r
+                               ColumnViewerEditorActivationEvent event) {\r
+                       // Update the focus cell when we activated the editor with these 2\r
+                       // events\r
+                       if (event.eventType == ColumnViewerEditorActivationEvent.PROGRAMMATIC\r
+                                       || event.eventType == ColumnViewerEditorActivationEvent.TRAVERSAL) {\r
+                               if (focusCellManager != null) {\r
+                                       try {\r
+                                               if (DEBUG)System.err.println("FOCUS CELL: " + focusCell);\r
+                                               \r
+                                               Method m = AbstractTableViewer.class.getDeclaredMethod(\r
+                                                               "getSelectionFromWidget", null);\r
+                                               m.setAccessible(true);\r
+                                               List l = (List) m.invoke(getViewer(), null);\r
+                                               if (focusCellManager != null) {\r
+                                                       m = focusCellManager\r
+                                                                       .getClass()\r
+                                                                       .getSuperclass()\r
+                                                                       .getDeclaredMethod("setFocusCell",\r
+                                                                                       new Class[] { ViewerCell.class });\r
+                                                       m.setAccessible(true);\r
+                                                       m.invoke(focusCellManager,\r
+                                                                       new Object[] { focusCell });\r
+                                               }\r
+                                               if (!l.contains(focusCell.getElement())) {\r
+                                                       getViewer().setSelection(\r
+                                                                       new StructuredSelection(focusCell\r
+                                                                                       .getElement()));\r
+                                               }\r
+                                       } catch (SecurityException e) {\r
+                                               e.printStackTrace();\r
+                                       } catch (IllegalArgumentException e) {\r
+                                               e.printStackTrace();\r
+                                       } catch (IllegalAccessException e) {\r
+                                               e.printStackTrace();\r
+                                       } catch (NoSuchMethodException e) {\r
+                                               e.printStackTrace();\r
+                                       } catch (InvocationTargetException e) {\r
+                                               e.printStackTrace();\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+\r
+               protected void processTraverseEvent(int columnIndex, ViewerRow row,\r
+                               TraverseEvent event) {\r
+                       ViewerCell cell2edit = null;\r
+                       if (event.detail == SWT.TRAVERSE_TAB_PREVIOUS) {\r
+                               event.doit = false;\r
+                               if ((event.stateMask & SWT.CTRL) == SWT.CTRL\r
+                                               && (feature & TABBING_VERTICAL) == TABBING_VERTICAL) {\r
+                                       cell2edit = searchCellAboveBelow(row, getViewer(),\r
+                                                       columnIndex, true);\r
+                               } else if ((feature & TABBING_HORIZONTAL) == TABBING_HORIZONTAL) {\r
+                                       cell2edit = searchPreviousCell(row,\r
+                                                       row.getCell(columnIndex), row.getCell(columnIndex),\r
+                                                       getViewer());\r
+                               }\r
+                       } else if (event.detail == SWT.TRAVERSE_TAB_NEXT) {\r
+                               event.doit = false;\r
+                               if ((event.stateMask & SWT.CTRL) == SWT.CTRL\r
+                                               && (feature & TABBING_VERTICAL) == TABBING_VERTICAL) {\r
+                                       cell2edit = searchCellAboveBelow(row, getViewer(),\r
+                                                       columnIndex, false);\r
+                               } else if ((feature & TABBING_HORIZONTAL) == TABBING_HORIZONTAL) {\r
+                                       cell2edit = searchNextCell(row, row.getCell(columnIndex),\r
+                                                       row.getCell(columnIndex), getViewer());\r
+                               }\r
+                       }\r
+                       if (DEBUG) System.err.println("NEXT CELL: " + cell2edit);\r
+                       if (cell2edit != null) {\r
+                               getViewer().getControl().setRedraw(false);\r
+                               ColumnViewerEditorActivationEvent acEvent = new ColumnViewerEditorActivationEvent(\r
+                                               cell2edit, event);\r
+                               try {\r
+                                       Method m = ColumnViewer.class\r
+                                                       .getDeclaredMethod(\r
+                                                                       "triggerEditorActivationEvent",\r
+                                                                       new Class[] { ColumnViewerEditorActivationEvent.class });\r
+                                       m.setAccessible(true);\r
+                                       m.invoke(getViewer(), new Object[] { acEvent });\r
+                               } catch (SecurityException e) {\r
+                                       e.printStackTrace();\r
+                               } catch (NoSuchMethodException e) {\r
+                                       e.printStackTrace();\r
+                               } catch (IllegalArgumentException e) {\r
+                                       e.printStackTrace();\r
+                               } catch (IllegalAccessException e) {\r
+                                       e.printStackTrace();\r
+                               } catch (InvocationTargetException e) {\r
+                                       e.printStackTrace();\r
+                               }\r
+                               getViewer().getControl().setRedraw(true);\r
+                       }\r
+               }\r
+\r
+               private ViewerCell searchCellAboveBelow(ViewerRow row,\r
+                               ColumnViewer viewer, int columnIndex, boolean above) {\r
+                       ViewerCell rv = null;\r
+                       ViewerRow newRow = null;\r
+                       if (above) {\r
+                               newRow = row.getNeighbor(ViewerRow.ABOVE, false);\r
+                       } else {\r
+                               newRow = row.getNeighbor(ViewerRow.BELOW, false);\r
+                       }\r
+                       try {\r
+                               if (newRow != null) {\r
+                                       Method m = ColumnViewer.class.getDeclaredMethod(\r
+                                                       "getViewerColumn", new Class[] { int.class });\r
+                                       m.setAccessible(true);\r
+                                       ViewerColumn column = (ViewerColumn) m.invoke(viewer,\r
+                                                       new Object[] { new Integer(columnIndex) });\r
+                                       m = ViewerColumn.class.getDeclaredMethod(\r
+                                                       "getEditingSupport", null);\r
+                                       m.setAccessible(true);\r
+                                       EditingSupport es = (EditingSupport) m.invoke(column, null);\r
+                                       if (column != null && es != null) {\r
+                                               m = EditingSupport.class.getDeclaredMethod("canEdit",\r
+                                                               new Class[] { Object.class });\r
+                                               m.setAccessible(true);\r
+                                               Boolean b = (Boolean) m.invoke(es,\r
+                                                               new Object[] { newRow.getItem().getData() });\r
+                                               if (b.booleanValue()) {\r
+                                                       rv = newRow.getCell(columnIndex);\r
+                                               }\r
+                                       } else {\r
+                                               rv = searchCellAboveBelow(newRow, viewer, columnIndex,\r
+                                                               above);\r
+                                       }\r
+                               }\r
+                       } catch (Exception e) {\r
+                               e.printStackTrace();\r
+                       }\r
+                       return rv;\r
+               }\r
+\r
+               private ViewerCell searchPreviousCell(ViewerRow row,\r
+                               ViewerCell currentCell, ViewerCell originalCell,\r
+                               ColumnViewer viewer) {\r
+                       ViewerCell rv = null;\r
+                       ViewerCell previousCell;\r
+                       if (currentCell != null) {\r
+                               previousCell = getNeighbor(currentCell, ViewerCell.LEFT, true);\r
+                       } else {\r
+                               if (row.getColumnCount() != 0) {\r
+                                       previousCell = row.getCell(getCreationIndex(row,\r
+                                                       row.getColumnCount() - 1));\r
+                               } else {\r
+                                       previousCell = row.getCell(0);\r
+                               }\r
+                       }\r
+                       // No endless loop\r
+                       if (originalCell.equals(previousCell)) {\r
+                               return null;\r
+                       }\r
+                       if (previousCell != null) {\r
+                               if (isCellEditable(viewer, previousCell)) {\r
+                                       rv = previousCell;\r
+                               } else {\r
+                                       rv = searchPreviousCell(row, previousCell, originalCell,\r
+                                                       viewer);\r
+                               }\r
+                       } else {\r
+                               if ((feature & TABBING_CYCLE_IN_ROW) == TABBING_CYCLE_IN_ROW) {\r
+                                       rv = searchPreviousCell(row, null, originalCell, viewer);\r
+                               } else if ((feature & TABBING_MOVE_TO_ROW_NEIGHBOR) == TABBING_MOVE_TO_ROW_NEIGHBOR) {\r
+                                       ViewerRow rowAbove = row\r
+                                                       .getNeighbor(ViewerRow.ABOVE, false);\r
+                                       if (rowAbove != null) {\r
+                                               rv = searchPreviousCell(rowAbove, null, originalCell,\r
+                                                               viewer);\r
+                                       }\r
+                               }\r
+                       }\r
+                       return rv;\r
+               }\r
+\r
+               private ViewerCell searchNextCell(ViewerRow row,\r
+                               ViewerCell currentCell, ViewerCell originalCell,\r
+                               ColumnViewer viewer) {\r
+                       ViewerCell rv = null;\r
+                       ViewerCell nextCell;\r
+                       if (currentCell != null) {\r
+                               nextCell = getNeighbor(currentCell, ViewerCell.RIGHT, true);\r
+                       } else {\r
+                               nextCell = row.getCell(getCreationIndex(row, 0));\r
+                       }\r
+                       // No endless loop\r
+                       if (originalCell.equals(nextCell)) {\r
+                               return null;\r
+                       }\r
+                       if (nextCell != null) {\r
+                               if (isCellEditable(viewer, nextCell)) {\r
+                                       rv = nextCell;\r
+                               } else {\r
+                                       rv = searchNextCell(row, nextCell, originalCell, viewer);\r
+                               }\r
+                       } else {\r
+                               if ((feature & TABBING_CYCLE_IN_ROW) == TABBING_CYCLE_IN_ROW) {\r
+                                       rv = searchNextCell(row, null, originalCell, viewer);\r
+                               } else if ((feature & TABBING_MOVE_TO_ROW_NEIGHBOR) == TABBING_MOVE_TO_ROW_NEIGHBOR) {\r
+                                       ViewerRow rowBelow = row\r
+                                                       .getNeighbor(ViewerRow.BELOW, false);\r
+                                       if (rowBelow != null) {\r
+                                               rv = searchNextCell(rowBelow, null, originalCell,\r
+                                                               viewer);\r
+                                       }\r
+                               }\r
+                       }\r
+                       return rv;\r
+               }\r
+\r
+               private boolean isCellEditable(ColumnViewer viewer, ViewerCell cell) {\r
+                       try {\r
+                               Method m = ColumnViewer.class.getDeclaredMethod(\r
+                                               "getViewerColumn", new Class[] { int.class });\r
+                               m.setAccessible(true);\r
+                               ViewerColumn column = (ViewerColumn) m.invoke(viewer,\r
+                                               new Object[] { new Integer(cell.getColumnIndex()) });\r
+                               m = ViewerColumn.class.getDeclaredMethod("getEditingSupport",\r
+                                               null);\r
+                               m.setAccessible(true);\r
+                               EditingSupport es = (EditingSupport) m.invoke(column, null);\r
+                               if (column != null && es != null) {\r
+                                       m = EditingSupport.class.getDeclaredMethod("canEdit",\r
+                                                       new Class[] { Object.class });\r
+                                       m.setAccessible(true);\r
+                                       // return true;\r
+                                       Boolean b = (Boolean) m.invoke(es,\r
+                                                       new Object[] { cell.getElement() });\r
+                                       return b.booleanValue();\r
+                               }\r
+                       } catch (Exception e) {\r
+                               e.printStackTrace();\r
+                       }\r
+                       return false;\r
+               }\r
+       }\r
+       \r
+       // Reimplementation of ViewerCell-Methods\r
+       private static int getVisualIndex(ViewerRow row, int creationIndex) {\r
+               TableItem item = (TableItem) row.getItem();\r
+               int[] order = item.getParent().getColumnOrder();\r
+               for (int i = 0; i < order.length; i++) {\r
+                       if (order[i] == creationIndex) {\r
+                               return i;\r
+                       }\r
+               }\r
+               return creationIndex;\r
+       }\r
+       \r
+       private static int getCreationIndex(ViewerRow row, int visualIndex) {\r
+               TableItem item = (TableItem) row.getItem();\r
+               if (item != null && !item.isDisposed() /*\r
+                                                                                                * && hasColumns() &&\r
+                                                                                                * isValidOrderIndex\r
+                                                                                                * (visualIndex)\r
+                                                                                                */) {\r
+                       return item.getParent().getColumnOrder()[visualIndex];\r
+               }\r
+               return visualIndex;\r
+       }\r
+       \r
+       private static ViewerCell getCellAtVisualIndex(ViewerRow row,\r
+                       int visualIndex) {\r
+               return getCell(row, getCreationIndex(row, visualIndex));\r
+       }\r
+\r
+       private static boolean isVisible(ViewerCell cell) {\r
+               return getWidth(cell) > 0;\r
+       }\r
+\r
+       private static int getWidth(ViewerCell cell) {\r
+               TableItem item = (TableItem) cell.getViewerRow().getItem();\r
+               return item.getParent().getColumn(cell.getColumnIndex()).getWidth();\r
+       }\r
+\r
+       private static ViewerCell getCell(ViewerRow row, int index) {\r
+               return row.getCell(index);\r
+       }\r
+       \r
+       \r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/property/BooleanPropertyManipulator.java b/org.simantics.g3d/src/org/simantics/g3d/property/BooleanPropertyManipulator.java
new file mode 100644 (file)
index 0000000..88a7444
--- /dev/null
@@ -0,0 +1,69 @@
+package org.simantics.g3d.property;\r
+\r
+\r
+public class BooleanPropertyManipulator implements PropertyManipulator {\r
+       \r
+       ValueProvider provider;\r
+       Object input;\r
+       \r
+       boolean editMode;\r
+       String editValue = null;\r
+       \r
+       public BooleanPropertyManipulator(ValueProvider provider, Object input) {\r
+               this.provider = provider;\r
+               this.input = input;\r
+       }\r
+       \r
+       @Override\r
+       public int getValueCount() {\r
+               return 1;\r
+       }\r
+       \r
+       @Override\r
+       public String getDescription(int i) {\r
+               if (i == 0)\r
+                       return "Value";\r
+               return null;\r
+       }\r
+       \r
+       @Override\r
+       public String getValue(int i) {\r
+               if (editMode)\r
+                       return editValue;\r
+               try {\r
+                       return provider.getValue(input).toString();\r
+               } catch (Exception e) {\r
+                       return null;\r
+               }\r
+       }\r
+       \r
+       @Override\r
+       public String setValue(String value, int i) {\r
+               try {\r
+                       editValue = value;\r
+                       provider.setValue(input, Boolean.parseBoolean(value));\r
+               } catch (Exception e) {\r
+                       return e.getMessage();\r
+               }\r
+               return null;\r
+       }\r
+       \r
+       @Override\r
+       public boolean getEditMode() {\r
+               return editMode;\r
+       }\r
+       \r
+       @Override\r
+       public void setEditMode(boolean b) {\r
+               editMode = b;\r
+               if (editMode) {\r
+                       try {\r
+                               editValue = provider.getValue(input).toString();\r
+                       } catch (Exception e) {\r
+                               \r
+                       }\r
+               }\r
+               \r
+       }\r
+\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/property/DefaultPropertyManipulatorFactory.java b/org.simantics.g3d/src/org/simantics/g3d/property/DefaultPropertyManipulatorFactory.java
new file mode 100644 (file)
index 0000000..c6074f2
--- /dev/null
@@ -0,0 +1,38 @@
+package org.simantics.g3d.property;\r
+\r
+import java.lang.reflect.Method;\r
+\r
+import javax.vecmath.Quat4d;\r
+import javax.vecmath.Vector3d;\r
+\r
+public class DefaultPropertyManipulatorFactory implements PropertyManipulatorFactory {\r
+       \r
+       @Override\r
+       public Class<? extends PropertyManipulator> get(Method get, Object value) {\r
+               Class<?> returnValue = null;\r
+               if (get != null)\r
+                       returnValue = get.getReturnType();\r
+               else\r
+                       returnValue = value.getClass();\r
+               if (Double.class.equals(returnValue))\r
+                       return DoublePropertyManipulator.class;\r
+               if (Vector3d.class.equals(returnValue))\r
+                       return VectorPropertyManipulator.class;\r
+               if (Quat4d.class.equals(returnValue))\r
+                       return QuatPropertyManipulator.class;\r
+               if (String.class.equals(returnValue))\r
+                       return StringPropertyManipulator.class;\r
+               if (Integer.class.equals(returnValue))\r
+                       return IntegerPropertyManipulator.class;\r
+               if (Boolean.class.equals(returnValue))\r
+                       return BooleanPropertyManipulator.class;\r
+               if(double.class.equals(returnValue)) \r
+                       return DoublePropertyManipulator.class;\r
+               if(int.class.equals(returnValue))\r
+                       return IntegerPropertyManipulator.class;\r
+               if(boolean.class.equals(returnValue))\r
+                       return BooleanPropertyManipulator.class;\r
+               throw new RuntimeException("Cannot handle value " + returnValue.getName() + " for method " + get);\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/property/DoublePropertyManipulator.java b/org.simantics.g3d/src/org/simantics/g3d/property/DoublePropertyManipulator.java
new file mode 100644 (file)
index 0000000..7f120b2
--- /dev/null
@@ -0,0 +1,69 @@
+package org.simantics.g3d.property;\r
+\r
+import java.lang.reflect.Method;\r
+\r
+public class DoublePropertyManipulator implements PropertyManipulator {\r
+       \r
+       ValueProvider provider;\r
+       Object input;\r
+       \r
+       boolean editMode;\r
+       String editValue = null;\r
+       \r
+       public DoublePropertyManipulator(ValueProvider provider, Object input) {\r
+               this.provider = provider;\r
+               this.input = input;\r
+       }\r
+       \r
+       @Override\r
+       public int getValueCount() {\r
+               return 1;\r
+       }\r
+       \r
+       @Override\r
+       public String getDescription(int i) {\r
+               if (i == 0)\r
+                       return "Value";\r
+               return null;\r
+       }\r
+       \r
+       @Override\r
+       public String getValue(int i) {\r
+               if (editMode)\r
+                       return editValue;\r
+               try {\r
+                       return provider.getValue(input).toString();\r
+               } catch (Exception e) {\r
+                       return null;\r
+               }\r
+       }\r
+       \r
+       @Override\r
+       public String setValue(String value, int i) {\r
+               try {\r
+                       editValue = value;\r
+                       provider.setValue(input, Double.parseDouble(value));\r
+               } catch (Exception e) {\r
+                       return e.getMessage();\r
+               }\r
+               return null;\r
+       }\r
+\r
+       @Override\r
+       public boolean getEditMode() {\r
+               return editMode;\r
+       }\r
+       \r
+       @Override\r
+       public void setEditMode(boolean b) {\r
+               editMode = b;\r
+               if (editMode) {\r
+                       try {\r
+                               editValue = provider.getValue(input).toString();\r
+                       } catch (Exception e) {\r
+                               \r
+                       }\r
+               }\r
+               \r
+       }\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/property/IntegerPropertyManipulator.java b/org.simantics.g3d/src/org/simantics/g3d/property/IntegerPropertyManipulator.java
new file mode 100644 (file)
index 0000000..b6243ba
--- /dev/null
@@ -0,0 +1,69 @@
+package org.simantics.g3d.property;\r
+\r
+\r
+public class IntegerPropertyManipulator implements PropertyManipulator {\r
+       \r
+       ValueProvider provider;\r
+       Object input;\r
+       \r
+       boolean editMode;\r
+       String editValue = null;\r
+       \r
+       public IntegerPropertyManipulator(ValueProvider provider, Object input) {\r
+               this.provider = provider;\r
+               this.input = input;\r
+       }\r
+       \r
+       @Override\r
+       public int getValueCount() {\r
+               return 1;\r
+       }\r
+       \r
+       @Override\r
+       public String getDescription(int i) {\r
+               if (i == 0)\r
+                       return "Value";\r
+               return null;\r
+       }\r
+       \r
+       @Override\r
+       public String getValue(int i) {\r
+               if (editMode)\r
+                       return editValue;\r
+               try {\r
+                       return provider.getValue(input).toString();\r
+               } catch (Exception e) {\r
+                       return null;\r
+               }\r
+       }\r
+       \r
+       @Override\r
+       public String setValue(String value, int i) {\r
+               try {\r
+                       editValue = value;\r
+                       provider.setValue(input, Integer.parseInt(value));\r
+               } catch (Exception e) {\r
+                       return e.getMessage();\r
+               }\r
+               return null;\r
+       }\r
+       \r
+       @Override\r
+       public boolean getEditMode() {\r
+               return editMode;\r
+       }\r
+       \r
+       @Override\r
+       public void setEditMode(boolean b) {\r
+               editMode = b;\r
+               if (editMode) {\r
+                       try {\r
+                               editValue = provider.getValue(input).toString();\r
+                       } catch (Exception e) {\r
+                               \r
+                       }\r
+               }\r
+               \r
+       }\r
+\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/property/MethodValueProvider.java b/org.simantics.g3d/src/org/simantics/g3d/property/MethodValueProvider.java
new file mode 100644 (file)
index 0000000..b75a1eb
--- /dev/null
@@ -0,0 +1,23 @@
+package org.simantics.g3d.property;\r
+\r
+import java.lang.reflect.Method;\r
+\r
+public class MethodValueProvider implements ValueProvider {\r
+\r
+       Method getter; \r
+       Method setter;\r
+       \r
+       public MethodValueProvider(Method getter, Method setter) {\r
+               this.getter = getter;\r
+               this.setter = setter;\r
+       }\r
+       \r
+       @Override\r
+       public Object getValue(Object obj) throws Exception{\r
+               return getter.invoke(obj);\r
+       }\r
+       @Override\r
+       public void setValue(Object obj, Object value) throws Exception {\r
+               setter.invoke(obj,value);\r
+       }\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/property/MethodWithMapValueProvider.java b/org.simantics.g3d/src/org/simantics/g3d/property/MethodWithMapValueProvider.java
new file mode 100644 (file)
index 0000000..256de3a
--- /dev/null
@@ -0,0 +1,31 @@
+package org.simantics.g3d.property;\r
+\r
+import java.lang.reflect.Method;\r
+import java.util.HashMap;\r
+import java.util.Map;\r
+\r
+public class MethodWithMapValueProvider implements ValueProvider {\r
+\r
+       Method getter; \r
+       Method setter;\r
+       String key;\r
+       \r
+       public MethodWithMapValueProvider(Method getter, Method setter, String key) {\r
+               this.getter = getter;\r
+               this.setter = setter;\r
+               this.key = key;\r
+       }\r
+       \r
+       @Override\r
+       public Object getValue(Object obj) throws Exception{\r
+               Map<String,Object> map = (Map<String, Object>)getter.invoke(obj);\r
+               return map.get(key);\r
+       }\r
+       @Override\r
+       public void setValue(Object obj, Object value) throws Exception {\r
+               Map<String,Object> map = new HashMap<String, Object>();\r
+               map.putAll((Map<String, Object>)getter.invoke(obj));\r
+               map.put(key, value);\r
+               setter.invoke(obj,map);\r
+       }\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/property/PropertyManipulator.java b/org.simantics.g3d/src/org/simantics/g3d/property/PropertyManipulator.java
new file mode 100644 (file)
index 0000000..3a50200
--- /dev/null
@@ -0,0 +1,50 @@
+package org.simantics.g3d.property;\r
+\r
+/**\r
+ * Interfaces for manipulating properties.\r
+ * \r
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>\r
+ *\r
+ */\r
+public interface PropertyManipulator {\r
+       \r
+       /**\r
+        * Returns number of individual values.\r
+        * @return\r
+        */\r
+       int getValueCount();\r
+       \r
+       /**\r
+        * Returns value at given index.\r
+        * @param i\r
+        * @return\r
+        */\r
+       String getValue(int i);\r
+       \r
+       /**\r
+        * Sets value at given index.\r
+        * @param i\r
+        * @return\r
+        */\r
+       String setValue(String value, int i);\r
+       \r
+       /**\r
+        * Returns description of a value at given index. The description is shown in the table header.\r
+        * @param i\r
+        * @return\r
+        */\r
+       String getDescription(int i);\r
+       \r
+       /**\r
+        * Gets edit mode status.\r
+        * @return\r
+        */\r
+       boolean getEditMode();\r
+       \r
+       /**\r
+        * Sets edit mode status.\r
+        * @param b\r
+        */\r
+       void setEditMode(boolean b);\r
+\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/property/PropertyManipulatorFactory.java b/org.simantics.g3d/src/org/simantics/g3d/property/PropertyManipulatorFactory.java
new file mode 100644 (file)
index 0000000..8f6a91a
--- /dev/null
@@ -0,0 +1,9 @@
+package org.simantics.g3d.property;\r
+\r
+import java.lang.reflect.Method;\r
+\r
+public interface PropertyManipulatorFactory {\r
+       \r
+       public Class<? extends PropertyManipulator> get(Method get, Object value);\r
+\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/property/PropertyTabContributor.java b/org.simantics.g3d/src/org/simantics/g3d/property/PropertyTabContributor.java
new file mode 100644 (file)
index 0000000..18a3a7f
--- /dev/null
@@ -0,0 +1,6 @@
+package org.simantics.g3d.property;\r
+\r
+public interface PropertyTabContributor  extends org.simantics.selectionview.PropertyTabContributor{\r
+\r
+       public String getId();\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/property/PropertyTabContributorFactory.java b/org.simantics.g3d/src/org/simantics/g3d/property/PropertyTabContributorFactory.java
new file mode 100644 (file)
index 0000000..3b0e7ef
--- /dev/null
@@ -0,0 +1,10 @@
+package org.simantics.g3d.property;\r
+\r
+import java.util.List;\r
+\r
+\r
+public interface PropertyTabContributorFactory {\r
+\r
+       \r
+       public List<PropertyTabContributor> getContributors(Object input);\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/property/PropertyTabUtil.java b/org.simantics.g3d/src/org/simantics/g3d/property/PropertyTabUtil.java
new file mode 100644 (file)
index 0000000..4d006ee
--- /dev/null
@@ -0,0 +1,35 @@
+package org.simantics.g3d.property;\r
+\r
+import java.util.Collections;\r
+import java.util.List;\r
+\r
+import org.simantics.g3d.property.annotations.PropertyContributor;\r
+\r
+public class PropertyTabUtil {\r
+       \r
+       \r
+       @SuppressWarnings("unchecked")\r
+       public static List<PropertyTabContributor> getContributors(Object input) {\r
+               PropertyTabContributorFactory factory = resolveFactory(input.getClass());\r
+               if (factory == null)\r
+                       return Collections.EMPTY_LIST;\r
+               return factory.getContributors(input);\r
+       }\r
+       \r
+       private static PropertyTabContributorFactory resolveFactory(Class<?> clazz) {\r
+               PropertyContributor contributor = clazz.getAnnotation(PropertyContributor.class);\r
+               if (contributor != null)\r
+                       try {\r
+                               return contributor.value().newInstance();\r
+                       } catch (InstantiationException e) {\r
+                               e.printStackTrace();\r
+                       } catch (IllegalAccessException e) {\r
+                               e.printStackTrace();\r
+                       }\r
+               Class<?> superClass = clazz.getSuperclass();\r
+               if (superClass != null)\r
+                       return resolveFactory(superClass);\r
+               return null;\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/property/QuatPropertyManipulator.java b/org.simantics.g3d/src/org/simantics/g3d/property/QuatPropertyManipulator.java
new file mode 100644 (file)
index 0000000..ca792ef
--- /dev/null
@@ -0,0 +1,265 @@
+package org.simantics.g3d.property;\r
+\r
+import javax.vecmath.AxisAngle4d;\r
+import javax.vecmath.Quat4d;\r
+import javax.vecmath.Vector3d;\r
+\r
+import org.simantics.g3d.Activator;\r
+import org.simantics.g3d.math.EulerTools;\r
+import org.simantics.g3d.math.EulerTools.Order;\r
+import org.simantics.g3d.math.MathTools;\r
+import org.simantics.g3d.preferences.PreferenceConstants;\r
+\r
+public class QuatPropertyManipulator implements PropertyManipulator {\r
+       \r
+       ValueProvider provider;\r
+       protected Object input;\r
+       \r
+       enum EditType {QUATERNION,AXIS_ANGLE,EULER};\r
+       \r
+       EditType type = EditType.QUATERNION;\r
+       Order order;\r
+       \r
+       boolean editMode;\r
+       Object editValue = null;\r
+       \r
+       public QuatPropertyManipulator(ValueProvider provider, Object input) {\r
+               this.provider = provider;\r
+               this.input = input;\r
+               \r
+               String set = Activator.getDefault().getPreferenceStore().getString(PreferenceConstants.ORIENTATION_PRESENTATION);\r
+               if ("quat".equals(set)) {\r
+                       type = EditType.QUATERNION;\r
+               } else if ("aa".equals(set)) {\r
+                       type = EditType.AXIS_ANGLE;\r
+               } else if ("euler".equals(set)) {\r
+                       type = EditType.EULER;\r
+                       String eulerOrder = Activator.getDefault().getPreferenceStore().getString(PreferenceConstants.EULER_ANGLE_ORDER);\r
+                       order = Order.valueOf(eulerOrder);\r
+                       if (order == null)\r
+                               order = Order.YXZ;\r
+               }\r
+       }\r
+       \r
+       @Override\r
+       public String getDescription(int i) {\r
+               switch (type) {\r
+               case QUATERNION:\r
+                       if (i == 0)\r
+                               return "X";\r
+                       if (i == 1)\r
+                               return "Y";\r
+                       if (i == 2)\r
+                               return "Z";\r
+                       if (i == 3)\r
+                               return "W";\r
+                       break;\r
+               case AXIS_ANGLE:\r
+                       if (i == 0)\r
+                               return "X";\r
+                       if (i == 1)\r
+                               return "Y";\r
+                       if (i == 2)\r
+                               return "Z";\r
+                       if (i == 3)\r
+                               return "Angle";\r
+                       break;\r
+               case EULER:\r
+                       if (i > 3)\r
+                               return null;\r
+                       return order.toString().substring(i, i+1);\r
+               default:\r
+                       break;\r
+               }\r
+               return null;\r
+       }\r
+       \r
+       @Override\r
+       public int getValueCount() {\r
+               switch (type) {\r
+               case QUATERNION:\r
+                       return 4;\r
+               case AXIS_ANGLE:\r
+                       return 4;\r
+               case EULER:\r
+                       return 3;\r
+               default:\r
+                       break;\r
+               }\r
+               return 0;\r
+       }\r
+       \r
+       @Override\r
+       public String getValue(int i) {\r
+               try {\r
+                       Quat4d q = (Quat4d) provider.getValue(input);\r
+                       double d = 0;\r
+                       switch (type) {\r
+                       case QUATERNION:\r
+                               if (editMode)\r
+                                       q = (Quat4d)editValue;\r
+                               else\r
+                                       q = new Quat4d(q);\r
+                               \r
+                               if (i == 0)\r
+                                       d = q.x;\r
+                               if (i == 1)\r
+                                       d = q.y;\r
+                               if (i == 2)\r
+                                       d = q.z;\r
+                               if (i == 3)\r
+                                       d = q.w;\r
+                               break;\r
+                               \r
+                       case AXIS_ANGLE: {\r
+                               AxisAngle4d aa;\r
+                               if (editMode)\r
+                                       aa = (AxisAngle4d)editValue;\r
+                               else {\r
+                                       aa = new AxisAngle4d();\r
+                                       aa.set(q);\r
+                               }\r
+                               if (i == 0)\r
+                                       d = aa.x;\r
+                               if (i == 1)\r
+                                       d = aa.y;\r
+                               if (i == 2)\r
+                                       d = aa.z;\r
+                               if (i == 3)\r
+                                       d = MathTools.radToDeg(aa.angle);\r
+                               break;\r
+                       }\r
+                       case EULER: {\r
+                               Vector3d aa;\r
+                               if (editMode)\r
+                                       aa = (Vector3d)editValue;\r
+                               else\r
+                                       aa = EulerTools.getEulerFromQuat(order, q);//MathTools.getEuler(q);\r
+                               if (i == 0)\r
+                                       d = aa.x;\r
+                               if (i == 1)\r
+                                       d = aa.y;\r
+                               if (i == 2)\r
+                                       d = aa.z;\r
+                               d = MathTools.radToDeg(d);\r
+                       }\r
+\r
+                       default:\r
+                               break;\r
+                       }\r
+                       return Double.toString(d);\r
+               } catch (Exception e) {\r
+                       return null;\r
+               }\r
+       }\r
+       \r
+       \r
+       \r
+       @Override\r
+       public String setValue(String value, int i) {\r
+               try {\r
+                       Double d = Double.parseDouble(value);\r
+                       Quat4d q = (Quat4d) provider.getValue(input);\r
+                       switch (type) {\r
+                       case QUATERNION:\r
+                               if (editMode)\r
+                                       q = (Quat4d)editValue;\r
+                               else\r
+                                       q = new Quat4d(q);\r
+                               \r
+                               if (i == 0)\r
+                                       q.x = d;\r
+                               if (i == 1)\r
+                                       q.y = d;\r
+                               if (i == 2)\r
+                                       q.z = d;\r
+                               if (i == 3)\r
+                                       q.w = d;\r
+                               break;\r
+                       case AXIS_ANGLE: {\r
+                               AxisAngle4d aa;\r
+                               if (editMode)\r
+                                       aa = (AxisAngle4d) editValue;\r
+                               else {\r
+                                       aa = new AxisAngle4d();\r
+                                       aa.set(q);\r
+                               }\r
+                               if (i == 0)\r
+                                       aa.x = d;\r
+                               if (i == 1)\r
+                                       aa.y = d;\r
+                               if (i == 2)\r
+                                       aa.z = d;\r
+                               if (i == 3)\r
+                                       aa.angle = MathTools.degToRad(d);\r
+                               q = new Quat4d();\r
+                               MathTools.getQuat(aa,q);\r
+                               break;\r
+                       }\r
+                       case EULER: {\r
+                               Vector3d e;\r
+                               if (editMode)\r
+                                       e = (Vector3d)editValue;\r
+                               else \r
+                                       e = EulerTools.getEulerFromQuat(order, q);//MathTools.getEuler(q);\r
+                               d = MathTools.degToRad(d);\r
+                               if (i == 0)\r
+                                       e.x = d;\r
+                               if (i == 1)\r
+                                       e.y = d;\r
+                               if (i == 2)\r
+                                       e.z = d;\r
+                               q = EulerTools.getQuatFromEuler(order, e);//MathTools.getQuat(e);\r
+                       }\r
+                       default:\r
+                               break;\r
+                       }\r
+                       q.normalize();\r
+                       setValue(q);\r
+               } catch (Exception e) {\r
+                       return e.getMessage();\r
+               }\r
+               return null;\r
+       }\r
+       \r
+       protected void setValue(Quat4d q) throws Exception {\r
+               provider.setValue(input, q);\r
+       }\r
+       \r
+       private void storeEditValue() {\r
+               try {\r
+                       Quat4d q = (Quat4d) provider.getValue(input);\r
+                       switch (type) {\r
+                       case QUATERNION:\r
+                               editValue = q;\r
+                               break;\r
+                       case AXIS_ANGLE:\r
+                               AxisAngle4d aa = new AxisAngle4d();\r
+                               aa.set(q);\r
+                               editValue = aa;\r
+                               break;\r
+                       case EULER:\r
+                               Vector3d e = EulerTools.getEulerFromQuat(order, q);\r
+                               editValue = e;\r
+                               break;\r
+                       }\r
+               } catch (Exception e) {\r
+                       \r
+               }\r
+       }\r
+       \r
+       @Override\r
+       public boolean getEditMode() {\r
+               return editMode;\r
+       }\r
+       \r
+       @Override\r
+       public void setEditMode(boolean b) {\r
+               editMode = b;\r
+               if (editMode) {\r
+                       storeEditValue();\r
+               }\r
+               \r
+       }\r
+\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/property/StringPropertyManipulator.java b/org.simantics.g3d/src/org/simantics/g3d/property/StringPropertyManipulator.java
new file mode 100644 (file)
index 0000000..8e6cb46
--- /dev/null
@@ -0,0 +1,69 @@
+package org.simantics.g3d.property;\r
+\r
+import java.lang.reflect.Method;\r
+\r
+public class StringPropertyManipulator implements PropertyManipulator {\r
+       \r
+       ValueProvider provider;\r
+       Object input;\r
+       \r
+       boolean editMode;\r
+       String editValue = null;\r
+       \r
+       public StringPropertyManipulator(ValueProvider provider, Object input) {\r
+               this.provider = provider;\r
+               this.input = input;\r
+       }\r
+       \r
+       @Override\r
+       public int getValueCount() {\r
+               return 1;\r
+       }\r
+       \r
+       @Override\r
+       public String getDescription(int i) {\r
+               if (i == 0)\r
+                       return "Value";\r
+               return null;\r
+       }\r
+       \r
+       @Override\r
+       public String getValue(int i) {\r
+               if (editMode)\r
+                       return editValue;\r
+               try {\r
+                       return provider.getValue(input).toString();\r
+               } catch (Exception e) {\r
+                       return null;\r
+               }\r
+       }\r
+       \r
+       @Override\r
+       public String setValue(String value, int i) {\r
+               try {\r
+                       editValue = value;\r
+                       provider.setValue(input, value);\r
+               } catch (Exception e) {\r
+                       return e.getMessage();\r
+               }\r
+               return null;\r
+       }\r
+\r
+       @Override\r
+       public boolean getEditMode() {\r
+               return editMode;\r
+       }\r
+       \r
+       @Override\r
+       public void setEditMode(boolean b) {\r
+               editMode = b;\r
+               if (editMode) {\r
+                       try {\r
+                               editValue = provider.getValue(input).toString();\r
+                       } catch (Exception e) {\r
+                               \r
+                       }\r
+               }\r
+               \r
+       }\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/property/ValueProvider.java b/org.simantics.g3d/src/org/simantics/g3d/property/ValueProvider.java
new file mode 100644 (file)
index 0000000..38ce9e1
--- /dev/null
@@ -0,0 +1,9 @@
+package org.simantics.g3d.property;\r
+\r
+public interface ValueProvider {\r
+       \r
+       \r
+       Object getValue(Object obj) throws Exception;\r
+       void setValue(Object obj, Object value) throws Exception;\r
+\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/property/VectorPropertyManipulator.java b/org.simantics.g3d/src/org/simantics/g3d/property/VectorPropertyManipulator.java
new file mode 100644 (file)
index 0000000..84095ed
--- /dev/null
@@ -0,0 +1,103 @@
+package org.simantics.g3d.property;\r
+\r
+import java.lang.reflect.InvocationTargetException;\r
+import java.lang.reflect.Method;\r
+\r
+import javax.vecmath.Vector3d;\r
+\r
+public class VectorPropertyManipulator implements PropertyManipulator {\r
+       \r
+       ValueProvider provider;\r
+       protected Object input;\r
+       \r
+       boolean editMode;\r
+       Vector3d editValue = null;\r
+       \r
+       public VectorPropertyManipulator(ValueProvider provider, Object input) {\r
+               this.provider = provider;\r
+               this.input = input;\r
+       }\r
+       \r
+       @Override\r
+       public int getValueCount() {\r
+               return 3;\r
+       }\r
+       \r
+       @Override\r
+       public String getDescription(int i) {\r
+               if (i == 0)\r
+                       return "X";\r
+               if (i == 1)\r
+                       return "Y";\r
+               if (i == 2)\r
+                       return "Z";\r
+               return null;\r
+       }\r
+       \r
+       @Override\r
+       public String getValue(int i) {\r
+               try {\r
+                       Vector3d v = _getValue();\r
+                       if (v == null)\r
+                               return null;\r
+                       if (i == 0)\r
+                               return Double.toString(v.x);\r
+                       if (i == 1)\r
+                               return Double.toString(v.y);\r
+                       if (i == 2)\r
+                               return Double.toString(v.z);\r
+                       return null;\r
+               } catch (Exception e) {\r
+                       return null;\r
+               }\r
+       }\r
+       \r
+       @Override\r
+       public String setValue(String value, int i) {\r
+               try {\r
+                       Double d = Double.parseDouble(value);\r
+                       Vector3d v = _getValue();\r
+                       v = new Vector3d(v.x, v.y, v.z);\r
+                       if (i == 0)\r
+                               v.x = d;\r
+                       if (i == 1)\r
+                               v.y = d;\r
+                       if (i == 2)\r
+                               v.z = d;\r
+                       editValue = v;\r
+                       setValue(v);\r
+               } catch (Exception e) {\r
+                       return e.getMessage();\r
+               }\r
+               return null;\r
+       }\r
+       \r
+       protected void setValue(Vector3d v) throws Exception {\r
+               provider.setValue(input, v);\r
+       }\r
+       \r
+       private Vector3d _getValue() throws Exception{\r
+               if (editMode)\r
+                       return editValue;\r
+               return (Vector3d) provider.getValue(input);\r
+       }\r
+       \r
+       @Override\r
+       public boolean getEditMode() {\r
+               return editMode;\r
+       }\r
+       \r
+       @Override\r
+       public void setEditMode(boolean b) {\r
+               editMode = b;\r
+               if (editMode) {\r
+                       try {\r
+                               editValue = (Vector3d) provider.getValue(input);\r
+                       } catch (Exception e) {\r
+                               \r
+                       }\r
+               }\r
+               \r
+       }\r
+\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/property/annotations/CompoundGetPropertyValue.java b/org.simantics.g3d/src/org/simantics/g3d/property/annotations/CompoundGetPropertyValue.java
new file mode 100644 (file)
index 0000000..a241d5e
--- /dev/null
@@ -0,0 +1,18 @@
+package org.simantics.g3d.property.annotations;\r
+\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+import org.simantics.g3d.property.DefaultPropertyManipulatorFactory;\r
+import org.simantics.g3d.property.PropertyManipulatorFactory;\r
+\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target(ElementType.METHOD)\r
+public @interface CompoundGetPropertyValue {\r
+       String value();\r
+       String name() default "";\r
+       String tabId() default "Default";\r
+       Class<? extends PropertyManipulatorFactory> manipulator() default DefaultPropertyManipulatorFactory.class; \r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/property/annotations/CompoundSetPropertyValue.java b/org.simantics.g3d/src/org/simantics/g3d/property/annotations/CompoundSetPropertyValue.java
new file mode 100644 (file)
index 0000000..067b5ce
--- /dev/null
@@ -0,0 +1,12 @@
+package org.simantics.g3d.property.annotations;\r
+\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target(ElementType.METHOD) \r
+public @interface CompoundSetPropertyValue {\r
+       String value();\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/property/annotations/GetPropertyValue.java b/org.simantics.g3d/src/org/simantics/g3d/property/annotations/GetPropertyValue.java
new file mode 100644 (file)
index 0000000..d79fb9a
--- /dev/null
@@ -0,0 +1,18 @@
+package org.simantics.g3d.property.annotations;\r
+\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+import org.simantics.g3d.property.DefaultPropertyManipulatorFactory;\r
+import org.simantics.g3d.property.PropertyManipulatorFactory;\r
+\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target(ElementType.METHOD)\r
+public @interface GetPropertyValue {\r
+       String value();\r
+       String name() default "";\r
+       String tabId() default "Default";\r
+       Class<? extends PropertyManipulatorFactory> manipulator() default DefaultPropertyManipulatorFactory.class; \r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/property/annotations/PropertyContributor.java b/org.simantics.g3d/src/org/simantics/g3d/property/annotations/PropertyContributor.java
new file mode 100644 (file)
index 0000000..148b6ea
--- /dev/null
@@ -0,0 +1,15 @@
+package org.simantics.g3d.property.annotations;\r
+\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+import org.simantics.g3d.property.AnnotatedPropertyTabContributorFactory;\r
+import org.simantics.g3d.property.PropertyTabContributorFactory;\r
+\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target(ElementType.TYPE) \r
+public @interface PropertyContributor {\r
+       Class<? extends PropertyTabContributorFactory> value() default AnnotatedPropertyTabContributorFactory.class;\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/property/annotations/PropertyTabBlacklist.java b/org.simantics.g3d/src/org/simantics/g3d/property/annotations/PropertyTabBlacklist.java
new file mode 100644 (file)
index 0000000..7178a5c
--- /dev/null
@@ -0,0 +1,13 @@
+package org.simantics.g3d.property.annotations;\r
+\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target(ElementType.TYPE) \r
+public @interface PropertyTabBlacklist {\r
+       String value() default "";\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/property/annotations/SetPropertyValue.java b/org.simantics.g3d/src/org/simantics/g3d/property/annotations/SetPropertyValue.java
new file mode 100644 (file)
index 0000000..b5ad4da
--- /dev/null
@@ -0,0 +1,12 @@
+package org.simantics.g3d.property.annotations;\r
+\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target(ElementType.METHOD) \r
+public @interface SetPropertyValue {\r
+       String value();\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/scenegraph/G3DNode.java b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/G3DNode.java
new file mode 100644 (file)
index 0000000..714e7a5
--- /dev/null
@@ -0,0 +1,149 @@
+package org.simantics.g3d.scenegraph;\r
+\r
+import javax.vecmath.Quat4d;\r
+import javax.vecmath.Vector3d;\r
+\r
+import org.simantics.g3d.ontology.G3D;\r
+import org.simantics.g3d.property.annotations.GetPropertyValue;\r
+import org.simantics.g3d.property.annotations.PropertyContributor;\r
+import org.simantics.g3d.property.annotations.SetPropertyValue;\r
+import org.simantics.g3d.scenegraph.base.INode;\r
+import org.simantics.g3d.scenegraph.base.Node;\r
+import org.simantics.g3d.tools.NodeTools;\r
+import org.simantics.objmap.graph.annotations.RelatedGetValue;\r
+import org.simantics.objmap.graph.annotations.RelatedSetValue;\r
+\r
+\r
+@PropertyContributor\r
+public class G3DNode extends Node implements IG3DNode {\r
+       \r
+       private Vector3d position = new Vector3d();\r
+       private Quat4d orientation = new Quat4d(0,0,0,1);\r
+       \r
+       @Override\r
+       @GetPropertyValue(value = G3D.URIs.hasOrientation, tabId = "Transform", name = "Orientation")\r
+       public Quat4d getOrientation() {\r
+               return orientation;\r
+       }\r
+       \r
+       @RelatedGetValue(G3D.URIs.hasOrientation)\r
+       public double[] getOrientationArr() {\r
+               double arr[] = new double[4];\r
+               orientation.get(arr);\r
+               return arr;\r
+               \r
+       }\r
+       \r
+       @Override\r
+       @GetPropertyValue(value = G3D.URIs.hasPosition, tabId = "Transform", name = "Position")\r
+       public Vector3d getPosition() {\r
+               return position;\r
+       }\r
+       \r
+       @RelatedGetValue(G3D.URIs.hasPosition)\r
+       public double[] getPositionArr() {\r
+               double arr[] = new double[3];\r
+               position.get(arr);\r
+               return arr;\r
+       }\r
+       \r
+       @Override\r
+       @SetPropertyValue(G3D.URIs.hasOrientation)\r
+       public void setOrientation(Quat4d orientation) {\r
+               assert(orientation != null);\r
+               this.orientation = orientation;\r
+               \r
+               firePropertyChanged(G3D.URIs.hasOrientation);\r
+       }\r
+       \r
+       @RelatedSetValue(G3D.URIs.hasOrientation)\r
+       public void setOrientation(double[] arr) {\r
+               if (arr == null)\r
+                       return;\r
+               setOrientation(new Quat4d(arr));\r
+       }\r
+       \r
+       @Override\r
+       @SetPropertyValue(G3D.URIs.hasPosition)\r
+       public void setPosition(Vector3d position) {\r
+               assert(position != null);\r
+               this.position = position;\r
+               \r
+               firePropertyChanged(G3D.URIs.hasPosition);\r
+       }\r
+       \r
+       @RelatedSetValue(G3D.URIs.hasPosition)\r
+       public void setPosition(double[] arr) {\r
+               if (arr == null)\r
+                       return;\r
+               setPosition(new Vector3d(arr));\r
+       }\r
+       \r
+       @Override\r
+       @GetPropertyValue(value = G3D.URIs.hasWorldPosition, tabId = "Transform", name = "World Position")\r
+       public Vector3d getWorldPosition() {\r
+               IG3DNode parent = (IG3DNode)getParent();\r
+               if (parent == null)\r
+                       return position;\r
+               return NodeTools.getWorldPosition(parent, new Vector3d(position));\r
+       }\r
+       \r
+       \r
+       public Vector3d getWorldPosition(Vector3d localPosition) {\r
+               return NodeTools.getWorldPosition(this,localPosition);\r
+       }\r
+\r
+       \r
+       @Override\r
+       @GetPropertyValue(value = G3D.URIs.hasWorldOrientation, tabId = "Transform", name = "World Orientation")\r
+       public Quat4d getWorldOrientation() {\r
+               return getWorldOrientation(new Quat4d(orientation));\r
+       }\r
+       \r
+       public Quat4d getWorldOrientation(Quat4d localOrientation) {\r
+               IG3DNode parent = (IG3DNode)getParent();\r
+               if (parent == null)\r
+                       return localOrientation;\r
+               return NodeTools.getWorldOrientation(parent, localOrientation);\r
+       }\r
+       \r
+       @Override\r
+       public Vector3d getLocalPosition(Vector3d worldPosition) {\r
+               IG3DNode parent = (IG3DNode)getParent();\r
+               if (parent == null)\r
+                       return worldPosition;\r
+               return NodeTools.getLocalPosition(parent,new Vector3d(worldPosition));\r
+       }\r
+       \r
+       @Override\r
+       public Quat4d getLocalOrientation(Quat4d worldOrientation) {\r
+               IG3DNode parent = (IG3DNode)getParent();\r
+               if (parent == null)\r
+                       return worldOrientation;\r
+               return NodeTools.getLocalOrientation(parent, new Quat4d(worldOrientation));\r
+       }\r
+       \r
+       @Override\r
+       @SetPropertyValue(G3D.URIs.hasWorldPosition)\r
+       public void setWorldPosition(Vector3d position) {\r
+               Vector3d localPos = getLocalPosition(position);\r
+               setPosition(localPos);\r
+       }\r
+       \r
+       @Override\r
+       @SetPropertyValue(G3D.URIs.hasWorldOrientation)\r
+       public void setWorldOrientation(Quat4d orientation) {\r
+               Quat4d localOr = getLocalOrientation(orientation);\r
+               setOrientation(localOr);\r
+       }\r
+       \r
+       @Override\r
+       public Object getAdapter(Class adapter) {\r
+               if (INode.class == adapter)\r
+                       return this;\r
+               if (IG3DNode.class == adapter)\r
+                       return this;\r
+               return null;\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/scenegraph/G3DparentNode.java b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/G3DparentNode.java
new file mode 100644 (file)
index 0000000..8e5cc81
--- /dev/null
@@ -0,0 +1,138 @@
+package org.simantics.g3d.scenegraph;\r
+\r
+import javax.vecmath.Quat4d;\r
+import javax.vecmath.Vector3d;\r
+\r
+import org.simantics.g3d.math.MathTools;\r
+import org.simantics.g3d.ontology.G3D;\r
+import org.simantics.g3d.property.annotations.GetPropertyValue;\r
+import org.simantics.g3d.property.annotations.SetPropertyValue;\r
+import org.simantics.g3d.scenegraph.base.ParentNode;\r
+import org.simantics.g3d.tools.NodeTools;\r
+import org.simantics.objmap.graph.annotations.RelatedGetValue;\r
+import org.simantics.objmap.graph.annotations.RelatedSetValue;\r
+\r
+\r
+public class G3DparentNode<T extends IG3DNode> extends ParentNode<T> implements IG3DNode{\r
+       private Vector3d position = new Vector3d();\r
+       private Quat4d orientation = MathTools.getIdentityQuat();\r
+       \r
+       \r
+       @Override\r
+       @GetPropertyValue(value = G3D.URIs.hasOrientation, tabId = "Transform", name = "Orientation")\r
+       public Quat4d getOrientation() {\r
+               return orientation;\r
+       }\r
+       \r
+       @RelatedGetValue(G3D.URIs.hasOrientation)\r
+       public double[] getOrientationArr() {\r
+               double arr[] = new double[4];\r
+               orientation.get(arr);\r
+               return arr;\r
+               \r
+       }\r
+       \r
+       @Override\r
+       @GetPropertyValue(value = G3D.URIs.hasPosition, tabId = "Transform", name = "Position")\r
+       public Vector3d getPosition() {\r
+               return position;\r
+       }\r
+       \r
+       @RelatedGetValue(G3D.URIs.hasPosition)\r
+       public double[] getPositionArr() {\r
+               double arr[] = new double[3];\r
+               position.get(arr);\r
+               return arr;\r
+       }\r
+       \r
+       @Override\r
+       @SetPropertyValue(G3D.URIs.hasOrientation)\r
+       public void setOrientation(Quat4d orientation) {\r
+               assert(orientation != null);\r
+               this.orientation = orientation;\r
+       }\r
+       \r
+       @Override\r
+       @SetPropertyValue(G3D.URIs.hasPosition)\r
+       public void setPosition(Vector3d position) {\r
+               assert(position != null);\r
+               this.position = position;\r
+       }\r
+       \r
+       @RelatedSetValue(G3D.URIs.hasOrientation)\r
+       public void setOrientation(double[] arr) {\r
+               if (arr == null)\r
+                       return;\r
+               setOrientation(new Quat4d(arr));\r
+       }\r
+       \r
+       @RelatedSetValue(G3D.URIs.hasPosition)\r
+       public void setPosition(double[] arr) {\r
+               if (arr == null)\r
+                       return;\r
+               setPosition(new Vector3d(arr));\r
+       }\r
+       \r
+       @Override\r
+       @GetPropertyValue(value = G3D.URIs.hasWorldPosition, tabId = "Transform", name = "World Position")\r
+       public Vector3d getWorldPosition() {\r
+               IG3DNode parent = (IG3DNode)getParent();\r
+               if (parent == null)\r
+                       return position;\r
+               return NodeTools.getWorldPosition(parent, new Vector3d(position));\r
+       }\r
+       \r
+       \r
+       public Vector3d getWorldPosition(Vector3d localPosition) {\r
+               return NodeTools.getWorldPosition(this,localPosition);\r
+       }\r
+\r
+       \r
+       @Override\r
+       @GetPropertyValue(value = G3D.URIs.hasWorldOrientation, tabId = "Transform", name = "World Orientation")\r
+       public Quat4d getWorldOrientation() {\r
+               return getWorldOrientation(new Quat4d(orientation));\r
+       }\r
+       \r
+       public Quat4d getWorldOrientation(Quat4d localOrientation) {\r
+               IG3DNode parent = (IG3DNode)getParent();\r
+               if (parent == null)\r
+                       return localOrientation;\r
+               return NodeTools.getWorldOrientation(parent, localOrientation);\r
+       }\r
+       \r
+       @Override\r
+       public Vector3d getLocalPosition(Vector3d worldPosition) {\r
+               IG3DNode parent = (IG3DNode)getParent();\r
+               if (parent == null)\r
+                       return worldPosition;\r
+               return NodeTools.getLocalPosition(parent,new Vector3d(worldPosition));\r
+       }\r
+       \r
+       @Override\r
+       public Quat4d getLocalOrientation(Quat4d worldOrientation) {\r
+               IG3DNode parent = (IG3DNode)getParent();\r
+               if (parent == null)\r
+                       return worldOrientation;\r
+               return NodeTools.getLocalOrientation(parent, new Quat4d(worldOrientation));\r
+       }\r
+       \r
+       @Override\r
+       @SetPropertyValue(G3D.URIs.hasWorldPosition)\r
+       public void setWorldPosition(Vector3d position) {\r
+               Vector3d localPos = getLocalPosition(position);\r
+               setPosition(localPos);\r
+       }\r
+       \r
+       @Override\r
+       @SetPropertyValue(G3D.URIs.hasWorldOrientation)\r
+       public void setWorldOrientation(Quat4d orientation) {\r
+               Quat4d localOr = getLocalOrientation(orientation);\r
+               setOrientation(localOr);\r
+       }\r
+       \r
+       @Override\r
+       public Object getAdapter(Class adapter) {\r
+               return null;\r
+       }\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/scenegraph/IG3DNode.java b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/IG3DNode.java
new file mode 100644 (file)
index 0000000..4d54a28
--- /dev/null
@@ -0,0 +1,35 @@
+package org.simantics.g3d.scenegraph;\r
+\r
+import javax.vecmath.Quat4d;\r
+import javax.vecmath.Vector3d;\r
+\r
+import org.eclipse.core.runtime.IAdaptable;\r
+import org.simantics.g3d.scenegraph.base.INode;\r
+\r
+\r
+public interface IG3DNode extends INode, IAdaptable {\r
+\r
+       \r
+       \r
+       public Vector3d getPosition();\r
+       public void setPosition(Vector3d position);\r
+       \r
+       public Quat4d getOrientation();\r
+       public void setOrientation(Quat4d orientation);\r
+       \r
+       public Vector3d getWorldPosition();\r
+       public Quat4d getWorldOrientation();\r
+       \r
+       public Vector3d getWorldPosition(Vector3d localPosition);\r
+       public Quat4d getWorldOrientation(Quat4d localOrientation);\r
+       \r
+       \r
+       public Vector3d getLocalPosition(Vector3d worldPosition);\r
+       public Quat4d getLocalOrientation(Quat4d worldOrientation);\r
+       \r
+       public void setWorldPosition(Vector3d position);\r
+       public void setWorldOrientation(Quat4d orientation);\r
+       \r
+       \r
+       \r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/scenegraph/NodeHighlighter.java b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/NodeHighlighter.java
new file mode 100644 (file)
index 0000000..155813c
--- /dev/null
@@ -0,0 +1,10 @@
+package org.simantics.g3d.scenegraph;\r
+\r
+\r
+public interface NodeHighlighter {\r
+       \r
+       public static enum HighlightObjectType{Actor, Node};\r
+       public static enum HighlightEventType{Selection, Hover, ClearSelection, ClearHover};\r
+\r
+       public void highlight(HighlightEventType type);\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/scenegraph/NodeMap.java b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/NodeMap.java
new file mode 100644 (file)
index 0000000..d4f12da
--- /dev/null
@@ -0,0 +1,48 @@
+package org.simantics.g3d.scenegraph;\r
+\r
+import java.util.Collection;\r
+\r
+import org.simantics.g3d.scenegraph.base.INode;\r
+import org.simantics.g3d.scenegraph.base.NodeListener;\r
+import org.simantics.g3d.scenegraph.base.ParentNode;\r
+\r
+public interface NodeMap<T> {\r
+\r
+       public Collection<T> getRenderObjects(INode node);\r
+       \r
+       public void updateRenderObjectsFor(INode node);\r
+       \r
+       public INode getNode(T t);\r
+       \r
+       public ParentNode<IG3DNode> getRootNode();\r
+       \r
+       /**\r
+        * Commit changes to the database.\r
+        */\r
+       public void commit();\r
+       \r
+       \r
+       /**\r
+        * Deletes (Disposes) the map. \r
+        */\r
+       public void delete();\r
+       \r
+       \r
+       /**\r
+        * Track changes that are going to be committed into the database.\r
+        * \r
+        * Disabling change tracking causes commit() to do nothing. \r
+        * @param enabled\r
+        */\r
+       public void setChangeTracking(boolean enabled);\r
+       public boolean  isChangeTracking();\r
+       \r
+       \r
+       /**\r
+        * Add listener for all scene-graph events.\r
+        * @param listener\r
+        */\r
+       public void addListener(NodeListener listener);\r
+       \r
+       public void removeListener(NodeListener listener);\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/scenegraph/NodeMapProvider.java b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/NodeMapProvider.java
new file mode 100644 (file)
index 0000000..f44701e
--- /dev/null
@@ -0,0 +1,6 @@
+package org.simantics.g3d.scenegraph;\r
+\r
+public interface NodeMapProvider<T> {\r
+\r
+       public NodeMap<T> getNodeMap();\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/scenegraph/RenderListener.java b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/RenderListener.java
new file mode 100644 (file)
index 0000000..af997a0
--- /dev/null
@@ -0,0 +1,6 @@
+package org.simantics.g3d.scenegraph;\r
+\r
+public interface RenderListener {\r
+       public void preRender();\r
+       public void postRender();\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/scenegraph/base/INode.java b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/base/INode.java
new file mode 100644 (file)
index 0000000..dc03564
--- /dev/null
@@ -0,0 +1,55 @@
+package org.simantics.g3d.scenegraph.base;\r
+\r
+import java.util.List;\r
+\r
+\r
+\r
+\r
+\r
+public interface INode {\r
+       \r
+       /**\r
+     * \r
+     * @return unique node identifier\r
+     */\r
+    public Long getId();\r
+\r
+        /**\r
+     * @return root node of the scene graph or <code>null</code> if this node is\r
+     *         not part of a properly rooted scene graph hierarchy\r
+     */\r
+    public ParentNode<?> getRootNode();\r
+\r
+    /**\r
+     * @return Parent node reference or <code>null</code> if not set\r
+     */\r
+    public ParentNode<?> getParent();\r
+    \r
+    public String getParentRel();\r
+    /**\r
+     * Set parent node. This method is for scene graph internal use only and\r
+     * should not be called outside the scene graph structure. This method\r
+     * simply sets the parent node parent field, and does not affect on parent\r
+     * node (i.e., should be called only from parent node).\r
+     */\r
+    public void setParent(ParentNode<?> parent, String name);\r
+\r
+    /**\r
+     * Perform cleanup for this node and for the child nodes. Any resources\r
+     * (including child nodes) related to this node are unusable after this\r
+     * operation. This method is for scene graph internal use only, thus should\r
+     * not be called outside the scene graph structure.\r
+     */\r
+    public void cleanup();\r
+    /**\r
+     * Remove this node and its children from the scene graph.\r
+     */\r
+    public void remove();\r
+\r
+    \r
+    public void addListener(NodeListener listener);\r
+       public void removeListener(NodeListener listener);\r
+       \r
+       public List<NodeListener> getListeners();\r
+\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/scenegraph/base/Node.java b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/base/Node.java
new file mode 100644 (file)
index 0000000..f2b9fe0
--- /dev/null
@@ -0,0 +1,88 @@
+package org.simantics.g3d.scenegraph.base;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+\r
+public abstract class Node implements INode {\r
+       public transient static long               IDCOUNTER              = 1;\r
+       protected transient ParentNode<?>          parent                 = null;\r
+       protected transient String                                 parentName                     = null; \r
+       protected Long                             id                     = IDCOUNTER++;\r
+       \r
+\r
+    public Long getId() {\r
+        return id;\r
+    }\r
+\r
+\r
+    public ParentNode<?> getParent() {\r
+        return parent;\r
+    }\r
+\r
+    \r
+    @Override\r
+    public String getParentRel() {\r
+       return parentName;\r
+    }\r
+    \r
+    public void setParent(ParentNode<?> parent, String name) {\r
+        this.parent = parent;\r
+        this.parentName = name;\r
+    }\r
+    \r
+    public ParentNode<?> getRootNode() {\r
+        return parent != null ? parent.getRootNode() : null;\r
+    }\r
+    \r
+    public void remove() {\r
+        if (parent != null) {\r
+            parent.removeNode(parentName, this);\r
+        }\r
+    }\r
+    \r
+    public void deattach() {\r
+        if (parent != null) {\r
+            parent.deattachNode(parentName, this);\r
+        }\r
+    }\r
+    \r
+    public void init() {\r
+    }\r
+    \r
+    public void cleanup() {\r
+       if (parent != null) {\r
+            parent.removeNode(parentName, this);\r
+        }\r
+    }\r
+    \r
+    @Override\r
+       public String toString() {\r
+               return getClass().getSimpleName();\r
+       }\r
+    \r
+    protected List<NodeListener> listeners = new ArrayList<NodeListener>();\r
+       \r
+       @Override\r
+       public void addListener(NodeListener listener) {\r
+               if (!listeners.contains(listener))\r
+                       listeners.add(listener);\r
+       }\r
+       \r
+       @Override\r
+       public void removeListener(NodeListener listener) {\r
+               listeners.remove(listener);\r
+       }\r
+       \r
+       @Override\r
+       public List<NodeListener> getListeners() {\r
+               return listeners;\r
+       }\r
+       \r
+       protected void firePropertyChanged(String id) {\r
+               for (NodeListener listener : listeners) {\r
+                       listener.propertyChanged(this, id);\r
+               }\r
+       }\r
+    \r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/scenegraph/base/NodeException.java b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/base/NodeException.java
new file mode 100644 (file)
index 0000000..409a989
--- /dev/null
@@ -0,0 +1,14 @@
+package org.simantics.g3d.scenegraph.base;\r
+\r
+public class NodeException extends RuntimeException{\r
+\r
+       private static final long serialVersionUID = -6067907301659268L;\r
+\r
+       public NodeException(String message) {\r
+               super(message);\r
+       }\r
+\r
+       public NodeException(String message, Exception e) {\r
+               super(message,e);\r
+       }\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/scenegraph/base/NodeListener.java b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/base/NodeListener.java
new file mode 100644 (file)
index 0000000..8131608
--- /dev/null
@@ -0,0 +1,29 @@
+package org.simantics.g3d.scenegraph.base;\r
+\r
+\r
+public interface NodeListener {\r
+\r
+       /**\r
+        * Event occurring when a node's property is changed\r
+        * @param node\r
+        * @param child\r
+        * @param rel\r
+        */\r
+       public void propertyChanged(INode node, String id);\r
+       \r
+       /**\r
+        * Event occurring when a new node is added to the scene-graph\r
+        * @param node\r
+        * @param child\r
+        * @param rel\r
+        */\r
+       public <T extends INode> void nodeAdded(ParentNode<T> node, INode child, String rel);\r
+       \r
+       /**\r
+        * Event occurring when a node is removed from the scene-graph\r
+        * @param nodeThe node, which contained the removed node.\r
+        * @param child The removed node.\r
+        * @param rel \r
+        */\r
+       public <T extends INode> void nodeRemoved(ParentNode<T> node, INode child, String rel);\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/scenegraph/base/ParentNode.java b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/base/ParentNode.java
new file mode 100644 (file)
index 0000000..6811217
--- /dev/null
@@ -0,0 +1,153 @@
+package org.simantics.g3d.scenegraph.base;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.List;\r
+\r
+import org.simantics.utils.datastructures.MapList;\r
+\r
+public abstract class ParentNode<T extends INode> extends Node {\r
+\r
+       private MapList<String, T> children = new MapList<String, T>();\r
+\r
+       public synchronized void addNode(String relName, T child) {\r
+               if (child.getParent() != null)\r
+                       child.getParent().removeNode(child.getParentRel(), child);\r
+\r
+               child.setParent(this, relName);\r
+               children.add(relName, (T) child);\r
+\r
+               childrenChanged();\r
+               fireNodeAdded(child, relName);\r
+       }\r
+\r
+       /**\r
+        * Removes child node and it's hierarchy.\r
+        * @param relName\r
+        * @param child\r
+        * @return\r
+        */\r
+       @SuppressWarnings("unchecked")\r
+       public synchronized final boolean removeNode(String relName, INode child) {\r
+               if (children.remove(relName, (T) child)) {\r
+                       fireNodeRemoved(child, relName);\r
+                   child.remove();\r
+                       child.setParent(null, null);\r
+                       return true;\r
+               }\r
+               return false;\r
+       }\r
+       \r
+       /**\r
+        * Removes child node. The child nodes hierarchy is left intact.\r
+        * @param relName\r
+        * @param child\r
+        * @return\r
+        */\r
+       @SuppressWarnings("unchecked")\r
+       public synchronized final boolean deattachNode(String relName, INode child) {\r
+               if (children.remove(relName, (T) child)) {\r
+                       fireNodeRemoved(child, relName);\r
+                       child.setParent(null, null);\r
+                       return true;\r
+               }\r
+               return false;\r
+       }\r
+       \r
+       public synchronized final boolean removeNodes(String relName) {\r
+               List<T> nodes = children.getValues(relName);\r
+               for (T child : nodes) {\r
+                       if (children.remove(relName, (T) child)) {\r
+                               fireNodeRemoved(child, relName);\r
+                           child.remove();\r
+                               child.setParent(null, null);\r
+                               \r
+                       }\r
+               }\r
+               return nodes.size() > 0;\r
+       }\r
+\r
+       public synchronized final void removeNodes() {\r
+               synchronized (children) {\r
+                       boolean changed = false;\r
+                       for (String key : children.getKeys()) {\r
+                               for (T child : children.getValues(key)) {\r
+                                       if (child != null) {\r
+                                               changed = true;\r
+                                               if (child instanceof ParentNode<?>) {\r
+                                                       ((ParentNode<?>) child).removeNodes();\r
+                                               }\r
+                                               child.cleanup();\r
+                                               child.setParent(null, null);\r
+                                               // if (propertyChangeListener != null) {\r
+                                               // propertyChangeListener.propertyChange(new\r
+                                               // PropertyChangeEvent(this,\r
+                                               // "children["+child.getId()+"]", child.getClass(),\r
+                                               // NULL)); // "children" is a special field name\r
+                                               // }\r
+                                       }\r
+                               }\r
+                       }\r
+                       children.clear();\r
+                       if (changed)\r
+                               childrenChanged();\r
+               }\r
+       }\r
+\r
+       public synchronized List<T> getNodes(String rel) {\r
+               return children.getValues(rel);\r
+       }\r
+\r
+       public synchronized List<T> getNodes() {\r
+               List<T> result = new ArrayList<T>();\r
+               for (String s : children.getKeys())\r
+                       result.addAll(children.getValues(s));\r
+               return result;\r
+       }\r
+\r
+       protected void childrenChanged() {\r
+       }\r
+\r
+\r
+       @Override\r
+       public void remove() {\r
+               synchronized (children) {\r
+                       List<T> toRemove = new ArrayList<T>();\r
+               \r
+                       for (String key : children.getKeys()) {\r
+               \r
+                               for (T child : children.getValues(key)) {\r
+                                       if (child != null) {\r
+                                               toRemove.add(child);\r
+                                       }\r
+                               }\r
+                       }\r
+\r
+                       for (T n : toRemove) {\r
+                               n.remove();\r
+                       }\r
+                       \r
+                       children.clear();\r
+                       if (toRemove.size() > 0)\r
+                               childrenChanged();\r
+                       super.remove();\r
+                       \r
+               }\r
+       }\r
+       \r
+       \r
+       \r
+       \r
+       protected void fireNodeAdded(INode node, String rel) {\r
+               for (NodeListener listener : listeners) {\r
+                       listener.nodeAdded(this, node, rel);\r
+               }\r
+       }\r
+       \r
+       protected void fireNodeRemoved(INode node, String rel) {\r
+               for (NodeListener listener : listeners) {\r
+                       listener.nodeRemoved(this, node, rel);\r
+               }\r
+       }\r
+       \r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/scenegraph/structural/ComponentNode.java b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/structural/ComponentNode.java
new file mode 100644 (file)
index 0000000..0cbdddd
--- /dev/null
@@ -0,0 +1,259 @@
+package org.simantics.g3d.scenegraph.structural;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.Collections;\r
+import java.util.List;\r
+\r
+import org.simantics.g3d.ontology.G3D;\r
+import org.simantics.g3d.property.annotations.GetPropertyValue;\r
+import org.simantics.g3d.property.annotations.SetPropertyValue;\r
+import org.simantics.g3d.scenegraph.base.Node;\r
+import org.simantics.layer0.Layer0;\r
+import org.simantics.objmap.graph.annotations.RelatedGetValue;\r
+import org.simantics.objmap.graph.annotations.RelatedSetValue;\r
+import org.simantics.objmap.structural.IStructuralObject;\r
+import org.simantics.utils.datastructures.MapList;\r
+\r
+public abstract class ComponentNode<T extends Connection, T2 extends IComponentNode> extends Node implements IComponentNode<T, T2>{\r
+\r
+       \r
+       private String name;\r
+       \r
+\r
+       @RelatedGetValue(Layer0.URIs.HasName)\r
+       @GetPropertyValue(value = Layer0.URIs.HasName, tabId = "Default", name = "Name")\r
+       public String getName() {\r
+               return name;\r
+       }\r
+       \r
+       @RelatedSetValue(Layer0.URIs.HasName)\r
+       @SetPropertyValue(Layer0.URIs.HasName)\r
+       public void setName(String name) {\r
+               if (name == null)\r
+                       return;\r
+               this.name = name;\r
+               firePropertyChanged(Layer0.URIs.HasName);\r
+       }\r
+       \r
+       @Override\r
+       public String toString() {\r
+               return getName();\r
+       }\r
+       \r
+       public boolean isPartOfInstantiatedModel() {\r
+               return ctx.size() > 0;\r
+       }\r
+       \r
+       public boolean isExposed() {\r
+               if (ctx.size() == 0)\r
+                       return true;\r
+               return getPublishedBy().contains(ctx.get(0));\r
+       }\r
+       \r
+       @Override\r
+       public boolean isInstantiatedModelRoot() {\r
+               return ctx.size() == 1 && this.equals(ctx.get(0));\r
+       }\r
+       \r
+       @Override\r
+       public boolean isPublishable() {\r
+               return !isPartOfInstantiatedModel();\r
+       }\r
+       \r
+       private List<IStructuralObject> ctx = new ArrayList<IStructuralObject>(1);\r
+       @Override\r
+       public List<IStructuralObject> getContext() {\r
+               return ctx;\r
+       }\r
+       \r
+       @Override\r
+       public void setContext(List<IStructuralObject> object) {\r
+               ctx = object;\r
+       }\r
+       \r
+       private List<IStructuralNode> publisher = new ArrayList<IStructuralNode>(1);\r
+       \r
+       \r
+       \r
+       protected abstract boolean isValidConnectionId(String id);\r
+       \r
+       @Override\r
+       public void connectionChanged(T c, T2 node, boolean add) {\r
+               \r
+       }\r
+       \r
+       @Override\r
+       public void addPublishedBy(IStructuralNode node) {\r
+               publisher.add(node);\r
+               firePropertyChanged(G3D.URIs.publishes);\r
+       }\r
+       \r
+       @Override\r
+       public Collection<IStructuralNode> getPublishedBy() {\r
+               return publisher;\r
+       }\r
+       \r
+       @Override\r
+       public void removePublishedBy(IStructuralNode node) {\r
+               if (publisher.remove(node))\r
+                       firePropertyChanged(G3D.URIs.publishes);\r
+       }\r
+       \r
+       \r
+       @Override\r
+       public List<T> getConnections(String id) {\r
+               List<T> list = new ArrayList<T>();\r
+               list.addAll(connections.getValues(id));\r
+               list.addAll(connections.getValues(id+"/str"));\r
+               return list;\r
+       }       \r
+       \r
+       public List<T2> getAllConnectedNodes() {\r
+               List<T2> list = new ArrayList<T2>();\r
+               for (T c : getAllConnections()) {\r
+                       T2 node = (T2)c.getOther(this);\r
+                       if (node != null)\r
+                               list.add(node);\r
+               }\r
+               return list;\r
+       }\r
+       \r
+    \r
+    @Override\r
+    public void addConnection(String id, T c) {\r
+       assert(isValidConnectionId(id));\r
+       if (!isPartOfInstantiatedModel())\r
+               _addConnection(id, c);\r
+       else\r
+               _addConnection(id+"/str", c);\r
+    }\r
+    \r
+    @Override\r
+    public void removeConnection(String id, T c) {\r
+       assert(isValidConnectionId(id));\r
+       if (!isPartOfInstantiatedModel())\r
+               _removeConnection(id, c);\r
+       else\r
+               _removeConnection(id+"/str", c);\r
+    }\r
+    \r
+    @Override\r
+    public void removeConnection(String id) {\r
+       assert(isValidConnectionId(id));\r
+       if (!isPartOfInstantiatedModel())\r
+               _removeConnection(id);\r
+       else\r
+               _removeConnection(id+"/str");\r
+    }\r
+       \r
+       private MapList<String, T> connections = new MapList<String, T>();\r
+       \r
+       \r
+       protected void _addConnection(String id, T c) {\r
+               connections.add(id, c);\r
+               c.addConnect(this);\r
+               firePropertyChanged(id);\r
+       }\r
+       \r
+       protected void _addStrConnection(String id, T c) {\r
+               _addConnection(id+"/str", c);\r
+       }\r
+       \r
+       protected  MapList<String, T> _getConnections() {\r
+               return connections;\r
+       }\r
+       \r
+       protected  List<T> _getConnections(String id) {\r
+               return connections.getValues(id);\r
+       }\r
+       \r
+       protected  List<T> _getStrConnections(String id) {\r
+               return _getConnections(id+"/str");\r
+       }\r
+       \r
+       protected void _removeConnection(String id, T c) {\r
+               if (connections.remove(id, c)) {\r
+                       c.remove();\r
+                       firePropertyChanged(id);\r
+               }\r
+       }\r
+       \r
+       protected void _removeConnection(String id) {\r
+               List<T> conns = new ArrayList<T>();\r
+               conns.addAll(_getConnections(id));\r
+               for (T c : conns) {\r
+                       _removeConnection(id, c);\r
+               }\r
+       }\r
+       \r
+       protected void _removeStrConnection(String id, T c) {\r
+               _removeConnection(id+"/str", c);\r
+       }\r
+       \r
+       public List<T> getAllConnections() {\r
+               List<T> list = new ArrayList<T>();\r
+               List<String> keys = new ArrayList<String>();\r
+               keys.addAll(connections.getKeys());\r
+               Collections.sort(keys);\r
+               for (String s : keys)\r
+                       list.addAll(connections.getValues(s));\r
+               return list;\r
+       }\r
+       \r
+       public void removeConnection(T c) {\r
+               String keys[] = connections.getKeys(new String[connections.getKeySize()]);\r
+               for (String s : keys) {\r
+                       if (connections.contains(s, c))\r
+                               _removeConnection(s, c);\r
+               }\r
+       }\r
+       \r
+       public List<T2> getConnectedNodes(String id) {\r
+               List<T2> list = new ArrayList<T2>();\r
+               for (T c : getConnections(id)) {\r
+                       T2 node = (T2)c.getOther(this);\r
+                       if (node != null)\r
+                               list.add(node);\r
+               }\r
+               return list;\r
+       }\r
+       \r
+       @Override\r
+       public String getConnectionId(T c) {\r
+               for (String s : connections.getKeys()) {\r
+                       if (connections.contains(s, c)) {\r
+                               if (!s.endsWith("/str"))\r
+                                       return s;\r
+                               return s.substring(0, s.length()-4);\r
+                       }\r
+               }\r
+               return null;\r
+       }\r
+       \r
+       @Override\r
+       public Collection<String> getConnectionIds(T2 node) {\r
+               Collection<String> ids = new ArrayList<String>();\r
+               for (String s : connections.getKeys()) {\r
+                       for (T c : connections.getValues(s)) {\r
+                               if (node.equals(c.getOther(this))) {\r
+                                       if (!s.endsWith("/str"))\r
+                                               ids.add(s);\r
+                                       else\r
+                                               ids.add(s.substring(0, s.length()-4));\r
+                               }\r
+                       }\r
+               }\r
+               return ids;\r
+       }\r
+       \r
+       @Override\r
+       public void remove() {\r
+               List<T> connections = getAllConnections();\r
+               for (T c : connections) {\r
+                       removeConnection(c);\r
+               }\r
+               super.remove();\r
+       \r
+       }\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/scenegraph/structural/Connection.java b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/structural/Connection.java
new file mode 100644 (file)
index 0000000..9f96205
--- /dev/null
@@ -0,0 +1,76 @@
+package org.simantics.g3d.scenegraph.structural;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.List;\r
+\r
+import org.simantics.db.Resource;\r
+import org.simantics.objmap.structural.IStructuralObject;\r
+\r
+@SuppressWarnings("rawtypes")\r
+public abstract class  Connection <T extends IComponentNode> implements IStructuralObject{\r
+\r
+       \r
+       private List<T> connects = new ArrayList<T>();\r
+       \r
+       \r
+       public void addConnect(T node) {\r
+               if (!connects.contains(node))\r
+                       connects.add(node);\r
+               fireChanged(node,true);\r
+       }\r
+       \r
+       protected void fireChanged(T node, boolean add){\r
+               for (IComponentNode n : connects) {\r
+                       n.connectionChanged(this,node,add);\r
+               }\r
+       }\r
+       \r
+       public Collection<T> getConnected() {\r
+               return connects;\r
+       }\r
+       \r
+       public void removeConnect(T node) {\r
+               connects.remove(node);\r
+               fireChanged(node,false);\r
+       }\r
+       \r
+       public void remove() {\r
+               List<T> toRemove = new ArrayList<T>(connects.size());\r
+               toRemove.addAll(connects);\r
+               for (IComponentNode node : toRemove) {\r
+                       node.removeConnection(this);\r
+               }\r
+       }\r
+       \r
+       public T getOther(T node) {\r
+               if (connects.size() != 2) \r
+                       return null;\r
+               if (connects.get(0).equals(node))\r
+                       return connects.get(1);\r
+               else if (connects.get(1).equals(node))\r
+                       return connects.get(0);\r
+               return null;\r
+       }\r
+       \r
+       @Override\r
+       public void setType(Resource type) {\r
+               \r
+       }\r
+       \r
+       @Override\r
+       public Resource getType() {\r
+               return null;\r
+       }\r
+       \r
+       private List<IStructuralObject> ctx = new ArrayList<IStructuralObject>(1);\r
+       @Override\r
+       public List<IStructuralObject> getContext() {\r
+               return ctx;\r
+       }\r
+       \r
+       @Override\r
+       public void setContext(List<IStructuralObject> object) {\r
+               ctx = object;\r
+       }\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/scenegraph/structural/G3DComponentNode.java b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/structural/G3DComponentNode.java
new file mode 100644 (file)
index 0000000..d9a6777
--- /dev/null
@@ -0,0 +1,259 @@
+package org.simantics.g3d.scenegraph.structural;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.Collections;\r
+import java.util.List;\r
+\r
+import org.simantics.g3d.ontology.G3D;\r
+import org.simantics.g3d.property.annotations.GetPropertyValue;\r
+import org.simantics.g3d.property.annotations.SetPropertyValue;\r
+import org.simantics.g3d.scenegraph.G3DNode;\r
+import org.simantics.layer0.Layer0;\r
+import org.simantics.objmap.graph.annotations.RelatedGetValue;\r
+import org.simantics.objmap.graph.annotations.RelatedSetValue;\r
+import org.simantics.objmap.structural.IStructuralObject;\r
+import org.simantics.utils.datastructures.MapList;\r
+\r
+public abstract class G3DComponentNode<T extends Connection, T2 extends IComponentNode> extends G3DNode implements IComponentNode<T, T2>{\r
+\r
+       \r
+       private String name;\r
+       \r
+\r
+       @RelatedGetValue(Layer0.URIs.HasName)\r
+       @GetPropertyValue(value = Layer0.URIs.HasName, tabId = "Default", name = "Name")\r
+       public String getName() {\r
+               return name;\r
+       }\r
+       \r
+       @RelatedSetValue(Layer0.URIs.HasName)\r
+       @SetPropertyValue(Layer0.URIs.HasName)\r
+       public void setName(String name) {\r
+               if (name == null)\r
+                       return;\r
+               this.name = name;\r
+               firePropertyChanged(Layer0.URIs.HasName);\r
+       }\r
+       \r
+       @Override\r
+       public String toString() {\r
+               return getName();\r
+       }\r
+       \r
+       public boolean isPartOfInstantiatedModel() {\r
+               return ctx.size() > 0;\r
+       }\r
+       \r
+       public boolean isExposed() {\r
+               if (ctx.size() == 0)\r
+                       return true;\r
+               return getPublishedBy().contains(ctx.get(0));\r
+       }\r
+       \r
+       @Override\r
+       public boolean isInstantiatedModelRoot() {\r
+               return ctx.size() == 1 && this.equals(ctx.get(0));\r
+       }\r
+       \r
+       @Override\r
+       public boolean isPublishable() {\r
+               return !isPartOfInstantiatedModel();\r
+       }\r
+       \r
+       private List<IStructuralObject> ctx = new ArrayList<IStructuralObject>(1);\r
+       @Override\r
+       public List<IStructuralObject> getContext() {\r
+               return ctx;\r
+       }\r
+       \r
+       @Override\r
+       public void setContext(List<IStructuralObject> object) {\r
+               ctx = object;\r
+       }\r
+       \r
+       private List<IStructuralNode> publisher = new ArrayList<IStructuralNode>(1);\r
+       \r
+       \r
+       \r
+       protected abstract boolean isValidConnectionId(String id);\r
+       \r
+       @Override\r
+       public void connectionChanged(T c, T2 node, boolean add) {\r
+               \r
+       }\r
+       \r
+       @Override\r
+       public void addPublishedBy(IStructuralNode node) {\r
+               publisher.add(node);\r
+               firePropertyChanged(G3D.URIs.publishes);\r
+       }\r
+       \r
+       @Override\r
+       public Collection<IStructuralNode> getPublishedBy() {\r
+               return publisher;\r
+       }\r
+       \r
+       @Override\r
+       public void removePublishedBy(IStructuralNode node) {\r
+               if (publisher.remove(node))\r
+                       firePropertyChanged(G3D.URIs.publishes);\r
+       }\r
+       \r
+       \r
+       @Override\r
+       public List<T> getConnections(String id) {\r
+               List<T> list = new ArrayList<T>();\r
+               list.addAll(connections.getValues(id));\r
+               list.addAll(connections.getValues(id+"/str"));\r
+               return list;\r
+       }       \r
+       \r
+       public List<T2> getAllConnectedNodes() {\r
+               List<T2> list = new ArrayList<T2>();\r
+               for (T c : getAllConnections()) {\r
+                       T2 node = (T2)c.getOther(this);\r
+                       if (node != null)\r
+                               list.add(node);\r
+               }\r
+               return list;\r
+       }\r
+       \r
+    \r
+    @Override\r
+    public void addConnection(String id, T c) {\r
+       assert(isValidConnectionId(id));\r
+       if (!isPartOfInstantiatedModel())\r
+               _addConnection(id, c);\r
+       else\r
+               _addConnection(id+"/str", c);\r
+    }\r
+    \r
+    @Override\r
+    public void removeConnection(String id, T c) {\r
+       assert(isValidConnectionId(id));\r
+       if (!isPartOfInstantiatedModel())\r
+               _removeConnection(id, c);\r
+       else\r
+               _removeConnection(id+"/str", c);\r
+    }\r
+    \r
+    @Override\r
+    public void removeConnection(String id) {\r
+       assert(isValidConnectionId(id));\r
+       if (!isPartOfInstantiatedModel())\r
+               _removeConnection(id);\r
+       else\r
+               _removeConnection(id+"/str");\r
+    }\r
+       \r
+       private MapList<String, T> connections = new MapList<String, T>();\r
+       \r
+       \r
+       protected void _addConnection(String id, T c) {\r
+               connections.add(id, c);\r
+               c.addConnect(this);\r
+               firePropertyChanged(id);\r
+       }\r
+       \r
+       protected void _addStrConnection(String id, T c) {\r
+               _addConnection(id+"/str", c);\r
+       }\r
+       \r
+       protected  MapList<String, T> _getConnections() {\r
+               return connections;\r
+       }\r
+       \r
+       protected  List<T> _getConnections(String id) {\r
+               return connections.getValues(id);\r
+       }\r
+       \r
+       protected  List<T> _getStrConnections(String id) {\r
+               return _getConnections(id+"/str");\r
+       }\r
+       \r
+       protected void _removeConnection(String id, T c) {\r
+               if (connections.remove(id, c)) {\r
+                       c.remove();\r
+                       firePropertyChanged(id);\r
+               }\r
+       }\r
+       \r
+       protected void _removeConnection(String id) {\r
+               List<T> conns = new ArrayList<T>();\r
+               conns.addAll(_getConnections(id));\r
+               for (T c : conns) {\r
+                       _removeConnection(id, c);\r
+               }\r
+       }\r
+       \r
+       protected void _removeStrConnection(String id, T c) {\r
+               _removeConnection(id+"/str", c);\r
+       }\r
+       \r
+       public List<T> getAllConnections() {\r
+               List<T> list = new ArrayList<T>();\r
+               List<String> keys = new ArrayList<String>();\r
+               keys.addAll(connections.getKeys());\r
+               Collections.sort(keys);\r
+               for (String s : keys)\r
+                       list.addAll(connections.getValues(s));\r
+               return list;\r
+       }\r
+       \r
+       public void removeConnection(T c) {\r
+               String keys[] = connections.getKeys(new String[connections.getKeySize()]);\r
+               for (String s : keys) {\r
+                       if (connections.contains(s, c))\r
+                               _removeConnection(s, c);\r
+               }\r
+       }\r
+       \r
+       public List<T2> getConnectedNodes(String id) {\r
+               List<T2> list = new ArrayList<T2>();\r
+               for (T c : getConnections(id)) {\r
+                       T2 node = (T2)c.getOther(this);\r
+                       if (node != null)\r
+                               list.add(node);\r
+               }\r
+               return list;\r
+       }\r
+       \r
+       @Override\r
+       public String getConnectionId(T c) {\r
+               for (String s : connections.getKeys()) {\r
+                       if (connections.contains(s, c)) {\r
+                               if (!s.endsWith("/str"))\r
+                                       return s;\r
+                               return s.substring(0, s.length()-4);\r
+                       }\r
+               }\r
+               return null;\r
+       }\r
+       \r
+       @Override\r
+       public Collection<String> getConnectionIds(T2 node) {\r
+               Collection<String> ids = new ArrayList<String>();\r
+               for (String s : connections.getKeys()) {\r
+                       for (T c : connections.getValues(s)) {\r
+                               if (node.equals(c.getOther(this))) {\r
+                                       if (!s.endsWith("/str"))\r
+                                               ids.add(s);\r
+                                       else\r
+                                               ids.add(s.substring(0, s.length()-4));\r
+                               }\r
+                       }\r
+               }\r
+               return ids;\r
+       }\r
+       \r
+       @Override\r
+       public void remove() {\r
+               List<T> connections = getAllConnections();\r
+               for (T c : connections) {\r
+                       removeConnection(c);\r
+               }\r
+               super.remove();\r
+       \r
+       }\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/scenegraph/structural/G3DStructuralParentNode.java b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/structural/G3DStructuralParentNode.java
new file mode 100644 (file)
index 0000000..7a99b8c
--- /dev/null
@@ -0,0 +1,171 @@
+package org.simantics.g3d.scenegraph.structural;\r
+\r
+import java.util.Collection;\r
+\r
+import javax.vecmath.Quat4d;\r
+import javax.vecmath.Vector3d;\r
+\r
+import org.simantics.g3d.math.MathTools;\r
+import org.simantics.g3d.ontology.G3D;\r
+import org.simantics.g3d.property.annotations.GetPropertyValue;\r
+import org.simantics.g3d.property.annotations.SetPropertyValue;\r
+import org.simantics.g3d.scenegraph.IG3DNode;\r
+import org.simantics.g3d.scenegraph.base.INode;\r
+import org.simantics.g3d.scenegraph.base.NodeException;\r
+import org.simantics.g3d.tools.NodeTools;\r
+import org.simantics.objmap.graph.annotations.RelatedGetValue;\r
+import org.simantics.objmap.graph.annotations.RelatedSetValue;\r
+\r
+public abstract class G3DStructuralParentNode<T extends IStructuralNode> extends StructuralParentNode<T> implements IG3DNode{\r
+       private Vector3d position = new Vector3d();\r
+       private Quat4d orientation = MathTools.getIdentityQuat();\r
+       \r
+\r
+       @GetPropertyValue(value = G3D.URIs.hasOrientation, tabId = "Transform", name = "Orientation")\r
+       public Quat4d getOrientation() {\r
+               if (getParent() == null)\r
+                       return MathTools.getIdentityQuat();\r
+               return orientation;\r
+       };\r
+       \r
+       @Override\r
+       @GetPropertyValue(value = G3D.URIs.hasPosition, tabId = "Transform", name = "Position")\r
+       public Vector3d getPosition() {\r
+               if (getParent() == null)\r
+                       return MathTools.ORIGIN;\r
+               return position;\r
+       }\r
+       \r
+       @Override\r
+       @GetPropertyValue(value = G3D.URIs.hasWorldOrientation, tabId = "Transform", name = "World Orientation")\r
+       public Quat4d getWorldOrientation() {\r
+               if (getParent() == null)\r
+                       return MathTools.getIdentityQuat();\r
+               return getWorldOrientation(orientation);\r
+       }\r
+       \r
+       @Override\r
+       @GetPropertyValue(value = G3D.URIs.hasWorldPosition, tabId = "Transform", name = "World Position")\r
+       public Vector3d getWorldPosition() {\r
+               IG3DNode parent = (IG3DNode)getParent();\r
+               if (parent == null)\r
+                       return MathTools.ORIGIN;\r
+               return NodeTools.getWorldPosition(parent, new Vector3d(position));\r
+       }\r
+       \r
+       @Override\r
+       public Quat4d getWorldOrientation(Quat4d localOrientation) {\r
+               IG3DNode parent = (IG3DNode)getParent();\r
+               if (parent == null)\r
+                       return localOrientation;\r
+               return NodeTools.getWorldOrientation(parent, localOrientation);\r
+       }\r
+       \r
+       \r
+       public Vector3d getWorldPosition(Vector3d localPosition) {\r
+               return NodeTools.getWorldPosition(this,localPosition);\r
+       }\r
+       \r
+       @Override\r
+       public Quat4d getLocalOrientation(Quat4d worldOrientation) {\r
+               IG3DNode parent = (IG3DNode)getParent();\r
+               if (parent == null)\r
+                       return worldOrientation;\r
+               return NodeTools.getLocalOrientation(parent, new Quat4d(worldOrientation));\r
+       }\r
+       \r
+       @Override\r
+       public Vector3d getLocalPosition(Vector3d worldPosition) {\r
+               IG3DNode parent = (IG3DNode)getParent();\r
+               if (parent == null)\r
+                       return worldPosition;\r
+               return NodeTools.getLocalPosition(parent,new Vector3d(worldPosition));\r
+       }\r
+       \r
+       @Override\r
+       @SetPropertyValue(G3D.URIs.hasPosition)\r
+       public void setPosition(Vector3d position) {\r
+               this.position = position;\r
+               firePropertyChanged(G3D.URIs.hasPosition);\r
+       }\r
+       \r
+       @Override\r
+       @SetPropertyValue(G3D.URIs.hasOrientation)\r
+       public void setOrientation(Quat4d orientation) {\r
+               this.orientation = orientation;\r
+               firePropertyChanged(G3D.URIs.hasOrientation);\r
+       }\r
+       \r
+       @Override\r
+       @SetPropertyValue(G3D.URIs.hasWorldOrientation)\r
+       public void setWorldOrientation(Quat4d orientation) {\r
+               if (getParent() == null)\r
+                       throw new NodeException("Cannot set root node orientation");\r
+               Quat4d localOr = getLocalOrientation(orientation);\r
+               setOrientation(localOr);\r
+       }\r
+       \r
+       @Override\r
+       @SetPropertyValue(G3D.URIs.hasWorldPosition)\r
+       public void setWorldPosition(Vector3d position) {\r
+               if (getParent() == null)\r
+                       throw new NodeException("Cannot set root node position");\r
+               Vector3d localPos = getLocalPosition(position);\r
+               setPosition(localPos);\r
+       }\r
+       \r
+       \r
+       \r
+       @RelatedGetValue(G3D.URIs.hasOrientation)\r
+       public double[] getOrientationArr() {\r
+               double arr[] = new double[4];\r
+               orientation.get(arr);\r
+               return arr;\r
+               \r
+       }\r
+       \r
+       @RelatedGetValue(G3D.URIs.hasPosition)\r
+       public double[] getPositionArr() {\r
+               double arr[] = new double[3];\r
+               position.get(arr);\r
+               return arr;\r
+       }\r
+       \r
+       @RelatedSetValue(G3D.URIs.hasOrientation)\r
+       public void setOrientation(double[] arr) {\r
+               if (arr == null)\r
+                       return;\r
+               setOrientation(new Quat4d(arr));\r
+       }\r
+       \r
+       @RelatedSetValue(G3D.URIs.hasPosition)\r
+       public void setPosition(double[] arr) {\r
+               if (arr == null)\r
+                       return;\r
+               setPosition(new Vector3d(arr));\r
+       }\r
+       \r
+       \r
+       protected void _addStrNode(String id, T child) {\r
+               addNode(id+"/str", child);\r
+       }\r
+       \r
+       protected boolean _removeStrNode(String id, T child) {\r
+               return removeNode(id+"/str", child);\r
+       }\r
+       \r
+       protected Collection<T> _getStrNodes(String id) {\r
+               return getNodes(id+"/str");\r
+       }\r
+       \r
+       public Object getAdapter(Class adapter) {\r
+               if (INode.class == adapter)\r
+                       return this;\r
+               if (IG3DNode.class == adapter)\r
+                       return this;\r
+               return null;\r
+       }\r
+       \r
+       \r
+       \r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/scenegraph/structural/IComponentNode.java b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/structural/IComponentNode.java
new file mode 100644 (file)
index 0000000..ac482b1
--- /dev/null
@@ -0,0 +1,25 @@
+package org.simantics.g3d.scenegraph.structural;\r
+\r
+import java.util.Collection;\r
+import java.util.List;\r
+\r
+\r
+@SuppressWarnings("rawtypes")\r
+public interface IComponentNode<T extends Connection, T2 extends IComponentNode> extends IStructuralNode{\r
+       \r
+       public List<T> getAllConnections();\r
+       //public void addConnection(Connection c);\r
+       public void removeConnection(T c);\r
+       public void connectionChanged(T c, T2 node, boolean add);\r
+\r
+       public List<T> getConnections(String id);\r
+       public void addConnection(String id,T c);\r
+       public void removeConnection(String id,T c);\r
+       public void removeConnection(String id);\r
+       \r
+       public String getConnectionId(T c);\r
+       public Collection<String> getConnectionIds(T2 node);\r
+       public List<T2> getAllConnectedNodes();\r
+       public List<T2> getConnectedNodes(String id);\r
+\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/scenegraph/structural/IStructuralNode.java b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/structural/IStructuralNode.java
new file mode 100644 (file)
index 0000000..612ea6d
--- /dev/null
@@ -0,0 +1,22 @@
+package org.simantics.g3d.scenegraph.structural;\r
+\r
+import java.util.Collection;\r
+\r
+import org.simantics.g3d.scenegraph.base.INode;\r
+import org.simantics.objmap.structural.IStructuralObject;\r
+\r
+public interface IStructuralNode extends INode, IStructuralObject {\r
+       \r
+       public String getName();\r
+       \r
+       public boolean isPartOfInstantiatedModel();\r
+       public boolean isExposed();\r
+       public boolean isInstantiatedModelRoot();\r
+       public boolean isPublishable();\r
+       \r
+\r
+\r
+       public Collection<IStructuralNode> getPublishedBy();\r
+       public void addPublishedBy(IStructuralNode node);\r
+       public void removePublishedBy(IStructuralNode node);\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/scenegraph/structural/IStructuralRootNode.java b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/structural/IStructuralRootNode.java
new file mode 100644 (file)
index 0000000..b158993
--- /dev/null
@@ -0,0 +1,43 @@
+package org.simantics.g3d.scenegraph.structural;\r
+\r
+import java.util.Collection;\r
+\r
+import org.simantics.layer0.Layer0;\r
+import org.simantics.objmap.graph.annotations.RelatedElementsAdd;\r
+import org.simantics.objmap.graph.annotations.RelatedElementsGet;\r
+import org.simantics.objmap.graph.annotations.RelatedElementsRem;\r
+import org.simantics.objmap.structural.annotations.TypeRelatedElementsAdd;\r
+import org.simantics.objmap.structural.annotations.TypeRelatedElementsGet;\r
+import org.simantics.objmap.structural.annotations.TypeRelatedElementsRem;\r
+\r
+public interface IStructuralRootNode extends IStructuralNode {\r
+       \r
+       @RelatedElementsAdd(Layer0.URIs.ConsistsOf)\r
+       public void addComponent(IStructuralNode node);\r
+       @RelatedElementsGet(Layer0.URIs.ConsistsOf)\r
+       public Collection<IStructuralNode> getComponent();\r
+       @RelatedElementsRem(Layer0.URIs.ConsistsOf)\r
+       public void removeComponent(IStructuralNode node);\r
+       \r
+       @TypeRelatedElementsAdd(Layer0.URIs.ConsistsOf)\r
+       public void addTypeComponent(IStructuralNode node);\r
+       @TypeRelatedElementsGet(Layer0.URIs.ConsistsOf)\r
+       public Collection<IStructuralNode> getTypeComponent();\r
+       @TypeRelatedElementsRem(Layer0.URIs.ConsistsOf)\r
+       public void removeTypeComponent(IStructuralNode node);\r
+       \r
+       @RelatedElementsAdd(Layer0.URIs.DomainOf)\r
+       public void addPublished(IStructuralNode node);\r
+       @RelatedElementsGet(Layer0.URIs.DomainOf)\r
+       public Collection<IStructuralNode> getPublished();\r
+       @RelatedElementsRem(Layer0.URIs.DomainOf)\r
+       public void removePublished(IStructuralNode node);\r
+       \r
+       @TypeRelatedElementsAdd(Layer0.URIs.DomainOf)\r
+       public void addTypePublished(IStructuralNode node);\r
+       @TypeRelatedElementsGet(Layer0.URIs.DomainOf)\r
+       public Collection<IStructuralNode> getTypePublished();\r
+       @TypeRelatedElementsRem(Layer0.URIs.DomainOf)\r
+       public void removeTypePublished(IStructuralNode node);\r
+\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/scenegraph/structural/StructuralParentNode.java b/org.simantics.g3d/src/org/simantics/g3d/scenegraph/structural/StructuralParentNode.java
new file mode 100644 (file)
index 0000000..d5e41a5
--- /dev/null
@@ -0,0 +1,99 @@
+package org.simantics.g3d.scenegraph.structural;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.List;\r
+\r
+import org.simantics.g3d.ontology.G3D;\r
+import org.simantics.g3d.property.annotations.GetPropertyValue;\r
+import org.simantics.g3d.property.annotations.SetPropertyValue;\r
+import org.simantics.g3d.scenegraph.base.ParentNode;\r
+import org.simantics.layer0.Layer0;\r
+import org.simantics.objmap.graph.annotations.RelatedGetValue;\r
+import org.simantics.objmap.graph.annotations.RelatedSetValue;\r
+import org.simantics.objmap.structural.IStructuralObject;\r
+\r
+public abstract class StructuralParentNode<T extends IStructuralNode> extends ParentNode<T> implements IStructuralNode{\r
+\r
+       private String name;\r
+       \r
+\r
+       @RelatedGetValue(Layer0.URIs.HasName)\r
+       @GetPropertyValue(value = Layer0.URIs.HasName, tabId = "Default", name = "Name")\r
+       public String getName() {\r
+               return name;\r
+       }\r
+       \r
+       @RelatedSetValue(Layer0.URIs.HasName)\r
+       @SetPropertyValue(Layer0.URIs.HasName)\r
+       public void setName(String name) {\r
+               if (name == null)\r
+                       return;\r
+               this.name = name;\r
+               firePropertyChanged(Layer0.URIs.HasName);\r
+       }\r
+       \r
+       @Override\r
+       public String toString() {\r
+               return getName();\r
+       }\r
+       \r
+       public boolean isPartOfInstantiatedModel() {\r
+               return ctx.size() > 0;\r
+       }\r
+       \r
+       public boolean isExposed() {\r
+               if (ctx.size() == 0)\r
+                       return true;\r
+               return getPublishedBy().contains(ctx.get(0));\r
+       }\r
+       \r
+       @Override\r
+       public boolean isInstantiatedModelRoot() {\r
+               return ctx.size() == 1 && this.equals(ctx.get(0));\r
+       }\r
+       \r
+       @Override\r
+       public boolean isPublishable() {\r
+               return !isPartOfInstantiatedModel();\r
+       }\r
+       \r
+       private List<IStructuralObject> ctx = new ArrayList<IStructuralObject>(1);\r
+       @Override\r
+       public List<IStructuralObject> getContext() {\r
+               return ctx;\r
+       }\r
+       \r
+       @Override\r
+       public void setContext(List<IStructuralObject> object) {\r
+               ctx = object;\r
+       }\r
+       \r
+    private List<IStructuralNode> publisher = new ArrayList<IStructuralNode>(1);\r
+       \r
+       @Override\r
+       public void addPublishedBy(IStructuralNode node) {\r
+               publisher.add(node);\r
+               firePropertyChanged(G3D.URIs.publishes);\r
+       }\r
+       \r
+       @Override\r
+       public Collection<IStructuralNode> getPublishedBy() {\r
+               return publisher;\r
+       }\r
+       \r
+       @Override\r
+       public void removePublishedBy(IStructuralNode node) {\r
+               if (publisher.remove(node))\r
+                       firePropertyChanged(G3D.URIs.publishes);\r
+       }\r
+       \r
+       @Override\r
+       public void remove() {\r
+               IStructuralRootNode root = (IStructuralRootNode)getRootNode();\r
+               if (root.getPublished().contains(this))\r
+                       root.removePublished(this);\r
+               \r
+               super.remove();\r
+       }\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/shape/Color4d.java b/org.simantics.g3d/src/org/simantics/g3d/shape/Color4d.java
new file mode 100644 (file)
index 0000000..5578d85
--- /dev/null
@@ -0,0 +1,30 @@
+package org.simantics.g3d.shape;\r
+\r
+import javax.vecmath.Tuple4d;\r
+import javax.vecmath.Tuple4f;\r
+\r
+public class Color4d extends Tuple4d{\r
+\r
+       private static final long serialVersionUID = -4217159803441535837L;\r
+\r
+       public Color4d() {\r
+               super();\r
+       }\r
+\r
+       public Color4d(double x, double y, double z, double w) {\r
+               super(x, y, z, w);\r
+       }\r
+\r
+       public Color4d(double[] t) {\r
+               super(t);\r
+       }\r
+\r
+       public Color4d(Tuple4d t1) {\r
+               super(t1);\r
+       }\r
+\r
+       public Color4d(Tuple4f t1) {\r
+               super(t1);\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/shape/Cone.java b/org.simantics.g3d/src/org/simantics/g3d/shape/Cone.java
new file mode 100644 (file)
index 0000000..19f9200
--- /dev/null
@@ -0,0 +1,64 @@
+package org.simantics.g3d.shape;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import javax.vecmath.AxisAngle4d;\r
+import javax.vecmath.Vector3d;\r
+\r
+import org.simantics.g3d.math.MathTools;\r
+\r
+public class Cone {\r
+\r
+       public static Mesh create(double radius, int s) {\r
+               if (s < 3 || radius < MathTools.NEAR_ZERO)\r
+                       throw new IllegalArgumentException();\r
+               List<Vector3d> vertices = new ArrayList<Vector3d>(s+2);\r
+               List<Vector3d> normals = new ArrayList<Vector3d>(vertices.size());\r
+               List<Integer> indices = new ArrayList<Integer>();\r
+               \r
+               vertices.add(new Vector3d(0.0,0.0,0.0));\r
+               normals.add(new Vector3d(0.0,-1.0,0.0));\r
+               vertices.add(new Vector3d(0.0,radius*2.0,0.0));\r
+               normals.add(new Vector3d(0.0,1.0,0.0));\r
+               \r
+               Vector3d v = new Vector3d(radius,0,0);\r
+               for (int i = 0; i < s; i++) {\r
+                       AxisAngle4d aa = new AxisAngle4d(0,1,0,((double)i/(double)s)*Math.PI * 2);\r
+                       Vector3d t = new Vector3d();\r
+                       MathTools.rotate(MathTools.getQuat(aa), v, t);\r
+                       vertices.add(t);\r
+                       Vector3d n = new Vector3d(t);\r
+                       n.normalize();\r
+                       normals.add(n);\r
+               }\r
+               \r
+               for (int i = 0; i < s; i++) {\r
+                       indices.add(0);\r
+                       \r
+                       if (i < s - 1)\r
+                               indices.add(i + 3);\r
+                       else\r
+                               indices.add(2);\r
+                       indices.add(i + 2);\r
+               }\r
+               \r
+               for (int i = 0; i < s; i++) {\r
+                       indices.add(1);\r
+                       indices.add(i + 2);\r
+                       if (i < s - 1)\r
+                               indices.add(i + 3);\r
+                       else\r
+                               indices.add(2);\r
+                       \r
+               }\r
+               return new Mesh(vertices,normals,indices);\r
+               \r
+       }\r
+       \r
+       public static void main(String arg[]) {\r
+               Mesh s1 = create(1.0, 3);\r
+               Mesh s2 = create(1.0, 4);\r
+               System.out.println("debug " + s1 + "\n" + s2);\r
+       }\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/shape/Cylinder.java b/org.simantics.g3d/src/org/simantics/g3d/shape/Cylinder.java
new file mode 100644 (file)
index 0000000..870abce
--- /dev/null
@@ -0,0 +1,23 @@
+package org.simantics.g3d.shape;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import javax.vecmath.Vector3d;\r
+\r
+public class Cylinder {\r
+       \r
+       public static Mesh create(Vector3d start, Vector3d dir, double r, int s) {\r
+               Tube tube = new Tube();\r
+               tube.setResolution(s);\r
+               tube.setRadius(r);\r
+               List<Vector3d> vertices = new ArrayList<Vector3d>();\r
+               vertices.add(start);\r
+               Vector3d t = new Vector3d(start);\r
+               t.add(dir);\r
+               vertices.add(dir);\r
+               tube.setVertices(vertices);\r
+               return tube.create();\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/shape/Mesh.java b/org.simantics.g3d/src/org/simantics/g3d/shape/Mesh.java
new file mode 100644 (file)
index 0000000..83aa360
--- /dev/null
@@ -0,0 +1,137 @@
+package org.simantics.g3d.shape;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import javax.vecmath.Quat4d;\r
+import javax.vecmath.Vector3d;\r
+\r
+import org.simantics.g3d.math.MathTools;\r
+\r
+public class Mesh {\r
+       private List<Vector3d> vertices;\r
+       private List<Vector3d> normals;\r
+       private List<Color4d> colors;\r
+       private List<Integer> indices;\r
+       \r
+       \r
+       public Mesh(List<Vector3d> vertices, List<Vector3d> normals,\r
+                       List<Color4d> colors, List<Integer> indices) {\r
+               this.vertices = vertices;\r
+               this.normals = normals;\r
+               this.colors = colors;\r
+               this.indices = indices;\r
+       }\r
+       \r
+       public Mesh(List<Vector3d> vertices, List<Vector3d> normals, List<Integer> indices) {\r
+               this.vertices = vertices;\r
+               this.normals = normals;\r
+               this.indices = indices;\r
+       }\r
+       \r
+       public Mesh(List<Vector3d> vertices, List<Integer> indices) {\r
+               this.vertices = vertices;\r
+               this.indices = indices;\r
+       }\r
+\r
+       public List<Vector3d> getVertices() {\r
+               return vertices;\r
+       }\r
+       \r
+       public List<Vector3d> getNormals() {\r
+               return normals;\r
+       }\r
+       \r
+       public List<Integer> getIndices() {\r
+               return indices;\r
+       }\r
+       \r
+       public List<Color4d> getColors() {\r
+               return colors;\r
+       }\r
+       \r
+       public void createNormals() {\r
+               normals = new ArrayList<Vector3d>(vertices.size());\r
+               for (int i = 0; i < vertices.size(); i++) {\r
+                       normals.add(new Vector3d());\r
+               }\r
+        Vector3d v1 = new Vector3d();\r
+        Vector3d v2 = new Vector3d();\r
+        Vector3d v3 = new Vector3d();\r
+        Vector3d t1 = new Vector3d();\r
+        Vector3d t2 = new Vector3d();\r
+        Vector3d n = new Vector3d();\r
+        for (int i = 0; i < indices.size(); i+=3) {\r
+            v1.set(vertices.get(i));\r
+            v2.set(vertices.get(i+1));\r
+            v3.set(vertices.get(i+2));\r
+            t1.sub(v3,v1);\r
+            t2.sub(v2,v1);\r
+            n.cross(t2, t1);\r
+            normals.get(i).add(n);\r
+            normals.get(i+1).add(n);\r
+            normals.get(i+2).add(n);\r
+        }\r
+        for (int i = 0; i < normals.size(); i++) {\r
+               normals.get(i).normalize();\r
+        }\r
+    }\r
+       \r
+       public void translate(Vector3d v) {\r
+               for (int i = 0; i < vertices.size(); i++) {\r
+                       vertices.get(i).add(v);\r
+               }\r
+       }\r
+       \r
+       public void rotate(Quat4d q) {\r
+               Vector3d t = new Vector3d();\r
+               for (int i = 0; i < vertices.size(); i++) {\r
+                       MathTools.rotate(q, vertices.get(i), t);\r
+                       vertices.get(i).set(t);\r
+               }\r
+               \r
+               if (normals != null) {\r
+                       for (int i = 0; i < normals.size(); i++) {\r
+                               MathTools.rotate(q, normals.get(i), t);\r
+                               t.normalize();\r
+                               normals.get(i).set(t);\r
+                       }       \r
+               }\r
+       }\r
+       \r
+       public void setColor(Color4d color) {\r
+               colors = new ArrayList<Color4d>(vertices.size());\r
+               for (int i = 0; i < vertices.size(); i++) {\r
+                       colors.add(color);\r
+               }\r
+       }\r
+       \r
+       public void add(Mesh mesh) {\r
+               int vindex = vertices.size();\r
+               int triIndex = indices.size();\r
+               vertices.addAll(mesh.getVertices());\r
+               indices.addAll(mesh.indices);\r
+               for (int i = triIndex; i < indices.size(); i++) {\r
+                       indices.set(i, indices.get(i)+vindex);\r
+               }\r
+               if (normals != null) {\r
+                       boolean hasNormals = true;\r
+                       if (mesh.getNormals() == null) {\r
+                               mesh.createNormals();\r
+                               hasNormals = false;\r
+                       }\r
+                       normals.addAll(mesh.getNormals());\r
+                       if (!hasNormals)\r
+                               mesh.normals = null;\r
+               }\r
+               if (colors != null) {\r
+                       if (mesh.getColors() != null) {\r
+                               colors.addAll(mesh.getColors());\r
+                       } else {\r
+                               for (int i = 0; i < mesh.getVertices().size(); i++) {\r
+                                       colors.add(new Color4d(1,1,1,0));\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/shape/Sphere.java b/org.simantics.g3d/src/org/simantics/g3d/shape/Sphere.java
new file mode 100644 (file)
index 0000000..63f9182
--- /dev/null
@@ -0,0 +1,94 @@
+package org.simantics.g3d.shape;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import javax.vecmath.AxisAngle4d;\r
+import javax.vecmath.Vector3d;\r
+\r
+import org.simantics.g3d.math.MathTools;\r
+\r
+public class Sphere {\r
+\r
+       public static Mesh create(double radius, int s, int p) {\r
+               if (s < 3 || p < 3 || radius < MathTools.NEAR_ZERO)\r
+                       throw new IllegalArgumentException();\r
+               List<Vector3d> vertices = new ArrayList<Vector3d>((s-2)*p + 2);\r
+               List<Vector3d> normals = new ArrayList<Vector3d>(vertices.size());\r
+               List<Integer> indices = new ArrayList<Integer>(((s-3)*p*2 + p * 2)*3);\r
+               Vector3d v = new Vector3d(0.0,-radius,0.0);\r
+               Vector3d vp = new Vector3d();\r
+               for (int ip = 0; ip < p; ip++) {\r
+                       if (ip == 0) {\r
+                               vertices.add(new Vector3d(0.0,-radius,0.0));\r
+                       } else if (ip == p - 1) {\r
+                               vertices.add(new Vector3d(0.0, radius,0.0));\r
+                               int off = 1 + (ip-2)*s;\r
+                               for (int is = 0; is < s; is++) {\r
+                                       indices.add(vertices.size() - 1);\r
+                                       indices.add(is+off);\r
+                                       if (is < s -1)\r
+                                               indices.add(is+off+1);\r
+                                       else\r
+                                               indices.add(off);\r
+                                       \r
+                                       \r
+                               }\r
+                       } else {\r
+                               AxisAngle4d aa = new AxisAngle4d(1, 0, 0, ((double)ip/(double)(p-1))*Math.PI);\r
+                               MathTools.rotate(MathTools.getQuat(aa), v, vp);\r
+                               for (int is = 0; is < s; is++) {\r
+                                       aa = new AxisAngle4d(0, 1, 0, ((double)is/(double)s)*Math.PI*2);\r
+                                       Vector3d vs = new Vector3d();\r
+                                       MathTools.rotate(MathTools.getQuat(aa), vp, vs);\r
+                                       vertices.add(vs);\r
+                               }\r
+                               if (ip == 1) {\r
+                                       for (int is = 0; is < s; is++) {\r
+                                               indices.add(0);\r
+                                               if (is < s -1)\r
+                                                       indices.add(is+2);\r
+                                               else\r
+                                                       indices.add(1);\r
+                                               indices.add(is+1);\r
+                                       }\r
+                               } else {\r
+                                       int off = 1 + (ip-1)*s;\r
+                                       for (int is = 0; is < s-1; is++) {\r
+                                               indices.add(off + is - s);\r
+                                               indices.add(off + is+1);\r
+                                               indices.add(off + is);\r
+                                               \r
+                                               \r
+                                               indices.add(off + is - s);\r
+                                               indices.add(off + is + 1 - s);\r
+                                               indices.add(off + is + 1);\r
+                                               \r
+                                       }\r
+                                       indices.add(off - 1);\r
+                                       indices.add(off);\r
+                                       indices.add(off + s - 1);\r
+                                       \r
+                                       indices.add(off -1);\r
+                                       indices.add(off - s);\r
+                                       indices.add(off);\r
+                                       \r
+                               }\r
+                       }\r
+               }\r
+               for (int i = 0; i < vertices.size(); i++) {\r
+                       Vector3d n = new Vector3d(vertices.get(i));\r
+                       n.normalize();\r
+                       normals.add(n);\r
+               }\r
+               \r
+               return new Mesh(vertices,normals,indices);\r
+               \r
+       }\r
+       \r
+       public static void main(String arg[]) {\r
+               Mesh s1 = create(1.0, 3, 3);\r
+               Mesh s2 = create(1.0, 4, 4);\r
+               System.out.println("debug " + s1 + " " + s2);\r
+       }\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/shape/Tube.java b/org.simantics.g3d/src/org/simantics/g3d/shape/Tube.java
new file mode 100644 (file)
index 0000000..958993e
--- /dev/null
@@ -0,0 +1,173 @@
+package org.simantics.g3d.shape;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import javax.vecmath.AxisAngle4d;\r
+import javax.vecmath.Vector3d;\r
+\r
+import org.simantics.g3d.math.MathTools;\r
+\r
+\r
+public class Tube {\r
+       List<Vector3d> vertices;\r
+       List<Color4d> colors;\r
+       List<Double> radiis;\r
+       Double radius = 1.0;\r
+       int resolution = 8;\r
+       \r
+       \r
+       public void setResolution(int resolution) {\r
+               if (resolution > 2)\r
+                       this.resolution = resolution;\r
+       }\r
+       \r
+       public void setVertices(List<Vector3d> vertices) {\r
+               this.vertices = vertices;\r
+       }\r
+\r
+       public void setColors(List<Color4d> colors) {\r
+               this.colors = colors;\r
+       }\r
+       \r
+       public void setRadiis(List<Double> radiis) {\r
+               this.radiis = radiis;\r
+       }\r
+       \r
+       public void setRadius(Double radius) {\r
+               this.radius = radius;\r
+       }\r
+       \r
+       \r
+       \r
+       public Mesh create() {\r
+               if (vertices.size() < 2 )\r
+                       throw new IllegalArgumentException("Tube must have at least two vertices");\r
+               \r
+               Vector3d t = new Vector3d();\r
+               \r
+               for (int i = 0; i < vertices.size() - 1; i++) {\r
+                       t.set(vertices.get(i+1));\r
+                       t.sub(vertices.get(i));\r
+                       if (t.lengthSquared() < 0.0001)\r
+                               throw new IllegalArgumentException("vertices at index " + i + " are too close to each other");\r
+               }\r
+               \r
+               List<Vector3d> points = new ArrayList<Vector3d>(vertices.size()*resolution);\r
+               List<Vector3d> normals = new ArrayList<Vector3d>(vertices.size()*resolution);\r
+               \r
+               for (int i = 0; i < vertices.size(); i++) {\r
+                       createCircle(i,points,normals);\r
+               }\r
+               \r
+               int index[] = new int[(vertices.size()-1)*resolution*6];\r
+               \r
+               createIndices(index);\r
+               List<Integer> indices = new ArrayList<Integer>();\r
+               for (int i = 0; i < index.length; i++) {\r
+                       indices.add(index[i]);\r
+               }\r
+               \r
+               \r
+               \r
+               vertices.clear();\r
+               if (colors != null)\r
+                       colors.clear();\r
+               if (radiis != null)\r
+                       radiis.clear();\r
+               \r
+               return new Mesh(points, normals, indices);\r
+               \r
+       }\r
+       \r
+       private void createCircle(int i, List<Vector3d> points, List<Vector3d> normals) {\r
+               final Vector3d up = new Vector3d(0,1,0);\r
+               final Vector3d up2 = new Vector3d(0,0,1);\r
+               Vector3d p = vertices.get(i);\r
+               Vector3d t = getTangent(i);\r
+               Vector3d n = new Vector3d();\r
+               if (up.dot(t) < 0.99) {\r
+                       n.cross(up, t);\r
+               } else {\r
+                       n.cross(up2, t);\r
+               }\r
+               n.normalize();\r
+               if (radiis != null) {\r
+                       n.scale(radiis.get(i));\r
+               } else {\r
+                       n.scale(radius);\r
+               }\r
+               \r
+               for (int index = 0; index < resolution; index ++) {\r
+                       Vector3d v;\r
+                       if (index == 0) {\r
+                               v = new Vector3d(n);\r
+                               \r
+                       } else {\r
+                               AxisAngle4d aa = new AxisAngle4d(t, (Math.PI * 2 * (double)index)/(double)resolution);\r
+                               v = new Vector3d();\r
+                               MathTools.rotate(MathTools.getQuat(aa), n, v);\r
+                       }\r
+                       //int vIndex = (i*resolution + index)*3;\r
+                       Vector3d pt = new Vector3d(p);\r
+                       pt.add(v);\r
+                       //points.set(vIndex, pt);\r
+                       points.add(pt);\r
+                       v.normalize();\r
+                       //normals.set(vIndex, v);\r
+                       normals.add(v);\r
+               }\r
+       }\r
+       \r
+       private Vector3d getTangent(int i) {\r
+               Vector3d p,n;\r
+               if (i == 0) {\r
+                       p = vertices.get(0);\r
+                       n = vertices.get(1);\r
+               } else if (i == vertices.size() - 1) {\r
+                       p = vertices.get(i-1);\r
+                       n = vertices.get(i);\r
+               } else {\r
+                       p = vertices.get(i-1);\r
+                       n = vertices.get(i+1);\r
+               }\r
+               n = new Vector3d(n);\r
+               n.sub(p);\r
+               n.normalize();\r
+               return n;\r
+       }\r
+       \r
+       private void createIndices(int index[]) {\r
+               for (int c = 0; c < vertices.size() - 1; c++) {\r
+                       for (int s = 0; s < resolution; s++) {\r
+                               int ii = (c * resolution + s) * 6;\r
+                               int iv = c*resolution + s;\r
+                               \r
+                               /*\r
+                            iv+1 ---- iv + resolution + 1\r
+                                     | /|\r
+                                     |/ |\r
+                                  iv ---- iv + resolution \r
+                               */\r
+                               if (s < resolution - 1) {\r
+                                       index[ii+2] = iv;\r
+                                       index[ii+1] = iv+resolution;\r
+                                       index[ii+0] = iv+resolution+1;\r
+                                       \r
+                                       index[ii+5] = iv;\r
+                                       index[ii+4] = iv+resolution+1;\r
+                                       index[ii+3] = iv+1;\r
+                               } else {\r
+                                       index[ii+2] = iv;\r
+                                       index[ii+1] = iv+resolution;\r
+                                       index[ii+0] = iv+1;\r
+                                       \r
+                                       index[ii+5] = iv;\r
+                                       index[ii+4] = iv+1;\r
+                                       index[ii+3] = iv+1-resolution;\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/toolbar/CommandStateRegistry.java b/org.simantics.g3d/src/org/simantics/g3d/toolbar/CommandStateRegistry.java
new file mode 100644 (file)
index 0000000..abb92f9
--- /dev/null
@@ -0,0 +1,151 @@
+package org.simantics.g3d.toolbar;\r
+\r
+import java.util.HashMap;\r
+import java.util.Map;\r
+\r
+import org.eclipse.core.commands.Command;\r
+import org.eclipse.core.commands.State;\r
+import org.eclipse.ui.IWorkbenchPart;\r
+import org.eclipse.ui.PlatformUI;\r
+import org.eclipse.ui.commands.ICommandService;\r
+import org.eclipse.ui.handlers.IHandlerService;\r
+import org.eclipse.ui.handlers.RadioState;\r
+import org.eclipse.ui.handlers.RegistryToggleState;\r
+\r
+/**\r
+ * Registry for storing command states separately for each IEditorPart\r
+ * \r
+ * TODO : how to change toggle/radios state from editor?\r
+ *   TODO : how to update visible buttons (ToolbarContributor)\r
+ * \r
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>\r
+ *\r
+ */\r
+public class CommandStateRegistry {\r
+\r
+       \r
+       private static CommandStateRegistry instance;\r
+       \r
+       \r
+       public static CommandStateRegistry getInstance() {\r
+               if (instance == null)\r
+                       instance = new CommandStateRegistry();\r
+               return instance;\r
+       }\r
+       \r
+       \r
+       \r
+       private Map<IWorkbenchPart,Map<String,Boolean>> toggleStates = new HashMap<IWorkbenchPart, Map<String,Boolean>>();\r
+       private Map<String,Boolean> defaultToggleStates = new HashMap<String, Boolean>();\r
+       \r
+       private Map<String,String> defaultRadioStates = new HashMap<String, String>();\r
+       private Map<IWorkbenchPart,Map<String,String>> radioStates = new HashMap<IWorkbenchPart, Map<String,String>>();\r
+\r
+       private ICommandService service;\r
+       private IHandlerService handlerService;\r
+       \r
+       private CommandStateRegistry() {\r
+               service = (ICommandService) PlatformUI.getWorkbench().getService(ICommandService.class);\r
+               handlerService = (IHandlerService) PlatformUI.getWorkbench().getService(IHandlerService.class);\r
+       }\r
+       \r
+       /**\r
+        * Stores default state for a command.\r
+        * \r
+        * Note: uses current state as default. \r
+        * \r
+        * @param commandId\r
+        */\r
+       public void storeDefaultState(String commandId) {\r
+               Command command = service.getCommand(commandId);\r
+               State toggleState = command.getState(RegistryToggleState.STATE_ID);\r
+               State radioState = command.getState(RadioState.STATE_ID);\r
+               if (toggleState != null) {\r
+                       if (!defaultToggleStates.containsKey(commandId))\r
+                               defaultToggleStates.put(commandId, getToggleState(command));\r
+               } else if (radioState != null) {\r
+                       String value = (String) radioState.getValue();\r
+                       if (!defaultRadioStates.containsKey(commandId))\r
+                               defaultRadioStates.put(commandId, value);\r
+               } else {\r
+                       throw new IllegalArgumentException("Command " + commandId + " does not have a state");\r
+               }\r
+       }\r
+       /**\r
+        * Stores toggle state of a command.\r
+        * @param part\r
+        * @param commandId\r
+        * @param checked\r
+        */\r
+       public void setEditorState(IWorkbenchPart part, String commandId, boolean checked) {\r
+               Map<String,Boolean> editorStates = toggleStates.get(part);\r
+               if (editorStates == null) {\r
+                       editorStates = new HashMap<String, Boolean>();\r
+                       toggleStates.put(part, editorStates);\r
+               }\r
+               editorStates.put(commandId, checked);\r
+       }\r
+       \r
+       /**\r
+        * Stores radio state of a command.\r
+        * @param part\r
+        * @param commandId\r
+        * @param value\r
+        */\r
+       public void setEditorState(IWorkbenchPart part, String commandId, String value) {\r
+               Map<String,String> editorStates = radioStates.get(part);\r
+               if (editorStates == null) {\r
+                       editorStates = new HashMap<String, String>();\r
+                       radioStates.put(part, editorStates);\r
+               }\r
+               editorStates.put(commandId, value);\r
+       }\r
+       \r
+       public Map<String, Boolean> getDefaultToggleStates() {\r
+               return defaultToggleStates;\r
+       }\r
+       \r
+       public Map<String, String> getDefaultRadioStates() {\r
+               return defaultRadioStates;\r
+       }\r
+       \r
+       public Map<String, Boolean> getEditorToggleStates(IWorkbenchPart part) {\r
+               return toggleStates.get(part);\r
+       }\r
+       \r
+       public Map<String, String> getEditorRadioStates(IWorkbenchPart part) {\r
+               return radioStates.get(part);\r
+       }\r
+       \r
+       public Boolean getToggleState(IWorkbenchPart part, String commandId) {\r
+               if (part == null)\r
+                       return defaultToggleStates.get(commandId);\r
+               Map<String,Boolean> editorStates = toggleStates.get(part);\r
+               if (editorStates == null) {\r
+                       return defaultToggleStates.get(commandId);\r
+               }\r
+               return editorStates.get(commandId);\r
+       }\r
+       \r
+       public String getRadioState(IWorkbenchPart part, String commandId) {\r
+               if (part == null)\r
+                       return defaultRadioStates.get(commandId);\r
+               Map<String,String> editorStates = radioStates.get(part);\r
+               if (editorStates == null) {\r
+                       return defaultRadioStates.get(commandId);\r
+               }\r
+               return editorStates.get(commandId);\r
+       }\r
+       \r
+       public void clearStates(IWorkbenchPart part) {\r
+               toggleStates.remove(part);\r
+               radioStates.remove(part);\r
+       }\r
+       \r
+       private boolean getToggleState(Command command) {\r
+               State toggleState = command.getState(RegistryToggleState.STATE_ID);\r
+               return (Boolean)toggleState.getValue();\r
+       }\r
+       \r
+       \r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/toolbar/ToolBarCommandRegistry.java b/org.simantics.g3d/src/org/simantics/g3d/toolbar/ToolBarCommandRegistry.java
new file mode 100644 (file)
index 0000000..2e94d3b
--- /dev/null
@@ -0,0 +1,126 @@
+package org.simantics.g3d.toolbar;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collections;\r
+import java.util.List;\r
+\r
+import org.eclipse.core.runtime.IConfigurationElement;\r
+import org.eclipse.core.runtime.IExtension;\r
+import org.eclipse.core.runtime.IExtensionPoint;\r
+import org.eclipse.core.runtime.Platform;\r
+import org.eclipse.core.runtime.dynamichelpers.ExtensionTracker;\r
+import org.eclipse.core.runtime.dynamichelpers.IExtensionChangeHandler;\r
+import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker;\r
+import org.eclipse.core.runtime.dynamichelpers.IFilter;\r
+import org.simantics.g3d.Activator;\r
+\r
+\r
+\r
+\r
+\r
+public class ToolBarCommandRegistry implements IExtensionChangeHandler {\r
+       private final static String NAMESPACE = Activator.PLUGIN_ID;\r
+\r
+       private final static String EP_NAME = "toolbarCommand";\r
+       \r
+       private ExtensionTracker tracker;\r
+       \r
+       private List<ToolbarCommandExtension> extensions = new ArrayList<ToolbarCommandExtension>();\r
+       \r
+       \r
+       private static ToolBarCommandRegistry INSTANCE;\r
+       \r
+       public static synchronized ToolBarCommandRegistry getInstance() {\r
+               if (INSTANCE == null)\r
+                       INSTANCE = new ToolBarCommandRegistry();\r
+               return INSTANCE;\r
+       }\r
+       \r
+       public static synchronized void dispose() {\r
+               if (INSTANCE != null) {\r
+                       INSTANCE.close();\r
+                       INSTANCE = null;\r
+               }       \r
+       }\r
+       \r
+       public ToolBarCommandRegistry() {\r
+               tracker = new ExtensionTracker();\r
+               \r
+               IExtensionPoint ep = Platform.getExtensionRegistry().getExtensionPoint(NAMESPACE,EP_NAME);\r
+               loadExtensions(ep.getConfigurationElements());\r
+               \r
+               IFilter filter = ExtensionTracker.createExtensionPointFilter(ep);\r
+               tracker.registerHandler(this, filter);\r
+       }\r
+       \r
+       private void close() {\r
+               tracker.close();\r
+               tracker = null;\r
+               extensions.clear();\r
+       }\r
+       \r
+       public synchronized List<ToolbarCommandExtension> getExtensions() {\r
+               return Collections.unmodifiableList(extensions);\r
+       }\r
+       \r
+       private synchronized void loadExtensions(IConfigurationElement[] elements) {\r
+               for (IConfigurationElement el : elements) {\r
+                       String commandId = el.getAttribute("commandId");\r
+                       \r
+                       ToolbarCommandExtension ext = new ToolbarCommandExtension(commandId);\r
+                       ext.toolbarId = el.getAttribute("toolbarId");\r
+                       ext.image = el.getAttribute("image");\r
+                       ext.name = el.getAttribute("name");\r
+                       ext.type = el.getAttribute("type");\r
+                       ext.value = el.getAttribute("value");\r
+                       ext.contributorId = el.getContributor().getName();\r
+                       tracker.registerObject(el.getDeclaringExtension(), ext, IExtensionTracker.REF_STRONG);\r
+                       extensions.add(ext);\r
+                       \r
+               }\r
+       }\r
+       \r
+       @Override\r
+    public void addExtension(IExtensionTracker tracker, IExtension extension) {\r
+        loadExtensions(extension.getConfigurationElements());\r
+    }\r
+       \r
+       @Override\r
+       public synchronized void removeExtension(IExtension extension, Object[] objects) {\r
+               for (Object o : objects) {\r
+                       ToolbarCommandExtension ext = (ToolbarCommandExtension) o;\r
+                       tracker.unregisterObject(extension, ext);\r
+                       extensions.remove(ext);\r
+               }\r
+       }\r
+       \r
+       public synchronized List<ToolbarCommandExtension> getExtensions(String toolbarId) {\r
+               List<ToolbarCommandExtension> list = new ArrayList<ToolbarCommandExtension>();\r
+               for (ToolbarCommandExtension ext : extensions)\r
+                       if (ext.toolbarId.equals(toolbarId))\r
+                               list.add(ext);\r
+               return list;\r
+               \r
+       }\r
+       \r
+       public class ToolbarCommandExtension {\r
+               public String commandId;\r
+               public String toolbarId;\r
+               public String name;\r
+               public String type;\r
+               public String value;\r
+               public String image;\r
+               public String contributorId;\r
+               public ToolbarCommandExtension(String commandId) {\r
+                       super();\r
+                       this.commandId = commandId;\r
+               }\r
+               \r
+               @Override\r
+               public String toString() {\r
+                       return "ToolbarCommandExtension, commandId= " + commandId + " toolbarId= " + toolbarId + " type= " + type + " value= " + value + " contributor= " + contributorId;\r
+               }\r
+       }\r
+       \r
+       \r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/toolbar/ToolbarContributor.java b/org.simantics.g3d/src/org/simantics/g3d/toolbar/ToolbarContributor.java
new file mode 100644 (file)
index 0000000..9f87b32
--- /dev/null
@@ -0,0 +1,482 @@
+package org.simantics.g3d.toolbar;\r
+\r
+import java.util.ArrayList;\r
+import java.util.HashMap;\r
+import java.util.HashSet;\r
+import java.util.List;\r
+import java.util.Map;\r
+import java.util.Set;\r
+\r
+import org.eclipse.core.commands.Command;\r
+import org.eclipse.core.commands.CommandEvent;\r
+import org.eclipse.core.commands.ExecutionException;\r
+import org.eclipse.core.commands.ICommandListener;\r
+import org.eclipse.core.commands.State;\r
+import org.eclipse.jface.action.Action;\r
+import org.eclipse.jface.action.ActionContributionItem;\r
+import org.eclipse.jface.action.IContributionItem;\r
+import org.eclipse.jface.action.ICoolBarManager;\r
+import org.eclipse.jface.action.IToolBarManager;\r
+import org.eclipse.jface.action.ToolBarContributionItem;\r
+import org.eclipse.jface.resource.ImageDescriptor;\r
+import org.eclipse.nebula.widgets.tablecombo.TableCombo;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.events.SelectionEvent;\r
+import org.eclipse.swt.events.SelectionListener;\r
+import org.eclipse.swt.layout.GridData;\r
+import org.eclipse.swt.layout.GridLayout;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.swt.widgets.Control;\r
+import org.eclipse.swt.widgets.TableItem;\r
+import org.eclipse.ui.IEditorPart;\r
+import org.eclipse.ui.IPartListener;\r
+import org.eclipse.ui.IWorkbenchPart;\r
+import org.eclipse.ui.PlatformUI;\r
+import org.eclipse.ui.commands.ICommandService;\r
+import org.eclipse.ui.handlers.HandlerUtil;\r
+import org.eclipse.ui.handlers.IHandlerService;\r
+import org.eclipse.ui.handlers.RadioState;\r
+import org.eclipse.ui.handlers.RegistryToggleState;\r
+import org.eclipse.ui.menus.WorkbenchWindowControlContribution;\r
+import org.eclipse.ui.part.EditorActionBarContributor;\r
+import org.simantics.db.common.utils.ErrorLogger;\r
+import org.simantics.g3d.Activator;\r
+import org.simantics.g3d.toolbar.ToolBarCommandRegistry.ToolbarCommandExtension;\r
+import org.simantics.utils.datastructures.MapList;\r
+\r
+\r
+/**\r
+ * EditorBarContributor, which tracks toggle states separately for each command.\r
+ * \r
+ * @see org.simantics.g3d.toolbarCommand Extension Point\r
+ * \r
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>\r
+ * \r
+ * \r
+ * \r
+ * TODO : test radio buttons.\r
+ * TODO : configuring the position of buttons. \r
+ *\r
+ */\r
+public abstract class ToolbarContributor extends EditorActionBarContributor implements ICommandListener, IPartListener {\r
+\r
+       private static final String PLATFORM = "platform:/plugin/";\r
+       \r
+       private IEditorPart    activePart;\r
+       private Set<IEditorPart> parts = new HashSet<IEditorPart>();\r
+    IToolBarManager        mgr;\r
+    \r
+    \r
+    ICommandService service;\r
+    IHandlerService handlerService;\r
+    List<IContributionItem> items = new ArrayList<IContributionItem>();\r
+    MapList<String, CommandAction> actions = new MapList<String, ToolbarContributor.CommandAction>();\r
+    \r
+    CommandStateRegistry stateRegistry;\r
+       \r
+       private Map<String,ComboContribution> menus = new HashMap<String, ComboContribution>();\r
+       \r
+       public ToolbarContributor() {\r
+               service = (ICommandService) PlatformUI.getWorkbench().getService(ICommandService.class); \r
+               handlerService = (IHandlerService) PlatformUI.getWorkbench().getService(IHandlerService.class);\r
+               stateRegistry = CommandStateRegistry.getInstance();\r
+       }\r
+       \r
+       public abstract String getToolbarId();\r
+       \r
+       public void contributeToCoolBar(ICoolBarManager coolBarManager) {\r
+               IContributionItem toolBar = coolBarManager.find(getToolbarId());\r
+                if (toolBar instanceof ToolBarContributionItem)\r
+                mgr = ((ToolBarContributionItem) toolBar).getToolBarManager();\r
+            if (mgr == null)\r
+                   return;\r
+            \r
+            createCommands();\r
+            \r
+            mgr.markDirty();\r
+            \r
+       }\r
+       \r
+       private void createCommands() {\r
+               for (ToolbarCommandExtension ext : ToolBarCommandRegistry.getInstance().getExtensions(getToolbarId())) {\r
+                       addCommand(ext);\r
+               }\r
+       }\r
+       \r
+       private void addCommand(ToolbarCommandExtension ext) {\r
+               String commandId = ext.commandId;\r
+               Command command = service.getCommand(commandId);\r
+               \r
+               String type = ext.type;\r
+               \r
+               State toggleState = command.getState(RegistryToggleState.STATE_ID);\r
+               State radioState = command.getState(RadioState.STATE_ID);\r
+               \r
+               String name = ext.name;\r
+               \r
+               \r
+               ImageDescriptor image = getImage(ext);\r
+               \r
+               CommandAction a = null;\r
+               if (type.equals("toggle") && toggleState != null) {\r
+                       a = new CommandCheckboxAction(command,name,image);\r
+\r
+                       stateRegistry.storeDefaultState(commandId);\r
+               } else if (radioState != null && ext.value != null) {\r
+                       stateRegistry.storeDefaultState(commandId);\r
+                       if (type.equals("radio")) {\r
+                               a = new CommandRadioAction(command,name,ext.value,image);\r
+                       } else if (type.equals("combo")) {\r
+                               a = new CommandRadioAction(command,name,ext.value,image);\r
+                               ComboContribution combo = menus.get(commandId);\r
+                               if (combo == null) {\r
+                                       combo = new ComboContribution();\r
+                                       menus.put(commandId, combo);\r
+                                       items.add(combo);\r
+                                       mgr.add(combo);\r
+                                       a.getCommand().addCommandListener(this);\r
+                               }\r
+                               actions.add(commandId,a);\r
+                               combo.addAction(a);\r
+                               return;\r
+                       }\r
+               } else if (type.equals("push")) {\r
+                       a = new CommandPushAction(command,name,image);\r
+               } else {\r
+                       ErrorLogger.defaultLogError(ext + " is not valid.");\r
+                       return;\r
+               }\r
+               a.getCommand().addCommandListener(this);\r
+               IContributionItem item =  new ActionContributionItem(a);\r
+               actions.add(commandId,a);\r
+               items.add(item);\r
+               mgr.add(item);\r
+       }\r
+       \r
+       private ImageDescriptor getImage(ToolbarCommandExtension ext) {\r
+               ImageDescriptor image = null;\r
+               if (ext.image != null) {\r
+                       String plugin = null;\r
+                       String file = null;\r
+                       if (ext.image.startsWith(PLATFORM)) {\r
+                               String s = ext.image.substring(PLATFORM.length());\r
+                               int i = s.indexOf("/");\r
+                               plugin = s.substring(0,i);\r
+                               file = s.substring(i+1);\r
+                       } else {\r
+                               plugin = ext.contributorId;\r
+                               file = ext.image;\r
+                       }\r
+                       image = Activator.imageDescriptorFromPlugin(plugin, file);\r
+               }\r
+               return image;\r
+       }\r
+       \r
+\r
+       \r
+       @Override\r
+       public void commandChanged(CommandEvent commandEvent) {\r
+               if (commandEvent.isHandledChanged()||commandEvent.isEnabledChanged()) {\r
+                       Command command = commandEvent.getCommand();\r
+                       String commandId = command.getId();\r
+                       for (CommandAction a : actions.getValues(commandId)) {\r
+                               a.setEnabled(command.isHandled() && command.isEnabled());\r
+                       }\r
+               }\r
+       }\r
+       \r
+       @Override\r
+       public void setActiveEditor(IEditorPart targetEditor) {\r
+               if (targetEditor == activePart)\r
+                       return;\r
+               setContext(targetEditor);\r
+       }\r
+       \r
+       private void setContext(IEditorPart part) {\r
+               this.activePart = part;\r
+        if (!parts.contains(activePart)) {\r
+               activePart.getSite().getPage().addPartListener(this);\r
+        }\r
+        if (part != null) {\r
+               for (String commandId : actions.getKeys()) {\r
+                               for (CommandAction a : actions.getValues(commandId)) {\r
+                                       a.setEnabled(true);\r
+                               }\r
+                       }\r
+            updateActionBars(part);\r
+        } else {\r
+                       for (String commandId : actions.getKeys()) {\r
+                               for (CommandAction a : actions.getValues(commandId)) {\r
+                                       a.setEnabled(false);\r
+                               }\r
+                       }\r
+        }\r
+    }\r
+\r
+    private void updateActionBars(IEditorPart part) {\r
+       restoreActionStates();\r
+        part.getEditorSite().getActionBars().updateActionBars();\r
+    }\r
+       \r
+       @Override\r
+       public void dispose() {\r
+               if (mgr != null) {\r
+                       for (IContributionItem item : items) {\r
+                               mgr.remove(item);\r
+                               item.dispose();\r
+                       }\r
+                       mgr.markDirty();\r
+                       mgr.update(true);\r
+                       if (activePart != null) {\r
+                                activePart.getEditorSite().getActionBars().updateActionBars();\r
+                       }\r
+                       \r
+                       for (String commandId : actions.getKeys()) {\r
+                               for (CommandAction a : actions.getValues(commandId)) {\r
+                                       a.getCommand().removeCommandListener(this);\r
+                               }\r
+                       }\r
+                       actions.clear();\r
+               }\r
+               \r
+               super.dispose();\r
+               activePart = null;\r
+       }\r
+       \r
+\r
+       private void storeRadioActionState(CommandRadioAction action, boolean checked) {\r
+               if (activePart == null)\r
+                       return;\r
+               stateRegistry.setEditorState(activePart, action.getCommandId(), action.getValue());\r
+       }\r
+       \r
+       private void storeToggleActionState(CommandAction action, boolean checked) {\r
+               if (activePart == null)\r
+                       return;\r
+               stateRegistry.setEditorState(activePart, action.getCommandId(), checked);\r
+       }\r
+       \r
+       private void restoreActionStates() {\r
+               if (activePart == null)\r
+                       return;\r
+               // toggles\r
+               Map<String,Boolean> defaultToggleStates = stateRegistry.getDefaultToggleStates();\r
+               for (String commandId : defaultToggleStates.keySet()) {\r
+                       for (CommandAction a : actions.getValues(commandId)) {\r
+                               a.setChecked(defaultToggleStates.get(commandId));\r
+                       }\r
+               }\r
+               Map<String,Boolean> editorStates = stateRegistry.getEditorToggleStates(activePart);//toggleStates.get(activePart);\r
+               if (editorStates != null) {\r
+                       for (String commandId : editorStates.keySet()) {\r
+                               for (CommandAction a : actions.getValues(commandId)) {\r
+                                       a.setChecked(editorStates.get(commandId));\r
+                               }\r
+                       }\r
+               }\r
+               // radios\r
+               Map<String,String> defaultRadioStates = stateRegistry.getDefaultRadioStates();\r
+               for (String commandId : defaultRadioStates.keySet()) {\r
+                       String defaultValue = defaultRadioStates.get(commandId);\r
+                       for (CommandAction a : actions.getValues(commandId)) {\r
+                               CommandRadioAction r = (CommandRadioAction)a;\r
+                               r.setChecked(r.getValue().equals(defaultValue));\r
+                       }\r
+               }\r
+               \r
+               Map<String,String> editorRadioStates = stateRegistry.getEditorRadioStates(activePart);//radioStates.get(activePart);\r
+               if (editorRadioStates != null) {\r
+                       for (String commandId : editorRadioStates.keySet()) {\r
+                               String defaultValue = editorRadioStates.get(commandId);\r
+                               for (CommandAction a : actions.getValues(commandId)) {\r
+                                       CommandRadioAction r = (CommandRadioAction)a;\r
+                                       r.setChecked(r.getValue().equals(defaultValue));\r
+                               }\r
+                       }\r
+               }\r
+               \r
+               for (ComboContribution c : menus.values()) {\r
+                       c.updateSelection();\r
+               }\r
+               \r
+\r
+       }\r
+       \r
+       @Override\r
+       public void partActivated(IWorkbenchPart part) {\r
+\r
+       }\r
+       \r
+       @Override\r
+       public void partBroughtToTop(IWorkbenchPart part) {\r
+               \r
+       }\r
+       \r
+       @Override\r
+       public void partClosed(IWorkbenchPart part) {\r
+               parts.remove(part);\r
+               stateRegistry.clearStates(part);\r
+               part.getSite().getPage().removePartListener(this);\r
+       }\r
+       \r
+       @Override\r
+       public void partDeactivated(IWorkbenchPart part) {\r
+               \r
+       }\r
+       \r
+       @Override\r
+       public void partOpened(IWorkbenchPart part) {\r
+               \r
+       }\r
+       \r
+       private boolean getToggleState(Command command) {\r
+               State toggleState = command.getState(RegistryToggleState.STATE_ID);\r
+               return (Boolean)toggleState.getValue();\r
+       }\r
+       \r
+       private abstract class CommandAction extends Action {\r
+               private Command command;\r
+               \r
+               public CommandAction(Command command, String name, ImageDescriptor image, int style) {\r
+                       super(name,style);\r
+                       this.command = command;\r
+                       if (image != null)\r
+                               setImageDescriptor(image);\r
+               }\r
+               \r
+               @Override\r
+               public void run() {\r
+                       try {\r
+                               handlerService.executeCommand(command.getId(), null);\r
+                       } catch (Exception e) {\r
+                               e.printStackTrace();\r
+                       }\r
+               }\r
+               \r
+               public Command getCommand() {\r
+                       return command;\r
+               }\r
+               \r
+               public String getCommandId() {\r
+                       return command.getId();\r
+               }\r
+       }\r
+       \r
+       private class CommandCheckboxAction extends CommandAction {\r
+               \r
+               public CommandCheckboxAction(Command command, String name, ImageDescriptor image) {\r
+                       super(command,name,image,Action.AS_CHECK_BOX);\r
+                       \r
+               }\r
+               \r
+               @Override\r
+               public void run() {\r
+                       boolean checked = isChecked(); \r
+                       storeToggleActionState(this, checked);\r
+                       try {\r
+                               if (checked == getToggleState(getCommand()))\r
+                                       HandlerUtil.toggleCommandState(getCommand());\r
+                       } catch (ExecutionException e) {\r
+                               e.printStackTrace();\r
+                       }\r
+                       super.run();\r
+               }\r
+               \r
+       }\r
+       \r
+       private class CommandRadioAction extends CommandAction {\r
+\r
+               private String value;\r
+               \r
+               public CommandRadioAction(Command command, String name, String value, ImageDescriptor image) {\r
+                       super(command,name,image,Action.AS_RADIO_BUTTON);\r
+                       this.value = value;\r
+               }\r
+               \r
+               @Override\r
+               public void run() {\r
+                       boolean checked = isChecked(); \r
+                       storeRadioActionState(this, checked);\r
+                       try {\r
+                               HandlerUtil.updateRadioState(getCommand(), value);\r
+                       } catch (ExecutionException e) {\r
+                               e.printStackTrace();\r
+                               return;\r
+                       }\r
+                       super.run();\r
+               }\r
+               \r
+               public String getValue() {\r
+                       return value;\r
+               }\r
+               \r
+       }\r
+\r
+       private class CommandPushAction extends CommandAction {\r
+               \r
+               public CommandPushAction(Command command, String name, ImageDescriptor image) {\r
+                       super(command,name,image,Action.AS_PUSH_BUTTON);\r
+               }\r
+\r
+       }\r
+       \r
+       private class ComboContribution extends WorkbenchWindowControlContribution {\r
+               private TableCombo combo;\r
+               \r
+               private List<Action> actions = new ArrayList<Action>();\r
+               \r
+               @Override\r
+               protected Control createControl(Composite parent) {\r
+                       Composite container = new Composite(parent, SWT.NONE);\r
+                       GridLayout glContainer = new GridLayout(1, false);\r
+                       glContainer.marginTop = 0;\r
+                       glContainer.marginHeight = 0;\r
+                       glContainer.marginWidth = 0;\r
+                       container.setLayout(glContainer);\r
+                       GridData glReader = new GridData(SWT.FILL, SWT.FILL, false, false, 1, 1);\r
+                       combo = new TableCombo(container, SWT.BORDER | SWT.READ_ONLY);\r
+                       combo.setLayoutData(glReader);\r
+\r
+                       for (Action a : actions) {\r
+                               TableItem item = new TableItem(combo.getTable(), SWT.NONE);\r
+                               item.setText(a.getText());\r
+                               if (a.getImageDescriptor() != null)\r
+                                       item.setImage(a.getImageDescriptor().createImage());\r
+                       }\r
+                       \r
+                       combo.addSelectionListener(new SelectionListener() {\r
+                               \r
+                               @Override\r
+                               public void widgetSelected(SelectionEvent e) {\r
+                                       int index = combo.getSelectionIndex();\r
+                                       if (index == -1)\r
+                                               return;\r
+                                       actions.get(index).run();\r
+                               }\r
+                               \r
+                               @Override\r
+                               public void widgetDefaultSelected(SelectionEvent e) {\r
+                                       \r
+                               }\r
+                       });\r
+                       updateSelection();\r
+                       return container;\r
+               }\r
+               \r
+               public void addAction(Action a) {\r
+                       actions.add(a);\r
+               }\r
+               \r
+               void updateSelection() {\r
+                       if (combo == null)\r
+                               return;\r
+                       for (int i = 0; i < actions.size(); i++) {\r
+                               if (actions.get(i).isChecked()) {\r
+                                       combo.select(i);\r
+                                       return;\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+       \r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/tools/AdaptationUtils.java b/org.simantics.g3d/src/org/simantics/g3d/tools/AdaptationUtils.java
new file mode 100644 (file)
index 0000000..5902b0a
--- /dev/null
@@ -0,0 +1,89 @@
+package org.simantics.g3d.tools;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.Collections;\r
+\r
+import org.eclipse.core.runtime.IAdaptable;\r
+import org.eclipse.jface.viewers.IStructuredSelection;\r
+import org.simantics.utils.Container;\r
+\r
+/**\r
+ * @author Antti Villberg\r
+ * @author Marko Luukkainen\r
+ * \r
+ * TODO: merge to os.ui.utils.\r
+ */\r
+public class AdaptationUtils {\r
+       /**\r
+        * \r
+        * @param o\r
+        * @param clazz\r
+        * @return object of given class or null\r
+        */\r
+       @SuppressWarnings("unchecked")\r
+    public static <T> T adaptToSingle(Object o, Class<T> clazz) {\r
+        if (o instanceof IStructuredSelection) {\r
+            IStructuredSelection iss = (IStructuredSelection) o;\r
+            if (iss.size() != 1)\r
+                return null;\r
+            Object element = iss.getFirstElement();\r
+            return adaptToSingle(element, clazz);\r
+        } else if (o instanceof Collection<?>) {\r
+            Collection<?> c = (Collection<?>) o;\r
+            if (c.size() != 1)\r
+                return null;\r
+            Object element = c.iterator().next();\r
+            return adaptToSingle(element, clazz);\r
+        } else if (o instanceof IAdaptable) {\r
+            IAdaptable a = (IAdaptable) o;\r
+            return (T)a.getAdapter(clazz);\r
+        } else if (clazz.isInstance(o)) {\r
+            return (T)o;\r
+        } else if (o instanceof Container<?>) {\r
+            Object obj = ((Container<?>) o).get();\r
+            if (obj == o)\r
+                return null;\r
+            return adaptToSingle(obj, clazz);\r
+        }\r
+        return null;\r
+    }\r
+       /**\r
+        * \r
+        * @param o\r
+        * @param clazz\r
+        * @return collection of objects of given class. \r
+        */\r
+       @SuppressWarnings("unchecked")\r
+       public static <T> Collection<T> adaptToCollection(Object o, Class<T> clazz) {\r
+               if (clazz.isInstance(o)) {\r
+            return Collections.singletonList((T)o);\r
+               } else if (o instanceof IStructuredSelection) {\r
+            IStructuredSelection iss = (IStructuredSelection) o;\r
+            return adaptToCollection(iss.toArray(), clazz);\r
+        } else if (o instanceof Collection<?>) {\r
+            Collection<?> c = (Collection<?>) o;\r
+            return adaptToCollection(c.toArray(), clazz);\r
+        } else if (o instanceof IAdaptable) {\r
+            IAdaptable a = (IAdaptable) o;\r
+            return Collections.singletonList((T)a.getAdapter(clazz));\r
+        } else if (o instanceof Container<?>) {\r
+            Object obj = ((Container<?>) o).get();\r
+            if (obj == o)\r
+                return Collections.EMPTY_LIST;\r
+            return adaptToCollection(obj, clazz);\r
+        }\r
+        return Collections.EMPTY_LIST;\r
+    }\r
+       \r
+       public static <T> Collection<T> adaptToCollection(Object arr[], Class<T> clazz) {\r
+               Collection<T> result = new ArrayList<T>();\r
+               for (Object o : arr) {\r
+                       Collection<T> tColl = adaptToCollection(o, clazz); \r
+                       for (T t : tColl)\r
+                               if (t != null && !result.contains(t))\r
+                                       result.add(t);\r
+               }\r
+               return result;\r
+       }\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/tools/Constraint.java b/org.simantics.g3d/src/org/simantics/g3d/tools/Constraint.java
new file mode 100644 (file)
index 0000000..901eaf9
--- /dev/null
@@ -0,0 +1,20 @@
+package org.simantics.g3d.tools;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import javax.vecmath.Point3d;\r
+import javax.vecmath.Vector3d;\r
+\r
+public class Constraint {\r
+       \r
+       public Constraint() {\r
+               points = new ArrayList<Point3d>();\r
+               dirs = new ArrayList<Vector3d>();\r
+       }\r
+       \r
+       public List<Point3d> points;\r
+       public List<Vector3d> dirs;\r
+\r
+}\r
+\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/tools/ConstraintDetector.java b/org.simantics.g3d/src/org/simantics/g3d/tools/ConstraintDetector.java
new file mode 100644 (file)
index 0000000..e629753
--- /dev/null
@@ -0,0 +1,407 @@
+package org.simantics.g3d.tools;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import javax.vecmath.Point3d;\r
+import javax.vecmath.Vector3d;\r
+\r
+import org.simantics.g3d.math.MathTools;\r
+import org.simantics.g3d.scenegraph.IG3DNode;\r
+import org.simantics.g3d.shape.Color4d;\r
+\r
+public abstract class ConstraintDetector {\r
+    \r
+    private static final int X = 0;\r
+    private static final int Y = 1;\r
+    private static final int Z = 2;\r
+    \r
+    \r
+//    private ThreeDimensionalEditorBase editor;\r
+    //private G3DNode constraintReference = null;\r
+    private IG3DNode constraintReference = null;\r
+    private ArrayList<Point3d> constraintPoints = new ArrayList<Point3d>();\r
+    private ArrayList<Vector3d> constraintDirections = new ArrayList<Vector3d>();\r
+//    private MaterialState ms;\r
+    \r
+    private Color4d xColor = new Color4d(1.f,0.f,0.f,1.f);\r
+    private Color4d yColor = new Color4d(0.f,1.f,0.f,1.f);\r
+    private Color4d zColor = new Color4d(0.f,0.f,1.f,1.f);\r
+    \r
+    \r
+//    public ConstraintDetector(ThreeDimensionalEditorBase editor) {\r
+//        this.editor = editor;\r
+//        ms = editor.getRenderingComponent().getDisplaySystem().getRenderer().createMaterialState();\r
+//        ms.setEmissive(new ColorRGBA(1.f,1.f,1.f,1.f));\r
+//        ms.setColorMaterial(MaterialState.CM_EMISSIVE);\r
+//    }\r
+    \r
+\r
+    public void clearConstraints() {\r
+        //System.out.println("ConstraintDetector.clearConstraints()");\r
+        constraintPoints.clear();\r
+        constraintDirections.clear();\r
+    }\r
+    \r
+    private void updateConstraints() {\r
+        clearConstraints();\r
+        if (constraintReference == null)\r
+            return;\r
+        Constraint c = (Constraint)constraintReference.getAdapter(Constraint.class);\r
+        if (c == null)\r
+               return;\r
+        constraintPoints.addAll(c.points);\r
+        constraintDirections.addAll(c.dirs);\r
+    }\r
+    \r
+    \r
+    public ArrayList<Point3d> getConstraintPoints() {\r
+        return constraintPoints;\r
+    }\r
+    \r
+    public ArrayList<Vector3d> getConstraintDirections() {\r
+        return constraintDirections;\r
+    }\r
+\r
+    public void updateConstraintReference(IG3DNode node) {\r
+       if (constraintReference != null && !constraintReference.equals(node)) {\r
+               constraintReference = node;\r
+               updateConstraints();\r
+       } else if (node != null){\r
+               constraintReference = node;\r
+               updateConstraints();\r
+       }\r
+       \r
+    }\r
+    \r
+    public void addContraintPoint(Point3d p) {\r
+        //System.out.println("ConstraintDetector.addConstraintPoint() " + p);\r
+        constraintPoints.add(p);\r
+    }\r
+    \r
+    public void addContraintDirection(Vector3d v) {\r
+        //System.out.println("ConstraintDetector.addConstraintDirection() " + v);\r
+        constraintDirections.add(v);\r
+    }\r
+    \r
+    private double snapAngle = 0.1;\r
+    private String snapString = "";\r
+\r
+//    private ArrayList<Geometry> constraintHighlights = new ArrayList<Geometry>();\r
+    \r
+    public Point3d getSnappedPoint(Vector3d pickPoint, Vector3d pickDir, Vector3d requestedPoint) {\r
+        \r
+        \r
+        Vector3d snappedPoint = new Vector3d();\r
+        Vector3d t = new Vector3d();\r
+        Point3d currentPoint = null;\r
+        // TODO : snap to closest angle\r
+        for (Vector3d constraintDir : constraintDirections) {\r
+            \r
+            MathTools.intersectStraightStraight(pickPoint,pickDir, requestedPoint, constraintDir, t, snappedPoint);\r
+            t.sub(snappedPoint);\r
+            if (t.lengthSquared() < snapAngle) {\r
+                \r
+                snapString += "Angle snap ";\r
+                currentPoint = new Point3d(snappedPoint);\r
+                break;\r
+            }\r
+        }\r
+        if (currentPoint != null) {\r
+            Vector3d dir = new Vector3d(currentPoint);\r
+            dir.sub(requestedPoint);\r
+            Point3d p = getPointSnap(requestedPoint, dir);\r
+            if (p != null)\r
+                currentPoint = p;\r
+        } else {\r
+               List<Double> distances = new ArrayList<Double>();\r
+               List<Point3d> snapPoints = new ArrayList<Point3d>();\r
+               List<String> snapStrings = new ArrayList<String>();\r
+               List<Color4d> snapColors = new ArrayList<Color4d>();\r
+            for (Point3d constraintPoint : constraintPoints) {\r
+               distances.clear();\r
+               snapPoints.clear();\r
+               snapStrings.clear();\r
+                MathTools.intersectStraightStraight(new Vector3d(constraintPoint), new Vector3d(1.0, 0.0, 0.0),\r
+                        pickPoint, pickDir, snappedPoint, t);\r
+                t.sub(snappedPoint);\r
+                double distance = t.lengthSquared();\r
+                if (distance < snapAngle) {\r
+                       distances.add(distance);\r
+                       snapPoints.add(new Point3d(snappedPoint));\r
+                       snapStrings.add("Point x-snap ");\r
+                       snapColors.add(xColor);\r
+                }\r
+                MathTools.intersectStraightStraight(new Vector3d(constraintPoint), new Vector3d(0.0, 1.0, 0.0),\r
+                        pickPoint, pickDir, snappedPoint, t);\r
+                t.sub(snappedPoint);\r
+                distance = t.lengthSquared();\r
+                if (distance < snapAngle) {\r
+                       distances.add(distance);\r
+                       snapPoints.add(new Point3d(snappedPoint));\r
+                       snapStrings.add("Point y-snap ");\r
+                       snapColors.add(yColor);\r
+                }\r
+                MathTools.intersectStraightStraight(new Vector3d(constraintPoint), new Vector3d(0.0, 0.0, 1.0),\r
+                        pickPoint, pickDir, snappedPoint, t);\r
+                t.sub(snappedPoint);\r
+                distance = t.lengthSquared();\r
+                if (distance < snapAngle) {\r
+                       distances.add(distance);\r
+                       snapPoints.add(new Point3d(snappedPoint));\r
+                       snapStrings.add("Point z-snap ");\r
+                       snapColors.add(zColor);\r
+                    \r
+                }\r
+                if (distances.size() > 0) {\r
+                    if (distances.size() > 1) {\r
+                        // more than one axes snape\r
+                       Vector3d ref = MathTools.closestPointOnStraight(constraintPoint, new Point3d(pickPoint), pickDir);\r
+                       ref.sub(constraintPoint);\r
+                       distance = ref.lengthSquared();\r
+                       if (distance < snapAngle) {\r
+                               // we are close enought to point, so we'll just snap there\r
+                               currentPoint = new Point3d(constraintPoint);\r
+                               snapString += "Point snap ";\r
+                       } else {\r
+                               // select the closest of axes snap to\r
+                               int min = 0;\r
+                               for (int i = 1; i < distances.size(); i++) {\r
+                                       if (distances.get(i) < distances.get(min))\r
+                                               min = i;\r
+                               }\r
+                               currentPoint = snapPoints.get(min);\r
+                               addConstrainLineHighlight(currentPoint, constraintPoint,snapColors.get(min));\r
+                               snapString += snapStrings.get(min);\r
+                       }\r
+                    } else {\r
+                       // only one of the axes snaps\r
+                       currentPoint = snapPoints.get(0);\r
+                       addConstrainLineHighlight(currentPoint, constraintPoint,snapColors.get(0));\r
+                       snapString += snapStrings.get(0);\r
+                    }\r
+                    break;\r
+                }\r
+            }\r
+        }\r
+        return currentPoint;\r
+\r
+    }\r
+    \r
+    public abstract void clearConstraintHighlights();\r
+    protected abstract void addConstrainLineHighlight(Point3d p1, Point3d p2, Color4d color);\r
+    protected abstract void addConstrainPlaneHighlight(Point3d p1, Point3d p2, int axis);\r
+    \r
+//    public void clearConstraintHighlights() {\r
+//        snapString = "";\r
+//\r
+//        for (Geometry s : constraintHighlights)\r
+//            s.removeFromParent();\r
+//        \r
+//        constraintHighlights.clear();\r
+//    }\r
+//    \r
+//    private void addConstrainLineHighlight(Point3d p1, Point3d p2, Color4d color) {\r
+//\r
+//     float coord[] = new float[6];\r
+//     ColorRGBA colors[] = new ColorRGBA[2];\r
+//     colors[0] = color;\r
+//     colors[1] = color;\r
+//     coord[0] = (float)p1.x;\r
+//     coord[1] = (float)p1.y;\r
+//     coord[2] = (float)p1.z;\r
+//     coord[3] = (float)p2.x;\r
+//     coord[4] = (float)p2.y;\r
+//     coord[5] = (float)p2.z;\r
+//     Line shape = new Line("",BufferUtils.createFloatBuffer(coord),null,BufferUtils.createFloatBuffer(colors),null);\r
+//     editor.getRenderingComponent().getNoShadowRoot().attachChild(shape);\r
+//     shape.setRenderState(ms);\r
+//     constraintHighlights.add(shape);\r
+//    }\r
+//    \r
+//    private void addConstrainPlaneHighlight(Point3d p1, Point3d p2, int axis) {\r
+//\r
+//     float coord[] = new float[9];\r
+//     ColorRGBA colors[] = new ColorRGBA[3];\r
+//     coord[0] = (float)p1.x;\r
+//     coord[1] = (float)p1.y;\r
+//     coord[2] = (float)p1.z;\r
+//     switch (axis) {\r
+//     case X:\r
+//             coord[3] = (float)p1.x;\r
+//             coord[4] = (float)p1.y;\r
+//             coord[5] = (float)p2.z;\r
+//             colors[0] = colors[1] = colors[2] = xColor;\r
+//             break;\r
+//     case Y:\r
+//             coord[3] = (float)p1.x;\r
+//             coord[4] = (float)p1.y;\r
+//             coord[5] = (float)p2.z;\r
+//             colors[0] = colors[1] = colors[2] = yColor;\r
+//             break;\r
+//     case Z:\r
+//             coord[3] = (float)p1.x;\r
+//             coord[4] = (float)p2.y;\r
+//             coord[5] = (float)p2.z;\r
+//             colors[0] = colors[1] = colors[2] = zColor;\r
+//             break;\r
+//     \r
+//     }\r
+//     coord[6] = (float)p2.x;\r
+//     coord[7] = (float)p2.y;\r
+//     coord[8] = (float)p2.z;\r
+//     Line shape = new Line("",BufferUtils.createFloatBuffer(coord),null,BufferUtils.createFloatBuffer(colors),null);\r
+//     shape.setMode(Line.CONNECTED);\r
+//     editor.getRenderingComponent().getNoShadowRoot().attachChild(shape);\r
+//     shape.setRenderState(ms);\r
+//        constraintHighlights.add(shape);\r
+//    }\r
+    \r
+    /**\r
+     * Snaps position to axis-aligned planes defined by constraint points\r
+     * Form of position is p+v, meaning that the position that is snapped is requestedPoint + requestedDir\r
+     * @param requestedPoint one part of the position to be snapped\r
+     * @param requestedDir second part of the position to be snapped and direction that the position is allowed to move\r
+     * @return\r
+     */\r
+    public Point3d getPointSnap(Vector3d requestedPoint, Vector3d requestedDir) {\r
+        \r
+        Vector3d snappedPoint = new Vector3d();\r
+        Point3d currentPoint = null;\r
+        double u[] = new double[1];\r
+        List<Point3d> p1s = new ArrayList<Point3d>();\r
+        List<Point3d> p2s = new ArrayList<Point3d>();\r
+        List<Integer> axes = new ArrayList<Integer>();\r
+        \r
+        for (Point3d constraintPoint : constraintPoints) {\r
+            boolean snap = false;\r
+            \r
+            if (MathTools.intersectStraightPlane(requestedPoint, requestedDir, new Vector3d(constraintPoint), getAxialVector(X), snappedPoint,u) && Math.abs(1.0 - u[0]) < snapAngle) {\r
+                currentPoint = new Point3d(snappedPoint);\r
+                //snapString += "Point/Plane x-snap ";\r
+                snap = true;\r
+                //addConstrainPlaneHighlight(constraintPoint, currentPoint,X);\r
+                p1s.add(constraintPoint);\r
+                p2s.add(currentPoint);\r
+                axes.add(X);\r
+            }\r
+            \r
+            if (MathTools.intersectStraightPlane(requestedPoint, requestedDir, new Vector3d(constraintPoint), getAxialVector(Y), snappedPoint,u) && Math.abs(1.0 - u[0]) < snapAngle) {\r
+                currentPoint = new Point3d(snappedPoint);\r
+                //snapString += "Point/Plane y-snap ";\r
+                snap = true;\r
+                //addConstrainPlaneHighlight(constraintPoint, currentPoint,Y);\r
+                p1s.add(constraintPoint);\r
+                p2s.add(currentPoint);\r
+                axes.add(Y);\r
+            }\r
+            \r
+            if (MathTools.intersectStraightPlane(requestedPoint, requestedDir, new Vector3d(constraintPoint), getAxialVector(Z), snappedPoint,u) && Math.abs(1.0 - u[0]) < snapAngle) {\r
+                currentPoint = new Point3d(snappedPoint);\r
+                //snapString += "Point/Plane z-snap ";\r
+                snap = true;\r
+                //addConstrainPlaneHighlight(constraintPoint, currentPoint,Z);\r
+                p1s.add(constraintPoint);\r
+                p2s.add(currentPoint);\r
+                axes.add(Z);\r
+            }\r
+            if (snap)\r
+                break;\r
+        }\r
+        if (p1s.size() == 0)\r
+               return null;\r
+        if (p1s.size() == 1) {\r
+               snapString += "Point/Plane ";\r
+               switch (axes.get(0)) {\r
+               case X:\r
+                       snapString += "x";\r
+                       break;\r
+               case Y:\r
+                       snapString += "y";\r
+                       break;\r
+               case Z:\r
+                       snapString += "z";\r
+                       break;\r
+               }\r
+               snapString += "-snap ";\r
+               addConstrainPlaneHighlight(p1s.get(0), p2s.get(0),axes.get(0));\r
+               return currentPoint;\r
+        } else if (p1s.size() == 3){\r
+               // all axial planes are intersecting, snapping point must be the constraint point\r
+               // all constraint points are the same, so just pick the first in the list\r
+               snapString += "Point/Point ";\r
+               return p1s.get(0);\r
+        } else {\r
+               Vector3d dir = new Vector3d();\r
+               dir.cross(getAxialVector(axes.get(0)), getAxialVector(axes.get(1)));\r
+               currentPoint = new Point3d(MathTools.closestPointOnStraight(currentPoint, p1s.get(0), dir));\r
+               addConstrainLineHighlight(p1s.get(0), currentPoint, xColor);\r
+               snapString += "Point/Line ";\r
+               return currentPoint;\r
+        }\r
+        \r
+    }\r
+    \r
+    private Vector3d getAxialVector(int axis) {\r
+       switch (axis) {\r
+       case X:\r
+               return new Vector3d(1.0,0.0,0.0);\r
+       case Y:\r
+               return new Vector3d(0.0,1.0,0.0);\r
+       case Z:\r
+               return new Vector3d(0.0,0.0,1.0);\r
+       }\r
+       throw new RuntimeException("Unknown axis " + axis);     \r
+    }\r
+    \r
+    /**\r
+     * Snaps the position to axis-aligned planes defined by constraint points\r
+     * @param requestedPoint point that is snapped\r
+     * @param requestedDir direction that point is allowed to move\r
+     * @return\r
+     */\r
+    \r
+    public Point3d getPointSnap2(Vector3d requestedPoint, Vector3d requestedDir) {\r
+        \r
+        Vector3d snappedPoint = new Vector3d();\r
+        Point3d currentPoint = null;\r
+        double u[] = new double[1];\r
+        //System.out.println(requestedPoint + "  " + requestedDir);\r
+        for (Point3d constraintPoint : constraintPoints) {\r
+            boolean snap = false;\r
+            //System.out.print(constraintPoint + " ");\r
+            if (MathTools.intersectStraightPlane(requestedPoint, requestedDir, new Vector3d(constraintPoint), new Vector3d(1.0,0.0,0.0), snappedPoint,u) && Math.abs(u[0]) < snapAngle) {\r
+                currentPoint = new Point3d(snappedPoint);\r
+                snapString += "Point/Plane x-snap ";\r
+                snap = true;\r
+                addConstrainPlaneHighlight(constraintPoint, currentPoint,X);\r
+                //System.out.print(" x " + u[0]);\r
+            }\r
+            \r
+            if (MathTools.intersectStraightPlane(requestedPoint, requestedDir, new Vector3d(constraintPoint), new Vector3d(0.0,1.0,0.0), snappedPoint,u) && Math.abs(u[0]) < snapAngle) {\r
+                currentPoint = new Point3d(snappedPoint);\r
+                snapString += "Point/Plane y-snap ";\r
+                snap = true;\r
+                addConstrainPlaneHighlight(constraintPoint, currentPoint,Y);\r
+                //System.out.print(" y " + u[0]);\r
+            }\r
+           \r
+            \r
+            if (MathTools.intersectStraightPlane(requestedPoint, requestedDir, new Vector3d(constraintPoint), new Vector3d(0.0,0.0,1.0), snappedPoint,u) && Math.abs(u[0]) < snapAngle) {\r
+                currentPoint = new Point3d(snappedPoint);\r
+                snapString += "Point/Plane z-snap ";\r
+                snap = true;\r
+                addConstrainPlaneHighlight(constraintPoint, currentPoint,Z);\r
+                //System.out.print(" z " + u[0]);\r
+            }\r
+            //System.out.println();\r
+            if (snap)\r
+                break;\r
+        }\r
+        return currentPoint;\r
+    }\r
+    \r
+    public String getSnapString() {\r
+        return snapString;\r
+    }\r
+}
\ No newline at end of file
diff --git a/org.simantics.g3d/src/org/simantics/g3d/tools/DummyConstraintDetector.java b/org.simantics.g3d/src/org/simantics/g3d/tools/DummyConstraintDetector.java
new file mode 100644 (file)
index 0000000..b79a91c
--- /dev/null
@@ -0,0 +1,24 @@
+package org.simantics.g3d.tools;\r
+\r
+import javax.vecmath.Point3d;\r
+\r
+import org.simantics.g3d.shape.Color4d;\r
+\r
+public class DummyConstraintDetector extends ConstraintDetector {\r
+       \r
+       @Override\r
+       protected void addConstrainLineHighlight(Point3d p1, Point3d p2, Color4d color) {\r
+               \r
+       }\r
+       \r
+       @Override\r
+       protected void addConstrainPlaneHighlight(Point3d p1, Point3d p2, int axis) {\r
+               \r
+       }\r
+       \r
+       @Override\r
+       public void clearConstraintHighlights() {\r
+       \r
+       }\r
+\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/tools/NodeTools.java b/org.simantics.g3d/src/org/simantics/g3d/tools/NodeTools.java
new file mode 100644 (file)
index 0000000..233fbac
--- /dev/null
@@ -0,0 +1,125 @@
+package org.simantics.g3d.tools;\r
+\r
+import javax.vecmath.Matrix4d;\r
+import javax.vecmath.Quat4d;\r
+import javax.vecmath.Vector3d;\r
+\r
+import org.simantics.g3d.math.MathTools;\r
+import org.simantics.g3d.scenegraph.IG3DNode;\r
+\r
+public class NodeTools {\r
+\r
+       public static Vector3d getWorldPosition(IG3DNode node, Vector3d localPosition) {\r
+               Vector3d v = new Vector3d(localPosition);\r
+               MathTools.rotate(node.getOrientation(), v, v);\r
+               v.add(node.getPosition());\r
+               \r
+               IG3DNode parent = (IG3DNode)node.getParent();\r
+               if (parent == null)\r
+                       return v;\r
+               return getWorldPosition(parent,v);\r
+       }\r
+       \r
+       public static Vector3d getWorldPosition(IG3DNode node) {\r
+               IG3DNode parent = (IG3DNode)node.getParent();\r
+               if (parent == null)\r
+                       return node.getPosition();\r
+               return NodeTools.getWorldPosition(parent,new Vector3d(node.getPosition()));\r
+       }\r
+       \r
+       public static Quat4d getWorldOrientation(IG3DNode node, Quat4d localOrientation) {\r
+               Quat4d q = new Quat4d();\r
+               q.set(node.getOrientation());\r
+               Quat4d q2 = new Quat4d();\r
+               q2.set(localOrientation);\r
+               q.mul(q2);\r
+               \r
+               IG3DNode parent = (IG3DNode)node.getParent();\r
+               if (parent == null)\r
+                       return q;\r
+               return getWorldOrientation(parent,q);\r
+       }\r
+       \r
+       public static Quat4d getWorldOrientation(IG3DNode node) {\r
+               IG3DNode parent = (IG3DNode)node.getParent();\r
+               if (parent == null)\r
+                       return node.getOrientation();\r
+               return NodeTools.getWorldOrientation(parent, node.getOrientation());\r
+       }\r
+       \r
+       \r
+       public static Vector3d getLocalPosition(IG3DNode node, Vector3d worldCoord)  {\r
+       \r
+               IG3DNode parent = (IG3DNode)node.getParent();\r
+        if (parent == null) {// this is a root node ( has no transformation) \r
+               return worldCoord;\r
+        }\r
+\r
+        Vector3d local = getLocalPosition(parent,worldCoord);\r
+        local.sub(node.getPosition());\r
+        \r
+        Quat4d q = new Quat4d();\r
+        q.set(node.getOrientation());\r
+        q.inverse();\r
+        MathTools.rotate(q, local, local);\r
+        \r
+        return local;\r
+    }\r
+       \r
+       public static Quat4d getLocalOrientation(IG3DNode node, Quat4d worldRot)  {\r
+\r
+               IG3DNode parent = (IG3DNode) node.getParent();\r
+               if (parent == null) // this is a rootnode ( has no transformation)\r
+                       return worldRot;\r
+               Quat4d local = getLocalOrientation(parent, worldRot);\r
+               Quat4d q = new Quat4d();\r
+               q.set(node.getOrientation());\r
+               q.inverse();\r
+               Quat4d q2 = new Quat4d();\r
+               q2.set(local);\r
+               q.mul(q2);\r
+               local.set(q);\r
+\r
+               return local;\r
+       }\r
+       \r
+       public static Matrix4d getWorldTransformation(IG3DNode node) {\r
+               Vector3d pos = node.getWorldPosition();\r
+               Quat4d q = node.getWorldOrientation();\r
+               \r
+               Matrix4d m1 = new Matrix4d();\r
+               Matrix4d m2 = new Matrix4d();\r
+               m1.set(pos);\r
+               m2.set(q);\r
+               m1.mul(m2);\r
+               return m1;\r
+       }\r
+       \r
+       public static Matrix4d getWorldOrientationMat(IG3DNode node) {\r
+               Quat4d q = node.getWorldOrientation();\r
+               \r
+               Matrix4d m2 = new Matrix4d();\r
+               m2.set(q);\r
+               return m2;\r
+       }\r
+       \r
+       public static Vector3d getPosition(IG3DNode relative, IG3DNode node) {\r
+               Vector3d wp = getWorldPosition(node);\r
+               return getLocalPosition(relative, wp);\r
+       }\r
+       \r
+       public static Quat4d getOrientation(IG3DNode relative, IG3DNode node) {\r
+               Quat4d wo = getWorldOrientation(node);\r
+               return getLocalOrientation(relative, wo);\r
+       }\r
+       \r
+       public static void setPosition(IG3DNode relative, IG3DNode node, Vector3d position) {\r
+               Vector3d wp = getWorldPosition(relative,position);\r
+               node.setWorldPosition(wp);\r
+       }\r
+       \r
+       public static void setOrientation(IG3DNode relative, IG3DNode node, Quat4d orientation) {\r
+               Quat4d wo = getWorldOrientation(relative,orientation);\r
+               node.setWorldOrientation(wo);\r
+       }\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/tools/PluginTools.java b/org.simantics.g3d/src/org/simantics/g3d/tools/PluginTools.java
new file mode 100644 (file)
index 0000000..d20fa85
--- /dev/null
@@ -0,0 +1,28 @@
+package org.simantics.g3d.tools;\r
+\r
+import java.io.File;\r
+import java.net.URL;\r
+\r
+import org.eclipse.core.runtime.FileLocator;\r
+import org.eclipse.core.runtime.IPath;\r
+import org.eclipse.core.runtime.Path;\r
+import org.osgi.framework.Bundle;\r
+\r
+public class PluginTools {\r
+       \r
+        public static String getAbsolutePath(Bundle inBundle, String fullpath) {\r
+               IPath path = new Path(fullpath);\r
+               URL u = FileLocator.find(inBundle, path, null);\r
+               if (u != null) {\r
+                   try {\r
+                       u = FileLocator.resolve(u);\r
+                       if ("file".equals(u.getProtocol())) {\r
+                           return new File(u.getFile()).getAbsolutePath();\r
+                       }\r
+                   } catch (Exception e) {\r
+                   }\r
+               }\r
+               return null;\r
+           }\r
+\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/ui/SceneGraphDebugger.java b/org.simantics.g3d/src/org/simantics/g3d/ui/SceneGraphDebugger.java
new file mode 100644 (file)
index 0000000..1eb4b31
--- /dev/null
@@ -0,0 +1,217 @@
+package org.simantics.g3d.ui;\r
+\r
+import org.eclipse.jface.layout.TreeColumnLayout;\r
+import org.eclipse.jface.viewers.CellLabelProvider;\r
+import org.eclipse.jface.viewers.ColumnWeightData;\r
+import org.eclipse.jface.viewers.TreeViewer;\r
+import org.eclipse.jface.viewers.TreeViewerColumn;\r
+import org.eclipse.jface.viewers.ViewerCell;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.ui.IPartListener2;\r
+import org.eclipse.ui.IPartService;\r
+import org.eclipse.ui.IWorkbenchPage;\r
+import org.eclipse.ui.IWorkbenchPart;\r
+import org.eclipse.ui.IWorkbenchPartReference;\r
+import org.eclipse.ui.IWorkbenchWindow;\r
+import org.eclipse.ui.part.ViewPart;\r
+import org.simantics.g3d.scenegraph.base.INode;\r
+import org.simantics.objmap.graph.IMapping;\r
+import org.simantics.objmap.structural.IStructuralObject;\r
+\r
+public class SceneGraphDebugger extends ViewPart {\r
+\r
+       private TreeViewer viewer;\r
+       \r
+       private boolean linkToPart = true;\r
+       \r
+       IWorkbenchPart       lastPart;\r
+       \r
+       private IMapping<Object, Object> mapping;\r
+       \r
+       public SceneGraphDebugger() {\r
+               // TODO Auto-generated constructor stub\r
+       }\r
+\r
+       @Override\r
+       public void createPartControl(Composite parent) {\r
+\r
+               viewer = new TreeViewer(parent,SWT.SINGLE|SWT.FULL_SELECTION);\r
+\r
+               TreeColumnLayout layout = new TreeColumnLayout();\r
+        parent.setLayout(layout);\r
+        \r
+        viewer.setContentProvider(new ScenegraphOutlinePage.ScenegraphContentProvider());\r
+        viewer.getTree().setHeaderVisible(true);\r
+        \r
+        TreeViewerColumn nameColumn = new TreeViewerColumn(viewer, SWT.LEFT);\r
+        nameColumn.setLabelProvider(new CellLabelProvider() {\r
+                       \r
+                       @Override\r
+                       public void update(ViewerCell cell) {\r
+                               cell.setText(cell.getElement().toString());\r
+                       }\r
+               });\r
+        \r
+        TreeViewerColumn typeColumn = new TreeViewerColumn(viewer, SWT.LEFT);\r
+        typeColumn.setLabelProvider(new CellLabelProvider() {\r
+                       \r
+                       @Override\r
+                       public void update(ViewerCell cell) {\r
+                               cell.setText(cell.getElement().getClass().getSimpleName());\r
+                       }\r
+               });\r
+        \r
+        TreeViewerColumn contextColumn = new TreeViewerColumn(viewer, SWT.LEFT);\r
+        contextColumn.setLabelProvider(new CellLabelProvider() {\r
+                       \r
+                       @Override\r
+                       public void update(ViewerCell cell) {\r
+                               if (!(cell.getElement() instanceof IStructuralObject))\r
+                                       cell.setText("N/A");\r
+                               else {\r
+                                       IStructuralObject o = (IStructuralObject)cell.getElement();\r
+                                       if (o.getContext() != null) {\r
+                                               cell.setText(o.getContext().toString());\r
+                                       } else {\r
+                                               cell.setText("none");\r
+                                       }\r
+                                       \r
+                               }\r
+                                       \r
+                       }\r
+               });\r
+        \r
+        TreeViewerColumn mappingColumn = new TreeViewerColumn(viewer, SWT.LEFT);\r
+        mappingColumn.setLabelProvider(new CellLabelProvider() {\r
+                       \r
+                       @Override\r
+                       public void update(ViewerCell cell) {\r
+                               if (mapping == null)\r
+                                       cell.setText("N/A");\r
+                               else {\r
+                                       Object o = mapping.inverseGet(cell.getElement());\r
+                                       if (o != null) {\r
+                                               cell.setText(o.toString());\r
+                                       } else {\r
+                                               cell.setText("none");\r
+                                       }\r
+                                       \r
+                               }\r
+                                       \r
+                       }\r
+               });\r
+        \r
+        nameColumn.getColumn().setText("Name");\r
+        typeColumn.getColumn().setText("Type");\r
+        contextColumn.getColumn().setText("Context");\r
+        mappingColumn.getColumn().setText("Mapping");\r
+        \r
+        layout.setColumnData(nameColumn.getColumn(), new ColumnWeightData(10, true));\r
+        layout.setColumnData(typeColumn.getColumn(), new ColumnWeightData(10, true));\r
+        layout.setColumnData(contextColumn.getColumn(), new ColumnWeightData(10, true));\r
+        layout.setColumnData(mappingColumn.getColumn(), new ColumnWeightData(10, true));\r
+        \r
+        IPartService partService = (IPartService) getSite().getService(IPartService.class);\r
+        partService.addPartListener(partListener);\r
+        \r
+       }\r
+\r
+       @Override\r
+       public void setFocus() {\r
+               viewer.getTree().setFocus();\r
+       }\r
+       \r
+       protected void refresh() {\r
+        IWorkbenchPart part = null;\r
+        try {\r
+            IWorkbenchWindow window = getSite().getWorkbenchWindow();\r
+            if (window == null)\r
+                return;\r
+            IWorkbenchPage page = window.getActivePage();\r
+            if (page == null)\r
+                return;\r
+            part = page.getActiveEditor();\r
+            if (part == null)\r
+                return;\r
+        } finally {\r
+            if (part == null) {\r
+                setContentDescription("No scene graph nodes available.");\r
+                // TODO: Show info page instead of tree view.\r
+            }\r
+        }\r
+\r
+        refresh(part);\r
+    }\r
+       \r
+        @SuppressWarnings({ "unchecked", "rawtypes" })\r
+       protected boolean refresh(IWorkbenchPart part) {\r
+                if (viewer.getTree().isDisposed()) {\r
+                        IPartService partService = (IPartService) getSite().getService(IPartService.class);\r
+                        partService.removePartListener(partListener);\r
+                       return false;\r
+               }\r
+               boolean foundInput = false;\r
+               try {\r
+                   Object obj = null;\r
+                   if (part != null) {\r
+                       obj = part.getAdapter(INode.class);\r
+                   }\r
+\r
+                   if (obj != null) {\r
+                       mapping = (IMapping)part.getAdapter(IMapping.class);\r
+                       if (!viewer.getTree().isDisposed())\r
+                               viewer.setInput(obj);\r
+                       foundInput = true;\r
+                   }\r
+                   lastPart = part;\r
+                   return foundInput;\r
+               } finally {\r
+                   if (!foundInput) {\r
+                       setContentDescription("No scene graph nodes available.");\r
+                       // TODO: Show info page instead of tree view.\r
+                   }\r
+               }\r
+           }\r
+       \r
+        IPartListener2 partListener = new IPartListener2() {\r
+               @Override\r
+               public void partVisible(IWorkbenchPartReference partRef) {\r
+               }\r
+               @Override\r
+               public void partOpened(IWorkbenchPartReference partRef) {\r
+               }\r
+               @Override\r
+               public void partInputChanged(IWorkbenchPartReference partRef) {\r
+               }\r
+               @Override\r
+               public void partHidden(IWorkbenchPartReference partRef) {\r
+               }\r
+               @Override\r
+               public void partDeactivated(IWorkbenchPartReference partRef) {\r
+               }\r
+               @Override\r
+               public void partClosed(IWorkbenchPartReference partRef) {\r
+                   if (linkToPart) {\r
+                       IWorkbenchPart part = partRef.getPart(false);\r
+                       if (part != null)\r
+                           refresh(null);\r
+                   }\r
+               }\r
+               @Override\r
+               public void partBroughtToTop(IWorkbenchPartReference partRef) {\r
+               }\r
+               @Override\r
+               public void partActivated(IWorkbenchPartReference partRef) {\r
+                   if (linkToPart) {\r
+                       IWorkbenchPart part = partRef.getPart(false);\r
+                       if (part != null) {\r
+                           if (part != lastPart) {\r
+                               refresh(part);\r
+                           }\r
+                       }\r
+                   }\r
+               }\r
+           };\r
+\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/ui/ScenegraphOutlinePage.java b/org.simantics.g3d/src/org/simantics/g3d/ui/ScenegraphOutlinePage.java
new file mode 100644 (file)
index 0000000..71e1c68
--- /dev/null
@@ -0,0 +1,195 @@
+package org.simantics.g3d.ui;\r
+\r
+import java.util.HashSet;\r
+import java.util.Set;\r
+\r
+import org.eclipse.jface.viewers.ITreeContentProvider;\r
+import org.eclipse.jface.viewers.LabelProvider;\r
+import org.eclipse.jface.viewers.TreeViewer;\r
+import org.eclipse.jface.viewers.Viewer;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.swt.widgets.Display;\r
+import org.eclipse.ui.views.contentoutline.ContentOutlinePage;\r
+import org.simantics.g3d.scenegraph.base.INode;\r
+import org.simantics.g3d.scenegraph.base.NodeListener;\r
+import org.simantics.g3d.scenegraph.base.ParentNode;\r
+\r
+public class ScenegraphOutlinePage extends ContentOutlinePage implements NodeListener {\r
+       \r
+       private ParentNode<? extends INode> rootNode;\r
+       \r
+       public ScenegraphOutlinePage(ParentNode<? extends INode> rootNode) {\r
+               if (rootNode == null)\r
+                       throw new NullPointerException();\r
+               this.rootNode = rootNode;\r
+       }\r
+\r
+       \r
+       @Override\r
+       public void createControl(Composite parent) {\r
+               super.createControl(parent);\r
+               if (rootNode == null)\r
+                       return;\r
+               TreeViewer viewer = getTreeViewer();\r
+               createProviders(viewer);\r
+               viewer.setInput(rootNode);\r
+               listen(rootNode);\r
+       }\r
+       \r
+       protected void createProviders(TreeViewer viewer) {\r
+               viewer.setContentProvider(new ScenegraphContentProvider());\r
+               viewer.setLabelProvider(new ScenegraphLabelProvider());\r
+       }\r
+       \r
+       \r
+       \r
+       @SuppressWarnings("unchecked")\r
+       protected void listen(INode node) {\r
+               node.addListener(this);\r
+               if (node instanceof ParentNode<?>) {\r
+                       ParentNode<INode> parentNode = (ParentNode<INode>)node;\r
+                       for (INode n : parentNode.getNodes())\r
+                               listen(n);\r
+               }\r
+       }\r
+       \r
+       @SuppressWarnings("unchecked")\r
+       protected void stopListening(INode node) {\r
+               node.removeListener(this);\r
+               if (node instanceof ParentNode<?>) {\r
+                       ParentNode<INode> parentNode = (ParentNode<INode>)node;\r
+                       for (INode n : parentNode.getNodes())\r
+                               stopListening(n);\r
+               }\r
+       }\r
+       \r
+       @Override\r
+       public void propertyChanged(INode node, String id) {\r
+               refershViewer(node);\r
+       }\r
+       \r
+       @Override\r
+       public <T extends INode> void nodeAdded(ParentNode<T> node, INode child,\r
+                       String rel) {\r
+               listen(child);\r
+               refershViewer(node);\r
+       }\r
+       \r
+       \r
+       \r
+       @Override\r
+       public <T extends INode> void nodeRemoved(ParentNode<T> node, INode child,\r
+                       String rel) {\r
+               stopListening(child);\r
+               refershViewer(node);\r
+       }\r
+       \r
+       //private Queue<INode> toRefresh = new LinkedList<INode>();\r
+       private Set<INode> toRefresh = new HashSet<INode>();\r
+       private NodeUpdater updater;\r
+       \r
+       protected void refershViewer(final INode node) {\r
+               if (getTreeViewer() == null)\r
+                       return;\r
+               synchronized (toRefresh) {\r
+                       toRefresh.add(node);\r
+                       if (updater != null)\r
+                               return;\r
+               }\r
+               \r
+               updater = new NodeUpdater();\r
+               Display.getDefault().asyncExec(updater);\r
+       }\r
+       \r
+       private class NodeUpdater implements Runnable {\r
+               @Override\r
+               public void run() {\r
+                       if (getTreeViewer().getTree().isDisposed()) {\r
+                               updater =null;\r
+                               return;\r
+                       }\r
+                       int count = 0;\r
+                       // limit the amount of refreshes.\r
+                       while (count < 100) {\r
+                               INode node = null;\r
+                               synchronized (toRefresh) {\r
+                                       // if the queue becomes too long, refresh the whole tree\r
+//                                     if (toRefresh.size() > 100) {\r
+//                                             toRefresh.clear();\r
+//                                             getTreeViewer().refresh();\r
+//                                             updater = null;\r
+//                                             return;\r
+//                                     }\r
+                                       \r
+                                       //node = toRefresh.poll();\r
+                                       if (toRefresh.size() > 0) {\r
+                                               node = toRefresh.iterator().next();\r
+                                               toRefresh.remove(node);\r
+                                       }\r
+                                       if (node == null) {\r
+                                               updater = null;\r
+                                               return;\r
+                                       }\r
+                               }\r
+                               getTreeViewer().refresh(node);\r
+                               count++;\r
+                       }\r
+                       if (toRefresh.size() > 0) {\r
+                               Display.getDefault().asyncExec(this);\r
+                       }\r
+               }\r
+       }\r
+       \r
+       public static class ScenegraphContentProvider implements ITreeContentProvider {\r
+               \r
+               public ScenegraphContentProvider() {\r
+                       \r
+               }\r
+               \r
+               @Override\r
+               public Object[] getChildren(Object parentElement) {\r
+                       if (parentElement instanceof ParentNode<?>) {\r
+                               ParentNode<?> parentNode = (ParentNode<?>)parentElement;\r
+                               return parentNode.getNodes().toArray();\r
+                       }\r
+                       return new Object[0];\r
+               }\r
+               \r
+               @Override\r
+               public Object[] getElements(Object inputElement) {\r
+                       return getChildren(inputElement);\r
+               }\r
+               \r
+               @Override\r
+               public Object getParent(Object element) {\r
+                       if (element instanceof INode) {\r
+                               INode node = (INode) element;\r
+                               return node.getParent();\r
+                       }\r
+                       return null;\r
+               }\r
+               \r
+               @Override\r
+               public boolean hasChildren(Object element) {\r
+                       if (element instanceof ParentNode<?>) {\r
+                               ParentNode<?> parentNode = (ParentNode<?>)element;\r
+                               return parentNode.getNodes().size() > 0;\r
+                       }\r
+                       return false;\r
+               }\r
+               \r
+               @Override\r
+               public void dispose() {\r
+                       \r
+               }\r
+               \r
+               @Override\r
+               public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {\r
+                       \r
+               }\r
+       }\r
+       \r
+       public class ScenegraphLabelProvider extends LabelProvider {\r
+               \r
+       }\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/wizard/IExportModel.java b/org.simantics.g3d/src/org/simantics/g3d/wizard/IExportModel.java
new file mode 100644 (file)
index 0000000..f313d23
--- /dev/null
@@ -0,0 +1,60 @@
+package org.simantics.g3d.wizard;\r
+\r
+import java.io.File;\r
+import java.util.Deque;\r
+\r
+import org.simantics.db.common.NamedResource;\r
+\r
+public abstract class IExportModel {\r
+       \r
+       File            exportLocation;\r
+       NamedResource model;\r
+       boolean overwrite;\r
+       \r
+       Deque<String>   recentLocations;\r
+       \r
+       Object          selection;\r
+       \r
+       public void setModel(NamedResource model) {\r
+               this.model = model;\r
+       }\r
+       \r
+       public NamedResource getModel() {\r
+               return model;\r
+       }\r
+       \r
+       public void setOverwrite(boolean overwrite) {\r
+               this.overwrite = overwrite;\r
+       }\r
+       \r
+       public boolean isOverwrite() {\r
+               return overwrite;\r
+       }\r
+\r
+       \r
+       public void setExportLocation(File exportLocation) {\r
+               this.exportLocation = exportLocation;\r
+       }\r
+       \r
+       public File getExportLocation() {\r
+               return exportLocation;\r
+       }\r
+       \r
+       public abstract boolean usesFile();\r
+       \r
+       public Deque<String> getRecentLocations() {\r
+               return recentLocations;\r
+       }\r
+       \r
+       public void setRecentLocations(Deque<String> recentLocations) {\r
+               this.recentLocations = recentLocations;\r
+       }\r
+       \r
+       public Object getSelection() {\r
+               return selection;\r
+       }\r
+       \r
+       public void setSelection(Object selection) {\r
+               this.selection = selection;\r
+       }\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/wizard/ModelExportWizard.java b/org.simantics.g3d/src/org/simantics/g3d/wizard/ModelExportWizard.java
new file mode 100644 (file)
index 0000000..27214c9
--- /dev/null
@@ -0,0 +1,215 @@
+package org.simantics.g3d.wizard;\r
+\r
+import java.io.File;\r
+import java.io.IOException;\r
+import java.lang.reflect.InvocationTargetException;\r
+import java.util.Deque;\r
+import java.util.Iterator;\r
+import java.util.LinkedList;\r
+import java.util.Set;\r
+import java.util.TreeSet;\r
+\r
+import org.eclipse.jface.dialogs.MessageDialog;\r
+import org.eclipse.jface.operation.IRunnableWithProgress;\r
+import org.eclipse.jface.preference.IPersistentPreferenceStore;\r
+import org.eclipse.jface.preference.IPreferenceStore;\r
+import org.eclipse.jface.viewers.IStructuredSelection;\r
+import org.eclipse.jface.wizard.Wizard;\r
+import org.eclipse.jface.wizard.WizardPage;\r
+import org.eclipse.ui.IExportWizard;\r
+import org.eclipse.ui.IMemento;\r
+import org.eclipse.ui.IWorkbench;\r
+import org.simantics.db.management.ISessionContext;\r
+import org.simantics.project.IProject;\r
+import org.simantics.project.ProjectKeys;\r
+import org.simantics.ui.SimanticsUI;\r
+import org.simantics.utils.ui.ErrorLogger;\r
+import org.simantics.utils.ui.ExceptionUtils;\r
+import org.simantics.utils.ui.workbench.StringMemento;\r
+\r
+public abstract class ModelExportWizard<T extends IExportModel> extends Wizard implements IExportWizard {\r
+       \r
+       private static final int MAX_RECENT_EXPORT_PATHS = 10;\r
+       Deque<String>            recentExportPaths;\r
+    boolean                  overwrite;\r
+    \r
+    T exportModel;\r
+   \r
+    protected abstract  T createExportModel(Deque<String> recentExportPaths);\r
+    \r
+    protected abstract ModelExportWizardPage<T> createExportPage(T exportModel);\r
+    \r
+    protected abstract IPersistentPreferenceStore getPreferenceStore();\r
+    \r
+    protected abstract IRunnableWithProgress createExportRunnable(T exportModel);\r
+    \r
+    protected abstract String getExportLocationId();\r
+    protected abstract String getExportOverwriteId();\r
+    \r
+    @Override\r
+       public void init(IWorkbench workbench, IStructuredSelection selection) {\r
+               readPreferences();\r
+\r
+        ISessionContext ctx = SimanticsUI.getSessionContext();\r
+        if (ctx == null)\r
+            return;\r
+        IProject project = ctx.getHint(ProjectKeys.KEY_PROJECT);\r
+        if (project == null)\r
+            return;\r
+        \r
+        exportModel = createExportModel(recentExportPaths);\r
+        exportModel.setSelection(selection.getFirstElement());\r
+        exportModel.setOverwrite(overwrite);\r
+       }\r
+    \r
+    @Override\r
+       public void addPages() {\r
+               super.addPages();\r
+               if (exportModel != null) {\r
+                       addPage(createExportPage(exportModel));\r
+               }\r
+       }\r
+    \r
+    \r
+    \r
+       @Override\r
+       public boolean performFinish() {\r
+        try {\r
+            recentExportPaths.addFirst(exportModel.getExportLocation().getAbsolutePath());\r
+            removeDuplicates(recentExportPaths);\r
+            if (recentExportPaths.size() > MAX_RECENT_EXPORT_PATHS)\r
+                recentExportPaths.pollLast();\r
+\r
+            writePreferences();\r
+        } catch (IOException e) {\r
+            ErrorLogger.defaultLogError("Failed to write preferences", e);\r
+        }\r
+        \r
+        if (exportModel.usesFile()) {\r
+\r
+               File outputFile = exportModel.getExportLocation();\r
+               \r
+               if (outputFile.exists()) {\r
+                       if (!outputFile.isFile()) {\r
+                               MessageDialog.openError(getShell(), "File Problem", "Output target is not a file " + outputFile.getAbsolutePath());\r
+                       return false;\r
+                       }\r
+                       if (!exportModel.isOverwrite()) {\r
+                               boolean ok = MessageDialog.openConfirm(getShell(), "Overwrite", "A file by the name " + outputFile.getAbsolutePath() + " contains files.\n\nDo you want to overwrite the files?");\r
+                               if (!ok) {\r
+                                       return false;\r
+                               }\r
+                               if (!outputFile.delete()) {\r
+                                       MessageDialog.openError(getShell(), "Delete Problem", "Could not overwrite previously existing file " + outputFile.getAbsolutePath());\r
+                         return false;\r
+                               }\r
+                       }\r
+               } \r
+        } else {\r
+               File outputFolder = exportModel.getExportLocation();\r
+            \r
+            if (outputFolder.exists()) {\r
+               if (!outputFolder.isDirectory()) {\r
+                       MessageDialog.openError(getShell(), "Folder Problem", "Output target is not a folder " + outputFolder.getAbsolutePath());\r
+                    return false;\r
+               }\r
+               String files[] = outputFolder.list();\r
+               if (files.length > 0) {\r
+                       if (!exportModel.isOverwrite()) {\r
+                               boolean ok = MessageDialog.openConfirm(getShell(), "Overwrite", "A folder by the name " + outputFolder.getAbsolutePath() + " contains files.\n\nDo you want to overwrite the files?");\r
+                               if (!ok) {\r
+                                       return false;\r
+                               }\r
+                       }\r
+                }\r
+\r
+            } else {\r
+               if (!outputFolder.mkdir()) {\r
+                       MessageDialog.openError(getShell(), "Folder Problem", "Could not create new folder " + outputFolder);\r
+                    return false;\r
+               }\r
+            }\r
+        }\r
+\r
+        try {\r
+            getContainer().run(true, true,createExportRunnable(exportModel));\r
+        } catch (InvocationTargetException e) {\r
+            Throwable t = e.getTargetException();\r
+            WizardPage cp = (WizardPage) getContainer().getCurrentPage();\r
+            if (t instanceof IOException) {\r
+                ErrorLogger.defaultLogError("An I/O problem occurred while exporting the model. See exception for details.", t);\r
+                cp.setErrorMessage("An I/O problem occurred while exporting the model.\n\nMessage: " + e.getMessage());\r
+            } else {\r
+                ErrorLogger.defaultLogError("Unexpected exception while exporting the model. See exception for details.", t);\r
+                cp.setErrorMessage("Unexpected exception while exporting the model. See error log for details.\n\nMessage: " + e.getMessage());\r
+            }\r
+            return false;\r
+        } catch (InterruptedException e) {\r
+            ExceptionUtils.logAndShowError(e);\r
+            return false;\r
+        }\r
+\r
+        return true;\r
+       }\r
+       \r
+       \r
+       \r
+       \r
+       private boolean readPreferences() {\r
+        IPreferenceStore store = getPreferenceStore();\r
+\r
+        String recentPathsPref = store.getString(getExportLocationId());\r
+        recentExportPaths = decodePaths(recentPathsPref);\r
+        overwrite = store.getBoolean(getExportOverwriteId());\r
+\r
+        return true;\r
+    }\r
+       \r
+       private void writePreferences() throws IOException {\r
+        IPersistentPreferenceStore store = getPreferenceStore();\r
+\r
+        store.putValue(getExportLocationId(), encodePaths(recentExportPaths));\r
+        store.setValue(getExportOverwriteId(), exportModel.isOverwrite());\r
+\r
+        if (store.needsSaving())\r
+            store.save();\r
+    }\r
+       \r
+       private static final String TAG_PATH = "path";\r
+       private static final String ATTR_NAME = "name";\r
+       \r
+       \r
+       public static Deque<String> decodePaths(String recentPathsPref) {\r
+               Deque<String> result = new LinkedList<String>();\r
+               try {\r
+                       StringMemento sm = new StringMemento(recentPathsPref);\r
+                       for (IMemento m : sm.getChildren(TAG_PATH)) {\r
+                               String name = m.getString(ATTR_NAME);\r
+                               if (name != null && !name.isEmpty())\r
+                                       result.add(name);\r
+                       }\r
+               } catch (IllegalArgumentException e) {\r
+               }\r
+               return result;\r
+       }\r
+       \r
+       public static String encodePaths(Deque<String> recentPaths) {\r
+               StringMemento sm = new StringMemento();\r
+               for (String path : recentPaths) {\r
+                       IMemento m = sm.createChild(TAG_PATH);\r
+                       m.putString(ATTR_NAME, path);\r
+               }\r
+               return sm.toString();\r
+       }\r
+       \r
+       public static <T> void removeDuplicates(Iterable<String> iter) {\r
+               // Remove duplicates\r
+               Set<String> dups = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);\r
+               for (Iterator<String> it = iter.iterator(); it.hasNext();) {\r
+                       String path = it.next();\r
+                       if (!dups.add(path)) {\r
+                               it.remove();\r
+                       }\r
+               }\r
+       }\r
+}\r
diff --git a/org.simantics.g3d/src/org/simantics/g3d/wizard/ModelExportWizardPage.java b/org.simantics.g3d/src/org/simantics/g3d/wizard/ModelExportWizardPage.java
new file mode 100644 (file)
index 0000000..95e384b
--- /dev/null
@@ -0,0 +1,285 @@
+package org.simantics.g3d.wizard;\r
+\r
+import java.io.File;\r
+import java.util.ArrayList;\r
+import java.util.Collections;\r
+import java.util.List;\r
+\r
+import org.eclipse.jface.layout.GridDataFactory;\r
+import org.eclipse.jface.resource.ImageDescriptor;\r
+import org.eclipse.jface.wizard.WizardPage;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.custom.CCombo;\r
+import org.eclipse.swt.events.ModifyEvent;\r
+import org.eclipse.swt.events.ModifyListener;\r
+import org.eclipse.swt.events.SelectionAdapter;\r
+import org.eclipse.swt.events.SelectionEvent;\r
+import org.eclipse.swt.layout.GridData;\r
+import org.eclipse.swt.layout.GridLayout;\r
+import org.eclipse.swt.widgets.Button;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.swt.widgets.DirectoryDialog;\r
+import org.eclipse.swt.widgets.FileDialog;\r
+import org.eclipse.swt.widgets.Label;\r
+import org.simantics.Simantics;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.common.NamedResource;\r
+import org.simantics.db.common.request.ReadRequest;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.layer0.Layer0;\r
+import org.simantics.ui.utils.ResourceAdaptionUtils;\r
+\r
+\r
+public abstract class ModelExportWizardPage<T extends IExportModel> extends WizardPage{\r
+       T exportData;\r
+\r
+       CCombo model;\r
+       CCombo exportLocation;\r
+       \r
+       boolean exportToFile = true;\r
+\r
+       private List<NamedResource> models = new ArrayList<NamedResource>();\r
+\r
+       private Button overwrite;\r
+       \r
+       \r
+       \r
+       public ModelExportWizardPage(String pageName, String title, ImageDescriptor titleImage, T data) {\r
+               super(pageName, title, titleImage);\r
+               this.exportData = data;\r
+               exportToFile = data.usesFile();\r
+       }\r
+       \r
+       protected abstract List<NamedResource> getSupportedModels(ReadGraph graph, Resource project) throws DatabaseException;\r
+       \r
+       public String[] getFilterExtensions() {\r
+               return new String[0];\r
+       }\r
+       \r
+       public String[] getFilterNames() {\r
+               return new String[0];\r
+       }\r
+\r
+       @Override\r
+       public void createControl(Composite parent) {\r
+               Composite container = new Composite(parent, SWT.NONE);\r
+               {\r
+                       GridLayout layout = new GridLayout();\r
+                       layout.horizontalSpacing = 20;\r
+                       layout.verticalSpacing = 10;\r
+                       layout.numColumns = 3;\r
+                       container.setLayout(layout);\r
+               }\r
+\r
+               new Label(container, SWT.NONE).setText("Exported &model:");\r
+               model = new CCombo(container, SWT.BORDER);\r
+               {\r
+                       model.setEditable(false);\r
+                       model.setText("");\r
+                       model.setToolTipText("Selects the model to export.");\r
+                       GridDataFactory.fillDefaults().grab(true, false).span(2, 1).applyTo(model);\r
+                       model.addSelectionListener(new SelectionAdapter() {\r
+                               @Override\r
+                               public void widgetSelected(SelectionEvent e) {\r
+                                       exportData.setModel(((NamedResource) model.getData(Integer.toString(model.getSelectionIndex()))));\r
+                                       validatePage();\r
+                               }\r
+                       });\r
+\r
+               }\r
+               if (exportToFile) {\r
+                        new Label(container, SWT.NONE).setText("&Target file:");\r
+                    exportLocation = new CCombo(container, SWT.BORDER);\r
+                    {\r
+                        exportLocation.setText("");\r
+                        GridDataFactory.fillDefaults().grab(true, false).span(1, 1).applyTo(exportLocation);\r
+                        exportLocation.addModifyListener(new ModifyListener(){\r
+                            @Override\r
+                            public void modifyText(ModifyEvent e) {\r
+                                validatePage();\r
+                            }\r
+                        });\r
+                    }\r
+                    Button browseFileButton = new Button(container, SWT.PUSH);\r
+                    {\r
+                        browseFileButton.setText("Browse...");\r
+                        browseFileButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));\r
+                        browseFileButton.addSelectionListener(new SelectionAdapter() {\r
+                            @Override\r
+                            public void widgetSelected(SelectionEvent e) {\r
+                                FileDialog dialog = new FileDialog(getShell(), SWT.SAVE);\r
+                                dialog.setText("Choose Export Target File");\r
+                                dialog.setFilterExtensions(getFilterExtensions());\r
+                                dialog.setFilterNames(getFilterNames());\r
+                                String loc = exportLocation.getText();\r
+                                dialog.setFilterPath(loc);\r
+                                String file = dialog.open();\r
+                                if (file == null)\r
+                                    return;\r
+                                exportLocation.setText(file);\r
+                                validatePage();\r
+                            }\r
+                        });\r
+                    }\r
+\r
+                   \r
+\r
+                   \r
+               } else {\r
+                    new Label(container, SWT.NONE).setText("&Target folder:");\r
+                    exportLocation = new CCombo(container, SWT.BORDER);\r
+                    {\r
+                        exportLocation.setText("");\r
+                        GridDataFactory.fillDefaults().grab(true, false).span(1, 1).applyTo(exportLocation);\r
+                        exportLocation.addModifyListener(new ModifyListener(){\r
+                            @Override\r
+                            public void modifyText(ModifyEvent e) {\r
+                                validatePage();\r
+                            }\r
+                        });\r
+                    }\r
+                    Button browseFileButton = new Button(container, SWT.PUSH);\r
+                    {\r
+                        browseFileButton.setText("Browse...");\r
+                        browseFileButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));\r
+                        browseFileButton.addSelectionListener(new SelectionAdapter() {\r
+                            @Override\r
+                            public void widgetSelected(SelectionEvent e) {\r
+                                DirectoryDialog dialog = new DirectoryDialog(getShell(), SWT.SAVE);\r
+                                dialog.setText("Choose Export Target Folder");\r
+                                String loc = exportLocation.getText();\r
+                                dialog.setFilterPath(loc);\r
+                                String file = dialog.open();\r
+                                if (file == null)\r
+                                    return;\r
+                                exportLocation.setText(file);\r
+                                validatePage();\r
+                            }\r
+                        });\r
+                    }\r
+               }\r
+               \r
+                Label horizRule = new Label(container, SWT.BORDER);\r
+            GridDataFactory.fillDefaults().hint(SWT.DEFAULT, 0).grab(true, false).span(3, 1).applyTo(horizRule);\r
+               \r
+                overwrite = new Button(container, SWT.CHECK);\r
+            overwrite.setText("&Overwrite existing files without warning");\r
+            overwrite.setSelection(exportData.isOverwrite());\r
+            GridDataFactory.fillDefaults().grab(true, false).span(3, 1).applyTo(overwrite);\r
+            overwrite.addSelectionListener(new SelectionAdapter() {\r
+                @Override\r
+                public void widgetSelected(SelectionEvent e) {\r
+                    validatePage();\r
+                }\r
+            });\r
+\r
+            try {\r
+                initializeData();\r
+            } catch (DatabaseException e) {\r
+                e.printStackTrace();\r
+            }\r
+\r
+            setControl(container);\r
+            validatePage();\r
+               \r
+       }\r
+       \r
+\r
+       \r
+       \r
+       protected void initializeData() throws DatabaseException {\r
+                 final Resource selection = ResourceAdaptionUtils.toSingleResource(exportData.getSelection());\r
+\r
+            Simantics.getSessionContext().getSession().syncRequest(\r
+                    new ReadRequest() {\r
+                        @Override\r
+                        public void run(ReadGraph graph) throws DatabaseException {\r
+                            Layer0 L0 = Layer0.getInstance(graph);\r
+                            models = getSupportedModels(graph, Simantics.getProject().get());\r
+                        }\r
+                    });\r
+\r
+                    Collections.sort(models);\r
+\r
+                    // Populate combo boxes\r
+                    int i = 0;\r
+                    boolean selected = false;\r
+                    for (NamedResource s : models) {\r
+                        model.add(s.getName());\r
+                        model.setData(String.valueOf(i), s);\r
+                        if (s.getResource().equals(selection)) {\r
+                            model.select(i);\r
+                            selected = true;\r
+                        }\r
+                        ++i;\r
+                    }\r
+                    if (!selected && i > 0)\r
+                        model.select(0);\r
+                    \r
+                    if (model.getSelectionIndex() >= 0) {\r
+                        exportData.setModel((NamedResource)model.getData(Integer.toString(model.getSelectionIndex())));\r
+                    }\r
+                    for (String path : exportData.getRecentLocations()) {\r
+                        exportLocation.add(path);\r
+                    }\r
+                    if (exportLocation.getItemCount() > 0)\r
+                        exportLocation.select(0);\r
+       }\r
+       \r
+       \r
+       \r
+       protected void validatePage() {\r
+               if (exportData.getModel() == null) {\r
+                       setMessage("Select model to export.");\r
+                       setErrorMessage(null);\r
+                       setPageComplete(false);\r
+                       return;\r
+               }\r
+               String exportLoc = exportLocation.getText();\r
+               File file;\r
+               if (exportToFile) {\r
+\r
+                       if (exportLoc.isEmpty()) {\r
+                               setMessage("Select target file.");\r
+                               setErrorMessage(null);\r
+                               setPageComplete(false);\r
+                               return;\r
+                       }\r
+                       file = new File(exportLoc);\r
+                       if (file.exists() && !file.isFile()) {\r
+                               setErrorMessage("The target must be a file, an existing directory was given.");\r
+                               setPageComplete(false);\r
+                               return;\r
+                       }\r
+                       File parent = file.getParentFile();\r
+                       if (parent == null || !parent.isDirectory()) {\r
+                               setErrorMessage("The target directory does not exist.");\r
+                               setPageComplete(false);\r
+                               return;\r
+                       }\r
+\r
+               } else {\r
+                       if (exportLoc.isEmpty()) {\r
+                               setMessage("Select target directory.");\r
+                               setErrorMessage(null);\r
+                               setPageComplete(false);\r
+                               return;\r
+                       }\r
+                       file = new File(exportLoc);\r
+                       if (file.exists() && !file.isDirectory()) {\r
+                               setErrorMessage("The target must be a directory, an existing file was given.");\r
+                               setPageComplete(false);\r
+                               return;\r
+                       }\r
+\r
+               }\r
+\r
+               exportData.setExportLocation(file);\r
+               exportData.setOverwrite(overwrite.getSelection());\r
+\r
+               setErrorMessage(null);\r
+               setMessage("Export selected model.");\r
+               setPageComplete(true);\r
+       }\r
+}\r
diff --git a/org.simantics.objmap2/.classpath b/org.simantics.objmap2/.classpath
new file mode 100644 (file)
index 0000000..8a8f166
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<classpath>\r
+       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>\r
+       <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>\r
+       <classpathentry kind="src" path="src"/>\r
+       <classpathentry kind="output" path="bin"/>\r
+</classpath>\r
diff --git a/org.simantics.objmap2/.project b/org.simantics.objmap2/.project
new file mode 100644 (file)
index 0000000..25f8723
--- /dev/null
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<projectDescription>\r
+       <name>org.simantics.objmap2</name>\r
+       <comment></comment>\r
+       <projects>\r
+       </projects>\r
+       <buildSpec>\r
+               <buildCommand>\r
+                       <name>org.eclipse.jdt.core.javabuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+               <buildCommand>\r
+                       <name>org.eclipse.pde.ManifestBuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+               <buildCommand>\r
+                       <name>org.eclipse.pde.SchemaBuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+       </buildSpec>\r
+       <natures>\r
+               <nature>org.eclipse.pde.PluginNature</nature>\r
+               <nature>org.eclipse.jdt.core.javanature</nature>\r
+       </natures>\r
+</projectDescription>\r
diff --git a/org.simantics.objmap2/.settings/org.eclipse.jdt.core.prefs b/org.simantics.objmap2/.settings/org.eclipse.jdt.core.prefs
new file mode 100644 (file)
index 0000000..7eb740e
--- /dev/null
@@ -0,0 +1,8 @@
+#Tue Jan 24 15:35:47 EET 2012\r
+eclipse.preferences.version=1\r
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled\r
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6\r
+org.eclipse.jdt.core.compiler.compliance=1.6\r
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error\r
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error\r
+org.eclipse.jdt.core.compiler.source=1.6\r
diff --git a/org.simantics.objmap2/META-INF/MANIFEST.MF b/org.simantics.objmap2/META-INF/MANIFEST.MF
new file mode 100644 (file)
index 0000000..521cdd4
--- /dev/null
@@ -0,0 +1,25 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Objmap2
+Bundle-SymbolicName: org.simantics.objmap2
+Bundle-Version: 1.0.0.qualifier
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6
+Require-Bundle: org.simantics.db;bundle-version="1.1.0",
+ gnu.trove3;bundle-version="3.0.0",
+ org.eclipse.core.runtime;bundle-version="3.7.0",
+ org.simantics.layer0;bundle-version="1.0.0",
+ org.apache.log4j;bundle-version="1.2.15",
+ org.simantics.db.common;bundle-version="1.1.0",
+ org.simantics.structural.ontology;bundle-version="1.1.0"
+Export-Package: org.simantics.objmap.backward,
+ org.simantics.objmap.bidirectional,
+ org.simantics.objmap.exceptions,
+ org.simantics.objmap.forward,
+ org.simantics.objmap.graph,
+ org.simantics.objmap.graph.annotations,
+ org.simantics.objmap.graph.annotations.factories,
+ org.simantics.objmap.graph.rules.factory,
+ org.simantics.objmap.graph.schema,
+ org.simantics.objmap.structural,
+ org.simantics.objmap.structural.annotations,
+ org.simantics.objmap.structural.schema
diff --git a/org.simantics.objmap2/build.properties b/org.simantics.objmap2/build.properties
new file mode 100644 (file)
index 0000000..41eb6ad
--- /dev/null
@@ -0,0 +1,4 @@
+source.. = src/\r
+output.. = bin/\r
+bin.includes = META-INF/,\\r
+               .\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/backward/IBackwardLinkType.java b/org.simantics.objmap2/src/org/simantics/objmap/backward/IBackwardLinkType.java
new file mode 100644 (file)
index 0000000..9ea95c0
--- /dev/null
@@ -0,0 +1,16 @@
+package org.simantics.objmap.backward;\r
+\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.objmap.exceptions.MappingException;\r
+\r
+/**\r
+ * Contains rules for creating and updating domain elements for given\r
+ * range elements.\r
+ * @author Hannu Niemist&ouml;\r
+ */\r
+public interface IBackwardLinkType<Domain, Range> extends IBackwardMappingRule<Domain, Range> {\r
+    /**\r
+     * Creates a domain element based on a known range element.\r
+     */\r
+    Domain createDomainElement(WriteGraph graph, Range rangeElement) throws MappingException;\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/backward/IBackwardMapping.java b/org.simantics.objmap2/src/org/simantics/objmap/backward/IBackwardMapping.java
new file mode 100644 (file)
index 0000000..d54b68e
--- /dev/null
@@ -0,0 +1,19 @@
+package org.simantics.objmap.backward;\r
+\r
+import java.util.Set;\r
+\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.objmap.exceptions.MappingException;\r
+\r
+/**\r
+ * A backward mapping is a one-to-one correspondence between domain and range\r
+ * elements. It supports adding new range elements and creating corresponding\r
+ * domain elements.\r
+ * \r
+ * @author Hannu Niemist&ouml;\r
+ */\r
+public interface IBackwardMapping<Domain, Range> {\r
+    Set<Range> getRange();\r
+    Domain inverseGet(Range rangeElement);\r
+    Domain inverseMap(WriteGraph graph, Range rangeElement) throws MappingException;\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/backward/IBackwardMappingRule.java b/org.simantics.objmap2/src/org/simantics/objmap/backward/IBackwardMappingRule.java
new file mode 100644 (file)
index 0000000..067d1ac
--- /dev/null
@@ -0,0 +1,29 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.backward;\r
+\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.objmap.exceptions.MappingException;\r
+\r
+public interface IBackwardMappingRule<Domain, Range> {\r
+    /**\r
+     * Modifies the domain element so that it corresponds to the range element.\r
+     * @param g write transaction\r
+     * @param map unidirectional view of the current mapping\r
+     * @param domainElement the domain element that is updated\r
+     * @param rangeElement the range element that corresponds to the domain element\r
+     * @return true if the rule made some modifications\r
+     * @throws MappingException \r
+     */    \r
+       boolean updateDomain(WriteGraph graph, IBackwardMapping<Domain, Range> mapping, Domain domainElement, Range rangeElement) throws MappingException;\r
+       void createDomain(WriteGraph graph, IBackwardMapping<Domain, Range> mapping, Domain domainElement, Range rangeElement) throws MappingException;\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/backward/IBackwardMappingSchema.java b/org.simantics.objmap2/src/org/simantics/objmap/backward/IBackwardMappingSchema.java
new file mode 100644 (file)
index 0000000..4f0dd13
--- /dev/null
@@ -0,0 +1,11 @@
+package org.simantics.objmap.backward;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.objmap.exceptions.MappingException;\r
+\r
+public interface IBackwardMappingSchema<Domain, Range> {   \r
+    /**\r
+     * @return Link type that should be used for the element.\r
+     */\r
+    IBackwardLinkType<Domain, Range> linkTypeOfRangeElement(ReadGraph graph, Range element) throws MappingException;\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/bidirectional/IBidirectionalLinkType.java b/org.simantics.objmap2/src/org/simantics/objmap/bidirectional/IBidirectionalLinkType.java
new file mode 100644 (file)
index 0000000..11bbcc9
--- /dev/null
@@ -0,0 +1,10 @@
+package org.simantics.objmap.bidirectional;\r
+\r
+import org.simantics.objmap.backward.IBackwardLinkType;\r
+import org.simantics.objmap.forward.IForwardLinkType;\r
+\r
+\r
+public interface IBidirectionalLinkType<Domain, Range> \r
+extends IForwardLinkType<Domain, Range>, IBackwardLinkType<Domain, Range>,\r
+IBidirectionalMappingRule<Domain, Range> {\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/bidirectional/IBidirectionalMapping.java b/org.simantics.objmap2/src/org/simantics/objmap/bidirectional/IBidirectionalMapping.java
new file mode 100644 (file)
index 0000000..611dab0
--- /dev/null
@@ -0,0 +1,9 @@
+package org.simantics.objmap.bidirectional;\r
+\r
+import org.simantics.objmap.backward.IBackwardMapping;\r
+import org.simantics.objmap.forward.IForwardMapping;\r
+\r
+\r
+public interface IBidirectionalMapping<Domain, Range> \r
+extends IForwardMapping<Domain, Range>, IBackwardMapping<Domain, Range> {\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/bidirectional/IBidirectionalMappingRule.java b/org.simantics.objmap2/src/org/simantics/objmap/bidirectional/IBidirectionalMappingRule.java
new file mode 100644 (file)
index 0000000..f29c01f
--- /dev/null
@@ -0,0 +1,20 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.bidirectional;\r
+\r
+import org.simantics.objmap.backward.IBackwardMappingRule;\r
+import org.simantics.objmap.forward.IForwardMappingRule;\r
+\r
+\r
+public interface IBidirectionalMappingRule<Domain, Range> \r
+extends IForwardMappingRule<Domain, Range>, IBackwardMappingRule<Domain, Range> {\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/bidirectional/IBidirectionalMappingSchema.java b/org.simantics.objmap2/src/org/simantics/objmap/bidirectional/IBidirectionalMappingSchema.java
new file mode 100644 (file)
index 0000000..12dd14f
--- /dev/null
@@ -0,0 +1,13 @@
+package org.simantics.objmap.bidirectional;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.objmap.backward.IBackwardMappingSchema;\r
+import org.simantics.objmap.exceptions.MappingException;\r
+import org.simantics.objmap.forward.IForwardMappingSchema;\r
+\r
+\r
+public interface IBidirectionalMappingSchema<Domain, Range> \r
+extends IForwardMappingSchema<Domain, Range>, IBackwardMappingSchema<Domain, Range> {\r
+    IBidirectionalLinkType<Domain, Range> linkTypeOfDomainElement(ReadGraph graph, Domain element) throws MappingException;\r
+    IBidirectionalLinkType<Domain, Range> linkTypeOfRangeElement(ReadGraph graph, Range element) throws MappingException;\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/exceptions/MappingException.java b/org.simantics.objmap2/src/org/simantics/objmap/exceptions/MappingException.java
new file mode 100644 (file)
index 0000000..bed3de7
--- /dev/null
@@ -0,0 +1,24 @@
+package org.simantics.objmap.exceptions;\r
+\r
+import org.simantics.db.exception.DatabaseException;\r
+\r
+public class MappingException extends DatabaseException {\r
+    private static final long serialVersionUID = 5381307568357191426L;\r
+    \r
+    \r
+    public MappingException() {\r
+               super();\r
+       }\r
+    \r
+    public MappingException(String message) {\r
+       super(message);\r
+    }\r
+    \r
+    public MappingException(Throwable cause) {\r
+       super(cause);\r
+    }\r
+    \r
+    public MappingException(String message, Throwable cause) {\r
+       super(message, cause);\r
+    }\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/forward/IForwardLinkType.java b/org.simantics.objmap2/src/org/simantics/objmap/forward/IForwardLinkType.java
new file mode 100644 (file)
index 0000000..9427266
--- /dev/null
@@ -0,0 +1,16 @@
+package org.simantics.objmap.forward;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.objmap.exceptions.MappingException;\r
+\r
+/**\r
+ * Contains rules for creating and updating range elements for given\r
+ * domain elements.\r
+ * @author Hannu Niemist&ouml;\r
+ */\r
+public interface IForwardLinkType<Domain, Range> extends IForwardMappingRule<Domain, Range> {\r
+    /**\r
+     * Creates a range element based on a known domain element.\r
+     */\r
+    Range createRangeElement(ReadGraph graph, Domain domainElement) throws MappingException;\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/forward/IForwardMapping.java b/org.simantics.objmap2/src/org/simantics/objmap/forward/IForwardMapping.java
new file mode 100644 (file)
index 0000000..23a484d
--- /dev/null
@@ -0,0 +1,12 @@
+package org.simantics.objmap.forward;\r
+\r
+import java.util.Set;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.objmap.exceptions.MappingException;\r
+\r
+public interface IForwardMapping<Domain, Range> {\r
+    Set<Domain> getDomain();\r
+    Range get(Domain domainElement);\r
+    Range map(ReadGraph graph, Domain domainElement) throws MappingException;\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/forward/IForwardMappingRule.java b/org.simantics.objmap2/src/org/simantics/objmap/forward/IForwardMappingRule.java
new file mode 100644 (file)
index 0000000..6c89d8d
--- /dev/null
@@ -0,0 +1,29 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.forward;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.objmap.exceptions.MappingException;\r
+\r
+public interface IForwardMappingRule<Domain, Range> {\r
+       /**\r
+        * Modifies the range element so that it corresponds to the domain element.\r
+        * @param g read transaction\r
+        * @param map unidirectional view of the current mapping\r
+        * @param domainElement the domain element that corresponds to the range element\r
+        * @param rangeElement the range element that is updated\r
+        * @return true if the rule made some modifications\r
+        * @throws MappingException\r
+        */\r
+       boolean updateRange(ReadGraph graph, IForwardMapping<Domain, Range> mapping, Domain domainElement, Range rangeElement) throws MappingException; \r
+       void createRange(ReadGraph graph, IForwardMapping<Domain, Range> mapping, Domain domainElement, Range rangeElement) throws MappingException;\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/forward/IForwardMappingSchema.java b/org.simantics.objmap2/src/org/simantics/objmap/forward/IForwardMappingSchema.java
new file mode 100644 (file)
index 0000000..d0a8afa
--- /dev/null
@@ -0,0 +1,11 @@
+package org.simantics.objmap.forward;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.objmap.exceptions.MappingException;\r
+\r
+public interface IForwardMappingSchema<Domain, Range> {\r
+    /**\r
+     * @return Link type that should be used for the element.\r
+     */\r
+    IForwardLinkType<Domain, Range> linkTypeOfDomainElement(ReadGraph graph, Domain element) throws MappingException;\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/IMapping.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/IMapping.java
new file mode 100644 (file)
index 0000000..fbf876b
--- /dev/null
@@ -0,0 +1,142 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.graph;\r
+\r
+import java.util.Collection;\r
+import java.util.Set;\r
+\r
+import org.simantics.db.Disposable;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.objmap.bidirectional.IBidirectionalMapping;\r
+import org.simantics.objmap.exceptions.MappingException;\r
+\r
+/**\r
+ * A mapping consists of domain (a set of resources), range (a set of Java objects) and\r
+ * a set of links relating them. The mapping is used to propagate modifications of\r
+ * domain elements to range and vice versa. \r
+ * \r
+ * @see <a href="http://www.simantics.org/wiki/index.php/org.simantics.objmap_Manual#Concepts">Manual</a>\r
+ * \r
+ * @author Hannu Niemistö\r
+ */\r
+public interface IMapping<Domain,Range> extends Disposable, IBidirectionalMapping<Domain, Range> {\r
+\r
+    /**\r
+     * Returns the domain of the mapping. All set operations are supported.\r
+     * Adding a new domain element does not automatically create a link to it.\r
+     * Removal of a domain element removes also a link and the target element,\r
+     * but does not remove the element from the database.\r
+     */\r
+    Set<Domain> getDomain();\r
+\r
+    /**\r
+     * Returns the range of the mapping. All set operations are supported.\r
+     * Adding a new range element does not automatically create a link to it.\r
+     * Removal of a range element removes also a link and the domain element,\r
+     * but does not remove the domain element from the database.\r
+     */\r
+    Set<Range> getRange();\r
+\r
+    /**\r
+     * Updates all domain elements whose counterpart is modified and creates new\r
+     * domain elements for previously added range elements. Returns the\r
+     * collection of domain elements that were modified or created in the update\r
+     * process.\r
+     */\r
+    Collection<Domain> updateDomain(WriteGraph g) throws MappingException;\r
+\r
+    /**\r
+     * Updates all range elements whose counterpart is modified and creates new\r
+     * range elements for previously added domain elements. Returns the\r
+     * collection of range elements that were modified or created in the update\r
+     * process.\r
+     */\r
+    Collection<Range> updateRange(ReadGraph g) throws MappingException;\r
+\r
+    /**\r
+     * Returns the counterpart of a domain element or null if the element does\r
+     * not belong to the domain or does not have a link.\r
+     */\r
+    Range get(Domain domainElement);\r
+\r
+    /**\r
+     * Returns the counterpart of a range element or null if the element does\r
+     * not belong to the range or does not have a link.\r
+     */\r
+    Domain inverseGet(Range rangeElement);\r
+\r
+    /**\r
+     * A convenience method that adds a domain element to the mapping and\r
+     * immediately updates the mapping and returns the corresponding range\r
+     * element.\r
+     */\r
+    Range map(ReadGraph g, Domain domainElement) throws MappingException;\r
+\r
+    /**\r
+     * A convenience method that adds a range element to the mapping and\r
+     * immediately updates the mapping and returns the corresponding domain\r
+     * element.\r
+     */\r
+    Domain inverseMap(WriteGraph g, Range rangeElement)\r
+            throws MappingException;\r
+\r
+    /**\r
+     * Tells the mapping that the domain element has been modified.\r
+     */\r
+    void domainModified(Domain domainElement);\r
+\r
+    /**\r
+     * Tells the mapping that the range element has been modified.\r
+     */\r
+    void rangeModified(Range rangeElement);\r
+\r
+    /**\r
+     * Tells if some domain elements have been modified or added.\r
+     */\r
+    boolean isDomainModified();\r
+\r
+    /**\r
+     * Tells if some range elements have been modified or added.\r
+     */\r
+    boolean isRangeModified();\r
+    \r
+    Collection<Domain> getDomainModified();\r
+    Collection<Range> getRangeModified();\r
+\r
+    /**\r
+     * Returns a collection of domain elements which have been modified and also\r
+     * their counterparts in the mapping are modified. These elements are in\r
+     * conflict in the sense that the updating domain and range in different\r
+     * orders may produce different results.\r
+     */\r
+    Collection<Domain> getConflictingDomainElements();\r
+\r
+    /**\r
+     * Returns a collection of range elements which have been modified and also\r
+     * their counterparts in the mapping are modified. These elements are in\r
+     * conflict in the sense that the updating domain and range in different\r
+     * orders may produce different results.\r
+     */\r
+    Collection<Range> getConflictingRangeElements();\r
+\r
+    /**\r
+     * Adds a listener for domain and range modifications.\r
+     */\r
+    void addMappingListener(IMappingListener listener);\r
+\r
+    /**\r
+     * Removes a previously added listener.\r
+     */\r
+    void removeMappingListener(IMappingListener listener);\r
+\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/IMappingListener.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/IMappingListener.java
new file mode 100644 (file)
index 0000000..a48166b
--- /dev/null
@@ -0,0 +1,30 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.graph;\r
+\r
+/**\r
+ * Listens modifications in a mapping.\r
+ * @author Hannu Niemistö\r
+ */\r
+public interface IMappingListener {\r
+    /**\r
+     * Called when some domain element is modified or created\r
+     * and the mapping was previously up to date.\r
+     */\r
+       void domainModified();\r
+       \r
+       /**\r
+     * Called when some range element is modified or created\r
+     * and the mapping was previously up to date.\r
+     */\r
+       void rangeModified();\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/Mappings.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/Mappings.java
new file mode 100644 (file)
index 0000000..e60b018
--- /dev/null
@@ -0,0 +1,43 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.graph;\r
+\r
+import org.simantics.db.Resource;\r
+import org.simantics.objmap.graph.impl.Mapping;\r
+import org.simantics.objmap.graph.schema.IMappingSchema;\r
+/**\r
+ * Static utility methods for mappings. \r
+ * @author Hannu Niemistö\r
+ */\r
+public class Mappings {\r
+       private Mappings() {}\r
+       \r
+       /**\r
+        * Creates a new mapping based on the given mapping schema. \r
+        * The created mapping is not thread-safe and will not\r
+        * listen database changes automatically.\r
+        */\r
+       public static <Domain,Range> IMapping<Domain,Range> createWithoutListening(IMappingSchema<Domain,Range> schema) {\r
+               return new Mapping<Domain,Range>(schema, false);\r
+       }\r
+       \r
+       /**\r
+     * Creates a new mapping based on the given mapping schema. \r
+     * The created mapping is not thread-safe. It listens database\r
+     * changes automatically.\r
+     */\r
+       public static <Domain,Range> IMapping<Domain,Range> createWithListening(IMappingSchema<Domain,Range> schema) {\r
+        return new Mapping<Domain,Range>(schema, true);\r
+    }\r
+       \r
+       \r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/Composition.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/Composition.java
new file mode 100644 (file)
index 0000000..2611b70
--- /dev/null
@@ -0,0 +1,22 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.graph.annotations;\r
+\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target({ElementType.FIELD,ElementType.METHOD})\r
+public @interface Composition {\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/CompoundRelatedGetValue.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/CompoundRelatedGetValue.java
new file mode 100644 (file)
index 0000000..709ae6f
--- /dev/null
@@ -0,0 +1,23 @@
+package org.simantics.objmap.graph.annotations;\r
+\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+import org.simantics.objmap.graph.annotations.meta.IsGetSetRule;\r
+import org.simantics.objmap.graph.rules.adapters.IdentityAdapter;\r
+import org.simantics.objmap.graph.rules.adapters.ValueAdapter;\r
+\r
+\r
+\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target(ElementType.METHOD)\r
+@IsGetSetRule\r
+@HasSetter(CompoundRelatedSetValue.class)\r
+public @interface CompoundRelatedGetValue {\r
+       String objRelation();\r
+       String objType();\r
+       String valRelation();\r
+//     Class<? extends ValueAdapter> adapter() default IdentityAdapter.class;\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/CompoundRelatedSetValue.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/CompoundRelatedSetValue.java
new file mode 100644 (file)
index 0000000..93ceeb4
--- /dev/null
@@ -0,0 +1,13 @@
+package org.simantics.objmap.graph.annotations;\r
+\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target(ElementType.METHOD)\r
+public @interface CompoundRelatedSetValue {\r
+       String value();\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/DynamicGraphType.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/DynamicGraphType.java
new file mode 100644 (file)
index 0000000..530803a
--- /dev/null
@@ -0,0 +1,12 @@
+package org.simantics.objmap.graph.annotations;\r
+\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target(ElementType.TYPE) \r
+public @interface DynamicGraphType {\r
+       String value();\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/GetType.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/GetType.java
new file mode 100644 (file)
index 0000000..f4be045
--- /dev/null
@@ -0,0 +1,15 @@
+package org.simantics.objmap.graph.annotations;\r
+\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+\r
+\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target(ElementType.METHOD)\r
+//@HasGetSetRuleFactory(RelatedGetSetValueRuleFactory.class)\r
+public @interface GetType {\r
+       String value();\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/GraphType.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/GraphType.java
new file mode 100644 (file)
index 0000000..24fff13
--- /dev/null
@@ -0,0 +1,12 @@
+package org.simantics.objmap.graph.annotations;\r
+\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target(ElementType.TYPE) \r
+public @interface GraphType {\r
+       String value();\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/HasCollectionAdder.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/HasCollectionAdder.java
new file mode 100644 (file)
index 0000000..640aa4d
--- /dev/null
@@ -0,0 +1,13 @@
+package org.simantics.objmap.graph.annotations;\r
+\r
+import java.lang.annotation.Annotation;\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target(ElementType.ANNOTATION_TYPE)\r
+public @interface HasCollectionAdder {\r
+        Class<? extends Annotation> value();\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/HasCollectionRemover.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/HasCollectionRemover.java
new file mode 100644 (file)
index 0000000..5e32a24
--- /dev/null
@@ -0,0 +1,13 @@
+package org.simantics.objmap.graph.annotations;\r
+\r
+import java.lang.annotation.Annotation;\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target(ElementType.ANNOTATION_TYPE)\r
+public @interface HasCollectionRemover {\r
+        Class<? extends Annotation> value();\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/HasSetter.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/HasSetter.java
new file mode 100644 (file)
index 0000000..e312cd7
--- /dev/null
@@ -0,0 +1,13 @@
+package org.simantics.objmap.graph.annotations;\r
+\r
+import java.lang.annotation.Annotation;\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target(ElementType.ANNOTATION_TYPE)\r
+public @interface HasSetter {\r
+        Class<? extends Annotation> value();\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/OptionalRelatedElements.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/OptionalRelatedElements.java
new file mode 100644 (file)
index 0000000..103af11
--- /dev/null
@@ -0,0 +1,30 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.graph.annotations;\r
+\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+import org.simantics.objmap.graph.annotations.meta.IsFieldRule;\r
+\r
+\r
+\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target(ElementType.FIELD)\r
+//@HasFieldRuleFactory(OptionalRelatedElementsRuleFactory.class)\r
+@IsFieldRule\r
+public @interface OptionalRelatedElements {\r
+       String value();\r
+       boolean composition() default false;\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedElement.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedElement.java
new file mode 100644 (file)
index 0000000..554d9a8
--- /dev/null
@@ -0,0 +1,27 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.graph.annotations;\r
+\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+import org.simantics.objmap.graph.annotations.meta.IsFieldRule;\r
+\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target(ElementType.FIELD)\r
+//HasFieldRuleFactory(RelatedElementRuleFactory.class)\r
+@IsFieldRule\r
+public @interface RelatedElement {\r
+       String value();\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedElements.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedElements.java
new file mode 100644 (file)
index 0000000..4ef5fb0
--- /dev/null
@@ -0,0 +1,29 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.graph.annotations;\r
+\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+import org.simantics.objmap.graph.annotations.meta.IsFieldRule;\r
+\r
+\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target(ElementType.FIELD)\r
+//@HasFieldRuleFactory(RelatedElementsRuleFactory.class)\r
+@IsFieldRule\r
+public @interface RelatedElements {\r
+       String value();\r
+       boolean composition() default false;\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedElementsAdd.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedElementsAdd.java
new file mode 100644 (file)
index 0000000..b071c7c
--- /dev/null
@@ -0,0 +1,12 @@
+package org.simantics.objmap.graph.annotations;\r
+\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target(ElementType.METHOD)\r
+public @interface RelatedElementsAdd {\r
+       String value();\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedElementsGet.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedElementsGet.java
new file mode 100644 (file)
index 0000000..135fadc
--- /dev/null
@@ -0,0 +1,22 @@
+package org.simantics.objmap.graph.annotations;\r
+\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+import org.simantics.objmap.graph.annotations.meta.IsCollectionRule;\r
+\r
+\r
+\r
+\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target(ElementType.METHOD)\r
+//@HasCollectionRuleFactory(RelatedElementsRuleFactory2.class)\r
+@IsCollectionRule\r
+@HasCollectionAdder(RelatedElementsAdd.class)\r
+@HasCollectionRemover(RelatedElementsRem.class)\r
+public @interface RelatedElementsGet {\r
+       String value();\r
+       boolean composition() default false;\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedElementsRem.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedElementsRem.java
new file mode 100644 (file)
index 0000000..fb8d1db
--- /dev/null
@@ -0,0 +1,13 @@
+package org.simantics.objmap.graph.annotations;\r
+\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target(ElementType.METHOD)\r
+public @interface RelatedElementsRem {\r
+       String value();\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedGetObj.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedGetObj.java
new file mode 100644 (file)
index 0000000..2a8f30c
--- /dev/null
@@ -0,0 +1,19 @@
+package org.simantics.objmap.graph.annotations;\r
+\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+import org.simantics.objmap.graph.annotations.meta.IsGetSetRule;\r
+\r
+\r
+\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target(ElementType.METHOD)\r
+//@HasGetSetRuleFactory(RelatedGetSetObjRuleFactory.class)\r
+@IsGetSetRule\r
+@HasSetter(RelatedSetObj.class)\r
+public @interface RelatedGetObj {\r
+       String value();\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedGetValue.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedGetValue.java
new file mode 100644 (file)
index 0000000..d3d1414
--- /dev/null
@@ -0,0 +1,22 @@
+package org.simantics.objmap.graph.annotations;\r
+\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+import org.simantics.objmap.graph.annotations.meta.IsGetSetRule;\r
+import org.simantics.objmap.graph.rules.adapters.IdentityAdapter;\r
+import org.simantics.objmap.graph.rules.adapters.ValueAdapter;\r
+\r
+\r
+\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target(ElementType.METHOD)\r
+//@HasGetSetRuleFactory(RelatedGetSetValueRuleFactory.class)\r
+@IsGetSetRule\r
+@HasSetter(RelatedSetValue.class)\r
+public @interface RelatedGetValue {\r
+       String value();\r
+        Class<? extends ValueAdapter> adapter() default IdentityAdapter.class;\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedOrderedSetElements.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedOrderedSetElements.java
new file mode 100644 (file)
index 0000000..fe6afef
--- /dev/null
@@ -0,0 +1,28 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.graph.annotations;\r
+\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+import org.simantics.objmap.graph.annotations.meta.IsFieldRule;\r
+\r
+\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target(ElementType.FIELD)\r
+//@HasFieldRuleFactory(RelatedOrderedSetElementsRuleFactory.class)\r
+@IsFieldRule\r
+public @interface RelatedOrderedSetElements {\r
+       boolean composition() default false;\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedSetObj.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedSetObj.java
new file mode 100644 (file)
index 0000000..e3212e1
--- /dev/null
@@ -0,0 +1,13 @@
+package org.simantics.objmap.graph.annotations;\r
+\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target(ElementType.METHOD)\r
+public @interface RelatedSetObj {\r
+       String value();\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedSetValue.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedSetValue.java
new file mode 100644 (file)
index 0000000..201b0cf
--- /dev/null
@@ -0,0 +1,13 @@
+package org.simantics.objmap.graph.annotations;\r
+\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target(ElementType.METHOD)\r
+public @interface RelatedSetValue {\r
+       String value();\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedValue.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/RelatedValue.java
new file mode 100644 (file)
index 0000000..e8148c4
--- /dev/null
@@ -0,0 +1,37 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.graph.annotations;\r
+\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+import org.simantics.objmap.graph.annotations.meta.IsFieldRule;\r
+import org.simantics.objmap.graph.rules.adapters.IdentityAdapter;\r
+import org.simantics.objmap.graph.rules.adapters.ValueAdapter;\r
+\r
+\r
+\r
+/**\r
+ * Specifies a correspondence between a field and \r
+ * functional property.\r
+ * @author Hannu Niemistö\r
+ */\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target(ElementType.FIELD)\r
+//@HasFieldRuleFactory(RelatedValueRuleFactory.class)\r
+@IsFieldRule\r
+public @interface RelatedValue {\r
+    String value();\r
+    Class<? extends ValueAdapter> adapter() default IdentityAdapter.class;\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/SetType.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/SetType.java
new file mode 100644 (file)
index 0000000..28ff9c1
--- /dev/null
@@ -0,0 +1,15 @@
+package org.simantics.objmap.graph.annotations;\r
+\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+\r
+\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target(ElementType.METHOD)\r
+//@HasGetSetRuleFactory(RelatedGetSetValueRuleFactory.class)\r
+public @interface SetType {\r
+       String value();\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/UpdateMethod.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/UpdateMethod.java
new file mode 100644 (file)
index 0000000..cc33986
--- /dev/null
@@ -0,0 +1,33 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.graph.annotations;\r
+\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+import org.simantics.objmap.graph.annotations.meta.IsFieldRule;\r
+\r
+\r
+\r
+/**\r
+ * Specifies that the annotated method should be called\r
+ * to update range object.\r
+ * @author Hannu Niemistö\r
+ */\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target(ElementType.METHOD)\r
+//@HasMethodRuleFactory(UpdateMethodFactory.class)\r
+@IsFieldRule\r
+public @interface UpdateMethod {\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/CompoundRelatedGetSetValueRuleFactory.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/CompoundRelatedGetSetValueRuleFactory.java
new file mode 100644 (file)
index 0000000..333686f
--- /dev/null
@@ -0,0 +1,102 @@
+package org.simantics.objmap.graph.annotations.factories;\r
+\r
+import java.lang.annotation.Annotation;\r
+import java.lang.reflect.Method;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.layer0.Layer0;\r
+import org.simantics.objmap.bidirectional.IBidirectionalMappingRule;\r
+import org.simantics.objmap.graph.annotations.CompoundRelatedGetValue;\r
+import org.simantics.objmap.graph.annotations.CompoundRelatedSetValue;\r
+import org.simantics.objmap.graph.rules.ValueRule;\r
+import org.simantics.objmap.graph.rules.adapters.IdentityAdapter;\r
+import org.simantics.objmap.graph.rules.adapters.ValueAdapter;\r
+import org.simantics.objmap.graph.rules.domain.CompoundValueAccessor;\r
+import org.simantics.objmap.graph.rules.factory.IGetSetRuleFactory;\r
+import org.simantics.objmap.graph.rules.range.AdaptedRangeAccessor;\r
+import org.simantics.objmap.graph.rules.range.CompoundGetSetValueAccessor;\r
+import org.simantics.objmap.graph.rules.range.IRangeAccessor;\r
+\r
+/**\r
+ * Rule factory for mapped value using Getter/Setter-methods.\r
+ * \r
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>\r
+ *\r
+ */\r
+public class CompoundRelatedGetSetValueRuleFactory<Range> implements IGetSetRuleFactory<Resource,Range> {\r
+       \r
+       @Override\r
+       public IBidirectionalMappingRule<Resource, Range> create(ReadGraph g, Annotation annotation,\r
+                       Method getter, Method setter)\r
+                       throws DatabaseException {\r
+               CompoundRelatedGetValue getterAnn = (CompoundRelatedGetValue)annotation;\r
+               \r
+//             Class<? extends ValueAdapter> adapterClass = getterAnn.adapter();\r
+               IRangeAccessor<Range,Object> rangeAccessor = new CompoundGetSetValueAccessor<Range,Object>(getter, setter);\r
+//        Resource valueType;\r
+//        if (adapterClass == IdentityAdapter.class) {\r
+//            valueType = dataTypeOfClass(g, getter.getReturnType());\r
+//        } else {\r
+//             try{\r
+//                      ValueAdapter adapter = adapterClass.newInstance();\r
+//                 rangeAccessor = new AdaptedRangeAccessor<Range>(rangeAccessor, adapter);\r
+//                 valueType = adapter.rangeTypeToDomainType(g, getter.getReturnType());\r
+//             } catch (InstantiationException e) {\r
+//                 throw new RuntimeException(e);\r
+//             } catch (IllegalAccessException e) {\r
+//                 throw new RuntimeException(e);\r
+//             }\r
+//        }\r
+               return new ValueRule<Resource,Range>(new CompoundValueAccessor(g.getResource(getterAnn.objRelation()),\r
+                                                                                                                                          g.getResource(getterAnn.objType()),\r
+                                                                                                                                          g.getResource(getterAnn.valRelation())),\r
+                                       rangeAccessor);\r
+       }\r
+       \r
+       @Override\r
+       public boolean isSetter(Annotation getterAnnotation, Annotation annotation) {\r
+               CompoundRelatedGetValue getterAnn = (CompoundRelatedGetValue)getterAnnotation;\r
+               CompoundRelatedSetValue setterAnn = (CompoundRelatedSetValue)annotation;\r
+               return getterAnn.objRelation().equals(setterAnn.value());\r
+       }\r
+       \r
+       public static Resource dataTypeOfClass(ReadGraph g, Class<?> clazz) {\r
+        Layer0 b = Layer0.getInstance(g);\r
+        if(clazz.equals(Double.class) || clazz.equals(double.class))\r
+            return b.Double;\r
+        else if(clazz.equals(String.class))\r
+            return b.String;\r
+        else if(clazz.equals(Integer.class) || clazz.equals(int.class))\r
+            return b.Integer;\r
+        else if(clazz.equals(Float.class) || clazz.equals(float.class))\r
+            return b.Float;\r
+        else if(clazz.equals(Boolean.class) || clazz.equals(boolean.class))\r
+            return b.Boolean;\r
+        else if(clazz.equals(Long.class) || clazz.equals(long.class))\r
+            return b.Long;\r
+        else if(clazz.equals(Byte.class) || clazz.equals(byte.class))\r
+            return b.Byte;\r
+        \r
+        else if(clazz.equals(double[].class))\r
+            return b.DoubleArray;\r
+        else if(clazz.equals(int[].class))\r
+            return b.IntegerArray;\r
+        else if(clazz.equals(byte[].class))\r
+            return b.ByteArray;\r
+        else if(clazz.equals(float[].class))\r
+            return b.FloatArray;\r
+        else if(clazz.equals(boolean[].class))\r
+            return b.BooleanArray;\r
+        else if(clazz.equals(String[].class))\r
+            return b.StringArray;\r
+        else if(clazz.equals(long[].class))\r
+            return b.LongArray;\r
+        else {\r
+               System.out.println("Couldn't find a data type for " + clazz);\r
+            return null;\r
+        }\r
+    }\r
+\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/DataTypeUtils.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/DataTypeUtils.java
new file mode 100644 (file)
index 0000000..b61ab05
--- /dev/null
@@ -0,0 +1,57 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.graph.annotations.factories;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.layer0.Layer0;\r
+\r
+public class DataTypeUtils {\r
+    \r
+    public static Resource dataTypeOfClass(ReadGraph g, Class<?> clazz) {\r
+        Layer0 b = Layer0.getInstance(g);\r
+        if(clazz.equals(Double.class) || clazz.equals(double.class))\r
+            return b.Double;\r
+        else if(clazz.equals(String.class))\r
+            return b.String;\r
+        else if(clazz.equals(Integer.class) || clazz.equals(int.class))\r
+            return b.Integer;\r
+        else if(clazz.equals(Float.class) || clazz.equals(float.class))\r
+            return b.Float;\r
+        else if(clazz.equals(Boolean.class) || clazz.equals(boolean.class))\r
+            return b.Boolean;\r
+        else if(clazz.equals(Long.class) || clazz.equals(long.class))\r
+            return b.Long;\r
+        else if(clazz.equals(Byte.class) || clazz.equals(byte.class))\r
+            return b.Byte;\r
+        \r
+        else if(clazz.equals(double[].class))\r
+            return b.DoubleArray;\r
+        else if(clazz.equals(int[].class))\r
+            return b.IntegerArray;\r
+        else if(clazz.equals(byte[].class))\r
+            return b.ByteArray;\r
+        else if(clazz.equals(float[].class))\r
+            return b.FloatArray;\r
+        else if(clazz.equals(boolean[].class))\r
+            return b.BooleanArray;\r
+        else if(clazz.equals(String[].class))\r
+            return b.StringArray;\r
+        else if(clazz.equals(long[].class))\r
+            return b.LongArray;\r
+        else {\r
+               System.out.println("Couldn't find a data type for " + clazz);\r
+            return null;\r
+        }\r
+    }\r
+    \r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/OptionalRelatedElementsRuleFactory.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/OptionalRelatedElementsRuleFactory.java
new file mode 100644 (file)
index 0000000..6900fda
--- /dev/null
@@ -0,0 +1,44 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.graph.annotations.factories;\r
+\r
+import java.lang.annotation.Annotation;\r
+import java.lang.reflect.Field;\r
+import java.util.Collection;\r
+import java.util.Collections;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.exception.ResourceNotFoundException;\r
+import org.simantics.db.exception.ServiceException;\r
+import org.simantics.db.exception.ValidationException;\r
+import org.simantics.objmap.bidirectional.IBidirectionalMappingRule;\r
+import org.simantics.objmap.graph.annotations.OptionalRelatedElements;\r
+import org.simantics.objmap.graph.rules.MappedElementsRule;\r
+import org.simantics.objmap.graph.rules.domain.RelatedObjectsAccessor;\r
+import org.simantics.objmap.graph.rules.factory.IFieldRuleFactory;\r
+import org.simantics.objmap.graph.rules.range.FieldAccessorWithDefault;\r
+\r
+\r
+public class OptionalRelatedElementsRuleFactory<Range> implements IFieldRuleFactory<Resource, Range> {\r
+\r
+    @Override\r
+    public IBidirectionalMappingRule<Resource, Range> create(ReadGraph g, Annotation _annotation, Field field) throws ResourceNotFoundException, ValidationException, ServiceException {\r
+        OptionalRelatedElements annotation = (OptionalRelatedElements)_annotation;\r
+        return new MappedElementsRule<Resource, Range>(\r
+                new RelatedObjectsAccessor(g.getResource(annotation.value()),\r
+                        annotation.composition()),\r
+                new FieldAccessorWithDefault<Range,Collection<Range>>(field, (Collection<Range>)Collections.emptyList())\r
+                );\r
+    }\r
+\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/RelatedElementRuleFactory.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/RelatedElementRuleFactory.java
new file mode 100644 (file)
index 0000000..6aab217
--- /dev/null
@@ -0,0 +1,41 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.graph.annotations.factories;\r
+\r
+import java.lang.annotation.Annotation;\r
+import java.lang.reflect.Field;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.exception.ResourceNotFoundException;\r
+import org.simantics.db.exception.ServiceException;\r
+import org.simantics.db.exception.ValidationException;\r
+import org.simantics.objmap.bidirectional.IBidirectionalMappingRule;\r
+import org.simantics.objmap.graph.annotations.RelatedElement;\r
+import org.simantics.objmap.graph.rules.MappedElementRule;\r
+import org.simantics.objmap.graph.rules.domain.RelatedObjectAccessor;\r
+import org.simantics.objmap.graph.rules.factory.IFieldRuleFactory;\r
+import org.simantics.objmap.graph.rules.range.FieldAccessor;\r
+\r
+\r
+public class RelatedElementRuleFactory<Range> implements IFieldRuleFactory<Resource,Range> {\r
+\r
+    @Override\r
+    public IBidirectionalMappingRule<Resource, Range> create(ReadGraph g, Annotation _annotation, Field field) throws ResourceNotFoundException, ValidationException, ServiceException {\r
+        RelatedElement annotation = (RelatedElement)_annotation;\r
+        return new MappedElementRule<Resource,Range>(\r
+                new RelatedObjectAccessor(g.getResource(annotation.value())),\r
+                new FieldAccessor<Range,Range>(field)\r
+                );\r
+    }\r
+\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/RelatedElementsRuleFactory.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/RelatedElementsRuleFactory.java
new file mode 100644 (file)
index 0000000..c086aed
--- /dev/null
@@ -0,0 +1,43 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.graph.annotations.factories;\r
+\r
+import java.lang.annotation.Annotation;\r
+import java.lang.reflect.Field;\r
+import java.util.Collection;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.exception.ResourceNotFoundException;\r
+import org.simantics.db.exception.ServiceException;\r
+import org.simantics.db.exception.ValidationException;\r
+import org.simantics.objmap.bidirectional.IBidirectionalMappingRule;\r
+import org.simantics.objmap.graph.annotations.RelatedElements;\r
+import org.simantics.objmap.graph.rules.MappedElementsRule;\r
+import org.simantics.objmap.graph.rules.domain.RelatedObjectsAccessor;\r
+import org.simantics.objmap.graph.rules.factory.IFieldRuleFactory;\r
+import org.simantics.objmap.graph.rules.range.FieldAccessor;\r
+\r
+\r
+public class RelatedElementsRuleFactory<Range> implements IFieldRuleFactory<Resource, Range> {\r
+\r
+    @Override\r
+    public IBidirectionalMappingRule<Resource, Range> create(ReadGraph g, Annotation _annotation, Field field) throws ResourceNotFoundException, ValidationException, ServiceException {\r
+        RelatedElements annotation = (RelatedElements)_annotation;\r
+        return new MappedElementsRule<Resource,Range>(\r
+                new RelatedObjectsAccessor(g.getResource(annotation.value()),\r
+                        annotation.composition()),\r
+                new FieldAccessor<Range,Collection<Range>>(field)\r
+                );\r
+    }\r
+\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/RelatedElementsRuleFactory2.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/RelatedElementsRuleFactory2.java
new file mode 100644 (file)
index 0000000..81bba3f
--- /dev/null
@@ -0,0 +1,44 @@
+package org.simantics.objmap.graph.annotations.factories;\r
+\r
+import java.lang.annotation.Annotation;\r
+import java.lang.reflect.Method;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.objmap.bidirectional.IBidirectionalMappingRule;\r
+import org.simantics.objmap.graph.annotations.RelatedElementsAdd;\r
+import org.simantics.objmap.graph.annotations.RelatedElementsGet;\r
+import org.simantics.objmap.graph.annotations.RelatedElementsRem;\r
+import org.simantics.objmap.graph.rules.MappedElementsRule;\r
+import org.simantics.objmap.graph.rules.domain.RelatedObjectsAccessor;\r
+import org.simantics.objmap.graph.rules.factory.ICollectionRuleFactory;\r
+import org.simantics.objmap.graph.rules.range.CollectionAccessor;\r
+\r
+\r
+public class RelatedElementsRuleFactory2<Range> implements ICollectionRuleFactory<Resource,Range> {\r
+       \r
+       @Override\r
+       public IBidirectionalMappingRule<Resource, Range> create(ReadGraph g, Annotation annotation,\r
+                       Method getter, Method adder, Method remover)\r
+                       throws DatabaseException {\r
+               RelatedElementsGet getterAnn = (RelatedElementsGet)annotation;\r
+               return new MappedElementsRule<Resource,Range>(new RelatedObjectsAccessor(g.getResource(getterAnn.value()),getterAnn.composition()),\r
+                                       new CollectionAccessor<Range,Range>(getter, adder, remover));\r
+       }\r
+       \r
+       @Override\r
+       public boolean isAdder(Annotation getterAnnotation, Annotation annotation) {\r
+               RelatedElementsGet getterAnn = (RelatedElementsGet)getterAnnotation;\r
+               RelatedElementsAdd adderAnn = (RelatedElementsAdd)annotation;\r
+               return getterAnn.value().equals(adderAnn.value());\r
+       }\r
+       \r
+       @Override\r
+       public boolean isRemover(Annotation getterAnnotation, Annotation annotation) {\r
+               RelatedElementsGet getterAnn = (RelatedElementsGet)getterAnnotation;\r
+               RelatedElementsRem adderAnn = (RelatedElementsRem)annotation;\r
+               return getterAnn.value().equals(adderAnn.value());\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/RelatedGetSetObjRuleFactory.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/RelatedGetSetObjRuleFactory.java
new file mode 100644 (file)
index 0000000..f031f4b
--- /dev/null
@@ -0,0 +1,44 @@
+package org.simantics.objmap.graph.annotations.factories;\r
+\r
+import java.lang.annotation.Annotation;\r
+import java.lang.reflect.Method;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.objmap.bidirectional.IBidirectionalMappingRule;\r
+import org.simantics.objmap.graph.annotations.RelatedGetObj;\r
+import org.simantics.objmap.graph.annotations.RelatedSetObj;\r
+import org.simantics.objmap.graph.rules.MappedElementRule;\r
+import org.simantics.objmap.graph.rules.domain.RelatedObjectAccessor;\r
+import org.simantics.objmap.graph.rules.factory.IGetSetRuleFactory;\r
+import org.simantics.objmap.graph.rules.range.GetSetObjectAccessor;\r
+\r
+\r
+/**\r
+ * Rule factory for mapped object using Getter/Setter-methods.\r
+ * \r
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>\r
+ *\r
+ */\r
+public class RelatedGetSetObjRuleFactory<Range> implements IGetSetRuleFactory<Resource,Range> {\r
+       \r
+       @Override\r
+       public IBidirectionalMappingRule<Resource,Range> create(ReadGraph g, Annotation annotation,\r
+                       Method getter, Method setter)\r
+                       throws DatabaseException {\r
+               RelatedGetObj getterAnn = (RelatedGetObj)annotation;\r
+               return new MappedElementRule<Resource,Range>(new RelatedObjectAccessor(g.getResource(getterAnn.value())),\r
+                                       new GetSetObjectAccessor<Range,Range>(getter, setter));\r
+       }\r
+       \r
+       @Override\r
+       public boolean isSetter(Annotation getterAnnotation, Annotation annotation) {\r
+               RelatedGetObj getterAnn = (RelatedGetObj)getterAnnotation;\r
+               RelatedSetObj setterAnn = (RelatedSetObj)annotation;\r
+               return getterAnn.value().equals(setterAnn.value());\r
+       }\r
+       \r
+       \r
+\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/RelatedGetSetValueRuleFactory.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/RelatedGetSetValueRuleFactory.java
new file mode 100644 (file)
index 0000000..5579b07
--- /dev/null
@@ -0,0 +1,100 @@
+package org.simantics.objmap.graph.annotations.factories;\r
+\r
+import java.lang.annotation.Annotation;\r
+import java.lang.reflect.Method;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.layer0.Layer0;\r
+import org.simantics.objmap.bidirectional.IBidirectionalMappingRule;\r
+import org.simantics.objmap.graph.annotations.RelatedGetValue;\r
+import org.simantics.objmap.graph.annotations.RelatedSetValue;\r
+import org.simantics.objmap.graph.rules.ValueRule;\r
+import org.simantics.objmap.graph.rules.adapters.IdentityAdapter;\r
+import org.simantics.objmap.graph.rules.adapters.ValueAdapter;\r
+import org.simantics.objmap.graph.rules.domain.RelatedValueAccessor;\r
+import org.simantics.objmap.graph.rules.factory.IGetSetRuleFactory;\r
+import org.simantics.objmap.graph.rules.range.AdaptedRangeAccessor;\r
+import org.simantics.objmap.graph.rules.range.GetSetValueAccessor;\r
+import org.simantics.objmap.graph.rules.range.IRangeAccessor;\r
+\r
+/**\r
+ * Rule factory for mapped value using Getter/Setter-methods.\r
+ * \r
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>\r
+ *\r
+ */\r
+public class RelatedGetSetValueRuleFactory<Range> implements IGetSetRuleFactory<Resource,Range> {\r
+       \r
+       @Override\r
+       public IBidirectionalMappingRule<Resource, Range> create(ReadGraph g, Annotation annotation,\r
+                       Method getter, Method setter)\r
+                       throws DatabaseException {\r
+               RelatedGetValue getterAnn = (RelatedGetValue)annotation;\r
+               \r
+               Class<? extends ValueAdapter> adapterClass = getterAnn.adapter();\r
+                IRangeAccessor<Range,Object> rangeAccessor = new GetSetValueAccessor<Range,Object>(getter, setter);\r
+        Resource valueType;\r
+        if (adapterClass == IdentityAdapter.class) {\r
+            valueType = dataTypeOfClass(g, getter.getReturnType());\r
+        } else {\r
+               try{\r
+                        ValueAdapter adapter = adapterClass.newInstance();\r
+                 rangeAccessor = new AdaptedRangeAccessor<Range>(rangeAccessor, adapter);\r
+                 valueType = adapter.rangeTypeToDomainType(g, getter.getReturnType());\r
+             } catch (InstantiationException e) {\r
+                 throw new RuntimeException(e);\r
+             } catch (IllegalAccessException e) {\r
+                 throw new RuntimeException(e);\r
+             }\r
+        }\r
+               return new ValueRule<Resource,Range>(new RelatedValueAccessor(g.getResource(getterAnn.value()), valueType),\r
+                                       rangeAccessor);\r
+       }\r
+       \r
+       @Override\r
+       public boolean isSetter(Annotation getterAnnotation, Annotation annotation) {\r
+               RelatedGetValue getterAnn = (RelatedGetValue)getterAnnotation;\r
+               RelatedSetValue setterAnn = (RelatedSetValue)annotation;\r
+               return getterAnn.value().equals(setterAnn.value());\r
+       }\r
+       \r
+       public static Resource dataTypeOfClass(ReadGraph g, Class<?> clazz) {\r
+        Layer0 b = Layer0.getInstance(g);\r
+        if(clazz.equals(Double.class) || clazz.equals(double.class))\r
+            return b.Double;\r
+        else if(clazz.equals(String.class))\r
+            return b.String;\r
+        else if(clazz.equals(Integer.class) || clazz.equals(int.class))\r
+            return b.Integer;\r
+        else if(clazz.equals(Float.class) || clazz.equals(float.class))\r
+            return b.Float;\r
+        else if(clazz.equals(Boolean.class) || clazz.equals(boolean.class))\r
+            return b.Boolean;\r
+        else if(clazz.equals(Long.class) || clazz.equals(long.class))\r
+            return b.Long;\r
+        else if(clazz.equals(Byte.class) || clazz.equals(byte.class))\r
+            return b.Byte;\r
+        \r
+        else if(clazz.equals(double[].class))\r
+            return b.DoubleArray;\r
+        else if(clazz.equals(int[].class))\r
+            return b.IntegerArray;\r
+        else if(clazz.equals(byte[].class))\r
+            return b.ByteArray;\r
+        else if(clazz.equals(float[].class))\r
+            return b.FloatArray;\r
+        else if(clazz.equals(boolean[].class))\r
+            return b.BooleanArray;\r
+        else if(clazz.equals(String[].class))\r
+            return b.StringArray;\r
+        else if(clazz.equals(long[].class))\r
+            return b.LongArray;\r
+        else {\r
+               System.out.println("Couldn't find a data type for " + clazz);\r
+            return null;\r
+        }\r
+    }\r
+\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/RelatedOrderedSetElementsRuleFactory.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/RelatedOrderedSetElementsRuleFactory.java
new file mode 100644 (file)
index 0000000..d9be274
--- /dev/null
@@ -0,0 +1,42 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.graph.annotations.factories;\r
+\r
+import java.lang.annotation.Annotation;\r
+import java.lang.reflect.Field;\r
+import java.util.Collection;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.exception.ResourceNotFoundException;\r
+import org.simantics.db.exception.ServiceException;\r
+import org.simantics.db.exception.ValidationException;\r
+import org.simantics.objmap.bidirectional.IBidirectionalMappingRule;\r
+import org.simantics.objmap.graph.annotations.RelatedOrderedSetElements;\r
+import org.simantics.objmap.graph.rules.MappedElementsRule;\r
+import org.simantics.objmap.graph.rules.domain.RelatedOrderedSetElementsAccessor;\r
+import org.simantics.objmap.graph.rules.factory.IFieldRuleFactory;\r
+import org.simantics.objmap.graph.rules.range.FieldAccessor;\r
+\r
+\r
+public class RelatedOrderedSetElementsRuleFactory<Range> implements IFieldRuleFactory<Resource, Range> {\r
+\r
+    @Override\r
+    public IBidirectionalMappingRule<Resource, Range> create(ReadGraph g, Annotation _annotation, Field field) throws ResourceNotFoundException, ValidationException, ServiceException {\r
+        RelatedOrderedSetElements annotation = (RelatedOrderedSetElements)_annotation;\r
+        return new MappedElementsRule<Resource,Range>(\r
+                new RelatedOrderedSetElementsAccessor(annotation.composition()),\r
+                new FieldAccessor<Range,Collection<Range>>(field)\r
+                );\r
+    }\r
+\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/RelatedValueRuleFactory.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/RelatedValueRuleFactory.java
new file mode 100644 (file)
index 0000000..2d90670
--- /dev/null
@@ -0,0 +1,60 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.graph.annotations.factories;\r
+\r
+import java.lang.annotation.Annotation;\r
+import java.lang.reflect.Field;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.exception.ResourceNotFoundException;\r
+import org.simantics.db.exception.ServiceException;\r
+import org.simantics.db.exception.ValidationException;\r
+\r
+import org.simantics.objmap.bidirectional.IBidirectionalMappingRule;\r
+import org.simantics.objmap.graph.annotations.RelatedValue;\r
+import org.simantics.objmap.graph.rules.ValueRule;\r
+import org.simantics.objmap.graph.rules.adapters.IdentityAdapter;\r
+import org.simantics.objmap.graph.rules.adapters.ValueAdapter;\r
+import org.simantics.objmap.graph.rules.domain.RelatedValueAccessor;\r
+import org.simantics.objmap.graph.rules.factory.IFieldRuleFactory;\r
+import org.simantics.objmap.graph.rules.range.AdaptedRangeAccessor;\r
+import org.simantics.objmap.graph.rules.range.FieldAccessor;\r
+import org.simantics.objmap.graph.rules.range.IRangeAccessor;\r
+\r
+\r
+public class RelatedValueRuleFactory<Range> implements IFieldRuleFactory<Resource, Range> {\r
+\r
+    @Override\r
+    public IBidirectionalMappingRule<Resource, Range> create(ReadGraph g, Annotation _annotation, Field field) throws ResourceNotFoundException,\r
+            ValidationException, ServiceException {\r
+        RelatedValue annotation = (RelatedValue) _annotation;\r
+        Class<? extends ValueAdapter> adapterClass = annotation.adapter();\r
+        IRangeAccessor<Range,Object> rangeAccessor = new FieldAccessor<Range,Object>(field);\r
+        Resource valueType;\r
+        if (adapterClass == IdentityAdapter.class) {\r
+            valueType = DataTypeUtils.dataTypeOfClass(g, field.getType());\r
+        } else {\r
+            try {\r
+                ValueAdapter adapter = adapterClass.newInstance();\r
+                rangeAccessor = new AdaptedRangeAccessor<Range>(rangeAccessor, adapter);\r
+                valueType = adapter.rangeTypeToDomainType(g, field.getType());\r
+            } catch (InstantiationException e) {\r
+                throw new RuntimeException(e);\r
+            } catch (IllegalAccessException e) {\r
+                throw new RuntimeException(e);\r
+            }\r
+        }\r
+        return new ValueRule<Resource,Range>(new RelatedValueAccessor(g.getResource(annotation.value()), valueType), rangeAccessor);\r
+    }\r
+\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/UpdateMethodFactory.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/factories/UpdateMethodFactory.java
new file mode 100644 (file)
index 0000000..9fde7b7
--- /dev/null
@@ -0,0 +1,70 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.graph.annotations.factories;\r
+\r
+import java.lang.annotation.Annotation;\r
+import java.lang.reflect.Method;\r
+\r
+import org.apache.log4j.Logger;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.objmap.backward.IBackwardMapping;\r
+import org.simantics.objmap.bidirectional.IBidirectionalMappingRule;\r
+import org.simantics.objmap.exceptions.MappingException;\r
+import org.simantics.objmap.forward.IForwardMapping;\r
+import org.simantics.objmap.graph.rules.factory.IMethodRuleFactory;\r
+\r
+public class UpdateMethodFactory<Domain, Range> implements IMethodRuleFactory<Domain, Range> {\r
+\r
+    static Logger LOGGER = Logger.getLogger("org.simantics.objmap");\r
+    \r
+    @Override\r
+    public IBidirectionalMappingRule<Domain, Range> create(ReadGraph g, \r
+            Annotation annotation, \r
+            final Method method)\r
+            throws DatabaseException {\r
+        method.setAccessible(true);\r
+        return new IBidirectionalMappingRule<Domain,Range>() {\r
+            \r
+            @Override\r
+            public boolean updateRange(ReadGraph g, IForwardMapping<Domain, Range> map,\r
+                    Domain domainElement, Range rangeElement)\r
+                    throws MappingException {\r
+                LOGGER.info("    UpdateMethodFactory.updateRange");      \r
+                try {\r
+                    return (Boolean)method.invoke(rangeElement, g, domainElement);\r
+                } catch (Exception e) {\r
+                    // TODO Auto-generated catch block\r
+                    e.printStackTrace();\r
+                }\r
+                return false;\r
+            }\r
+            \r
+            @Override\r
+            public boolean updateDomain(WriteGraph g, IBackwardMapping<Domain,Range> map,\r
+                    Domain domainElement, Range rangeElement)\r
+                    throws MappingException {\r
+                return false;\r
+            }\r
+            \r
+            public void createDomain(WriteGraph g, IBackwardMapping<Domain,Range> map, Domain domainElement, Range rangeElement) throws MappingException {\r
+               updateDomain(g, map, domainElement, rangeElement);\r
+            };\r
+            \r
+            public void createRange(ReadGraph g, IForwardMapping<Domain,Range> map, Domain domainElement, Range rangeElement) throws MappingException {\r
+               updateRange(g, map, domainElement, rangeElement);\r
+            };\r
+        };\r
+    }\r
+\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/meta/IsClassRule.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/meta/IsClassRule.java
new file mode 100644 (file)
index 0000000..9f3c62d
--- /dev/null
@@ -0,0 +1,23 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.graph.annotations.meta;\r
+\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target(ElementType.ANNOTATION_TYPE) \r
+public @interface IsClassRule {\r
+    \r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/meta/IsCollectionRule.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/meta/IsCollectionRule.java
new file mode 100644 (file)
index 0000000..55003a5
--- /dev/null
@@ -0,0 +1,12 @@
+package org.simantics.objmap.graph.annotations.meta;\r
+\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target(ElementType.ANNOTATION_TYPE) \r
+public @interface IsCollectionRule {\r
+       \r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/meta/IsFieldRule.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/meta/IsFieldRule.java
new file mode 100644 (file)
index 0000000..2e85c53
--- /dev/null
@@ -0,0 +1,23 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.graph.annotations.meta;\r
+\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target(ElementType.ANNOTATION_TYPE) \r
+public @interface IsFieldRule {\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/meta/IsGetSetRule.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/meta/IsGetSetRule.java
new file mode 100644 (file)
index 0000000..d723b10
--- /dev/null
@@ -0,0 +1,13 @@
+package org.simantics.objmap.graph.annotations.meta;\r
+\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target(ElementType.ANNOTATION_TYPE) \r
+public @interface IsGetSetRule {\r
+       \r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/meta/IsMethodRule.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/annotations/meta/IsMethodRule.java
new file mode 100644 (file)
index 0000000..0e0ab1e
--- /dev/null
@@ -0,0 +1,23 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.graph.annotations.meta;\r
+\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target(ElementType.ANNOTATION_TYPE) \r
+public @interface IsMethodRule {\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/impl/Link.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/impl/Link.java
new file mode 100644 (file)
index 0000000..95591f5
--- /dev/null
@@ -0,0 +1,40 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+/**\r
+ * \r
+ */\r
+package org.simantics.objmap.graph.impl;\r
+\r
+import org.simantics.objmap.graph.schema.ILinkType;\r
+\r
+\r
+/**\r
+ * An indication that the domain element corresponds to the range element\r
+ * in the mapping. The link type describes how source and target objects\r
+ * are updated. There are additionally flags for dirtiness of the link.\r
+ * @author Hannu Niemistö\r
+ */\r
+public class Link<Domain,Range> {\r
+       public ILinkType<Domain,Range> type;\r
+       public Domain domainElement;\r
+       public Range rangeElement;\r
+       \r
+       public boolean domainModified = false;\r
+       public boolean rangeModified = false;\r
+       public boolean removed = false;\r
+       \r
+       public Link(ILinkType<Domain,Range> type, Domain domainElement, Range rangeElement) {\r
+               this.type = type;\r
+               this.domainElement = domainElement;\r
+               this.rangeElement = rangeElement;               \r
+       }               \r
+}
\ No newline at end of file
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/impl/Mapping.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/impl/Mapping.java
new file mode 100644 (file)
index 0000000..3b75e7e
--- /dev/null
@@ -0,0 +1,476 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.graph.impl;\r
+\r
+\r
+import gnu.trove.map.hash.THashMap;\r
+\r
+import java.util.AbstractSet;\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.Iterator;\r
+import java.util.List;\r
+import java.util.Set;\r
+\r
+import org.apache.log4j.Logger;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.db.exception.DatabaseException;\r
+\r
+import org.simantics.objmap.backward.IBackwardMapping;\r
+import org.simantics.objmap.exceptions.MappingException;\r
+import org.simantics.objmap.forward.IForwardMapping;\r
+import org.simantics.objmap.graph.IMapping;\r
+import org.simantics.objmap.graph.IMappingListener;\r
+import org.simantics.objmap.graph.schema.ILinkType;\r
+import org.simantics.objmap.graph.schema.IMappingSchema;\r
+\r
+/**\r
+ * An implementation of IMapping. The class should not be created\r
+ * directly but using methods in Mappings.\r
+ * @see org.simantics.objmap.graph.Mappings\r
+ * @author Hannu Niemistö\r
+ */\r
+public class Mapping<Domain, Range> implements IMapping<Domain, Range> {\r
+\r
+       static Logger LOGGER = Logger.getLogger("org.simantics.objmap");\r
+       \r
+       \r
+       IMappingSchema<Domain, Range> schema;\r
+       \r
+       THashMap<Domain, Link<Domain,Range>> domain = new THashMap<Domain, Link<Domain,Range>>();\r
+       THashMap<Range, Link<Domain,Range>> range = new THashMap<Range, Link<Domain,Range>>();\r
+       ArrayList<IMappingListener> listeners = new ArrayList<IMappingListener>();\r
+\r
+       ArrayList<Link<Domain,Range>> modifiedDomainLinks = new ArrayList<Link<Domain,Range>>();\r
+       ArrayList<Link<Domain,Range>> modifiedRangeLinks = new ArrayList<Link<Domain,Range>>();\r
+\r
+       boolean disposed = false;\r
+       \r
+       boolean listensDomain; \r
+       \r
+       public Mapping(IMappingSchema<Domain, Range> schema, boolean listensDomain) {\r
+               this.schema = schema;\r
+               this.listensDomain = listensDomain;\r
+       }\r
+       \r
+       private void removeLink(Link<Domain,Range> link) {\r
+               if(link.domainModified)\r
+                       modifiedDomainLinks.remove(link);\r
+               if(link.rangeModified)\r
+                       modifiedRangeLinks.remove(link);\r
+               link.removed = true;\r
+       }\r
+       \r
+       private void createDomain(WriteGraph g, Link<Domain,Range> link) throws MappingException {\r
+           LOGGER.info("        createDomain for " + link.rangeElement);\r
+               ILinkType<Domain,Range> type = schema.linkTypeOfRangeElement(link.rangeElement);\r
+               Domain domainElement = type.createDomainElement(g, link.rangeElement);\r
+               link.type = type;\r
+               link.domainElement = domainElement;\r
+               domain.put(domainElement, link);\r
+               type.createDomain(g, new RangeToDomain(g), domainElement, link.rangeElement);\r
+               \r
+        // TODO Should we do this only if the mapping is listening?\r
+        domainModified(link);\r
+       }\r
+       \r
+       private void createRange(ReadGraph g, Link<Domain,Range> link) throws MappingException {\r
+               ILinkType<Domain,Range> type = schema.linkTypeOfDomainElement(g, link.domainElement);           \r
+               Range rangeElement = type.createRangeElement(g, link.domainElement);\r
+               \r
+               link.type = type;\r
+               link.rangeElement = rangeElement;\r
+               range.put(rangeElement, link);\r
+               type.createRange(g, new DomainToRange(g), link.domainElement, rangeElement);\r
+       }\r
+       \r
+       Set<Domain> domainSet = new AbstractSet<Domain>() {\r
+\r
+               public boolean add(Domain e) {\r
+                       if(domain.containsKey(e))\r
+                               return false;\r
+                       Link<Domain,Range> link = new Link<Domain,Range>(null, e, null);\r
+                       domain.put(e, link);\r
+                       modifiedDomainLinks.add(link);\r
+                       return true;\r
+               }\r
+               \r
+               public boolean contains(Object o) {\r
+                       return domain.contains(o);\r
+               }\r
+               \r
+               public boolean remove(Object o) {\r
+                       Link<Domain,Range> link = domain.remove(o);                     \r
+                       if(link == null)\r
+                               return false;\r
+                       removeLink(link);\r
+                       if(link.rangeElement != null)\r
+                               range.remove(link.rangeElement);\r
+                       return true;    \r
+               }\r
+               \r
+               @Override\r
+               public Iterator<Domain> iterator() {\r
+                   // FIXME does not implement Iterator.remove correctly\r
+                       return domain.keySet().iterator();\r
+               }\r
+\r
+               @Override\r
+               public int size() {\r
+                       return domain.size();\r
+               }\r
+               \r
+       };\r
+       \r
+       Set<Range> rangeSet = new AbstractSet<Range>() {\r
+\r
+               public boolean add(Range e) {\r
+                       if(range.containsKey(e))\r
+                               return false;\r
+                       Link<Domain,Range> link = new Link<Domain,Range>(null, null, e);\r
+                       range.put(e, link);\r
+                       modifiedRangeLinks.add(link);\r
+                       return true;\r
+               }\r
+               \r
+               public boolean contains(Object o) {\r
+                       return range.contains(o);\r
+               }\r
+               \r
+               public boolean remove(Object o) {\r
+                       Link<Domain,Range> link = range.remove(o);                      \r
+                       if(link == null)\r
+                               return false;\r
+                       removeLink(link);\r
+                       if(link.domainElement != null)\r
+                               domain.remove(link.domainElement);\r
+                       return true;\r
+               }\r
+               \r
+               @Override\r
+               public Iterator<Range> iterator() {\r
+                   // FIXME does not implement Iterator.remove correctly\r
+                       return range.keySet().iterator();\r
+               }\r
+\r
+               @Override\r
+               public int size() {\r
+                       return range.size();\r
+               }\r
+               \r
+       };\r
+       \r
+       class DomainToRange implements IForwardMapping<Domain, Range> {\r
+\r
+               ReadGraph g;\r
+               \r
+               public DomainToRange(ReadGraph g) {\r
+                       this.g = g;\r
+               }\r
+\r
+               @Override\r
+               public Range get(Domain element)  {\r
+                       Link<Domain,Range> link = domain.get(element);\r
+                       if (link != null)\r
+                               return link.rangeElement;\r
+                       return null;\r
+                       \r
+               }\r
+               \r
+               @Override\r
+               public Range map(ReadGraph graph, Domain element)\r
+                               throws MappingException {\r
+                       Link<Domain,Range> link = domain.get(element);\r
+                       if(link == null) {\r
+                           link = new Link<Domain,Range>(null, element, null);\r
+                   link.domainModified = true;\r
+                   modifiedDomainLinks.add(link);\r
+                           domain.put(element, link);           \r
+                           createRange(g, link);       \r
+                       }\r
+                       else if(link.type == null) \r
+                               createRange(g, link);\r
+            return link.rangeElement;\r
+               }\r
+               \r
+               @Override\r
+               public Set<Domain> getDomain() {\r
+                       return domain.keySet();\r
+               }\r
+               \r
+       };\r
+       \r
+       class RangeToDomain extends DomainToRange implements IBackwardMapping<Domain, Range> {\r
+\r
+               WriteGraph g;\r
+               \r
+               public RangeToDomain(WriteGraph g) {\r
+                       super(g);\r
+                       this.g = g;\r
+               }\r
+               @Override\r
+               public Domain inverseGet(Range element) {\r
+                       \r
+                       Link<Domain,Range> link = range.get(element);\r
+                       if(link != null)\r
+                               return link.domainElement;\r
+                       return null;\r
+               }\r
+               \r
+               @Override\r
+               public Domain inverseMap(WriteGraph graph, Range element)\r
+                               throws MappingException {\r
+                       Link<Domain,Range> link = range.get(element);\r
+                       if(link == null) {\r
+                           link = new Link<Domain,Range>(null, null, element);\r
+                           link.rangeModified = true;\r
+                modifiedRangeLinks.add(link);\r
+                           range.put(element, link);\r
+                           createDomain(g, link);                              \r
+                       }\r
+                       else if(link.type == null)\r
+                               createDomain(g, link);\r
+                       return link.domainElement;\r
+               }\r
+               \r
+               \r
+               @Override\r
+               public Set<Range> getRange() {\r
+                       return range.keySet();\r
+               }\r
+       };\r
+       \r
+       @Override\r
+       public Set<Domain> getDomain() {\r
+               return domainSet;\r
+       }\r
+       \r
+       @Override\r
+       public Set<Range> getRange() {\r
+               return rangeSet;\r
+       }\r
+       \r
+       \r
+       @Override\r
+       public synchronized Collection<Domain> updateDomain(WriteGraph g) throws MappingException {\r
+           LOGGER.info("Mapping.updateDomain");\r
+               RangeToDomain map = new RangeToDomain(g);\r
+               ArrayList<Domain> updated = new ArrayList<Domain>();\r
+               while(!modifiedRangeLinks.isEmpty()) {\r
+                   LOGGER.info("    modifiedRangeLinks.size() = " + modifiedRangeLinks.size());\r
+                   \r
+                       Link<Domain,Range> link = modifiedRangeLinks.remove(modifiedRangeLinks.size()-1);\r
+                       link.rangeModified = false;\r
+                       /*if(link.domainModified) {\r
+                               link.domainModified = false;\r
+                               modifiedDomainLinks.remove(link);\r
+                       }*/\r
+                       \r
+                       if(link.type == null) {\r
+                               createDomain(g, link);\r
+                       }\r
+                       \r
+                       if(link.type.updateDomain(g, map, link.domainElement, link.rangeElement))\r
+                               updated.add(link.domainElement);\r
+               }       \r
+               if (listensDomain)\r
+                       updateRange(g); //FIXME: without this listening would stop. \r
+               return updated;\r
+       }\r
+       \r
+       @Override\r
+       public synchronized Collection<Range> updateRange(ReadGraph g) throws MappingException {\r
+           LOGGER.info("Mapping.updateRange");\r
+               DomainToRange map = new DomainToRange(g);\r
+               ArrayList<Range> updated = new ArrayList<Range>();\r
+               while(!modifiedDomainLinks.isEmpty()) {             \r
+                   LOGGER.info("    modifiedDomainLinks.size() = " + modifiedDomainLinks.size());\r
+                   \r
+                       Link<Domain,Range> link = modifiedDomainLinks.remove(modifiedDomainLinks.size()-1);\r
+                       link.domainModified = false;\r
+                       /*if(link.rangeModified) {\r
+                               link.rangeModified = false;\r
+                               modifiedRangeLinks.remove(link);\r
+                       }*/\r
+                       \r
+                       if(link.type == null) {\r
+                               createRange(g, link);\r
+                       }\r
+                       \r
+                       if(listensDomain) {\r
+                           RangeUpdateRequest<Domain,Range> request = new RangeUpdateRequest<Domain,Range>(link, map, this);\r
+                           try {\r
+                    g.syncRequest(request, request);\r
+                } catch (DatabaseException e) {\r
+                    throw new MappingException(e);\r
+                }\r
+                           // TODO check if really modified\r
+                           updated.add(link.rangeElement);\r
+                       }\r
+                       else\r
+                           if(link.type.updateRange(g, map, link.domainElement, link.rangeElement))\r
+                               updated.add(link.rangeElement);\r
+               }       \r
+               return updated;\r
+       }\r
+\r
+       @Override\r
+       public Range get(Domain domainElement) {\r
+               Link<Domain,Range> link = domain.get(domainElement);\r
+               if(link == null)\r
+                       return null;\r
+               return link.rangeElement;\r
+       }\r
+\r
+       @Override\r
+       public Domain inverseGet(Range rangeElement) {\r
+               Link<Domain,Range> link = range.get(rangeElement);\r
+               if(link == null)\r
+                       return null;\r
+               return link.domainElement;\r
+       }\r
+\r
+       @Override\r
+       public Domain inverseMap(WriteGraph g, Range rangeElement) throws MappingException {\r
+               getRange().add(rangeElement);\r
+               updateDomain(g);\r
+               return inverseGet(rangeElement);\r
+       }\r
+\r
+       @Override\r
+       public Range map(ReadGraph g, Domain domainElement) throws MappingException {\r
+               getDomain().add(domainElement);\r
+               updateRange(g);\r
+               return get(domainElement);\r
+       }\r
+\r
+       void domainModified(Link<Domain,Range> link) {\r
+           if(!link.domainModified) {          \r
+               synchronized(modifiedDomainLinks) {\r
+                   LOGGER.info("        domainModified for " + link.rangeElement);\r
+                link.domainModified = true;\r
+                modifiedDomainLinks.add(link);\r
+                if(modifiedDomainLinks.size() == 1) {\r
+                    for(IMappingListener listener : listeners)\r
+                        listener.domainModified();\r
+                }\r
+               }\r
+        }\r
+       }\r
+       \r
+       @Override\r
+       public void domainModified(Domain domainElement) {\r
+               Link<Domain,Range> link = domain.get(domainElement);\r
+               if(link != null)\r
+                   domainModified(link);\r
+       }\r
+\r
+       void rangeModified(Link<Domain,Range> link) {\r
+           if(!link.rangeModified) {\r
+               synchronized(modifiedRangeLinks) {\r
+                link.rangeModified = true;\r
+                modifiedRangeLinks.add(link);\r
+                if(modifiedRangeLinks.size() == 1) {\r
+                    for(IMappingListener listener : listeners)\r
+                        listener.rangeModified();\r
+                }\r
+               }\r
+        }\r
+       }\r
+       \r
+       @Override\r
+       public void rangeModified(Range rangeElement) {\r
+               Link<Domain,Range> link = range.get(rangeElement);\r
+               if(link != null)\r
+                   rangeModified(link);\r
+       }\r
+\r
+       @Override\r
+       public boolean isDomainModified() {\r
+               return !modifiedDomainLinks.isEmpty();\r
+       }\r
+\r
+       @Override\r
+       public boolean isRangeModified() {\r
+               return !modifiedRangeLinks.isEmpty();\r
+       }\r
+       \r
+       @Override\r
+       public Collection<Domain> getDomainModified() {\r
+               List<Domain> list = new ArrayList<Domain>(modifiedDomainLinks.size());\r
+               for (Link<Domain, Range> link : modifiedDomainLinks)\r
+                       list.add(link.domainElement);\r
+               return list;\r
+                               \r
+       }\r
+       \r
+       @Override\r
+       public Collection<Range> getRangeModified() {\r
+               List<Range> list = new ArrayList<Range>(modifiedRangeLinks.size());\r
+               for (Link<Domain, Range> link : modifiedRangeLinks)\r
+                       list.add(link.rangeElement);\r
+               return list;\r
+       }\r
+\r
+       @Override\r
+       public void addMappingListener(IMappingListener listener) {\r
+               listeners.add(listener);\r
+       }\r
+\r
+       @Override\r
+       public void removeMappingListener(IMappingListener listener) {\r
+               listeners.remove(listener);             \r
+       }\r
+\r
+       @Override\r
+       public Collection<Domain> getConflictingDomainElements() {\r
+               ArrayList<Domain> result = new ArrayList<Domain>();\r
+               if(modifiedDomainLinks.size() < modifiedRangeLinks.size()) {\r
+                       for(Link<Domain,Range> link : modifiedDomainLinks)\r
+                               if(link.rangeModified)\r
+                                       result.add(link.domainElement);\r
+               }\r
+               else {\r
+                       for(Link<Domain,Range> link : modifiedRangeLinks)\r
+                               if(link.domainModified)\r
+                                       result.add(link.domainElement);\r
+               }\r
+               return result;\r
+       }\r
+\r
+       @Override\r
+       public Collection<Range> getConflictingRangeElements() {\r
+               ArrayList<Range> result = new ArrayList<Range>();\r
+               if(modifiedDomainLinks.size() < modifiedRangeLinks.size()) {\r
+                       for(Link<Domain,Range> link : modifiedDomainLinks)\r
+                               if(link.rangeModified)\r
+                                       result.add(link.rangeElement);\r
+               }\r
+               else {\r
+                       for(Link<Domain,Range> link : modifiedRangeLinks)\r
+                               if(link.domainModified)\r
+                                       result.add(link.rangeElement);\r
+               }\r
+               return result;\r
+       }\r
+\r
+    @Override\r
+    public void dispose() {\r
+        disposed = true;\r
+    }\r
+    \r
+    public boolean isDisposed() {\r
+        return disposed;\r
+    }\r
+       \r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/impl/RangeUpdateRequest.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/impl/RangeUpdateRequest.java
new file mode 100644 (file)
index 0000000..599f249
--- /dev/null
@@ -0,0 +1,77 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.graph.impl;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.procedure.SyncListener;\r
+import org.simantics.db.request.Read;\r
+\r
+import org.simantics.objmap.exceptions.MappingException;\r
+import org.simantics.objmap.forward.IForwardMapping;\r
+import org.simantics.objmap.graph.impl.Link;\r
+\r
+\r
+public class RangeUpdateRequest<Domain,Range> implements Read<Boolean>, SyncListener<Boolean> {\r
+\r
+    Link<Domain,Range> link;\r
+    /*\r
+     * Note that this map uses a read request that it has got from caller and \r
+     * not the one that is used in updateRange. This is intentional.\r
+     */\r
+    IForwardMapping<Domain, Range> map; // map==null is used to flag that request is performed once\r
+    Mapping<Domain, Range> mapping; // mapping==null is used as a flag the request disposed\r
+    \r
+    public RangeUpdateRequest(Link<Domain,Range> link, IForwardMapping<Domain,Range> map, Mapping<Domain,Range> mapping) {\r
+        this.link = link;\r
+        this.map = map;\r
+        this.mapping = mapping;\r
+    }\r
+\r
+    @Override\r
+    public Boolean perform(ReadGraph g) throws DatabaseException {\r
+        if(map != null) {\r
+            link.type.updateRange(g, map, link.domainElement, link.rangeElement);\r
+            map = null;\r
+            return Boolean.TRUE;\r
+        }\r
+        else if(mapping != null) {\r
+            mapping.domainModified(link);\r
+            mapping = null;\r
+            return Boolean.FALSE;\r
+        }\r
+        else\r
+            return null;\r
+    }\r
+    \r
+    @Override\r
+    public void exception(ReadGraph graph, Throwable throwable)\r
+            throws DatabaseException {\r
+        if(throwable instanceof DatabaseException)\r
+            throw (DatabaseException)throwable;\r
+        else\r
+            throw new MappingException(throwable);\r
+    }\r
+\r
+    @Override\r
+    public void execute(ReadGraph graph, Boolean result)\r
+            throws DatabaseException {       \r
+    }\r
+\r
+    @Override\r
+    public boolean isDisposed() {\r
+        return mapping == null || link.removed || mapping.isDisposed();\r
+    }\r
+    \r
+    \r
+    \r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/MappedElementRule.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/MappedElementRule.java
new file mode 100644 (file)
index 0000000..85d8b6e
--- /dev/null
@@ -0,0 +1,73 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.graph.rules;\r
+\r
+import org.apache.log4j.Logger;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.objmap.backward.IBackwardMapping;\r
+import org.simantics.objmap.bidirectional.IBidirectionalMappingRule;\r
+import org.simantics.objmap.exceptions.MappingException;\r
+import org.simantics.objmap.forward.IForwardMapping;\r
+import org.simantics.objmap.graph.rules.domain.IDomainAccessor;\r
+import org.simantics.objmap.graph.rules.range.IRangeAccessor;\r
+\r
+\r
+\r
+\r
+/**\r
+ * A rule that synchronizes collection of elements between\r
+ * domain and range accessors. Elements are mapped from\r
+ * between domain and range during the synchronization.\r
+ * @author Hannu Niemistö\r
+ */\r
+public class MappedElementRule<Domain, Range> implements IBidirectionalMappingRule<Domain, Range> {\r
+    \r
+    static Logger LOGGER = Logger.getLogger("org.simantics.objmap");\r
+    \r
+       IDomainAccessor<Domain,Domain> domainAccessor;\r
+       IRangeAccessor<Range,Range> rangeAccessor;\r
+       \r
+       public MappedElementRule(IDomainAccessor<Domain,Domain> domainAccessor,\r
+            IRangeAccessor<Range,Range> rangeAccessor) {\r
+        this.domainAccessor = domainAccessor;\r
+        this.rangeAccessor = rangeAccessor;\r
+    }\r
+\r
+    @Override\r
+       public boolean updateDomain(WriteGraph g, IBackwardMapping<Domain, Range> map,\r
+                       Domain domainElement, Range rangeElement)\r
+                       throws MappingException {\r
+        LOGGER.info("    MappedElementRule.updateDomain");\r
+           Range value = rangeAccessor.get(rangeElement);\r
+           Domain mappedValue = value == null ? null : map.inverseMap(g, value);//map.inverseGet(value);\r
+               return domainAccessor.set(g, domainElement, mappedValue);\r
+       }\r
+\r
+       @Override\r
+       public boolean updateRange(ReadGraph g, IForwardMapping<Domain, Range> map,\r
+                       Domain domainElement, Range rangeElement)\r
+                       throws MappingException {\r
+        LOGGER.info("    MappedElementRule.updateRange");   \r
+           Domain value = domainAccessor.get(g, domainElement);\r
+        Range mappedValue = value == null ? null : map.map(g, value);////map.get(value);\r
+        return rangeAccessor.set(rangeElement, mappedValue);\r
+       }       \r
+       \r
+       public void createDomain(WriteGraph g, IBackwardMapping<Domain,Range> map, Domain domainElement, Range rangeElement) throws MappingException {\r
+               updateDomain(g, map, domainElement, rangeElement);\r
+       };\r
+       \r
+       public void createRange(ReadGraph g, IForwardMapping<Domain,Range> map, Domain domainElement, Range rangeElement) throws MappingException {\r
+               updateRange(g, map, domainElement, rangeElement);\r
+       };\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/MappedElementsRule.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/MappedElementsRule.java
new file mode 100644 (file)
index 0000000..6f24fb1
--- /dev/null
@@ -0,0 +1,82 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.graph.rules;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+\r
+import org.apache.log4j.Logger;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.objmap.backward.IBackwardMapping;\r
+import org.simantics.objmap.bidirectional.IBidirectionalMappingRule;\r
+import org.simantics.objmap.exceptions.MappingException;\r
+import org.simantics.objmap.forward.IForwardMapping;\r
+import org.simantics.objmap.graph.rules.domain.IDomainAccessor;\r
+import org.simantics.objmap.graph.rules.range.IRangeAccessor;\r
+\r
+\r
+/**\r
+ * A rule that synchronizes collection of elements between\r
+ * domain and range accessors. Elements are mapped from\r
+ * between domain and range during the synchronization.\r
+ * @author Hannu Niemistö\r
+ */\r
+public class MappedElementsRule<Domain, Range> implements IBidirectionalMappingRule<Domain, Range> {\r
+\r
+    static Logger LOGGER = Logger.getLogger("org.simantics.objmap");\r
+\r
+    IDomainAccessor<Domain,Collection<Domain>> domainAccessor;\r
+    IRangeAccessor<Range,Collection<Range>> rangeAccessor;\r
+\r
+    public MappedElementsRule(IDomainAccessor<Domain,Collection<Domain>> domainAccessor,\r
+            IRangeAccessor<Range,Collection<Range>> rangeAccessor) {\r
+        this.domainAccessor = domainAccessor;\r
+        this.rangeAccessor = rangeAccessor;\r
+    }\r
+\r
+    @Override\r
+    public boolean updateDomain(WriteGraph g, IBackwardMapping<Domain, Range> map,\r
+            Domain domainElement, Range rangeElement)\r
+    throws MappingException {\r
+        LOGGER.info("    MappedElementsRule.updateDomain");\r
+        // Snapshot the accessed range value for concurrency safety.\r
+        // NOTE: still assumes that the accessed collection is concurrent or\r
+        // synchronized for toArray to be atomic.\r
+        Collection<Range> value = rangeAccessor.get(rangeElement);\r
+        Object[] rangeSnapshot = value.toArray();\r
+        ArrayList<Domain> mappedValue = new ArrayList<Domain>(rangeSnapshot.length);\r
+        for (Object obj : rangeSnapshot)\r
+            mappedValue.add(map.inverseMap(g, (Range)obj));//map.inverseGet((Range)obj));\r
+        return domainAccessor.set(g, domainElement, mappedValue);\r
+    }\r
+\r
+    @Override\r
+    public boolean updateRange(ReadGraph g, IForwardMapping<Domain, Range> map,\r
+            Domain domainElement, Range rangeElement)\r
+    throws MappingException {\r
+        LOGGER.info("    MappedElementsRule.updateRange");\r
+        Collection<Domain> value = domainAccessor.get(g, domainElement);\r
+        ArrayList<Range> mappedValue = new ArrayList<Range>(value.size());\r
+        for(Domain r : value)\r
+            mappedValue.add(map.map(g, r));//map.get(r));\r
+        return rangeAccessor.set(rangeElement, mappedValue);\r
+    }\r
+    \r
+    public void createDomain(WriteGraph g, IBackwardMapping<Domain,Range> map, Domain domainElement, Range rangeElement) throws MappingException {\r
+       updateDomain(g, map, domainElement, rangeElement);\r
+    };\r
+    \r
+    public void createRange(ReadGraph g, IForwardMapping<Domain,Range> map, Domain domainElement, Range rangeElement) throws MappingException {\r
+       updateRange(g, map, domainElement, rangeElement);\r
+    };\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/ValueRule.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/ValueRule.java
new file mode 100644 (file)
index 0000000..468a0c2
--- /dev/null
@@ -0,0 +1,69 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.graph.rules;\r
+\r
+import org.apache.log4j.Logger;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.objmap.backward.IBackwardMapping;\r
+import org.simantics.objmap.bidirectional.IBidirectionalMappingRule;\r
+import org.simantics.objmap.exceptions.MappingException;\r
+import org.simantics.objmap.forward.IForwardMapping;\r
+import org.simantics.objmap.graph.rules.domain.IDomainAccessor;\r
+import org.simantics.objmap.graph.rules.range.IRangeAccessor;\r
+\r
+\r
+/**\r
+ * A rule that synchronizes values between domain and\r
+ * range accessors.\r
+ * @author Hannu Niemistö\r
+ */\r
+public class ValueRule<Domain, Range> implements IBidirectionalMappingRule<Domain, Range> {\r
+    \r
+    static Logger LOGGER = Logger.getLogger("org.simantics.objmap");\r
+    \r
+       IDomainAccessor<Domain,Object> domainAccessor;\r
+       IRangeAccessor<Range,Object> rangeAccessor;\r
+       \r
+       public ValueRule(IDomainAccessor<Domain,Object> domainAccessor,\r
+                       IRangeAccessor<Range,Object> rangeAccessor) {\r
+               this.domainAccessor = domainAccessor;\r
+               this.rangeAccessor = rangeAccessor;\r
+       }\r
+\r
+       @Override\r
+       public boolean updateDomain(WriteGraph g, IBackwardMapping<Domain, Range> map,\r
+                       Domain domainElement, Range rangeElement)\r
+                       throws MappingException {\r
+        LOGGER.info("    ValueRule.updateDomain");         \r
+               Object value = rangeAccessor.get(rangeElement);\r
+               return domainAccessor.set(g, domainElement, value);\r
+       }\r
+\r
+       @Override\r
+       public boolean updateRange(ReadGraph g, IForwardMapping<Domain, Range> map,\r
+                       Domain domainElement, Range rangeElement)\r
+                       throws MappingException {\r
+        LOGGER.info("    ValueRule.updateRange");\r
+               Object value = domainAccessor.get(g, domainElement);\r
+               return rangeAccessor.set(rangeElement, value);\r
+       }       \r
+       \r
+       public void createDomain(WriteGraph g, IBackwardMapping<Domain,Range> map, Domain domainElement, Range rangeElement) throws MappingException {\r
+               updateDomain(g, map, domainElement, rangeElement);\r
+       };\r
+       public void createRange(ReadGraph g, IForwardMapping<Domain,Range> map, Domain domainElement, Range rangeElement) throws MappingException {\r
+               updateRange(g, map, domainElement, rangeElement);\r
+       };\r
+}\r
+\r
+\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/adapters/IdentityAdapter.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/adapters/IdentityAdapter.java
new file mode 100644 (file)
index 0000000..7c498ec
--- /dev/null
@@ -0,0 +1,23 @@
+package org.simantics.objmap.graph.rules.adapters;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+\r
+public enum IdentityAdapter implements ValueAdapter {\r
+    INSTANCE;\r
+\r
+    @Override\r
+    public Object domainToRange(Object domainValue) {\r
+        return domainValue;\r
+    }\r
+\r
+    @Override\r
+    public Object rangeToDomain(Object rangeValue) {\r
+        return rangeValue;\r
+    }\r
+\r
+    @Override\r
+    public Resource rangeTypeToDomainType(ReadGraph graph, Class<?> rangeType) {\r
+        return null;\r
+    }\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/adapters/ValueAdapter.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/adapters/ValueAdapter.java
new file mode 100644 (file)
index 0000000..1910059
--- /dev/null
@@ -0,0 +1,10 @@
+package org.simantics.objmap.graph.rules.adapters;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+\r
+public interface ValueAdapter {\r
+    Resource rangeTypeToDomainType(ReadGraph graph, Class<?> rangeType);\r
+    Object domainToRange(Object domainValue);\r
+    Object rangeToDomain(Object rangeValue);\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/domain/CompoundValueAccessor.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/domain/CompoundValueAccessor.java
new file mode 100644 (file)
index 0000000..abf15ec
--- /dev/null
@@ -0,0 +1,151 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.graph.rules.domain;\r
+\r
+import java.util.Arrays;\r
+import java.util.Collection;\r
+import java.util.HashMap;\r
+import java.util.Map;\r
+\r
+import org.apache.log4j.Logger;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.Statement;\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.layer0.Layer0;\r
+import org.simantics.objmap.exceptions.MappingException;\r
+import org.simantics.objmap.graph.annotations.factories.CompoundRelatedGetSetValueRuleFactory;\r
+\r
+/**\r
+ * \r
+ * @author Marko Luukkainen\r
+ */\r
+public class CompoundValueAccessor implements IDomainAccessor<Resource,Object> {\r
+\r
+    static Logger LOGGER = Logger.getLogger("org.simantics.objmap");\r
+    \r
+       Resource objRelation;\r
+       Resource objType;\r
+       Resource valRelation;\r
+\r
+       public CompoundValueAccessor(Resource objRelation, Resource objType, Resource valRelation) {\r
+               this.objRelation = objRelation;\r
+               this.objType = objType;\r
+               this.valRelation = valRelation;\r
+       }\r
+\r
+       @Override\r
+       public Object get(ReadGraph g, Resource element) throws MappingException {\r
+               try {\r
+                       Layer0 l0 = Layer0.getInstance(g);\r
+                   LOGGER.info("        CompoundValueAccessor.get");\r
+                   Collection<Statement> coll = g.getStatements(element, objRelation);\r
+                   Map<String,Object> map = new HashMap<String, Object>();\r
+                   for (Statement c : coll) {\r
+                       String name = g.getRelatedValue(c.getObject(), l0.HasName);\r
+                       if (!map.containsKey(name) || !c.isAsserted(element))\r
+                               map.put(name, g.getRelatedValue(c.getObject(), valRelation));\r
+                   }\r
+                       return map;\r
+               } catch (DatabaseException e) {\r
+                       throw new MappingException(e);\r
+               }\r
+       }\r
+       \r
+       @Override\r
+       public boolean set(WriteGraph g, Resource element, Object v)\r
+                       throws MappingException {\r
+               try {\r
+                       Layer0 l0 = Layer0.getInstance(g);\r
+                   LOGGER.info("        CompoundValueAccessor.set");\r
+                   Map<String,Object> values = (Map<String, Object>)v;\r
+                   \r
+                   Collection<Statement> coll = g.getStatements(element, objRelation);\r
+                   Map<String,Statement> stmMap = new HashMap<String, Statement>();\r
+                   Map<String,Object> valueMap = new HashMap<String, Object>();\r
+                   for (Statement c : coll) {\r
+                       String name = g.getRelatedValue(c.getObject(), l0.HasName);\r
+                       if (!stmMap.containsKey(name) || !c.isAsserted(element)) {\r
+                               stmMap.put(name, c);\r
+                               valueMap.put(name, g.getRelatedValue(c.getObject(), valRelation));\r
+                       }\r
+                   }\r
+                   boolean changed = false;\r
+                   for (String key : values.keySet()) {\r
+                       Object value = values.get(key);\r
+                       if (value.equals(valueMap.get(key)))\r
+                               continue;\r
+                       changed = true;\r
+                       Statement stm = stmMap.get(key);\r
+                       if (stm == null || stm.isAsserted(element)) {\r
+                               Resource obj = g.newResource();\r
+                               g.claim(obj, l0.InstanceOf, objType);\r
+                               g.claimLiteral(obj, l0.HasName, key);\r
+                               g.claim(element, objRelation, obj);\r
+                               stm = getStatement(g, element, objRelation, obj);\r
+                       }\r
+                       \r
+                       Statement valueStatement = g.getPossibleStatement(stm.getObject(), valRelation);\r
+                       Resource valueType = CompoundRelatedGetSetValueRuleFactory.dataTypeOfClass(g, value.getClass());\r
+                               if(valueStatement == null) {\r
+                                       \r
+                                       Resource valueResource = g.newResource();\r
+                                       g.claim(valueResource, Layer0.getInstance(g).InstanceOf, null,  valueType);\r
+                                       g.claim(stm.getObject(), valRelation, valueResource);\r
+                                       g.claimValue(valueResource, value);                             \r
+                               } else {\r
+                                                                       \r
+                                       \r
+                                       if (!valueStatement.isAsserted(stm.getObject()))\r
+                                               g.claimValue(valueStatement.getObject(), value);\r
+                                       else {\r
+                                               Resource valueResource = g.newResource();\r
+                                               g.claim(valueResource, Layer0.getInstance(g).InstanceOf, null,\r
+                                                               valueType);\r
+                                               g.claim(stm.getObject(), valRelation, valueResource);\r
+                                               g.claimValue(valueResource, value);\r
+                                       }\r
+                               }\r
+                   }\r
+                   return changed;\r
+                   \r
+               } catch (DatabaseException e) {\r
+                       throw new MappingException(e);\r
+               }\r
+               \r
+       }\r
+       \r
+       private Statement getStatement(ReadGraph g, Resource s, Resource p, Resource o) throws DatabaseException{\r
+               for (Statement stm : g.getStatements(s, p)) {\r
+                       if (stm.getObject().equals(o))\r
+                               return stm;\r
+               }\r
+               return null;\r
+       }\r
+       \r
+       private boolean equals(Object o1, Object o2) {\r
+               if (o1 instanceof boolean[])\r
+                       Arrays.equals((boolean[])o1,(boolean[])o2);\r
+               if (o1 instanceof int[])\r
+                       Arrays.equals((int[])o1,(int[])o2);\r
+               if (o1 instanceof float[])\r
+                       Arrays.equals((float[])o1,(float[])o2);\r
+               if (o1 instanceof double[])\r
+                       Arrays.equals((double[])o1,(double[])o2);\r
+               if (o1 instanceof byte[])\r
+                       Arrays.equals((byte[])o1,(byte[])o2);\r
+               return o1.equals(o2);\r
+               \r
+       }\r
+\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/domain/IDomainAccessor.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/domain/IDomainAccessor.java
new file mode 100644 (file)
index 0000000..cd9b697
--- /dev/null
@@ -0,0 +1,26 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.graph.rules.domain;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.objmap.exceptions.MappingException;\r
+\r
+\r
+/**\r
+ * Provides access to some property of domain elements.\r
+ * @author Hannu Niemistö\r
+ */\r
+public interface IDomainAccessor<Domain,T> {\r
+       T get(ReadGraph g, Domain element) throws MappingException;\r
+       boolean set(WriteGraph g, Domain element, T value) throws MappingException;\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/domain/MappingUtils.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/domain/MappingUtils.java
new file mode 100644 (file)
index 0000000..1b6724b
--- /dev/null
@@ -0,0 +1,92 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.graph.rules.domain;\r
+\r
+import java.util.Arrays;\r
+import java.util.Collection;\r
+\r
+import org.apache.log4j.Logger;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.db.exception.DatabaseException;\r
+\r
+/**\r
+ * Static utility methods for rule implementations.\r
+ * @author Hannu Niemistö\r
+ */\r
+public class MappingUtils {\r
+\r
+    static Logger LOGGER = Logger.getLogger("org.simantics.objmap");\r
+    \r
+    /**\r
+     * Adds and removes statements to/from the database so that <code>objects</code>\r
+     * will be exactly the objects connected to <code>subject</code> by <code>predicate</code>.\r
+     * Returns true if the method made modifications to the database.\r
+     */\r
+       public static boolean synchronizeStatements(WriteGraph g, Resource subject, Resource predicate, Resource[] objects,\r
+               boolean deleteExtraObjects) \r
+               throws DatabaseException {\r
+               Collection<Resource> currentObjects0 = g.getObjects(subject, predicate);\r
+               Resource[] currentObjects = currentObjects0.toArray(new Resource[currentObjects0.size()]);\r
+               \r
+               Arrays.sort(objects);\r
+               Arrays.sort(currentObjects);\r
+               \r
+               boolean modified = false;\r
+               int i=0, j=0;   \r
+               if(currentObjects.length > 0 && objects.length > 0)\r
+               while(true) {\r
+                       int cmp = currentObjects[i].compareTo(objects[j]);\r
+                       if(cmp < 0) {\r
+                           LOGGER.info("            remove statement");\r
+                           if(deleteExtraObjects)\r
+                               g.deny(currentObjects[i]);\r
+                           else\r
+                               g.denyStatement(subject, predicate, currentObjects[i]);                                 \r
+                               modified = true;\r
+                               ++i;\r
+                               if(i >= currentObjects.length)\r
+                                       break;\r
+                       }\r
+                       else if(cmp > 0) {\r
+                           LOGGER.info("            add statement");\r
+                               g.claim(subject, predicate, objects[j]);\r
+                               modified = true;\r
+                               ++j;\r
+                               if(j >= objects.length)\r
+                                       break;\r
+                       }\r
+                       else {\r
+                               ++i; ++j;\r
+                               if(i >= currentObjects.length)\r
+                                       break;\r
+                               if(j >= objects.length)\r
+                                       break;\r
+                       }\r
+               }\r
+               while(i < currentObjects.length) {\r
+                   if(deleteExtraObjects)\r
+                g.deny(currentObjects[i]);\r
+            else\r
+                g.denyStatement(subject, predicate, currentObjects[i]);\r
+                       modified = true;\r
+                       ++i;\r
+               }\r
+               while(j < objects.length) {\r
+                       g.claim(subject, predicate, objects[j]);\r
+                       modified = true;\r
+                       ++j;\r
+               }\r
+               return modified;\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/domain/RelatedObjectAccessor.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/domain/RelatedObjectAccessor.java
new file mode 100644 (file)
index 0000000..f1f4ce6
--- /dev/null
@@ -0,0 +1,71 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.graph.rules.domain;\r
+\r
+import org.apache.log4j.Logger;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.objmap.exceptions.MappingException;\r
+\r
+/**\r
+ * Accesses a resource attached to the element by given functional relation.\r
+ * @author Hannu Niemistö\r
+ */\r
+public class RelatedObjectAccessor implements IDomainAccessor<Resource,Resource> {\r
+\r
+    static Logger LOGGER = Logger.getLogger("org.simantics.objmap");\r
+    \r
+       Resource relation;\r
+       \r
+       public RelatedObjectAccessor(Resource relation) {\r
+               this.relation = relation;\r
+       }\r
+\r
+       @Override\r
+       public Resource get(ReadGraph g, Resource element) throws MappingException {\r
+               try {\r
+                   LOGGER.info("        RelatedObjectAccessor.get");\r
+                       return g.getPossibleObject(element, relation);\r
+               } catch (DatabaseException e) {\r
+                       throw new MappingException(e);\r
+               }\r
+       }\r
+       \r
+       @Override\r
+       public boolean set(WriteGraph g, Resource element, Resource value)\r
+                       throws MappingException {\r
+               try {\r
+                   LOGGER.info("        RelatedObjectAccessor.set");\r
+                   Resource resource = g.getPossibleObject(element, relation);\r
+                       if(resource == null) {\r
+                           if(value == null)\r
+                               return false;\r
+                           g.claim(element, relation, value);\r
+                           return true;\r
+                       }\r
+                       else if(resource.equals(value))\r
+                           return false;\r
+                       else {\r
+                           g.deny(element, relation);\r
+                           if(value != null)\r
+                               g.claim(element, relation, value);\r
+                           return true;\r
+                       }\r
+               } catch (DatabaseException e) {\r
+                       throw new MappingException(e);\r
+               }\r
+               \r
+       }\r
+\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/domain/RelatedObjectsAccessor.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/domain/RelatedObjectsAccessor.java
new file mode 100644 (file)
index 0000000..a544116
--- /dev/null
@@ -0,0 +1,63 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.graph.rules.domain;\r
+\r
+import java.util.Collection;\r
+\r
+import org.apache.log4j.Logger;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.objmap.exceptions.MappingException;\r
+\r
+/**\r
+ * Accesses the set of objects attached to the element by the given relation.\r
+ * @author Hannu Niemistö\r
+ */\r
+public class RelatedObjectsAccessor implements IDomainAccessor<Resource,Collection<Resource>> {\r
+\r
+    static Logger LOGGER = Logger.getLogger("org.simantics.objmap");\r
+    \r
+       Resource relation;\r
+       boolean deleteExtraObjects;\r
+\r
+       public RelatedObjectsAccessor(Resource relation, boolean deleteExtraObjects) {\r
+        super();\r
+        this.relation = relation;\r
+        this.deleteExtraObjects = deleteExtraObjects;\r
+    }\r
+\r
+    @Override\r
+       public Collection<Resource> get(ReadGraph g, Resource element) throws MappingException {\r
+               try {\r
+                   LOGGER.info("        RelatedObjectsAccessor.get");\r
+                       return g.getObjects(element, relation);\r
+               } catch (DatabaseException e) {\r
+                       throw new MappingException(e);\r
+               }\r
+       }\r
+       \r
+       @Override\r
+       public boolean set(WriteGraph g, Resource element, Collection<Resource> value)\r
+                       throws MappingException {\r
+               try {\r
+                   LOGGER.info("        RelatedObjectsAccessor.set");\r
+                       return MappingUtils.synchronizeStatements(g, element, relation, \r
+                               value.toArray(new Resource[value.size()]), deleteExtraObjects);\r
+               } catch (DatabaseException e) {\r
+                       throw new MappingException(e);\r
+               }\r
+               \r
+       }\r
+\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/domain/RelatedOrderedSetElementsAccessor.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/domain/RelatedOrderedSetElementsAccessor.java
new file mode 100644 (file)
index 0000000..7458379
--- /dev/null
@@ -0,0 +1,62 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.graph.rules.domain;\r
+\r
+import java.util.Collection;\r
+\r
+import org.apache.log4j.Logger;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.db.common.utils.OrderedSetUtils;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.objmap.exceptions.MappingException;\r
+\r
+/**\r
+ * Accesses the set of objects attached to the element by the given relation.\r
+ * @author Hannu Niemistö\r
+ */\r
+public class RelatedOrderedSetElementsAccessor implements IDomainAccessor<Resource, Collection<Resource>> {\r
+\r
+    static Logger LOGGER = Logger.getLogger("org.simantics.objmap");\r
+    \r
+       boolean deleteExtraObjects;\r
+\r
+       public RelatedOrderedSetElementsAccessor(boolean deleteExtraObjects) {\r
+        super();\r
+        this.deleteExtraObjects = deleteExtraObjects;\r
+    }\r
+\r
+    @Override\r
+       public Collection<Resource> get(ReadGraph g, Resource element) throws MappingException {\r
+               try {\r
+                   LOGGER.info("        RelatedOrderedSetElementsAccessor.get");\r
+                       return OrderedSetUtils.toList(g, element);\r
+               } catch (DatabaseException e) {\r
+                       throw new MappingException(e);\r
+               }\r
+       }\r
+       \r
+       @Override\r
+       public boolean set(WriteGraph g, Resource element, Collection<Resource> value)\r
+                       throws MappingException {\r
+               try {\r
+                   LOGGER.info("        RelatedOrderedSetElementsAccessor.set");\r
+                   return OrderedSetUtils.set(g, element, value);\r
+                   // FIXME Implement deleteExtraObjects\r
+               } catch (DatabaseException e) {\r
+                       throw new MappingException(e);\r
+               }\r
+               \r
+       }\r
+\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/domain/RelatedValueAccessor.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/domain/RelatedValueAccessor.java
new file mode 100644 (file)
index 0000000..e4531c4
--- /dev/null
@@ -0,0 +1,114 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.graph.rules.domain;\r
+\r
+import java.util.Arrays;\r
+\r
+import org.apache.log4j.Logger;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.Statement;\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.layer0.Layer0;\r
+import org.simantics.objmap.exceptions.MappingException;\r
+\r
+/**\r
+ * Accesses a value attached to the element by given functional relation.\r
+ * @author Hannu Niemist�\r
+ */\r
+public class RelatedValueAccessor implements IDomainAccessor<Resource,Object> {\r
+\r
+    static Logger LOGGER = Logger.getLogger("org.simantics.objmap");\r
+    \r
+       Resource relation;\r
+       Resource valueType;\r
+\r
+       public RelatedValueAccessor(Resource relation, Resource valueType) {\r
+               this.relation = relation;\r
+               this.valueType = valueType;\r
+       }\r
+\r
+       @Override\r
+       public Object get(ReadGraph g, Resource element) throws MappingException {\r
+               try {\r
+                   LOGGER.info("        RelatedValueAccessor.get");\r
+                       Resource valueResource = g.getPossibleObject(element, relation);\r
+                       if(valueResource == null)\r
+                               return null;\r
+                       return g.getValue(valueResource);\r
+               } catch (DatabaseException e) {\r
+                       throw new MappingException(e);\r
+               }\r
+       }\r
+       \r
+       @Override\r
+       public boolean set(WriteGraph g, Resource element, Object value)\r
+                       throws MappingException {\r
+               try {\r
+                   LOGGER.info("        RelatedValueAccessor.set");\r
+                   Statement valueStatement = g.getPossibleStatement(element, relation);\r
+                       if(valueStatement == null) {\r
+                               if(value == null)\r
+                                       return false;\r
+                               Resource valueResource = g.newResource();\r
+                               g.claim(valueResource, Layer0.getInstance(g).InstanceOf, null,\r
+                                               valueType);\r
+                               g.claim(element, relation, valueResource);\r
+                               g.claimValue(valueResource, value);                             \r
+                               return true;\r
+                       }\r
+                       else {\r
+                               if(value == null) {\r
+                                       if (!valueStatement.isAsserted(element)) {\r
+                                               g.deny(valueStatement.getObject());\r
+                                               return true;\r
+                                       } else {\r
+                                               return false;\r
+                                       }\r
+                               }                               \r
+                               Object currentValue = g.getValue(valueStatement.getObject());\r
+                               if(equals(currentValue,value))\r
+                                       return false;\r
+                               if (!valueStatement.isAsserted(element))\r
+                                       g.claimValue(valueStatement.getObject(), value);\r
+                               else {\r
+                                       Resource valueResource = g.newResource();\r
+                                       g.claim(valueResource, Layer0.getInstance(g).InstanceOf, null,\r
+                                                       valueType);\r
+                                       g.claim(element, relation, valueResource);\r
+                                       g.claimValue(valueResource, value);\r
+                               }\r
+                               return true;\r
+                       }\r
+               } catch (DatabaseException e) {\r
+                       throw new MappingException(e);\r
+               }\r
+               \r
+       }\r
+       \r
+       private boolean equals(Object o1, Object o2) {\r
+               if (o1 instanceof boolean[])\r
+                       Arrays.equals((boolean[])o1,(boolean[])o2);\r
+               if (o1 instanceof int[])\r
+                       Arrays.equals((int[])o1,(int[])o2);\r
+               if (o1 instanceof float[])\r
+                       Arrays.equals((float[])o1,(float[])o2);\r
+               if (o1 instanceof double[])\r
+                       Arrays.equals((double[])o1,(double[])o2);\r
+               if (o1 instanceof byte[])\r
+                       Arrays.equals((byte[])o1,(byte[])o2);\r
+               return o1.equals(o2);\r
+               \r
+       }\r
+\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/factory/IClassRuleFactory.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/factory/IClassRuleFactory.java
new file mode 100644 (file)
index 0000000..bb307ce
--- /dev/null
@@ -0,0 +1,22 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.graph.rules.factory;\r
+\r
+import java.lang.annotation.Annotation;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.objmap.bidirectional.IBidirectionalMappingRule;\r
+\r
+public interface IClassRuleFactory<Domain, Range> {\r
+    IBidirectionalMappingRule<Domain, Range> create(ReadGraph g, Annotation annotation, Class<?> clazz) throws DatabaseException;\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/factory/ICollectionRuleFactory.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/factory/ICollectionRuleFactory.java
new file mode 100644 (file)
index 0000000..835639a
--- /dev/null
@@ -0,0 +1,14 @@
+package org.simantics.objmap.graph.rules.factory;\r
+\r
+import java.lang.annotation.Annotation;\r
+import java.lang.reflect.Method;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.objmap.bidirectional.IBidirectionalMappingRule;\r
+\r
+public interface ICollectionRuleFactory<Domain,Range> {\r
+       IBidirectionalMappingRule<Domain, Range> create(ReadGraph g, Annotation annotation, Method getter, Method adder, Method remover) throws DatabaseException;\r
+       boolean isAdder(Annotation getterAnnotation, Annotation annotation);\r
+       boolean isRemover(Annotation getterAnnotation, Annotation annotation);\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/factory/IFieldRuleFactory.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/factory/IFieldRuleFactory.java
new file mode 100644 (file)
index 0000000..6da0454
--- /dev/null
@@ -0,0 +1,23 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.graph.rules.factory;\r
+\r
+import java.lang.annotation.Annotation;\r
+import java.lang.reflect.Field;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.objmap.bidirectional.IBidirectionalMappingRule;\r
+\r
+public interface IFieldRuleFactory<Domain, Range> {\r
+    IBidirectionalMappingRule<Domain, Range> create(ReadGraph g, Annotation annotation, Field field) throws DatabaseException;\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/factory/IGetSetRuleFactory.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/factory/IGetSetRuleFactory.java
new file mode 100644 (file)
index 0000000..e3397d6
--- /dev/null
@@ -0,0 +1,13 @@
+package org.simantics.objmap.graph.rules.factory;\r
+\r
+import java.lang.annotation.Annotation;\r
+import java.lang.reflect.Method;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.objmap.bidirectional.IBidirectionalMappingRule;\r
+\r
+public interface IGetSetRuleFactory<Domain,Range> {\r
+       IBidirectionalMappingRule<Domain, Range> create(ReadGraph g, Annotation annotation, Method getter, Method setter) throws DatabaseException;\r
+       boolean isSetter(Annotation getterAnnotation, Annotation annotation);\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/factory/IMethodRuleFactory.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/factory/IMethodRuleFactory.java
new file mode 100644 (file)
index 0000000..96336ee
--- /dev/null
@@ -0,0 +1,23 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.graph.rules.factory;\r
+\r
+import java.lang.annotation.Annotation;\r
+import java.lang.reflect.Method;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.objmap.bidirectional.IBidirectionalMappingRule;\r
+\r
+public interface IMethodRuleFactory<Domain, Range> {\r
+    IBidirectionalMappingRule<Domain, Range> create(ReadGraph g, Annotation annotation, Method method) throws DatabaseException;\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/range/AdaptedRangeAccessor.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/range/AdaptedRangeAccessor.java
new file mode 100644 (file)
index 0000000..a38cb9e
--- /dev/null
@@ -0,0 +1,27 @@
+package org.simantics.objmap.graph.rules.range;\r
+\r
+import org.simantics.objmap.exceptions.MappingException;\r
+import org.simantics.objmap.graph.rules.adapters.ValueAdapter;\r
+\r
+\r
+\r
+public class AdaptedRangeAccessor<Range> implements IRangeAccessor<Range,Object> {\r
+    IRangeAccessor<Range,Object> baseAccessor;\r
+    ValueAdapter adapter;\r
+    \r
+    public AdaptedRangeAccessor(IRangeAccessor<Range,Object> baseAccessror,\r
+            ValueAdapter adapter) {\r
+        this.baseAccessor = baseAccessror;\r
+        this.adapter = adapter;\r
+    }\r
+\r
+    @Override\r
+    public Object get(Range element) throws MappingException {\r
+        return adapter.rangeToDomain(baseAccessor.get(element));    \r
+    }\r
+    \r
+    @Override\r
+    public boolean set(Range element, Object value) throws MappingException {\r
+        return baseAccessor.set(element, adapter.domainToRange(value));\r
+    }\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/range/CollectionAccessor.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/range/CollectionAccessor.java
new file mode 100644 (file)
index 0000000..c4141f7
--- /dev/null
@@ -0,0 +1,80 @@
+package org.simantics.objmap.graph.rules.range;\r
+\r
+import java.lang.reflect.InvocationTargetException;\r
+import java.lang.reflect.Method;\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+\r
+import org.simantics.objmap.exceptions.MappingException;\r
+\r
+\r
+/**\r
+ * Accessor for mapped collections. \r
+ * Uses three methods:\r
+ * - Getter: returns the collection.\r
+ * - Adder: adds one item into the collection.\r
+ * - Remover: removes one item from the collection. \r
+ * \r
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>\r
+ *\r
+ * @param <T>\r
+ */\r
+public class CollectionAccessor<Range,T>  implements IRangeAccessor<Range,Collection<T>> {\r
+       \r
+       private Method getter;\r
+       private Method adder;\r
+       private Method remover;\r
+       \r
+       public CollectionAccessor(Method getter, Method adder, Method remover) {\r
+               this.getter = getter;\r
+               this.adder = adder;\r
+               this.remover = remover;\r
+       }\r
+       \r
+       @SuppressWarnings("unchecked")\r
+       public java.util.Collection<T> get(Object element) throws MappingException {\r
+               try {\r
+                       return (Collection<T>) getter.invoke(element);\r
+               } catch (IllegalArgumentException e) {\r
+                       throw new MappingException(e);\r
+               } catch (IllegalAccessException e) {\r
+                       throw new MappingException(e);\r
+               } catch (InvocationTargetException e) {\r
+                       throw new MappingException(e);\r
+               }\r
+       };\r
+\r
+       @Override\r
+       public boolean set(Range element, Collection<T> value)\r
+                       throws MappingException {\r
+               java.util.Collection<T> current = get(element);\r
+               Collection<T> adding = new ArrayList<T>();\r
+               Collection<T> removing = new ArrayList<T>();\r
+               for (T e : current) {\r
+                       if (!value.contains(e))\r
+                               removing.add(e);\r
+               }\r
+               for (T e : value) {\r
+                       if (!current.contains(e))\r
+                               adding.add(e);\r
+               }\r
+               \r
+               try {\r
+                       for (T e : removing) {\r
+                               remover.invoke(element, e);\r
+                       }\r
+                       \r
+                       for (T e : adding) {\r
+                               adder.invoke(element, e);\r
+                       }\r
+               } catch (IllegalArgumentException e) {\r
+                       throw new MappingException(e);\r
+               } catch (IllegalAccessException e) {\r
+                       throw new MappingException(e);\r
+               } catch (InvocationTargetException e) {\r
+                       throw new MappingException(e);\r
+               }\r
+               return removing.size() > 0 || adding.size() > 0;\r
+               \r
+       }\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/range/CompoundGetSetValueAccessor.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/range/CompoundGetSetValueAccessor.java
new file mode 100644 (file)
index 0000000..ce05153
--- /dev/null
@@ -0,0 +1,73 @@
+package org.simantics.objmap.graph.rules.range;\r
+\r
+import java.lang.reflect.InvocationTargetException;\r
+import java.lang.reflect.Method;\r
+\r
+import org.simantics.objmap.exceptions.MappingException;\r
+\r
+\r
+/**\r
+ * Accessor for mapped value. Uses two methods:\r
+ * - Getter: returns the current value.\r
+ * - Setter: sets the current value. The value may be null. (if setter parameter is primitive, null value is not mapped).\r
+ * \r
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>\r
+ *\r
+ * @param <T>\r
+ */\r
+public class CompoundGetSetValueAccessor<Range,T>  implements IRangeAccessor<Range,T> {\r
+       \r
+       private Method getter;\r
+       private Method setter;\r
+       private boolean primitive;\r
+       \r
+       public CompoundGetSetValueAccessor(Method getter, Method setter) {\r
+               this.getter = getter;\r
+               this.setter = setter;\r
+               this.primitive = setter.getParameterTypes()[0].isPrimitive();\r
+       }\r
+       \r
+       @SuppressWarnings("unchecked")\r
+       public T get(Range element) throws MappingException {\r
+               try {\r
+                       return (T) getter.invoke(element);\r
+               } catch (IllegalArgumentException e) {\r
+                       throw new MappingException(e);\r
+               } catch (IllegalAccessException e) {\r
+                       throw new MappingException(e);\r
+               } catch (InvocationTargetException e) {\r
+                       throw new MappingException(e);\r
+               }\r
+       };\r
+\r
+       @Override\r
+       public boolean set(Range element, T value)\r
+                       throws MappingException {\r
+               if (value == null && primitive)\r
+                       return false;\r
+               if (equal(get(element),value))\r
+                       return false;\r
+               try {\r
+                       setter.invoke(element, value);\r
+               } catch (IllegalArgumentException e) {\r
+                       throw new MappingException(e);\r
+               } catch (IllegalAccessException e) {\r
+                       throw new MappingException(e);\r
+               } catch (InvocationTargetException e) {\r
+                       throw new MappingException(e);\r
+               }\r
+               return true;\r
+               \r
+       }\r
+       \r
+       private boolean equal(Object v1, Object v2) {\r
+               if (v1 == null) {\r
+                       if (v2 == null)\r
+                               return true;\r
+                       return false;\r
+               } else if (v2 == null) {\r
+                       return false;\r
+               }\r
+               return v1.equals(v2);\r
+       }\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/range/FieldAccessor.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/range/FieldAccessor.java
new file mode 100644 (file)
index 0000000..91f9b80
--- /dev/null
@@ -0,0 +1,75 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.graph.rules.range;\r
+\r
+import java.lang.reflect.Field;\r
+\r
+import org.apache.log4j.Logger;\r
+import org.simantics.objmap.exceptions.MappingException;\r
+\r
+\r
+/**\r
+ * Accesses the given field of the element.\r
+ * @author Hannu Niemistö\r
+ */\r
+public class FieldAccessor<Range,T> implements IRangeAccessor<Range,T> {\r
+    \r
+    static Logger LOGGER = Logger.getLogger("org.simantics.objmap");\r
+    \r
+       Field field;\r
+\r
+       public FieldAccessor(Field field) {\r
+               this.field = field;\r
+       }\r
+\r
+       @Override\r
+       public T get(Range element) throws MappingException {\r
+               try {\r
+                   T result = (T)field.get(element);\r
+                   \r
+               if(LOGGER.isInfoEnabled())\r
+                   LOGGER.info("        FieldAccessor.get " +\r
+                           field.getName() + " -> " + result\r
+                   );\r
+               \r
+                       return result;\r
+               } catch (IllegalArgumentException e) {\r
+                       throw new MappingException(e);\r
+               } catch (IllegalAccessException e) {\r
+                       throw new MappingException(e);\r
+               }\r
+       }\r
+\r
+       @Override\r
+       public boolean set(Range element, T value) throws MappingException {\r
+               try {\r
+                       Object currentValue = field.get(element);\r
+                       \r
+            if(LOGGER.isInfoEnabled())\r
+                LOGGER.info("        FieldAccessor.set " +\r
+                        field.getName() + " " + currentValue +  \r
+                        " -> " + value\r
+                );\r
+                       \r
+                       if(value == null \r
+                               ? (currentValue == null || field.getType().isPrimitive()) \r
+                               : value.equals(currentValue))\r
+                               return false;                   \r
+                       field.set(element, value);\r
+                       return true;\r
+               } catch (IllegalArgumentException e) {\r
+                       throw new MappingException(e);\r
+               } catch (IllegalAccessException e) {\r
+                       throw new MappingException(e);\r
+               }\r
+       }       \r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/range/FieldAccessorWithDefault.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/range/FieldAccessorWithDefault.java
new file mode 100644 (file)
index 0000000..528826e
--- /dev/null
@@ -0,0 +1,40 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.graph.rules.range;\r
+\r
+import java.lang.reflect.Field;\r
+\r
+import org.simantics.objmap.exceptions.MappingException;\r
+\r
+\r
+/**\r
+ * Accesses the given field of the element.\r
+ * @author Hannu Niemist�\r
+ */\r
+public class FieldAccessorWithDefault<Range,T> extends FieldAccessor<Range,T> {\r
+    \r
+       T defaultValue;\r
+\r
+       public FieldAccessorWithDefault(Field field, T defaultValue) {\r
+        super(field);\r
+        this.defaultValue = defaultValue;\r
+    }\r
+\r
+    @Override\r
+       public T get(Range element) throws MappingException {\r
+               T value = super.get(element);\r
+               if(value == null)\r
+                   return defaultValue;\r
+               else\r
+                   return value;\r
+       }\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/range/GetSetObjectAccessor.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/range/GetSetObjectAccessor.java
new file mode 100644 (file)
index 0000000..f5cd609
--- /dev/null
@@ -0,0 +1,58 @@
+package org.simantics.objmap.graph.rules.range;\r
+\r
+import java.lang.reflect.InvocationTargetException;\r
+import java.lang.reflect.Method;\r
+\r
+import org.simantics.objmap.exceptions.MappingException;\r
+\r
+\r
+/**\r
+ * Accessor for mapped objects. Uses two methods:\r
+ * - Getter: returns the current object.\r
+ * - Setter: sets the current object. The object may be null.\r
+ * \r
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>\r
+ *\r
+ * @param <T>\r
+ */\r
+public class GetSetObjectAccessor<Range,T>  implements IRangeAccessor<Range,T> {\r
+       \r
+       private Method getter;\r
+       private Method setter;\r
+       \r
+       \r
+       public GetSetObjectAccessor(Method getter, Method setter) {\r
+               this.getter = getter;\r
+               this.setter = setter;\r
+               \r
+       }\r
+       \r
+       @SuppressWarnings("unchecked")\r
+       public T get(Range element) throws MappingException {\r
+               try {\r
+                       return (T) getter.invoke(element);\r
+               } catch (IllegalArgumentException e) {\r
+                       throw new MappingException(e);\r
+               } catch (IllegalAccessException e) {\r
+                       throw new MappingException(e);\r
+               } catch (InvocationTargetException e) {\r
+                       throw new MappingException(e);\r
+               }\r
+       };\r
+\r
+       @Override\r
+       public boolean set(Range element, T value)\r
+                       throws MappingException {       \r
+               try {\r
+                       setter.invoke(element, value);\r
+               } catch (IllegalArgumentException e) {\r
+                       throw new MappingException(e);\r
+               } catch (IllegalAccessException e) {\r
+                       throw new MappingException(e);\r
+               } catch (InvocationTargetException e) {\r
+                       throw new MappingException(e);\r
+               }\r
+               return true;\r
+               \r
+       }\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/range/GetSetValueAccessor.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/range/GetSetValueAccessor.java
new file mode 100644 (file)
index 0000000..94fc5d4
--- /dev/null
@@ -0,0 +1,73 @@
+package org.simantics.objmap.graph.rules.range;\r
+\r
+import java.lang.reflect.InvocationTargetException;\r
+import java.lang.reflect.Method;\r
+\r
+import org.simantics.objmap.exceptions.MappingException;\r
+\r
+\r
+/**\r
+ * Accessor for mapped value. Uses two methods:\r
+ * - Getter: returns the current value.\r
+ * - Setter: sets the current value. The value may be null. (if setter parameter is primitive, null value is not mapped).\r
+ * \r
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>\r
+ *\r
+ * @param <T>\r
+ */\r
+public class GetSetValueAccessor<Range,T>  implements IRangeAccessor<Range,T> {\r
+       \r
+       private Method getter;\r
+       private Method setter;\r
+       private boolean primitive;\r
+       \r
+       public GetSetValueAccessor(Method getter, Method setter) {\r
+               this.getter = getter;\r
+               this.setter = setter;\r
+               this.primitive = setter.getParameterTypes()[0].isPrimitive();\r
+       }\r
+       \r
+       @SuppressWarnings("unchecked")\r
+       public T get(Range element) throws MappingException {\r
+               try {\r
+                       return (T) getter.invoke(element);\r
+               } catch (IllegalArgumentException e) {\r
+                       throw new MappingException(e);\r
+               } catch (IllegalAccessException e) {\r
+                       throw new MappingException(e);\r
+               } catch (InvocationTargetException e) {\r
+                       throw new MappingException(e);\r
+               }\r
+       };\r
+\r
+       @Override\r
+       public boolean set(Range element, T value)\r
+                       throws MappingException {\r
+               if (value == null && primitive)\r
+                       return false;\r
+               if (equal(get(element),value))\r
+                       return false;\r
+               try {\r
+                       setter.invoke(element, value);\r
+               } catch (IllegalArgumentException e) {\r
+                       throw new MappingException(e);\r
+               } catch (IllegalAccessException e) {\r
+                       throw new MappingException(e);\r
+               } catch (InvocationTargetException e) {\r
+                       throw new MappingException(e);\r
+               }\r
+               return true;\r
+               \r
+       }\r
+       \r
+       private boolean equal(Object v1, Object v2) {\r
+               if (v1 == null) {\r
+                       if (v2 == null)\r
+                               return true;\r
+                       return false;\r
+               } else if (v2 == null) {\r
+                       return false;\r
+               }\r
+               return v1.equals(v2);\r
+       }\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/range/IRangeAccessor.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/rules/range/IRangeAccessor.java
new file mode 100644 (file)
index 0000000..871ec72
--- /dev/null
@@ -0,0 +1,25 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.graph.rules.range;\r
+\r
+import org.simantics.objmap.exceptions.MappingException;\r
+\r
+\r
+\r
+/**\r
+ * Provides access to some property of range elements.\r
+ * @author Hannu Niemistö\r
+ */\r
+public interface IRangeAccessor<Range,T> {\r
+       T get(Range element) throws MappingException;\r
+       boolean set(Range element, T value) throws MappingException;\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/schema/AdaptedLinkType.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/schema/AdaptedLinkType.java
new file mode 100644 (file)
index 0000000..c75c5ed
--- /dev/null
@@ -0,0 +1,75 @@
+package org.simantics.objmap.graph.schema;\r
+\r
+//import org.apache.log4j.Logger;\r
+import org.eclipse.core.runtime.IAdaptable;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.db.exception.DatabaseException;\r
+\r
+import org.simantics.objmap.backward.IBackwardMapping;\r
+import org.simantics.objmap.exceptions.MappingException;\r
+import org.simantics.objmap.forward.IForwardMapping;\r
+\r
+/**\r
+ * A link type that is associated with adaptable resource (ReadGraph.getAdapter(Resource,Class)). \r
+ * The adapted object must implement IAdaptable interface for returning the original Resource. \r
+ * \r
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>\r
+ *\r
+ */\r
+public class AdaptedLinkType<Range> implements ILinkType<Resource,Range> {\r
+\r
+       \r
+       //static Logger LOGGER = Logger.getLogger("org.simantics.objmap");\r
+    \r
+    Resource domainType;\r
+    Class<?> rangeType;\r
+    \r
+    \r
+    public AdaptedLinkType(Resource domainType, Class<?> rangeType) {\r
+        this.domainType = domainType;\r
+        this.rangeType = rangeType;\r
+    }\r
+    \r
+    @Override\r
+    public Resource createDomainElement(WriteGraph g, Range rangeElement)\r
+               throws MappingException {\r
+       try {\r
+               IAdaptable adaptable = (IAdaptable)rangeElement;\r
+               Resource res = (Resource)adaptable.getAdapter(Resource.class);\r
+               if (res == null)\r
+                       throw new NullPointerException();\r
+               return res;\r
+       } catch (Exception e) {\r
+               throw new MappingException("Adapted object must implement IAdaptable interface to return the source Resource.", e);\r
+       }\r
+       \r
+    }\r
+    \r
+    @Override\r
+    public Range createRangeElement(ReadGraph g, Resource domainElement)\r
+               throws MappingException {\r
+       try {\r
+               return (Range)g.adapt(domainElement, rangeType);\r
+       } catch (DatabaseException e) {\r
+               throw new MappingException(e);\r
+       }\r
+    }\r
+    \r
+    public void createDomain(WriteGraph graph, IBackwardMapping<Resource,Range> mapping, Resource domainElement, Range rangeElement) throws MappingException {\r
+       \r
+    };\r
+    \r
+    public void createRange(ReadGraph graph, org.simantics.objmap.forward.IForwardMapping<Resource,Range> mapping, Resource domainElement, Range rangeElement) throws MappingException {\r
+       \r
+    };\r
+    \r
+    public boolean updateDomain(WriteGraph g, IBackwardMapping<Resource,Range> map, Resource domainElement, Range rangeElement) throws MappingException {\r
+       return false;\r
+    }\r
+    \r
+    public boolean updateRange(ReadGraph g, IForwardMapping<Resource,Range> map, Resource domainElement, Range rangeElement) throws MappingException {\r
+       return false;\r
+    }\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/schema/DefaultSchema.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/schema/DefaultSchema.java
new file mode 100644 (file)
index 0000000..14f4d66
--- /dev/null
@@ -0,0 +1,96 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.graph.schema;\r
+\r
+\r
+\r
+import gnu.trove.map.hash.THashMap;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.common.utils.NameUtils;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.objmap.exceptions.MappingException;\r
+\r
+\r
+/**\r
+ * \r
+ */\r
+public class DefaultSchema implements IMappingSchema<Resource,Object> {\r
+\r
+    THashMap<Resource, ILinkType<Resource,Object>> domainLinkTypes = \r
+        new THashMap<Resource, ILinkType<Resource,Object>>();\r
+    THashMap<Class<?>, ILinkType<Resource,Object>> rangeLinkTypes = \r
+        new THashMap<Class<?>, ILinkType<Resource,Object>>();\r
+    \r
+    public void addLinkType(SimpleLinkType<Object> linkType) {\r
+        domainLinkTypes.put(linkType.domainType, linkType);\r
+        rangeLinkTypes.put(linkType.rangeType, linkType);\r
+    }\r
+    \r
+    public void addLinkType(AdaptedLinkType<Object> linkType) {\r
+        domainLinkTypes.put(linkType.domainType, linkType);\r
+        rangeLinkTypes.put(linkType.rangeType, linkType);\r
+    }\r
+    \r
+    @Override\r
+    public ILinkType<Resource,Object> linkTypeOfDomainElement(ReadGraph g, Resource element) throws MappingException {        \r
+        try {\r
+               \r
+               for(Resource type : g.getTypes(element)) {\r
+\r
+                       ILinkType<Resource,Object> linkType = domainLinkTypes.get(type);\r
+                       if(linkType != null) return linkType;\r
+                       \r
+               }\r
+               \r
+               throw new MappingException("Didn't find a link type for " +\r
+                               NameUtils.getSafeName(g, element) + ".");\r
+                               \r
+        } catch (DatabaseException e) {\r
+            throw new MappingException(e);\r
+        }\r
+    }\r
+\r
+    @Override\r
+    public ILinkType<Resource,Object> linkTypeOfRangeElement(Object element) throws MappingException {\r
+       ILinkType<Resource,Object> type = rangeLinkTypes.get(element.getClass());\r
+               if(type == null)  {\r
+                       for (Class<?> clazz : element.getClass().getInterfaces()) {\r
+                               type = rangeLinkTypes.get(clazz);\r
+                               if (type != null)\r
+                                       return type;\r
+                               \r
+                       }\r
+                       throw new MappingException("Didn't find a link type for " +     element + ".");\r
+               }\r
+               return type;\r
+    }\r
+\r
+    \r
+    public ILinkType<Resource,Object> linkTypeOfDomainType(ReadGraph g, Resource type)  {        \r
+       return domainLinkTypes.get(type);\r
+    }\r
+    \r
+    public ILinkType<Resource,Object> linkTypeOfRangeType(Class<?> clazz) {\r
+       ILinkType<Resource,Object> type = rangeLinkTypes.get(clazz);\r
+       if(type == null)  {\r
+                       for (Class<?> c : clazz.getInterfaces()) {\r
+                               type = rangeLinkTypes.get(clazz);\r
+                               if (type != null)\r
+                                       return type;\r
+                               \r
+                       }\r
+               }\r
+       return null;\r
+    }\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/schema/DynamicSimpleLinkType.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/schema/DynamicSimpleLinkType.java
new file mode 100644 (file)
index 0000000..e7da15a
--- /dev/null
@@ -0,0 +1,112 @@
+package org.simantics.objmap.graph.schema;\r
+\r
+import java.lang.reflect.InvocationTargetException;\r
+import java.lang.reflect.Method;\r
+import java.util.ArrayList;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.db.common.utils.NameUtils;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.layer0.Layer0;\r
+import org.simantics.objmap.bidirectional.IBidirectionalMappingRule;\r
+import org.simantics.objmap.exceptions.MappingException;\r
+import org.simantics.objmap.graph.annotations.GetType;\r
+import org.simantics.objmap.graph.annotations.SetType;\r
+\r
+public class DynamicSimpleLinkType<Range> extends SimpleLinkType<Range>{\r
+\r
+       protected Method typeGetter;\r
+       protected Method typeSetter;\r
+       \r
+       public DynamicSimpleLinkType(Resource domainType, Class<?> rangeType, ArrayList<IBidirectionalMappingRule<Resource, Range>> rules) {\r
+               super(domainType, rangeType, rules);\r
+               findTypeGetter(rangeType);\r
+       }\r
+\r
+       public DynamicSimpleLinkType(Resource domainType, Class<?> rangeType) {\r
+               super(domainType, rangeType);\r
+               findTypeGetter(rangeType);\r
+       }\r
+       \r
+       private void findTypeGetter(Class<?> clazz) {\r
+               for (Method m : clazz.getDeclaredMethods()) {\r
+                        m.setAccessible(true);\r
+                        GetType t = m.getAnnotation(GetType.class);\r
+                        if (t != null) {\r
+                                typeGetter = m;\r
+                        }\r
+                        SetType t2 = m.getAnnotation(SetType.class);\r
+                        if (t2 != null) {\r
+                                typeSetter = m;\r
+                        }\r
+               }\r
+               if (typeGetter == null || typeSetter == null) {\r
+                       Class<?> superClazz = clazz.getSuperclass();\r
+                       if (superClazz != Object.class)\r
+                               findTypeGetter(superClazz);\r
+                       if (typeGetter == null || typeSetter == null) {\r
+                               throw new RuntimeException("Cannot find dynamic type methods for class " + clazz.getSimpleName());      \r
+                       }\r
+               }\r
+               \r
+                       \r
+       }\r
+       \r
+       @Override\r
+    public Resource createDomainElement(WriteGraph g, Range rangeElement)\r
+            throws MappingException {\r
+        try {\r
+               String typeUri = (String)typeGetter.invoke(rangeElement, null);\r
+            if(LOGGER.isInfoEnabled())\r
+                LOGGER.info("SimpleLinkType.createDomainElement " +\r
+                        rangeElement.toString()\r
+                );\r
+            Resource actualDomainType = g.getResource(typeUri);\r
+            Resource result = g.newResource();\r
+            //g.claim(result, Layer0.getInstance(g).InstanceOf, null, domainType);\r
+            g.claim(result, Layer0.getInstance(g).InstanceOf, null, actualDomainType);\r
+            return result;\r
+        } catch(DatabaseException e) {\r
+            throw new MappingException(e);\r
+        } catch (IllegalArgumentException e) {\r
+                throw new MappingException(e);\r
+               } catch (IllegalAccessException e) {\r
+                        throw new MappingException(e);\r
+               } catch (InvocationTargetException e) {\r
+                        throw new MappingException(e);\r
+               }\r
+    }\r
+       \r
+        @Override\r
+           public Range createRangeElement(ReadGraph g, Resource domainElement)\r
+                   throws MappingException {\r
+               try {\r
+                   if(LOGGER.isInfoEnabled())\r
+                       try { \r
+                           LOGGER.info("SimpleLinkType.createRangeElement " +\r
+                                       NameUtils.getSafeName(g, domainElement)\r
+                                   );\r
+                       } catch(DatabaseException e) {\r
+                           throw new MappingException(e);\r
+                       }\r
+                  Range r =  (Range)rangeType.newInstance();\r
+                  Resource type = g.getSingleType(domainElement, domainType);\r
+                  String uri = g.getURI(type);\r
+                  typeSetter.invoke(r, uri);\r
+                  return r;\r
+               } catch (InstantiationException e) {\r
+                   throw new MappingException(e);\r
+               } catch (IllegalAccessException e) {\r
+                   throw new MappingException(e);\r
+               } catch (DatabaseException e) {\r
+                       throw new MappingException(e);\r
+                       } catch (IllegalArgumentException e) {\r
+                               throw new MappingException(e);\r
+                       } catch (InvocationTargetException e) {\r
+                               throw new MappingException(e);\r
+                       } \r
+           }\r
+\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/schema/ILinkType.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/schema/ILinkType.java
new file mode 100644 (file)
index 0000000..aec6973
--- /dev/null
@@ -0,0 +1,32 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.graph.schema;\r
+\r
+import org.simantics.objmap.backward.IBackwardLinkType;\r
+import org.simantics.objmap.bidirectional.IBidirectionalMappingRule;\r
+import org.simantics.objmap.forward.IForwardLinkType;\r
+\r
+/**\r
+ * Contains rules for how a link should be created and maintained.\r
+ * @author Hannu Niemistö\r
+ */\r
+public interface ILinkType<Domain,Range> extends IBidirectionalMappingRule<Domain, Range>, IBackwardLinkType<Domain,Range>, IForwardLinkType<Domain,Range> {\r
+    /**\r
+     * Creates a domain element based on known range element.\r
+     */\r
+       //Resource createDomainElement(WriteGraph g, Object rangeElement) throws MappingException;\r
+       \r
+       /**\r
+     * Creates a range element based on known domain element.\r
+     */\r
+       //Object createRangeElement(ReadGraph g, Resource domainElement) throws MappingException;\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/schema/IMappingSchema.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/schema/IMappingSchema.java
new file mode 100644 (file)
index 0000000..c5cdb0f
--- /dev/null
@@ -0,0 +1,31 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.graph.schema;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.objmap.exceptions.MappingException;\r
+\r
+/**\r
+ * Specifies the link types of new elements added to a mapping.\r
+ * @author Hannu Niemistö\r
+ */\r
+public interface IMappingSchema<Domain,Range> {\r
+    /**\r
+     * @return Link type that should be used for the element.\r
+     */\r
+       ILinkType<Domain,Range> linkTypeOfDomainElement(ReadGraph g, Domain element) throws MappingException;\r
+       \r
+       /**\r
+     * @return Link type that should be used for the element.\r
+     */\r
+       ILinkType<Domain,Range> linkTypeOfRangeElement(Range element) throws MappingException;\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/schema/MappingSchemas.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/schema/MappingSchemas.java
new file mode 100644 (file)
index 0000000..6a7d940
--- /dev/null
@@ -0,0 +1,238 @@
+package org.simantics.objmap.graph.schema;\r
+\r
+import java.lang.annotation.Annotation;\r
+import java.lang.reflect.Field;\r
+import java.lang.reflect.Method;\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.objmap.bidirectional.IBidirectionalMappingRule;\r
+import org.simantics.objmap.graph.annotations.CompoundRelatedGetValue;\r
+import org.simantics.objmap.graph.annotations.DynamicGraphType;\r
+import org.simantics.objmap.graph.annotations.GraphType;\r
+import org.simantics.objmap.graph.annotations.HasCollectionAdder;\r
+import org.simantics.objmap.graph.annotations.HasCollectionRemover;\r
+import org.simantics.objmap.graph.annotations.HasSetter;\r
+import org.simantics.objmap.graph.annotations.OptionalRelatedElements;\r
+import org.simantics.objmap.graph.annotations.RelatedElements;\r
+import org.simantics.objmap.graph.annotations.RelatedElementsGet;\r
+import org.simantics.objmap.graph.annotations.RelatedGetObj;\r
+import org.simantics.objmap.graph.annotations.RelatedGetValue;\r
+import org.simantics.objmap.graph.annotations.RelatedOrderedSetElements;\r
+import org.simantics.objmap.graph.annotations.RelatedValue;\r
+import org.simantics.objmap.graph.annotations.UpdateMethod;\r
+import org.simantics.objmap.graph.annotations.factories.CompoundRelatedGetSetValueRuleFactory;\r
+import org.simantics.objmap.graph.annotations.factories.OptionalRelatedElementsRuleFactory;\r
+import org.simantics.objmap.graph.annotations.factories.RelatedElementsRuleFactory;\r
+import org.simantics.objmap.graph.annotations.factories.RelatedElementsRuleFactory2;\r
+import org.simantics.objmap.graph.annotations.factories.RelatedGetSetObjRuleFactory;\r
+import org.simantics.objmap.graph.annotations.factories.RelatedGetSetValueRuleFactory;\r
+import org.simantics.objmap.graph.annotations.factories.RelatedOrderedSetElementsRuleFactory;\r
+import org.simantics.objmap.graph.annotations.factories.RelatedValueRuleFactory;\r
+import org.simantics.objmap.graph.annotations.factories.UpdateMethodFactory;\r
+import org.simantics.objmap.graph.annotations.meta.IsClassRule;\r
+import org.simantics.objmap.graph.annotations.meta.IsCollectionRule;\r
+import org.simantics.objmap.graph.annotations.meta.IsFieldRule;\r
+import org.simantics.objmap.graph.annotations.meta.IsGetSetRule;\r
+import org.simantics.objmap.graph.annotations.meta.IsMethodRule;\r
+import org.simantics.objmap.graph.rules.factory.IClassRuleFactory;\r
+import org.simantics.objmap.graph.rules.factory.ICollectionRuleFactory;\r
+import org.simantics.objmap.graph.rules.factory.IFieldRuleFactory;\r
+import org.simantics.objmap.graph.rules.factory.IGetSetRuleFactory;\r
+import org.simantics.objmap.graph.rules.factory.IMethodRuleFactory;\r
+\r
+\r
+public class MappingSchemas {\r
+       /**\r
+     * Creates a new SimpleLinkType based on the annotations in the given class.\r
+     * @throws IllegalAccessException \r
+     * @throws InstantiationException \r
+     * @see GraphType\r
+     * @see RelatedValue\r
+     */\r
+       public static SimpleLinkType<Object> fromAnnotations(ReadGraph g, Class<?> clazz) throws DatabaseException, InstantiationException, IllegalAccessException {\r
+           GraphType graphType = clazz.getAnnotation(GraphType.class);\r
+           \r
+           if (graphType != null) {\r
+                   ArrayList<IBidirectionalMappingRule<Resource, Object>> rules = new ArrayList<IBidirectionalMappingRule<Resource, Object>>();\r
+                   collectRulesFromAnnotations(g, clazz, rules);\r
+                   \r
+                   return new SimpleLinkType<Object>(g.getResource(graphType.value()), clazz, rules);  \r
+           }\r
+           DynamicGraphType dynamicType = clazz.getAnnotation(DynamicGraphType.class);\r
+           if (dynamicType != null) {\r
+               ArrayList<IBidirectionalMappingRule<Resource, Object>> rules = new ArrayList<IBidirectionalMappingRule<Resource, Object>>();\r
+                   collectRulesFromAnnotations(g, clazz, rules);\r
+                   \r
+                   return new DynamicSimpleLinkType<Object>(g.getResource(dynamicType.value()), clazz, rules);\r
+           }\r
+           throw new IllegalArgumentException("Class " + clazz.toString() + " does not contain annotations.");\r
+       }\r
+       \r
+       public static void collectRulesFromAnnotations(ReadGraph g, Class<?> clazz, Collection<IBidirectionalMappingRule<Resource, Object>> rules) throws DatabaseException, InstantiationException, IllegalAccessException {\r
+           Class<?> superclass = clazz.getSuperclass();\r
+           if(superclass != null)\r
+               collectRulesFromAnnotations(g, superclass, rules);\r
+               \r
+        for(Annotation annotation : clazz.getAnnotations()) {\r
+\r
+               IsClassRule tag = annotation.annotationType().getAnnotation(IsClassRule.class);\r
+            if(tag!= null) {\r
+               rules.add(createClassRule(g, annotation, clazz).create(g, annotation, clazz));\r
+            }\r
+        }\r
+\r
+        for(Field f : clazz.getDeclaredFields()) {\r
+            f.setAccessible(true);\r
+\r
+            for(Annotation annotation : f.getAnnotations()) {\r
+\r
+               IsFieldRule tag = annotation.annotationType().getAnnotation(IsFieldRule.class);\r
+                if(tag != null) {\r
+                    rules.add(createFieldRule(g, annotation, f).create(g, annotation, f));\r
+                }\r
+            }\r
+        }\r
+\r
+        for(Method m : clazz.getDeclaredMethods()) {\r
+            m.setAccessible(true);\r
+\r
+            for(Annotation annotation : m.getAnnotations()) {\r
+               IsMethodRule tag = \r
+                        annotation.annotationType().getAnnotation(IsMethodRule.class);\r
+                if(tag != null) {\r
+                       rules.add(createMethodRule(g, annotation, m).create(g, annotation, m));\r
+                }\r
+            }\r
+        }\r
+        \r
+        for (Method m : clazz.getDeclaredMethods()) {\r
+               m.setAccessible(true);\r
+               for (Annotation annotation : m.getAnnotations()) {\r
+                       Class<? extends Annotation> annotationType = annotation.annotationType();\r
+\r
+                        IsGetSetRule tag = \r
+                         annotationType.getAnnotation(IsGetSetRule.class);\r
+                        if (tag != null) {\r
+                                \r
+                                HasSetter setterAnnType = annotationType.getAnnotation(HasSetter.class);\r
+                                \r
+                                Class<? extends Annotation> setterAnn = setterAnnType.value();\r
+                                \r
+                                Method getter = m;\r
+                                \r
+                                IGetSetRuleFactory<Resource,Object> ruleFactory = createGetSetRuleFactory(g, annotation, getter);\r
+                                \r
+                                \r
+                                Method setter = null;\r
+                                \r
+                                for (Method m2 : clazz.getDeclaredMethods()) {\r
+                                        Annotation set = m2.getAnnotation(setterAnn);\r
+                                        if (set != null && ruleFactory.isSetter(annotation, set))\r
+                                                setter = m2;\r
+                                }\r
+\r
+                                rules.add(ruleFactory.create(g, annotation, getter, setter));\r
+                        }\r
+                \r
+               }\r
+        }\r
+        \r
+        for (Method m : clazz.getDeclaredMethods()) {\r
+               m.setAccessible(true);\r
+               for (Annotation annotation : m.getAnnotations()) {\r
+                       Class<? extends Annotation> annotationType = annotation.annotationType();\r
+\r
+                        IsCollectionRule tag = \r
+                         annotationType.getAnnotation(IsCollectionRule.class);\r
+                        if (tag != null) {\r
+                                \r
+                                HasCollectionAdder adderAnnType = annotationType.getAnnotation(HasCollectionAdder.class);\r
+                                HasCollectionRemover removerAnnType = annotationType.getAnnotation(HasCollectionRemover.class);\r
+                \r
+                                Class<? extends Annotation> adderAnn = adderAnnType.value();\r
+                                Class<? extends Annotation> removerAnn = removerAnnType.value();\r
+                                \r
+                                Method getter = m;\r
+                                \r
+                                ICollectionRuleFactory<Resource,Object> ruleFactory = createCollectionRuleFactory(g, annotation, getter);\r
+                                \r
+                                \r
+                                Method adder = null;\r
+                                Method remover = null;\r
+                                \r
+                                for (Method m2 : clazz.getDeclaredMethods()) {\r
+                                        Annotation add = m2.getAnnotation(adderAnn);\r
+                                        Annotation rem = m2.getAnnotation(removerAnn);\r
+                                        if (add != null && ruleFactory.isAdder(annotation, add))\r
+                                                adder = m2;\r
+                                        if (rem != null && ruleFactory.isRemover(annotation, rem))\r
+                                                remover = m2;\r
+                                }\r
+                                \r
+                                \r
+                                \r
+                                rules.add(ruleFactory.create(g, annotation, getter,adder,remover));\r
+                        }\r
+                \r
+               }\r
+        }\r
+    }\r
+       \r
+       public static IClassRuleFactory<Resource, Object> createClassRule(ReadGraph g, Annotation annotation, Class<?> clazz) {\r
+               return null;\r
+       }\r
+       \r
+       public static IFieldRuleFactory<Resource,Object> createFieldRule(ReadGraph g, Annotation annotation, Field field) {\r
+               if (annotation.annotationType().equals(RelatedElements.class))\r
+                       return new RelatedElementsRuleFactory<Object>();\r
+               if (annotation.annotationType().equals(RelatedValue.class))\r
+                       return new RelatedValueRuleFactory<Object>();\r
+               if (annotation.annotationType().equals(OptionalRelatedElements.class))\r
+                       return new OptionalRelatedElementsRuleFactory<Object>();\r
+               if (annotation.annotationType().equals(RelatedOrderedSetElements.class))\r
+                       return new RelatedOrderedSetElementsRuleFactory<Object>();\r
+               return null;\r
+       }\r
+       \r
+       public static IMethodRuleFactory<Resource, Object> createMethodRule(ReadGraph g, Annotation annotation, Method m) {\r
+               if (annotation.annotationType().equals(UpdateMethod.class))\r
+                       return new UpdateMethodFactory<Resource,Object>();\r
+               return null;\r
+       }\r
+       \r
+       public static IGetSetRuleFactory<Resource,Object> createGetSetRuleFactory(ReadGraph g, Annotation annotation, Method getter) {\r
+               if (annotation.annotationType().equals(RelatedGetValue.class))\r
+                       return new RelatedGetSetValueRuleFactory<Object>();\r
+               if (annotation.annotationType().equals(RelatedGetObj.class))\r
+                       return new RelatedGetSetObjRuleFactory<Object>();\r
+               if (annotation.annotationType().equals(CompoundRelatedGetValue.class))\r
+                       return new CompoundRelatedGetSetValueRuleFactory<Object>();\r
+               return null;\r
+       }\r
+       \r
+       public static ICollectionRuleFactory<Resource,Object> createCollectionRuleFactory(ReadGraph g, Annotation annotation, Method getter) {\r
+               if (annotation.annotationType().equals(RelatedElementsGet.class))\r
+                       return new RelatedElementsRuleFactory2<Object>();\r
+               return null;\r
+       }\r
+       \r
+       /**\r
+     * Creates a new SimpleLinkType based on the annotations in the given class.\r
+     * @throws IllegalAccessException \r
+     * @throws InstantiationException \r
+     * @see GraphType\r
+     * @see RelatedValue\r
+     */\r
+       \r
+       public static AdaptedLinkType<Object> fromAdaptable(ReadGraph g, String type, Class<?> clazz) throws DatabaseException, InstantiationException, IllegalAccessException {\r
+           \r
+           \r
+           return new AdaptedLinkType<Object>(g.getResource(type), clazz);    \r
+       }\r
+       \r
+       \r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/schema/SimpleLinkType.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/schema/SimpleLinkType.java
new file mode 100644 (file)
index 0000000..812b22d
--- /dev/null
@@ -0,0 +1,139 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.graph.schema;\r
+\r
+import java.util.ArrayList;\r
+\r
+import org.apache.log4j.Logger;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.db.common.utils.NameUtils;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.layer0.Layer0;\r
+import org.simantics.objmap.backward.IBackwardMapping;\r
+import org.simantics.objmap.bidirectional.IBidirectionalMappingRule;\r
+import org.simantics.objmap.exceptions.MappingException;\r
+import org.simantics.objmap.forward.IForwardMapping;\r
+\r
+\r
+/**\r
+ * A link type that is associated with single domain and range type (class).\r
+ * SimpleLinkType is composed of simpler rules whose combination determines\r
+ * its update policy.\r
+ * @author Hannu Niemist�\r
+ */\r
+public class SimpleLinkType<Range> implements ILinkType<Resource,Range> {\r
+    \r
+    static Logger LOGGER = Logger.getLogger("org.simantics.objmap");\r
+    \r
+    public Resource domainType;\r
+    public Class<?> rangeType;\r
+    ArrayList<IBidirectionalMappingRule<Resource, Range>> rules;\r
+    \r
+    public SimpleLinkType(Resource domainType, Class<?> rangeType,\r
+            ArrayList<IBidirectionalMappingRule<Resource, Range>> rules) {\r
+        this.domainType = domainType;\r
+        this.rangeType = rangeType;\r
+        this.rules = rules;\r
+    }\r
+\r
+    public SimpleLinkType(Resource domainType, Class<?> rangeType) {\r
+        this(domainType, rangeType, new ArrayList<IBidirectionalMappingRule<Resource, Range>>());\r
+    }\r
+\r
+    /**\r
+     * Adds a new rule to this link type that is enforced\r
+     * during updates.\r
+     */\r
+    public void addRule(IBidirectionalMappingRule<Resource, Range> rule) {\r
+        rules.add(rule);\r
+    }\r
+    \r
+    @Override\r
+    public Resource createDomainElement(WriteGraph g, Range rangeElement)\r
+            throws MappingException {\r
+        try {\r
+            if(LOGGER.isInfoEnabled())\r
+                LOGGER.info("SimpleLinkType.createDomainElement " +\r
+                        rangeElement.toString()\r
+                );\r
+            Resource result = g.newResource();\r
+            g.claim(result, Layer0.getInstance(g).InstanceOf, null, domainType);\r
+            return result;\r
+        } catch(DatabaseException e) {\r
+            throw new MappingException(e);\r
+        }\r
+    }\r
+    @Override\r
+    public Range createRangeElement(ReadGraph g, Resource domainElement)\r
+            throws MappingException {\r
+        try {\r
+            if(LOGGER.isInfoEnabled())\r
+                try { \r
+                    LOGGER.info("SimpleLinkType.createRangeElement " +\r
+                               NameUtils.getSafeName(g, domainElement)\r
+                            );\r
+                } catch(DatabaseException e) {\r
+                    throw new MappingException(e);\r
+                }\r
+            return (Range)rangeType.newInstance();\r
+        } catch (InstantiationException e) {\r
+            throw new MappingException(e);\r
+        } catch (IllegalAccessException e) {\r
+            throw new MappingException(e);\r
+        }\r
+    }\r
+    \r
+    public void createDomain(WriteGraph graph, IBackwardMapping<Resource,Range> mapping, Resource domainElement, Range rangeElement) throws MappingException {\r
+       updateDomain(graph, mapping, domainElement, rangeElement);\r
+    };\r
+    \r
+    public void createRange(ReadGraph graph, org.simantics.objmap.forward.IForwardMapping<Resource,Range> mapping, Resource domainElement, Range rangeElement) throws MappingException {\r
+       updateRange(graph, mapping, domainElement, rangeElement);\r
+    };\r
+    \r
+    public boolean updateDomain(WriteGraph g, IBackwardMapping<Resource,Range> map, Resource domainElement, Range rangeElement) throws MappingException {\r
+        if(LOGGER.isInfoEnabled())\r
+            try { \r
+                LOGGER.info("SimpleLinkType.updateDomain " +\r
+                        NameUtils.getSafeName(g, domainElement) + " " +\r
+                        rangeElement.toString()\r
+                        );\r
+            } catch(DatabaseException e) {\r
+                throw new MappingException(e);\r
+            }\r
+        \r
+        boolean updated = false;\r
+        for(IBidirectionalMappingRule<Resource, Range> rule : rules)\r
+               updated |= rule.updateDomain(g, map, domainElement, rangeElement);\r
+        return updated;\r
+    }\r
+    \r
+    public boolean updateRange(ReadGraph g, IForwardMapping<Resource,Range> map, Resource domainElement, Range rangeElement) throws MappingException {\r
+    \r
+        if(LOGGER.isInfoEnabled())\r
+            try { \r
+                LOGGER.info("SimpleLinkType.updateRange " +\r
+                               NameUtils.getSafeName(g, domainElement) + " " +\r
+                        rangeElement.toString()\r
+                        );\r
+            } catch(DatabaseException e) {\r
+                throw new MappingException(e);\r
+            }\r
+        \r
+        boolean updated = false;\r
+        for(IBidirectionalMappingRule<Resource, Range> rule : rules)\r
+            updated |= rule.updateRange(g, map, domainElement, rangeElement);\r
+        return updated;\r
+    }\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/graph/schema/SimpleSchema.java b/org.simantics.objmap2/src/org/simantics/objmap/graph/schema/SimpleSchema.java
new file mode 100644 (file)
index 0000000..87f4cfb
--- /dev/null
@@ -0,0 +1,94 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.graph.schema;\r
+\r
+\r
+import java.util.Stack;\r
+\r
+import gnu.trove.map.hash.THashMap;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.common.utils.NameUtils;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.objmap.exceptions.MappingException;\r
+\r
+\r
+/**\r
+ * An implementation of IMappingSchema that contains\r
+ * only SimpleLinkTypes. The link type of any domain\r
+ * element is based solely on its type in database and\r
+ * the link type of any range element is based on its class.\r
+ * @author Hannu Niemistö\r
+ */\r
+public class SimpleSchema implements IMappingSchema<Resource,Object> {\r
+\r
+    THashMap<Resource, ILinkType<Resource,Object>> domainLinkTypes = \r
+        new THashMap<Resource, ILinkType<Resource,Object>>();\r
+    THashMap<Class<?>, ILinkType<Resource,Object>> rangeLinkTypes = \r
+        new THashMap<Class<?>, ILinkType<Resource,Object>>();\r
+    \r
+    public void addLinkType(SimpleLinkType<Object> linkType) {\r
+        domainLinkTypes.put(linkType.domainType, linkType);\r
+        rangeLinkTypes.put(linkType.rangeType, linkType);\r
+    }\r
+    \r
+    public void addLinkType(AdaptedLinkType<Object> linkType) {\r
+        domainLinkTypes.put(linkType.domainType, linkType);\r
+        rangeLinkTypes.put(linkType.rangeType, linkType);\r
+    }\r
+    \r
+    @Override\r
+    public ILinkType<Resource,Object> linkTypeOfDomainElement(ReadGraph g, Resource element) throws MappingException {        \r
+        try {\r
+               \r
+               for(Resource type : g.getTypes(element)) {\r
+\r
+                       ILinkType<Resource,Object> linkType = domainLinkTypes.get(type);\r
+                       if(linkType != null) return linkType;\r
+                       \r
+               }\r
+               \r
+               throw new MappingException("Didn't find a link type for " +     NameUtils.getSafeName(g, element) + ".");\r
+                               \r
+        } catch (DatabaseException e) {\r
+            throw new MappingException(e);\r
+        }\r
+    }\r
+\r
+    @Override\r
+    public ILinkType<Resource,Object> linkTypeOfRangeElement(Object element) throws MappingException {\r
+       ILinkType<Resource,Object> type = rangeLinkTypes.get(element.getClass());\r
+       if(type == null)  {\r
+               Stack<Class<?>> clazzes = new Stack<Class<?>>();\r
+               for (Class<?> clazz : element.getClass().getInterfaces()) {\r
+                       clazzes.add(clazz);\r
+               }\r
+               clazzes.add(element.getClass().getSuperclass());\r
+               \r
+               \r
+                       while (!clazzes.isEmpty()) {\r
+                               Class<?> clazz = clazzes.pop();\r
+                       \r
+                               type = rangeLinkTypes.get(clazz);\r
+                               if (type != null)\r
+                                       return type;\r
+                               for (Class<?> c : clazz.getInterfaces())\r
+                                       clazzes.add(c);\r
+                               \r
+                       }\r
+                       throw new MappingException("Didn't find a link type for " +     element.getClass() + ".");\r
+               }\r
+               return type;\r
+    }\r
+\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/internal/BidirectionalLink.java b/org.simantics.objmap2/src/org/simantics/objmap/internal/BidirectionalLink.java
new file mode 100644 (file)
index 0000000..326782d
--- /dev/null
@@ -0,0 +1,19 @@
+package org.simantics.objmap.internal;\r
+\r
+import org.simantics.objmap.bidirectional.IBidirectionalLinkType;\r
+\r
+public class BidirectionalLink<Domain, Range> {\r
+    IBidirectionalLinkType<Domain, Range> linkType;\r
+    Domain domainElement;\r
+    Range rangeElement;\r
+    \r
+    boolean domainModified;\r
+    boolean rangeModified;\r
+    \r
+    public BidirectionalLink(IBidirectionalLinkType<Domain, Range> linkType,\r
+            Domain domainElement, Range rangeElement) {\r
+        this.linkType = linkType;\r
+        this.domainElement = domainElement;\r
+        this.rangeElement = rangeElement;\r
+    }\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/internal/BidirectionalMapping.java b/org.simantics.objmap2/src/org/simantics/objmap/internal/BidirectionalMapping.java
new file mode 100644 (file)
index 0000000..b3fdaca
--- /dev/null
@@ -0,0 +1,129 @@
+package org.simantics.objmap.internal;\r
+\r
+import gnu.trove.map.hash.THashMap;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.Collections;\r
+import java.util.Set;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.objmap.bidirectional.IBidirectionalLinkType;\r
+import org.simantics.objmap.bidirectional.IBidirectionalMapping;\r
+import org.simantics.objmap.bidirectional.IBidirectionalMappingSchema;\r
+import org.simantics.objmap.exceptions.MappingException;\r
+\r
+public class BidirectionalMapping<Domain, Range> implements IBidirectionalMapping<Domain, Range> {\r
+\r
+    IBidirectionalMappingSchema<Domain, Range> schema;\r
+    THashMap<Domain, BidirectionalLink<Domain, Range>> forwardMap =\r
+            new THashMap<Domain, BidirectionalLink<Domain, Range>>();\r
+    THashMap<Range, BidirectionalLink<Domain, Range>> backwardMap =\r
+            new THashMap<Range, BidirectionalLink<Domain, Range>>();\r
+    \r
+    ArrayList<BidirectionalLink<Domain, Range>> modifiedDomain = new ArrayList<BidirectionalLink<Domain, Range>>();\r
+    ArrayList<BidirectionalLink<Domain, Range>> modifiedRange = new ArrayList<BidirectionalLink<Domain, Range>>();\r
+    \r
+    private void markDomainModified(BidirectionalLink<Domain, Range> link) {\r
+        if(!link.domainModified) {\r
+            link.domainModified = true;\r
+            modifiedDomain.add(link);\r
+        }\r
+    }\r
+    \r
+    private void markRangeModified(BidirectionalLink<Domain, Range> link) {\r
+        if(!link.rangeModified) {\r
+            link.rangeModified = true;\r
+            modifiedRange.add(link);\r
+        }\r
+    }\r
+    \r
+    public BidirectionalMapping(IBidirectionalMappingSchema<Domain, Range> schema) {\r
+        this.schema = schema;\r
+    }\r
+\r
+    private BidirectionalLink<Domain, Range> addLink(IBidirectionalLinkType<Domain, Range> linkType, Domain domainElement, Range rangeElement) {\r
+        BidirectionalLink<Domain, Range> link = \r
+                new BidirectionalLink<Domain, Range>(linkType, domainElement, rangeElement);\r
+        forwardMap.put(domainElement, link);\r
+        backwardMap.put(rangeElement, link);\r
+        return link;\r
+    }\r
+    \r
+    @Override\r
+    public Set<Domain> getDomain() {\r
+        return Collections.unmodifiableSet(forwardMap.keySet());\r
+    }\r
+\r
+    @Override\r
+    public Range get(Domain domainElement) {\r
+        BidirectionalLink<Domain, Range> link = forwardMap.get(domainElement);\r
+        if(link == null)\r
+            return null;\r
+        return link.rangeElement;\r
+    }\r
+\r
+    @Override\r
+    public Range map(ReadGraph graph, Domain domainElement) throws MappingException {\r
+        Range result = get(domainElement);\r
+        if(result == null) {\r
+            IBidirectionalLinkType<Domain, Range> linkType = \r
+                    schema.linkTypeOfDomainElement(graph, domainElement);\r
+            Range rangeElement = linkType.createRangeElement(graph, domainElement);\r
+            addLink(linkType, domainElement, rangeElement);\r
+            linkType.createRange(graph, this, domainElement, rangeElement);\r
+        }\r
+        return result;\r
+    }\r
+    \r
+    public Collection<Range> updateRange(ReadGraph graph) throws MappingException {\r
+        ArrayList<Range> updated = new ArrayList<Range>(Math.max(10, modifiedDomain.size())); \r
+        for(BidirectionalLink<Domain, Range> link : modifiedDomain) {\r
+            link.domainModified = false;\r
+            if(link.linkType.updateRange(graph, this, link.domainElement, link.rangeElement))\r
+                updated.add(link.rangeElement);\r
+        }\r
+        modifiedDomain.clear();\r
+        return updated;        \r
+    }\r
+\r
+    @Override\r
+    public Set<Range> getRange() {\r
+        return Collections.unmodifiableSet(backwardMap.keySet());\r
+    }\r
+\r
+    @Override\r
+    public Domain inverseGet(Range rangeElement) {\r
+        BidirectionalLink<Domain, Range> link = backwardMap.get(rangeElement);\r
+        if(link == null)\r
+            return null;\r
+        return link.domainElement;\r
+    }\r
+\r
+    @Override\r
+    public Domain inverseMap(WriteGraph graph, Range rangeElement)\r
+            throws MappingException {\r
+        Domain result = inverseGet(rangeElement);\r
+        if(result == null) {\r
+            IBidirectionalLinkType<Domain, Range> linkType = \r
+                    schema.linkTypeOfRangeElement(graph, rangeElement);\r
+            Domain domainElement = linkType.createDomainElement(graph, rangeElement);\r
+            addLink(linkType, domainElement, rangeElement);\r
+            linkType.createDomain(graph, this, domainElement, rangeElement);\r
+        }\r
+        return result;\r
+    }\r
+    \r
+    public Collection<Domain> updateDomain(WriteGraph graph) throws MappingException {\r
+        ArrayList<Domain> updated = new ArrayList<Domain>(Math.max(10, modifiedRange.size())); \r
+        for(BidirectionalLink<Domain, Range> link : modifiedRange) {\r
+            link.rangeModified = false;\r
+            if(link.linkType.updateDomain(graph, this, link.domainElement, link.rangeElement))\r
+                updated.add(link.domainElement);\r
+        }\r
+        modifiedDomain.clear();\r
+        return updated;        \r
+    }\r
+\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/internal/MonotoneBackwardMapping.java b/org.simantics.objmap2/src/org/simantics/objmap/internal/MonotoneBackwardMapping.java
new file mode 100644 (file)
index 0000000..709d3e0
--- /dev/null
@@ -0,0 +1,52 @@
+package org.simantics.objmap.internal;\r
+\r
+import gnu.trove.map.hash.THashMap;\r
+\r
+import java.util.Collections;\r
+import java.util.Set;\r
+\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.objmap.backward.IBackwardLinkType;\r
+import org.simantics.objmap.backward.IBackwardMapping;\r
+import org.simantics.objmap.backward.IBackwardMappingSchema;\r
+import org.simantics.objmap.exceptions.MappingException;\r
+\r
+/**\r
+ * An unidirectional (from range to domain) mapping that does not support removals.\r
+ * \r
+ * @author Hannu Niemist&ouml;\r
+ */\r
+public class MonotoneBackwardMapping<Domain, Range> implements IBackwardMapping<Domain, Range> {\r
+\r
+    IBackwardMappingSchema<Domain, Range> schema;\r
+    THashMap<Range, Domain> map = new THashMap<Range, Domain>();\r
+    \r
+    public MonotoneBackwardMapping(IBackwardMappingSchema<Domain, Range> schema) {\r
+        this.schema = schema;\r
+    }\r
+\r
+    @Override\r
+    public Set<Range> getRange() {\r
+        return Collections.unmodifiableSet(map.keySet());\r
+    }\r
+\r
+    @Override\r
+    public Domain inverseGet(Range rangeElement) {\r
+        return map.get(rangeElement);\r
+    }\r
+\r
+    @Override\r
+    public Domain inverseMap(WriteGraph graph, Range rangeElement) throws MappingException {\r
+        Domain result = inverseGet(rangeElement);\r
+        if(result == null) {\r
+            IBackwardLinkType<Domain, Range> linkType = \r
+                    schema.linkTypeOfRangeElement(graph, rangeElement);\r
+            // Two phase creation makes cyclic references possible\r
+            Domain domainElement = linkType.createDomainElement(graph, rangeElement);\r
+            map.put(rangeElement, domainElement);\r
+            linkType.createDomain(graph, this, domainElement, rangeElement);\r
+        }\r
+        return result;\r
+    }\r
+\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/internal/MonotoneForwardMapping.java b/org.simantics.objmap2/src/org/simantics/objmap/internal/MonotoneForwardMapping.java
new file mode 100644 (file)
index 0000000..51065ff
--- /dev/null
@@ -0,0 +1,47 @@
+package org.simantics.objmap.internal;\r
+\r
+import gnu.trove.map.hash.THashMap;\r
+\r
+import java.util.Collections;\r
+import java.util.Set;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.objmap.exceptions.MappingException;\r
+import org.simantics.objmap.forward.IForwardLinkType;\r
+import org.simantics.objmap.forward.IForwardMapping;\r
+import org.simantics.objmap.forward.IForwardMappingSchema;\r
+\r
+public class MonotoneForwardMapping<Domain, Range> implements IForwardMapping<Domain, Range> {\r
+\r
+    IForwardMappingSchema<Domain, Range> schema;\r
+    THashMap<Domain, Range> map = new THashMap<Domain, Range>();\r
+    \r
+    public MonotoneForwardMapping(IForwardMappingSchema<Domain, Range> schema) {\r
+        this.schema = schema;\r
+    }\r
+\r
+    @Override\r
+    public Set<Domain> getDomain() {\r
+        return Collections.unmodifiableSet(map.keySet());\r
+    }\r
+\r
+    @Override\r
+    public Range get(Domain domainElement) {\r
+        return map.get(domainElement);\r
+    }\r
+\r
+    @Override\r
+    public Range map(ReadGraph graph, Domain domainElement) throws MappingException {\r
+        Range result = get(domainElement);\r
+        if(result == null) {\r
+            IForwardLinkType<Domain, Range> linkType = \r
+                    schema.linkTypeOfDomainElement(graph, domainElement);\r
+            // Two phase creation makes cyclic references possible\r
+            Range rangeElement = linkType.createRangeElement(graph, domainElement);\r
+            map.put(domainElement, rangeElement);\r
+            linkType.createRange(graph, this, domainElement, rangeElement);\r
+        }\r
+        return result;\r
+    }\r
+\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/IStructuralObject.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/IStructuralObject.java
new file mode 100644 (file)
index 0000000..051f375
--- /dev/null
@@ -0,0 +1,38 @@
+package org.simantics.objmap.structural;\r
+\r
+import java.util.List;\r
+\r
+import org.simantics.db.Resource;\r
+\r
+/**\r
+ * Interface for structurally mapped Java objects.\r
+ * \r
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>\r
+ *\r
+ */\r
+public interface IStructuralObject {\r
+       \r
+       /**\r
+        * Context of an object. \r
+        * @return\r
+        */\r
+       public List<IStructuralObject> getContext();\r
+\r
+       /**\r
+        * Sets object's context. Used by ObjMap, don't touch. \r
+        * @param object\r
+        */\r
+       public void setContext(List<IStructuralObject> object);\r
+       \r
+       /**\r
+        * Return type resource for Structural instances. For other objects returns null.\r
+        * @return\r
+        */\r
+       public Resource getType();\r
+       \r
+       /**\r
+        * Sets object's type. Used by ObjMap, don't touch.\r
+        * @param object\r
+        */\r
+       public void setType(Resource type);\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/StructuralResource.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/StructuralResource.java
new file mode 100644 (file)
index 0000000..20e9230
--- /dev/null
@@ -0,0 +1,156 @@
+package org.simantics.objmap.structural;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.layer0.Layer0;\r
+\r
+/**\r
+ * An object representing structural Resource.\r
+ * \r
+ * \r
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>\r
+ *\r
+ */\r
+public class StructuralResource  {\r
+\r
+       private Resource resource;\r
+       private List<Resource> context = new ArrayList<Resource>(1);\r
+       \r
+       private Resource typeResource = null;\r
+       \r
+       public StructuralResource(Resource resource) {\r
+               assert(resource != null);\r
+               this.resource = resource;\r
+       }\r
+       public StructuralResource(ReadGraph g, Resource resource, Resource context) throws DatabaseException {\r
+               assert(resource != null);\r
+               this.resource = resource;\r
+               this.context.add(context);\r
+               resolveType(g);\r
+       }\r
+       \r
+       public StructuralResource(ReadGraph g, Resource resource, Resource... context) throws DatabaseException {\r
+               assert(resource != null);\r
+               this.resource = resource;\r
+               for (Resource r : context)\r
+                       this.context.add(r);\r
+               resolveType(g);\r
+       }\r
+       \r
+       public StructuralResource(ReadGraph g, Resource resource, List<Resource> context) throws DatabaseException {\r
+               assert(resource != null);\r
+               this.resource = resource;\r
+               for (Resource r : context)\r
+                       this.context.add(r);\r
+               resolveType(g); \r
+       }\r
+       public StructuralResource(ReadGraph g, Resource resource, List<Resource> context, Resource context2) throws DatabaseException {\r
+               assert(resource != null);\r
+               this.resource = resource;\r
+               for (Resource r : context)\r
+                       this.context.add(r);\r
+               this.context.add(context2);\r
+               resolveType(g);\r
+       }\r
+       \r
+       private void resolveType(ReadGraph g) throws DatabaseException {\r
+               if (this.context.contains(resource)) {\r
+                       Layer0 l0 = Layer0.getInstance(g);\r
+                       typeResource = g.getSingleObject(resource, l0.InstanceOf);\r
+               } \r
+       }\r
+       \r
+       \r
+       /**\r
+        * The Resource in the DB.\r
+        * @return\r
+        */\r
+       public Resource getResource() {\r
+               return resource;\r
+       }\r
+       \r
+       /**\r
+        * Context in which this resource is accessed. Each context resource represents a structural model instance. \r
+        * @return\r
+        */\r
+       public List<Resource> getContext() {\r
+               return context;\r
+       }\r
+       \r
+       /**\r
+        * If the resource is structural model instance, this returns the type Resource. Otherwise returns null.\r
+        * @return\r
+        */\r
+       public Resource getTypeResource() {\r
+               return typeResource;\r
+       }\r
+       \r
+       /**\r
+        * Returns true, if the resource is structural, \r
+        * @return\r
+        */\r
+       public boolean isStructural() {\r
+               return context.size() > 0;\r
+       }\r
+       \r
+       /**\r
+        * Returns true is the Resource is root of Structural Model instance.\r
+        * In this case the resource instance is editable.\r
+        * \r
+        * @return\r
+        */\r
+       public boolean isStructuralRoot() {\r
+               return (context.size() == 1 && context.get(0).equals(resource));\r
+       }\r
+       \r
+       /**\r
+        * Returns true,  the resource is structural model instance.\r
+        * @return\r
+        */\r
+       public boolean isStructuralInstance() {\r
+               return typeResource != null;\r
+       }\r
+       \r
+       @Override\r
+       public int hashCode() {\r
+               int hashCode = resource.hashCode();\r
+               for (Resource ctx : context)\r
+                       hashCode += ctx.hashCode();\r
+               return hashCode;\r
+       }\r
+       \r
+       @Override\r
+       public boolean equals(Object obj) {\r
+               if (obj == this)\r
+                       return true;\r
+               if (obj == null)\r
+                       return false;\r
+               if (obj.getClass() != getClass())\r
+                       return false;\r
+               StructuralResource other = (StructuralResource)obj;\r
+               if (!resource.equals(other.resource))\r
+                       return false;\r
+               if (context.size() != other.context.size())\r
+                       return false;\r
+               for (int i = 0; i < context.size(); i++) {\r
+                       if (!context.get(i).equals(other.context.get(i)))\r
+                               return false;\r
+               }\r
+               return true;\r
+       }\r
+       \r
+       @Override\r
+       public String toString() {\r
+               String s = "Res: " + resource + " Context:";\r
+               for (Resource ctx : context) \r
+                       s+= " "+ ctx;\r
+               if (typeResource != null)\r
+                       s+= " Type: " + typeResource;\r
+               return s;\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/StructuralRelatedElementsAdd.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/StructuralRelatedElementsAdd.java
new file mode 100644 (file)
index 0000000..4237abc
--- /dev/null
@@ -0,0 +1,12 @@
+package org.simantics.objmap.structural.annotations;\r
+\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target(ElementType.METHOD)\r
+public @interface StructuralRelatedElementsAdd {\r
+       String value();\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/StructuralRelatedElementsGet.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/StructuralRelatedElementsGet.java
new file mode 100644 (file)
index 0000000..65f3b25
--- /dev/null
@@ -0,0 +1,21 @@
+package org.simantics.objmap.structural.annotations;\r
+\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+import org.simantics.objmap.graph.annotations.HasCollectionAdder;\r
+import org.simantics.objmap.graph.annotations.HasCollectionRemover;\r
+import org.simantics.objmap.graph.annotations.meta.IsCollectionRule;\r
+\r
+\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target(ElementType.METHOD)\r
+@IsCollectionRule\r
+@HasCollectionAdder(StructuralRelatedElementsAdd.class)\r
+@HasCollectionRemover(StructuralRelatedElementsRem.class)\r
+public @interface StructuralRelatedElementsGet {\r
+       String value();\r
+       boolean composition() default false;\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/StructuralRelatedElementsRem.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/StructuralRelatedElementsRem.java
new file mode 100644 (file)
index 0000000..aaa8d7f
--- /dev/null
@@ -0,0 +1,13 @@
+package org.simantics.objmap.structural.annotations;\r
+\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target(ElementType.METHOD)\r
+public @interface StructuralRelatedElementsRem {\r
+       String value();\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/StructuralRelatedGetObj.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/StructuralRelatedGetObj.java
new file mode 100644 (file)
index 0000000..f274eb8
--- /dev/null
@@ -0,0 +1,19 @@
+package org.simantics.objmap.structural.annotations;\r
+\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+import org.simantics.objmap.graph.annotations.HasSetter;\r
+import org.simantics.objmap.graph.annotations.meta.IsGetSetRule;\r
+\r
+\r
+\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target(ElementType.METHOD)\r
+@IsGetSetRule\r
+@HasSetter(StructuralRelatedSetObj.class)\r
+public @interface StructuralRelatedGetObj {\r
+       String value();\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/StructuralRelatedSetObj.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/StructuralRelatedSetObj.java
new file mode 100644 (file)
index 0000000..19cf3bf
--- /dev/null
@@ -0,0 +1,13 @@
+package org.simantics.objmap.structural.annotations;\r
+\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target(ElementType.METHOD)\r
+public @interface StructuralRelatedSetObj {\r
+       String value();\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/TypeRelatedElementsAdd.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/TypeRelatedElementsAdd.java
new file mode 100644 (file)
index 0000000..82b675e
--- /dev/null
@@ -0,0 +1,12 @@
+package org.simantics.objmap.structural.annotations;\r
+\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target(ElementType.METHOD)\r
+public @interface TypeRelatedElementsAdd {\r
+       String value();\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/TypeRelatedElementsGet.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/TypeRelatedElementsGet.java
new file mode 100644 (file)
index 0000000..5ec2f45
--- /dev/null
@@ -0,0 +1,21 @@
+package org.simantics.objmap.structural.annotations;\r
+\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+import org.simantics.objmap.graph.annotations.HasCollectionAdder;\r
+import org.simantics.objmap.graph.annotations.HasCollectionRemover;\r
+import org.simantics.objmap.graph.annotations.meta.IsCollectionRule;\r
+\r
+\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target(ElementType.METHOD)\r
+@IsCollectionRule\r
+@HasCollectionAdder(TypeRelatedElementsAdd.class)\r
+@HasCollectionRemover(TypeRelatedElementsRem.class)\r
+public @interface TypeRelatedElementsGet {\r
+       String value();\r
+       boolean composition() default false;\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/TypeRelatedElementsRem.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/TypeRelatedElementsRem.java
new file mode 100644 (file)
index 0000000..773b652
--- /dev/null
@@ -0,0 +1,13 @@
+package org.simantics.objmap.structural.annotations;\r
+\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target(ElementType.METHOD)\r
+public @interface TypeRelatedElementsRem {\r
+       String value();\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/TypeRelatedGetObj.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/TypeRelatedGetObj.java
new file mode 100644 (file)
index 0000000..e2d0b9f
--- /dev/null
@@ -0,0 +1,20 @@
+package org.simantics.objmap.structural.annotations;\r
+\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+import org.simantics.objmap.graph.annotations.HasSetter;\r
+import org.simantics.objmap.graph.annotations.meta.IsGetSetRule;\r
+\r
+\r
+\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target(ElementType.METHOD)\r
+//@HasGetSetRuleFactory(RelatedGetSetObjRuleFactory.class)\r
+@IsGetSetRule\r
+@HasSetter(TypeRelatedSetObj.class)\r
+public @interface TypeRelatedGetObj {\r
+       String value();\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/TypeRelatedGetValue.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/TypeRelatedGetValue.java
new file mode 100644 (file)
index 0000000..2cb19f5
--- /dev/null
@@ -0,0 +1,23 @@
+package org.simantics.objmap.structural.annotations;\r
+\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+import org.simantics.objmap.graph.annotations.HasSetter;\r
+import org.simantics.objmap.graph.annotations.meta.IsGetSetRule;\r
+import org.simantics.objmap.graph.rules.adapters.IdentityAdapter;\r
+import org.simantics.objmap.graph.rules.adapters.ValueAdapter;\r
+\r
+\r
+\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target(ElementType.METHOD)\r
+//@HasGetSetRuleFactory(RelatedGetSetValueRuleFactory.class)\r
+@IsGetSetRule\r
+@HasSetter(TypeRelatedSetValue.class)\r
+public @interface TypeRelatedGetValue {\r
+       String value();\r
+        Class<? extends ValueAdapter> adapter() default IdentityAdapter.class;\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/TypeRelatedSetObj.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/TypeRelatedSetObj.java
new file mode 100644 (file)
index 0000000..71e9628
--- /dev/null
@@ -0,0 +1,13 @@
+package org.simantics.objmap.structural.annotations;\r
+\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target(ElementType.METHOD)\r
+public @interface TypeRelatedSetObj {\r
+       String value();\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/TypeRelatedSetValue.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/TypeRelatedSetValue.java
new file mode 100644 (file)
index 0000000..de8a604
--- /dev/null
@@ -0,0 +1,13 @@
+package org.simantics.objmap.structural.annotations;\r
+\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+\r
+\r
+@Retention(RetentionPolicy.RUNTIME)\r
+@Target(ElementType.METHOD)\r
+public @interface TypeRelatedSetValue {\r
+       String value();\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/DataTypeUtils.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/DataTypeUtils.java
new file mode 100644 (file)
index 0000000..36091e4
--- /dev/null
@@ -0,0 +1,57 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.structural.annotations.factories;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.layer0.Layer0;\r
+\r
+public class DataTypeUtils {\r
+    \r
+    public static Resource dataTypeOfClass(ReadGraph g, Class<?> clazz) {\r
+        Layer0 b = Layer0.getInstance(g);\r
+        if(clazz.equals(Double.class) || clazz.equals(double.class))\r
+            return b.Double;\r
+        else if(clazz.equals(String.class))\r
+            return b.String;\r
+        else if(clazz.equals(Integer.class) || clazz.equals(int.class))\r
+            return b.Integer;\r
+        else if(clazz.equals(Float.class) || clazz.equals(float.class))\r
+            return b.Float;\r
+        else if(clazz.equals(Boolean.class) || clazz.equals(boolean.class))\r
+            return b.Boolean;\r
+        else if(clazz.equals(Long.class) || clazz.equals(long.class))\r
+            return b.Long;\r
+        else if(clazz.equals(Byte.class) || clazz.equals(byte.class))\r
+            return b.Byte;\r
+        \r
+        else if(clazz.equals(double[].class))\r
+            return b.DoubleArray;\r
+        else if(clazz.equals(int[].class))\r
+            return b.IntegerArray;\r
+        else if(clazz.equals(byte[].class))\r
+            return b.ByteArray;\r
+        else if(clazz.equals(float[].class))\r
+            return b.FloatArray;\r
+        else if(clazz.equals(boolean[].class))\r
+            return b.BooleanArray;\r
+        else if(clazz.equals(String[].class))\r
+            return b.StringArray;\r
+        else if(clazz.equals(long[].class))\r
+            return b.LongArray;\r
+        else {\r
+               System.out.println("Couldn't find a data type for " + clazz);\r
+            return null;\r
+        }\r
+    }\r
+    \r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/OptionalRelatedElementsRuleFactory.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/OptionalRelatedElementsRuleFactory.java
new file mode 100644 (file)
index 0000000..ad603ec
--- /dev/null
@@ -0,0 +1,44 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.structural.annotations.factories;\r
+\r
+import java.lang.annotation.Annotation;\r
+import java.lang.reflect.Field;\r
+import java.util.Collection;\r
+import java.util.Collections;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.exception.ResourceNotFoundException;\r
+import org.simantics.db.exception.ServiceException;\r
+import org.simantics.db.exception.ValidationException;\r
+import org.simantics.objmap.bidirectional.IBidirectionalMappingRule;\r
+import org.simantics.objmap.graph.annotations.OptionalRelatedElements;\r
+import org.simantics.objmap.graph.rules.MappedElementsRule;\r
+import org.simantics.objmap.structural.rules.domain.RelatedObjectsAccessor;\r
+import org.simantics.objmap.graph.rules.factory.IFieldRuleFactory;\r
+import org.simantics.objmap.graph.rules.range.FieldAccessorWithDefault;\r
+import org.simantics.objmap.structural.StructuralResource;\r
+\r
+\r
+public class OptionalRelatedElementsRuleFactory<Range> implements IFieldRuleFactory<StructuralResource, Range> {\r
+\r
+    @Override\r
+    public IBidirectionalMappingRule<StructuralResource, Range> create(ReadGraph g, Annotation _annotation, Field field) throws ResourceNotFoundException, ValidationException, ServiceException {\r
+        OptionalRelatedElements annotation = (OptionalRelatedElements)_annotation;\r
+        return new MappedElementsRule<StructuralResource, Range>(\r
+                new RelatedObjectsAccessor(g.getResource(annotation.value()),\r
+                        annotation.composition(),false),\r
+                new FieldAccessorWithDefault<Range,Collection<Range>>(field, (Collection<Range>)Collections.emptyList())\r
+                );\r
+    }\r
+\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/RelatedElementRuleFactory.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/RelatedElementRuleFactory.java
new file mode 100644 (file)
index 0000000..b607404
--- /dev/null
@@ -0,0 +1,41 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.structural.annotations.factories;\r
+\r
+import java.lang.annotation.Annotation;\r
+import java.lang.reflect.Field;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.exception.ResourceNotFoundException;\r
+import org.simantics.db.exception.ServiceException;\r
+import org.simantics.db.exception.ValidationException;\r
+import org.simantics.objmap.bidirectional.IBidirectionalMappingRule;\r
+import org.simantics.objmap.graph.annotations.RelatedElement;\r
+import org.simantics.objmap.graph.rules.MappedElementRule;\r
+import org.simantics.objmap.graph.rules.domain.RelatedObjectAccessor;\r
+import org.simantics.objmap.graph.rules.factory.IFieldRuleFactory;\r
+import org.simantics.objmap.graph.rules.range.FieldAccessor;\r
+\r
+\r
+public class RelatedElementRuleFactory<Range> implements IFieldRuleFactory<Resource,Range> {\r
+\r
+    @Override\r
+    public IBidirectionalMappingRule<Resource, Range> create(ReadGraph g, Annotation _annotation, Field field) throws ResourceNotFoundException, ValidationException, ServiceException {\r
+        RelatedElement annotation = (RelatedElement)_annotation;\r
+        return new MappedElementRule<Resource,Range>(\r
+                new RelatedObjectAccessor(g.getResource(annotation.value())),\r
+                new FieldAccessor<Range,Range>(field)\r
+                );\r
+    }\r
+\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/RelatedElementsRuleFactory.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/RelatedElementsRuleFactory.java
new file mode 100644 (file)
index 0000000..b1c5f82
--- /dev/null
@@ -0,0 +1,43 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.structural.annotations.factories;\r
+\r
+import java.lang.annotation.Annotation;\r
+import java.lang.reflect.Field;\r
+import java.util.Collection;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.exception.ResourceNotFoundException;\r
+import org.simantics.db.exception.ServiceException;\r
+import org.simantics.db.exception.ValidationException;\r
+import org.simantics.objmap.bidirectional.IBidirectionalMappingRule;\r
+import org.simantics.objmap.graph.annotations.RelatedElements;\r
+import org.simantics.objmap.graph.rules.MappedElementsRule;\r
+import org.simantics.objmap.structural.rules.domain.RelatedObjectsAccessor;\r
+import org.simantics.objmap.graph.rules.factory.IFieldRuleFactory;\r
+import org.simantics.objmap.graph.rules.range.FieldAccessor;\r
+import org.simantics.objmap.structural.StructuralResource;\r
+\r
+\r
+public class RelatedElementsRuleFactory<Range> implements IFieldRuleFactory<StructuralResource, Range> {\r
+\r
+    @Override\r
+    public IBidirectionalMappingRule<StructuralResource, Range> create(ReadGraph g, Annotation _annotation, Field field) throws ResourceNotFoundException, ValidationException, ServiceException {\r
+        RelatedElements annotation = (RelatedElements)_annotation;\r
+        return new MappedElementsRule<StructuralResource,Range>(\r
+                new RelatedObjectsAccessor(g.getResource(annotation.value()),\r
+                        annotation.composition(),false),\r
+                new FieldAccessor<Range,Collection<Range>>(field)\r
+                );\r
+    }\r
+\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/RelatedElementsRuleFactory2.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/RelatedElementsRuleFactory2.java
new file mode 100644 (file)
index 0000000..08feae2
--- /dev/null
@@ -0,0 +1,44 @@
+package org.simantics.objmap.structural.annotations.factories;\r
+\r
+import java.lang.annotation.Annotation;\r
+import java.lang.reflect.Method;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.objmap.bidirectional.IBidirectionalMappingRule;\r
+import org.simantics.objmap.graph.annotations.RelatedElementsAdd;\r
+import org.simantics.objmap.graph.annotations.RelatedElementsGet;\r
+import org.simantics.objmap.graph.annotations.RelatedElementsRem;\r
+import org.simantics.objmap.graph.rules.MappedElementsRule;\r
+import org.simantics.objmap.graph.rules.factory.ICollectionRuleFactory;\r
+import org.simantics.objmap.graph.rules.range.CollectionAccessor;\r
+import org.simantics.objmap.structural.StructuralResource;\r
+import org.simantics.objmap.structural.rules.domain.RelatedObjectsAccessor;\r
+\r
+\r
+public class RelatedElementsRuleFactory2<Range> implements ICollectionRuleFactory<StructuralResource,Range> {\r
+       \r
+       @Override\r
+       public IBidirectionalMappingRule<StructuralResource, Range> create(ReadGraph g, Annotation annotation,\r
+                       Method getter, Method adder, Method remover)\r
+                       throws DatabaseException {\r
+               RelatedElementsGet getterAnn = (RelatedElementsGet)annotation;\r
+               return new MappedElementsRule<StructuralResource,Range>(new RelatedObjectsAccessor(g.getResource(getterAnn.value()),getterAnn.composition(),false,true,false),\r
+                                       new CollectionAccessor<Range,Range>(getter, adder, remover));\r
+       }\r
+       \r
+       @Override\r
+       public boolean isAdder(Annotation getterAnnotation, Annotation annotation) {\r
+               RelatedElementsGet getterAnn = (RelatedElementsGet)getterAnnotation;\r
+               RelatedElementsAdd adderAnn = (RelatedElementsAdd)annotation;\r
+               return getterAnn.value().equals(adderAnn.value());\r
+       }\r
+       \r
+       @Override\r
+       public boolean isRemover(Annotation getterAnnotation, Annotation annotation) {\r
+               RelatedElementsGet getterAnn = (RelatedElementsGet)getterAnnotation;\r
+               RelatedElementsRem adderAnn = (RelatedElementsRem)annotation;\r
+               return getterAnn.value().equals(adderAnn.value());\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/RelatedGetSetObjRuleFactory.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/RelatedGetSetObjRuleFactory.java
new file mode 100644 (file)
index 0000000..9c6bc77
--- /dev/null
@@ -0,0 +1,44 @@
+package org.simantics.objmap.structural.annotations.factories;\r
+\r
+import java.lang.annotation.Annotation;\r
+import java.lang.reflect.Method;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.objmap.bidirectional.IBidirectionalMappingRule;\r
+import org.simantics.objmap.graph.annotations.RelatedGetObj;\r
+import org.simantics.objmap.graph.annotations.RelatedSetObj;\r
+import org.simantics.objmap.graph.rules.MappedElementRule;\r
+import org.simantics.objmap.structural.rules.domain.RelatedObjectAccessor;\r
+import org.simantics.objmap.graph.rules.factory.IGetSetRuleFactory;\r
+import org.simantics.objmap.graph.rules.range.GetSetObjectAccessor;\r
+import org.simantics.objmap.structural.StructuralResource;\r
+\r
+\r
+/**\r
+ * Rule factory for mapped object using Getter/Setter-methods.\r
+ * \r
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>\r
+ *\r
+ */\r
+public class RelatedGetSetObjRuleFactory<Range> implements IGetSetRuleFactory<StructuralResource,Range> {\r
+       \r
+       @Override\r
+       public IBidirectionalMappingRule<StructuralResource,Range> create(ReadGraph g, Annotation annotation,\r
+                       Method getter, Method setter)\r
+                       throws DatabaseException {\r
+               RelatedGetObj getterAnn = (RelatedGetObj)annotation;\r
+               return new MappedElementRule<StructuralResource,Range>(new RelatedObjectAccessor(g.getResource(getterAnn.value()),false,true,false),\r
+                                       new GetSetObjectAccessor<Range,Range>(getter, setter));\r
+       }\r
+       \r
+       @Override\r
+       public boolean isSetter(Annotation getterAnnotation, Annotation annotation) {\r
+               RelatedGetObj getterAnn = (RelatedGetObj)getterAnnotation;\r
+               RelatedSetObj setterAnn = (RelatedSetObj)annotation;\r
+               return getterAnn.value().equals(setterAnn.value());\r
+       }\r
+       \r
+       \r
+\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/RelatedGetSetValueRuleFactory.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/RelatedGetSetValueRuleFactory.java
new file mode 100644 (file)
index 0000000..5974dd8
--- /dev/null
@@ -0,0 +1,101 @@
+package org.simantics.objmap.structural.annotations.factories;\r
+\r
+import java.lang.annotation.Annotation;\r
+import java.lang.reflect.Method;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.layer0.Layer0;\r
+import org.simantics.objmap.bidirectional.IBidirectionalMappingRule;\r
+import org.simantics.objmap.graph.annotations.RelatedGetValue;\r
+import org.simantics.objmap.graph.annotations.RelatedSetValue;\r
+import org.simantics.objmap.graph.rules.ValueRule;\r
+import org.simantics.objmap.graph.rules.adapters.IdentityAdapter;\r
+import org.simantics.objmap.graph.rules.adapters.ValueAdapter;\r
+import org.simantics.objmap.structural.StructuralResource;\r
+import org.simantics.objmap.structural.rules.domain.RelatedValueAccessor;\r
+import org.simantics.objmap.graph.rules.factory.IGetSetRuleFactory;\r
+import org.simantics.objmap.graph.rules.range.AdaptedRangeAccessor;\r
+import org.simantics.objmap.graph.rules.range.GetSetValueAccessor;\r
+import org.simantics.objmap.graph.rules.range.IRangeAccessor;\r
+\r
+/**\r
+ * Rule factory for mapped value using Getter/Setter-methods.\r
+ * \r
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>\r
+ *\r
+ */\r
+public class RelatedGetSetValueRuleFactory<Range> implements IGetSetRuleFactory<StructuralResource,Range> {\r
+       \r
+       @Override\r
+       public IBidirectionalMappingRule<StructuralResource, Range> create(ReadGraph g, Annotation annotation,\r
+                       Method getter, Method setter)\r
+                       throws DatabaseException {\r
+               RelatedGetValue getterAnn = (RelatedGetValue)annotation;\r
+               \r
+               Class<? extends ValueAdapter> adapterClass = getterAnn.adapter();\r
+                IRangeAccessor<Range,Object> rangeAccessor = new GetSetValueAccessor<Range,Object>(getter, setter);\r
+        Resource valueType;\r
+        if (adapterClass == IdentityAdapter.class) {\r
+            valueType = dataTypeOfClass(g, getter.getReturnType());\r
+        } else {\r
+               try{\r
+                        ValueAdapter adapter = adapterClass.newInstance();\r
+                 rangeAccessor = new AdaptedRangeAccessor<Range>(rangeAccessor, adapter);\r
+                 valueType = adapter.rangeTypeToDomainType(g, getter.getReturnType());\r
+             } catch (InstantiationException e) {\r
+                 throw new RuntimeException(e);\r
+             } catch (IllegalAccessException e) {\r
+                 throw new RuntimeException(e);\r
+             }\r
+        }\r
+               return new ValueRule<StructuralResource,Range>(new RelatedValueAccessor(g.getResource(getterAnn.value()), valueType,false,true,false),\r
+                                       rangeAccessor);\r
+       }\r
+       \r
+       @Override\r
+       public boolean isSetter(Annotation getterAnnotation, Annotation annotation) {\r
+               RelatedGetValue getterAnn = (RelatedGetValue)getterAnnotation;\r
+               RelatedSetValue setterAnn = (RelatedSetValue)annotation;\r
+               return getterAnn.value().equals(setterAnn.value());\r
+       }\r
+       \r
+       public static Resource dataTypeOfClass(ReadGraph g, Class<?> clazz) {\r
+        Layer0 b = Layer0.getInstance(g);\r
+        if(clazz.equals(Double.class) || clazz.equals(double.class))\r
+            return b.Double;\r
+        else if(clazz.equals(String.class))\r
+            return b.String;\r
+        else if(clazz.equals(Integer.class) || clazz.equals(int.class))\r
+            return b.Integer;\r
+        else if(clazz.equals(Float.class) || clazz.equals(float.class))\r
+            return b.Float;\r
+        else if(clazz.equals(Boolean.class) || clazz.equals(boolean.class))\r
+            return b.Boolean;\r
+        else if(clazz.equals(Long.class) || clazz.equals(long.class))\r
+            return b.Long;\r
+        else if(clazz.equals(Byte.class) || clazz.equals(byte.class))\r
+            return b.Byte;\r
+        \r
+        else if(clazz.equals(double[].class))\r
+            return b.DoubleArray;\r
+        else if(clazz.equals(int[].class))\r
+            return b.IntegerArray;\r
+        else if(clazz.equals(byte[].class))\r
+            return b.ByteArray;\r
+        else if(clazz.equals(float[].class))\r
+            return b.FloatArray;\r
+        else if(clazz.equals(boolean[].class))\r
+            return b.BooleanArray;\r
+        else if(clazz.equals(String[].class))\r
+            return b.StringArray;\r
+        else if(clazz.equals(long[].class))\r
+            return b.LongArray;\r
+        else {\r
+               System.out.println("Couldn't find a data type for " + clazz);\r
+            return null;\r
+        }\r
+    }\r
+\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/RelatedOrderedSetElementsRuleFactory.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/RelatedOrderedSetElementsRuleFactory.java
new file mode 100644 (file)
index 0000000..01838ab
--- /dev/null
@@ -0,0 +1,42 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.structural.annotations.factories;\r
+\r
+import java.lang.annotation.Annotation;\r
+import java.lang.reflect.Field;\r
+import java.util.Collection;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.exception.ResourceNotFoundException;\r
+import org.simantics.db.exception.ServiceException;\r
+import org.simantics.db.exception.ValidationException;\r
+import org.simantics.objmap.bidirectional.IBidirectionalMappingRule;\r
+import org.simantics.objmap.graph.annotations.RelatedOrderedSetElements;\r
+import org.simantics.objmap.graph.rules.MappedElementsRule;\r
+import org.simantics.objmap.graph.rules.factory.IFieldRuleFactory;\r
+import org.simantics.objmap.graph.rules.range.FieldAccessor;\r
+import org.simantics.objmap.structural.StructuralResource;\r
+import org.simantics.objmap.structural.rules.domain.RelatedOrderedSetElementsAccessor;\r
+\r
+\r
+public class RelatedOrderedSetElementsRuleFactory<Range> implements IFieldRuleFactory<StructuralResource, Range> {\r
+\r
+    @Override\r
+    public IBidirectionalMappingRule<StructuralResource, Range> create(ReadGraph g, Annotation _annotation, Field field) throws ResourceNotFoundException, ValidationException, ServiceException {\r
+        RelatedOrderedSetElements annotation = (RelatedOrderedSetElements)_annotation;\r
+        return new MappedElementsRule<StructuralResource,Range>(\r
+                new RelatedOrderedSetElementsAccessor(annotation.composition(),false),\r
+                new FieldAccessor<Range,Collection<Range>>(field)\r
+                );\r
+    }\r
+\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/RelatedValueRuleFactory.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/RelatedValueRuleFactory.java
new file mode 100644 (file)
index 0000000..5ee9f20
--- /dev/null
@@ -0,0 +1,61 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.structural.annotations.factories;\r
+\r
+import java.lang.annotation.Annotation;\r
+import java.lang.reflect.Field;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.exception.ResourceNotFoundException;\r
+import org.simantics.db.exception.ServiceException;\r
+import org.simantics.db.exception.ValidationException;\r
+\r
+import org.simantics.objmap.bidirectional.IBidirectionalMappingRule;\r
+import org.simantics.objmap.graph.annotations.RelatedValue;\r
+import org.simantics.objmap.graph.rules.ValueRule;\r
+import org.simantics.objmap.graph.rules.adapters.IdentityAdapter;\r
+import org.simantics.objmap.graph.rules.adapters.ValueAdapter;\r
+import org.simantics.objmap.structural.rules.domain.RelatedValueAccessor;\r
+import org.simantics.objmap.graph.rules.factory.IFieldRuleFactory;\r
+import org.simantics.objmap.graph.rules.range.AdaptedRangeAccessor;\r
+import org.simantics.objmap.graph.rules.range.FieldAccessor;\r
+import org.simantics.objmap.graph.rules.range.IRangeAccessor;\r
+import org.simantics.objmap.structural.StructuralResource;\r
+\r
+\r
+public class RelatedValueRuleFactory<Range> implements IFieldRuleFactory<StructuralResource, Range> {\r
+\r
+    @Override\r
+    public IBidirectionalMappingRule<StructuralResource, Range> create(ReadGraph g, Annotation _annotation, Field field) throws ResourceNotFoundException,\r
+            ValidationException, ServiceException {\r
+        RelatedValue annotation = (RelatedValue) _annotation;\r
+        Class<? extends ValueAdapter> adapterClass = annotation.adapter();\r
+        IRangeAccessor<Range,Object> rangeAccessor = new FieldAccessor<Range,Object>(field);\r
+        Resource valueType;\r
+        if (adapterClass == IdentityAdapter.class) {\r
+            valueType = DataTypeUtils.dataTypeOfClass(g, field.getType());\r
+        } else {\r
+            try {\r
+                ValueAdapter adapter = adapterClass.newInstance();\r
+                rangeAccessor = new AdaptedRangeAccessor<Range>(rangeAccessor, adapter);\r
+                valueType = adapter.rangeTypeToDomainType(g, field.getType());\r
+            } catch (InstantiationException e) {\r
+                throw new RuntimeException(e);\r
+            } catch (IllegalAccessException e) {\r
+                throw new RuntimeException(e);\r
+            }\r
+        }\r
+        return new ValueRule<StructuralResource,Range>(new RelatedValueAccessor(g.getResource(annotation.value()), valueType,false,true,false), rangeAccessor);\r
+    }\r
+\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/StructuralRelatedElementsRuleFactory2.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/StructuralRelatedElementsRuleFactory2.java
new file mode 100644 (file)
index 0000000..ad30aee
--- /dev/null
@@ -0,0 +1,44 @@
+package org.simantics.objmap.structural.annotations.factories;\r
+\r
+import java.lang.annotation.Annotation;\r
+import java.lang.reflect.Method;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.objmap.bidirectional.IBidirectionalMappingRule;\r
+import org.simantics.objmap.graph.rules.MappedElementsRule;\r
+import org.simantics.objmap.graph.rules.factory.ICollectionRuleFactory;\r
+import org.simantics.objmap.graph.rules.range.CollectionAccessor;\r
+import org.simantics.objmap.structural.StructuralResource;\r
+import org.simantics.objmap.structural.annotations.StructuralRelatedElementsAdd;\r
+import org.simantics.objmap.structural.annotations.StructuralRelatedElementsGet;\r
+import org.simantics.objmap.structural.annotations.StructuralRelatedElementsRem;\r
+import org.simantics.objmap.structural.rules.domain.StructuralRelatedObjectsAccessor;\r
+\r
+\r
+public class StructuralRelatedElementsRuleFactory2<Range> implements ICollectionRuleFactory<StructuralResource,Range> {\r
+       \r
+       @Override\r
+       public IBidirectionalMappingRule<StructuralResource, Range> create(ReadGraph g, Annotation annotation,\r
+                       Method getter, Method adder, Method remover)\r
+                       throws DatabaseException {\r
+               StructuralRelatedElementsGet getterAnn = (StructuralRelatedElementsGet)annotation;\r
+               return new MappedElementsRule<StructuralResource,Range>(new StructuralRelatedObjectsAccessor(g.getResource(getterAnn.value()),getterAnn.composition()),\r
+                                       new CollectionAccessor<Range,Range>(getter, adder, remover));\r
+       }\r
+       \r
+       @Override\r
+       public boolean isAdder(Annotation getterAnnotation, Annotation annotation) {\r
+               StructuralRelatedElementsGet getterAnn = (StructuralRelatedElementsGet)getterAnnotation;\r
+               StructuralRelatedElementsAdd adderAnn = (StructuralRelatedElementsAdd)annotation;\r
+               return getterAnn.value().equals(adderAnn.value());\r
+       }\r
+       \r
+       @Override\r
+       public boolean isRemover(Annotation getterAnnotation, Annotation annotation) {\r
+               StructuralRelatedElementsGet getterAnn = (StructuralRelatedElementsGet)getterAnnotation;\r
+               StructuralRelatedElementsRem adderAnn = (StructuralRelatedElementsRem)annotation;\r
+               return getterAnn.value().equals(adderAnn.value());\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/StructuralRelatedGetSetObjRuleFactory.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/StructuralRelatedGetSetObjRuleFactory.java
new file mode 100644 (file)
index 0000000..bb97f7b
--- /dev/null
@@ -0,0 +1,44 @@
+package org.simantics.objmap.structural.annotations.factories;\r
+\r
+import java.lang.annotation.Annotation;\r
+import java.lang.reflect.Method;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.objmap.bidirectional.IBidirectionalMappingRule;\r
+import org.simantics.objmap.graph.rules.MappedElementRule;\r
+import org.simantics.objmap.graph.rules.factory.IGetSetRuleFactory;\r
+import org.simantics.objmap.graph.rules.range.GetSetObjectAccessor;\r
+import org.simantics.objmap.structural.StructuralResource;\r
+import org.simantics.objmap.structural.annotations.StructuralRelatedGetObj;\r
+import org.simantics.objmap.structural.annotations.StructuralRelatedSetObj;\r
+import org.simantics.objmap.structural.rules.domain.StructuralRelatedObjectAccessor;\r
+\r
+\r
+/**\r
+ * Rule factory for mapped object using Getter/Setter-methods.\r
+ * \r
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>\r
+ *\r
+ */\r
+public class StructuralRelatedGetSetObjRuleFactory<Range> implements IGetSetRuleFactory<StructuralResource,Range> {\r
+       \r
+       @Override\r
+       public IBidirectionalMappingRule<StructuralResource,Range> create(ReadGraph g, Annotation annotation,\r
+                       Method getter, Method setter)\r
+                       throws DatabaseException {\r
+               StructuralRelatedGetObj getterAnn = (StructuralRelatedGetObj)annotation;\r
+               return new MappedElementRule<StructuralResource,Range>(new StructuralRelatedObjectAccessor(g.getResource(getterAnn.value()),false,true,false),\r
+                                       new GetSetObjectAccessor<Range,Range>(getter, setter));\r
+       }\r
+       \r
+       @Override\r
+       public boolean isSetter(Annotation getterAnnotation, Annotation annotation) {\r
+               StructuralRelatedGetObj getterAnn = (StructuralRelatedGetObj)getterAnnotation;\r
+               StructuralRelatedSetObj setterAnn = (StructuralRelatedSetObj)annotation;\r
+               return getterAnn.value().equals(setterAnn.value());\r
+       }\r
+       \r
+       \r
+\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/TypeRelatedElementsRuleFactory2.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/TypeRelatedElementsRuleFactory2.java
new file mode 100644 (file)
index 0000000..565f9dc
--- /dev/null
@@ -0,0 +1,44 @@
+package org.simantics.objmap.structural.annotations.factories;\r
+\r
+import java.lang.annotation.Annotation;\r
+import java.lang.reflect.Method;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.objmap.bidirectional.IBidirectionalMappingRule;\r
+import org.simantics.objmap.graph.rules.MappedElementsRule;\r
+import org.simantics.objmap.graph.rules.factory.ICollectionRuleFactory;\r
+import org.simantics.objmap.graph.rules.range.CollectionAccessor;\r
+import org.simantics.objmap.structural.StructuralResource;\r
+import org.simantics.objmap.structural.annotations.TypeRelatedElementsAdd;\r
+import org.simantics.objmap.structural.annotations.TypeRelatedElementsGet;\r
+import org.simantics.objmap.structural.annotations.TypeRelatedElementsRem;\r
+import org.simantics.objmap.structural.rules.domain.RelatedObjectsAccessor;\r
+\r
+\r
+public class TypeRelatedElementsRuleFactory2<Range> implements ICollectionRuleFactory<StructuralResource,Range> {\r
+       \r
+       @Override\r
+       public IBidirectionalMappingRule<StructuralResource, Range> create(ReadGraph g, Annotation annotation,\r
+                       Method getter, Method adder, Method remover)\r
+                       throws DatabaseException {\r
+               TypeRelatedElementsGet getterAnn = (TypeRelatedElementsGet)annotation;\r
+               return new MappedElementsRule<StructuralResource,Range>(new RelatedObjectsAccessor(g.getResource(getterAnn.value()),getterAnn.composition(),true,true,true),\r
+                                       new CollectionAccessor<Range,Range>(getter, adder, remover));\r
+       }\r
+       \r
+       @Override\r
+       public boolean isAdder(Annotation getterAnnotation, Annotation annotation) {\r
+               TypeRelatedElementsGet getterAnn = (TypeRelatedElementsGet)getterAnnotation;\r
+               TypeRelatedElementsAdd adderAnn = (TypeRelatedElementsAdd)annotation;\r
+               return getterAnn.value().equals(adderAnn.value());\r
+       }\r
+       \r
+       @Override\r
+       public boolean isRemover(Annotation getterAnnotation, Annotation annotation) {\r
+               TypeRelatedElementsGet getterAnn = (TypeRelatedElementsGet)getterAnnotation;\r
+               TypeRelatedElementsRem adderAnn = (TypeRelatedElementsRem)annotation;\r
+               return getterAnn.value().equals(adderAnn.value());\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/TypeRelatedGetSetObjRuleFactory.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/TypeRelatedGetSetObjRuleFactory.java
new file mode 100644 (file)
index 0000000..44dfffd
--- /dev/null
@@ -0,0 +1,44 @@
+package org.simantics.objmap.structural.annotations.factories;\r
+\r
+import java.lang.annotation.Annotation;\r
+import java.lang.reflect.Method;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.objmap.bidirectional.IBidirectionalMappingRule;\r
+import org.simantics.objmap.graph.rules.MappedElementRule;\r
+import org.simantics.objmap.graph.rules.factory.IGetSetRuleFactory;\r
+import org.simantics.objmap.graph.rules.range.GetSetObjectAccessor;\r
+import org.simantics.objmap.structural.StructuralResource;\r
+import org.simantics.objmap.structural.annotations.TypeRelatedGetObj;\r
+import org.simantics.objmap.structural.annotations.TypeRelatedSetObj;\r
+import org.simantics.objmap.structural.rules.domain.RelatedObjectAccessor;\r
+\r
+\r
+/**\r
+ * Rule factory for mapped object using Getter/Setter-methods.\r
+ * \r
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>\r
+ *\r
+ */\r
+public class TypeRelatedGetSetObjRuleFactory<Range> implements IGetSetRuleFactory<StructuralResource,Range> {\r
+       \r
+       @Override\r
+       public IBidirectionalMappingRule<StructuralResource,Range> create(ReadGraph g, Annotation annotation,\r
+                       Method getter, Method setter)\r
+                       throws DatabaseException {\r
+               TypeRelatedGetObj getterAnn = (TypeRelatedGetObj)annotation;\r
+               return new MappedElementRule<StructuralResource,Range>(new RelatedObjectAccessor(g.getResource(getterAnn.value()),true,true,true),\r
+                                       new GetSetObjectAccessor<Range,Range>(getter, setter));\r
+       }\r
+       \r
+       @Override\r
+       public boolean isSetter(Annotation getterAnnotation, Annotation annotation) {\r
+               TypeRelatedGetObj getterAnn = (TypeRelatedGetObj)getterAnnotation;\r
+               TypeRelatedSetObj setterAnn = (TypeRelatedSetObj)annotation;\r
+               return getterAnn.value().equals(setterAnn.value());\r
+       }\r
+       \r
+       \r
+\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/TypeRelatedGetSetValueRuleFactory.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/TypeRelatedGetSetValueRuleFactory.java
new file mode 100644 (file)
index 0000000..05dd678
--- /dev/null
@@ -0,0 +1,101 @@
+package org.simantics.objmap.structural.annotations.factories;\r
+\r
+import java.lang.annotation.Annotation;\r
+import java.lang.reflect.Method;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.layer0.Layer0;\r
+import org.simantics.objmap.bidirectional.IBidirectionalMappingRule;\r
+import org.simantics.objmap.graph.rules.ValueRule;\r
+import org.simantics.objmap.graph.rules.adapters.IdentityAdapter;\r
+import org.simantics.objmap.graph.rules.adapters.ValueAdapter;\r
+import org.simantics.objmap.graph.rules.factory.IGetSetRuleFactory;\r
+import org.simantics.objmap.graph.rules.range.AdaptedRangeAccessor;\r
+import org.simantics.objmap.graph.rules.range.GetSetValueAccessor;\r
+import org.simantics.objmap.graph.rules.range.IRangeAccessor;\r
+import org.simantics.objmap.structural.StructuralResource;\r
+import org.simantics.objmap.structural.annotations.TypeRelatedGetValue;\r
+import org.simantics.objmap.structural.annotations.TypeRelatedSetValue;\r
+import org.simantics.objmap.structural.rules.domain.RelatedValueAccessor;\r
+\r
+/**\r
+ * Rule factory for mapped value using Getter/Setter-methods.\r
+ * \r
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>\r
+ *\r
+ */\r
+public class TypeRelatedGetSetValueRuleFactory<Range> implements IGetSetRuleFactory<StructuralResource,Range> {\r
+       \r
+       @Override\r
+       public IBidirectionalMappingRule<StructuralResource, Range> create(ReadGraph g, Annotation annotation,\r
+                       Method getter, Method setter)\r
+                       throws DatabaseException {\r
+               TypeRelatedGetValue getterAnn = (TypeRelatedGetValue)annotation;\r
+               \r
+               Class<? extends ValueAdapter> adapterClass = getterAnn.adapter();\r
+                IRangeAccessor<Range,Object> rangeAccessor = new GetSetValueAccessor<Range,Object>(getter, setter);\r
+        Resource valueType;\r
+        if (adapterClass == IdentityAdapter.class) {\r
+            valueType = dataTypeOfClass(g, getter.getReturnType());\r
+        } else {\r
+               try{\r
+                        ValueAdapter adapter = adapterClass.newInstance();\r
+                 rangeAccessor = new AdaptedRangeAccessor<Range>(rangeAccessor, adapter);\r
+                 valueType = adapter.rangeTypeToDomainType(g, getter.getReturnType());\r
+             } catch (InstantiationException e) {\r
+                 throw new RuntimeException(e);\r
+             } catch (IllegalAccessException e) {\r
+                 throw new RuntimeException(e);\r
+             }\r
+        }\r
+               return new ValueRule<StructuralResource,Range>(new RelatedValueAccessor(g.getResource(getterAnn.value()), valueType,true,true,true),\r
+                                       rangeAccessor);\r
+       }\r
+       \r
+       @Override\r
+       public boolean isSetter(Annotation getterAnnotation, Annotation annotation) {\r
+               TypeRelatedGetValue getterAnn = (TypeRelatedGetValue)getterAnnotation;\r
+               TypeRelatedSetValue setterAnn = (TypeRelatedSetValue)annotation;\r
+               return getterAnn.value().equals(setterAnn.value());\r
+       }\r
+       \r
+       public static Resource dataTypeOfClass(ReadGraph g, Class<?> clazz) {\r
+        Layer0 b = Layer0.getInstance(g);\r
+        if(clazz.equals(Double.class) || clazz.equals(double.class))\r
+            return b.Double;\r
+        else if(clazz.equals(String.class))\r
+            return b.String;\r
+        else if(clazz.equals(Integer.class) || clazz.equals(int.class))\r
+            return b.Integer;\r
+        else if(clazz.equals(Float.class) || clazz.equals(float.class))\r
+            return b.Float;\r
+        else if(clazz.equals(Boolean.class) || clazz.equals(boolean.class))\r
+            return b.Boolean;\r
+        else if(clazz.equals(Long.class) || clazz.equals(long.class))\r
+            return b.Long;\r
+        else if(clazz.equals(Byte.class) || clazz.equals(byte.class))\r
+            return b.Byte;\r
+        \r
+        else if(clazz.equals(double[].class))\r
+            return b.DoubleArray;\r
+        else if(clazz.equals(int[].class))\r
+            return b.IntegerArray;\r
+        else if(clazz.equals(byte[].class))\r
+            return b.ByteArray;\r
+        else if(clazz.equals(float[].class))\r
+            return b.FloatArray;\r
+        else if(clazz.equals(boolean[].class))\r
+            return b.BooleanArray;\r
+        else if(clazz.equals(String[].class))\r
+            return b.StringArray;\r
+        else if(clazz.equals(long[].class))\r
+            return b.LongArray;\r
+        else {\r
+               System.out.println("Couldn't find a data type for " + clazz);\r
+            return null;\r
+        }\r
+    }\r
+\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/UpdateMethodFactory.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/annotations/factories/UpdateMethodFactory.java
new file mode 100644 (file)
index 0000000..690e006
--- /dev/null
@@ -0,0 +1,70 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.structural.annotations.factories;\r
+\r
+import java.lang.annotation.Annotation;\r
+import java.lang.reflect.Method;\r
+\r
+import org.apache.log4j.Logger;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.objmap.backward.IBackwardMapping;\r
+import org.simantics.objmap.bidirectional.IBidirectionalMappingRule;\r
+import org.simantics.objmap.exceptions.MappingException;\r
+import org.simantics.objmap.forward.IForwardMapping;\r
+import org.simantics.objmap.graph.rules.factory.IMethodRuleFactory;\r
+\r
+public class UpdateMethodFactory<Domain, Range> implements IMethodRuleFactory<Domain, Range> {\r
+\r
+    static Logger LOGGER = Logger.getLogger("org.simantics.objmap");\r
+    \r
+    @Override\r
+    public IBidirectionalMappingRule<Domain, Range> create(ReadGraph g, \r
+            Annotation annotation, \r
+            final Method method)\r
+            throws DatabaseException {\r
+        method.setAccessible(true);\r
+        return new IBidirectionalMappingRule<Domain,Range>() {\r
+            \r
+            @Override\r
+            public boolean updateRange(ReadGraph g, IForwardMapping<Domain, Range> map,\r
+                    Domain domainElement, Range rangeElement)\r
+                    throws MappingException {\r
+                LOGGER.info("    UpdateMethodFactory.updateRange");      \r
+                try {\r
+                    return (Boolean)method.invoke(rangeElement, g, domainElement);\r
+                } catch (Exception e) {\r
+                    // TODO Auto-generated catch block\r
+                    e.printStackTrace();\r
+                }\r
+                return false;\r
+            }\r
+            \r
+            @Override\r
+            public boolean updateDomain(WriteGraph g, IBackwardMapping<Domain,Range> map,\r
+                    Domain domainElement, Range rangeElement)\r
+                    throws MappingException {\r
+                return false;\r
+            }\r
+            \r
+            public void createDomain(WriteGraph g, IBackwardMapping<Domain,Range> map, Domain domainElement, Range rangeElement) throws MappingException {\r
+               updateDomain(g, map, domainElement, rangeElement);\r
+            };\r
+            \r
+            public void createRange(ReadGraph g, IForwardMapping<Domain,Range> map, Domain domainElement, Range rangeElement) throws MappingException {\r
+               updateRange(g, map, domainElement, rangeElement);\r
+            };\r
+        };\r
+    }\r
+\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/rules/domain/RelatedObjectAccessor.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/rules/domain/RelatedObjectAccessor.java
new file mode 100644 (file)
index 0000000..5cf862f
--- /dev/null
@@ -0,0 +1,111 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.structural.rules.domain;\r
+\r
+import org.apache.log4j.Logger;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.objmap.exceptions.MappingException;\r
+import org.simantics.objmap.graph.rules.domain.IDomainAccessor;\r
+import org.simantics.objmap.structural.StructuralResource;\r
+\r
+\r
+public class RelatedObjectAccessor implements IDomainAccessor<StructuralResource,StructuralResource> {\r
+\r
+    static Logger LOGGER = Logger.getLogger("org.simantics.objmap");\r
+    \r
+       Resource relation;\r
+       boolean useTypeResource;\r
+       \r
+       private boolean preventStructuralChanges = true;\r
+       private boolean preventStructuralRootChanges = true;\r
+       \r
+       public RelatedObjectAccessor(Resource relation, boolean useTypeResource) {\r
+               this.relation = relation;\r
+               this.useTypeResource = useTypeResource;\r
+       }\r
+       \r
+       public RelatedObjectAccessor(Resource relation, boolean useTypeResource, boolean preventStructuralChanges, boolean preventStructuralRootChanges) {\r
+               this.relation = relation;\r
+               this.useTypeResource = useTypeResource;\r
+               this.preventStructuralChanges = preventStructuralChanges;\r
+               this.preventStructuralRootChanges = preventStructuralRootChanges;\r
+       }\r
+       \r
+ private boolean preventChange(StructuralResource element) {\r
+       return preventStructuralChanges && element.isStructural() && (!element.isStructuralRoot()||preventStructuralRootChanges);       \r
+    }\r
+\r
+       @Override\r
+       public StructuralResource get(ReadGraph g, StructuralResource element) throws MappingException {\r
+               try {\r
+                   LOGGER.info("        RelatedObjectAccessor.get");\r
+                   Resource res = getServiceResource(g, element);\r
+                   if (res == null)\r
+                       return null;\r
+                       Resource r =  g.getPossibleObject(res, relation);\r
+                       if (r == null)\r
+                               return null;\r
+                       if (StructuralUtils.isStructuralInstance(g, r)) {\r
+                               return new StructuralResource(g, r, element.getContext(),r);\r
+                       } else {\r
+                               return new StructuralResource(g, r, element.getContext());\r
+                       }\r
+               } catch (DatabaseException e) {\r
+                       throw new MappingException(e);\r
+               }\r
+       }\r
+       \r
+       @Override\r
+       public boolean set(WriteGraph g, StructuralResource selement, StructuralResource value)\r
+                       throws MappingException {\r
+               try {\r
+                   LOGGER.info("        RelatedObjectAccessor.set");\r
+                   Resource element = getServiceResource(g, selement);\r
+                   if (element == null)\r
+                       return false;\r
+                   Resource resource = g.getPossibleObject(element, relation);\r
+                       if(resource == null) {\r
+                           if(value == null)\r
+                               return false;\r
+                           if (preventChange(selement))\r
+                                       return false;\r
+                           g.claim(element, relation, value.getResource());\r
+                           return true;\r
+                       }\r
+                       else if(resource.equals(value))\r
+                           return false;\r
+                       else {\r
+                               if (preventChange(selement))\r
+                                       return false;\r
+                           g.deny(element, relation);\r
+                           if(value != null)\r
+                               g.claim(element, relation, value.getResource());\r
+                           return true;\r
+                       }\r
+               } catch (DatabaseException e) {\r
+                       throw new MappingException(e);\r
+               }\r
+               \r
+       }\r
+       \r
+               \r
+       \r
+       private Resource getServiceResource(ReadGraph g, StructuralResource element) {\r
+               if(!useTypeResource)\r
+                       return element.getResource();\r
+               return element.getTypeResource();\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/rules/domain/RelatedObjectsAccessor.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/rules/domain/RelatedObjectsAccessor.java
new file mode 100644 (file)
index 0000000..0289564
--- /dev/null
@@ -0,0 +1,113 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.structural.rules.domain;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.Collections;\r
+import java.util.List;\r
+\r
+import org.apache.log4j.Logger;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.objmap.exceptions.MappingException;\r
+import org.simantics.objmap.graph.rules.domain.IDomainAccessor;\r
+import org.simantics.objmap.graph.rules.domain.MappingUtils;\r
+import org.simantics.objmap.structural.StructuralResource;\r
+\r
+\r
+public class RelatedObjectsAccessor implements IDomainAccessor<StructuralResource,Collection<StructuralResource>> {\r
+\r
+    static Logger LOGGER = Logger.getLogger("org.simantics.objmap");\r
+    \r
+       Resource relation;\r
+       boolean deleteExtraObjects;\r
+       boolean useTypeResource;\r
+       \r
+       private boolean preventStructuralChanges = true;\r
+       private boolean preventStructuralRootChanges = true;\r
+\r
+       public RelatedObjectsAccessor(Resource relation, boolean deleteExtraObjects, boolean useTypeResource) {\r
+        super();\r
+        this.relation = relation;\r
+        this.deleteExtraObjects = deleteExtraObjects;\r
+        this.useTypeResource = useTypeResource;\r
+    }\r
+       \r
+       public RelatedObjectsAccessor(Resource relation, boolean deleteExtraObjects, boolean useTypeResource, boolean preventStructuralChanges, boolean preventStructuralRootChanges) {\r
+        super();\r
+        this.relation = relation;\r
+        this.deleteExtraObjects = deleteExtraObjects;\r
+        this.useTypeResource = useTypeResource;\r
+               this.preventStructuralChanges = preventStructuralChanges;\r
+               this.preventStructuralRootChanges = preventStructuralRootChanges;\r
+    }\r
+\r
+    @Override\r
+       public Collection<StructuralResource> get(ReadGraph g, StructuralResource element) throws MappingException {\r
+               try {\r
+                   LOGGER.info("        RelatedObjectsAccessor.get");\r
+                       \r
+                  \r
+                   Resource res = getServiceResource(g, element);\r
+                   if (res == null)\r
+                       return Collections.EMPTY_LIST;\r
+                   Collection<Resource> coll = g.getObjects(res, relation);\r
+                       List<StructuralResource> result = new ArrayList<StructuralResource>(coll.size());\r
+                       for (Resource r : coll) {\r
+                               if (StructuralUtils.isStructuralInstance(g, r)) {\r
+                                       result.add(new StructuralResource(g, r, element.getContext(),r));\r
+                               } else {\r
+                                       result.add(new StructuralResource(g, r, element.getContext()));\r
+                               }\r
+                       }\r
+                       return result;\r
+               } catch (DatabaseException e) {\r
+                       throw new MappingException(e);\r
+               }\r
+       }\r
+    \r
+    private boolean preventChange(StructuralResource element) {\r
+       return preventStructuralChanges && element.isStructural() && (!element.isStructuralRoot()||preventStructuralRootChanges);       \r
+    }\r
+       \r
+       @Override\r
+       public boolean set(WriteGraph g, StructuralResource element, Collection<StructuralResource> value)\r
+                       throws MappingException {\r
+               try {\r
+                   LOGGER.info("        RelatedObjectsAccessor.set");\r
+                   Resource res = getServiceResource(g, element);\r
+                   if (res == null)\r
+                       return false;\r
+                   if (preventChange(element))\r
+                               return false;\r
+                   Resource[] arr = new Resource[value.size()];\r
+                   int i = 0; \r
+                   for (StructuralResource sr : value) {\r
+                       arr[i++] = sr.getResource();\r
+                   }\r
+                       return MappingUtils.synchronizeStatements(g, res, relation, \r
+                               arr, deleteExtraObjects);\r
+               } catch (DatabaseException e) {\r
+                       throw new MappingException(e);\r
+               }\r
+               \r
+       }\r
+\r
+       private Resource getServiceResource(ReadGraph g, StructuralResource element) {\r
+               if (!useTypeResource)\r
+                       return element.getResource();\r
+               return element.getTypeResource();\r
+       }\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/rules/domain/RelatedOrderedSetElementsAccessor.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/rules/domain/RelatedOrderedSetElementsAccessor.java
new file mode 100644 (file)
index 0000000..654a325
--- /dev/null
@@ -0,0 +1,86 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.structural.rules.domain;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.Collections;\r
+import java.util.List;\r
+\r
+import org.apache.log4j.Logger;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.db.common.utils.OrderedSetUtils;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.objmap.exceptions.MappingException;\r
+import org.simantics.objmap.graph.rules.domain.IDomainAccessor;\r
+import org.simantics.objmap.structural.StructuralResource;\r
+\r
+public class RelatedOrderedSetElementsAccessor implements IDomainAccessor<StructuralResource, Collection<StructuralResource>> {\r
+\r
+    static Logger LOGGER = Logger.getLogger("org.simantics.objmap");\r
+    \r
+       boolean deleteExtraObjects;\r
+       boolean useTypeResource;\r
+\r
+       public RelatedOrderedSetElementsAccessor(boolean deleteExtraObjects, boolean useTypeResource) {\r
+        super();\r
+        this.deleteExtraObjects = deleteExtraObjects;\r
+        this.useTypeResource = useTypeResource;\r
+    }\r
+\r
+    @Override\r
+       public Collection<StructuralResource> get(ReadGraph g, StructuralResource element) throws MappingException {\r
+               try {\r
+                   LOGGER.info("        RelatedOrderedSetElementsAccessor.get");\r
+                   Resource res = getServiceResource(g, element);\r
+                   if (res == null)\r
+                       return Collections.EMPTY_LIST;\r
+                       List<Resource> list =  OrderedSetUtils.toList(g, res);\r
+                       List<StructuralResource> result = new ArrayList<StructuralResource>(list.size());\r
+                       for (Resource r : list) {\r
+                               result.add(new StructuralResource(g,r,element.getContext()));\r
+                       }\r
+                       return result;\r
+               } catch (DatabaseException e) {\r
+                       throw new MappingException(e);\r
+               }\r
+       }\r
+       \r
+       @Override\r
+       public boolean set(WriteGraph g, StructuralResource element, Collection<StructuralResource> value)\r
+                       throws MappingException {\r
+               try {\r
+                   LOGGER.info("        RelatedOrderedSetElementsAccessor.set");\r
+                   Resource res = getServiceResource(g, element);\r
+                   if (res == null)\r
+                       return false;\r
+                   List<Resource> list = new ArrayList<Resource>(value.size());\r
+                   for (StructuralResource r : value) {\r
+                       list.add(r.getResource());\r
+                   }\r
+                   return OrderedSetUtils.set(g, res, list);\r
+                   // FIXME Implement deleteExtraObjects\r
+               } catch (DatabaseException e) {\r
+                       throw new MappingException(e);\r
+               }\r
+               \r
+       }\r
+       \r
+       private Resource getServiceResource(ReadGraph g, StructuralResource element) {\r
+               if (!useTypeResource)\r
+                       return element.getResource();\r
+               return element.getTypeResource();\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/rules/domain/RelatedValueAccessor.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/rules/domain/RelatedValueAccessor.java
new file mode 100644 (file)
index 0000000..0c152c1
--- /dev/null
@@ -0,0 +1,150 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.structural.rules.domain;\r
+\r
+import java.util.Arrays;\r
+\r
+import org.apache.log4j.Logger;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.Statement;\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.layer0.Layer0;\r
+import org.simantics.objmap.exceptions.MappingException;\r
+import org.simantics.objmap.graph.rules.domain.IDomainAccessor;\r
+import org.simantics.objmap.structural.StructuralResource;\r
+\r
+\r
+public class RelatedValueAccessor implements IDomainAccessor<StructuralResource,Object> {\r
+\r
+    static Logger LOGGER = Logger.getLogger("org.simantics.objmap");\r
+    \r
+       Resource relation;\r
+       Resource valueType;\r
+       boolean useTypeResource;\r
+       \r
+       private boolean preventStructuralChanges = true;\r
+       private boolean preventStructuralRootChanges = true;\r
+       \r
+       public RelatedValueAccessor(Resource relation, Resource valueType, boolean useTypeResource) {\r
+               this.relation = relation;\r
+               this.valueType = valueType;\r
+               this.useTypeResource = useTypeResource;\r
+       }\r
+       \r
+       public RelatedValueAccessor(Resource relation, Resource valueType, boolean useTypeResource, boolean preventStructuralChanges, boolean preventStructuralRootChanges) {\r
+               this.relation = relation;\r
+               this.valueType = valueType;\r
+               this.useTypeResource = useTypeResource;\r
+               this.preventStructuralChanges = preventStructuralChanges;\r
+               this.preventStructuralRootChanges = preventStructuralRootChanges;\r
+       }\r
+       \r
+       private boolean preventChange(StructuralResource element) {\r
+       return preventStructuralChanges && element.isStructural() && (!element.isStructuralRoot()||preventStructuralRootChanges);       \r
+    }\r
+\r
+       @Override\r
+       public Object get(ReadGraph g, StructuralResource element) throws MappingException {\r
+               try {\r
+                   LOGGER.info("        RelatedValueAccessor.get");\r
+                   Resource res = getServiceResource(g, element);\r
+                   if (res == null)\r
+                       return null;\r
+                       Resource valueResource = g.getPossibleObject(res, relation);\r
+                       if(valueResource == null)\r
+                               return null;\r
+                       return g.getValue(valueResource);\r
+               } catch (DatabaseException e) {\r
+                       throw new MappingException(e);\r
+               }\r
+       }\r
+       \r
+       @Override\r
+       public boolean set(WriteGraph g, StructuralResource relement, Object value)\r
+                       throws MappingException {\r
+               try {\r
+                   LOGGER.info("        RelatedValueAccessor.set");\r
+                   \r
+                   Resource element = getServiceResource(g, relement);\r
+                   if (element == null)\r
+                       return false;\r
+                   Statement valueStatement = g.getPossibleStatement(element, relation);\r
+                       if(valueStatement == null) {\r
+                               if(value == null)\r
+                                       return false;\r
+                               if (preventChange(relement))\r
+                                       return false;\r
+                               Resource valueResource = g.newResource();\r
+                               g.claim(valueResource, Layer0.getInstance(g).InstanceOf, null,\r
+                                               valueType);\r
+                               g.claim(element, relation, valueResource);\r
+                               g.claimValue(valueResource, value);                             \r
+                               return true;\r
+                       }\r
+                       else {\r
+                               if(value == null) {\r
+                                       if (preventChange(relement))\r
+                                               return false;\r
+                                       if (!valueStatement.isAsserted(element)) {\r
+                                               g.deny(valueStatement.getObject());\r
+                                               return true;\r
+                                       } else {\r
+                                               return false;\r
+                                       }\r
+                                       \r
+                               }                               \r
+                               Object currentValue = g.getValue(valueStatement.getObject());\r
+                               if(equals(currentValue,value))\r
+                                       return false;\r
+                               if (preventChange(relement))\r
+                                       return false;\r
+                               if (!valueStatement.isAsserted(element))\r
+                                       g.claimValue(valueStatement.getObject(), value);\r
+                               else {\r
+                                       Resource valueResource = g.newResource();\r
+                                       g.claim(valueResource, Layer0.getInstance(g).InstanceOf, null,\r
+                                                       valueType);\r
+                                       g.claim(element, relation, valueResource);\r
+                                       g.claimValue(valueResource, value);\r
+                               }\r
+                               return true;\r
+                       }\r
+               } catch (DatabaseException e) {\r
+                       throw new MappingException(e);\r
+               }\r
+               \r
+       }\r
+       \r
+       private Resource getServiceResource(ReadGraph g, StructuralResource element) {\r
+               if (!useTypeResource)\r
+                       return element.getResource();\r
+               return element.getTypeResource();\r
+       }\r
+       \r
+       private boolean equals(Object o1, Object o2) {\r
+               if (o1 instanceof boolean[])\r
+                       Arrays.equals((boolean[])o1,(boolean[])o2);\r
+               if (o1 instanceof int[])\r
+                       Arrays.equals((int[])o1,(int[])o2);\r
+               if (o1 instanceof float[])\r
+                       Arrays.equals((float[])o1,(float[])o2);\r
+               if (o1 instanceof double[])\r
+                       Arrays.equals((double[])o1,(double[])o2);\r
+               if (o1 instanceof byte[])\r
+                       Arrays.equals((byte[])o1,(byte[])o2);\r
+               return o1.equals(o2);\r
+               \r
+       }\r
+\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/rules/domain/StructuralRelatedObjectAccessor.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/rules/domain/StructuralRelatedObjectAccessor.java
new file mode 100644 (file)
index 0000000..5148360
--- /dev/null
@@ -0,0 +1,131 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.structural.rules.domain;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import org.apache.log4j.Logger;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.objmap.exceptions.MappingException;\r
+import org.simantics.objmap.graph.rules.domain.IDomainAccessor;\r
+import org.simantics.objmap.structural.StructuralResource;\r
+\r
+\r
+public class StructuralRelatedObjectAccessor implements IDomainAccessor<StructuralResource,StructuralResource> {\r
+\r
+    static Logger LOGGER = Logger.getLogger("org.simantics.objmap");\r
+    \r
+       Resource relation;\r
+       boolean useTypeResource;\r
+       \r
+       private boolean preventStructuralChanges = true;\r
+       private boolean preventStructuralRootChanges = true;\r
+       \r
+       public StructuralRelatedObjectAccessor(Resource relation, boolean useTypeResource) {\r
+               this.relation = relation;\r
+               this.useTypeResource = useTypeResource;\r
+       }\r
+       \r
+       public StructuralRelatedObjectAccessor(Resource relation, boolean useTypeResource, boolean preventStructuralChanges, boolean preventStructuralRootChanges) {\r
+               this.relation = relation;\r
+               this.useTypeResource = useTypeResource;\r
+               this.preventStructuralChanges = preventStructuralChanges;\r
+               this.preventStructuralRootChanges = preventStructuralRootChanges;\r
+       }\r
+       \r
+ private boolean preventChange(StructuralResource element) {\r
+       return preventStructuralChanges && element.isStructural() && (!element.isStructuralRoot()||preventStructuralRootChanges);       \r
+    }\r
+\r
+       @Override\r
+       public StructuralResource get(ReadGraph g, StructuralResource element) throws MappingException {\r
+               try {\r
+                       \r
+                       LOGGER.info("        RelatedObjectAccessor.get");\r
+                       \r
+                       if (!element.isStructural())\r
+                               return null;\r
+                       Resource instance = StructuralUtils.getContainingInstance(element);\r
+                           \r
+                       Resource publicRelation = StructuralUtils.getPublishedRelation(g, element, relation);\r
+\r
+                    if (publicRelation == null)\r
+                       return null;\r
+                       Resource r =  g.getPossibleObject(instance, publicRelation);\r
+                       if (r == null)\r
+                               return null;\r
+                       List<Resource> context = new ArrayList<Resource>();\r
+                       for (int i = 0; i < element.getContext().size()-1; i++)\r
+                               context.add(element.getContext().get(i));\r
+                       if (StructuralUtils.isStructuralInstance(g, r)) {\r
+                               return new StructuralResource(g, r, context,r);\r
+                       } else {\r
+                               return new StructuralResource(g, r, context);\r
+                       }\r
+               } catch (DatabaseException e) {\r
+                       throw new MappingException(e);\r
+               }\r
+       }\r
+       \r
+       @Override\r
+       public boolean set(WriteGraph g, StructuralResource element, StructuralResource value)\r
+                       throws MappingException {\r
+               try {\r
+                   LOGGER.info("        RelatedObjectAccessor.set");\r
+                   Resource instance = StructuralUtils.getContainingInstance(element);\r
+                   Resource publicRelation = null;\r
+                   if (instance == null)\r
+                       return false;\r
+                   publicRelation = StructuralUtils.getPublishedRelation(g, element, relation);\r
+                   if (value == null) {\r
+                       if (publicRelation == null)\r
+                               return false;\r
+                       if (preventChange(element))\r
+                               return false;\r
+                       g.deny(instance, publicRelation);\r
+                       return true;\r
+                   } else {\r
+                       if (publicRelation == null) {\r
+                               if (preventChange(element))\r
+                                       return false;\r
+                               publicRelation = StructuralUtils.getOrCreatePublishedRelation(g, element, relation);\r
+                               g.claim(instance, publicRelation, value.getResource());\r
+                               return true;\r
+                       } else {\r
+                               Resource r = g.getPossibleObject(instance, publicRelation);\r
+                               if (r == null) {\r
+                                       if (preventChange(element))\r
+                                               return false;\r
+                                       g.claim(instance, publicRelation, value.getResource());\r
+                                       return true;\r
+                               } else {\r
+                                       if (r.equals(value.getResource()))\r
+                                               return false;\r
+                                       if (preventChange(element))\r
+                                               return false;\r
+                                       g.deny(instance, publicRelation);\r
+                                       g.claim(instance, publicRelation, value.getResource());\r
+                                       return true;\r
+                               }\r
+                       }\r
+                   }\r
+               } catch (DatabaseException e) {\r
+                       throw new MappingException(e);\r
+               }\r
+               \r
+       }\r
+\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/rules/domain/StructuralRelatedObjectsAccessor.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/rules/domain/StructuralRelatedObjectsAccessor.java
new file mode 100644 (file)
index 0000000..5b32a98
--- /dev/null
@@ -0,0 +1,118 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.structural.rules.domain;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.Collections;\r
+import java.util.List;\r
+\r
+import org.apache.log4j.Logger;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.layer0.Layer0;\r
+import org.simantics.objmap.exceptions.MappingException;\r
+import org.simantics.objmap.graph.rules.domain.IDomainAccessor;\r
+import org.simantics.objmap.graph.rules.domain.MappingUtils;\r
+import org.simantics.objmap.structural.StructuralResource;\r
+import org.simantics.structural.stubs.StructuralResource2;\r
+\r
+\r
+public class StructuralRelatedObjectsAccessor implements IDomainAccessor<StructuralResource,Collection<StructuralResource>> {\r
+\r
+    static Logger LOGGER = Logger.getLogger("org.simantics.objmap");\r
+    \r
+       Resource relation;\r
+       boolean deleteExtraObjects;\r
+\r
+       public StructuralRelatedObjectsAccessor(Resource relation, boolean deleteExtraObjects) {\r
+        super();\r
+        this.relation = relation;\r
+        this.deleteExtraObjects = deleteExtraObjects;\r
+    }\r
+\r
+    @Override\r
+       public Collection<StructuralResource> get(ReadGraph g, StructuralResource element) throws MappingException {\r
+               try {\r
+                   LOGGER.info("        RelatedObjectsAccessor.get");\r
+                       \r
+                   if (!element.isStructural())\r
+                       return Collections.EMPTY_LIST;\r
+                   \r
+                   // Structural instance\r
+                   Resource instance = StructuralUtils.getContainingInstance(element);\r
+                   \r
+                   Resource publicRelation = StructuralUtils.getPublishedRelation(g, element, relation);\r
+                   \r
+                   if (publicRelation == null)\r
+                     return Collections.EMPTY_LIST;\r
+                   \r
+                   Collection<Resource> coll = g.getObjects(instance, publicRelation);\r
+                       List<StructuralResource> result = new ArrayList<StructuralResource>(coll.size());\r
+                       List<Resource> context = new ArrayList<Resource>();\r
+                       for (int i = 0; i < element.getContext().size()-1; i++)\r
+                               context.add(element.getContext().get(i));\r
+                       for (Resource r : coll) {\r
+                               if (StructuralUtils.isStructuralInstance(g, r)) {\r
+                                       result.add(new StructuralResource(g, r, context,r));\r
+                               } else {\r
+                                       result.add(new StructuralResource(g, r, context));\r
+                               }\r
+                       }\r
+                       return result;\r
+               } catch (DatabaseException e) {\r
+                       throw new MappingException(e);\r
+               }\r
+       }\r
+       \r
+       @Override\r
+       public boolean set(WriteGraph g, StructuralResource element, Collection<StructuralResource> value)\r
+                       throws MappingException {\r
+               try {\r
+                   LOGGER.info("        RelatedObjectsAccessor.set");\r
+                   \r
+                   if (!element.isStructural())\r
+                       return false;\r
+                   \r
+                   Resource instance = StructuralUtils.getContainingInstance(element);\r
+                   Resource publicRelation = null;\r
+                   if (value.size() == 0) {\r
+                       publicRelation = StructuralUtils.getPublishedRelation(g, element, relation);\r
+                       if (publicRelation == null)\r
+                               return false;\r
+                       else {\r
+                               return MappingUtils.synchronizeStatements(g, instance, publicRelation, new Resource[0], deleteExtraObjects);\r
+                       }\r
+                   } else {\r
+                       publicRelation = StructuralUtils.getOrCreatePublishedRelation(g, element, relation);\r
+                       if (publicRelation == null)\r
+                               throw new MappingException("Structural Resource " + element + " cannot contain structural elements, the Resource is not published.");\r
+                           Resource[] arr = new Resource[value.size()];\r
+                           int i = 0; \r
+                           for (StructuralResource sr : value) {\r
+                               arr[i++] = sr.getResource();\r
+                           }\r
+                           return MappingUtils.synchronizeStatements(g, instance, publicRelation, arr, deleteExtraObjects);\r
+                   }\r
+                   \r
+                   \r
+                       \r
+               } catch (DatabaseException e) {\r
+                       throw new MappingException(e);\r
+               }\r
+               \r
+       }\r
+\r
+       \r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/rules/domain/StructuralUtils.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/rules/domain/StructuralUtils.java
new file mode 100644 (file)
index 0000000..c4ba704
--- /dev/null
@@ -0,0 +1,105 @@
+package org.simantics.objmap.structural.rules.domain;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.exception.NoSingleResultException;\r
+import org.simantics.layer0.Layer0;\r
+import org.simantics.objmap.structural.StructuralResource;\r
+import org.simantics.structural.stubs.StructuralResource2;\r
+\r
+public class StructuralUtils {\r
+\r
+       \r
+       public static boolean isStructuralInstance(ReadGraph g, Resource r) throws DatabaseException {\r
+               StructuralResource2 sr = StructuralResource2.getInstance(g);\r
+                if (g.isInstanceOf(r, sr.Component)) {\r
+                        Resource type = g.getSingleType(r);\r
+                        return g.isInstanceOf(type, sr.Component);\r
+                }\r
+                return false;\r
+               \r
+       }\r
+       \r
+       public static Resource getContainingInstance(StructuralResource element) {\r
+               if (!element.isStructural())\r
+                       return null;\r
+               Resource instance = element.getContext().get(element.getContext().size()-1);\r
+               return instance;\r
+       }\r
+       \r
+       public static Resource getPublishedRelation(ReadGraph g, StructuralResource element, Resource relation) throws DatabaseException{\r
+               Resource instance = getContainingInstance(element);\r
+               if (instance == null)\r
+                       return null;\r
+               \r
+               Layer0 l0 = Layer0.getInstance(g);\r
+               StructuralResource2 sr = StructuralResource2.getInstance(g);\r
+               \r
+           Resource type = null;\r
+           try {\r
+               type = g.getSingleType(instance);\r
+           } catch (NoSingleResultException e) {\r
+               \r
+           }\r
+           if (type == null)\r
+               return null;\r
+           \r
+           boolean elementPublished = false;\r
+           Resource publicRelation = null;\r
+           for (Resource r : g.getObjects(type, l0.DomainOf)) {\r
+               if (r.equals(element.getResource()))\r
+                       elementPublished = true;\r
+               if (g.isInstanceOf(r, relation)) {\r
+                       if (element.getResource().equals(g.getPossibleObject(r, sr.IsBoundBy)))\r
+                               publicRelation = r;\r
+               }\r
+           }\r
+           if (!elementPublished)\r
+               return null;\r
+           return publicRelation;\r
+       }\r
+       \r
+       public static Resource getOrCreatePublishedRelation(WriteGraph g, StructuralResource element, Resource relation) throws DatabaseException{\r
+               Resource instance = getContainingInstance(element);\r
+               if (instance == null)\r
+                       return null;\r
+               \r
+               Layer0 l0 = Layer0.getInstance(g);\r
+               StructuralResource2 sr = StructuralResource2.getInstance(g);\r
+               \r
+           Resource type = g.getSingleType(instance);\r
+           \r
+           boolean elementPublished = false;\r
+           Resource publicRelation = null;\r
+           for (Resource r : g.getObjects(type, l0.DomainOf)) {\r
+               if (r.equals(element.getResource()))\r
+                       elementPublished = true;\r
+               if (g.isInstanceOf(r, relation)) {\r
+                       if (element.getResource().equals(g.getPossibleObject(r, sr.IsBoundBy)))\r
+                               publicRelation = r;\r
+               }\r
+           }\r
+           if (!elementPublished)\r
+               return null;\r
+           if (publicRelation != null)\r
+               return publicRelation;\r
+           \r
+           publicRelation = g.newResource();\r
+           // TODO: type ConsistsOf publicRelation, publicRelation ConsistsOf publicInverse ?\r
+           g.claim(publicRelation, l0.SubrelationOf, l0.IsRelatedTo);\r
+           g.claim(publicRelation, l0.InstanceOf, relation);\r
+           g.claim(publicRelation, sr.IsBoundBy, element.getResource());\r
+           g.claim(type, l0.DomainOf, publicRelation);\r
+           g.claimLiteral(publicRelation, l0.HasName, g.getRelatedValue(element.getResource(), l0.HasName) +"_" + g.getRelatedValue(relation, l0.HasName)); \r
+           Resource inverse = g.getPossibleInverse(relation);\r
+           if (inverse != null) {\r
+               Resource publicInverse = g.newResource();\r
+               g.claim(publicInverse, l0.SubrelationOf, inverse);\r
+               g.claim(publicRelation, l0.InverseOf, publicInverse);\r
+           }\r
+           return publicRelation;\r
+           \r
+       }\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/schema/AdaptedLinkType.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/schema/AdaptedLinkType.java
new file mode 100644 (file)
index 0000000..9981a73
--- /dev/null
@@ -0,0 +1,79 @@
+package org.simantics.objmap.structural.schema;\r
+\r
+//import org.apache.log4j.Logger;\r
+import org.eclipse.core.runtime.IAdaptable;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.objmap.backward.IBackwardMapping;\r
+import org.simantics.objmap.exceptions.MappingException;\r
+import org.simantics.objmap.forward.IForwardMapping;\r
+import org.simantics.objmap.graph.schema.ILinkType;\r
+import org.simantics.objmap.structural.IStructuralObject;\r
+import org.simantics.objmap.structural.StructuralResource;\r
+\r
+/**\r
+ * A link type that is associated with adaptable resource (ReadGraph.getAdapter(Resource,Class)). \r
+ * The adapted object must implement IAdaptable interface for returning the original Resource. \r
+ * \r
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>\r
+ *\r
+ */\r
+public class AdaptedLinkType implements ILinkType<StructuralResource,IStructuralObject> {\r
+\r
+       \r
+       //static Logger LOGGER = Logger.getLogger("org.simantics.objmap");\r
+    \r
+    Resource domainType;\r
+    Class<?> rangeType;\r
+    \r
+    \r
+    public AdaptedLinkType(Resource domainType, Class<?> rangeType) {\r
+        this.domainType = domainType;\r
+        this.rangeType = rangeType;\r
+    }\r
+    \r
+    @Override\r
+    public StructuralResource createDomainElement(WriteGraph g, IStructuralObject rangeElement)\r
+               throws MappingException {\r
+       try {\r
+               IAdaptable adaptable = (IAdaptable)rangeElement;\r
+               Resource res = (Resource)adaptable.getAdapter(Resource.class);\r
+               if (res == null)\r
+                       throw new NullPointerException();\r
+               return new StructuralResource(g,res);\r
+       } catch (Exception e) {\r
+               throw new MappingException("Adapted object must implement IAdaptable interface to return the source Resource.", e);\r
+       }\r
+       \r
+    }\r
+\r
+    \r
+    @Override\r
+    public IStructuralObject createRangeElement(ReadGraph g, StructuralResource domainElement)\r
+               throws MappingException {\r
+       try {\r
+               // FIXME : this will not work, we cannot assume that adapted objects would implement IStructuralObject interface.\r
+               return (IStructuralObject)g.adapt(domainElement.getResource(), rangeType);\r
+       } catch (DatabaseException e) {\r
+               throw new MappingException(e);\r
+       }\r
+    }\r
+    \r
+    public void createDomain(WriteGraph graph, IBackwardMapping<StructuralResource, IStructuralObject> mapping, StructuralResource domainElement, IStructuralObject rangeElement) throws MappingException {\r
+       \r
+    };\r
+    \r
+    public void createRange(ReadGraph graph, org.simantics.objmap.forward.IForwardMapping<StructuralResource, IStructuralObject> mapping, StructuralResource domainElement, IStructuralObject rangeElement) throws MappingException {\r
+       \r
+    };\r
+    \r
+    public boolean updateDomain(WriteGraph g, IBackwardMapping<StructuralResource, IStructuralObject> map, StructuralResource domainElement, IStructuralObject rangeElement) throws MappingException {\r
+       return false;\r
+    }\r
+    \r
+    public boolean updateRange(ReadGraph g, IForwardMapping<StructuralResource, IStructuralObject> map, StructuralResource domainElement, IStructuralObject rangeElement) throws MappingException {\r
+       return false;\r
+    }\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/schema/DefaultSchema.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/schema/DefaultSchema.java
new file mode 100644 (file)
index 0000000..d0fa805
--- /dev/null
@@ -0,0 +1,123 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.structural.schema;\r
+\r
+\r
+\r
+import java.util.Stack;\r
+\r
+import gnu.trove.map.hash.THashMap;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.common.utils.NameUtils;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.objmap.exceptions.MappingException;\r
+import org.simantics.objmap.graph.schema.ILinkType;\r
+import org.simantics.objmap.graph.schema.IMappingSchema;\r
+import org.simantics.objmap.structural.IStructuralObject;\r
+import org.simantics.objmap.structural.StructuralResource;\r
+\r
+\r
+/**\r
+ * \r
+ */\r
+public class DefaultSchema implements IMappingSchema<StructuralResource, IStructuralObject> {\r
+\r
+    THashMap<Resource, ILinkType<StructuralResource, IStructuralObject>> domainLinkTypes = \r
+        new THashMap<Resource, ILinkType<StructuralResource, IStructuralObject>>();\r
+    THashMap<Class<?>, ILinkType<StructuralResource, IStructuralObject>> rangeLinkTypes = \r
+        new THashMap<Class<?>, ILinkType<StructuralResource, IStructuralObject>>();\r
+    \r
+    public void addLinkType(SimpleLinkType linkType) {\r
+        domainLinkTypes.put(linkType.domainType, linkType);\r
+        rangeLinkTypes.put(linkType.rangeType, linkType);\r
+    }\r
+    \r
+    public void addLinkType(AdaptedLinkType linkType) {\r
+        domainLinkTypes.put(linkType.domainType, linkType);\r
+        rangeLinkTypes.put(linkType.rangeType, linkType);\r
+    }\r
+    \r
+    @Override\r
+    public ILinkType<StructuralResource, IStructuralObject> linkTypeOfDomainElement(ReadGraph g, StructuralResource element) throws MappingException {        \r
+        try {\r
+               \r
+               for(Resource type : g.getTypes(element.getResource())) {\r
+\r
+                       ILinkType<StructuralResource, IStructuralObject> linkType = domainLinkTypes.get(type);\r
+                       if(linkType != null) return linkType;\r
+                       \r
+               }\r
+               \r
+               throw new MappingException("Didn't find a link type for " +\r
+                               NameUtils.getSafeName(g, element.getResource()) + ".");\r
+                               \r
+        } catch (DatabaseException e) {\r
+            throw new MappingException(e);\r
+        }\r
+    }\r
+\r
+    @Override\r
+    public ILinkType<StructuralResource, IStructuralObject> linkTypeOfRangeElement(IStructuralObject element) throws MappingException {\r
+       ILinkType<StructuralResource, IStructuralObject> type = rangeLinkTypes.get(element.getClass());\r
+               if(type == null)  {\r
+                       Stack<Class<?>> clazzes = new Stack<Class<?>>();\r
+               for (Class<?> clazz : element.getClass().getInterfaces()) {\r
+                       clazzes.add(clazz);\r
+               }\r
+               clazzes.add(element.getClass().getSuperclass());\r
+               \r
+                       while (!clazzes.isEmpty()) {\r
+                               Class<?> clazz = clazzes.pop();\r
+                       \r
+                               type = rangeLinkTypes.get(clazz);\r
+                               if (type != null)\r
+                                       return type;\r
+                               for (Class<?> c : clazz.getInterfaces())\r
+                                       clazzes.add(c);\r
+                               \r
+                       }\r
+                       throw new MappingException("Didn't find a link type for " +     element + ".");\r
+               }\r
+               return type;\r
+    }\r
+\r
+    \r
+    public ILinkType<StructuralResource, IStructuralObject> linkTypeOfDomainType(ReadGraph g, Resource type)  {        \r
+       return domainLinkTypes.get(type);\r
+    }\r
+    \r
+    public ILinkType<StructuralResource, IStructuralObject> linkTypeOfRangeType(Class<?> clazz) {\r
+       ILinkType<StructuralResource, IStructuralObject> type = rangeLinkTypes.get(clazz);\r
+       if(type == null)  {\r
+               Stack<Class<?>> clazzes = new Stack<Class<?>>();\r
+               for (Class<?> c : clazz.getInterfaces()) {\r
+                       clazzes.add(c);\r
+               }\r
+               clazzes.add(clazz.getSuperclass());\r
+               \r
+               while (!clazzes.isEmpty()) {\r
+                               Class<?> c = clazzes.pop();\r
+                       \r
+                               type = rangeLinkTypes.get(c);\r
+                               if (type != null)\r
+                                       return type;\r
+                               for (Class<?> c2 : c.getInterfaces())\r
+                                       clazzes.add(c2);\r
+                               \r
+                       }\r
+               \r
+               }\r
+       return null;\r
+    }\r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/schema/MappingSchemas.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/schema/MappingSchemas.java
new file mode 100644 (file)
index 0000000..c656368
--- /dev/null
@@ -0,0 +1,247 @@
+package org.simantics.objmap.structural.schema;\r
+\r
+import java.lang.annotation.Annotation;\r
+import java.lang.reflect.Field;\r
+import java.lang.reflect.Method;\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.objmap.bidirectional.IBidirectionalMappingRule;\r
+import org.simantics.objmap.graph.annotations.GraphType;\r
+import org.simantics.objmap.graph.annotations.HasCollectionAdder;\r
+import org.simantics.objmap.graph.annotations.HasCollectionRemover;\r
+import org.simantics.objmap.graph.annotations.HasSetter;\r
+import org.simantics.objmap.graph.annotations.OptionalRelatedElements;\r
+import org.simantics.objmap.graph.annotations.RelatedElements;\r
+import org.simantics.objmap.graph.annotations.RelatedElementsGet;\r
+import org.simantics.objmap.graph.annotations.RelatedGetObj;\r
+import org.simantics.objmap.graph.annotations.RelatedGetValue;\r
+import org.simantics.objmap.graph.annotations.RelatedOrderedSetElements;\r
+import org.simantics.objmap.graph.annotations.RelatedValue;\r
+import org.simantics.objmap.graph.annotations.UpdateMethod;\r
+import org.simantics.objmap.structural.annotations.StructuralRelatedElementsGet;\r
+import org.simantics.objmap.structural.annotations.StructuralRelatedGetObj;\r
+import org.simantics.objmap.structural.annotations.TypeRelatedElementsGet;\r
+import org.simantics.objmap.structural.annotations.TypeRelatedGetObj;\r
+import org.simantics.objmap.structural.annotations.TypeRelatedGetValue;\r
+import org.simantics.objmap.structural.annotations.factories.OptionalRelatedElementsRuleFactory;\r
+import org.simantics.objmap.structural.annotations.factories.RelatedElementsRuleFactory;\r
+import org.simantics.objmap.structural.annotations.factories.RelatedElementsRuleFactory2;\r
+import org.simantics.objmap.structural.annotations.factories.RelatedGetSetObjRuleFactory;\r
+import org.simantics.objmap.structural.annotations.factories.RelatedGetSetValueRuleFactory;\r
+import org.simantics.objmap.structural.annotations.factories.RelatedOrderedSetElementsRuleFactory;\r
+import org.simantics.objmap.structural.annotations.factories.RelatedValueRuleFactory;\r
+import org.simantics.objmap.structural.annotations.factories.StructuralRelatedElementsRuleFactory2;\r
+import org.simantics.objmap.structural.annotations.factories.StructuralRelatedGetSetObjRuleFactory;\r
+import org.simantics.objmap.structural.annotations.factories.TypeRelatedElementsRuleFactory2;\r
+import org.simantics.objmap.structural.annotations.factories.TypeRelatedGetSetObjRuleFactory;\r
+import org.simantics.objmap.structural.annotations.factories.TypeRelatedGetSetValueRuleFactory;\r
+import org.simantics.objmap.structural.annotations.factories.UpdateMethodFactory;\r
+import org.simantics.objmap.graph.annotations.meta.IsClassRule;\r
+import org.simantics.objmap.graph.annotations.meta.IsCollectionRule;\r
+import org.simantics.objmap.graph.annotations.meta.IsFieldRule;\r
+import org.simantics.objmap.graph.annotations.meta.IsGetSetRule;\r
+import org.simantics.objmap.graph.annotations.meta.IsMethodRule;\r
+import org.simantics.objmap.graph.rules.factory.IClassRuleFactory;\r
+import org.simantics.objmap.graph.rules.factory.ICollectionRuleFactory;\r
+import org.simantics.objmap.graph.rules.factory.IFieldRuleFactory;\r
+import org.simantics.objmap.graph.rules.factory.IGetSetRuleFactory;\r
+import org.simantics.objmap.graph.rules.factory.IMethodRuleFactory;\r
+import org.simantics.objmap.structural.IStructuralObject;\r
+import org.simantics.objmap.structural.StructuralResource;\r
+\r
+\r
+public class MappingSchemas {\r
+       /**\r
+     * Creates a new SimpleLinkType based on the annotations in the given class.\r
+     * @throws IllegalAccessException \r
+     * @throws InstantiationException \r
+     * @see GraphType\r
+     * @see RelatedValue\r
+     */\r
+       public static SimpleLinkType fromAnnotations(ReadGraph g, Class<?> clazz) throws DatabaseException, InstantiationException, IllegalAccessException {\r
+           GraphType graphType = clazz.getAnnotation(GraphType.class);\r
+           \r
+           ArrayList<IBidirectionalMappingRule<StructuralResource, IStructuralObject>> rules = new ArrayList<IBidirectionalMappingRule<StructuralResource, IStructuralObject>>();\r
+           collectRulesFromAnnotations(g, clazz, rules);\r
+           \r
+           return new SimpleLinkType(\r
+                   g.getResource(graphType.value()), \r
+                clazz, rules);    \r
+       }\r
+       \r
+       public static void collectRulesFromAnnotations(ReadGraph g, Class<?> clazz, Collection<IBidirectionalMappingRule<StructuralResource, IStructuralObject>> rules) throws DatabaseException, InstantiationException, IllegalAccessException {\r
+                 Class<?> superclass = clazz.getSuperclass();\r
+                   if(superclass != null)\r
+                       collectRulesFromAnnotations(g, superclass, rules);\r
+                       \r
+               for(Annotation annotation : clazz.getAnnotations()) {\r
+\r
+                       IsClassRule tag = annotation.annotationType().getAnnotation(IsClassRule.class);\r
+                   if(tag!= null) {\r
+                       rules.add(createClassRule(g, annotation, clazz).create(g, annotation, clazz));\r
+                   }\r
+               }\r
+\r
+               for(Field f : clazz.getDeclaredFields()) {\r
+                   f.setAccessible(true);\r
+\r
+                   for(Annotation annotation : f.getAnnotations()) {\r
+\r
+                       IsFieldRule tag = annotation.annotationType().getAnnotation(IsFieldRule.class);\r
+                       if(tag != null) {\r
+                           rules.add(createFieldRule(g, annotation, f).create(g, annotation, f));\r
+                       }\r
+                   }\r
+               }\r
+\r
+               for(Method m : clazz.getDeclaredMethods()) {\r
+                   m.setAccessible(true);\r
+\r
+                   for(Annotation annotation : m.getAnnotations()) {\r
+                       IsMethodRule tag = \r
+                               annotation.annotationType().getAnnotation(IsMethodRule.class);\r
+                       if(tag != null) {\r
+                               rules.add(createMethodRule(g, annotation, m).create(g, annotation, m));\r
+                       }\r
+                   }\r
+               }\r
+               \r
+               for (Method m : clazz.getDeclaredMethods()) {\r
+                       m.setAccessible(true);\r
+                       for (Annotation annotation : m.getAnnotations()) {\r
+                               Class<? extends Annotation> annotationType = annotation.annotationType();\r
+\r
+                                IsGetSetRule tag = \r
+                                annotationType.getAnnotation(IsGetSetRule.class);\r
+                                if (tag != null) {\r
+                                        \r
+                                        HasSetter setterAnnType = annotationType.getAnnotation(HasSetter.class);\r
+                                        \r
+                                        Class<? extends Annotation> setterAnn = setterAnnType.value();\r
+                                        \r
+                                        Method getter = m;\r
+                                        \r
+                                        IGetSetRuleFactory<StructuralResource, IStructuralObject> ruleFactory = createGetSetRuleFactory(g, annotation, getter);\r
+                                        \r
+                                        \r
+                                        Method setter = null;\r
+                                        \r
+                                        for (Method m2 : clazz.getDeclaredMethods()) {\r
+                                                Annotation set = m2.getAnnotation(setterAnn);\r
+                                                if (set != null && ruleFactory.isSetter(annotation, set))\r
+                                                        setter = m2;\r
+                                        }\r
+\r
+                                        rules.add(ruleFactory.create(g, annotation, getter, setter));\r
+                                }\r
+                       \r
+                       }\r
+               }\r
+               \r
+               for (Method m : clazz.getDeclaredMethods()) {\r
+                       m.setAccessible(true);\r
+                       for (Annotation annotation : m.getAnnotations()) {\r
+                               Class<? extends Annotation> annotationType = annotation.annotationType();\r
+\r
+                                IsCollectionRule tag = \r
+                                annotationType.getAnnotation(IsCollectionRule.class);\r
+                                if (tag != null) {\r
+                                        \r
+                                        HasCollectionAdder adderAnnType = annotationType.getAnnotation(HasCollectionAdder.class);\r
+                                        HasCollectionRemover removerAnnType = annotationType.getAnnotation(HasCollectionRemover.class);\r
+                       \r
+                                        Class<? extends Annotation> adderAnn = adderAnnType.value();\r
+                                        Class<? extends Annotation> removerAnn = removerAnnType.value();\r
+                                        \r
+                                        Method getter = m;\r
+                                        \r
+                                        ICollectionRuleFactory<StructuralResource, IStructuralObject> ruleFactory = createCollectionRuleFactory(g, annotation, getter);\r
+                                        \r
+                                        \r
+                                        Method adder = null;\r
+                                        Method remover = null;\r
+                                        \r
+                                        for (Method m2 : clazz.getDeclaredMethods()) {\r
+                                                Annotation add = m2.getAnnotation(adderAnn);\r
+                                                Annotation rem = m2.getAnnotation(removerAnn);\r
+                                                if (add != null && ruleFactory.isAdder(annotation, add))\r
+                                                        adder = m2;\r
+                                                if (rem != null && ruleFactory.isRemover(annotation, rem))\r
+                                                        remover = m2;\r
+                                        }\r
+                                        \r
+                                        \r
+                                        \r
+                                        rules.add(ruleFactory.create(g, annotation, getter,adder,remover));\r
+                                }\r
+                       \r
+                       }\r
+               }\r
+           }\r
+               \r
+               public static IClassRuleFactory<StructuralResource, IStructuralObject> createClassRule(ReadGraph g, Annotation annotation, Class<?> clazz) {\r
+                       return null;\r
+               }\r
+               \r
+               public static IFieldRuleFactory<StructuralResource, IStructuralObject> createFieldRule(ReadGraph g, Annotation annotation, Field field) {\r
+                       if (annotation.annotationType().equals(RelatedElements.class))\r
+                               return new RelatedElementsRuleFactory<IStructuralObject>();\r
+                       if (annotation.annotationType().equals(RelatedValue.class))\r
+                               return new RelatedValueRuleFactory<IStructuralObject>();\r
+                       if (annotation.annotationType().equals(OptionalRelatedElements.class))\r
+                               return new OptionalRelatedElementsRuleFactory<IStructuralObject>();\r
+                       if (annotation.annotationType().equals(RelatedOrderedSetElements.class))\r
+                               return new RelatedOrderedSetElementsRuleFactory<IStructuralObject>();\r
+                       return null;\r
+               }\r
+               \r
+               public static IMethodRuleFactory<StructuralResource, IStructuralObject> createMethodRule(ReadGraph g, Annotation annotation, Method m) {\r
+                       if (annotation.annotationType().equals(UpdateMethod.class))\r
+                               return new UpdateMethodFactory<StructuralResource,IStructuralObject>();\r
+                       return null;\r
+               }\r
+               \r
+               public static IGetSetRuleFactory<StructuralResource, IStructuralObject> createGetSetRuleFactory(ReadGraph g, Annotation annotation, Method getter) {\r
+                       if (annotation.annotationType().equals(RelatedGetValue.class))\r
+                               return new RelatedGetSetValueRuleFactory<IStructuralObject>();\r
+                       if (annotation.annotationType().equals(RelatedGetObj.class))\r
+                               return new RelatedGetSetObjRuleFactory<IStructuralObject>();\r
+                       if (annotation.annotationType().equals(TypeRelatedGetValue.class))\r
+                               return new TypeRelatedGetSetValueRuleFactory<IStructuralObject>();\r
+                       if (annotation.annotationType().equals(TypeRelatedGetObj.class))\r
+                               return new TypeRelatedGetSetObjRuleFactory<IStructuralObject>();\r
+                       if (annotation.annotationType().equals(StructuralRelatedGetObj.class))\r
+                               return new StructuralRelatedGetSetObjRuleFactory<IStructuralObject>();\r
+                       return null;\r
+               }\r
+               \r
+               public static ICollectionRuleFactory<StructuralResource, IStructuralObject> createCollectionRuleFactory(ReadGraph g, Annotation annotation, Method getter) {\r
+                       if (annotation.annotationType().equals(RelatedElementsGet.class))\r
+                               return new RelatedElementsRuleFactory2<IStructuralObject>();\r
+                       if (annotation.annotationType().equals(TypeRelatedElementsGet.class))\r
+                               return new TypeRelatedElementsRuleFactory2<IStructuralObject>();\r
+                       if (annotation.annotationType().equals(StructuralRelatedElementsGet.class))\r
+                               return new StructuralRelatedElementsRuleFactory2<IStructuralObject>();\r
+                       return null;\r
+               }\r
+       \r
+       \r
+       /**\r
+     * Creates a new SimpleLinkType based on the annotations in the given class.\r
+     * @throws IllegalAccessException \r
+     * @throws InstantiationException \r
+     * @see GraphType\r
+     * @see RelatedValue\r
+     */\r
+       public static AdaptedLinkType fromAdaptable(ReadGraph g, String type, Class<?> clazz) throws DatabaseException, InstantiationException, IllegalAccessException {\r
+           \r
+           \r
+           return new AdaptedLinkType(g.getResource(type), clazz);    \r
+       }\r
+       \r
+       \r
+}\r
diff --git a/org.simantics.objmap2/src/org/simantics/objmap/structural/schema/SimpleLinkType.java b/org.simantics.objmap2/src/org/simantics/objmap/structural/schema/SimpleLinkType.java
new file mode 100644 (file)
index 0000000..01c0fe0
--- /dev/null
@@ -0,0 +1,186 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.objmap.structural.schema;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collections;\r
+import java.util.List;\r
+\r
+import org.apache.log4j.Logger;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.db.common.utils.NameUtils;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.layer0.Layer0;\r
+import org.simantics.objmap.backward.IBackwardMapping;\r
+import org.simantics.objmap.bidirectional.IBidirectionalMappingRule;\r
+import org.simantics.objmap.exceptions.MappingException;\r
+import org.simantics.objmap.forward.IForwardMapping;\r
+import org.simantics.objmap.graph.schema.ILinkType;\r
+import org.simantics.objmap.structural.IStructuralObject;\r
+import org.simantics.objmap.structural.StructuralResource;\r
+\r
+\r
+\r
+public class SimpleLinkType implements ILinkType<StructuralResource,IStructuralObject> {\r
+    \r
+    static Logger LOGGER = Logger.getLogger("org.simantics.objmap");\r
+    \r
+    public Resource domainType;\r
+    public Class<?> rangeType;\r
+    ArrayList<IBidirectionalMappingRule<StructuralResource,IStructuralObject>> rules;\r
+    \r
+    public SimpleLinkType(Resource domainType, Class<?> rangeType,\r
+            ArrayList<IBidirectionalMappingRule<StructuralResource,IStructuralObject>> rules) {\r
+        this.domainType = domainType;\r
+        this.rangeType = rangeType;\r
+        this.rules = rules;\r
+    }\r
+\r
+    public SimpleLinkType(Resource domainType, Class<?> rangeType) {\r
+        this(domainType, rangeType, new ArrayList<IBidirectionalMappingRule<StructuralResource,IStructuralObject>>());\r
+    }\r
+\r
+    /**\r
+     * Adds a new rule to this link type that is enforced\r
+     * during updates.\r
+     */\r
+    public void addRule(IBidirectionalMappingRule<StructuralResource,IStructuralObject> rule) {\r
+        rules.add(rule);\r
+    }\r
+    \r
+    @Override\r
+    public StructuralResource createDomainElement(WriteGraph g, IStructuralObject rangeElement)\r
+            throws MappingException {\r
+        try {\r
+            if(LOGGER.isInfoEnabled())\r
+                LOGGER.info("SimpleLinkType.createDomainElement " +\r
+                        rangeElement.toString()\r
+                );\r
+            if (rangeElement.getContext().size() == 0) {\r
+               // there is no context, this not a structural resource / object.\r
+               Resource result = g.newResource();\r
+               g.claim(result, Layer0.getInstance(g).InstanceOf, null, domainType);\r
+               return new StructuralResource(g,result);\r
+            } else {\r
+               if (rangeElement.getContext().size() == 1 && rangeElement.getContext().get(0).equals(rangeElement)) {\r
+                       // Structural object's context is itself, we are instantiating a new structural model.\r
+                       Resource type = rangeElement.getType();\r
+                       Resource result = g.newResource();\r
+                       g.claim(result, Layer0.getInstance(g).InstanceOf, null, type);\r
+                       return new StructuralResource(g,result,result);\r
+               } else {\r
+                       // Structural object's context is not itself, which means that the object is inside of a structural model.\r
+                       // At the moment we do not support modifying instantiated structural models.\r
+                       throw new MappingException("Cannot create a new StucturalObject " + rangeElement + " " + rangeElement.getClass());\r
+               }\r
+            }\r
+        } catch(DatabaseException e) {\r
+            throw new MappingException(e);\r
+        }\r
+    }\r
+    @Override\r
+    public IStructuralObject createRangeElement(ReadGraph g, StructuralResource domainElement)\r
+            throws MappingException {\r
+        try {\r
+            if(LOGGER.isInfoEnabled())\r
+                try { \r
+                    LOGGER.info("SimpleLinkType.createRangeElement " + NameUtils.getSafeName(g, domainElement.getResource()));\r
+                } catch(DatabaseException e) {\r
+                    throw new MappingException(e);\r
+                }\r
+            IStructuralObject result = (IStructuralObject)rangeType.newInstance();\r
+            if (domainElement.getContext().size() == 1) {\r
+               if (domainElement.getContext().get(0).equals(domainElement.getResource()))\r
+                       result.setContext(Collections.singletonList(result));\r
+               else {\r
+                       //result.setContext(result); \r
+               }\r
+            }\r
+            return result;\r
+        } catch (InstantiationException e) {\r
+            throw new MappingException(e);\r
+        } catch (IllegalAccessException e) {\r
+            throw new MappingException(e);\r
+        }\r
+    }\r
+    \r
+    @SuppressWarnings("unchecked")\r
+       public void createDomain(WriteGraph graph, IBackwardMapping<StructuralResource,IStructuralObject> mapping, StructuralResource domainElement, IStructuralObject rangeElement) throws MappingException {\r
+       if (domainElement.isStructuralRoot())\r
+               // FIXME: this is nasty, but when a structural model is instantiated by creating new IStructuralObject, its related objects must be read from the graph first, or otherwise the objects would be deleted from the graph.\r
+               //        as a side effect, if the new IStructuralObject has any properties set, those properties are set to null (because the graph does not contain those values).\r
+               // \r
+               updateRange(graph, (IForwardMapping<StructuralResource, IStructuralObject>)mapping, domainElement, rangeElement);\r
+       updateDomain(graph, mapping, domainElement, rangeElement);\r
+    };\r
+    \r
+    \r
+    @Override\r
+    public void createRange(ReadGraph graph, IForwardMapping<StructuralResource, IStructuralObject> mapping, StructuralResource domainElement, IStructuralObject rangeElement) throws MappingException {\r
+       if (rangeElement.getContext().size() == 0 && domainElement.getContext().size() > 0) {\r
+               List<IStructuralObject> ctx = new ArrayList<IStructuralObject>(domainElement.getContext().size());\r
+                       try {\r
+                               List<Resource> context = new ArrayList<Resource>();\r
+                               for (int i = 0; i <domainElement.getContext().size(); i++) {\r
+                                       context.add(domainElement.getContext().get(i));\r
+                                       IStructuralObject ctxObj = mapping.get(new StructuralResource(graph,context.get(context.size()-1),context));\r
+                                       if (ctxObj == null) throw new MappingException("Cannot resolve range context for domain element " + domainElement);\r
+                                       ctx.add(ctxObj);\r
+                               }\r
+                               //ctx = mapping.get(new StructuralResource(graph,context.get(context.size()-1),context));\r
+                       } catch (DatabaseException e) {\r
+                               throw new MappingException(e);\r
+                       }\r
+               if (ctx.size() == 0)\r
+                       throw new MappingException("Cannot find context for structural object, " + domainElement);\r
+               rangeElement.setContext(ctx);\r
+       }\r
+       updateRange(graph, mapping, domainElement, rangeElement);\r
+    }\r
+    \r
+    public boolean updateDomain(WriteGraph g, IBackwardMapping<StructuralResource,IStructuralObject> map, StructuralResource domainElement, IStructuralObject rangeElement) throws MappingException {\r
+        if(LOGGER.isInfoEnabled())\r
+            try { \r
+                LOGGER.info("SimpleLinkType.updateDomain " +\r
+                        NameUtils.getSafeName(g, domainElement.getResource()) + " " +\r
+                        rangeElement.toString()\r
+                        );\r
+            } catch(DatabaseException e) {\r
+                throw new MappingException(e);\r
+            }\r
+        \r
+        boolean updated = false;\r
+        for(IBidirectionalMappingRule<StructuralResource, IStructuralObject> rule : rules)\r
+               updated |= rule.updateDomain(g, map, domainElement, rangeElement);\r
+        return updated;\r
+    }\r
+    \r
+    public boolean updateRange(ReadGraph g, IForwardMapping<StructuralResource, IStructuralObject> map, StructuralResource domainElement, IStructuralObject rangeElement) throws MappingException {\r
+    \r
+        if(LOGGER.isInfoEnabled())\r
+            try { \r
+                LOGGER.info("SimpleLinkType.updateRange " +\r
+                               NameUtils.getSafeName(g, domainElement.getResource()) + " " +\r
+                        rangeElement.toString()\r
+                        );\r
+            } catch(DatabaseException e) {\r
+                throw new MappingException(e);\r
+            }\r
+        \r
+        boolean updated = false;\r
+        for(IBidirectionalMappingRule<StructuralResource, IStructuralObject> rule : rules)\r
+            updated |= rule.updateRange(g, map, domainElement, rangeElement);\r
+        return updated;\r
+    }\r
+}\r
diff --git a/org.simantics.opencascade.vtk/.classpath b/org.simantics.opencascade.vtk/.classpath
new file mode 100644 (file)
index 0000000..8a8f166
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<classpath>\r
+       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>\r
+       <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>\r
+       <classpathentry kind="src" path="src"/>\r
+       <classpathentry kind="output" path="bin"/>\r
+</classpath>\r
diff --git a/org.simantics.opencascade.vtk/.project b/org.simantics.opencascade.vtk/.project
new file mode 100644 (file)
index 0000000..e0986a7
--- /dev/null
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<projectDescription>\r
+       <name>org.simantics.opencascade.vtk</name>\r
+       <comment></comment>\r
+       <projects>\r
+       </projects>\r
+       <buildSpec>\r
+               <buildCommand>\r
+                       <name>org.eclipse.jdt.core.javabuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+               <buildCommand>\r
+                       <name>org.eclipse.pde.ManifestBuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+               <buildCommand>\r
+                       <name>org.eclipse.pde.SchemaBuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+       </buildSpec>\r
+       <natures>\r
+               <nature>org.eclipse.pde.PluginNature</nature>\r
+               <nature>org.eclipse.jdt.core.javanature</nature>\r
+       </natures>\r
+</projectDescription>\r
diff --git a/org.simantics.opencascade.vtk/.settings/org.eclipse.jdt.core.prefs b/org.simantics.opencascade.vtk/.settings/org.eclipse.jdt.core.prefs
new file mode 100644 (file)
index 0000000..24422af
--- /dev/null
@@ -0,0 +1,8 @@
+#Wed Aug 08 16:10:05 EEST 2012\r
+eclipse.preferences.version=1\r
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled\r
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6\r
+org.eclipse.jdt.core.compiler.compliance=1.6\r
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error\r
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error\r
+org.eclipse.jdt.core.compiler.source=1.6\r
diff --git a/org.simantics.opencascade.vtk/META-INF/MANIFEST.MF b/org.simantics.opencascade.vtk/META-INF/MANIFEST.MF
new file mode 100644 (file)
index 0000000..f9a953f
--- /dev/null
@@ -0,0 +1,17 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Vtk
+Bundle-SymbolicName: org.simantics.opencascade.vtk
+Bundle-Version: 1.0.0.qualifier
+Bundle-Activator: org.simantics.opencascade.vtk.Activator
+Bundle-Vendor: VTT
+Require-Bundle: org.eclipse.ui,
+ org.eclipse.core.runtime,
+ org.jcae.opencascade;bundle-version="6.5.2",
+ org.simantics.opencascade;bundle-version="1.0.0",
+ vtk;bundle-version="5.8.0",
+ javax.vecmath;bundle-version="1.5.2",
+ org.simantics.utils.datastructures;bundle-version="1.1.0"
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6
+Bundle-ActivationPolicy: lazy
+Export-Package: org.simantics.opencascade.vtk
diff --git a/org.simantics.opencascade.vtk/build.properties b/org.simantics.opencascade.vtk/build.properties
new file mode 100644 (file)
index 0000000..41eb6ad
--- /dev/null
@@ -0,0 +1,4 @@
+source.. = src/\r
+output.. = bin/\r
+bin.includes = META-INF/,\\r
+               .\r
diff --git a/org.simantics.opencascade.vtk/src/org/simantics/opencascade/vtk/Activator.java b/org.simantics.opencascade.vtk/src/org/simantics/opencascade/vtk/Activator.java
new file mode 100644 (file)
index 0000000..7c3e13a
--- /dev/null
@@ -0,0 +1,50 @@
+package org.simantics.opencascade.vtk;\r
+\r
+import org.eclipse.ui.plugin.AbstractUIPlugin;\r
+import org.osgi.framework.BundleContext;\r
+\r
+/**\r
+ * The activator class controls the plug-in life cycle\r
+ */\r
+public class Activator extends AbstractUIPlugin {\r
+\r
+       // The plug-in ID\r
+       public static final String PLUGIN_ID = "org.simantics.opencascade.vtk"; //$NON-NLS-1$\r
+\r
+       // The shared instance\r
+       private static Activator plugin;\r
+       \r
+       /**\r
+        * The constructor\r
+        */\r
+       public Activator() {\r
+       }\r
+\r
+       /*\r
+        * (non-Javadoc)\r
+        * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)\r
+        */\r
+       public void start(BundleContext context) throws Exception {\r
+               super.start(context);\r
+               plugin = this;\r
+       }\r
+\r
+       /*\r
+        * (non-Javadoc)\r
+        * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)\r
+        */\r
+       public void stop(BundleContext context) throws Exception {\r
+               plugin = null;\r
+               super.stop(context);\r
+       }\r
+\r
+       /**\r
+        * Returns the shared instance\r
+        *\r
+        * @return the shared instance\r
+        */\r
+       public static Activator getDefault() {\r
+               return plugin;\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.opencascade.vtk/src/org/simantics/opencascade/vtk/EdgePointsFilter.java b/org.simantics.opencascade.vtk/src/org/simantics/opencascade/vtk/EdgePointsFilter.java
new file mode 100644 (file)
index 0000000..e8505d3
--- /dev/null
@@ -0,0 +1,97 @@
+package org.simantics.opencascade.vtk;\r
+\r
+import java.util.HashSet;\r
+import java.util.List;\r
+import java.util.Set;\r
+\r
+import javax.vecmath.Point3d;\r
+import javax.vecmath.Vector3d;\r
+\r
+import org.simantics.utils.datastructures.MapList;\r
+\r
+import vtk.vtkCell;\r
+import vtk.vtkIdList;\r
+import vtk.vtkLine;\r
+import vtk.vtkPoints;\r
+import vtk.vtkPolyData;\r
+import vtk.vtkProgrammableFilter;\r
+import vtk.vtkVertex;\r
+\r
+public class EdgePointsFilter extends vtkProgrammableFilter {\r
+       vtkPoints outputPoints;\r
+       \r
+       \r
+       public EdgePointsFilter() {\r
+               SetExecuteMethod(this, "compute");\r
+       }\r
+       \r
+       public void compute() {\r
+               vtkPolyData polyDataInput = GetPolyDataInput();\r
+               vtkPolyData polyDataOutput = GetPolyDataOutput();\r
+               vtkPoints inputPoints = polyDataInput.GetPoints();\r
\r
+           outputPoints = new vtkPoints();\r
+\r
+               MapList<Integer, Integer> edgeIndices = new MapList<Integer, Integer>();\r
+               for (int i = 0; i <polyDataInput.GetNumberOfCells(); i++) {\r
+                       vtkCell cell= polyDataInput.GetCell(i);\r
+                       if (cell.IsA("vtkLine") > 0) {\r
+                               vtkLine line = (vtkLine)cell;\r
+                               int i1 = line.GetPointId(0);\r
+                               int i2 = line.GetPointId(1);\r
+                               if (!edgeIndices.contains(i1, i2)) {\r
+                                       edgeIndices.add(i1, i2);\r
+                                       edgeIndices.add(i2, i1);\r
+                               }\r
+                               line.Delete();\r
+                       }        \r
+               }\r
+                               \r
+               Set<Integer> vertices = new HashSet<Integer>();\r
+               for (Integer i : edgeIndices.getKeys()) {\r
+                       List<Integer> edges = edgeIndices.getValues(i);\r
+                       if (edges.size() != 2)\r
+                               vertices.add(i);\r
+                       else {\r
+                               double tp[] = inputPoints.GetPoint(i);\r
+                               double ep1[] = inputPoints.GetPoint(edges.get(0));\r
+                               double ep2[] = inputPoints.GetPoint(edges.get(1));\r
+                               Point3d t = new Point3d(tp);\r
+                               Vector3d v1 = new Vector3d(ep1);\r
+                               Vector3d v2 = new Vector3d(ep2);\r
+                               v1.sub(t);\r
+                               v2.sub(t);\r
+                               double angle = Math.PI - v1.angle(v2);\r
+                               if (angle > Math.PI/6)\r
+                                       vertices.add(i);\r
+                       }\r
+               }\r
+               for (int i : vertices) {\r
+                       outputPoints.InsertNextPoint(inputPoints.GetPoint(i));\r
+               }\r
+               polyDataOutput.Allocate(vertices.size(), vertices.size());\r
+               \r
+               vtkVertex vertex = new vtkVertex();\r
+               vtkIdList list = vertex.GetPointIds();\r
+               for (int i = 0; i < vertices.size(); i++) {\r
+                       list.SetId(0, i);\r
+                       polyDataOutput.InsertNextCell(vertex.GetCellType(), list);\r
+               }\r
+               \r
+               polyDataOutput.SetPoints(outputPoints);\r
+               \r
+               \r
+               list.Delete();\r
+               vertex.Delete();\r
+               \r
+               polyDataOutput.Delete();\r
+               polyDataInput.Delete();\r
+               \r
+       }\r
+       \r
+       @Override\r
+       public void Delete() {\r
+               outputPoints.Delete();\r
+               super.Delete();\r
+       }\r
+}\r
diff --git a/org.simantics.opencascade.vtk/src/org/simantics/opencascade/vtk/VTKOCCTool.java b/org.simantics.opencascade.vtk/src/org/simantics/opencascade/vtk/VTKOCCTool.java
new file mode 100644 (file)
index 0000000..187c785
--- /dev/null
@@ -0,0 +1,709 @@
+package org.simantics.opencascade.vtk;\r
+\r
+import java.util.List;\r
+\r
+import javax.vecmath.Matrix4d;\r
+import javax.vecmath.Point3d;\r
+\r
+import org.jcae.opencascade.jni.BRepMesh_IncrementalMesh;\r
+import org.jcae.opencascade.jni.BRep_Tool;\r
+import org.jcae.opencascade.jni.GP_Trsf;\r
+import org.jcae.opencascade.jni.Poly_Triangulation;\r
+import org.jcae.opencascade.jni.TopAbs_Orientation;\r
+import org.jcae.opencascade.jni.TopAbs_ShapeEnum;\r
+import org.jcae.opencascade.jni.TopExp_Explorer;\r
+import org.jcae.opencascade.jni.TopLoc_Location;\r
+import org.jcae.opencascade.jni.TopoDS_Face;\r
+import org.jcae.opencascade.jni.TopoDS_Shape;\r
+import org.simantics.opencascade.OCCTTool;\r
+\r
+import vtk.vtkActor;\r
+import vtk.vtkAlgorithmOutput;\r
+import vtk.vtkAppendPolyData;\r
+import vtk.vtkAssembly;\r
+import vtk.vtkCleanPolyData;\r
+import vtk.vtkDataSetMapper;\r
+import vtk.vtkFeatureEdges;\r
+import vtk.vtkGlyph3D;\r
+import vtk.vtkIdList;\r
+import vtk.vtkPoints;\r
+import vtk.vtkPolyData;\r
+import vtk.vtkPolyDataMapper;\r
+import vtk.vtkPolyDataNormals;\r
+import vtk.vtkProp;\r
+import vtk.vtkPropCollection;\r
+import vtk.vtkProperty;\r
+import vtk.vtkSphereSource;\r
+import vtk.vtkTriangle;\r
+\r
+public class VTKOCCTool {\r
+       public static vtkAssembly vtkTestAssembly() {\r
+               vtkAssembly assemblies = new vtkAssembly();\r
+               vtkPolyData partGrid = createTestPartGrid();\r
+               gridToAssembly(assemblies, partGrid);\r
+               return assemblies;\r
+       }\r
+       \r
+       public static vtkAssembly vtkOCCShapeToAssembly(TopoDS_Shape shape) {\r
+               double deflection = 0.001;\r
+\r
+               if (deflection <= 0.0) {\r
+                       deflection = 0.0005;\r
+                       System.out.println("Bad value for deflection. Using: " + deflection);\r
+               }\r
+\r
+               // FIXME : leaks memory!\r
+               //BRepTools.clean(shape);\r
+\r
+               double mass = OCCTTool.getMass(shape);\r
+\r
+               if (mass < 1.0e-12) {\r
+                       System.out.println("Non 3D-shape detected");\r
+                       System.out.println("The cad import features are currently limited to 3D models.");\r
+               }\r
+\r
+               double length = OCCTTool.getBoundingBoxDiagonal(shape);\r
+               deflection *= length; // use relative units\r
+\r
+               BRepMesh_IncrementalMesh mesh = new BRepMesh_IncrementalMesh(shape,deflection);\r
+\r
+               int faceNumber = 0;\r
+               TopExp_Explorer expFace = new TopExp_Explorer();\r
+\r
+               vtkAssembly assemblies = new vtkAssembly();\r
+               for (expFace.init(shape, TopAbs_ShapeEnum.FACE); expFace.more(); expFace.next()) {\r
+                       TopoDS_Face face = (TopoDS_Face) expFace.current();\r
+                       vtkPolyData partGrid = createPartGrid(face);\r
+                       face.delete();\r
+                       if (partGrid == null)\r
+                               continue;\r
+                       faceNumber++;\r
+                       //gridToAssembly(assemblies, partGrid, stlSurfaceData, stlEdgeData);\r
+                       gridToAssembly(assemblies, partGrid);\r
+                       \r
+               }\r
+               expFace.delete();\r
+               mesh.delete();\r
+\r
+               if (faceNumber == 0) {\r
+                       System.out\r
+                                       .println("Cad import: error: no surface triangulation was generated.");\r
+                       return null;\r
+               }\r
+\r
+               return assemblies;\r
+       }\r
+       \r
+       private static void gridToAssembly(vtkAssembly assemblies, vtkPolyData partGrid, vtkAppendPolyData stlSurfaceData, vtkAppendPolyData stlEdgeData) {\r
+        \r
+        double featureAngle = 30;\r
+\r
+        \r
+        vtkDataSetMapper partMapper = new vtkDataSetMapper();\r
+        \r
+        boolean computeNormals = true;\r
+        boolean cleanPart = true;\r
+        boolean mergePoints = false;\r
+\r
+        vtkCleanPolyData partCleaner = new vtkCleanPolyData();       \r
+        if (cleanPart)\r
+        {\r
+            partCleaner.SetInput(partGrid);\r
+            if(mergePoints) {\r
+              partCleaner.PointMergingOn();\r
+            } else {\r
+              partCleaner.PointMergingOff();\r
+            }\r
+        }\r
+        \r
+        if (computeNormals)\r
+        {\r
+            vtkPolyDataNormals partNormals = new vtkPolyDataNormals();\r
+         \r
+            if (cleanPart)\r
+            {\r
+                partNormals.SetInputConnection(partCleaner.GetOutputPort());\r
+            }\r
+            else partNormals.SetInput(partGrid);\r
+                \r
+            partNormals.SetFeatureAngle(featureAngle); // this do not have to be neccesarily called\r
+            partMapper.SetInputConnection(partNormals.GetOutputPort());\r
+            partNormals.Delete();          \r
+        }\r
+        else\r
+        {\r
+            if (cleanPart) partMapper.SetInputConnection(partCleaner.GetOutputPort()); // metoda 2, ne tak pekne, viz http://www.codeguru.com/cpp/g-m/opengl/article.php/c2681\r
+            else partMapper.SetInput(partGrid); // metoda 1, ne tak pekne stinovani, viz: http://www.codeguru.com/cpp/g-m/opengl/article.php/c2681\r
+        }\r
+        partMapper.ScalarVisibilityOn();\r
+        \r
+        vtkActor partActor = new vtkActor();\r
+\r
+        partActor.SetPickable(1);\r
+        partActor.GetProperty().SetColor(1, 1, 0);\r
+        partActor.SetMapper(partMapper);\r
+        \r
+        // EDGES OF PARTS DETECTION\r
+        vtkFeatureEdges partEdges = new vtkFeatureEdges();\r
+        if (cleanPart) partEdges.SetInputConnection(partCleaner.GetOutputPort());\r
+        else partEdges.SetInput(partGrid); \r
+        partEdges.SetFeatureAngle(featureAngle);  // this do not have to be neccesarily called\r
+        partEdges.FeatureEdgesOn();\r
+        partEdges.BoundaryEdgesOn();\r
+        partEdges.NonManifoldEdgesOn();\r
+        partEdges.ManifoldEdgesOn();\r
+\r
+        vtkDataSetMapper partEdgesMapper = new vtkDataSetMapper();\r
+        partEdgesMapper.SetInputConnection(partEdges.GetOutputPort());\r
+        partEdgesMapper.SetResolveCoincidentTopologyToPolygonOffset();\r
+        partEdgesMapper.ScalarVisibilityOff();\r
+        \r
+        vtkActor partEdgesActor = new vtkActor();\r
+        partEdgesActor.SetPickable(0);\r
+        partEdgesActor.GetProperty().SetColor(1, 0, 1);\r
+        partEdgesActor.SetMapper(partEdgesMapper);\r
+        \r
+\r
+        // Add triangles and edges to STL structures:\r
+        //--------------------------------------------\r
+        if (cleanPart) stlSurfaceData.AddInput(partCleaner.GetOutput());\r
+        else stlSurfaceData.AddInput(partGrid);\r
+        stlEdgeData.AddInput(partEdges.GetOutput());\r
+                \r
+        assemblies.AddPart(partActor);\r
+        assemblies.AddPart(partEdgesActor);        \r
+        \r
+        // Clean up:\r
+        //----------\r
+        partEdgesActor.Delete();\r
+        partEdgesMapper.Delete();\r
+        partEdges.Delete();\r
+        partActor.Delete();\r
+        partMapper.Delete();\r
+        partGrid.Delete();\r
+        partCleaner.Delete();\r
+    }\r
+\r
+public static void gridToAssembly(vtkAssembly assemblies, vtkPolyData partGrid) {\r
+    \r
+    double featureAngle = 30;\r
+\r
+    \r
+    vtkDataSetMapper partMapper = new vtkDataSetMapper();\r
+    \r
+    boolean computeNormals = true;\r
+    boolean cleanPart = false;\r
+    boolean mergePoints = false;\r
+\r
+    vtkCleanPolyData partCleaner = new vtkCleanPolyData();       \r
+    if (cleanPart)\r
+    {\r
+        partCleaner.SetInput(partGrid);\r
+        if(mergePoints) {\r
+          partCleaner.PointMergingOn();\r
+        } else {\r
+          partCleaner.PointMergingOff();\r
+        }\r
+    }\r
+    \r
+    if (computeNormals)\r
+    {\r
+        vtkPolyDataNormals partNormals = new vtkPolyDataNormals();\r
+     \r
+        if (cleanPart)\r
+        {\r
+               vtkAlgorithmOutput out = partCleaner.GetOutputPort();\r
+            partNormals.SetInputConnection(out);\r
+            out.Delete();\r
+        }\r
+        else partNormals.SetInput(partGrid);\r
+            \r
+        partNormals.SetFeatureAngle(featureAngle); // this do not have to be neccesarily called\r
+        vtkAlgorithmOutput out = partNormals.GetOutputPort();\r
+        partMapper.SetInputConnection(out);\r
+        out.Delete();\r
+        partNormals.Delete();          \r
+    }\r
+    else\r
+    {\r
+        if (cleanPart) {\r
+               vtkAlgorithmOutput out = partCleaner.GetOutputPort();\r
+               partMapper.SetInputConnection(out); // metoda 2, ne tak pekne, viz http://www.codeguru.com/cpp/g-m/opengl/article.php/c2681\r
+               out.Delete();\r
+        }\r
+        else partMapper.SetInput(partGrid); // metoda 1, ne tak pekne stinovani, viz: http://www.codeguru.com/cpp/g-m/opengl/article.php/c2681\r
+    }\r
+    partMapper.ScalarVisibilityOn();\r
+    \r
+    vtkActor partActor = new vtkActor();\r
+    partActor.SetPickable(1);\r
+    vtkProperty prop = partActor.GetProperty();\r
+    prop.SetColor(1, 1, 0);\r
+    prop.Delete();\r
+    partActor.SetMapper(partMapper);\r
+    \r
+    assemblies.AddPart(partActor);\r
+    \r
+    {\r
+           // EDGES OF PARTS DETECTION\r
+           vtkFeatureEdges partEdges = new vtkFeatureEdges();\r
+           if (cleanPart) {\r
+               vtkAlgorithmOutput out = partCleaner.GetOutputPort();\r
+               partEdges.SetInputConnection(out);\r
+               out.Delete();\r
+           }\r
+           else partEdges.SetInput(partGrid); \r
+          // partEdges.SetFeatureAngle(featureAngle);  // this do not have to be neccesarily called\r
+           partEdges.FeatureEdgesOn();\r
+           partEdges.BoundaryEdgesOn();\r
+           partEdges.NonManifoldEdgesOn();\r
+           partEdges.ManifoldEdgesOn();\r
+       \r
+           vtkDataSetMapper partEdgesMapper = new vtkDataSetMapper();\r
+           vtkAlgorithmOutput out = partEdges.GetOutputPort();\r
+           partEdgesMapper.SetInputConnection(out);\r
+           out.Delete();\r
+           partEdgesMapper.SetResolveCoincidentTopologyToPolygonOffset();\r
+           partEdgesMapper.ScalarVisibilityOff();\r
+           \r
+           vtkActor partEdgesActor = new vtkActor();\r
+          \r
+           prop = partEdgesActor.GetProperty();\r
+           prop.SetColor(0, 0, 0);\r
+           prop.SetLineWidth(2.0);\r
+           prop.Delete();\r
+           partEdgesActor.SetMapper(partEdgesMapper);\r
+           partEdgesActor.PickableOn();  \r
+           \r
+           assemblies.AddPart(partEdgesActor);        \r
+           \r
+           {\r
+\r
+               EdgePointsFilter edgePoints = new EdgePointsFilter();\r
+               \r
+                \r
+               out = partEdges.GetOutputPort();\r
+                   edgePoints.SetInputConnection(out);\r
+                   out.Delete();\r
+                   \r
+//                 vtkDataSetMapper partEdgePointsMapper = new vtkDataSetMapper();\r
+//                 out = edgePoints.GetOutputPort();\r
+//                 partEdgePointsMapper.SetInputConnection(out);\r
+//                 out.Delete();\r
+                   \r
+//                 vtkVertexGlyphFilter glyphFilter = new vtkVertexGlyphFilter();\r
+//                 out = edgePoints.GetOutputPort();\r
+//                 glyphFilter.SetInputConnection(out);\r
+//                 glyphFilter.Update();\r
+//                 out.Delete();\r
+//                 \r
+//                 vtkPolyDataMapper partEdgePointsMapper = new vtkPolyDataMapper();\r
+//                 out = glyphFilter.GetOutputPort();\r
+//                 partEdgePointsMapper.SetInputConnection(out);\r
+//                 out.Delete();\r
+                   \r
+                   vtkSphereSource sphereSource = new vtkSphereSource();\r
+                   vtkGlyph3D glyph3D = new vtkGlyph3D();\r
+                   out = sphereSource.GetOutputPort();\r
+                   glyph3D.SetSourceConnection(out);\r
+                   out.Delete();\r
+                   \r
+                   out = edgePoints.GetOutputPort();\r
+                   glyph3D.SetInputConnection(out);\r
+                   out.Delete();\r
+                   \r
+                   //glyph3D.ScalingOff();\r
+                   glyph3D.SetScaleFactor(0.03);\r
+                   \r
+                   glyph3D.Update();\r
+                   \r
+                   vtkPolyDataMapper partEdgePointsMapper = new vtkPolyDataMapper();\r
+                   out = glyph3D.GetOutputPort();\r
+                   partEdgePointsMapper.SetInputConnection(out);\r
+                   out.Delete();\r
+                   \r
+                   vtkActor edgePointsActor = new vtkActor();\r
+                  \r
+                   prop = edgePointsActor.GetProperty();\r
+                   prop.SetColor(0, 0, 1);\r
+                   //prop.SetPointSize(10.0);\r
+                   //prop.SetRepresentationToPoints();\r
+                   prop.Delete();\r
+                   edgePointsActor.SetMapper(partEdgePointsMapper);\r
+                  \r
+                   edgePointsActor.PickableOn();\r
+                   assemblies.AddPart(edgePointsActor);\r
+                   \r
+                   \r
+                   edgePointsActor.Delete();\r
+                   partEdgePointsMapper.Delete();\r
+                  // edgePoints.Delete();\r
+           }\r
+           // Clean up:\r
+           //----------\r
+           partEdgesActor.Delete();\r
+           partEdgesMapper.Delete();\r
+           partEdges.Delete();\r
+    }\r
+   \r
+    partActor.Delete();\r
+    partMapper.Delete();\r
+    partGrid.Delete();\r
+    partCleaner.Delete();\r
+}\r
+       \r
+       \r
+       \r
+       public static vtkPolyData createPartGrid ( TopoDS_Face face)\r
+    {\r
+        TopLoc_Location Location = new TopLoc_Location();\r
+        \r
+        Poly_Triangulation triangulation = BRep_Tool.triangulation(face, Location);\r
+\r
+        if(triangulation == null) {\r
+               Location.delete();\r
+               System.out.println("Encountered empty triangulation after face");\r
+               return null;\r
+        }\r
+                \r
+        boolean reverse = face.orientation()==TopAbs_Orientation.REVERSED;\r
+\r
+        int[]triangles = triangulation.triangles();\r
+        double[]nodes = triangulation.nodes();\r
+\r
+        int nofTriangles = triangulation.nbTriangles();\r
+        int nofNodes = triangulation.nbNodes();\r
+        \r
+        triangulation.delete();\r
+\r
+        if(nofTriangles < 1) {\r
+          System.out.println("No triangles for mesh on face");\r
+          Location.delete();\r
+          return null;\r
+        }\r
+\r
+        if(nofNodes < 1) {\r
+            System.out.println("No nodes for mesh on face:");\r
+            Location.delete();\r
+            return null;\r
+        }\r
+        //System.out.println("v " + nofNodes + " t " +nofTriangles);\r
+        vtkPolyData partGrid = new vtkPolyData();\r
+        partGrid.Allocate(nofTriangles, nofTriangles);\r
+\r
+        vtkTriangle triangle = new vtkTriangle();\r
+        vtkIdList list = triangle.GetPointIds();\r
+        for(int i = 0; i < nofTriangles; i++) \r
+        {\r
+          int n0, n1, n2;\r
+          if (!reverse) {\r
+                 n0 = triangles[3 * i]; \r
+                 n1 = triangles[3 * i + 1]; \r
+                 n2 = triangles[3 * i + 2];\r
+          } else {\r
+                 n0 = triangles[3 * i + 2]; \r
+                 n1 = triangles[3 * i + 1]; \r
+                 n2 = triangles[3 * i];\r
+          }\r
+          \r
+          list.SetId(0, n0);\r
+          list.SetId(1, n1);\r
+          list.SetId(2, n2);\r
+          partGrid.InsertNextCell(triangle.GetCellType(), list);\r
+          \r
+        }\r
+        list.Delete();\r
+        triangle.Delete();   \r
+        \r
+        GP_Trsf transformation = Location.transformation();\r
+        Location.delete();\r
+\r
+        double d_mat[] = new double[16];\r
+        double d_p[] = new double[3];\r
+        transformation.getValues(d_mat);\r
+        Matrix4d mat = new Matrix4d(d_mat);\r
+        \r
+        vtkPoints partPoints = new vtkPoints();\r
+        \r
+        for(int i = 0; i < nofNodes; i++) {     \r
+          // FIXME: GP_Trsf.transform(double[]) leaks memory\r
+               \r
+          //double xyz[] = new double[]{nodes[3 * i], nodes[3 * i + 1], nodes[3 * i + 2]};          \r
+          //transformation.transforms(xyz);\r
+          //partPoints.InsertPoint(i, xyz);\r
+               Point3d p = new Point3d(nodes[3 * i], nodes[3 * i + 1], nodes[3 * i + 2]);\r
+               mat.transform(p);\r
+               d_p[0] = p.x;\r
+               d_p[1] = p.y;\r
+               d_p[2] = p.z;\r
+               partPoints.InsertPoint(i, d_p);\r
+        }\r
+        \r
+        transformation.delete();\r
+        \r
+        partGrid.SetPoints(partPoints);\r
+        partPoints.Delete();\r
+       \r
+        return partGrid;\r
+    }\r
+       \r
+       \r
+       \r
+       public static vtkPolyData createPartGrid ( List<Double> meshPoints, List<Integer> meshTriangles)\r
+    {\r
+       \r
+                \r
+      \r
+\r
+        \r
+        int nofTriangles = meshTriangles.size() / 3;\r
+        int nofNodes = meshPoints.size() /3;\r
+        \r
+      \r
+        if(nofTriangles < 1) {\r
+          System.out.println("No triangles for mesh on face");\r
+          return null;\r
+        }\r
+\r
+        if(nofNodes < 1) {\r
+            System.out.println("No nodes for mesh on face:");\r
+            return null;\r
+        }\r
+        //System.out.println("v " + nofNodes + " t " +nofTriangles);\r
+        vtkPolyData partGrid = new vtkPolyData();\r
+        partGrid.Allocate(nofTriangles, nofTriangles);\r
+\r
+        vtkTriangle triangle = new vtkTriangle();\r
+        vtkIdList list = triangle.GetPointIds();\r
+        for(int i = 0; i < nofTriangles; i++) \r
+        {\r
+          int n0, n1, n2;          \r
+          n0 = meshTriangles.get(3 * i); \r
+          n1 = meshTriangles.get(3 * i + 1);\r
+          n2 = meshTriangles.get(3 * i + 2); \r
+\r
+         \r
+          list.SetId(0, n0);\r
+          list.SetId(1, n1);\r
+          list.SetId(2, n2);\r
+          partGrid.InsertNextCell(triangle.GetCellType(), list);\r
+          \r
+        }\r
+        list.Delete();\r
+        triangle.Delete();   \r
+        \r
+\r
+\r
+        double d_p[] = new double[3];\r
+\r
+        \r
+        vtkPoints partPoints = new vtkPoints();\r
+        \r
+        for(int i = 0; i < nofNodes; i++) {     \r
+\r
+               d_p[0] = meshPoints.get(3*i);\r
+               d_p[1] = meshPoints.get(3*i+1);\r
+               d_p[2] = meshPoints.get(3*i+2);\r
+               partPoints.InsertPoint(i, d_p);\r
+        }\r
+        \r
+        partGrid.SetPoints(partPoints);\r
+        partPoints.Delete();\r
+       \r
+        return partGrid;\r
+    }\r
+       \r
+       private static vtkPolyData createTestPartGrid ()\r
+    {\r
+               int size = 64;\r
+               \r
+        double[] nodes = new double[(size+1)*(size+1)*3];\r
+        int[] triangles = new int[3 * size * size * 2];\r
+\r
+        double es = 1.0;\r
+        for (int i = 0; i <= size; i++) {\r
+               for (int j = 0; j <= size; j++) {\r
+                       int index = j * size + i;\r
+                       index *= 3;\r
+                       double x = (double)i * es;\r
+                       double y = (Math.sin((double)i/(double)size)  + Math.sin((double)j/(double)size)) * es;\r
+                       double z = (double)j * es;\r
+                       nodes[index] = x;\r
+                       nodes[index+1] = y;\r
+                       nodes[index+2] = z;\r
+               }\r
+        }\r
+        \r
+        for (int i = 0; i < size; i++) {\r
+               for (int j = 0; j < size; j++) {\r
+                       int index = j * size + i;\r
+                       index *= 3;\r
+                       index *= 2;\r
+                       triangles[index  ] = (j     * (size+1) + i  );\r
+                       triangles[index+1] = (j     * (size+1) + i+1);\r
+                       triangles[index+2] = ((j+1) * (size+1) + i  );\r
+                       triangles[index+3] = ((j+1) * (size+1) + i  );\r
+                       triangles[index+4] = ((j  ) * (size+1) + i +1 );\r
+                       triangles[index+5] = ((j+1) * (size+1) + i +1 );\r
+               }\r
+        }\r
+\r
+        int nofTriangles = triangles.length / 3;\r
+        int nofNodes = nodes.length / 3;\r
+\r
+        if(nofTriangles < 1) {\r
+         \r
+          return null;\r
+        }\r
+\r
+        if(nofNodes < 1) {\r
+           \r
+            return null;\r
+        }\r
+        //System.out.println("v " + nofNodes + " t " +nofTriangles);\r
+        vtkPolyData partGrid = new vtkPolyData();\r
+        partGrid.Allocate(nofTriangles, nofTriangles);\r
+\r
+        vtkTriangle triangle = new vtkTriangle();\r
+        vtkIdList list = triangle.GetPointIds();\r
+        for(int i = 0; i < nofTriangles; i++) \r
+        {\r
+          int n0, n1, n2;          \r
+          n0 = triangles[3 * i]; n1 = triangles[3 * i + 1]; n2 = triangles[3 * i + 2]; // triangles(i).Get(n0, n1, n2);\r
+\r
+//          if(face.orientation() != TopAbs_Orientation.FORWARD) {\r
+//              int tmp = n2; n2 = n1; n1 = tmp;\r
+//          }\r
+         \r
+          list.SetId(0, n0);\r
+          list.SetId(1, n1);\r
+          list.SetId(2, n2);\r
+          partGrid.InsertNextCell(triangle.GetCellType(), list);\r
+          \r
+        }\r
+        list.Delete();\r
+        triangle.Delete();      \r
+\r
+        vtkPoints partPoints = new vtkPoints();\r
+        for(int i = 0; i < nofNodes; i++) {       \r
+            double xyz[] = new double[]{nodes[3 * i], nodes[3 * i + 1], nodes[3 * i + 2]};          \r
+            partPoints.InsertPoint(i, xyz);\r
+        }\r
+        \r
+        partGrid.SetPoints(partPoints);\r
+        \r
+        partPoints.Delete();\r
+\r
+        return partGrid;\r
+    }\r
+       \r
+       public static void test() {\r
+               TopoDS_Shape shape = null;\r
+               //shape = OccTriangulator.makeCylinder(new double[]{0,0,0}, new double[]{0,1,0}, 1, 1);\r
+               for (int t = 0; t < 5000; t++) {\r
+                       //shape = OccTriangulator.makeCylinder(new double[]{0,0,0}, new double[]{0,1,0}, 1, 1);\r
+                       int test = 2;\r
+                       if (test == 0) {\r
+                               vtkAssembly ass = VTKOCCTool.vtkOCCShapeToAssembly(shape);\r
+                               vtkPropCollection col;\r
+                       col = ass.GetParts();\r
+                       for (int i = 0; i < col.GetNumberOfItems(); i++)\r
+                       {\r
+                           vtkProp prop = (vtkProp) col.GetItemAsObject(i);\r
+                           //System.out.println(prop.Print());\r
+                           prop.Delete();\r
+                       }\r
+                       col.Delete();\r
+                       ass.Delete();\r
+                       }\r
+                       else if (test == 1) {\r
+                               //BRepTools.clean(shape);\r
+                               \r
+                               \r
+                               vtkAssembly ass = new vtkAssembly();\r
+                               \r
+                               double vol = OCCTTool.getBoundingBoxDiagonal(shape);\r
+                               double d = 0.001 * vol;\r
+                               BRepMesh_IncrementalMesh mesh = new BRepMesh_IncrementalMesh(shape,d);\r
+                               TopExp_Explorer expFace = new TopExp_Explorer();\r
+                               for (expFace.init(shape, TopAbs_ShapeEnum.FACE); expFace.more(); expFace.next()) {\r
+                                       TopoDS_Face face = (TopoDS_Face) expFace.current();\r
+                                       {\r
+//                                             TopLoc_Location Location = new TopLoc_Location();\r
+//                                             Poly_Triangulation triangulation = BRep_Tool.triangulation(face, Location);\r
+//                                             if (triangulation != null) {\r
+//                                                     \r
+//                                                     int[]triangles = triangulation.triangles();\r
+//                                             double[]nodes = triangulation.nodes();\r
+//                                             int nofTriangles = triangulation.nbTriangles();\r
+//                                             int nofNodes = triangulation.nbNodes();\r
+//                                             \r
+//                                             triangulation.delete();\r
+//                                             \r
+//                                             GP_Trsf transformation = Location.transformation();\r
+//                                             double d_mat[] = new double[16];\r
+//                                             transformation.getValues(d_mat);\r
+//                                             Matrix4d mat = new Matrix4d(d_mat);\r
+//                                             for(int i = 0; i < nofNodes; i++) {       \r
+//                                                 //double xyz[] = new double[]{nodes[3 * i], nodes[3 * i + 1], nodes[3 * i + 2]};          \r
+//                                                 Point3d p = new Point3d(nodes[3 * i], nodes[3 * i + 1], nodes[3 * i + 2]);\r
+//                                                     //transformation.transforms(xyz);\r
+//                                                 mat.transform(p);\r
+//                                             }\r
+//                                             transformation.delete();\r
+//                                             }\r
+//                                             \r
+//                                             Location.delete();\r
+                                               vtkPolyData data = VTKOCCTool.createPartGrid(face);\r
+                                               VTKOCCTool.gridToAssembly(ass, data);\r
+                                               //data.Delete();\r
+                                       }\r
+                                       face.delete();\r
+                               }\r
+                               expFace.delete();\r
+                               mesh.delete();\r
+                               \r
+                               vtkPropCollection col;\r
+                       col = ass.GetParts();\r
+                       for (int i = 0; i < col.GetNumberOfItems(); i++)\r
+                       {\r
+                           vtkProp prop = (vtkProp) col.GetItemAsObject(i);\r
+                           //System.out.println(prop.Print());\r
+                           prop.Delete();\r
+                       }\r
+                       col.Delete();\r
+                       ass.Delete();\r
+                       } else if (test == 2) {\r
+                               double[] pointStruct = new double[]{0,0,0}, dirStruct = new double[]{0,1,0};\r
+                               double radius = 1.0;\r
+                               double height = 1.0;\r
+                               \r
+                               double[] axe = new double[6];\r
+                                \r
+                       System.arraycopy(pointStruct, 0, axe, 0, 3);\r
+                       System.arraycopy(dirStruct, 0, axe, 3, 3);\r
+                       org.jcae.opencascade.jni.BRepPrimAPI_MakeCylinder cyl = new org.jcae.opencascade.jni.BRepPrimAPI_MakeCylinder(axe, radius, height, 2 * Math.PI);\r
+                       org.jcae.opencascade.jni.TopoDS_Shape tds = cyl.shape();\r
+                       cyl.delete();\r
+                       \r
+                       double vol = OCCTTool.getBoundingBoxDiagonal(tds);\r
+                               double d = 0.001 * vol;\r
+                               BRepMesh_IncrementalMesh mesh = new BRepMesh_IncrementalMesh(tds,d);\r
+//                             TopExp_Explorer expFace = new TopExp_Explorer();\r
+//                             for (expFace.init(tds, TopAbs_ShapeEnum.FACE); expFace.more(); expFace.next()) {\r
+//                                     TopoDS_Face face = (TopoDS_Face) expFace.current();\r
+//                                     {\r
+//                                             \r
+//                                     }\r
+//                                     face.delete();\r
+//                             }\r
+                               mesh.delete();\r
+                               \r
+                       tds.delete();\r
+                       }\r
+                       //shape.delete();\r
+               System.out.println(t);\r
+               }\r
+               //shape.delete();\r
+       }\r
+}\r
diff --git a/org.simantics.opencascade.vtk/src/org/simantics/opencascade/vtk/vtkSolidObject.java b/org.simantics.opencascade.vtk/src/org/simantics/opencascade/vtk/vtkSolidObject.java
new file mode 100644 (file)
index 0000000..221c45b
--- /dev/null
@@ -0,0 +1,464 @@
+package org.simantics.opencascade.vtk;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.List;\r
+\r
+import org.jcae.opencascade.jni.BRepMesh_IncrementalMesh;\r
+import org.jcae.opencascade.jni.TopAbs_ShapeEnum;\r
+import org.jcae.opencascade.jni.TopExp_Explorer;\r
+import org.jcae.opencascade.jni.TopoDS_Face;\r
+import org.jcae.opencascade.jni.TopoDS_Shape;\r
+import org.simantics.opencascade.OCCTTool;\r
+import org.simantics.utils.threads.AWTThread;\r
+import org.simantics.utils.threads.ThreadUtils;\r
+\r
+import vtk.vtkActor;\r
+import vtk.vtkAlgorithmOutput;\r
+import vtk.vtkCleanPolyData;\r
+import vtk.vtkDataSetMapper;\r
+import vtk.vtkFeatureEdges;\r
+import vtk.vtkGlyph3D;\r
+import vtk.vtkPanel;\r
+import vtk.vtkPolyData;\r
+import vtk.vtkPolyDataMapper;\r
+import vtk.vtkPolyDataNormals;\r
+import vtk.vtkPolyDataSilhouette;\r
+import vtk.vtkProp3D;\r
+import vtk.vtkProperty;\r
+import vtk.vtkRenderer;\r
+import vtk.vtkSphereSource;\r
+\r
+public class vtkSolidObject {\r
+       \r
+       public static double deflection = 0.001;\r
+       \r
+       public static double featureAngle = 30;\r
+       public static boolean computeNormals = true;\r
+       public static boolean cleanPart = false;\r
+       public static boolean mergePoints = false;\r
+       \r
+       private vtkPanel panel;\r
+       private TopoDS_Shape shape;\r
+       \r
+       private List<vtkProp3D> actors = new ArrayList<vtkProp3D>(2);\r
+       \r
+       private List<vtkProp3D> solid = new ArrayList<vtkProp3D>(1);\r
+       private List<vtkProp3D> edges =  new ArrayList<vtkProp3D>(1);\r
+       private vtkActor silhouette = null;\r
+       \r
+       public vtkSolidObject(vtkPanel panel,TopoDS_Shape shape) {\r
+               this.shape = shape;\r
+               this.panel = panel;\r
+       }\r
+       \r
+       public void visualizeSolid(boolean showEdges, boolean showVertices) {\r
+               visualizeSolid(true, showEdges, showVertices);\r
+       }\r
+       \r
+       public void visualizeSolid(boolean showFaces, boolean showEdges, boolean showVertices) {\r
+               visualizeSolid(showFaces, showEdges, showVertices, false);\r
+       }\r
+       \r
+       public void visualizeSolid(boolean showFaces, boolean showEdges, boolean showVertices, boolean showSilhouette) {\r
+               clearActorsAWT();\r
+               vtkPolyData data = createSolidMesh(shape);\r
+               if (data == null)\r
+                       return;\r
+               if (showFaces) {\r
+                       solid.add(createActor(data));           \r
+               }\r
+               if (showEdges) {\r
+                       vtkActor edge = createEdgesActor(data);\r
+                       edges.add(edge);                        \r
+                       if (showVertices) {\r
+                               actors.add(createVerticesActor(edge));\r
+                       }\r
+               }\r
+               if (showSilhouette) {\r
+                       silhouette = createSilhouette(panel.GetRenderer(), data);\r
+               }\r
+               actors.addAll(solid);\r
+               actors.addAll(edges);\r
+               if (silhouette != null)\r
+                       actors.add(silhouette);\r
+               data.Delete();\r
+               showActorsAWT();\r
+       }\r
+       \r
+       public void visualizeFaces(boolean showEdges, boolean showVertices) {\r
+               clearActorsAWT();\r
+               Collection<vtkPolyData> datas = createFaceMeshes(shape);\r
+               for (vtkPolyData data : datas) {\r
+                       solid.add(createActor(data));\r
+                       \r
+                       if (showEdges) {\r
+                               vtkActor edgesActor = createEdgesActor(data); \r
+                               edges.add(edgesActor);\r
+                               if (showVertices) {\r
+                                       actors.add(createVerticesActor(edgesActor));\r
+                               }\r
+                       }\r
+                       data.Delete();\r
+               }\r
+               actors.addAll(solid);\r
+               actors.addAll(edges);\r
+               \r
+               showActorsAWT();\r
+       }\r
+       \r
+       public List<vtkProp3D> getActors() {\r
+               assert (Thread.currentThread() == AWTThread.getThreadAccess().getThread());\r
+               return actors;\r
+       }\r
+       \r
+       public List<vtkProp3D> getSolid() {\r
+               assert (Thread.currentThread() == AWTThread.getThreadAccess().getThread());\r
+               return solid;\r
+       }\r
+       \r
+       public List<vtkProp3D> getEdges() {\r
+               assert (Thread.currentThread() == AWTThread.getThreadAccess().getThread());\r
+               return edges;\r
+       }\r
+       \r
+       public vtkActor getSilhouette() {\r
+               assert (Thread.currentThread() == AWTThread.getThreadAccess().getThread());\r
+               return silhouette;\r
+       }\r
+       \r
+       public void showActorsAWT() {\r
+               assert (Thread.currentThread() == AWTThread.getThreadAccess().getThread());\r
+               vtkRenderer ren = panel.GetRenderer();\r
+               for (vtkProp3D act : actors) {\r
+                       ren.AddActor(act);\r
+               }\r
+       }\r
+       \r
+       public void showActors() {\r
+               ThreadUtils.asyncExec(AWTThread.getThreadAccess(), new Runnable() {\r
+                       \r
+                       @Override\r
+                       public void run() {\r
+                               showActorsAWT();\r
+                       }\r
+               });\r
+       }\r
+       \r
+       public void clearActorsAWT() {\r
+               assert (Thread.currentThread() == AWTThread.getThreadAccess().getThread());\r
+               if (actors.size() == 0)\r
+                       return;\r
+               vtkRenderer ren = panel.GetRenderer();\r
+               for (vtkProp3D act : actors) {\r
+                       if (act.GetVTKId() != 0) {\r
+                               ren.RemoveActor(act);\r
+                               act.Delete();\r
+                       }\r
+               }\r
+               actors.clear();\r
+               solid.clear();\r
+               edges.clear();\r
+       }\r
+       \r
+       private void clearActorsAWT(List<vtkProp3D> actors) {\r
+               assert (Thread.currentThread() == AWTThread.getThreadAccess().getThread());\r
+               \r
+               if (actors.size() == 0)\r
+                       return;\r
+               vtkRenderer ren = panel.GetRenderer();\r
+               panel.lock();\r
+               for (vtkProp3D act : actors) {\r
+                       if (act.GetVTKId() != 0) {\r
+                               ren.RemoveActor(act);\r
+                               act.Delete();\r
+                       }\r
+               }\r
+               panel.unlock();\r
+       }\r
+       \r
+       public void clearActors() {\r
+               if (actors.size() == 0)\r
+                       return;\r
+               final List<vtkProp3D> temp = new ArrayList<vtkProp3D>(actors.size());\r
+               temp.addAll(actors);\r
+               actors.clear();\r
+               solid.clear();\r
+               edges.clear();\r
+               ThreadUtils.asyncExec(AWTThread.getThreadAccess(), new Runnable() {\r
+                       \r
+                       @Override\r
+                       public void run() {\r
+                               clearActorsAWT(temp);\r
+                       }\r
+               });\r
+       }\r
+       \r
+       public void dispose() {\r
+               if (shape != null) {\r
+                       shape.delete();\r
+                       shape = null;\r
+               }\r
+               clearActors();\r
+       }\r
+       \r
+       public void delete() {\r
+               if (shape != null) {\r
+                       shape.delete();\r
+                       shape = null;\r
+               }\r
+               clearActorsAWT();\r
+       }\r
+       \r
+       private static double TOLERANCE = 0.01;\r
+       \r
+       public static vtkPolyData createSolidMesh(TopoDS_Shape shape) {\r
+               \r
+               double volume = OCCTTool.getBoundingBoxDiagonal(shape);\r
+               if (volume < TOLERANCE)\r
+                       return null;\r
+               \r
+               BRepMesh_IncrementalMesh mesh = new BRepMesh_IncrementalMesh(shape,deflection*volume);\r
+       \r
+               TopExp_Explorer expFace = new TopExp_Explorer();\r
+               \r
+               List<Double> meshPoints = new ArrayList<Double>();\r
+               List<Integer> meshTriangles = new ArrayList<Integer>();\r
+               for (expFace.init(shape, TopAbs_ShapeEnum.FACE); expFace.more(); expFace.next()) {\r
+                       TopoDS_Face face = (TopoDS_Face) expFace.current();\r
+                       OCCTTool.appendToMesh(face, meshPoints, meshTriangles);\r
+                       face.delete();\r
+               }\r
+               if (meshPoints.size() == 0 || meshTriangles.size() == 0)\r
+                       return null;\r
+                       \r
+               vtkPolyData data = VTKOCCTool.createPartGrid(meshPoints, meshTriangles);\r
+               \r
+               expFace.delete();\r
+               mesh.delete();\r
+               \r
+               return data;\r
+       }\r
+       \r
+       public static Collection<vtkPolyData> createFaceMeshes(TopoDS_Shape shape) {\r
+               \r
+               double volume = OCCTTool.getBoundingBoxDiagonal(shape);\r
+               Collection<vtkPolyData> faces = new ArrayList<vtkPolyData>();\r
+               \r
+               if (volume > TOLERANCE) {\r
+               \r
+                       BRepMesh_IncrementalMesh mesh = new BRepMesh_IncrementalMesh(shape,deflection*volume);\r
+               \r
+                       TopExp_Explorer expFace = new TopExp_Explorer();\r
+                       \r
+                       \r
+                       for (expFace.init(shape, TopAbs_ShapeEnum.FACE); expFace.more(); expFace.next()) {\r
+                               TopoDS_Face face = (TopoDS_Face) expFace.current();\r
+                               vtkPolyData data = VTKOCCTool.createPartGrid(face);\r
+                               face.delete();\r
+                               faces.add(data);\r
+                       }\r
+                       \r
+                       expFace.delete();\r
+                       mesh.delete();\r
+               }\r
+               \r
+               return faces;\r
+       }\r
+       \r
+       \r
+       \r
+       public static vtkActor createActor(vtkPolyData partGrid) {\r
+               \r
+               \r
+           vtkDataSetMapper partMapper = new vtkDataSetMapper();\r
+           \r
+           vtkCleanPolyData partCleaner = null;       \r
+           if (cleanPart)\r
+           {\r
+               partCleaner = new vtkCleanPolyData();\r
+               partCleaner.SetInput(partGrid);\r
+               if(mergePoints) {\r
+                 partCleaner.PointMergingOn();\r
+               } else {\r
+                 partCleaner.PointMergingOff();\r
+               }\r
+           }\r
+           \r
+           if (computeNormals)\r
+           {\r
+               vtkPolyDataNormals partNormals = new vtkPolyDataNormals();\r
+            \r
+               if (cleanPart)\r
+               {\r
+                       vtkAlgorithmOutput out = partCleaner.GetOutputPort();\r
+                   partNormals.SetInputConnection(out);\r
+                   out.Delete();\r
+               }\r
+               else partNormals.SetInput(partGrid);\r
+                   \r
+               partNormals.SetFeatureAngle(featureAngle); // this do not have to be neccesarily called\r
+               vtkAlgorithmOutput out = partNormals.GetOutputPort();\r
+               partMapper.SetInputConnection(out);\r
+               out.Delete();\r
+               partNormals.Delete();          \r
+           }\r
+           else\r
+           {\r
+               if (cleanPart) {\r
+                       vtkAlgorithmOutput out = partCleaner.GetOutputPort();\r
+                       partMapper.SetInputConnection(out); // metoda 2, ne tak pekne, viz http://www.codeguru.com/cpp/g-m/opengl/article.php/c2681\r
+                       out.Delete();\r
+               }\r
+               else partMapper.SetInput(partGrid); // metoda 1, ne tak pekne stinovani, viz: http://www.codeguru.com/cpp/g-m/opengl/article.php/c2681\r
+           }\r
+           partMapper.ScalarVisibilityOn();\r
+           \r
+           vtkActor partActor = new vtkActor();\r
+          // partActor.SetPickable(1);\r
+           vtkProperty prop = partActor.GetProperty();\r
+           prop.SetColor(1, 1, 0);\r
+           prop.Delete();\r
+           partActor.SetMapper(partMapper);\r
+           \r
+           partMapper.Delete();\r
+           \r
+           if (cleanPart)\r
+               partCleaner.Delete();\r
+           \r
+           return partActor;\r
+       }\r
+       \r
+       public static vtkActor createEdgesActor(vtkPolyData partGrid) {\r
+               vtkCleanPolyData partCleaner = null;       \r
+          \r
+               if (cleanPart)\r
+           {\r
+                       partCleaner = new vtkCleanPolyData();\r
+               partCleaner.SetInput(partGrid);\r
+               if(mergePoints) {\r
+                 partCleaner.PointMergingOn();\r
+               } else {\r
+                 partCleaner.PointMergingOff();\r
+               }\r
+           }\r
+           \r
+               vtkFeatureEdges partEdges = new vtkFeatureEdges();\r
+           if (cleanPart) {\r
+               vtkAlgorithmOutput out = partCleaner.GetOutputPort();\r
+               partEdges.SetInputConnection(out);\r
+               out.Delete();\r
+           }\r
+           else partEdges.SetInput(partGrid); \r
+          // partEdges.SetFeatureAngle(featureAngle);  // this do not have to be neccesarily called\r
+           partEdges.FeatureEdgesOn();\r
+           partEdges.BoundaryEdgesOn();\r
+           partEdges.NonManifoldEdgesOn();\r
+           partEdges.ManifoldEdgesOn();\r
+       \r
+           vtkDataSetMapper partEdgesMapper = new vtkDataSetMapper();\r
+           vtkAlgorithmOutput out = partEdges.GetOutputPort();\r
+           partEdgesMapper.SetInputConnection(out);\r
+           out.Delete();\r
+           partEdgesMapper.SetResolveCoincidentTopologyToPolygonOffset();\r
+           partEdgesMapper.ScalarVisibilityOff();\r
+           \r
+           vtkActor partEdgesActor = new vtkActor();\r
+          \r
+           vtkProperty prop = partEdgesActor.GetProperty();\r
+           prop.SetColor(0, 0, 0);\r
+           prop.SetLineWidth(2.0);\r
+           prop.Delete();\r
+           partEdgesActor.SetMapper(partEdgesMapper);\r
+\r
+           partEdgesMapper.Delete();\r
+           partEdges.Delete();\r
+           \r
+           if (cleanPart)\r
+               partCleaner.Delete();\r
+           \r
+           return partEdgesActor;\r
+       }\r
+       \r
+       public static vtkActor createVerticesActor(vtkActor partEdgesActor) {\r
+               vtkDataSetMapper partEdgesMapper = (vtkDataSetMapper) partEdgesActor.GetMapper();\r
+               vtkAlgorithmOutput out = partEdgesMapper.GetInputConnection(0, 0);\r
+               vtkFeatureEdges partEdges = (vtkFeatureEdges)out.GetProducer();\r
+               \r
+               vtkActor edgePointsActor = createVerticesActor(partEdges);\r
+               \r
+               partEdges.Delete();\r
+               //out.Delete();\r
+               partEdgesMapper.Delete();\r
+               return edgePointsActor;\r
+       }\r
+       \r
+       public static vtkActor createVerticesActor(vtkFeatureEdges partEdges) {\r
+               EdgePointsFilter edgePoints = new EdgePointsFilter();\r
+       \r
+        \r
+       vtkAlgorithmOutput out = partEdges.GetOutputPort();\r
+           edgePoints.SetInputConnection(out);\r
+           out.Delete();\r
+           \r
+           vtkSphereSource sphereSource = new vtkSphereSource();\r
+           vtkGlyph3D glyph3D = new vtkGlyph3D();\r
+           out = sphereSource.GetOutputPort();\r
+           glyph3D.SetSourceConnection(out);\r
+           out.Delete();\r
+           \r
+           out = edgePoints.GetOutputPort();\r
+           glyph3D.SetInputConnection(out);\r
+           out.Delete();\r
+           \r
+           glyph3D.SetScaleFactor(0.03);\r
+           \r
+           glyph3D.Update();\r
+           \r
+           vtkPolyDataMapper partEdgePointsMapper = new vtkPolyDataMapper();\r
+           out = glyph3D.GetOutputPort();\r
+           partEdgePointsMapper.SetInputConnection(out);\r
+           out.Delete();\r
+           \r
+           vtkActor edgePointsActor = new vtkActor();\r
+          \r
+           vtkProperty prop = edgePointsActor.GetProperty();\r
+           prop.SetColor(0, 0, 1);\r
+           prop.Delete();\r
+           edgePointsActor.SetMapper(partEdgePointsMapper);\r
+          \r
+           edgePointsActor.PickableOn();\r
+\r
+           \r
+           partEdgePointsMapper.Delete();\r
+           edgePoints.Delete();\r
+           sphereSource.Delete();\r
+           \r
+           return edgePointsActor;\r
+       }\r
+       \r
+       public static vtkActor createSilhouette(vtkRenderer ren, vtkPolyData data) {\r
+               \r
+               \r
+               vtkPolyDataSilhouette silhouette = new vtkPolyDataSilhouette();\r
+               \r
+               silhouette.SetInput(data);\r
+               silhouette.SetCamera(ren.GetActiveCamera());\r
+               silhouette.SetEnableFeatureAngle(0);\r
+               vtkPolyDataMapper mapper = new vtkPolyDataMapper();\r
+               \r
+               mapper.SetInputConnection(silhouette.GetOutputPort());\r
+               \r
+               vtkActor actor = new vtkActor();\r
+               actor.SetMapper(mapper);\r
+               \r
+               actor.GetProperty().SetColor(0,0,1);\r
+               actor.GetProperty().SetLineWidth(6);\r
+               \r
+               return actor;\r
+               \r
+               \r
+               \r
+       }\r
+\r
+}\r
diff --git a/org.simantics.opencascade/.classpath b/org.simantics.opencascade/.classpath
new file mode 100644 (file)
index 0000000..8a8f166
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<classpath>\r
+       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>\r
+       <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>\r
+       <classpathentry kind="src" path="src"/>\r
+       <classpathentry kind="output" path="bin"/>\r
+</classpath>\r
diff --git a/org.simantics.opencascade/.project b/org.simantics.opencascade/.project
new file mode 100644 (file)
index 0000000..332b01d
--- /dev/null
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<projectDescription>\r
+       <name>org.simantics.opencascade</name>\r
+       <comment></comment>\r
+       <projects>\r
+       </projects>\r
+       <buildSpec>\r
+               <buildCommand>\r
+                       <name>org.eclipse.jdt.core.javabuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+               <buildCommand>\r
+                       <name>org.eclipse.pde.ManifestBuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+               <buildCommand>\r
+                       <name>org.eclipse.pde.SchemaBuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+       </buildSpec>\r
+       <natures>\r
+               <nature>org.eclipse.pde.PluginNature</nature>\r
+               <nature>org.eclipse.jdt.core.javanature</nature>\r
+       </natures>\r
+</projectDescription>\r
diff --git a/org.simantics.opencascade/.settings/org.eclipse.jdt.core.prefs b/org.simantics.opencascade/.settings/org.eclipse.jdt.core.prefs
new file mode 100644 (file)
index 0000000..a29390a
--- /dev/null
@@ -0,0 +1,8 @@
+#Mon Dec 12 17:21:52 EET 2011\r
+eclipse.preferences.version=1\r
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled\r
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6\r
+org.eclipse.jdt.core.compiler.compliance=1.6\r
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error\r
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error\r
+org.eclipse.jdt.core.compiler.source=1.6\r
diff --git a/org.simantics.opencascade/META-INF/MANIFEST.MF b/org.simantics.opencascade/META-INF/MANIFEST.MF
new file mode 100644 (file)
index 0000000..3456c4d
--- /dev/null
@@ -0,0 +1,14 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Opencascade
+Bundle-SymbolicName: org.simantics.opencascade
+Bundle-Version: 1.0.0.qualifier
+Bundle-Activator: org.simantics.opencascade.Activator
+Bundle-Vendor: VTT
+Require-Bundle: org.eclipse.core.runtime,
+ javax.vecmath;bundle-version="1.5.2",
+ org.jcae.opencascade;bundle-version="1.0.0",
+ org.simantics.utils.datastructures;bundle-version="1.1.0"
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6
+Bundle-ActivationPolicy: lazy
+Export-Package: org.simantics.opencascade
diff --git a/org.simantics.opencascade/build.properties b/org.simantics.opencascade/build.properties
new file mode 100644 (file)
index 0000000..41eb6ad
--- /dev/null
@@ -0,0 +1,4 @@
+source.. = src/\r
+output.. = bin/\r
+bin.includes = META-INF/,\\r
+               .\r
diff --git a/org.simantics.opencascade/src/org/simantics/opencascade/Activator.java b/org.simantics.opencascade/src/org/simantics/opencascade/Activator.java
new file mode 100644 (file)
index 0000000..73b38c8
--- /dev/null
@@ -0,0 +1,30 @@
+package org.simantics.opencascade;\r
+\r
+import org.osgi.framework.BundleActivator;\r
+import org.osgi.framework.BundleContext;\r
+\r
+public class Activator implements BundleActivator {\r
+\r
+       private static BundleContext context;\r
+\r
+       static BundleContext getContext() {\r
+               return context;\r
+       }\r
+\r
+       /*\r
+        * (non-Javadoc)\r
+        * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)\r
+        */\r
+       public void start(BundleContext bundleContext) throws Exception {\r
+               Activator.context = bundleContext;\r
+       }\r
+\r
+       /*\r
+        * (non-Javadoc)\r
+        * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)\r
+        */\r
+       public void stop(BundleContext bundleContext) throws Exception {\r
+               Activator.context = null;\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.opencascade/src/org/simantics/opencascade/OCCTTool.java b/org.simantics.opencascade/src/org/simantics/opencascade/OCCTTool.java
new file mode 100644 (file)
index 0000000..eba42a6
--- /dev/null
@@ -0,0 +1,206 @@
+package org.simantics.opencascade;\r
+\r
+import java.util.List;\r
+\r
+import javax.vecmath.Matrix4d;\r
+import javax.vecmath.Point3d;\r
+\r
+import org.jcae.opencascade.jni.BRepBndLib;\r
+import org.jcae.opencascade.jni.BRepGProp;\r
+import org.jcae.opencascade.jni.BRep_Tool;\r
+import org.jcae.opencascade.jni.Bnd_Box;\r
+import org.jcae.opencascade.jni.GP_Trsf;\r
+import org.jcae.opencascade.jni.GProp_GProps;\r
+import org.jcae.opencascade.jni.GProp_VelGProps;\r
+import org.jcae.opencascade.jni.Poly_Triangulation;\r
+import org.jcae.opencascade.jni.TopAbs_Orientation;\r
+import org.jcae.opencascade.jni.TopLoc_Location;\r
+import org.jcae.opencascade.jni.TopoDS_Face;\r
+import org.jcae.opencascade.jni.TopoDS_Shape;\r
+\r
+public class OCCTTool {\r
+public static double getBoundingBoxDiagonal(TopoDS_Shape shape) {\r
+        \r
+        double []min = new double[3];\r
+        double []max = new double[3];\r
+        double []mmm = new double[3];\r
+        double []bb = new double[6];\r
+                \r
+        // Compute bounding box:\r
+        //----------------------\r
+        Bnd_Box boundingBox = new Bnd_Box();\r
+        BRepBndLib.add(shape, boundingBox);\r
+        boundingBox.get(bb);\r
+        boundingBox.delete();\r
+        \r
+        min[0] = bb[0]; min[1] = bb[1]; min[2] = bb[2];\r
+        max[0] = bb[3]; max[1] = bb[4]; max[2] = bb[5];\r
+\r
+        //System.out.println("Bounding box: "+"[ "+min[0]+", "+min[1]+", " + min[2] + "] x "+"[ " +max[0] +", " +max[1] +", " +max[2] +"]");\r
+\r
+        // The length of the space diagonal of cuboid\r
+        for (int i = 0; i < 3; i++) mmm[i] = max[i] - min[i];\r
+        double length = Math.sqrt(mmm[2]*mmm[2] + mmm[1]*mmm[1] + mmm[0]*mmm[0]);\r
+\r
+        double t0 = mmm[0]*mmm[0];\r
+        double t1 = mmm[1]*mmm[1];\r
+        double t2 = mmm[2]*mmm[2];\r
+\r
+        double tol = 1.0e-6 * length;\r
+\r
+        if((t0 < tol) || (t1 < tol) || (t2 < tol)) {\r
+            System.out.println("Shape seems to be 2D. Unable to proceed. Aborting.");\r
+            return 0;\r
+        }\r
+        return length;\r
+    }\r
+       \r
+ public static double getBoundingBoxVolume(TopoDS_Shape shape) {\r
+        \r
+        double []min = new double[3];\r
+        double []max = new double[3];\r
+        double []mmm = new double[3];\r
+        double []bb = new double[6];\r
+                \r
+        // Compute bounding box:\r
+        //----------------------\r
+        Bnd_Box boundingBox = new Bnd_Box();\r
+        BRepBndLib.add(shape, boundingBox);\r
+        boundingBox.get(bb);\r
+        boundingBox.delete();\r
+        \r
+        min[0] = bb[0]; min[1] = bb[1]; min[2] = bb[2];\r
+        max[0] = bb[3]; max[1] = bb[4]; max[2] = bb[5];\r
+\r
+        //System.out.println("Bounding box: "+"[ "+min[0]+", "+min[1]+", " + min[2] + "] x "+"[ " +max[0] +", " +max[1] +", " +max[2] +"]");\r
+\r
+        for (int i = 0; i < 3; i++) mmm[i] = max[i] - min[i];\r
+        double vol = Math.sqrt(mmm[2]*mmm[1]*mmm[0]);\r
+\r
+        return vol;\r
+    }\r
\r
+        private static GProp_GProps getGProp(TopoDS_Shape shape) {\r
+                GProp_GProps GSystem = null;\r
+               int type = 0;\r
+               if (type == 0) {\r
+                       GSystem = new GProp_GProps();\r
+                       BRepGProp.volumeProperties(shape, GSystem,0.001);\r
+               } else if (type == 1) {\r
+                       GSystem = new GProp_VelGProps();\r
+                       BRepGProp.volumeProperties(shape, GSystem,0.001);\r
+               } else if (type == 2) {\r
+                       GSystem = new GProp_VelGProps();\r
+                       BRepGProp.volumePropertiesGK(shape, GSystem, 0.001);\r
+               }\r
+               return GSystem;\r
+        }\r
+       \r
+       public static double getMass( TopoDS_Shape shape) {\r
+               \r
+               GProp_GProps GSystem = getGProp(shape);\r
+               \r
+               \r
+               double mass = GSystem.mass();\r
+               //System.out.println("Mass " + mass);\r
+               GSystem.delete();\r
+               return mass;\r
+       }\r
+       \r
+       public static double[] getInertia(TopoDS_Shape shape) {\r
+               GProp_GProps GSystem = getGProp(shape);\r
+               \r
+               double inertia[] = GSystem.matrixOfInertia();\r
+               GSystem.delete();\r
+               return inertia;\r
+       }\r
+       \r
+       public static double[] getCentreOfMass(TopoDS_Shape shape) {\r
+               GProp_GProps GSystem = getGProp(shape);\r
+               \r
+               double cm[] = GSystem.centreOfMass();\r
+               GSystem.delete();\r
+               return cm;\r
+       }\r
+       \r
+       public static boolean appendToMesh (TopoDS_Face face, List<Double> meshPoints, List<Integer> meshTriangles)\r
+    {\r
+        TopLoc_Location Location = new TopLoc_Location();\r
+        \r
+        Poly_Triangulation triangulation = BRep_Tool.triangulation(face, Location);\r
+\r
+        if(triangulation == null) {\r
+               Location.delete();\r
+               System.out.println("Encountered empty triangulation after face");\r
+               return false;\r
+        }\r
+                \r
+        boolean reverse = face.orientation()==TopAbs_Orientation.REVERSED;\r
+        \r
+        int lastPoint = meshPoints.size() / 3;\r
+\r
+        int[]triangles = triangulation.triangles();\r
+        double[]nodes = triangulation.nodes();\r
+\r
+        int nofTriangles = triangulation.nbTriangles();\r
+        int nofNodes = triangulation.nbNodes();\r
+        \r
+        \r
+        triangulation.delete();\r
+\r
+        if(nofTriangles < 1) {\r
+          System.out.println("No triangles for mesh on face");\r
+          Location.delete();\r
+          return false;\r
+        }\r
+\r
+        if(nofNodes < 1) {\r
+            System.out.println("No nodes for mesh on face:");\r
+            Location.delete();\r
+            return false;\r
+        }\r
+       \r
+        for(int i = 0; i < nofTriangles; i++) \r
+        {\r
+          int n0, n1, n2;  \r
+          if (!reverse) {\r
+                 n0 = triangles[3 * i]; \r
+                 n1 = triangles[3 * i + 1]; \r
+                 n2 = triangles[3 * i + 2];\r
+          } else {\r
+                 n0 = triangles[3 * i + 2]; \r
+                 n1 = triangles[3 * i + 1]; \r
+                 n2 = triangles[3 * i];\r
+          }\r
+         \r
+          meshTriangles.add(n0 + lastPoint);\r
+          meshTriangles.add(n1 + lastPoint);\r
+          meshTriangles.add(n2 + lastPoint);\r
+        }\r
+\r
+        \r
+        GP_Trsf transformation = Location.transformation();\r
+        Location.delete();\r
+\r
+        double d_mat[] = new double[16];\r
+\r
+        transformation.getValues(d_mat);\r
+        Matrix4d mat = new Matrix4d(d_mat);\r
+        \r
+        \r
+        for(int i = 0; i < nofNodes; i++) {     \r
+\r
+               Point3d p = new Point3d(nodes[3 * i], nodes[3 * i + 1], nodes[3 * i + 2]);\r
+               mat.transform(p);\r
+\r
+               meshPoints.add(p.x);\r
+               meshPoints.add(p.y);\r
+               meshPoints.add(p.z);\r
+               \r
+        }\r
+        \r
+        transformation.delete();\r
+        \r
+        return true;\r
+    }\r
+}\r
diff --git a/org.simantics.opencascade/src/org/simantics/opencascade/OccTriangulator.java b/org.simantics.opencascade/src/org/simantics/opencascade/OccTriangulator.java
new file mode 100644 (file)
index 0000000..e545a69
--- /dev/null
@@ -0,0 +1,303 @@
+package org.simantics.opencascade;\r
+\r
+/*******************************************************************************\r
+ * Copyright (c) 2007- VTT Technical Research Centre of Finland.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+\r
+import javax.vecmath.Vector2d;\r
+\r
+import org.jcae.opencascade.jni.BRepBuilderAPI_MakeEdge;\r
+import org.jcae.opencascade.jni.BRepBuilderAPI_MakeFace;\r
+import org.jcae.opencascade.jni.BRepBuilderAPI_MakeWire;\r
+import org.jcae.opencascade.jni.BRepBuilderAPI_Transform;\r
+import org.jcae.opencascade.jni.BRepPrimAPI_MakePrism;\r
+import org.jcae.opencascade.jni.BRepPrimAPI_MakeTorus;\r
+import org.jcae.opencascade.jni.BRep_Builder;\r
+import org.jcae.opencascade.jni.GP_Elips;\r
+import org.jcae.opencascade.jni.GP_Trsf;\r
+import org.jcae.opencascade.jni.TopoDS_Edge;\r
+import org.jcae.opencascade.jni.TopoDS_Face;\r
+import org.jcae.opencascade.jni.TopoDS_Shape;\r
+import org.jcae.opencascade.jni.TopoDS_Wire;\r
+\r
+\r
+public class OccTriangulator {\r
+\r
+    \r
+    public static final double MIN_VALUE = 0.001;\r
+    \r
+    public OccTriangulator() {\r
+        \r
+    }\r
+\r
+\r
+    public static TopoDS_Shape getShapeFromFile(String filename) {\r
+        assert (filename != null);\r
+        String lowerFileName = filename.toLowerCase(); \r
+        if (lowerFileName.endsWith(".stp") || lowerFileName.endsWith(".step")) {\r
+            TopoDS_Shape shape = importSTEP(filename);\r
+            return shape;\r
+        } else if (lowerFileName.endsWith(".iges")) {\r
+            TopoDS_Shape shape = importIGES(filename);\r
+            return shape;\r
+        } else if (lowerFileName.endsWith(".brep")) {\r
+            TopoDS_Shape shape = importBREP(filename);\r
+            return shape;\r
+        } else {\r
+            throw new UnsupportedOperationException("Unsupported format " + filename);\r
+        }\r
+    }\r
+\r
+    public static TopoDS_Shape importBREP(String filename) {\r
+               return importBREP(filename,1.0); // convert to meters.\r
+    }\r
+    public static TopoDS_Shape importBREP(String filename, double scale) {\r
+        org.jcae.opencascade.jni.BRep_Builder aBuilder = new org.jcae.opencascade.jni.BRep_Builder();\r
+        org.jcae.opencascade.jni.TopoDS_Shape myShape = org.jcae.opencascade.jni.BRepTools.read(filename, aBuilder);\r
+        aBuilder.delete();\r
+        if (Math.abs(scale-1.0) < 0.001)\r
+               return myShape;\r
+        TopoDS_Shape scaled = makeScale(myShape, scale);\r
+        myShape.delete();\r
+        return scaled;\r
+    }\r
+\r
+    public static TopoDS_Shape importIGES(String filename) {\r
+        org.jcae.opencascade.jni.IGESControl_Reader aReader = new org.jcae.opencascade.jni.IGESControl_Reader();\r
+        aReader.setReadUnitM();\r
+        aReader.readFile(filename.getBytes());\r
+        aReader.clearShapes();\r
+        aReader.transferRoots();\r
+        TopoDS_Shape result = aReader.oneShape();\r
+        aReader.delete();\r
+        return result;\r
+    }\r
+    \r
+    public static TopoDS_Shape importSTEP(String filename) {\r
+        org.jcae.opencascade.jni.STEPControl_Reader aReader = new org.jcae.opencascade.jni.STEPControl_Reader();\r
+        aReader.setReadUnitM();\r
+        aReader.readFile(filename.getBytes());\r
+        aReader.clearShapes();\r
+        aReader.transferRoots();\r
+        TopoDS_Shape result = aReader.oneShape();\r
+        aReader.delete();\r
+        return result;\r
+    }\r
+\r
+\r
+\r
+    public static TopoDS_Shape makeTranslation(TopoDS_Shape aShape, double x, double y, double z) {\r
+        GP_Trsf theTransformation = new GP_Trsf();\r
+        theTransformation.setTranslation(new double[] { x, y, z });\r
+        BRepBuilderAPI_Transform bt = new BRepBuilderAPI_Transform(aShape, theTransformation, true);\r
+\r
+        TopoDS_Shape shape = bt.shape();\r
+        bt.delete();\r
+        theTransformation.delete();\r
+        return shape;\r
+    }\r
+\r
+    public static TopoDS_Shape makeTorus(double[] pointStruct, double[] dirStruct, double r1, double r2) {\r
+        double[] axe = new double[6];\r
+        System.arraycopy(pointStruct, 0, axe, 0, 3);\r
+        System.arraycopy(dirStruct, 0, axe, 3, 3);\r
+        BRepPrimAPI_MakeTorus torus = new BRepPrimAPI_MakeTorus(axe, r1, r2);\r
+        org.jcae.opencascade.jni.TopoDS_Shape tds = torus.shape();\r
+        torus.delete();\r
+        return tds;\r
+    }\r
+    \r
+    public static TopoDS_Shape makeTorus(double[] pointStruct, double[] dirStruct, double r1, double r2, double angle1, double angle2, double angle) {\r
+        double[] axe = new double[6];\r
+        System.arraycopy(pointStruct, 0, axe, 0, 3);\r
+        System.arraycopy(dirStruct, 0, axe, 3, 3);\r
+        BRepPrimAPI_MakeTorus torus = new BRepPrimAPI_MakeTorus(axe, r1, r2,angle1,angle2,angle);\r
+        org.jcae.opencascade.jni.TopoDS_Shape tds = torus.shape();\r
+        torus.delete();\r
+        return tds;\r
+    }\r
+\r
+    public static TopoDS_Shape makeSphere(double x, double y, double z, double radius) {\r
+        double[] c = new double[] { x, y, z };\r
+        org.jcae.opencascade.jni.BRepPrimAPI_MakeSphere sphere = new org.jcae.opencascade.jni.BRepPrimAPI_MakeSphere(c, radius);\r
+        org.jcae.opencascade.jni.TopoDS_Shape tds = sphere.shape();\r
+        sphere.delete();\r
+        return tds;\r
+    }\r
+\r
+\r
+    public static TopoDS_Shape makeRotation(TopoDS_Shape aShape, double[] axisStruct, double angle) {\r
+\r
+        GP_Trsf theTransformation = new GP_Trsf();\r
+        theTransformation.setRotation(axisStruct, angle);\r
+        BRepBuilderAPI_Transform bt = new BRepBuilderAPI_Transform(aShape, theTransformation, true);\r
+        TopoDS_Shape shape = bt.shape();\r
+        bt.delete();\r
+        theTransformation.delete();\r
+        return shape;\r
+    }\r
+\r
+    public static TopoDS_Shape makeScale(TopoDS_Shape aShape, double s) {\r
+\r
+        GP_Trsf theTransformation = new GP_Trsf();\r
+        theTransformation.setValues(s, 0, 0, 0,\r
+                                           0, s, 0, 0, \r
+                                           0, 0, s, 0, 1, 1);\r
+        BRepBuilderAPI_Transform bt = new BRepBuilderAPI_Transform(aShape, theTransformation, true);\r
+        TopoDS_Shape shape = bt.shape();\r
+        bt.delete();\r
+        theTransformation.delete();\r
+        return shape;\r
+    }\r
+\r
+\r
+    public static TopoDS_Shape makeCylinder(double[] pointStruct, double[] dirStruct, double radius, double height) {\r
+        double[] axe = new double[6];\r
+        System.arraycopy(pointStruct, 0, axe, 0, 3);\r
+        System.arraycopy(dirStruct, 0, axe, 3, 3);\r
+        org.jcae.opencascade.jni.BRepPrimAPI_MakeCylinder cyl = new org.jcae.opencascade.jni.BRepPrimAPI_MakeCylinder(axe, radius, height, 2 * Math.PI);\r
+        org.jcae.opencascade.jni.TopoDS_Shape tds = cyl.shape();\r
+        cyl.delete();\r
+        return tds;\r
+    }\r
+\r
+    public static TopoDS_Shape makeCopy(TopoDS_Shape topoDS_Shape) {\r
+        throw new UnsupportedOperationException();\r
+    }\r
+\r
+    public static TopoDS_Shape makeCone(double[] pointStruct, double[] dirStruct, double radius1, double radius2, double height) {\r
+        double[] axe = new double[6];\r
+        System.arraycopy(pointStruct, 0, axe, 0, 3);\r
+        System.arraycopy(dirStruct, 0, axe, 3, 3);\r
+        org.jcae.opencascade.jni.BRepPrimAPI_MakeCone cone = new org.jcae.opencascade.jni.BRepPrimAPI_MakeCone(axe, radius1, radius2, height, 2 * Math.PI);\r
+        org.jcae.opencascade.jni.TopoDS_Shape tds = cone.shape();\r
+        cone.delete();\r
+        return tds;\r
+    }\r
+\r
+    public static TopoDS_Shape makeCompound(TopoDS_Shape[] shapes) {\r
+        BRep_Builder builder = new BRep_Builder();\r
+        org.jcae.opencascade.jni.TopoDS_Compound comp = new org.jcae.opencascade.jni.TopoDS_Compound();\r
+        builder.makeCompound(comp);\r
+        for (int i = 0; i < shapes.length; i++) {\r
+\r
+            builder.add(comp, shapes[i]);\r
+        }\r
+        builder.delete();\r
+        return comp;\r
+    }\r
+\r
+\r
+    public static TopoDS_Shape makeBox(double x1, double y1, double z1, double x2, double y2, double z2) {\r
+        double[] p1 = new double[] { x1, y1, z1 };\r
+        double[] p2 = new double[] { x2, y2, z2 };\r
+        org.jcae.opencascade.jni.BRepPrimAPI_MakeBox box = new org.jcae.opencascade.jni.BRepPrimAPI_MakeBox(p1, p2); \r
+        org.jcae.opencascade.jni.TopoDS_Shape tds = box.shape();\r
+        box.delete();\r
+        return tds;\r
+    }\r
+\r
+    public static TopoDS_Shape makeCut(TopoDS_Shape shape1, TopoDS_Shape shape2) {\r
+       org.jcae.opencascade.jni.BRepAlgoAPI_Cut cut = new org.jcae.opencascade.jni.BRepAlgoAPI_Cut(shape1, shape2);\r
+        org.jcae.opencascade.jni.TopoDS_Shape s = cut.shape();\r
+        cut.delete();\r
+        return s;\r
+    }\r
+    \r
+    public static TopoDS_Shape makeCommon(TopoDS_Shape shape1, TopoDS_Shape shape2) {\r
+       org.jcae.opencascade.jni.BRepAlgoAPI_Common common = new org.jcae.opencascade.jni.BRepAlgoAPI_Common(shape1, shape2); \r
+        org.jcae.opencascade.jni.TopoDS_Shape s = common.shape();\r
+        common.delete();\r
+        return s;\r
+    }\r
+    \r
+    public static TopoDS_Shape makeFuse(TopoDS_Shape shape1, TopoDS_Shape shape2) {\r
+       org.jcae.opencascade.jni.BRepAlgoAPI_Fuse fuse = new org.jcae.opencascade.jni.BRepAlgoAPI_Fuse(shape1, shape2);\r
+        org.jcae.opencascade.jni.TopoDS_Shape s = fuse.shape();\r
+        fuse.delete();\r
+        return s;\r
+    }\r
+\r
+    \r
+    public static TopoDS_Shape makeWedge(double[] pointStruct, double[] dirStruct,double dx, double dy, double dz, double xmin, double zmin, double xmax, double zmax) {\r
+        double[] axe = new double[6];\r
+        System.arraycopy(pointStruct, 0, axe, 0, 3);\r
+        System.arraycopy(dirStruct, 0, axe, 3, 3);\r
+        \r
+        org.jcae.opencascade.jni.BRepPrimAPI_MakeWedge wedge = new org.jcae.opencascade.jni.BRepPrimAPI_MakeWedge(axe,  dx,  dy,  dz,  xmin,  zmin, xmax, zmax); \r
+        org.jcae.opencascade.jni.TopoDS_Shape s = wedge.shape();\r
+        wedge.delete();\r
+        return s;\r
+    }\r
+    \r
+    public static TopoDS_Shape makeEllipticCylinder(double h, double r1, double r2) {\r
+       GP_Elips ellipse;\r
+               if (r1 < r2) {\r
+                       // FIXME : ellipse should be rotated, but current JNI won't allow it since Ax2 is not separate object\r
+                       ellipse = new GP_Elips(new double[]{0.0,-h*0.5,0.0,0.0,1.0,0.0},r2,r1);\r
+               } else {\r
+                       ellipse = new GP_Elips(new double[]{0.0,-h*0.5,0.0,0.0,1.0,0.0},r1,r2);\r
+               }\r
+               BRepBuilderAPI_MakeEdge edge = new BRepBuilderAPI_MakeEdge(ellipse);\r
+               TopoDS_Edge ed = (TopoDS_Edge) edge.shape();\r
+               BRepBuilderAPI_MakeWire wire = new BRepBuilderAPI_MakeWire(ed);\r
+               TopoDS_Wire w = (TopoDS_Wire) wire.shape();\r
+               BRepBuilderAPI_MakeFace face = new BRepBuilderAPI_MakeFace(w); \r
+        TopoDS_Face F = (TopoDS_Face) face.shape();\r
+        BRepPrimAPI_MakePrism prism = new BRepPrimAPI_MakePrism(F, new double[] { 0.0, h, 0.0 }); \r
+        TopoDS_Shape shape = prism.shape();\r
+        ellipse.delete();\r
+        edge.delete();\r
+        wire.delete();\r
+        face.delete();\r
+        ed.delete();\r
+        w.delete();\r
+        F.delete();\r
+        prism.delete();\r
+        return shape;\r
+    }\r
+\r
+    public static TopoDS_Shape makeReqularPrism(double h, double r, int n) {\r
+       if (n < 3)\r
+               n = 3;\r
+       Vector2d vertices[] = new Vector2d[n];\r
+               for (int i = 0; i < n; i++) {\r
+                       vertices[i] = new Vector2d(Math.sin(Math.PI * 2.0 * i / n)*r,Math.cos(Math.PI * 2.0 * i / n)*r);\r
+               }\r
+               BRepBuilderAPI_MakeWire wire = new BRepBuilderAPI_MakeWire();\r
+               for (int i = 0; i < n; i++) {\r
+                       Vector2d v1 = vertices[i];\r
+                       Vector2d v2 = vertices[(i+1)%n];\r
+                       BRepBuilderAPI_MakeEdge edge = new BRepBuilderAPI_MakeEdge(new double[]{v1.x,-h*0.5,v1.y},new double[]{v2.x,-h*0.5,v2.y}); \r
+                       wire.add((TopoDS_Edge)edge.shape());\r
+                       edge.delete();\r
+               }\r
+               TopoDS_Wire w = (TopoDS_Wire)wire.shape();\r
+               \r
+               BRepBuilderAPI_MakeFace face = new BRepBuilderAPI_MakeFace(w);\r
+               TopoDS_Face F = (TopoDS_Face) face.shape();\r
+               face.delete();\r
+               \r
+               BRepPrimAPI_MakePrism prism = new BRepPrimAPI_MakePrism(F, new double[] { 0.0, h, 0.0 }); \r
+        TopoDS_Shape shape = prism.shape();    \r
+        prism.delete();\r
+        \r
+        wire.delete();\r
+        w.delete();\r
+        F.delete();\r
+        return shape;\r
+    }\r
\r
+\r
+    public static void exportBREP(TopoDS_Shape shape, String filename) {\r
+        org.jcae.opencascade.jni.BRepTools.write(shape, filename);\r
+    }\r
+    \r
+}\r
diff --git a/org.simantics.opencascade/src/org/simantics/opencascade/ParametricSolidModelProvider.java b/org.simantics.opencascade/src/org/simantics/opencascade/ParametricSolidModelProvider.java
new file mode 100644 (file)
index 0000000..f066002
--- /dev/null
@@ -0,0 +1,11 @@
+package org.simantics.opencascade;\r
+\r
+import java.util.Map;\r
+\r
+public interface ParametricSolidModelProvider extends SolidModelProvider{\r
+       \r
+       public void setProperties(Map<String,Object> props);\r
+       \r
+       public void updateCalculatedProperties(Map<String,Object> returnProps);\r
+\r
+}\r
diff --git a/org.simantics.opencascade/src/org/simantics/opencascade/SolidModelProvider.java b/org.simantics.opencascade/src/org/simantics/opencascade/SolidModelProvider.java
new file mode 100644 (file)
index 0000000..bc45ec9
--- /dev/null
@@ -0,0 +1,11 @@
+package org.simantics.opencascade;\r
+\r
+import java.util.Collection;\r
+\r
+import org.jcae.opencascade.jni.TopoDS_Shape;\r
+\r
+public interface SolidModelProvider {\r
+\r
+       \r
+       public Collection<TopoDS_Shape> getModel()  throws Exception;\r
+}\r