From 477a3eae417fe71addfcf8f87dab41f87151a384 Mon Sep 17 00:00:00 2001 From: lehtonen Date: Sat, 20 Sep 2008 00:28:54 +0000 Subject: [PATCH] Moved 3D plug-ins to /3d/branches/dev. git-svn-id: https://www.simantics.org/svn/simantics/3d/branches/dev@6666 ac1ea38d-2e2b-0410-8846-a27921b304fc --- org.simantics.feature.proconf.g3d/.project | 17 + .../build.properties | 1 + org.simantics.feature.proconf.g3d/feature.xml | 88 ++ org.simantics.proconf.g3d.csg/.classpath | 7 + org.simantics.proconf.g3d.csg/.project | 28 + .../META-INF/MANIFEST.MF | 17 + .../build.properties | 4 + .../simantics/proconf/g3d/csg/Activator.java | 60 + org.simantics.proconf.g3d.occ/.classpath | 7 + org.simantics.proconf.g3d.occ/.project | 28 + .../META-INF/MANIFEST.MF | 21 + .../build.properties | 5 + org.simantics.proconf.g3d.occ/plugin.xml | 12 + .../simantics/proconf/g3d/occ/Activator.java | 75 + .../proconf/g3d/occ/OccResources.java | 20 + .../g3d/occ/geometry/IndexedGeometry.java | 81 + .../g3d/occ/geometry/OccTriangulator.java | 820 ++++++++++ .../g3d/occ/geometry/ViewableShapeImpl.java | 498 ++++++ .../.classpath | 7 + .../.project | 28 + .../META-INF/MANIFEST.MF | 33 + .../build.properties | 5 + .../icons/difference.png | Bin 0 -> 624 bytes .../icons/difference.svg | 87 ++ .../icons/intersection.png | Bin 0 -> 622 bytes .../icons/intersection.svg | 87 ++ .../icons/link.png | Bin 0 -> 439 bytes .../icons/link.svg | 145 ++ .../icons/union.png | Bin 0 -> 682 bytes .../icons/union.svg | 87 ++ .../icons/unlink.png | Bin 0 -> 484 bytes .../icons/unlink.svg | 126 ++ .../plugin.xml | 167 ++ .../proconf/g3d/shapeeditor/Activator.java | 95 ++ .../g3d/shapeeditor/ShapeEditorResources.java | 48 + .../g3d/shapeeditor/actions/ExportAction.java | 100 ++ .../g3d/shapeeditor/actions/ImportAction.java | 81 + .../shapeeditor/actions/LoadFileAction.java | 62 + .../shapeeditor/actions/LoadFolderAction.java | 100 ++ .../common/ViewpointGenerator.java | 196 +++ .../dialogs/PropertySelectionDialog.java | 112 ++ .../handlers/CSGProjectAdapter.java | 26 + .../shapeeditor/handlers/CSGProjectType.java | 57 + .../handlers/NewCSGModelHandler.java | 54 + .../handlers/ResourceEditorAdapter1.java | 46 + .../handlers/ResourceEditorAdapter3.java | 45 + .../perspectives/CSGModellingPerspective.java | 23 + .../shapeeditor/scenegraph/CSGShapeNode.java | 108 ++ .../tools/AnimationContribution.java | 774 ++++++++++ .../tools/CSGModellingContribution.java | 777 ++++++++++ .../tools/ParameterizationContribution.java | 680 +++++++++ .../shapeeditor/views/CSGModellingView.java | 33 + .../views/ParameterizationEditor.java | 587 +++++++ .../shapeeditor/views/ShapeEditorBase.java | 628 ++++++++ .../shapeeditor/views/ShapeEditorView.java | 36 + .../views/StructureOutlinePage.java | 21 + .../g3d/shapeeditor/views/StructureView.java | 44 + org.simantics.proconf.g3d/.classpath | 7 + org.simantics.proconf.g3d/.project | 28 + .../META-INF/MANIFEST.MF | 44 + org.simantics.proconf.g3d/build.properties | 5 + .../data/defaultfont.tga | Bin 0 -> 1048594 bytes org.simantics.proconf.g3d/icons/batch.png | Bin 0 -> 778 bytes org.simantics.proconf.g3d/icons/batch.svg | 100 ++ org.simantics.proconf.g3d/icons/delete.png | Bin 0 -> 479 bytes org.simantics.proconf.g3d/icons/delete.svg | 104 ++ org.simantics.proconf.g3d/icons/eye.png | Bin 0 -> 310 bytes org.simantics.proconf.g3d/icons/eye.svg | 122 ++ org.simantics.proconf.g3d/icons/ff.png | Bin 0 -> 472 bytes org.simantics.proconf.g3d/icons/ff.svg | 130 ++ org.simantics.proconf.g3d/icons/geometry.png | Bin 0 -> 942 bytes org.simantics.proconf.g3d/icons/geometry.svg | 100 ++ org.simantics.proconf.g3d/icons/node.png | Bin 0 -> 772 bytes org.simantics.proconf.g3d/icons/node.svg | 100 ++ org.simantics.proconf.g3d/icons/play.png | Bin 0 -> 530 bytes org.simantics.proconf.g3d/icons/play.svg | 127 ++ org.simantics.proconf.g3d/icons/rotate.png | Bin 0 -> 718 bytes org.simantics.proconf.g3d/icons/rotate.svg | 108 ++ org.simantics.proconf.g3d/icons/rw.png | Bin 0 -> 477 bytes org.simantics.proconf.g3d/icons/rw.svg | 130 ++ .../icons/silk/control_eject.png | Bin 0 -> 603 bytes .../icons/silk/control_eject_blue.png | Bin 0 -> 727 bytes .../icons/silk/control_end.png | Bin 0 -> 621 bytes .../icons/silk/control_end_blue.png | Bin 0 -> 737 bytes .../icons/silk/control_equalizer.png | Bin 0 -> 432 bytes .../icons/silk/control_equalizer_blue.png | Bin 0 -> 764 bytes .../icons/silk/control_fastforward.png | Bin 0 -> 607 bytes .../icons/silk/control_fastforward_blue.png | Bin 0 -> 736 bytes .../icons/silk/control_pause.png | Bin 0 -> 598 bytes .../icons/silk/control_pause_blue.png | Bin 0 -> 721 bytes .../icons/silk/control_play.png | Bin 0 -> 592 bytes .../icons/silk/control_play_blue.png | Bin 0 -> 717 bytes .../icons/silk/control_repeat.png | Bin 0 -> 422 bytes .../icons/silk/control_repeat_blue.png | Bin 0 -> 750 bytes .../icons/silk/control_rewind.png | Bin 0 -> 614 bytes .../icons/silk/control_rewind_blue.png | Bin 0 -> 745 bytes .../icons/silk/control_start.png | Bin 0 -> 604 bytes .../icons/silk/control_start_blue.png | Bin 0 -> 720 bytes .../icons/silk/control_stop.png | Bin 0 -> 403 bytes .../icons/silk/control_stop_blue.png | Bin 0 -> 695 bytes org.simantics.proconf.g3d/icons/silk/lock.png | Bin 0 -> 749 bytes .../icons/silk/lock_open.png | Bin 0 -> 727 bytes org.simantics.proconf.g3d/icons/stop.png | Bin 0 -> 426 bytes org.simantics.proconf.g3d/icons/stop.svg | 104 ++ org.simantics.proconf.g3d/icons/translate.png | Bin 0 -> 573 bytes org.simantics.proconf.g3d/icons/translate.svg | 117 ++ org.simantics.proconf.g3d/logging.properties | 54 + org.simantics.proconf.g3d/plugin.xml | 47 + .../schema/geometry.exsd | 112 ++ .../org/simantics/proconf/g3d/Activator.java | 94 ++ .../org/simantics/proconf/g3d/Resources.java | 45 + .../proconf/g3d/actions/CameraAction.java | 134 ++ .../actions/ConstrainedTransformAction.java | 74 + .../proconf/g3d/actions/ContextAction.java | 53 + .../g3d/actions/ContextActionFactory.java | 20 + .../g3d/actions/ContextActionRegistry.java | 54 + .../proconf/g3d/actions/FocusAction.java | 71 + .../g3d/actions/InteractiveAction.java | 64 + .../proconf/g3d/actions/ReadAction.java | 52 + .../g3d/actions/ReadInteractiveAction.java | 48 + .../proconf/g3d/actions/RemoveAction.java | 56 + .../proconf/g3d/actions/RotateAction.java | 453 ++++++ .../proconf/g3d/actions/TranslateAction.java | 422 ++++++ .../actions/TranslateActionConstraints.java | 147 ++ .../proconf/g3d/actions/WriteAction.java | 61 + .../g3d/actions/WriteInteractiveAction.java | 49 + .../animation/AbstractScalarInterpolator.java | 24 + .../proconf/g3d/animation/Animatable.java | 45 + .../proconf/g3d/animation/Animation.java | 33 + .../g3d/animation/AnimationController.java | 23 + .../g3d/animation/AnimationSystem.java | 94 ++ .../animation/AnimationSystemListener.java | 18 + .../animation/ChanneledColorInterpolator.java | 68 + .../ChanneledPositionInterpolator.java | 43 + .../g3d/animation/ConstantInterpolator.java | 27 + .../proconf/g3d/animation/Interpolator.java | 18 + .../ResourceAnimationController.java | 64 + .../g3d/animation/ScalarInterpolator.java | 17 + .../ScaledResourceAnimationController.java | 40 + .../g3d/animation/SlerpInterpolator.java | 47 + .../g3d/animation/TCBInterpolator.java | 27 + .../animation/TestAnimationController.java | 55 + .../animation/ui/AnimationControlCreator.java | 139 ++ .../proconf/g3d/base/AppearanceTools.java | 454 ++++++ .../proconf/g3d/base/Constraint.java | 19 + .../proconf/g3d/base/ConstraintDetector.java | 442 ++++++ .../proconf/g3d/base/EditorContribution.java | 70 + .../simantics/proconf/g3d/base/G3DAPI.java | 94 ++ .../simantics/proconf/g3d/base/G3DTools.java | 399 +++++ .../proconf/g3d/base/GeometryProvider.java | 50 + .../g3d/base/GeometryProviderRegistry.java | 77 + .../g3d/base/JmeRenderingComponent.java | 93 ++ .../simantics/proconf/g3d/base/MathTools.java | 395 +++++ .../g3d/base/ResourceTextureCache.java | 220 +++ .../proconf/g3d/base/ScenegraphAdapter.java | 122 ++ .../g3d/base/ScenegraphAdapterImpl.java | 828 ++++++++++ .../proconf/g3d/base/SelectionAdapter.java | 445 ++++++ .../g3d/base/ThreeDimensionalEditorBase.java | 741 +++++++++ .../g3d/base/ThreeDimensionalEditorPart.java | 205 +++ .../base/ThreeDimensionalEditorProvider.java | 25 + .../proconf/g3d/base/TransformationTools.java | 520 +++++++ .../proconf/g3d/base/VecmathJmeTools.java | 78 + .../g3d/base/VisualizationScheduler.java | 199 +++ .../proconf/g3d/common/JmeComposite.java | 112 ++ .../JmeSinglePassRenderingComponent.java | 411 +++++ .../proconf/g3d/common/OrbitalCamera.java | 205 +++ .../proconf/g3d/common/PropertyTester2.java | 18 + .../common/StructuredResourceSelection.java | 173 +++ .../proconf/g3d/dialogs/JMEDialog.java | 174 +++ .../proconf/g3d/dnd/DropListener.java | 23 + .../proconf/g3d/dnd/ShapeDropTarget.java | 124 ++ .../proconf/g3d/gizmo/AbstractGizmo.java | 198 +++ .../simantics/proconf/g3d/gizmo/Gizmo.java | 50 + .../g3d/gizmo/MultiSelectionGizmo.java | 110 ++ .../proconf/g3d/gizmo/RotateGizmo.java | 308 ++++ .../proconf/g3d/gizmo/TransformGizmo.java | 316 ++++ .../g3d/gizmo/TransformInlineGizmo.java | 215 +++ .../proconf/g3d/input/AWTInputProvider.java | 309 ++++ .../proconf/g3d/input/InputProvider.java | 72 + .../proconf/g3d/input/SWTInputProvider.java | 511 +++++++ .../g3d/preferences/G3DPreferencesPage.java | 121 ++ .../g3d/preferences/PreferenceConstants.java | 22 + .../preferences/PreferenceInitializer.java | 39 + .../g3d/scenegraph/AbstractGraphicsNode.java | 200 +++ .../proconf/g3d/scenegraph/IGeometryNode.java | 19 + .../proconf/g3d/scenegraph/IGraphicsNode.java | 44 + .../g3d/scenegraph/ISelectableNode.java | 22 + .../proconf/g3d/scenegraph/ModelNode.java | 195 +++ .../g3d/scenegraph/NonTransformableNode.java | 79 + .../scenegraph/ParameterizedModelNode.java | 188 +++ .../g3d/scenegraph/RootGraphicsNode.java | 77 + .../proconf/g3d/scenegraph/ShapeNode.java | 719 +++++++++ .../proconf/g3d/shapes/AxesShape.java | 51 + .../proconf/g3d/shapes/FloorShape.java | 91 ++ .../proconf/g3d/shapes/GridShape.java | 57 + .../simantics/proconf/g3d/shapes/Quad.java | 130 ++ .../g3d/tools/OEPathSelectionListener.java | 46 + .../g3d/tools/OESelectionListener.java | 44 + .../proconf/g3d/tools/PropertyTree.java | 313 ++++ .../g3d/tools/ScenegraphLockTraverser.java | 32 + .../proconf/g3d/views/AppearanceEditor.java | 1146 ++++++++++++++ .../proconf/g3d/views/ScenegraphViewPart.java | 610 ++++++++ .../g3d/views/SinglePageResourceEditor.java | 233 +++ .../g3d/views/SinglePageResourceView.java | 155 ++ .../.classpath | 7 + org.simantics.proconf.processeditor/.project | 28 + .../META-INF/MANIFEST.MF | 28 + .../build.properties | 5 + .../data/dcp.mtl | 2 + .../data/dcp.obj | 476 ++++++ .../icons/Component.png | Bin 0 -> 511 bytes .../icons/Component.svg | 128 ++ .../icons/Elbow.png | Bin 0 -> 668 bytes .../icons/Elbow.svg | 127 ++ .../icons/Nozzle.png | Bin 0 -> 421 bytes .../icons/Nozzle.svg | 110 ++ .../icons/Straight.png | Bin 0 -> 298 bytes .../icons/Straight.svg | 96 ++ .../icons/bubble.png | Bin 0 -> 1049 bytes .../icons/bubble.svg | 127 ++ .../icons/crosshair.png | Bin 0 -> 661 bytes .../icons/crosshair.svg | 78 + .../icons/factory.png | Bin 0 -> 468 bytes .../icons/factory.svg | 308 ++++ .../icons/middle.png | Bin 0 -> 2273 bytes .../icons/middle.svg | 190 +++ .../icons/plus.png | Bin 0 -> 2098 bytes .../icons/plus.svg | 184 +++ .../icons/tank.png | Bin 0 -> 428 bytes .../icons/tank.svg | 184 +++ .../icons/translate_d.png | Bin 0 -> 363 bytes .../icons/translate_d.svg | 118 ++ .../icons/x-axis.png | Bin 0 -> 380 bytes .../icons/x-axis.svg | 82 + .../icons/x-plane.png | Bin 0 -> 439 bytes .../icons/x-plane.svg | 89 ++ .../icons/y-axis.png | Bin 0 -> 340 bytes .../icons/y-axis.svg | 83 + .../icons/y-plane.png | Bin 0 -> 371 bytes .../icons/y-plane.svg | 89 ++ .../icons/z-axis.png | Bin 0 -> 357 bytes .../icons/z-axis.svg | 83 + .../icons/z-plane.png | Bin 0 -> 422 bytes .../icons/z-plane.svg | 89 ++ .../plugin.xml | 266 ++++ .../simantics/processeditor/Activator.java | 97 ++ .../processeditor/ProcessResource.java | 43 + .../actions/InsertComponentAction.java | 403 +++++ .../actions/InsertEquipmentAction.java | 115 ++ .../actions/InsertNozzleAction.java | 139 ++ .../processeditor/actions/PositionType.java | 15 + .../actions/ReversePipelineAction.java | 57 + .../actions/RoutePipeAction.java | 1342 +++++++++++++++++ .../actions/SelectSplitPointAction.java | 135 ++ .../actions/SplitPointListener.java | 19 + .../actions/TranslateElbowAction.java | 232 +++ .../TranslateInlineComponentAction.java | 234 +++ .../actions/TranslateStraightAction.java | 404 +++++ .../InlineComponentConstraintAdapter.java | 36 + .../adapters/NozzleConstraintAdapter.java | 32 + .../TurnComponentConstraintAdapter.java | 42 + .../animations/PipeAnimationController.java | 141 ++ .../animations/PipeFlowAnimation.java | 144 ++ .../ResourcePipeAnimationController.java | 72 + .../common/ControlPointTools.java | 1198 +++++++++++++++ .../processeditor/common/PathUtils.java | 145 ++ .../common/PipeComponentProvider.java | 531 +++++++ .../processeditor/common/PipingRules.java | 1134 ++++++++++++++ .../processeditor/common/PipingTools.java | 225 +++ .../processeditor/common/PipingTools2.java | 668 ++++++++ .../dialogs/ConfigureAnimationDialog.java | 478 ++++++ .../dialogs/ConfigureMonitorDialog.java | 309 ++++ .../ConfigurePipelineAnimationDialog.java | 315 ++++ .../dialogs/EquipmentDialog.java | 27 + .../dialogs/LibraryComponentDialog.java | 195 +++ .../processeditor/dialogs/NozzleDialog.java | 27 + .../dialogs/PipelineComponentDialog.java | 34 + .../processeditor/dialogs/PipelineDialog.java | 132 ++ .../gizmo/PositionSelectionGizmo.java | 177 +++ .../handlers/EquipmentEditorAdapter.java | 40 + .../handlers/NewComponentHandler.java | 290 ++++ .../handlers/NewEquipmentHandler.java | 110 ++ .../handlers/NewPlantHandler.java | 95 ++ .../PipelineComponentEditorAdapter.java | 45 + .../handlers/Plant3DEditorAdapter.java | 34 + .../handlers/Plant3DProjectAdapter.java | 14 + .../handlers/Plant3DProjectType.java | 53 + .../monitors/BillboardMonitor.java | 216 +++ .../processeditor/monitors/Monitor.java | 62 + .../monitors/MonitorTextProvider.java | 23 + .../monitors/ObjectPropertyProvider.java | 64 + .../processeditor/monitors/PathContainer.java | 61 + .../ResourcePathPropertyProvider.java | 87 ++ .../processeditor/monitors/TextMonitor.java | 272 ++++ .../Plant3DModellingPerspective.java | 13 + .../perspectives/ViewpointGenerator.java | 108 ++ .../scenegraph/NonVisibleNode.java | 29 + .../scenegraph/PipeComponentNode.java | 107 ++ .../processeditor/scenegraph/PipeRunNode.java | 29 + .../scenegraph/PipelineComponentNode.java | 87 ++ .../tools/ControlPointContribution.java | 431 ++++++ .../tools/NozzleContribution.java | 129 ++ .../tools/PlantEditContribution.java | 330 ++++ .../tools/PlantVisualizationContribution.java | 376 +++++ .../views/EquipmentEditorPart.java | 46 + .../views/PipelineComponentEditorPart.java | 46 + .../views/PlantStructureOutlinePage.java | 27 + .../views/PlantStructureView.java | 22 + .../processeditor/views/ProcessEditor.java | 704 +++++++++ .../views/ProcessEditorPart.java | 25 + 310 files changed, 41199 insertions(+) create mode 100644 org.simantics.feature.proconf.g3d/.project create mode 100644 org.simantics.feature.proconf.g3d/build.properties create mode 100644 org.simantics.feature.proconf.g3d/feature.xml create mode 100644 org.simantics.proconf.g3d.csg/.classpath create mode 100644 org.simantics.proconf.g3d.csg/.project create mode 100644 org.simantics.proconf.g3d.csg/META-INF/MANIFEST.MF create mode 100644 org.simantics.proconf.g3d.csg/build.properties create mode 100644 org.simantics.proconf.g3d.csg/src/org/simantics/proconf/g3d/csg/Activator.java create mode 100644 org.simantics.proconf.g3d.occ/.classpath create mode 100644 org.simantics.proconf.g3d.occ/.project create mode 100644 org.simantics.proconf.g3d.occ/META-INF/MANIFEST.MF create mode 100644 org.simantics.proconf.g3d.occ/build.properties create mode 100644 org.simantics.proconf.g3d.occ/plugin.xml create mode 100644 org.simantics.proconf.g3d.occ/src/org/simantics/proconf/g3d/occ/Activator.java create mode 100644 org.simantics.proconf.g3d.occ/src/org/simantics/proconf/g3d/occ/OccResources.java create mode 100644 org.simantics.proconf.g3d.occ/src/org/simantics/proconf/g3d/occ/geometry/IndexedGeometry.java create mode 100644 org.simantics.proconf.g3d.occ/src/org/simantics/proconf/g3d/occ/geometry/OccTriangulator.java create mode 100644 org.simantics.proconf.g3d.occ/src/org/simantics/proconf/g3d/occ/geometry/ViewableShapeImpl.java create mode 100644 org.simantics.proconf.g3d.shapeeditor/.classpath create mode 100644 org.simantics.proconf.g3d.shapeeditor/.project create mode 100644 org.simantics.proconf.g3d.shapeeditor/META-INF/MANIFEST.MF create mode 100644 org.simantics.proconf.g3d.shapeeditor/build.properties create mode 100644 org.simantics.proconf.g3d.shapeeditor/icons/difference.png create mode 100644 org.simantics.proconf.g3d.shapeeditor/icons/difference.svg create mode 100644 org.simantics.proconf.g3d.shapeeditor/icons/intersection.png create mode 100644 org.simantics.proconf.g3d.shapeeditor/icons/intersection.svg create mode 100644 org.simantics.proconf.g3d.shapeeditor/icons/link.png create mode 100644 org.simantics.proconf.g3d.shapeeditor/icons/link.svg create mode 100644 org.simantics.proconf.g3d.shapeeditor/icons/union.png create mode 100644 org.simantics.proconf.g3d.shapeeditor/icons/union.svg create mode 100644 org.simantics.proconf.g3d.shapeeditor/icons/unlink.png create mode 100644 org.simantics.proconf.g3d.shapeeditor/icons/unlink.svg create mode 100644 org.simantics.proconf.g3d.shapeeditor/plugin.xml create mode 100644 org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/Activator.java create mode 100644 org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/ShapeEditorResources.java create mode 100644 org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/actions/ExportAction.java create mode 100644 org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/actions/ImportAction.java create mode 100644 org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/actions/LoadFileAction.java create mode 100644 org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/actions/LoadFolderAction.java create mode 100644 org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/common/ViewpointGenerator.java create mode 100644 org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/dialogs/PropertySelectionDialog.java create mode 100644 org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/handlers/CSGProjectAdapter.java create mode 100644 org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/handlers/CSGProjectType.java create mode 100644 org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/handlers/NewCSGModelHandler.java create mode 100644 org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/handlers/ResourceEditorAdapter1.java create mode 100644 org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/handlers/ResourceEditorAdapter3.java create mode 100644 org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/perspectives/CSGModellingPerspective.java create mode 100644 org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/scenegraph/CSGShapeNode.java create mode 100644 org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/tools/AnimationContribution.java create mode 100644 org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/tools/CSGModellingContribution.java create mode 100644 org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/tools/ParameterizationContribution.java create mode 100644 org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/views/CSGModellingView.java create mode 100644 org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/views/ParameterizationEditor.java create mode 100644 org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/views/ShapeEditorBase.java create mode 100644 org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/views/ShapeEditorView.java create mode 100644 org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/views/StructureOutlinePage.java create mode 100644 org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/views/StructureView.java create mode 100644 org.simantics.proconf.g3d/.classpath create mode 100644 org.simantics.proconf.g3d/.project create mode 100644 org.simantics.proconf.g3d/META-INF/MANIFEST.MF create mode 100644 org.simantics.proconf.g3d/build.properties create mode 100644 org.simantics.proconf.g3d/data/defaultfont.tga create mode 100644 org.simantics.proconf.g3d/icons/batch.png create mode 100644 org.simantics.proconf.g3d/icons/batch.svg create mode 100644 org.simantics.proconf.g3d/icons/delete.png create mode 100644 org.simantics.proconf.g3d/icons/delete.svg create mode 100644 org.simantics.proconf.g3d/icons/eye.png create mode 100644 org.simantics.proconf.g3d/icons/eye.svg create mode 100644 org.simantics.proconf.g3d/icons/ff.png create mode 100644 org.simantics.proconf.g3d/icons/ff.svg create mode 100644 org.simantics.proconf.g3d/icons/geometry.png create mode 100644 org.simantics.proconf.g3d/icons/geometry.svg create mode 100644 org.simantics.proconf.g3d/icons/node.png create mode 100644 org.simantics.proconf.g3d/icons/node.svg create mode 100644 org.simantics.proconf.g3d/icons/play.png create mode 100644 org.simantics.proconf.g3d/icons/play.svg create mode 100644 org.simantics.proconf.g3d/icons/rotate.png create mode 100644 org.simantics.proconf.g3d/icons/rotate.svg create mode 100644 org.simantics.proconf.g3d/icons/rw.png create mode 100644 org.simantics.proconf.g3d/icons/rw.svg create mode 100644 org.simantics.proconf.g3d/icons/silk/control_eject.png create mode 100644 org.simantics.proconf.g3d/icons/silk/control_eject_blue.png create mode 100644 org.simantics.proconf.g3d/icons/silk/control_end.png create mode 100644 org.simantics.proconf.g3d/icons/silk/control_end_blue.png create mode 100644 org.simantics.proconf.g3d/icons/silk/control_equalizer.png create mode 100644 org.simantics.proconf.g3d/icons/silk/control_equalizer_blue.png create mode 100644 org.simantics.proconf.g3d/icons/silk/control_fastforward.png create mode 100644 org.simantics.proconf.g3d/icons/silk/control_fastforward_blue.png create mode 100644 org.simantics.proconf.g3d/icons/silk/control_pause.png create mode 100644 org.simantics.proconf.g3d/icons/silk/control_pause_blue.png create mode 100644 org.simantics.proconf.g3d/icons/silk/control_play.png create mode 100644 org.simantics.proconf.g3d/icons/silk/control_play_blue.png create mode 100644 org.simantics.proconf.g3d/icons/silk/control_repeat.png create mode 100644 org.simantics.proconf.g3d/icons/silk/control_repeat_blue.png create mode 100644 org.simantics.proconf.g3d/icons/silk/control_rewind.png create mode 100644 org.simantics.proconf.g3d/icons/silk/control_rewind_blue.png create mode 100644 org.simantics.proconf.g3d/icons/silk/control_start.png create mode 100644 org.simantics.proconf.g3d/icons/silk/control_start_blue.png create mode 100644 org.simantics.proconf.g3d/icons/silk/control_stop.png create mode 100644 org.simantics.proconf.g3d/icons/silk/control_stop_blue.png create mode 100644 org.simantics.proconf.g3d/icons/silk/lock.png create mode 100644 org.simantics.proconf.g3d/icons/silk/lock_open.png create mode 100644 org.simantics.proconf.g3d/icons/stop.png create mode 100644 org.simantics.proconf.g3d/icons/stop.svg create mode 100644 org.simantics.proconf.g3d/icons/translate.png create mode 100644 org.simantics.proconf.g3d/icons/translate.svg create mode 100644 org.simantics.proconf.g3d/logging.properties create mode 100644 org.simantics.proconf.g3d/plugin.xml create mode 100644 org.simantics.proconf.g3d/schema/geometry.exsd create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/Activator.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/Resources.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/CameraAction.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/ConstrainedTransformAction.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/ContextAction.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/ContextActionFactory.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/ContextActionRegistry.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/FocusAction.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/InteractiveAction.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/ReadAction.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/ReadInteractiveAction.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/RemoveAction.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/RotateAction.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/TranslateAction.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/TranslateActionConstraints.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/WriteAction.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/WriteInteractiveAction.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/AbstractScalarInterpolator.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/Animatable.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/Animation.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/AnimationController.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/AnimationSystem.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/AnimationSystemListener.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/ChanneledColorInterpolator.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/ChanneledPositionInterpolator.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/ConstantInterpolator.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/Interpolator.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/ResourceAnimationController.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/ScalarInterpolator.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/ScaledResourceAnimationController.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/SlerpInterpolator.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/TCBInterpolator.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/TestAnimationController.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/ui/AnimationControlCreator.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/AppearanceTools.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/Constraint.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/ConstraintDetector.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/EditorContribution.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/G3DAPI.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/G3DTools.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/GeometryProvider.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/GeometryProviderRegistry.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/JmeRenderingComponent.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/MathTools.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/ResourceTextureCache.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/ScenegraphAdapter.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/ScenegraphAdapterImpl.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/SelectionAdapter.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/ThreeDimensionalEditorBase.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/ThreeDimensionalEditorPart.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/ThreeDimensionalEditorProvider.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/TransformationTools.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/VecmathJmeTools.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/VisualizationScheduler.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/common/JmeComposite.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/common/JmeSinglePassRenderingComponent.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/common/OrbitalCamera.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/common/PropertyTester2.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/common/StructuredResourceSelection.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/dialogs/JMEDialog.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/dnd/DropListener.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/dnd/ShapeDropTarget.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/gizmo/AbstractGizmo.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/gizmo/Gizmo.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/gizmo/MultiSelectionGizmo.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/gizmo/RotateGizmo.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/gizmo/TransformGizmo.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/gizmo/TransformInlineGizmo.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/input/AWTInputProvider.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/input/InputProvider.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/input/SWTInputProvider.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/preferences/G3DPreferencesPage.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/preferences/PreferenceConstants.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/preferences/PreferenceInitializer.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/AbstractGraphicsNode.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/IGeometryNode.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/IGraphicsNode.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/ISelectableNode.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/ModelNode.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/NonTransformableNode.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/ParameterizedModelNode.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/RootGraphicsNode.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/ShapeNode.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/shapes/AxesShape.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/shapes/FloorShape.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/shapes/GridShape.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/shapes/Quad.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/tools/OEPathSelectionListener.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/tools/OESelectionListener.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/tools/PropertyTree.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/tools/ScenegraphLockTraverser.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/views/AppearanceEditor.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/views/ScenegraphViewPart.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/views/SinglePageResourceEditor.java create mode 100644 org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/views/SinglePageResourceView.java create mode 100644 org.simantics.proconf.processeditor/.classpath create mode 100644 org.simantics.proconf.processeditor/.project create mode 100644 org.simantics.proconf.processeditor/META-INF/MANIFEST.MF create mode 100644 org.simantics.proconf.processeditor/build.properties create mode 100644 org.simantics.proconf.processeditor/data/dcp.mtl create mode 100644 org.simantics.proconf.processeditor/data/dcp.obj create mode 100644 org.simantics.proconf.processeditor/icons/Component.png create mode 100644 org.simantics.proconf.processeditor/icons/Component.svg create mode 100644 org.simantics.proconf.processeditor/icons/Elbow.png create mode 100644 org.simantics.proconf.processeditor/icons/Elbow.svg create mode 100644 org.simantics.proconf.processeditor/icons/Nozzle.png create mode 100644 org.simantics.proconf.processeditor/icons/Nozzle.svg create mode 100644 org.simantics.proconf.processeditor/icons/Straight.png create mode 100644 org.simantics.proconf.processeditor/icons/Straight.svg create mode 100644 org.simantics.proconf.processeditor/icons/bubble.png create mode 100644 org.simantics.proconf.processeditor/icons/bubble.svg create mode 100644 org.simantics.proconf.processeditor/icons/crosshair.png create mode 100644 org.simantics.proconf.processeditor/icons/crosshair.svg create mode 100644 org.simantics.proconf.processeditor/icons/factory.png create mode 100644 org.simantics.proconf.processeditor/icons/factory.svg create mode 100644 org.simantics.proconf.processeditor/icons/middle.png create mode 100644 org.simantics.proconf.processeditor/icons/middle.svg create mode 100644 org.simantics.proconf.processeditor/icons/plus.png create mode 100644 org.simantics.proconf.processeditor/icons/plus.svg create mode 100644 org.simantics.proconf.processeditor/icons/tank.png create mode 100644 org.simantics.proconf.processeditor/icons/tank.svg create mode 100644 org.simantics.proconf.processeditor/icons/translate_d.png create mode 100644 org.simantics.proconf.processeditor/icons/translate_d.svg create mode 100644 org.simantics.proconf.processeditor/icons/x-axis.png create mode 100644 org.simantics.proconf.processeditor/icons/x-axis.svg create mode 100644 org.simantics.proconf.processeditor/icons/x-plane.png create mode 100644 org.simantics.proconf.processeditor/icons/x-plane.svg create mode 100644 org.simantics.proconf.processeditor/icons/y-axis.png create mode 100644 org.simantics.proconf.processeditor/icons/y-axis.svg create mode 100644 org.simantics.proconf.processeditor/icons/y-plane.png create mode 100644 org.simantics.proconf.processeditor/icons/y-plane.svg create mode 100644 org.simantics.proconf.processeditor/icons/z-axis.png create mode 100644 org.simantics.proconf.processeditor/icons/z-axis.svg create mode 100644 org.simantics.proconf.processeditor/icons/z-plane.png create mode 100644 org.simantics.proconf.processeditor/icons/z-plane.svg create mode 100644 org.simantics.proconf.processeditor/plugin.xml create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/Activator.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/ProcessResource.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/InsertComponentAction.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/InsertEquipmentAction.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/InsertNozzleAction.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/PositionType.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/ReversePipelineAction.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/RoutePipeAction.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/SelectSplitPointAction.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/SplitPointListener.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/TranslateElbowAction.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/TranslateInlineComponentAction.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/TranslateStraightAction.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/adapters/InlineComponentConstraintAdapter.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/adapters/NozzleConstraintAdapter.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/adapters/TurnComponentConstraintAdapter.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/animations/PipeAnimationController.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/animations/PipeFlowAnimation.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/animations/ResourcePipeAnimationController.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/ControlPointTools.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/PathUtils.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/PipeComponentProvider.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/PipingRules.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/PipingTools.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/PipingTools2.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/ConfigureAnimationDialog.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/ConfigureMonitorDialog.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/ConfigurePipelineAnimationDialog.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/EquipmentDialog.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/LibraryComponentDialog.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/NozzleDialog.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/PipelineComponentDialog.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/PipelineDialog.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/gizmo/PositionSelectionGizmo.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/EquipmentEditorAdapter.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/NewComponentHandler.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/NewEquipmentHandler.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/NewPlantHandler.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/PipelineComponentEditorAdapter.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/Plant3DEditorAdapter.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/Plant3DProjectAdapter.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/Plant3DProjectType.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/BillboardMonitor.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/Monitor.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/MonitorTextProvider.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/ObjectPropertyProvider.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/PathContainer.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/ResourcePathPropertyProvider.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/TextMonitor.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/perspectives/Plant3DModellingPerspective.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/perspectives/ViewpointGenerator.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/scenegraph/NonVisibleNode.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/scenegraph/PipeComponentNode.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/scenegraph/PipeRunNode.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/scenegraph/PipelineComponentNode.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/tools/ControlPointContribution.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/tools/NozzleContribution.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/tools/PlantEditContribution.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/tools/PlantVisualizationContribution.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/EquipmentEditorPart.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/PipelineComponentEditorPart.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/PlantStructureOutlinePage.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/PlantStructureView.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/ProcessEditor.java create mode 100644 org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/ProcessEditorPart.java diff --git a/org.simantics.feature.proconf.g3d/.project b/org.simantics.feature.proconf.g3d/.project new file mode 100644 index 00000000..8bf470cd --- /dev/null +++ b/org.simantics.feature.proconf.g3d/.project @@ -0,0 +1,17 @@ + + + org.simantics.feature.proconf.g3d + + + + + + org.eclipse.pde.FeatureBuilder + + + + + + org.eclipse.pde.FeatureNature + + diff --git a/org.simantics.feature.proconf.g3d/build.properties b/org.simantics.feature.proconf.g3d/build.properties new file mode 100644 index 00000000..82ab19c6 --- /dev/null +++ b/org.simantics.feature.proconf.g3d/build.properties @@ -0,0 +1 @@ +bin.includes = feature.xml diff --git a/org.simantics.feature.proconf.g3d/feature.xml b/org.simantics.feature.proconf.g3d/feature.xml new file mode 100644 index 00000000..9f6f62db --- /dev/null +++ b/org.simantics.feature.proconf.g3d/feature.xml @@ -0,0 +1,88 @@ + + + + + [Enter Feature Description here.] + + + + [Enter Copyright Description here.] + + + + [Enter License Description here.] + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.simantics.proconf.g3d.csg/.classpath b/org.simantics.proconf.g3d.csg/.classpath new file mode 100644 index 00000000..02159672 --- /dev/null +++ b/org.simantics.proconf.g3d.csg/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/org.simantics.proconf.g3d.csg/.project b/org.simantics.proconf.g3d.csg/.project new file mode 100644 index 00000000..f4e22d78 --- /dev/null +++ b/org.simantics.proconf.g3d.csg/.project @@ -0,0 +1,28 @@ + + + org.simantics.proconf.g3d.csg + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/org.simantics.proconf.g3d.csg/META-INF/MANIFEST.MF b/org.simantics.proconf.g3d.csg/META-INF/MANIFEST.MF new file mode 100644 index 00000000..cbca8234 --- /dev/null +++ b/org.simantics.proconf.g3d.csg/META-INF/MANIFEST.MF @@ -0,0 +1,17 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Csg Plug-in +Bundle-SymbolicName: org.simantics.proconf.g3d.csg +Bundle-Version: 1.0.0 +Bundle-Activator: org.simantics.proconf.g3d.csg.Activator +Bundle-Vendor: VTT +Require-Bundle: org.eclipse.ui, + org.eclipse.core.runtime, + org.simantics.proconf.g3d, + org.simantics.g2d.stubs, + org.simantics.db, + org.simantics.layer0.utils, + org.simantics.layer0.stubs, + org.simantics.utils.datastructures +ipse-LazyStart: true +Export-Package: org.simantics.proconf.g3d.csg.stubs diff --git a/org.simantics.proconf.g3d.csg/build.properties b/org.simantics.proconf.g3d.csg/build.properties new file mode 100644 index 00000000..41eb6ade --- /dev/null +++ b/org.simantics.proconf.g3d.csg/build.properties @@ -0,0 +1,4 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + . diff --git a/org.simantics.proconf.g3d.csg/src/org/simantics/proconf/g3d/csg/Activator.java b/org.simantics.proconf.g3d.csg/src/org/simantics/proconf/g3d/csg/Activator.java new file mode 100644 index 00000000..9a0c1261 --- /dev/null +++ b/org.simantics.proconf.g3d.csg/src/org/simantics/proconf/g3d/csg/Activator.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.csg; + +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.BundleContext; + +/** + * The activator class controls the plug-in life cycle + */ +public class Activator extends AbstractUIPlugin { + + // The plug-in ID + public static final String PLUGIN_ID = "fi.vtt.simantics.proconf.g3d.csg"; + + // The shared instance + private static Activator plugin; + + /** + * The constructor + */ + public Activator() { + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext) + */ + public void start(BundleContext context) throws Exception { + super.start(context); + plugin = this; + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext) + */ + public void stop(BundleContext context) throws Exception { + plugin = null; + super.stop(context); + } + + /** + * Returns the shared instance + * + * @return the shared instance + */ + public static Activator getDefault() { + return plugin; + } + +} diff --git a/org.simantics.proconf.g3d.occ/.classpath b/org.simantics.proconf.g3d.occ/.classpath new file mode 100644 index 00000000..02159672 --- /dev/null +++ b/org.simantics.proconf.g3d.occ/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/org.simantics.proconf.g3d.occ/.project b/org.simantics.proconf.g3d.occ/.project new file mode 100644 index 00000000..83bfecce --- /dev/null +++ b/org.simantics.proconf.g3d.occ/.project @@ -0,0 +1,28 @@ + + + org.simantics.proconf.g3d.occ + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/org.simantics.proconf.g3d.occ/META-INF/MANIFEST.MF b/org.simantics.proconf.g3d.occ/META-INF/MANIFEST.MF new file mode 100644 index 00000000..82853e1c --- /dev/null +++ b/org.simantics.proconf.g3d.occ/META-INF/MANIFEST.MF @@ -0,0 +1,21 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: G3D OpenCascade Plug-in +Bundle-SymbolicName: org.simantics.proconf.g3d.occ;singleton:=true +Bundle-Version: 1.0.0 +Bundle-Activator: org.simantics.proconf.g3d.occ.Activator +Bundle-Vendor: VTT +Require-Bundle: org.eclipse.ui, + org.eclipse.core.runtime, + org.simantics.proconf.g3d, + com.jme.eclipse, + javax.vecmath, + org.jcae.opencascade.jni, + org.simantics.db, + org.simantics.layer0.stubs, + org.simantics.layer0.utils, + org.simantics.utils, + org.simantics.proconf.ui, + org.simantics.proconf.g3d.csg +Eclipse-LazyStart: true +Export-Package: org.simantics.proconf.g3d.occ.geometry diff --git a/org.simantics.proconf.g3d.occ/build.properties b/org.simantics.proconf.g3d.occ/build.properties new file mode 100644 index 00000000..6f20375d --- /dev/null +++ b/org.simantics.proconf.g3d.occ/build.properties @@ -0,0 +1,5 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + plugin.xml diff --git a/org.simantics.proconf.g3d.occ/plugin.xml b/org.simantics.proconf.g3d.occ/plugin.xml new file mode 100644 index 00000000..3784ffec --- /dev/null +++ b/org.simantics.proconf.g3d.occ/plugin.xml @@ -0,0 +1,12 @@ + + + + + + + + + diff --git a/org.simantics.proconf.g3d.occ/src/org/simantics/proconf/g3d/occ/Activator.java b/org.simantics.proconf.g3d.occ/src/org/simantics/proconf/g3d/occ/Activator.java new file mode 100644 index 00000000..a4f7cd42 --- /dev/null +++ b/org.simantics.proconf.g3d.occ/src/org/simantics/proconf/g3d/occ/Activator.java @@ -0,0 +1,75 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.occ; + +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.BundleContext; +import org.simantics.proconf.g3d.csg.stubs.CSGResource; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.proconf.g3d.stubs.G3DResource; +import org.simantics.proconf.ui.ProConfUI; + +/** + * The activator class controls the plug-in life cycle + */ +public class Activator extends AbstractUIPlugin { + + // The plug-in ID + public static final String PLUGIN_ID = "org.simantics.proconf.g3d.occ"; + + // The shared instance + private static Activator plugin; + + /** + * The constructor + */ + public Activator() { + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext) + */ + public void start(BundleContext context) throws Exception { + super.start(context); + plugin = this; + + ProConfUI.getSession().syncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + OccResources.csgResource = CSGResource.getInstance(g); + OccResources.g3dResource = G3DResource.getInstance(g); + return GraphRequestStatus.transactionComplete(); + } + }); + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext) + */ + public void stop(BundleContext context) throws Exception { + plugin = null; + super.stop(context); + } + + /** + * Returns the shared instance + * + * @return the shared instance + */ + public static Activator getDefault() { + return plugin; + } + +} diff --git a/org.simantics.proconf.g3d.occ/src/org/simantics/proconf/g3d/occ/OccResources.java b/org.simantics.proconf.g3d.occ/src/org/simantics/proconf/g3d/occ/OccResources.java new file mode 100644 index 00000000..1023fb66 --- /dev/null +++ b/org.simantics.proconf.g3d.occ/src/org/simantics/proconf/g3d/occ/OccResources.java @@ -0,0 +1,20 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.occ; + +import org.simantics.proconf.g3d.csg.stubs.CSGResource; +import org.simantics.proconf.g3d.stubs.G3DResource; + + +public class OccResources { + public static CSGResource csgResource; + public static G3DResource g3dResource; +} diff --git a/org.simantics.proconf.g3d.occ/src/org/simantics/proconf/g3d/occ/geometry/IndexedGeometry.java b/org.simantics.proconf.g3d.occ/src/org/simantics/proconf/g3d/occ/geometry/IndexedGeometry.java new file mode 100644 index 00000000..cf3732d8 --- /dev/null +++ b/org.simantics.proconf.g3d.occ/src/org/simantics/proconf/g3d/occ/geometry/IndexedGeometry.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.occ.geometry; + + +public class IndexedGeometry +{ + private float[] coordinates=new float[0]; + private float[] tcoordinates=new float[0]; + private float[] normals=new float[0]; + private int[] indices = new int[0]; + private float[] colors=new float[0]; + + public IndexedGeometry() + { + } + + + + public int[] getIndices() + { + return indices; + } + + public float[] getCoordinates() + { + return coordinates; + } + + public float[] getTCoordinates() + { + return tcoordinates; + } + + + public void setIndices(int[] value) + { + indices=value; + } + + public void setCoordinates(float[] value) + { + coordinates=value; + } + + public void setTCoordinates(float[] value) + { + tcoordinates=value; + } + + public float[] getColors() + { + return colors; + } + + public void setColors(float[] arg) + { + colors=arg; + } + + + public float[] getNormals() + { + return normals; + } + + public void setNormals(float[] arg) + { + normals=arg; + } + + +} diff --git a/org.simantics.proconf.g3d.occ/src/org/simantics/proconf/g3d/occ/geometry/OccTriangulator.java b/org.simantics.proconf.g3d.occ/src/org/simantics/proconf/g3d/occ/geometry/OccTriangulator.java new file mode 100644 index 00000000..ca5af06a --- /dev/null +++ b/org.simantics.proconf.g3d.occ/src/org/simantics/proconf/g3d/occ/geometry/OccTriangulator.java @@ -0,0 +1,820 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.occ.geometry; + +import java.io.IOException; +import java.util.Collection; + +import javax.vecmath.AxisAngle4d; +import javax.vecmath.Tuple3d; +import javax.vecmath.Vector2d; + +import org.jcae.opencascade.jni.BRepBuilderAPI_MakeEdge; +import org.jcae.opencascade.jni.BRepBuilderAPI_MakeFace; +import org.jcae.opencascade.jni.BRepBuilderAPI_MakeWire; +import org.jcae.opencascade.jni.BRepBuilderAPI_Transform; +import org.jcae.opencascade.jni.BRepOffsetAPI_ThruSections; +import org.jcae.opencascade.jni.BRepPrimAPI_MakePrism; +import org.jcae.opencascade.jni.BRepPrimAPI_MakeRevol; +import org.jcae.opencascade.jni.BRepPrimAPI_MakeTorus; +import org.jcae.opencascade.jni.BRep_Builder; +import org.jcae.opencascade.jni.GC_MakeArcOfCircle; +import org.jcae.opencascade.jni.GC_MakeSegment; +import org.jcae.opencascade.jni.GP_Elips; +import org.jcae.opencascade.jni.GP_Trsf; +import org.jcae.opencascade.jni.TopoDS_Edge; +import org.jcae.opencascade.jni.TopoDS_Face; +import org.jcae.opencascade.jni.TopoDS_Shape; +import org.jcae.opencascade.jni.TopoDS_Wire; +import org.simantics.proconf.g3d.csg.stubs.Barrel; +import org.simantics.proconf.g3d.csg.stubs.BooleanOperation; +import org.simantics.proconf.g3d.csg.stubs.Box; +import org.simantics.proconf.g3d.csg.stubs.CSGShape; +import org.simantics.proconf.g3d.csg.stubs.Cone; +import org.simantics.proconf.g3d.csg.stubs.Cylinder; +import org.simantics.proconf.g3d.csg.stubs.EllipticCylinder; +import org.simantics.proconf.g3d.csg.stubs.RectangularSolid; +import org.simantics.proconf.g3d.csg.stubs.RegularPrism; +import org.simantics.proconf.g3d.csg.stubs.Sphere; +import org.simantics.proconf.g3d.csg.stubs.Torus; +import org.simantics.layer0.utils.IEntity; +import org.simantics.proconf.g3d.base.G3DTools; +import org.simantics.proconf.g3d.base.GeometryProvider; +import org.simantics.proconf.g3d.occ.OccResources; +import org.simantics.utils.ErrorLogger; + +import com.jme.eclipse.test.ply.PLY_Loader; +import com.jme.scene.Geometry; +import com.jme.scene.Line; +import com.jme.scene.TriMesh; +import com.jme.util.geom.BufferUtils; + +public class OccTriangulator implements GeometryProvider{ + + + public static final double MIN_VALUE = 0.001; + + public OccTriangulator() { + + } + + + + public boolean canHandle(IEntity instance) { + if (instance.isInstanceOf(OccResources.csgResource.CSGShape)) { + return true; + } + return false; + } + + public Geometry[] getGeometryFromResource(IEntity resource, boolean transform) { + if (resource.isInstanceOf(OccResources.csgResource.CSGShape)) { + TopoDS_Shape shape = OccTriangulator.getShapeFromResource(resource, transform); + Geometry[] g = OccTriangulator.getGeometry(shape); + shape.delete(); + return g; + } + return null; + } + + public boolean reconstructGeometry(IEntity instance, boolean transform, Geometry[] geometry) { + if (instance.isInstanceOf(OccResources.csgResource.CSGShape)) { + TopoDS_Shape shape = OccTriangulator.getShapeFromResource(instance, transform); + boolean b = OccTriangulator.getGeometry(shape,geometry); + shape.delete(); + return b; + } + return false; + + } + + public static Geometry[] getGeometry(TopoDS_Shape tds_shape) { + Geometry g[] = new Geometry[]{new TriMesh(),new Line()}; + if (getGeometry(tds_shape, g)) + return g; + return null; + + } + + public static boolean getGeometry(TopoDS_Shape tds_shape, Geometry[] geometry) { + ViewableShapeImpl shape = new ViewableShapeImpl(tds_shape); + //System.out.println("Geometries in shape " + shape.numGeometries()); + if (shape.numGeometries() > 0) { + int totalIndicesCount = 0; + int totalVerticesCount = 0; + boolean hasTCoords = true; + for (int geometryIndex = 0; geometryIndex < shape.numGeometries(); geometryIndex++) { + IndexedGeometry geom = shape.getGeometry(geometryIndex); + totalIndicesCount += geom.getIndices().length; + totalVerticesCount += (geom.getCoordinates().length / 3); + if (geom.getTCoordinates() == null || geom.getTCoordinates().length == 0) + hasTCoords = false; + } + int currentVertex = 0; + int currentIndex = 0; + int indices[] = new int[totalIndicesCount]; + + + + //TriMesh mesh = new TriMesh(); + TriMesh mesh = (TriMesh)geometry[0]; + float data[] = new float[totalVerticesCount*3]; + float normals[] = new float[totalVerticesCount*3]; + float tcoords[] = null; + if (hasTCoords) + tcoords = new float[totalVerticesCount*2]; + for (int geometryIndex = 0; geometryIndex < shape.numGeometries(); geometryIndex++) { + IndexedGeometry geom = shape.getGeometry(geometryIndex); + System.arraycopy(geom.getCoordinates(), 0, data, currentVertex*3, geom.getCoordinates().length); + System.arraycopy(geom.getNormals(), 0, normals, currentVertex*3, geom.getCoordinates().length); + if (hasTCoords) + System.arraycopy(geom.getTCoordinates(), 0, tcoords, currentVertex*2, geom.getTCoordinates().length - 1); + + for (int i = 0; i < geom.getIndices().length; i++) { + indices[currentIndex + i] = geom.getIndices()[i] + currentVertex; + } + + currentVertex += geom.getCoordinates().length/3; + currentIndex += geom.getIndices().length; + + } + mesh.reconstruct(BufferUtils.createFloatBuffer(data),BufferUtils.createFloatBuffer(normals) , null, hasTCoords ? BufferUtils.createFloatBuffer(tcoords) : null, BufferUtils.createIntBuffer(indices)); + + int numEdgeVertices = 0; + int currentEdgeVertex = 0; + for (int i = 0; i < shape.getNumEdges(); i++) { + numEdgeVertices += shape.getEdge(i).length/3; + } + + Line lines = (Line)geometry[1]; + data = new float[numEdgeVertices*3]; + for (int i = 0; i < shape.getNumEdges(); i++) { + int index = currentEdgeVertex *3; + System.arraycopy(shape.getEdge(i), 0,data, index, shape.getEdge(i).length); + currentEdgeVertex+= shape.getEdge(i).length/3; + } + lines.reconstruct(BufferUtils.createFloatBuffer(data), null, null, null); + + tds_shape.delete(); + return true; + } else { + tds_shape.delete(); + return false; + } + } + /* + public static Geometry[] getGeometry(TopoDS_Shape tds_shape) { + return getGeometry(tds_shape,true); + } + */ + /* + public static boolean getGeometry(TopoDS_Shape tds_shape, Geometry[] geometry) { + return getGeometry(tds_shape,true, geometry); + } + */ + + private static TopoDS_Shape getPrimitiveFromResource(IEntity thing) { + if (!thing.isInstanceOf(OccResources.csgResource.Primitive)) + throw new IllegalArgumentException("Resource is not a primitive"); + TopoDS_Shape shape = null; + if (thing.isInstanceOf(OccResources.csgResource.Box)) { + Box box = new Box(thing); + double sx = box.getXAxisSize()[0]; + double sy = box.getYAxisSize()[0]; + double sz = box.getZAxisSize()[0]; + if (sx <= MIN_VALUE) + sx = MIN_VALUE; + if (sy <= MIN_VALUE) + sy = MIN_VALUE; + if (sz <= MIN_VALUE) + sz = MIN_VALUE; + + shape = makeBox(-sx * 0.5, -sy * 0.5, -sz * 0.5, sx * 0.5, sy * 0.5, sz * 0.5); + } else if (thing.isInstanceOf(OccResources.csgResource.Cone)) { + Cone cone = new Cone(thing); + double h = cone.getHeight()[0]; + double r1 = cone.getBottomRadius()[0]; + double r2 = cone.getTopRadius()[0]; + if (Math.abs(r1 - r2) > MIN_VALUE) { // OpenCASCADE won't work, + // if r1 == r2 + shape = makeCone(new double[] { 0.0, -h * 0.5, 0.0 }, new double[] { 0.0, 1.0, 0.0 }, r1, + r2, h); + } else { + shape = makeCylinder(new double[] { 0.0, -h * 0.5, 0.0 }, new double[] { 0.0, 1.0, 0.0 }, + r1, h); + } + } else if (thing.isInstanceOf(OccResources.csgResource.Sphere)) { + Sphere sphere = new Sphere(thing); + double r = sphere.getRadius()[0]; + if (r <= MIN_VALUE) + r = MIN_VALUE; + shape = makeSphere(0.0, 0.0, 0.0, r); + } else if (thing.isInstanceOf(OccResources.csgResource.Torus)) { + Torus torus = new Torus(thing); + double r1 = torus.getMajorRadius()[0]; + double r2 = torus.getMinorRadius()[0]; + if (r1 <= MIN_VALUE) + r1 = MIN_VALUE; + if (r2 <= MIN_VALUE) + r2 = MIN_VALUE; + shape = makeTorus(new double[] { 0.0, 0.0, 0.0 }, new double[] { 0.0, 1.0, 0.0 }, r1, r2); + } else if (thing.isInstanceOf(OccResources.csgResource.Cylinder)) { + Cylinder cylinder = new Cylinder(thing); + double h = cylinder.getHeight()[0]; + double r = cylinder.getRadius()[0]; + if (r <= MIN_VALUE) + r = MIN_VALUE; + if (h <= MIN_VALUE) + h = MIN_VALUE; + shape = makeCylinder(new double[] { 0.0, -h * 0.5, 0.0 }, new double[] { 0.0, 1.0, 0.0 }, r, h); + } else if (thing.isInstanceOf(OccResources.csgResource.Barrel)) { + Barrel barrel = new Barrel(thing); + double h = barrel.getHeight()[0]; + if (h <= 0.0) + h = 0.01; + double r1 = barrel.getMinorRadius()[0]; + if (r1 <= MIN_VALUE) + r1 = MIN_VALUE; + double r2 = barrel.getMajorRadius()[0]; + if (r2 <= MIN_VALUE) + r2 = MIN_VALUE; + if (Math.abs(r1 -r2)< MIN_VALUE) + r2 = r1 + MIN_VALUE; + double p0[] = new double[]{0.0,-h*0.5,0.0}; + double p1[] = new double[]{0.0,-h*0.5,r1}; + double p2[] = new double[]{0.0, 0.0 ,r2}; + double p3[] = new double[]{0.0, h*0.5,r1}; + double p4[] = new double[]{0.0, h*0.5,0.0}; + GC_MakeArcOfCircle m = new GC_MakeArcOfCircle(p1,p2,p3); + GC_MakeSegment s1 = new GC_MakeSegment(p0,p1); + GC_MakeSegment s2 = new GC_MakeSegment(p3,p4); + TopoDS_Edge e1 = (TopoDS_Edge)new BRepBuilderAPI_MakeEdge(s1.value()).shape(); + TopoDS_Edge e2 = (TopoDS_Edge)new BRepBuilderAPI_MakeEdge(m.value()).shape(); + TopoDS_Edge e3 = (TopoDS_Edge)new BRepBuilderAPI_MakeEdge(s2.value()).shape(); + TopoDS_Wire w = (TopoDS_Wire) new BRepBuilderAPI_MakeWire(e1,e2,e3).shape(); + TopoDS_Face F = (TopoDS_Face) new BRepBuilderAPI_MakeFace(w).shape(); + shape = new BRepPrimAPI_MakeRevol(F,new double[]{0.0,0.0,0.0,0.0,1.0,0.0}).shape(); + m.delete(); + s1.delete(); + s2.delete(); + e1.delete(); + e2.delete(); + e3.delete(); + w.delete(); + F.delete(); + } else if (thing.isInstanceOf(OccResources.csgResource.EllipticCylinder)) { + EllipticCylinder cylinder = new EllipticCylinder(thing); + double h = cylinder.getHeight()[0]; + if (h < MIN_VALUE) + h = MIN_VALUE; + double r2 = cylinder.getMinorRadius()[0]; + if (r2 < MIN_VALUE) + r2 = MIN_VALUE; + double r1 = cylinder.getMajorRadius()[0]; + if (r1 < MIN_VALUE) + r1 = MIN_VALUE; + GP_Elips ellipse; + if (r1 < r2) { + // FIXME : ellipse should be rotated, but current JNI won't allow it since Ax2 is not separate object + ellipse = new GP_Elips(new double[]{0.0,-h*0.5,0.0,0.0,1.0,0.0},r2,r1); + } else { + ellipse = new GP_Elips(new double[]{0.0,-h*0.5,0.0,0.0,1.0,0.0},r1,r2); + } + TopoDS_Edge ed = (TopoDS_Edge) new BRepBuilderAPI_MakeEdge(ellipse).shape(); + TopoDS_Wire w = (TopoDS_Wire) new BRepBuilderAPI_MakeWire(ed).shape(); + TopoDS_Face F = (TopoDS_Face) new BRepBuilderAPI_MakeFace(w).shape(); + shape = new BRepPrimAPI_MakePrism(F, new double[] { 0.0, h, 0.0 }).shape(); + ellipse.delete(); + ed.delete(); + w.delete(); + F.delete(); + } else if (thing.isInstanceOf(OccResources.csgResource.RegularPrism)) { + RegularPrism prism = new RegularPrism(thing); + int n = prism.getCorners()[0]; + if (n < 3) + n = 3; + double h = prism.getHeight()[0]; + if (h < MIN_VALUE) + h = MIN_VALUE; + double r = prism.getRadius()[0]; + if (r < MIN_VALUE) + r = MIN_VALUE; + Vector2d vertices[] = new Vector2d[n]; + for (int i = 0; i < n; i++) { + vertices[i] = new Vector2d(Math.sin(Math.PI * 2.0 * i / n)*r,Math.cos(Math.PI * 2.0 * i / n)*r); + } + BRepBuilderAPI_MakeWire wire = new BRepBuilderAPI_MakeWire(); + for (int i = 0; i < n; i++) { + Vector2d v1 = vertices[i]; + Vector2d v2 = vertices[(i+1)%n]; + wire.add((TopoDS_Edge)new BRepBuilderAPI_MakeEdge(new double[]{v1.x,-h*0.5,v1.y},new double[]{v2.x,-h*0.5,v2.y}).shape()); + } + TopoDS_Wire w = (TopoDS_Wire)wire.shape(); + TopoDS_Face F = (TopoDS_Face) new BRepBuilderAPI_MakeFace(w).shape(); + shape = new BRepPrimAPI_MakePrism(F, new double[] { 0.0, h, 0.0 }).shape(); + wire.delete(); + w.delete(); + F.delete(); + } else if (thing.isInstanceOf(OccResources.csgResource.RectangularSolid)) { + RectangularSolid solid = new RectangularSolid(thing); + double x1 = solid.getXAxisMinimumSize()[0]; + double x2 = solid.getXAxisMaximumSize()[0]; + double y = solid.getYAxisSize()[0]; + double z1 = solid.getZAxisMinimumSize()[0]; + double z2 = solid.getZAxisMaximumSize()[0]; + if (x1 < MIN_VALUE) + x1 = MIN_VALUE; + if (x2 < MIN_VALUE) + x2 = MIN_VALUE; + if (y < MIN_VALUE) + y = MIN_VALUE; + if (z1 < MIN_VALUE) + z1 = MIN_VALUE; + if (z2 < MIN_VALUE) + z2 = MIN_VALUE; + x1 *= 0.5; + x2 *= 0.5; + y *= 0.5; + z1 *= 0.5; + z2 *= 0.5; + + BRepBuilderAPI_MakeWire wire = new BRepBuilderAPI_MakeWire(); + wire.add((TopoDS_Edge)new BRepBuilderAPI_MakeEdge(new double[]{x1,-y,z1},new double[]{x1,-y,-z1}).shape()); + wire.add((TopoDS_Edge)new BRepBuilderAPI_MakeEdge(new double[]{x1,-y,-z1},new double[]{-x1,-y,-z1}).shape()); + wire.add((TopoDS_Edge)new BRepBuilderAPI_MakeEdge(new double[]{-x1,-y,-z1},new double[]{-x1,-y,z1}).shape()); + wire.add((TopoDS_Edge)new BRepBuilderAPI_MakeEdge(new double[]{-x1,-y,z1},new double[]{x1,-y,z1}).shape()); + TopoDS_Wire w1 = (TopoDS_Wire)wire.shape(); + wire.delete(); + wire = new BRepBuilderAPI_MakeWire(); + wire.add((TopoDS_Edge)new BRepBuilderAPI_MakeEdge(new double[]{x2, y,z2},new double[]{x2, y,-z2}).shape()); + wire.add((TopoDS_Edge)new BRepBuilderAPI_MakeEdge(new double[]{x2, y,-z2},new double[]{-x2, y,-z2}).shape()); + wire.add((TopoDS_Edge)new BRepBuilderAPI_MakeEdge(new double[]{-x2, y,-z2},new double[]{-x2, y,z2}).shape()); + wire.add((TopoDS_Edge)new BRepBuilderAPI_MakeEdge(new double[]{-x2, y,z2},new double[]{x2, y,z2}).shape()); + TopoDS_Wire w2 = (TopoDS_Wire)wire.shape(); + BRepOffsetAPI_ThruSections generatorb = new BRepOffsetAPI_ThruSections(true, true); + generatorb.addWire(w1); + generatorb.addWire(w2); + generatorb.build(); + shape = generatorb.shape(); + wire.delete(); + w1.delete(); + w2.delete(); + } else { + throw new UnsupportedOperationException("Unsupported primitive"); + + } + return shape; + } + + private static TopoDS_Shape getBooleanOp(IEntity thing, TopoDS_Shape topoDSshape1, TopoDS_Shape topoDSshape2) { + if (!thing.isInstanceOf(OccResources.csgResource.BooleanOperation)) + throw new IllegalArgumentException("Resource is not a boolean operation"); + TopoDS_Shape shape = null; + int type; + if (thing.isInstanceOf(OccResources.csgResource.Difference)) { + type = 0; + } else if (thing.isInstanceOf(OccResources.csgResource.Union)) { + type = 1; + } else if (thing.isInstanceOf(OccResources.csgResource.Intersection)) { + type = 2; + } else { + throw new UnsupportedOperationException("Unsupported boolean operation"); + } + + switch (type) { + case 0: + shape = makeCut(topoDSshape1, topoDSshape2); + break; + case 1: + shape = makeFuse(topoDSshape1, topoDSshape2); + break; + case 2: + shape = makeCommon(topoDSshape1, topoDSshape2); + break; + } + topoDSshape1.delete(); + topoDSshape2.delete(); + return shape; + } + + private static TopoDS_Shape getBooleanOpFromResource(IEntity thing) { + if (!thing.isInstanceOf(OccResources.csgResource.BooleanOperation)) + throw new IllegalArgumentException("Resource is not a boolean operation"); + + TopoDS_Shape shape = null; + TopoDS_Shape topoDSshape1 = null; + TopoDS_Shape topoDSshape2 = null; + BooleanOperation op = new BooleanOperation(thing); + CSGShape mainShape = op.getMainShape(); + Collection secondaryShapes = op.getSecondaryShape(); + if (mainShape == null || secondaryShapes.size() < 1) { + throw new RuntimeException("Cannot find requested Shapes for boolean operation"); + } + topoDSshape1 = getShapeFromResource(mainShape); + for (CSGShape shape2 : secondaryShapes) { + topoDSshape2 = getShapeFromResource(shape2); + shape = getBooleanOp(thing,topoDSshape1,topoDSshape2); + topoDSshape1.delete(); + topoDSshape1 = shape; + } + + topoDSshape2.delete(); + return shape; + } + + private static TopoDS_Shape getShapeFromResource(IEntity thing) { + return getShapeFromResource(thing, true); + } + + private static TopoDS_Shape getShapeFromResource(IEntity thing, boolean transform) { + if (thing.isInstanceOf(OccResources.csgResource.CSGShape)) { + TopoDS_Shape shape = null; + + if (thing.isInstanceOf(OccResources.csgResource.Primitive)) { + shape = getPrimitiveFromResource(thing); + + } else if (thing.isInstanceOf(OccResources.csgResource.BooleanOperation)) { + shape = getBooleanOpFromResource(thing); + + } else { + throw new UnsupportedOperationException("Shape must be a primitive or a boolean operation"); + } + Tuple3d c = null; + CSGShape shapeType = new CSGShape(thing); + + if (shapeType.getCenter() != null) + c = G3DTools.getVector(shapeType.getCenter()); + + TopoDS_Shape tShape = null; + if(c != null) { + tShape = makeTranslation(shape, c.x, c.y, c.z); + shape.delete(); + shape = tShape; + } + if (transform) { + //CSGShape shapeType = CSGShapeFactory.create(resource); + Tuple3d p = G3DTools.getVector(shapeType.getLocalPosition()); + AxisAngle4d r = G3DTools.getOrientation(shapeType.getLocalOrientation()); + + if (Math.abs(r.angle) > 0.01) { + tShape = makeRotation(shape, new double[] { 0.0, 0.0, 0.0, r.x, r.y, r.z }, r.angle); + shape.delete(); + shape = tShape; + } + tShape = makeTranslation(shape, p.x, p.y, p.z); + shape.delete(); + shape = tShape; + } + + return shape; + + } + throw new UnsupportedOperationException("Resource is not a shape"); + } + + private static TopoDS_Shape getShapeFromFile(String filename) { + assert (filename != null); + if (filename.endsWith("stp")) { + TopoDS_Shape shape = importSTEP(filename); + return shape; + } else if (filename.endsWith("step")) { + TopoDS_Shape shape = importSTEP(filename); + return shape; + } else if (filename.endsWith("iges")) { + TopoDS_Shape shape = importIGES(filename); + return shape; + } else if (filename.endsWith("brep")) { + TopoDS_Shape shape = importBREP(filename); + return shape; + } else { + throw new UnsupportedOperationException("Unsupported format " + filename); + } + + } + + + + public static Geometry[] getGeometryFromFile(String filename) { + if (filename.endsWith("ply")) { + try { + return new Geometry[]{PLY_Loader.loadPLY(filename)}; + } catch (IOException e) { + ErrorLogger.defaultLogError(e); + return null; + } + } + TopoDS_Shape shape = OccTriangulator.getShapeFromFile(filename); + Geometry g[] = OccTriangulator.getGeometry(shape); + shape.delete(); + return g; + } + + public static TopoDS_Shape importBREP(String filename) { + org.jcae.opencascade.jni.BRep_Builder aBuilder = new org.jcae.opencascade.jni.BRep_Builder(); + org.jcae.opencascade.jni.TopoDS_Shape myShape = org.jcae.opencascade.jni.BRepTools.read(filename, aBuilder); + aBuilder.delete(); + return myShape; + } + + public static TopoDS_Shape importIGES(String filename) { + org.jcae.opencascade.jni.IGESControl_Reader aReader = new org.jcae.opencascade.jni.IGESControl_Reader(); + aReader.readFile(filename); + aReader.clearShapes(); + aReader.transferRoots(); + TopoDS_Shape result = aReader.oneShape(); + aReader.delete(); + return result; + } + + public static TopoDS_Shape importSTEP(String filename) { + org.jcae.opencascade.jni.STEPControl_Reader aReader = new org.jcae.opencascade.jni.STEPControl_Reader(); + aReader.readFile(filename); + aReader.clearShapes(); + aReader.transferRoots(); + TopoDS_Shape result = aReader.oneShape(); + aReader.delete(); + return result; + } + + public static TopoDS_Shape archimede(TopoDS_Shape topoDS_Shape, double param, double param2, double param3) { + throw new UnsupportedOperationException(); + } + + public static TopoDS_Shape suppressHolesInFaceOrShell(TopoDS_Shape topoDS_Shape, TopoDS_Shape[] topoDS_Shape1) { + throw new UnsupportedOperationException(); + } + + public static TopoDS_Shape suppressHole(TopoDS_Shape topoDS_Shape, TopoDS_Shape[] topoDS_Shape1, + TopoDS_Shape[] topoDS_Shape2, TopoDS_Shape[] topoDS_Shape3) { + throw new UnsupportedOperationException(); + } + + public static TopoDS_Shape[] suppressFaces(TopoDS_Shape topoDS_Shape, TopoDS_Shape[] topoDS_Shape1) { + throw new UnsupportedOperationException(); + } + + public static TopoDS_Shape[] subShapeAll(TopoDS_Shape topoDS_Shape, short param) { + throw new UnsupportedOperationException(); + } + + public static TopoDS_Shape subShape(TopoDS_Shape topoDS_Shape, short param, TopoDS_Shape[] topoDS_Shape2) { + throw new UnsupportedOperationException(); + } + + public static boolean setBlock(TopoDS_Shape topoDS_Shape) { + throw new UnsupportedOperationException(); + } + + public static TopoDS_Shape partitionKeepFaces(TopoDS_Shape[] topoDS_Shape, TopoDS_Shape topoDS_Shape1, boolean param) { + throw new UnsupportedOperationException(); + } + + public static TopoDS_Shape orientationChange(TopoDS_Shape topoDS_Shape) { + throw new UnsupportedOperationException(); + } + + public static short nbLabels() { + throw new UnsupportedOperationException(); + } + + public static TopoDS_Shape makeWire(TopoDS_Shape[] topoDS_Shape) { + throw new UnsupportedOperationException(); + } + + public static TopoDS_Shape makeVertex(double param, double param1, double param2) { + throw new UnsupportedOperationException(); + } + + public static TopoDS_Shape makeVector(double[] pointStruct, double[] pointStruct1) { + throw new UnsupportedOperationException(); + } + + public static TopoDS_Shape makeTranslation(TopoDS_Shape aShape, double x, double y, double z) { + GP_Trsf theTransformation = new GP_Trsf(); + theTransformation.setTranslation(new double[] { x, y, z }); + BRepBuilderAPI_Transform bt = new BRepBuilderAPI_Transform(aShape, theTransformation, true); + + TopoDS_Shape shape = bt.shape(); + bt.delete(); + theTransformation.delete(); + return shape; + } + + public static TopoDS_Shape makeTorus(double[] pointStruct, double[] dirStruct, double r1, double r2) { + double[] axe = new double[6]; + System.arraycopy(pointStruct, 0, axe, 0, 3); + System.arraycopy(dirStruct, 0, axe, 3, 3); + org.jcae.opencascade.jni.TopoDS_Shape tds = new BRepPrimAPI_MakeTorus(axe, r1, r2).shape(); + return tds; + } + + public static TopoDS_Shape makeSphere(double x, double y, double z, double radius) { + double[] c = new double[] { x, y, z }; + org.jcae.opencascade.jni.TopoDS_Shape tds = new org.jcae.opencascade.jni.BRepPrimAPI_MakeSphere(c, radius) + .shape(); + return tds; + } + + public static TopoDS_Shape makeSewingShape(TopoDS_Shape topoDS_Shape, double param) { + throw new UnsupportedOperationException(); + } + + public static TopoDS_Shape makeSewing(TopoDS_Shape[] topoDS_Shape, double param) { + throw new UnsupportedOperationException(); + } + + public static TopoDS_Shape makeScaleTransform(TopoDS_Shape topoDS_Shape, double[] pointStruct, double param) { + throw new UnsupportedOperationException(); + } + + public static TopoDS_Shape makeRotation(TopoDS_Shape aShape, double[] axisStruct, double angle) { + + GP_Trsf theTransformation = new GP_Trsf(); + theTransformation.setRotation(axisStruct, angle); + BRepBuilderAPI_Transform bt = new BRepBuilderAPI_Transform(aShape, theTransformation, true); + TopoDS_Shape shape = bt.shape(); + bt.delete(); + theTransformation.delete(); + return shape; + } + + public static TopoDS_Shape makeRevolution(TopoDS_Shape topoDS_Shape, double[] axisStruct, double param) { + throw new UnsupportedOperationException(); + } + + public static TopoDS_Shape makePrism(TopoDS_Shape topoDS_Shape, double[] pointStruct, double[] pointStruct2) { + throw new UnsupportedOperationException(); + } + + public static TopoDS_Shape makePlane(double[] pointStruct, double[] dirStruct, double param) { + throw new UnsupportedOperationException(); + } + + public static TopoDS_Shape makePlacedBox(double param, double param1, double param2, double param3, double param4, + double param5) { + throw new UnsupportedOperationException(); + } + + public static TopoDS_Shape makePipe(TopoDS_Shape topoDS_Shape, TopoDS_Shape topoDS_Shape1) { + throw new UnsupportedOperationException(); + } + + public static TopoDS_Shape makePanel(TopoDS_Shape topoDS_Shape, short param, double param2) { + throw new UnsupportedOperationException(); + } + + public static TopoDS_Shape makeMultiTranslation2D(TopoDS_Shape topoDS_Shape, double[] dirStruct, double param, + short param3, double[] dirStruct4, double param5, short param6) { + throw new UnsupportedOperationException(); + } + + public static TopoDS_Shape makeMultiTranslation1D(TopoDS_Shape topoDS_Shape, double[] dirStruct, double param, short param3) { + throw new UnsupportedOperationException(); + } + + public static TopoDS_Shape makeMultiRotation2D(TopoDS_Shape topoDS_Shape, double[] dirStruct, double[] pointStruct, + double param, short param4, double param5, short param6) { + throw new UnsupportedOperationException(); + } + + public static TopoDS_Shape makeMultiRotation1D(TopoDS_Shape topoDS_Shape, double[] dirStruct, double[] pointStruct, + short param) { + throw new UnsupportedOperationException(); + } + + public static TopoDS_Shape makeMirrorByPlane(TopoDS_Shape topoDS_Shape, TopoDS_Shape topoDS_Shape1) { + throw new UnsupportedOperationException(); + } + + public static TopoDS_Shape makeLine(double[] pointStruct, double[] dirStruct) { + throw new UnsupportedOperationException(); + } + + public static TopoDS_Shape makeFilling(TopoDS_Shape topoDS_Shape, short param, short param2, double param3, double param4, + short param5) { + throw new UnsupportedOperationException(); + } + + public static TopoDS_Shape makeFillet(TopoDS_Shape topoDS_Shape, double param, short param2, TopoDS_Shape[] topoDS_Shape3) { + throw new UnsupportedOperationException(); + } + + public static TopoDS_Shape makeFace(TopoDS_Shape topoDS_Shape, boolean param) { + throw new UnsupportedOperationException(); + } + + public static TopoDS_Shape makeEdge(double[] pointStruct, double[] pointStruct1) { + throw new UnsupportedOperationException(); + } + + public static TopoDS_Shape makeCylinder(double[] pointStruct, double[] dirStruct, double radius, double height) { + double[] axe = new double[6]; + System.arraycopy(pointStruct, 0, axe, 0, 3); + System.arraycopy(dirStruct, 0, axe, 3, 3); + org.jcae.opencascade.jni.TopoDS_Shape tds = new org.jcae.opencascade.jni.BRepPrimAPI_MakeCylinder(axe, radius, + height, 2 * Math.PI).shape(); + return tds; + } + + public static TopoDS_Shape makeCopy(TopoDS_Shape topoDS_Shape) { + throw new UnsupportedOperationException(); + } + + public static TopoDS_Shape makeCone(double[] pointStruct, double[] dirStruct, double radius1, double radius2, double height) { + double[] axe = new double[6]; + System.arraycopy(pointStruct, 0, axe, 0, 3); + System.arraycopy(dirStruct, 0, axe, 3, 3); + org.jcae.opencascade.jni.TopoDS_Shape tds = new org.jcae.opencascade.jni.BRepPrimAPI_MakeCone(axe, radius1, + radius2, height, 2 * Math.PI).shape(); + return tds; + } + + public static TopoDS_Shape makeCompound(TopoDS_Shape[] shapes) { + BRep_Builder builder = new BRep_Builder(); + org.jcae.opencascade.jni.TopoDS_Compound comp = new org.jcae.opencascade.jni.TopoDS_Compound(); + builder.makeCompound(comp); + for (int i = 0; i < shapes.length; i++) { + + builder.add(comp, shapes[i]); + } + builder.delete(); + return comp; + } + + public static TopoDS_Shape makeCircle(double[] pointStruct, double[] dirStruct, double param) { + throw new UnsupportedOperationException(); + } + + public static TopoDS_Shape makeChamfer(TopoDS_Shape topoDS_Shape, double param, double param2, short param3, + TopoDS_Shape[] topoDS_Shape4) { + throw new UnsupportedOperationException(); + } + + public static TopoDS_Shape makeCDG(TopoDS_Shape topoDS_Shape) { + throw new UnsupportedOperationException(); + } + + public static TopoDS_Shape makeBox(double x1, double y1, double z1, double x2, double y2, double z2) { + double[] p1 = new double[] { x1, y1, z1 }; + double[] p2 = new double[] { x2, y2, z2 }; + org.jcae.opencascade.jni.TopoDS_Shape tds = new org.jcae.opencascade.jni.BRepPrimAPI_MakeBox(p1, p2).shape(); + return tds; + } + + public static TopoDS_Shape makeCut(TopoDS_Shape shape1, TopoDS_Shape shape2) { + + org.jcae.opencascade.jni.TopoDS_Shape s = new org.jcae.opencascade.jni.BRepAlgoAPI_Cut(shape1, shape2).shape(); + return s; + } + + public static TopoDS_Shape makeCommon(TopoDS_Shape shape1, TopoDS_Shape shape2) { + + org.jcae.opencascade.jni.TopoDS_Shape s = new org.jcae.opencascade.jni.BRepAlgoAPI_Common(shape1, shape2).shape(); + return s; + } + + public static TopoDS_Shape makeFuse(TopoDS_Shape shape1, TopoDS_Shape shape2) { + + org.jcae.opencascade.jni.TopoDS_Shape s = new org.jcae.opencascade.jni.BRepAlgoAPI_Fuse(shape1, shape2).shape(); + return s; + } + + public static TopoDS_Shape makeArc(double[] pointStruct, double[] pointStruct1, double[] pointStruct2) { + throw new UnsupportedOperationException(); + } + + public static TopoDS_Shape makeWedge(double[] pointStruct, double[] dirStruct,double dx, double dy, double dz, double xmin, double zmin, double xmax, double zmax) { + double[] axe = new double[6]; + System.arraycopy(pointStruct, 0, axe, 0, 3); + System.arraycopy(dirStruct, 0, axe, 3, 3); + org.jcae.opencascade.jni.TopoDS_Shape s = new org.jcae.opencascade.jni.BRepPrimAPI_MakeWedge(axe, dx, dy, dz, xmin, zmin, xmax, zmax).shape(); + return s; + } + + + + public static void exportBREP(TopoDS_Shape shape, String filename) { + org.jcae.opencascade.jni.BRepTools.write(shape, filename); + } + + public static void exportIGES(TopoDS_Shape shape, String filename) { + throw new UnsupportedOperationException(); + +// IGESControl_Writer writer=new IGESControl_Writer(); +// writer.addShape(shape); writer.write(filename,false); + + } + + + + + +} diff --git a/org.simantics.proconf.g3d.occ/src/org/simantics/proconf/g3d/occ/geometry/ViewableShapeImpl.java b/org.simantics.proconf.g3d.occ/src/org/simantics/proconf/g3d/occ/geometry/ViewableShapeImpl.java new file mode 100644 index 00000000..e08c9b73 --- /dev/null +++ b/org.simantics.proconf.g3d.occ/src/org/simantics/proconf/g3d/occ/geometry/ViewableShapeImpl.java @@ -0,0 +1,498 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +/* + This class is combination of jCAE's classes to generate meshes from shapes. + Faces are lisetd as individual meshes. + + Marko Luukkainen + + jCAE stand for Java Computer Aided Engineering. Features are : Small CAD + modeler, Finit element mesher, Plugin architecture. + + Copyright (C) 2003 Jerome Robert + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +package org.simantics.proconf.g3d.occ.geometry; +import org.jcae.opencascade.jni.BRepBndLib; +import org.jcae.opencascade.jni.BRepMesh_IncrementalMesh; +import org.jcae.opencascade.jni.BRepTools; +import org.jcae.opencascade.jni.BRep_Tool; +import org.jcae.opencascade.jni.Bnd_Box; +import org.jcae.opencascade.jni.GCPnts_UniformDeflection; +import org.jcae.opencascade.jni.GP_Trsf; +import org.jcae.opencascade.jni.GeomAPI_ProjectPointOnSurf; +import org.jcae.opencascade.jni.GeomAdaptor_Curve; +import org.jcae.opencascade.jni.GeomLProp_SLProps; +import org.jcae.opencascade.jni.Geom_Curve; +import org.jcae.opencascade.jni.Geom_Surface; +import org.jcae.opencascade.jni.Poly_Triangulation; +import org.jcae.opencascade.jni.TopAbs_Orientation; +import org.jcae.opencascade.jni.TopAbs_ShapeEnum; +import org.jcae.opencascade.jni.TopExp_Explorer; +import org.jcae.opencascade.jni.TopLoc_Location; +import org.jcae.opencascade.jni.TopoDS_Edge; +import org.jcae.opencascade.jni.TopoDS_Face; +import org.jcae.opencascade.jni.TopoDS_Shape; +import org.jcae.opencascade.jni.TopoDS_Vertex; + + +import java.util.ArrayList; +import java.util.HashSet; + +import javax.vecmath.Matrix4d; +import javax.vecmath.Point3d; +import javax.vecmath.Vector3f; + + +public class ViewableShapeImpl +{ + + + ArrayList faceMeshes =new ArrayList(); + ArrayList edges=new ArrayList(); + + public ViewableShapeImpl(TopoDS_Shape g) + { + BRepTools.clean(g); + buildFaces(g); + buildEdges(g); + + } + /* + public ViewableShapeImpl(TopoDS_Shape g, boolean alternative) + { + + if (alternative) + buildFaces(g); + else { + BRepTools.clean(g); + buildFaces2(g); + } + + buildEdges(g); + + } + */ + + public IndexedGeometry getGeometry(int i) + { + return faceMeshes.get(i); + } + + public int numGeometries() + { + return faceMeshes.size(); + + } + + public int getNumEdges() { + return edges.size(); + } + + public float[] getEdge(int i) { + return edges.get(i); + } + + /** + * org.jcae.viewer3d.cad.occ.OCCEdgeDomain + * @param shape + * @param geom + */ + private void buildFaces(TopoDS_Shape shape) { + TopExp_Explorer explorer = new TopExp_Explorer(); + TopLoc_Location loc = new TopLoc_Location(); + + int meshIter=4; + double deflection = deflection(shape); + for (explorer.init(shape, TopAbs_ShapeEnum.FACE); explorer.more(); explorer.next()) + { + //System.out.println("Triangulation"); + TopoDS_Shape s = explorer.current(); + if (!(s instanceof TopoDS_Face)) continue; // should not happen! + TopoDS_Face face = (TopoDS_Face)s; + Poly_Triangulation pt = BRep_Tool.triangulation(face,loc); + + //float error=0.01f; + double error = deflection; + int iter=0; + // if shape was generated with program triangulation seems to be always null, + // but model is loaded from file, it may already contain triangulation + // So : in those cases can we delete existing triangulation and generate a new one ? + //if (pt == null) { + //System.out.println("Initial triangulation of face "+face+" not found. Using Incremental mesh"); + //} else { + //System.out.println("Initial triangulation of face "+face+" found."); + //} + while((pt==null)&(iter alreadyDone=new HashSet(); + double boundingBoxDeflection = edgeDeflection(shape); + + for (explorer.init(shape, TopAbs_ShapeEnum.EDGE); explorer.more(); explorer.next()) + { + TopoDS_Shape s = explorer.current(); + if (!(s instanceof TopoDS_Edge)) continue; // should not happen! + TopoDS_Edge e = (TopoDS_Edge)s; + + if(!alreadyDone.add(e)) + continue; + + double[] range = BRep_Tool.range(e); + Geom_Curve gc = BRep_Tool.curve(e, range); + float[] array; + if(gc!=null) + { + GeomAdaptor_Curve adaptator = new GeomAdaptor_Curve(gc); + GCPnts_UniformDeflection deflector = new GCPnts_UniformDeflection(); + + deflector.initialize(adaptator, boundingBoxDeflection, range[0], range[1]); + int npts = deflector.nbPoints(); + + // Allocate one additional point at each end = parametric value 0, 1 + int size = 0; + if (npts > 2) + size = (npts-2)*2; + size+=2; + size*=3; + array = new float[size]; + int j=0; + double[] values = adaptator.value(range[0]); + array[j++] = (float) values[0]; + array[j++] = (float) values[1]; + array[j++] = (float) values[2]; + // All intermediary points + for (int i=1; i draw lines between the vertices and ignore curvature + // best approximation we can do + ArrayList aa = new ArrayList(); // store points here + for (TopExp_Explorer explorer2 = new TopExp_Explorer(s, TopAbs_ShapeEnum.VERTEX); + explorer2.more(); explorer2.next()) + { + TopoDS_Shape sv = explorer2.current(); + if (!(sv instanceof TopoDS_Vertex)) continue; // should not happen! + TopoDS_Vertex v = (TopoDS_Vertex)sv; + aa.add(BRep_Tool.pnt(v)); + } + int size = 0; + if (aa.size() > 2) + size = (aa.size()-2)*2; + size+=2; + double[] f=(double[])aa.get(0); + array = new float[size*3]; + array[0]=(float) f[0]; + array[1]=(float) f[1]; + array[2]=(float) f[2]; + for(int i=1, j=3; i + + + + + + diff --git a/org.simantics.proconf.g3d.shapeeditor/.project b/org.simantics.proconf.g3d.shapeeditor/.project new file mode 100644 index 00000000..875413f2 --- /dev/null +++ b/org.simantics.proconf.g3d.shapeeditor/.project @@ -0,0 +1,28 @@ + + + org.simantics.proconf.g3d.shapeeditor + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/org.simantics.proconf.g3d.shapeeditor/META-INF/MANIFEST.MF b/org.simantics.proconf.g3d.shapeeditor/META-INF/MANIFEST.MF new file mode 100644 index 00000000..3ff48b95 --- /dev/null +++ b/org.simantics.proconf.g3d.shapeeditor/META-INF/MANIFEST.MF @@ -0,0 +1,33 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Shapeeditor Plug-in +Bundle-SymbolicName: org.simantics.proconf.g3d.shapeeditor;singleton:=true +Bundle-Version: 1.0.0 +Bundle-Activator: org.simantics.proconf.g3d.shapeeditor.Activator +Bundle-Vendor: VTT +Require-Bundle: org.eclipse.ui, + org.eclipse.core.runtime, + org.eclipse.ui.views.properties.tabbed, + com.jme.eclipse, + javax.vecmath, + org.jcae.opencascade.jni, + org.simantics.proconf.g3d, + org.simantics.image.stubs, + org.simantics.layer0.stubs, + org.simantics.layer0.utils, + org.simantics.g2d.stubs, + org.simantics.utils, + org.simantics.proconf.g3d.occ, + org.simantics.proconf.ui, + org.simantics.proconf.ui.workbench, + org.simantics.proconf.animation, + org.simantics.proconf.ode, + org.simantics.utils.ui, + org.simantics.equation, + org.simantics.db, + org.simantics.utils.ui.workbench, + org.simantics.proconf.browsing, + org.simantics.db.services, + org.simantics.proconf.g3d.csg +Eclipse-LazyStart: true +Export-Package: org.simantics.proconf.g3d.shapeeditor.views diff --git a/org.simantics.proconf.g3d.shapeeditor/build.properties b/org.simantics.proconf.g3d.shapeeditor/build.properties new file mode 100644 index 00000000..6f20375d --- /dev/null +++ b/org.simantics.proconf.g3d.shapeeditor/build.properties @@ -0,0 +1,5 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + plugin.xml diff --git a/org.simantics.proconf.g3d.shapeeditor/icons/difference.png b/org.simantics.proconf.g3d.shapeeditor/icons/difference.png new file mode 100644 index 0000000000000000000000000000000000000000..d7b2747ee908a8610ff83131d702c08a513a6f8c GIT binary patch literal 624 zcmV-$0+0QPP)_b* zs30h46av~!-B>};f+bM9C^XPTtlAParms0Jl9#-er!x$fIrq*P=G-xm*a|FAwlTuxy?DYOo;7cVs){?e5jv&nGk5BB%A?>uubp) zBrc|e)5|_lY8IU{KcVsgw919xOD{<5&nz!?`uQP&1Uk2pzzZWEIsIyuvo|*YM5mzd zVPnYDC5RloOkX;$bw8{)W;g_-kgV#9=wOUOTiNc`ovpUAqhppsH_niBVgkS5{T%)@ z80$AZPvk-{D2NG+V9jn`--(ga1+Mnguu>6U7AQ{=ovgSJ9A7@KG9U}&mxN8=0c(P( zsG%7A$5+=a0DP7x+4AIRc>#>?Vc^P1{xpe2ue^(>bB19-lcRfA?ew_rfh0Km_zgSW zYVBB5$L{k~5C*k_9)adTo0csSjDN#_uR(yWL#5J9Rs#LPe*#ph3I7b#x`M#gplTBR zV0Lveov997S^};Cy%Gl{zPkzIbtV#{n0Np + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/org.simantics.proconf.g3d.shapeeditor/icons/intersection.png b/org.simantics.proconf.g3d.shapeeditor/icons/intersection.png new file mode 100644 index 0000000000000000000000000000000000000000..95915d3ec26701d120b906e95e691f6b25ce61ad GIT binary patch literal 622 zcmV-!0+IcRP) zbh2@%LzgUL*H*}2w zVW{L`_AwN+vD0zgZfyxKa#~{Fo`)I>Cm=n~hps4LDd4#7!Pvk-sXRIO#i0@j0ndP+fuVLrSo_*gU{&lJ z;LemlWrvd>7u47EgV`ne6(BK-ITHg8g{#yg-2bdKyGYAYs7YbQj + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/org.simantics.proconf.g3d.shapeeditor/icons/link.png b/org.simantics.proconf.g3d.shapeeditor/icons/link.png new file mode 100644 index 0000000000000000000000000000000000000000..b8ac73c164890ed76425c4ca0ef24eac5a08b027 GIT binary patch literal 439 zcmV;o0Z9IdP)L zkiSbpVH7~mefT2-%PFECgy~j;OG84?6j4G$NJA7Mlua!WP3e$OL4QFIZc#MV=-^bl zhD3z~B}tP)gYY8X*N{=>Qxng6zI(Xe6{QsIU;&VMmQeVsj9}%1h`J!(G=Rd7uwG;B z96{rN*4n}?2Br#$p0)z3#p7keV~;cs2v##0^qd`v#wc!a)eDGH3Ynu1I|Bf_&pQ(? z-ny?H<2Ui#+KLU`t%S#1Z$~V!G5C}TW?pLo)k)C|kL^Ukut2upwA{~bdqy0(nkjZ_ zx*!i2L{kf?gn6KX;kBQZ4eQ?6zIO{@@sG{|lc`|prS1_mi0O{S`PSu0nVDvZmdds1lHD8UVl`%GaNNhJ|=Kn7)JtNBoWN+}Do~ huB@H>9{zWr5uf;^aUqO7?YjT~002ovPDHLkV1gCfy21be literal 0 HcmV?d00001 diff --git a/org.simantics.proconf.g3d.shapeeditor/icons/link.svg b/org.simantics.proconf.g3d.shapeeditor/icons/link.svg new file mode 100644 index 00000000..2ad1a0af --- /dev/null +++ b/org.simantics.proconf.g3d.shapeeditor/icons/link.svg @@ -0,0 +1,145 @@ + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/org.simantics.proconf.g3d.shapeeditor/icons/union.png b/org.simantics.proconf.g3d.shapeeditor/icons/union.png new file mode 100644 index 0000000000000000000000000000000000000000..7ffeedb8be658154f8691d2ae06e4c58e7be6eb1 GIT binary patch literal 682 zcmV;b0#*HqP)NX){-$VG*LBv?cd zLPEO8jSv!%Mh^tL zfkd?S8it$T#Vng!HsEo9QbApu>uBR)^(4h!Q93H@e@yP4zRsSpT+l8_#0GfsA_Vt9 zqWOx5^_2t>OcFWYm%w}jvTi~!Q3DcH1M!bz{o+-D1UkQwzy?EaIWam%`=uQKMW3Md z{(6(GE#RoTOl{XUWi75XVBAUrT9MYm899#*FkZY8sa81{E)@y;(*IcUlk(w@xf%YS z*l&Xo3R2yxjRehY$Tf}(6Qu-@tG+=l#^vhWE5k%Vn_&h>7_=etD=$l(fDxuxwQ5tnI!)%W-u27%Nqr2c11+n{6&>_GrJYV#JpklqixJ4{u78-Zl8 zYLjghW%yCza*PVT!tfcgtYaf(lhHkp1m(l8*#AsfBSkv+6y?nze&mRg4@CNc`0R|6 z_JhN|JdeF+od8_})2w7r0=c`bA}JUi{Lwx!pBYCG8KNc9qC_JY6@~Z)0I-FisU3Q2 zpzj!D`nQ@+_y^H|N`c&Ww%ki0)auUnd&xdy*@SUuXUFlI6$2@zufQr_fmNM#X(1*Z zE8R7zQ7m^l(c~b0 + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/org.simantics.proconf.g3d.shapeeditor/icons/unlink.png b/org.simantics.proconf.g3d.shapeeditor/icons/unlink.png new file mode 100644 index 0000000000000000000000000000000000000000..5db0efc8d4b3bdf5f2f392daee85386102d8c55c GIT binary patch literal 484 zcmVL zk~=IzaTLaX=U(mgifB3*8WFFs=^!BuiLjc`m>9g;#b~WbVkVN3G$bZ5kyu15R*5Sy z2qogtNEd^6G`+ol15&+O&u{(C`JHpV98pT~9~A*eKSL-2Iga4MBBC}(d<#GkKnQi8=1+ju2h)#Y7?FZWzXAkTK69)#x~AdwVLjbv>W#j_ z0E-AZZS&WYGb@*)3m%dk=(OSCfcSmVb{Vrz#o9zqw8`fL$j3j()VoJSWKpy2ZqCzt z04=L6WqL77Hqxn3WrCbwGi?r<+n)e5ih*A0#nP;dO7-gH>9v9J=AC$z(e4-=2fECl zd6OIBsY-GDkg!P)iAe0isOY@%y6f_s-hdE-_eXLDQ<<8}+!@EcQ`M#pMUtmRDOHgT z(W!lv*3X`|j)F(Gf}G^3cm#F}13t=Tn%A4N&BF3w@Ng5HAr_E--S0yPy{*0b-uz?0 aS9$^ey@Sgo+eokg0000FxR30 literal 0 HcmV?d00001 diff --git a/org.simantics.proconf.g3d.shapeeditor/icons/unlink.svg b/org.simantics.proconf.g3d.shapeeditor/icons/unlink.svg new file mode 100644 index 00000000..ca82a54c --- /dev/null +++ b/org.simantics.proconf.g3d.shapeeditor/icons/unlink.svg @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/org.simantics.proconf.g3d.shapeeditor/plugin.xml b/org.simantics.proconf.g3d.shapeeditor/plugin.xml new file mode 100644 index 00000000..82655511 --- /dev/null +++ b/org.simantics.proconf.g3d.shapeeditor/plugin.xml @@ -0,0 +1,167 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/Activator.java b/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/Activator.java new file mode 100644 index 00000000..e256c294 --- /dev/null +++ b/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/Activator.java @@ -0,0 +1,95 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.shapeeditor; + +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.BundleContext; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.management.ISessionContext; +import org.simantics.db.management.ISessionContextChangedListener; +import org.simantics.db.management.SessionContextChangedEvent; +import org.simantics.proconf.ui.ProConfUI; + +/** + * The activator class controls the plug-in life cycle + */ +public class Activator extends AbstractUIPlugin { + + // The plug-in ID + public static final String PLUGIN_ID = "org.simantics.proconf.g3d.shapeeditor"; + + // The shared instance + private static Activator plugin; + + /** + * The constructor + */ + public Activator() { + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext) + */ + public void start(BundleContext context) throws Exception { + super.start(context); + plugin = this; + ProConfUI.getSessionContextProvider().addContextChangedListener(new ISessionContextChangedListener() { + @Override + public void sessionContextChanged(SessionContextChangedEvent event) { + ISessionContext ctx = event.getNewValue(); + if (ctx != null) { + ctx.getSession().asyncRead(new GraphRequestAdapter() { + public GraphRequestStatus perform(Graph g) throws Exception { + ShapeEditorResources.initialize(g); + return GraphRequestStatus.transactionComplete(); + }; + }); + } else { + ShapeEditorResources.deinitialize(); + } + } + }); + try { + ProConfUI.getSession().asyncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + ShapeEditorResources.initialize(g); + return GraphRequestStatus.transactionComplete(); + } + }); + } catch (Exception e) { + + } + + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext) + */ + public void stop(BundleContext context) throws Exception { + plugin = null; + super.stop(context); + } + + /** + * Returns the shared instance + * + * @return the shared instance + */ + public static Activator getDefault() { + return plugin; + } + +} diff --git a/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/ShapeEditorResources.java b/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/ShapeEditorResources.java new file mode 100644 index 00000000..2418c9c7 --- /dev/null +++ b/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/ShapeEditorResources.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.shapeeditor; + +import org.simantics.proconf.g3d.csg.stubs.CSGResource; +import org.simantics.db.Builtins; +import org.simantics.db.Graph; +import org.simantics.equation.stubs.EquationResource; +import org.simantics.g2d.stubs.anim.AnimationResource; +import org.simantics.proconf.animation.curve.CurveBuilder; +import org.simantics.proconf.animation.curve.CurveBuilderImpl; +import org.simantics.proconf.g3d.stubs.G3DResource; + +public class ShapeEditorResources { + public static Builtins builtins; + public static G3DResource g3dResource; + public static CSGResource csgResource; + public static AnimationResource animationResource; + public static CurveBuilder curveBuilder; + public static EquationResource equationResource; + + public static void initialize(Graph g) { + builtins = g.getBuiltins(); + animationResource = AnimationResource.getInstance(g); + csgResource = CSGResource.getInstance(g); + g3dResource = G3DResource.getInstance(g); + curveBuilder = new CurveBuilderImpl(ShapeEditorResources.animationResource); + equationResource = EquationResource.getInstance(g); + } + + public static void deinitialize() { + builtins = null; + g3dResource = null; + csgResource = null; + animationResource = null; + curveBuilder = null; + equationResource = null; + } + +} diff --git a/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/actions/ExportAction.java b/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/actions/ExportAction.java new file mode 100644 index 00000000..eca99896 --- /dev/null +++ b/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/actions/ExportAction.java @@ -0,0 +1,100 @@ +package org.simantics.proconf.g3d.shapeeditor.actions; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Collection; + +import org.eclipse.jface.action.Action; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.FileDialog; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Resource; +import org.simantics.db.Statement; +import org.simantics.layer0.utils.direct.GraphUtils; +import org.simantics.layer0.utils.extent.Extent; +import org.simantics.layer0.utils.extent.ExtentUtils; +import org.simantics.layer0.utils.extent.IExtentAdvisor; +import org.simantics.layer0.utils.serialization.ConnectionPointMap; +import org.simantics.layer0.utils.serialization.TransferableGraph; +import org.simantics.layer0.utils.serialization.TransferableGraphUtils; +import org.simantics.proconf.g3d.shapeeditor.views.ShapeEditorBase; +import org.simantics.utils.ErrorLogger; + + +public class ExportAction extends Action{ + private ShapeEditorBase parent; + + public ExportAction(ShapeEditorBase parent) { + this.parent = parent; + this.setText("Export"); + this.setId("g3d shape export"); + } + + @Override + public void run() { + try { + doExport(); + } catch (IOException e) { + ErrorLogger.defaultLogError(e); + } + } + + private void doExport() throws IOException { + FileDialog dialog = new FileDialog(parent.getRenderingComposite().getShell(),SWT.SAVE); + String filename = dialog.open(); + if (filename == null) + return; + + final File file = new File(filename); + final FileOutputStream fos = new FileOutputStream(file); + + parent.getSession().asyncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + Resource modelResource = parent.getModelResource(); + System.out.println("Exporting " + modelResource); + Collection model = ExtentUtils.determineExtent(g, new ExtentAdvisor(), modelResource); + + for (Statement s : model) + System.out.println(GraphUtils.getReadableName(g, s.getSubject())+", "+GraphUtils.getReadableName(g, s.getPredicate())+", "+GraphUtils.getReadableName(g, s.getObject())); + + ConnectionPointMap purposeProvider = new ConnectionPointMap(); + purposeProvider.put(modelResource, TransferableGraphUtils.CP_OBJECT); + + TransferableGraph dbIndependentSubgraph = TransferableGraphUtils.extractTransferableGraph(g, model, purposeProvider, null); + + byte[] data = TransferableGraphUtils.serialize(dbIndependentSubgraph); + + fos.write(data); + + System.out.println("Exporting done."); + return GraphRequestStatus.transactionComplete(); + } + + @Override + public void requestCompleted(GraphRequestStatus status) { + try { + fos.close(); + } catch (IOException e) { + ErrorLogger.defaultLogError(e); + } + + } + }); + } + + public class ExtentAdvisor implements IExtentAdvisor { + @Override + public ExtentAdvice getAdvice(Graph g, Extent currentState, Resource extent) { + System.out.println("Extent advice : " + currentState + " : " + extent); + + //if (extent.equals(ShapeEditorResources.equationResource.Expression)) return ExtentAdvice.Include; + //return ExtentAdvice.Exclude; + return ExtentAdvice.Include; + } + } + +} diff --git a/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/actions/ImportAction.java b/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/actions/ImportAction.java new file mode 100644 index 00000000..7a4d063a --- /dev/null +++ b/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/actions/ImportAction.java @@ -0,0 +1,81 @@ +package org.simantics.proconf.g3d.shapeeditor.actions; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; + +import org.eclipse.jface.action.Action; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.FileDialog; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Resource; +import org.simantics.db.Statement; +import org.simantics.layer0.utils.serialization.ConnectionPointList; +import org.simantics.layer0.utils.serialization.TransferableGraph; +import org.simantics.layer0.utils.serialization.TransferableGraphUtils; +import org.simantics.proconf.g3d.shapeeditor.views.ShapeEditorBase; +import org.simantics.utils.ErrorLogger; + +public class ImportAction extends Action { + + private ShapeEditorBase parent; + + public ImportAction(ShapeEditorBase parent) { + this.parent = parent; + setText("Import"); + setId("g3d shape import"); + } + + @Override + public void run() { + try { + doImport(); + } catch (IOException e) { + ErrorLogger.defaultLogError(e); + } + } + + private void doImport() throws IOException { + FileDialog dialog = new FileDialog(parent.getRenderingComposite().getShell(),SWT.OPEN); + String filename = dialog.open(); + if (filename == null) + return; + File file = new File(filename); + FileInputStream fis = new FileInputStream(file); + BufferedInputStream bis = new BufferedInputStream(fis); + byte[] data = new byte[0]; + byte[] buf = new byte[256]; + int res = 0; + while ((res = bis.read(buf)) != -1) { + byte[] newData = new byte[data.length + res]; + System.arraycopy(data, 0, newData, 0, data.length); + System.arraycopy(buf, 0, newData, data.length, res); + data = newData; + } + bis.close(); + final byte fdata[] = data; + parent.getSession().asyncWrite(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + TransferableGraph sg = TransferableGraphUtils.deserialize(fdata); + ConnectionPointList purposes = TransferableGraphUtils.integrateTransferableGraph(g, sg, null); + Resource modelResource = purposes.getSingleByDescription(TransferableGraphUtils.CP_OBJECT).resource; + Resource currentModelResource = parent.getModelResource(); + for (Statement s : g.getStatements(modelResource)) { + g.removeStatements(currentModelResource, s.getPredicate()); + } + for (Statement s : g.getStatements(modelResource)) { + + g.removeStatement(s); + g.addStatement(currentModelResource, s.getPredicate(), s.getObject()); + } + + return GraphRequestStatus.transactionComplete(); + } + }); + } + +} diff --git a/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/actions/LoadFileAction.java b/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/actions/LoadFileAction.java new file mode 100644 index 00000000..193fe45a --- /dev/null +++ b/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/actions/LoadFileAction.java @@ -0,0 +1,62 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.shapeeditor.actions; + +import org.eclipse.jface.action.Action; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.FileDialog; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.occ.geometry.OccTriangulator; + +import com.jme.renderer.ColorRGBA; +import com.jme.scene.Geometry; +import com.jme.scene.state.MaterialState; + + +public class LoadFileAction extends Action { + private ThreeDimensionalEditorBase editor; + + public LoadFileAction(ThreeDimensionalEditorBase editor) { + super("Load file"); + this.editor = editor; + + } + + public void run() { + FileDialog loadDialog = new FileDialog(editor.getRenderingComposite().getShell(), SWT.OPEN); + String exts[] = { "*.stp;*.step", "*.iges", "*.brep", "*.ply" }; //$NON-NLS-1$ + String names[] = { "STEP (AP214/AP203)", "IGES", "BREP", "PLY" }; //$NON-NLS-1$ + loadDialog.setFilterNames(names); + loadDialog.setFilterExtensions(exts); + loadDialog.setText("Load model"); + + String filename = loadDialog.open(); + if (filename != null) { + Geometry g = OccTriangulator.getGeometryFromFile(filename)[0]; + MaterialState ms = editor.getRenderingComponent().getDisplaySystem().getRenderer().createMaterialState(); + ms.setAmbient(new ColorRGBA(0.f,0.f,0.f,0.f)); + ms.setEmissive(new ColorRGBA(0.f,0.f,0.f,0.f)); + ms.setShininess(128.f); + ms.setDiffuse(new ColorRGBA(0.8f,0.8f,0.8f,0.f)); + ms.setSpecular(new ColorRGBA(1.f,1.f,1.f,0.f)); + ms.setMaterialFace(MaterialState.MF_FRONT_AND_BACK); + if (g.getColorBuffer(0) != null) { + ms.setColorMaterial(MaterialState.CM_DIFFUSE); + } + g.setRenderState(ms); + editor.getRenderingComponent().getShadowRoot().attachChild(g); + // mo.setGeometry(mesh, filename); + // xithComposite.getScene().compile(); + } + + } + +} diff --git a/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/actions/LoadFolderAction.java b/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/actions/LoadFolderAction.java new file mode 100644 index 00000000..2b7d49ec --- /dev/null +++ b/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/actions/LoadFolderAction.java @@ -0,0 +1,100 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.shapeeditor.actions; + +import java.io.File; +import java.io.FilenameFilter; +import java.util.Stack; + +import org.eclipse.jface.action.Action; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.DirectoryDialog; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.occ.geometry.OccTriangulator; + +import com.jme.bounding.BoundingBox; +import com.jme.renderer.ColorRGBA; +import com.jme.scene.Geometry; +import com.jme.scene.state.MaterialState; + + +public class LoadFolderAction extends Action { + private ThreeDimensionalEditorBase editor; + + public LoadFolderAction(ThreeDimensionalEditorBase editor) { + super("Load folder"); + this.editor = editor; + + } + + public void run() { + + DirectoryDialog loadDialog = new DirectoryDialog(editor.getRenderingComposite().getShell(), SWT.OPEN); + loadDialog.setText("Select directory"); + + String directory = loadDialog.open(); + if (directory != null) { + File file = new File(directory); + if (!file.isDirectory()) + return; + Stack directories = new Stack(); + directories.push(file); + boolean recursive = true; + while (!directories.empty()) { + File dir = directories.pop(); + + String[] files = dir.list(new PLYFilter()); + for (String filename : files) { + Geometry g = OccTriangulator.getGeometryFromFile(dir.getAbsolutePath() + "/" + filename)[0]; + MaterialState ms = editor.getRenderingComponent().getDisplaySystem().getRenderer().createMaterialState(); + ms.setAmbient(new ColorRGBA(0.f,0.f,0.f,0.f)); + ms.setEmissive(new ColorRGBA(0.f,0.f,0.f,0.f)); + ms.setShininess(128.f); + ms.setDiffuse(new ColorRGBA(0.8f,0.8f,0.8f,0.f)); + ms.setSpecular(new ColorRGBA(1.f,1.f,1.f,0.f)); + ms.setMaterialFace(MaterialState.MF_FRONT_AND_BACK); + if (g.getColorBuffer(0) != null) { + ms.setColorMaterial(MaterialState.CM_DIFFUSE); + } + g.setModelBound(new BoundingBox()); + g.updateModelBound(); + g.setRenderState(ms); + editor.getRenderingComponent().getShadowRoot().attachChild(g); + g.updateWorldBound(); + g.lock(); + + } + if (recursive) { + File[] newDirs = dir.listFiles(new DirectoryFilter()); + for (File d : newDirs) + directories.push(d); + } + } + + } + + + } + + protected class DirectoryFilter implements FilenameFilter { + public boolean accept(File dir, String name) { + File file = new File(dir.getAbsolutePath() + "/" + name); + return file.isDirectory(); + } + } + + protected class PLYFilter implements FilenameFilter { + public boolean accept(File dir, String name) { + return (name.endsWith("ply")); + } + } + +} diff --git a/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/common/ViewpointGenerator.java b/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/common/ViewpointGenerator.java new file mode 100644 index 00000000..68737366 --- /dev/null +++ b/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/common/ViewpointGenerator.java @@ -0,0 +1,196 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.shapeeditor.common; + +import java.util.Collection; + +import org.simantics.db.Builtins; +import org.simantics.db.Resource; +import org.simantics.layer0.utils.Statement; +import org.simantics.layer0.utils.IEntity; +import org.simantics.layer0.utils.viewpoints.AcceptDecision; +import org.simantics.layer0.utils.viewpoints.AcceptRule; +import org.simantics.layer0.utils.viewpoints.PlainStateFactory; +import org.simantics.layer0.utils.viewpoints.ResourceViewpoint; +import org.simantics.layer0.utils.viewpoints.State; +import org.simantics.layer0.utils.viewpoints.StateFactory; +import org.simantics.layer0.utils.viewpoints.TraversalDecision; +import org.simantics.layer0.utils.viewpoints.TraversalRule; +import org.simantics.layer0.utils.viewpoints.rules.AcceptAllResourceAcceptRule; +import org.simantics.proconf.g3d.shapeeditor.ShapeEditorResources; + + +public class ViewpointGenerator { + + public static ResourceViewpoint createStuctureViewpoint() { + StateFactory f = new PlainStateFactory(); + final State rootState = f.newState(); + final State projectState = f.newState(); + final State libraryState = f.newState(); + + return new ResourceViewpoint(new TraversalRule() { + @Override + public TraversalDecision makeTraversalDecision(State state, + Statement statement) { + Builtins b = statement.getGraph().getBuiltins(); + if (state.equals(rootState)) { + if (!statement.getPredicate().equals(b.ConsistsOf)) + return TraversalDecision.stopTraversal; + //if (!statement.getObject().isInstanceOf(b.Project)) + // return TraversalDecision.stopTraversal; + return TraversalDecision.continueTraversal(projectState); + } else if (state.equals(projectState)) { + if (!statement.getPredicate().equals(b.ConsistsOf)) + return TraversalDecision.stopTraversal; + //if (!statement.getObject().isInstanceOf(b.Library)) + // return TraversalDecision.stopTraversal; + return TraversalDecision.continueTraversal(libraryState); + } else if (state.equals(libraryState)) { + if (!statement.getPredicate().equals(b.ConsistsOf) + && !statement.getPredicate().isSubrelationOf( + ShapeEditorResources.g3dResource.HasChild)) + return TraversalDecision.stopTraversal; + return TraversalDecision.continueTraversal(libraryState); + } + return TraversalDecision.stopTraversal; + } + + @Override + public boolean areAllStatesRelevant() { + return true; + } + + @Override + public Collection relevantStates() { + return null; + } + }, new AcceptAllResourceAcceptRule(), rootState); + } + + public static ResourceViewpoint createObjectStructureViewpoint() { + StateFactory f = new PlainStateFactory(); + final State rootState = f.newState(); + + return new ResourceViewpoint(new TraversalRule() { + @Override + public TraversalDecision makeTraversalDecision(State state, + Statement statement) { + if (state.equals(rootState)) { + if (!statement.getPredicate().isSubrelationOf( + ShapeEditorResources.g3dResource.HasChild)) + return TraversalDecision.stopTraversal; + return TraversalDecision.continueTraversal(rootState); + } + return TraversalDecision.stopTraversal; + } + + @Override + public boolean areAllStatesRelevant() { + return true; + } + + @Override + public Collection relevantStates() { + return null; + } + }, new AcceptAllResourceAcceptRule(), rootState); + } + + public static ResourceViewpoint createObjectSizingParameterViewpoint(Resource modelToParameterRelation) { + StateFactory f = new PlainStateFactory(); + final State rootState = f.newState(); + final State endState = f.newState(); + final Resource relation = modelToParameterRelation; + + return new ResourceViewpoint(new TraversalRule() { + @Override + public TraversalDecision makeTraversalDecision(State state, + Statement statement) { + if (state.equals(rootState)) { + if (!statement.getPredicate().isSubrelationOf(relation)) + return TraversalDecision.stopTraversal; + return TraversalDecision.continueTraversal(endState); + } + return TraversalDecision.stopTraversal; + } + + @Override + public boolean areAllStatesRelevant() { + return true; + } + + @Override + public Collection relevantStates() { + return null; + } + }, new AcceptAllResourceAcceptRule(), rootState); + } + + public static ResourceViewpoint createViewpoint() { + StateFactory f = new PlainStateFactory(); + final State rootState = f.newState(); + final State projectState = f.newState(); + final State libraryState = f.newState(); + + return new ResourceViewpoint(new TraversalRule() { + @Override + public TraversalDecision makeTraversalDecision(State state, Statement statement) { + Builtins b = statement.getGraph().getBuiltins(); + if (state.equals(rootState)) { + if (statement.getObject().isInstanceOf(b.Ontology)) + return TraversalDecision.stopTraversal; + if(!statement.getPredicate().equals(b.ConsistsOf)) + return TraversalDecision.stopTraversal; + return TraversalDecision.continueTraversal(projectState); + } else if (state.equals(projectState)) { + if(!statement.getPredicate().equals(b.ConsistsOf)) + return TraversalDecision.stopTraversal; + return TraversalDecision.continueTraversal(libraryState); + } else if (state.equals(libraryState)) { + if(!statement.getPredicate().equals(b.ConsistsOf)) + return TraversalDecision.stopTraversal; + return TraversalDecision.continueTraversal(libraryState); + } + return TraversalDecision.stopTraversal; + } + + @Override + public boolean areAllStatesRelevant() { + return true; + } + + @Override + public Collection relevantStates() { + return null; + } + }, new AcceptRule() { + @Override + public AcceptDecision makeAcceptDecision(State state, IEntity obj) { + Builtins b = obj.getGraph().getBuiltins(); + //NOSEResource nr = NOSEResource.getInstance(obj.getGraph()); + if(obj.isInstanceOf(b.Project)) return AcceptDecision.REJECT; + else if (obj.isInstanceOf(b.Ontology)) return AcceptDecision.REJECT; + else return AcceptDecision.ACCEPT; + } + + @Override + public boolean areAllStatesRelevant() { + return true; + } + + @Override + public Collection relevantStates() { + return null; + } + }, rootState); + } + +} diff --git a/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/dialogs/PropertySelectionDialog.java b/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/dialogs/PropertySelectionDialog.java new file mode 100644 index 00000000..09a5addb --- /dev/null +++ b/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/dialogs/PropertySelectionDialog.java @@ -0,0 +1,112 @@ +package org.simantics.proconf.g3d.shapeeditor.dialogs; + +import java.util.List; + +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Tree; +import org.eclipse.swt.widgets.TreeItem; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Resource; +import org.simantics.db.Session; +import org.simantics.proconf.g3d.tools.PropertyTree; + +public class PropertySelectionDialog extends Dialog { + String title = null; + String message = null; + + Session session; + PropertyTree propertyTree; + Resource[] selectedTypes = null; + List selectedPropertyInstances = null; + List selectedInstances = null; + + public PropertySelectionDialog(Shell parentShell, String dialogTitle, String dialogMessage, Session session, List selectedResources) { + super(parentShell); + this.session = session; + this.title = dialogTitle; + this.message = dialogMessage; + this.selectedInstances = selectedResources; + } + + @Override + protected void configureShell(Shell newShell) { + + super.configureShell(newShell); + if (title != null) + newShell.setText(title); + } + + protected Control createDialogArea(Composite parent) { + Composite composite = (Composite) super.createDialogArea(parent); + + Label label = new Label(composite, SWT.WRAP); + label.setText(message); + GridData data = new GridData(GridData.GRAB_HORIZONTAL + | GridData.GRAB_VERTICAL | GridData.HORIZONTAL_ALIGN_FILL + | GridData.VERTICAL_ALIGN_CENTER); + data.widthHint = convertHorizontalDLUsToPixels(IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH); + label.setLayoutData(data); + label.setFont(parent.getFont()); + + Tree tree = new Tree(composite,SWT.SINGLE); + propertyTree = new PropertyTree(tree,session); + + GridData data2 = new GridData(GridData.GRAB_HORIZONTAL + | GridData.GRAB_VERTICAL | GridData.HORIZONTAL_ALIGN_FILL + | GridData.VERTICAL_ALIGN_FILL); + data2.widthHint = convertHorizontalDLUsToPixels(IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH); + data2.heightHint = 200; + tree.setLayoutData(data2); + tree.setFont(parent.getFont()); + + tree.showSelection(); + + applyDialogFont(composite); + + //propertyTree.setProperties(selectionAdapter.getCurrentSelection()); + propertyTree.setProperties(selectedInstances); + return composite; + } + + @Override + public boolean close() { + TreeItem selected[] = propertyTree.getTree().getSelection(); + if (selected.length == 0) { + selectedTypes = null; + } else { + selectedTypes = new Resource[selected.length]; + for (int i = 0; i < selected.length; i++) { + selectedTypes[i] = (Resource)selected[i].getData(); + } + } + //final ArrayList instances = new ArrayList(); +// for (Resource rs : selectionAdapter.getCurrentSelection().getSelectionList()) { +// instances.add(rs); +// } + + + session.syncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + selectedPropertyInstances = propertyTree.findPropertyInstances(g,selectedInstances); + return GraphRequestStatus.transactionComplete(); + } + }); + + return super.close(); + } + + public List getSelectedPropertyInstances() { + return selectedPropertyInstances; + } + +} \ No newline at end of file diff --git a/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/handlers/CSGProjectAdapter.java b/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/handlers/CSGProjectAdapter.java new file mode 100644 index 00000000..5c0835d5 --- /dev/null +++ b/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/handlers/CSGProjectAdapter.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.shapeeditor.handlers; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.db.adaption.AdaptionException; +import org.simantics.db.adaption.ResourceAdapter; + + +public class CSGProjectAdapter implements ResourceAdapter { + @SuppressWarnings("unchecked") + @Override + public T adapt(Graph graph, Resource resource, Resource mia) throws AdaptionException { + return (T) new CSGProjectType(graph, resource); + + } +} diff --git a/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/handlers/CSGProjectType.java b/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/handlers/CSGProjectType.java new file mode 100644 index 00000000..a220f784 --- /dev/null +++ b/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/handlers/CSGProjectType.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.shapeeditor.handlers; + +import java.util.ArrayList; +import java.util.Collection; + +import org.simantics.db.Builtins; +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.layer0.utils.direct.GraphUtils; +import org.simantics.proconf.ui.projects.IProject; +import org.simantics.proconf.ui.projects.ProjectType; + +public class CSGProjectType extends ProjectType { + + public CSGProjectType(Graph graph, Resource projectTypeResource) { + super(graph, projectTypeResource); + } + + @Override + public Resource createProject(Graph g, String name) throws Exception { + Resource project = super.createProject(g, name); + Builtins b = g.getBuiltins(); + + { // Models + Resource modelLibrary = g.newResource(); + g.addStatement(modelLibrary, b.InstanceOf, b.ModelLibrary); + GraphUtils.addRelatedScalarString(g, modelLibrary, b.HasName, "Models"); + g.addStatement(project, b.ConsistsOf, modelLibrary); + } + + + + return project; + } + + @Override + public IProject loadProject(Graph g, Resource r) { + IProject project = super.loadProject(g, r); + project.set(DefaultPerspective, "org.simantics.proconf.shapeeditor.perspectives.csg"); + Collection perspectives = new ArrayList(); + perspectives.add("org.simantics.proconf.shapeeditor.perspectives.csg"); + project.set(Perspectives, perspectives); + + return project; + } + +} diff --git a/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/handlers/NewCSGModelHandler.java b/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/handlers/NewCSGModelHandler.java new file mode 100644 index 00000000..be793634 --- /dev/null +++ b/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/handlers/NewCSGModelHandler.java @@ -0,0 +1,54 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.shapeeditor.handlers; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.ui.handlers.HandlerUtil; +import org.simantics.proconf.g3d.csg.stubs.CSGModel; + +import org.simantics.proconf.ui.ProConfUI; +import org.simantics.proconf.ui.utils.ResourceAdaptionUtils; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Resource; +import org.simantics.layer0.stubs.Library; + + +public class NewCSGModelHandler extends AbstractHandler { + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + ISelection s = HandlerUtil.getCurrentSelectionChecked(event); + IStructuredSelection ss = (IStructuredSelection) s; + if (ss.size() != 1) + return null; + final Resource lib = ResourceAdaptionUtils.toSingleResource(ss); + ProConfUI.getSession().asyncWrite(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + CSGModel model = CSGModel.createDefault(g); + Library l = new Library(g, lib); + l.addStatement(g.getBuiltins().ConsistsOf, model); + + return GraphRequestStatus.transactionComplete(); + } + }); + + + return null; + } + +} diff --git a/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/handlers/ResourceEditorAdapter1.java b/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/handlers/ResourceEditorAdapter1.java new file mode 100644 index 00000000..41f07ade --- /dev/null +++ b/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/handlers/ResourceEditorAdapter1.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.shapeeditor.handlers; + +import org.simantics.proconf.g3d.shapeeditor.Activator; +import org.simantics.proconf.g3d.shapeeditor.ShapeEditorResources; +import org.simantics.proconf.ui.workbench.ResourceEditorInput; +import org.simantics.proconf.ui.workbench.editor.SimpleEditorAdapter; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.utils.ui.BundleUtils; +import org.simantics.utils.ui.workbench.WorkbenchUtils; + + +public class ResourceEditorAdapter1 extends SimpleEditorAdapter { + + public ResourceEditorAdapter1() { + super("ShapeEditor", + BundleUtils.getImageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/union.png"), + null,null,null); + } + + @Override + public boolean canHandle(Graph g, Resource r) { + if(ShapeEditorResources.csgResource == null) return false; + if(ShapeEditorResources.csgResource.CSGModel == null) return false; + return g.isInstanceOf(r, ShapeEditorResources.csgResource.CSGModel); + } + + + @Override + public void openEditor(Resource r) throws Exception { + WorkbenchUtils.openEditor("org.simantics.proconf.shapeeditor.editor1", new ResourceEditorInput("org.simantics.proconf.shapeeditor.editor1",r)); + + } + +} diff --git a/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/handlers/ResourceEditorAdapter3.java b/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/handlers/ResourceEditorAdapter3.java new file mode 100644 index 00000000..f861179e --- /dev/null +++ b/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/handlers/ResourceEditorAdapter3.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.shapeeditor.handlers; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.proconf.g3d.shapeeditor.Activator; +import org.simantics.proconf.g3d.shapeeditor.ShapeEditorResources; +import org.simantics.proconf.ui.workbench.ResourceEditorInput; +import org.simantics.proconf.ui.workbench.editor.SimpleEditorAdapter; +import org.simantics.utils.ui.BundleUtils; +import org.simantics.utils.ui.workbench.WorkbenchUtils; + + +public class ResourceEditorAdapter3 extends SimpleEditorAdapter { + + public ResourceEditorAdapter3() { + super("Parameterization Editor", + BundleUtils.getImageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/unlink.png"), + null,null,null); + } + + @Override + public boolean canHandle(Graph g, Resource r) { + if(ShapeEditorResources.csgResource == null) return false; + if(ShapeEditorResources.csgResource.CSGModel == null) return false; + return g.isInstanceOf(r, ShapeEditorResources.csgResource.CSGModel); + } + + + @Override + public void openEditor(Resource r) throws Exception { + WorkbenchUtils.openEditor("org.simantics.proconf.shapeeditor.editor3", new ResourceEditorInput("org.simantics.proconf.shapeeditor.editor3",r)); + + } + +} diff --git a/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/perspectives/CSGModellingPerspective.java b/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/perspectives/CSGModellingPerspective.java new file mode 100644 index 00000000..f6c6a58c --- /dev/null +++ b/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/perspectives/CSGModellingPerspective.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.shapeeditor.perspectives; + +import org.eclipse.ui.IPageLayout; +import org.eclipse.ui.IPerspectiveFactory; + +public class CSGModellingPerspective implements IPerspectiveFactory { + + @Override + public void createInitialLayout(IPageLayout layout) { + + } + +} diff --git a/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/scenegraph/CSGShapeNode.java b/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/scenegraph/CSGShapeNode.java new file mode 100644 index 00000000..1bf8fe70 --- /dev/null +++ b/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/scenegraph/CSGShapeNode.java @@ -0,0 +1,108 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.shapeeditor.scenegraph; + + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.proconf.g3d.base.GeometryProviderRegistry; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.scenegraph.IGraphicsNode; +import org.simantics.proconf.g3d.scenegraph.ShapeNode; + +import com.jme.scene.Geometry; +import com.jme.scene.state.AlphaState; +import com.jme.scene.state.ZBufferState; + + + +public class CSGShapeNode extends ShapeNode{ + + + //protected Geometry axesGeometry = null; + protected boolean axesVisible = false; + + public CSGShapeNode(ThreeDimensionalEditorBase editor,IGraphicsNode parent, Graph graph, Resource shapeResource) { + super(editor,parent, graph,shapeResource); + //axesGeometry = AxesShape.getShape(editor.getRenderingComponent().getDisplaySystem().getRenderer()); + ZBufferState zs = editor.getRenderingComponent().getDisplaySystem().getRenderer().createZBufferState(); + zs.setFunction(ZBufferState.CF_ALWAYS); + AlphaState as = editor.getRenderingComponent().getDisplaySystem().getRenderer().createAlphaState(); + as.setBlendEnabled(true); + as.setDstFunction(AlphaState.DB_ONE_MINUS_SRC_ALPHA); + as.setSrcFunction(AlphaState.DB_SRC_ALPHA); +// axesGeometry.setRenderState(zs); +// axesGeometry.setRenderState(as); +// axesGeometry.setRenderQueueMode(Renderer.QUEUE_TRANSPARENT); + } + + + + public Geometry[] getGeometry(Graph graph) { + + return GeometryProviderRegistry.getGeometry(getG3DNode(graph), false); + } + + public void updateAllGeometry() { + //System.out.println("CSGSHapeNode.updateAllGeometry " + shapeResource.getResourceId()); + editor.getScenegraphAdapter().updateGeometry(shapeResource); + if (parent != null && parent instanceof CSGShapeNode) { + ((CSGShapeNode)parent).updateAllGeometry(); + } + + } + + @Override + public void updateGeometry(Graph graph) { + super.updateGeometry(graph); + if (isAxesVisible()) { + //getGroup().attachChild(axesGeometry); + } else { + //axesGeometry.removeFromParent(); + } + } + + + + public boolean isAxesVisible() { + return axesVisible; + } + + public void setAxesVisible(boolean axesVisible) { + + if (this.axesVisible == axesVisible) + return; + this.axesVisible = axesVisible; + if (isAxesVisible()) { + //getGroup().getParent().attachChild(axesGeometry); + //getGroup().attachChild(axesGeometry); + } else { + //axesGeometry.removeFromParent(); + } + } + + public void setSelected(boolean selected) { + if (this.selected == selected) + return; + this.selected = selected; + if (selected) { + + setSelectedVisible(true); + setAxesVisible(true); + setTransparentVisible(true); + } else { + setSelectedVisible(false); + setAxesVisible(false); + setTransparentVisible(false); + } + } + +} diff --git a/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/tools/AnimationContribution.java b/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/tools/AnimationContribution.java new file mode 100644 index 00000000..b81aa30b --- /dev/null +++ b/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/tools/AnimationContribution.java @@ -0,0 +1,774 @@ +package org.simantics.proconf.g3d.shapeeditor.tools; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import javax.vecmath.AxisAngle4d; +import javax.vecmath.Quat4d; + +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.IToolBarManager; +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.InputDialog; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.CCombo; +import org.eclipse.swt.events.FocusAdapter; +import org.eclipse.swt.events.FocusEvent; +import org.eclipse.swt.events.KeyAdapter; +import org.eclipse.swt.events.KeyEvent; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.layout.FormAttachment; +import org.eclipse.swt.layout.FormData; +import org.eclipse.swt.layout.FormLayout; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Slider; +import org.eclipse.swt.widgets.Text; +import org.simantics.db.ContextGraph; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.GraphRequestWithResult; +import org.simantics.db.Resource; +import org.simantics.g2d.stubs.anim.Animation; +import org.simantics.g2d.stubs.anim.Interpolator; +import org.simantics.g2d.stubs.anim.ScalarInterpolator; +import org.simantics.g2d.stubs.anim.SlerpInterpolator; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.layer0.utils.Property; +import org.simantics.proconf.animation.curve.SlerpCurve; +import org.simantics.proconf.animation.curve.TCBCurve; +import org.simantics.proconf.g3d.actions.ContextAction; +import org.simantics.proconf.g3d.actions.RotateAction; +import org.simantics.proconf.g3d.actions.TranslateAction; +import org.simantics.proconf.g3d.animation.Animatable; +import org.simantics.proconf.g3d.base.EditorContribution; +import org.simantics.proconf.g3d.base.G3DTools; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.base.VisualizationScheduler; +import org.simantics.proconf.g3d.common.StructuredResourceSelection; +import org.simantics.proconf.g3d.scenegraph.IGraphicsNode; +import org.simantics.proconf.g3d.scenegraph.ISelectableNode; +import org.simantics.proconf.g3d.shapeeditor.ShapeEditorResources; +import org.simantics.proconf.g3d.shapeeditor.dialogs.PropertySelectionDialog; +import org.simantics.proconf.g3d.shapeeditor.views.ShapeEditorBase; +import org.simantics.proconf.g3d.stubs.G3DModel; +import org.simantics.proconf.g3d.stubs.Orientation; +import org.simantics.utils.ErrorLogger; + +public class AnimationContribution implements EditorContribution { + List actions = new ArrayList(); + + private ShapeEditorBase parent; + + private final String NO_ANIMATION = "None"; + + private Slider timeSlider; + private double key = 0; + private Composite buttonComposite; + private Button insertKeyFrameButton; + private Button clearKeyFrameButton; + private CCombo animationCombo; + private Button addAnimationButton; + private Button removeAnimationButton; + private Button clearAnimationButton; + private Button animateButton; + private Button usePrecalculation; + private Text timeText; + private Composite infoComposite; + private Text infoText; + + private Resource animationResource; + + private ContextAction translateAction; + private ContextAction rotateAction; + + public AnimationContribution(ThreeDimensionalEditorBase parent) { + this.parent = (ShapeEditorBase)parent; + } + + @Override + public String getName() { + return "Animator"; + } + + @Override + public void createControl(Composite parent) { + FormLayout flayout = new FormLayout(); + parent.setLayout(flayout); + infoComposite = new Composite(parent, SWT.BORDER); + FormData data = new FormData(); + data.top = new FormAttachment(0, 0); + data.left = new FormAttachment(0, 0); + data.right = new FormAttachment(100, 0); + data.bottom = new FormAttachment(infoComposite, 0, SWT.TOP); + this.parent.getRenderingComposite().setLayoutData(data); + + infoComposite.setLayout(new FillLayout(SWT.VERTICAL)); + infoText = new Text(infoComposite, SWT.NONE); + GridLayout layout = new GridLayout(2, false); + layout.horizontalSpacing = 2; + layout.verticalSpacing = 2; + layout.marginWidth = 1; + layout.marginHeight = 1; + infoComposite.setLayout(layout); + GridData gdata = new GridData(SWT.BEGINNING, SWT.CENTER, true, false, 2, 1); + // FIXME : allows text widget to take all available space (horizontal / width) + gdata.widthHint = 2000; + infoText.setLayoutData(gdata); + timeSlider = new Slider(infoComposite, SWT.NONE); + timeSlider.setValues(0, 0, 100, 1, 1, 1); + timeSlider.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + key = ((double) timeSlider.getSelection()) / 100.0; + updateTime(); + } + }); + timeSlider.setLayoutData(new GridData(SWT.FILL, 1, true, false)); + timeText = new Text(infoComposite, SWT.SINGLE); + timeText.addFocusListener(new FocusAdapter() { + @Override + public void focusLost(FocusEvent e) { + updateTime(); + } + }); + timeText.addKeyListener(new KeyAdapter() { + @Override + public void keyReleased(KeyEvent e) { + if (e.keyCode == SWT.CR) + updateTime(); + } + }); + + buttonComposite = new Composite(infoComposite, SWT.NONE); + buttonComposite.setLayout(new FillLayout(SWT.HORIZONTAL)); + buttonComposite.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, true, false, 2, 1)); + insertKeyFrameButton = new Button(buttonComposite, SWT.PUSH); + insertKeyFrameButton.setText("Insert Keyframe"); + insertKeyFrameButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + insertKeyFrame(); + } + }); + + clearKeyFrameButton = new Button(buttonComposite, SWT.PUSH); + clearKeyFrameButton.setText("Clear Keyframe"); + + animationCombo = new CCombo(buttonComposite, SWT.NONE); + animationCombo.add(NO_ANIMATION); + animationCombo.select(0); + animationCombo.setEditable(false); + animationCombo.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + selectAnimation(); + } + }); + + addAnimationButton = new Button(buttonComposite, SWT.PUSH); + addAnimationButton.setText("New Animation"); + addAnimationButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + addAnimation(); + } + }); + + clearAnimationButton = new Button(buttonComposite, SWT.PUSH); + clearAnimationButton.setText("Clear Animation"); + clearAnimationButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + clearAnimation(); + } + }); + + removeAnimationButton = new Button(buttonComposite, SWT.PUSH); + removeAnimationButton.setText("Remove Animation"); + removeAnimationButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + removeAnimation(); + } + }); + + animateButton = new Button(buttonComposite, SWT.TOGGLE); + animateButton.setText("Animate"); + animateButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + animate(); + } + }); + + usePrecalculation = new Button(buttonComposite, SWT.CHECK); + usePrecalculation.setText("Precalc"); + + data = new FormData(); + data.left = new FormAttachment(0, 0); + data.right = new FormAttachment(100, 0); + data.bottom = new FormAttachment(100, 0); + // FIXME : take account font size + data.height = 20 * 3; + infoComposite.setLayoutData(data); + + this.parent.getSelectionAdapter().addSelectionChangedListener(new ISelectionChangedListener() { + public void selectionChanged(SelectionChangedEvent event) { + updateUI(); + } + }); + updateUI(); + + this.parent.getSession().asyncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + G3DModel m = new G3DModel(g,AnimationContribution.this.parent.getModelResource()); + Collection animations = m.getAnimation(); + + final List animationNames = new ArrayList(); + for (Animation a : animations) { + animationNames.add(a.getName()); + } + AnimationContribution.this.parent.getRenderingComposite().getDisplay().asyncExec(new Runnable() { + public void run() { + for (String s : animationNames) + animationCombo.add(s); + } + }); + return GraphRequestStatus.transactionComplete(); + } + + }); + } + + @Override + public void disposeControl() { + if (animateRunnable != null) + VisualizationScheduler.getInstance().removeVisualization(animateRunnable); + animateRunnable = null; + + infoComposite.dispose(); + + } + + @Override + public void fillContextMenu(Graph graph, IMenuManager manager, StructuredResourceSelection selection) { + + } + + + + @Override + public Collection getActions() { + return actions; + } + + @Override + public void initialize(Graph graph) { + actions.add(translateAction = new TranslateAction(parent) { + @Override + public void setInfoText(String text) { + infoText.setText(text); + } + }); + actions.add(rotateAction = new RotateAction(parent){ + @Override + public void setInfoText(String text) { + infoText.setText(text); + } + }); + } + + private double getCurrentKey() { + return key; + } + + private void updateTime() { + final double t = getCurrentKey(); + timeText.setText(Double.toString(t)); + if (animationResource == null) + return; + if (usePrecalculation.getSelection()) { + for (IGraphicsNode n : parent.getScenegraphAdapter().getNodes()) { + if (n instanceof Animatable) { + // TODO : frame-rate dependent animations + ((Animatable)n).animate(t,0.0); + } + parent.setViewChanged(true); + } + } else { + parent.getSession().asyncWrite(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + Collection interpolators = getAnimation(g).getRelatedObjects(ShapeEditorResources.animationResource.HasInterpolator); + for (IEntity i : interpolators) { + if (i.isInstanceOf(ShapeEditorResources.animationResource.ScalarInterpolator)) { + // TODO : creating curve each time when time is set is + // slow. Curve should be cached + TCBCurve c = (TCBCurve) ShapeEditorResources.curveBuilder.loadInterpolator(i); + double out = c.evaluate(t); + g.setScalarDouble(i.getSingleRelatedObject(ShapeEditorResources.animationResource.HasTarget).getResource(), out); + } else if (i.isInstanceOf(ShapeEditorResources.animationResource.SlerpInterpolator)) { + // TODO : creating curve each time when time is set is slow. + // Curve should be cached + SlerpCurve c = (SlerpCurve) ShapeEditorResources.curveBuilder.loadInterpolator(i); + Quat4d out = c.evaluate(t); + Orientation r = new Orientation(i.getSingleRelatedObject(ShapeEditorResources.animationResource.HasTarget)); + AxisAngle4d aa = new AxisAngle4d(); + aa.set(out); + G3DTools.setOrientation(r, aa); + } + } + return GraphRequestStatus.transactionComplete(); + } + + @Override + public void requestCompleted(GraphRequestStatus status) { + parent.getScenegraphAdapter().setChanged(true); + } + }); + } + } + + private IEntity findPropertyInterpolator(Graph g, Resource property) { + Collection interpolators = getAnimation(g).getRelatedObjects(ShapeEditorResources.animationResource.HasInterpolator); + for (IEntity i : interpolators) { + IEntity e = i.getAtMostOneRelatedObject(ShapeEditorResources.animationResource.HasTarget); + if (e == null) + continue; + if (e.getResource().equals(property)) { + return i; + } + } + return null; + } + + private void insertKeyFrame() { + ArrayList instances = new ArrayList(); + for (Resource rs : parent.getSelectionAdapter().getCurrentSelection().getSelectionList()) { + instances.add(rs); + } + PropertySelectionDialog dialog = new PropertySelectionDialog(parent.getRenderingComposite().getShell(),"Select property","Select animated property",parent.getSession(),instances); + if (dialog.open() == Dialog.CANCEL) { + return; + } + final List properties = dialog.getSelectedPropertyInstances(); + parent.getSession().asyncWrite(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + for (Resource r : properties) { + IEntity t = EntityFactory.create(g,r); + IEntity current = findPropertyInterpolator(g, r); + if (t.isInstanceOf(ShapeEditorResources.g3dResource.Position)) { + + for (int i = 0; i < 3; i++) { + IEntity d = null; + switch (i) { + case 0: + d = t.getSingleRelatedObject(ShapeEditorResources.g3dResource.HasX); + break; + case 1: + d = t.getSingleRelatedObject(ShapeEditorResources.g3dResource.HasY); + break; + case 2: + d = t.getSingleRelatedObject(ShapeEditorResources.g3dResource.HasZ); + break; + } + current = findPropertyInterpolator(g, d.getResource()); + addScalarKey(current,d); + } + + } else if (t.isInstanceOf(ShapeEditorResources.g3dResource.Orientation)) { + Orientation rot = new Orientation(t); + addSlerpKey(current, rot); + } else if (t.isInstanceOf(ShapeEditorResources.g3dResource.Color)) { + for (int i = 0; i < 3; i++) { + IEntity d = null; + switch (i) { + case 0: + d = t.getSingleRelatedObject(ShapeEditorResources.g3dResource.HasRed); + break; + case 1: + break; + case 2: + break; + } + current = findPropertyInterpolator(g, d.getResource()); + addScalarKey(current,d); + } + } else if (t.isInstanceOf(g.getBuiltins().Double)) { + addScalarKey(current,t); + } else { + // TODO: basic cases are handled, only way to support + // is to find all doubles from property structure and + // interpolators attached to them, if there's any + ErrorLogger.getDefault().logWarning("Default keyframe adding has not been implemented", null); + } + } + return GraphRequestStatus.transactionComplete(); + } + }); + } + + private void addScalarKey(IEntity current, IEntity d) { + + Graph graph = d.getGraph(); + if (current == null) { + current = ScalarInterpolator.createDefault(graph).toInterpolator(); // FIXME : stubcast + getAnimation(graph).addStatement(ShapeEditorResources.animationResource.HasInterpolator, current); + current.addStatement(ShapeEditorResources.animationResource.HasTarget, d); + } + ShapeEditorResources.curveBuilder.addKey(current,getCurrentKey(),new double[]{d.getGraph().getScalarDouble(d.getResource()),0.0,0.0,0.0}); + } + + private void addSlerpKey(IEntity current, Orientation r) { + Graph graph = r.getGraph(); + if (current == null) { + current = SlerpInterpolator.createDefault(graph).toInterpolator(); // FIXME : stubcast + getAnimation(graph).addStatement(ShapeEditorResources.animationResource.HasInterpolator, current); + current.addStatement(ShapeEditorResources.animationResource.HasTarget, r); + + } + AxisAngle4d aa = G3DTools.getOrientation(r); + Quat4d q = new Quat4d(); + q.set(aa); + ShapeEditorResources.curveBuilder.addKey(current,getCurrentKey(),new double[]{q.w,q.x,q.y,q.z}); + } + + private void selectAnimation() { + if (animationCombo.getSelectionIndex() == 0) { + animationResource = null; + updateUI(); + } else { + final String name = animationCombo.getItem(animationCombo.getSelectionIndex()); + parent.getSession().asyncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + + Resource modelResource = parent.getModelResource(); + G3DModel m = new G3DModel(g, modelResource); + Collection animations = m.getAnimation(); + boolean found = false; + for (Animation a : animations) { + if (a.getName().startsWith(name) && a.getName().length() == name.length()) { + animationResource = a.getResource(); + found = true; + break; + } + } + if (!found) { + ErrorLogger.defaultLogError("Could find animation " + name + " for model " + m.getResource(), null); + animationResource = null; + } + return GraphRequestStatus.transactionComplete(); + } + @Override + public void requestCompleted(GraphRequestStatus status) { + parent.getRenderingComposite().getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + updateUI(); + } + }); + } + }); + } + } + + private Animation getAnimation(Graph graph) { + return new Animation(graph, animationResource); + } + + private void addAnimation() { + InputDialog d = new InputDialog(parent.getRenderingComposite().getShell(),"Animation name","Animation name","",null); + if (d.open() == InputDialog.CANCEL) { + return; + } + final String name = d.getValue(); + if (name == null || name.length() == 0) { + return; + } + parent.getSession().asyncWrite(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + G3DModel m = parent.getModel(g); + Collection animations = m.getRelatedObjects(ShapeEditorResources.animationResource.HasAnimation); + for (IEntity a : animations) { + if (a.getName().startsWith(name) && a.getName().length() == name.length()) { + ErrorLogger.getDefault().logWarning("Cannot add animation with the same name " + name, null); + return GraphRequestStatus.transactionCancel(); + } + } + + Animation newAnimation = Animation.createDefault(g); + newAnimation.setName(name); + m.addStatement(ShapeEditorResources.animationResource.HasAnimation, newAnimation); + + return GraphRequestStatus.transactionComplete(); + } + + @Override + public void requestCompleted(GraphRequestStatus status) { + parent.getRenderingComposite().getDisplay().asyncExec(new Runnable() { + public void run() { + animationCombo.add(name); + animationCombo.select(animationCombo.indexOf(name)); + selectAnimation(); + } + }); + } + }); + } + + private void removeAnimation() { + assert(animationResource != null); + GraphRequestWithResult r = new GraphRequestWithResult() { + public String performWithResult(Graph g) throws Exception { + return getAnimation(g).getName(); + }; + }; + parent.getSession().syncRead(r); + MessageDialog dialog = new MessageDialog(parent.getRenderingComposite().getShell(),"Confirm",null,"Do you want to remove animation " + r.getResult() ,MessageDialog.QUESTION,new String[]{"Yes","No"},1); + if (dialog.open() == 1) + return; + parent.getSession().asyncWrite(new GraphRequestAdapter() { + String name; + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + + Animation currentAnimation = getAnimation(g); + name = currentAnimation.getName(); + parent.getModel(g).removeStatement(ShapeEditorResources.animationResource.HasAnimation, currentAnimation); + + return GraphRequestStatus.transactionComplete(); + } + + @Override + public void requestCompleted(GraphRequestStatus status) { + parent.getRenderingComposite().getDisplay().asyncExec(new Runnable() { + public void run() { + animationCombo.remove(animationCombo.indexOf(name)); + } + }); + } + }); + } + + private void clearAnimation() { + assert(animationResource != null); + + parent.getSession().asyncWrite(new GraphRequestAdapter() { + + boolean proceed; + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + int size = getAnimation(g).getInterpolator().size(); + if (size == 0) + return GraphRequestStatus.transactionCancel(); + final String name = getAnimation(g).getName(); + parent.getRenderingComposite().getDisplay().syncExec(new Runnable() { + public void run() { + MessageDialog dialog = new MessageDialog(parent.getRenderingComposite().getShell(),"Confirm",null,"Do you want to clear animation " + name ,MessageDialog.QUESTION,new String[]{"Yes","No"},1); + proceed = (dialog.open() != MessageDialog.CANCEL); + } + }); + if (proceed) { + //getAnimation(g).getInterpolator().clear(); + getAnimation(g).removeRelatedStatements(ShapeEditorResources.animationResource.HasInterpolator); + return GraphRequestStatus.transactionComplete(); + } else { + return GraphRequestStatus.transactionCancel(); + } + } + }); + } + + public Graph createAnimationParameterization(Graph g) { + if (g.getObjects(parent.getModelResource(), ShapeEditorResources.g3dResource.HasSizingParameter).size() > 0) { + ContextGraph graph; + if (!(g instanceof ContextGraph)) { + graph = new ContextGraph(g); + graph.setContext(parent.getModelResource()); + } else { + graph = (ContextGraph)g; + } + Animation animation = getAnimation(graph); + Collection interpolators = animation.getInterpolator(); + for (org.simantics.g2d.stubs.anim.Interpolator interpolator : interpolators) { + IEntity target = interpolator.getTarget(); + // check all model properties + G3DModel model = parent.getModel(graph); + Collection modelProperties = model.getRelatedProperties(ShapeEditorResources.g3dResource.HasSizingParameter); + for (Property p : modelProperties) { + IEntity t = EntityFactory.create(graph,p.getResource()); + // get parameterization equations + Collection equations = t.getRelatedObjects(ShapeEditorResources.equationResource.HasTarget); + // get parameterized values + Collection parameterTargets = new ArrayList(); + for (IEntity eq : equations) { + Collection tgts = eq.getRelatedObjects(ShapeEditorResources.equationResource.HasTarget); + assert(tgts.size() == 1); + parameterTargets.add(tgts.iterator().next()); + } + // do matching between interpolator targets and parameterized values + // TODO : old system did not have inverse relations but current system does. + // it is possible to take interpolation target and find if it is connected to an equation + // this would make code much faster (no more stupid loops over everything) + for (IEntity d : parameterTargets) { + if (d.getResource().equals(target.getResource())) { + // get default value for sizing property + Collection prop = t.getRelatedObjects(ShapeEditorResources.g3dResource.HasDefaultDoubleValue); + if (prop.size() == 1) { + ShapeEditorResources.curveBuilder.parameterize(interpolator, prop.iterator().next().toProperty().getDoubleArray(), p.getDoubleArray()); + } else { + ErrorLogger.defaultLogError("Cannot parameterize interpolator " + interpolator.getResource() + " of animation " + animation.getResource() + " since parameter " + p.getResource() + " has no default value", null); + } + } + } + } + } + + return graph; + } else { + return g; + } + } + + private AnimateRunnable animateRunnable = null; + + private void animate() { + updateUI(); + if (animateButton.getSelection()) { + if (animateRunnable != null) + return; + if (usePrecalculation.getSelection()) { + parent.getSession().asyncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + Graph graph = parent.createParameterization(g); + createAnimationParameterization(graph); + for (IGraphicsNode n : parent.getScenegraphAdapter().getNodes()) { + if (n instanceof ISelectableNode) { + if (!((ISelectableNode)n).isVisible()) + continue; + } + if (n instanceof Animatable) { + ((Animatable)n).setAnimation(graph,animationResource); + } + } + return GraphRequestStatus.transactionComplete(); + } + + @Override + public void requestCompleted(GraphRequestStatus status) { + animateRunnable = new AnimateRunnable(); + VisualizationScheduler.getInstance().addVisualization(animateRunnable); + } + }); + } else { + animateRunnable = new AnimateRunnable(); + VisualizationScheduler.getInstance().addVisualization(animateRunnable); + } + + } else { + if (animateRunnable == null) + return; + VisualizationScheduler.getInstance().removeVisualization(animateRunnable); + animateRunnable = null; + if (usePrecalculation.getSelection()) { + // updateTime updates values to graph if precalculation is not used. + // we must store current values from animation to synchronize view and graph + // information so that use can modify animation properly. + usePrecalculation.setSelection(false); + updateTime(); + usePrecalculation.setSelection(true); + for (IGraphicsNode n : parent.getScenegraphAdapter().getNodes()) { + if (n instanceof Animatable) { + ((Animatable)n).setAnimation(null,null); + } + } + } + } + } + + private void updateUI() { + if (animationResource != null) { + animateButton.setEnabled(true); + timeSlider.setEnabled(true); + if (animateButton.getSelection()) { + addAnimationButton.setEnabled(false); + insertKeyFrameButton.setEnabled(false); + removeAnimationButton.setEnabled(false); + clearKeyFrameButton.setEnabled(false); + animationCombo.setEnabled(false); + usePrecalculation.setEnabled(false); + clearAnimationButton.setEnabled(false); + } else { + addAnimationButton.setEnabled(true); + insertKeyFrameButton.setEnabled(!parent.getSelectionAdapter().getCurrentSelection().isEmpty()); + removeAnimationButton.setEnabled(true); + clearKeyFrameButton.setEnabled(false); //FIXME : detect keyframes + animationCombo.setEnabled(true); + usePrecalculation.setEnabled(true); + clearAnimationButton.setEnabled(true); + } + } else { + timeSlider.setEnabled(false); + addAnimationButton.setEnabled(true); + insertKeyFrameButton.setEnabled(false); + removeAnimationButton.setEnabled(false); + clearKeyFrameButton.setEnabled(false); + animateButton.setEnabled(false); + animateButton.setSelection(false); + animationCombo.setEnabled(true); + usePrecalculation.setEnabled(false); + clearAnimationButton.setEnabled(false); + } + } + + private void updateKey(double k) { + key = k; + if (key >= 1.0) + key = 0.0; + else if (key < 0.0) + key = 1.0; + timeSlider.setSelection((int)(key*100.0)); + } + + private class AnimateRunnable implements Runnable { + public void run() { + try { + updateKey(key + 0.01); + updateTime(); + } catch (Exception e) { + VisualizationScheduler.getInstance().removeVisualization(animateRunnable); + } + } + } + + @Override + public void fillLocalToolBar(IToolBarManager manager) { + + } + + @Override + public void fillLocalPullDown(IMenuManager manager) { + + } + + @Override + public void dispose() { + + } + + @Override + public void run() { + + } + +} diff --git a/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/tools/CSGModellingContribution.java b/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/tools/CSGModellingContribution.java new file mode 100644 index 00000000..dd80c96b --- /dev/null +++ b/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/tools/CSGModellingContribution.java @@ -0,0 +1,777 @@ +package org.simantics.proconf.g3d.shapeeditor.tools; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.TreeMap; +import java.util.Map.Entry; + +import javax.vecmath.AxisAngle4d; +import javax.vecmath.Point3d; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.IToolBarManager; +import org.eclipse.jface.action.MenuManager; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.FormAttachment; +import org.eclipse.swt.layout.FormData; +import org.eclipse.swt.layout.FormLayout; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.ISharedImages; +import org.eclipse.ui.PlatformUI; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Resource; +import org.simantics.layer0.stubs.Property; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.layer0.utils.instantiation.Instance; +import org.simantics.layer0.utils.instantiation.InstanceFactory; +import org.simantics.proconf.g3d.actions.ContextAction; +import org.simantics.proconf.g3d.actions.FocusAction; +import org.simantics.proconf.g3d.actions.RemoveAction; +import org.simantics.proconf.g3d.actions.RotateAction; +import org.simantics.proconf.g3d.actions.TranslateAction; +import org.simantics.proconf.g3d.actions.WriteAction; +import org.simantics.proconf.g3d.base.EditorContribution; +import org.simantics.proconf.g3d.base.G3DAPI; +import org.simantics.proconf.g3d.base.G3DTools; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.common.StructuredResourceSelection; +import org.simantics.proconf.g3d.csg.stubs.BooleanOperation; +import org.simantics.proconf.g3d.csg.stubs.CSGModel; +import org.simantics.proconf.g3d.csg.stubs.CSGShape; +import org.simantics.proconf.g3d.csg.stubs.Difference; +import org.simantics.proconf.g3d.csg.stubs.Intersection; +import org.simantics.proconf.g3d.csg.stubs.Primitive; +import org.simantics.proconf.g3d.csg.stubs.Union; +import org.simantics.proconf.g3d.scenegraph.IGraphicsNode; +import org.simantics.proconf.g3d.shapeeditor.Activator; +import org.simantics.proconf.g3d.shapeeditor.ShapeEditorResources; +import org.simantics.proconf.g3d.shapeeditor.views.ShapeEditorBase; +import org.simantics.proconf.g3d.stubs.G3DNode; +import org.simantics.proconf.g3d.stubs.Shape; +import org.simantics.utils.ErrorLogger; + +public class CSGModellingContribution implements EditorContribution { + + private static ImageDescriptor INTERSECTION_IMAGE = Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID,"icons/intersection.png"); + private static ImageDescriptor UNION_IMAGE = Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/union.png"); + private static ImageDescriptor DIFFERENCE_IMAGE = Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID,"icons/difference.png"); + + private ShapeEditorBase parent; + + private List actions = new ArrayList(); + + private List addActions = new ArrayList(); + private ContextAction unionAction; + private ContextAction differenceAction; + private ContextAction intersectionAction; + private ContextAction splitAction; + private ContextAction linkAction; + private ContextAction unlinkAction; + private ContextAction translateAction; + private ContextAction rotateAction; + private ContextAction removeAction; + + private Composite infoComposite; + private Text infoText; + + + public CSGModellingContribution(ThreeDimensionalEditorBase parent) { + this.parent = (ShapeEditorBase)parent; + } + + @Override + public String getName() { + return "Shape Editing"; + } + + @Override + public void initialize(Graph graph) { + makeActions(graph); + } + + @Override + public void createControl(Composite parent) { + FormLayout flayout = new FormLayout(); + parent.setLayout(flayout); + infoComposite = new Composite(parent, SWT.BORDER); + FormData data = new FormData(); + data.top = new FormAttachment(0, 0); + data.left = new FormAttachment(0, 0); + data.right = new FormAttachment(100, 0); + data.bottom = new FormAttachment(infoComposite, 0, SWT.TOP); + this.parent.getRenderingComposite().setLayoutData(data); + data = new FormData(); + data.left = new FormAttachment(0, 0); + data.right = new FormAttachment(100, 0); + data.bottom = new FormAttachment(100, 0); + data.height = 18; + infoComposite.setLayoutData(data); + GridLayout layout = new GridLayout(1,false); + layout.marginWidth = 1; + layout.marginHeight = 1; + infoComposite.setLayout(layout); + infoText = new Text(infoComposite, SWT.NONE); + GridData gdata = new GridData(); + gdata.grabExcessHorizontalSpace = true; + gdata.horizontalAlignment = SWT.FILL; + infoText.setLayoutData(gdata); + } + + @Override + public void disposeControl() { + infoComposite.dispose(); + } + + @Override + public void fillContextMenu(Graph graph, IMenuManager manager, StructuredResourceSelection selection) { + + if (selection.isEmpty()) { + MenuManager addMenu = new MenuManager("Add", "add"); + addMenu.setRemoveAllWhenShown(false); + for (Action a : addActions) { + addMenu.add(a); + } + manager.add(addMenu); + } + + } + + protected void makeActions(Graph graph) { + actions.add(translateAction = new TranslateAction(parent) { + @Override + public void setInfoText(String text) { + infoText.setText(text); + } + }); + actions.add(rotateAction = new RotateAction(parent){ + @Override + public void setInfoText(String text) { + infoText.setText(text); + } + }); + actions.add(removeAction = new RemoveAction(parent)); + actions.add(new FocusAction(parent)); + + + IEntity primitive = EntityFactory.create(graph,ShapeEditorResources.csgResource.Primitive); + + Collection primitives = primitive.getRelatedObjects(graph.getBuiltins().SupertypeOf); + + TreeMap sorter = new TreeMap(); + for (IEntity p : primitives) { + String key = p.getName(); + if (key.equals("")) + key = "ERROR (" + p.getURI() + ")"; + sorter.put(key, p.getResource()); + } + + for (Entry e : sorter.entrySet()) { + final String name = e.getKey(); + final Resource r = e.getValue(); + Action a = new Action() { + Resource res; + public void run() { + parent.getSession().asyncWrite(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + + Instance ins = InstanceFactory.getInstanceOfType(g,r); + Resource instance = ins.instantiate(g); + Shape shape = new Shape(g,instance); + res = shape.getResource(); + resetShape(shape); + CSGModel model = new CSGModel(g,parent.getModelResource()); + model.addStatement(ShapeEditorResources.g3dResource.HasChild, shape.getResource()); + return GraphRequestStatus.transactionComplete(); + } + + @Override + public void handleException(Throwable e) { + super.handleException(e); + ErrorLogger.defaultLogError("Adding " + name + " failed.", e); + } + + @Override + public void requestCompleted(GraphRequestStatus status) { + parent.getRenderingComposite().getDisplay().asyncExec(new Runnable(){ + public void run() { + parent.getSelectionAdapter().updateSelection(new StructuredResourceSelection(res)); + } + }); + } + }); + } + }; + a.setText(name); + a.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(ISharedImages.IMG_OBJS_INFO_TSK)); + addActions.add(a); + + } + + unionAction = new WriteAction(parent,false) { + + Resource r; + @Override + public boolean usable(Graph graph,List resources) { + if (resources.size() >= 2) + return true; + return false; + } + + public GraphRequestStatus doChanges(Graph graph) { + List list = parent.getSelectionAdapter().getSelectedObjects(); + if (list.size() < 2) { + showMessage("Union works between two objects"); + return GraphRequestStatus.transactionCancel(); + } + Resource r1 = list.get(0).getResource(); + CSGShape shape1 = new CSGShape(graph,r1); + + G3DNode parent = shape1.getParent(); + if (parent == null) { + showMessage("Primary shape has no parent, don't know what to do"); + return GraphRequestStatus.transactionCancel(); + } + BooleanOperation op = Union.createDefault(graph).toBooleanOperation(); //FIXME : stubcast + r = op.getResource(); + if (createBooleanOp(op, parent, shape1, list)) + return GraphRequestStatus.transactionComplete(); + else + return GraphRequestStatus.transactionCancel(); + } + + @Override + public void afterChanges(GraphRequestStatus status) { + parent.getRenderingComposite().getDisplay().asyncExec(new Runnable(){ + public void run() { + parent.getSelectionAdapter().updateSelection(new StructuredResourceSelection(r)); + } + }); + } + }; + unionAction.setText("Union"); + unionAction.setToolTipText("Union"); + unionAction.setImageDescriptor(UNION_IMAGE); + + differenceAction = new WriteAction(parent,false) { + + Resource r; + @Override + public boolean usable(Graph graph,List resources) { + if (resources.size() >= 2) + return true; + return false; + } + + public GraphRequestStatus doChanges(Graph graph) { + List list = parent.getSelectionAdapter().getSelectedObjects(); + if (list.size() < 2) { + showMessage("Difference works between two objects"); + return GraphRequestStatus.transactionCancel(); + } + CSGShape shape1 = new CSGShape(graph,list.get(0).getResource()); + G3DNode parent = shape1.getParent(); + if (parent == null) { + showMessage("Primary shape has no parent, don't know what to do"); + return GraphRequestStatus.transactionCancel(); + } + BooleanOperation op = Difference.createDefault(graph).toBooleanOperation(); //FIXME : stubcast + r = op.getResource(); + if (createBooleanOp(op, parent, shape1, list)) + return GraphRequestStatus.transactionComplete(); + else + return GraphRequestStatus.transactionCancel(); + } + + @Override + public void afterChanges(GraphRequestStatus status) { + parent.getRenderingComposite().getDisplay().asyncExec(new Runnable(){ + public void run() { + parent.getSelectionAdapter().updateSelection(new StructuredResourceSelection(r)); + } + }); + } + }; + differenceAction.setText("Difference"); + differenceAction.setToolTipText("Difference"); + differenceAction.setImageDescriptor(DIFFERENCE_IMAGE); + + intersectionAction = new WriteAction(parent,false) { + Resource r; + @Override + public boolean usable(Graph graph,List resources) { + if (resources.size() >= 2) + return true; + return false; + } + + public GraphRequestStatus doChanges(Graph graph) { + List list = parent.getSelectionAdapter() + .getSelectedObjects(); + if (list.size() < 2) { + showMessage("Intersection works between two objects"); + return GraphRequestStatus.transactionCancel(); + } + CSGShape shape1 = new CSGShape(graph,list.get(0).getResource()); + G3DNode parent = shape1.getParent(); + if (parent == null) { + showMessage("Primary shape has no parent, don't know what to do"); + return GraphRequestStatus.transactionCancel(); + } + BooleanOperation op = Intersection.createDefault(graph).toBooleanOperation(); //FIXME : stubcast + r = op.getResource(); + if (createBooleanOp(op, parent, shape1, list)) + return GraphRequestStatus.transactionComplete(); + else + return GraphRequestStatus.transactionCancel(); + } + + @Override + public void afterChanges(GraphRequestStatus status) { + parent.getRenderingComposite().getDisplay().asyncExec(new Runnable(){ + public void run() { + parent.getSelectionAdapter().updateSelection(new StructuredResourceSelection(r)); + } + }); + + } + }; + intersectionAction.setText("Intersection"); + intersectionAction.setToolTipText("Intersection"); + intersectionAction.setImageDescriptor(INTERSECTION_IMAGE); + + splitAction = new WriteAction(parent,false) { + + @Override + public boolean usable(Graph graph,List resources) { + if (resources.size() == 1) { + Resource r = resources.iterator().next(); + IEntity t = EntityFactory.create(graph,r); + if (t.isInstanceOf(ShapeEditorResources.csgResource.BooleanOperation)) { + return true; + } + } + + return false; + } + + + + public GraphRequestStatus doChanges(Graph graph) { + List list = parent.getSelectionAdapter().getSelectedObjects(); + if (list.size() != 1) { + showMessage("Split requires one object"); + return GraphRequestStatus.transactionCancel(); + } + Resource deletedResource = list.get(0).getResource(); + IEntity deletedEntity = EntityFactory.create(graph,deletedResource); + if (!deletedEntity.isInstanceOf(ShapeEditorResources.csgResource.BooleanOperation)) { + showMessage("Split requires boolean operation"); + return GraphRequestStatus.transactionCancel(); + } + Collection parents = deletedEntity.getRelatedObjects(ShapeEditorResources.g3dResource.HasParent); + if (parents.size() != 1) { + showMessage("Shape has " + parents.size() + + " parents, don't know what to do"); + return GraphRequestStatus.transactionCancel(); + } + IEntity parent = parents.iterator().next(); + // find all shapes and their positions and orientations relative to world coordinates + BooleanOperation op = new BooleanOperation(deletedEntity); + CSGShape shape1 = op.getMainShape(); + Point3d shape1WorldPos = G3DTools.getPoint(shape1.getWorldPosition()); + AxisAngle4d shape1WorldRot = G3DTools.getOrientation(shape1.getWorldOrientation()); + //System.out.println(shape1WorldPos + " " + shape1WorldRot); + Collection shape2s = op.getSecondaryShape(); + + ArrayList shape2WorldPos = new ArrayList(); + ArrayList shape2WorldRot = new ArrayList(); + for (CSGShape shape : shape2s) { + Point3d pos = G3DTools.getPoint(shape.getWorldPosition()); + AxisAngle4d rot = G3DTools.getOrientation(shape.getWorldOrientation()); + shape2WorldPos.add(pos); + shape2WorldRot.add(rot); + //System.out.println(pos + " " + rot); + } + + // removed boolean operation is either connected to model or another boolean operation. + CSGModel m = new CSGModel(graph,CSGModellingContribution.this.parent.getModelResource()); + if (parent.getResource().equals(CSGModellingContribution.this.parent.getModelResource())) { + // if deleted boolean operation is connected to the model, + // all its children are added to the model + + m.removeStatement(ShapeEditorResources.g3dResource.HasChild, op); + m.addStatement(ShapeEditorResources.g3dResource.HasChild, shape1); + for (CSGShape shape2 : shape2s) { + m.addStatement(ShapeEditorResources.g3dResource.HasChild, shape2); + } + + } else { + // deleted boolean operation is connected to another boolean + // operation + // if the deleted boolean operation is primary child, we'll + // must replace it with deleted boolean operations + // primary child + if (!parent.isInstanceOf(ShapeEditorResources.csgResource.BooleanOperation)) { + ErrorLogger.defaultLogError("Parent shape is not a boolean operation nor model ?!", null); + return GraphRequestStatus.transactionCancel(); + } + BooleanOperation parentOp = new BooleanOperation(parent); + // we'll have to list all secondary shapes in parent boolean + // op so that we can find the correct relatio + Collection parentShape2s = parentOp.getRelatedObjects(ShapeEditorResources.csgResource.HasSecondaryShape); + + if (parentOp.getMainShape().getResource().equals(deletedResource)) { + // split boolean operation is the primary child in the + // parent boolean operation + parent.removeStatement(ShapeEditorResources.csgResource.HasMainShape,deletedResource); + // graph.commitChanges(ShapeEditorView.this); + parent.addStatement(ShapeEditorResources.csgResource.HasMainShape, shape1); + // graph.commitChanges(ShapeEditorView.this); + for (CSGShape shape2 : shape2s) { + m.addStatement(ShapeEditorResources.g3dResource.HasChild, shape2); + } + } else if (contains(parentShape2s, deletedResource)) { + // split boolean operation is one of the secondary + // shapes in the parent boolean operation + parent.removeStatement(ShapeEditorResources.csgResource.HasSecondaryShape,deletedResource); + // graph.commitChanges(ShapeEditorView.this); + parent.addStatement(ShapeEditorResources.csgResource.HasSecondaryShape,shape1); + // graph.commitChanges(ShapeEditorView.this); + + // model.getConsistOfShapeSet().add(shape2); + for (CSGShape shape2 : shape2s) { + m.addStatement(ShapeEditorResources.g3dResource.HasChild, shape2); + } + } else { + ErrorLogger.defaultLogError("Parent shape is not a boolean operation nor model ?!", null); + return GraphRequestStatus.transactionCancel(); + } + } + deletedEntity.removeStatement(ShapeEditorResources.csgResource.HasMainShape, shape1); + for (CSGShape shape2 : shape2s) + deletedEntity.removeStatement(ShapeEditorResources.csgResource.HasSecondaryShape, shape2); + //graph.commit(); + //System.out.println("Setting original transformations"); + //G3DTools.setTuple3(shape1.getWorldPosition(), shape1WorldPos); + //G3DTools.setOrientation(shape1.getWorldOrientation(), shape1WorldRot); + G3DAPI.setWorldTransformation(shape1, shape1WorldPos,shape1WorldRot); + + int i = 0; + for (CSGShape shape : shape2s) { + G3DAPI.setWorldTransformation(shape, shape2WorldPos.get(i),shape2WorldRot.get(i)); + //G3DTools.setTuple3(shape.getWorldPosition(), shape2WorldPos.get(i)); + //G3DTools.setOrientation(shape.getWorldOrientation(),shape2WorldRot.get(i)); + i++; + } + return GraphRequestStatus.transactionComplete(); + + } + }; + splitAction.setText("Split"); + splitAction.setToolTipText("Split"); + splitAction.setImageDescriptor(PlatformUI.getWorkbench() + .getSharedImages().getImageDescriptor( + ISharedImages.IMG_OBJS_INFO_TSK)); + + linkAction = new WriteAction(parent,false) { + Resource r; + @Override + public boolean usable(Graph graph,List resources) { + if (resources.size() == 2) { + Iterator i = resources.iterator(); + Shape s1 = new Shape(graph,i.next()); + Shape s2 = new Shape(graph,i.next()); + if (s1.getRelatedObjects(ShapeEditorResources.g3dResource.GeometryDefinitionOf).size() == 0 && + s2.getRelatedObjects(ShapeEditorResources.g3dResource.GeometryDefinitionOf).size() == 0) + return true; + + } + return false; + } + + public GraphRequestStatus doChanges(Graph graph) { + List list = parent.getSelectionAdapter().getSelectedObjects(); + if (list.size() != 2) { + showMessage("Link works between two objects"); + return GraphRequestStatus.transactionCancel(); + } + Resource r1 = list.get(0).getResource(); + Resource r2 = list.get(1).getResource(); + + CSGShape shape1 = new CSGShape(graph,r1); + CSGShape shape2 = new CSGShape(graph,r2); + + Point3d p = G3DTools.getPoint(shape2.getWorldPosition()); + AxisAngle4d aa = G3DTools.getOrientation(shape2.getWorldOrientation()); + //System.out.println(p + " " + aa); + shape2.removeRelatedStatements(ShapeEditorResources.g3dResource.HasParent); + r = shape2.getResource(); + //System.out.println("Link remove commit"); + //graph.commitChanges(ShapeEditorView.this); + //shape1.getChild().add(shape2.toG3DNode()); //FIXME : stubcast + shape1.addStatement(ShapeEditorResources.g3dResource.HasChild, shape2); + // FIXME : this is needed + //System.out.println("Link add commit"); + //graph.commitChanges(ShapeEditorView.this); + //G3DTools.setTuple3(shape2.getWorldPosition(), p); + //G3DTools.setOrientation(shape2.getWorldOrientation(), aa); + G3DAPI.setWorldTransformation(shape2, p, aa); + return GraphRequestStatus.transactionComplete(); + } + + @Override + public void afterChanges(GraphRequestStatus status) { + parent.getRenderingComposite().getDisplay().asyncExec(new Runnable(){ + public void run() { + parent.getSelectionAdapter().updateSelection(new StructuredResourceSelection(r)); + } + }); + } + }; + linkAction.setText("Link"); + linkAction.setToolTipText("Link"); + linkAction.setImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/link.png")); + + unlinkAction = new WriteAction(parent,false) { + Resource r; + @Override + public boolean usable(Graph graph,List resources) { + if (resources.size() == 1) { + Iterator i = resources.iterator(); + Shape s1 = new Shape(graph,i.next()); + return (s1.getRelatedObjects(ShapeEditorResources.g3dResource.GeometryDefinitionOf).size() == 0 + && s1.getParent() != null && !s1.getParent() + .getResource().equals(CSGModellingContribution.this.parent.getModelResource())); + + } + return false; + } + + public GraphRequestStatus doChanges(Graph graph) { + List list = parent.getSelectionAdapter().getSelectedObjects(); + if (list.size() != 1) { + showMessage("Unlink works with one object"); + return GraphRequestStatus.transactionCancel(); + } + Resource r1 = list.get(0).getResource(); + + CSGShape shape1 = new CSGShape(graph,r1); + CSGModel m = new CSGModel(graph,CSGModellingContribution.this.parent.getModelResource()); + Point3d p = G3DTools.getPoint(shape1.getWorldPosition()); + AxisAngle4d aa = G3DTools.getOrientation(shape1.getWorldOrientation()); + shape1.removeRelatedStatements(ShapeEditorResources.g3dResource.HasParent); + //graph.commitChanges(ShapeEditorView.this); + m.addStatement(ShapeEditorResources.g3dResource.HasChild, shape1); + // FIXME : this is needed + //graph.commitChanges(ShapeEditorView.this); + //G3DTools.setTuple3(shape1.getWorldPosition(), p); + //G3DTools.setOrientation(shape1.getWorldOrientation(), aa); + G3DAPI.setWorldTransformation(shape1, p, aa); + r = shape1.getResource(); + return GraphRequestStatus.transactionComplete(); + } + + @Override + public void afterChanges(GraphRequestStatus status) { + parent.getRenderingComposite().getDisplay().asyncExec(new Runnable(){ + public void run() { + parent.getSelectionAdapter().updateSelection(new StructuredResourceSelection(r)); + } + }); + } + }; + unlinkAction.setText("Unlink"); + unlinkAction.setToolTipText("Unlink"); + unlinkAction.setImageDescriptor(Activator.imageDescriptorFromPlugin( + Activator.PLUGIN_ID, "icons/unlink.png")); + + actions.add(unionAction); + actions.add(intersectionAction); + actions.add(differenceAction); + actions.add(splitAction); + actions.add(linkAction); + actions.add(unlinkAction); + } + + boolean contains(ArrayList parentShape2sIds, Resource id) { + for (int i = 0; i < parentShape2sIds.size(); i++) { + if (parentShape2sIds.get(i).equals(id)) + return true; + + } + return false; + } + + boolean contains(Collection parentShape2sIds, Resource id) { + for (IEntity e : parentShape2sIds) { + if (e.getResource().equals(id)) + return true; + + } + return false; + } + + private boolean createBooleanOp(BooleanOperation op, G3DNode parent, + CSGShape shape1, List list) { + + resetShape(op.toShape()); //FIXME : stubcast + // new boolean operation is added to the first shape's parent + // the parent is the model + + Point3d refPos = G3DTools.getPoint(shape1.getLocalPosition()); + G3DTools.setTuple3(op.getLocalPosition(), refPos); + refPos.negate(); + G3DTools.addTuple3(shape1.getLocalPosition(), refPos); + op.removeRelatedStatements(ShapeEditorResources.csgResource.HasMainShape); + op.addStatement(ShapeEditorResources.csgResource.HasMainShape, shape1); + + if (!replaceShape(parent, shape1.toShape(), op.toShape())) { //FIXME : stubcast + return false; + } + //model.getConsistOfSet().remove(shape1); + for (int i = 1; i < list.size(); i++) { + CSGShape shape2 = new CSGShape(op.getGraph(),list.get(i).getResource()); + G3DTools.addTuple3(shape2.getLocalPosition(), refPos); + G3DNode shape2parent = shape2.getParent(); + if (shape2parent != null) { + // we'll must link before removing or shape will be deleted + //op.addStatement(ShapeEditorResources.csgResource.HasSecondaryShape,shape2); + //if (!replaceShape(shape2parent, shape2, null)) { + // op.removeStatement(ShapeEditorResources.csgResource.HasSecondaryShape, shape2); + // // shape couldn't be removed so we'll remove the link + //} + + if (replaceShape(shape2parent, shape2.toShape(), null)) { //FIXME : stubcast + op.addStatement(ShapeEditorResources.csgResource.HasSecondaryShape,shape2); + } + } + } + // Commit is not needed because this is final call in all transactions + //graph.commitChanges(ShapeEditorView.this); + return true; + } + + /** + * Replaces or removes parent from shape + * @param parent parent containing shape + * @param removed the shape + * @param added the replacing shape or null + * @return true if replacing or removing was successful + * @throws TransactionException + */ + private boolean replaceShape(G3DNode parent, Shape removed, Shape added) { + assert (parent != null); + assert (removed != null); + + + //CSGModel m = CSGModelFactory.create(parent.getGraph(),model); + if (parent.getResource().equals(this.parent.getModelResource())) { + // parent is model (rootnode). + // shape is connected to it with "Has Child" relation + parent.removeStatement(ShapeEditorResources.g3dResource.HasChild, removed); + if (added != null) { + parent.addStatement(ShapeEditorResources.g3dResource.HasChild, added); + } + } else { + // the first shape's parent is boolean operation + // so we must know if its connected as a primary shape or as a secondary shape + if (!parent.isInstanceOf(ShapeEditorResources.csgResource.BooleanOperation)) { + ErrorLogger.defaultLogError("Parent shape is not a boolean operation nor model ?!",null); + return false; + } + BooleanOperation parentOp = new BooleanOperation(parent); + // listing all secondary shapes in the parent boolean operation + Collection parentShape2s = parentOp.getSecondaryShape(); + ArrayList parentShape2sIds = new ArrayList(); + for (CSGShape shape2 : parentShape2s) + parentShape2sIds.add(shape2.getResource()); + if (parentOp.getMainShape().getResource().equals(removed.getResource())) { + if (added == null) { + return false; + } + parent.removeStatement(ShapeEditorResources.csgResource.HasMainShape, removed); + parent.addStatement(ShapeEditorResources.csgResource.HasMainShape, added); + + } else if (contains(parentShape2sIds, removed.getResource())) { + + parent.removeStatement(ShapeEditorResources.csgResource.HasSecondaryShape, removed); + parent.addStatement(ShapeEditorResources.csgResource.HasSecondaryShape, added); + + } else { + ErrorLogger.defaultLogError("Parent shape is not a boolean operation nor model ?!",null); + //coreTC.cancelTransaction(); + return false; + } + } + return true; + } + + /** + * Resets shape to identity rotation and zero translation + * + * @param shape + */ + private void resetShape(Shape shape) { + G3DTools.resetTransformation(shape); + Graph graph = shape.getGraph(); + if (shape.isInstanceOf(ShapeEditorResources.csgResource.Primitive)) { + Primitive prim = new Primitive(shape); + Collection c = prim.getSizingProperty(); + if (c.size() == 0) + ErrorLogger.getDefault().logWarning("Shape does not contain sizing properties.", null); + + for (Property p : c) { + if (p.isInstanceOf(graph.getBuiltins().Double)) { + graph.setScalarDouble(p.getResource(), 1.0); + } else if (p.isInstanceOf(graph.getBuiltins().Integer)) { + graph.setScalarInteger(p.getResource(), 1); + } else { + ErrorLogger.getDefault().logWarning("Cannot handle sizing property " + p.getName() , null); + } + } + } + + } + + protected void showMessage(String s) { + parent.showMessage(s); + } + + @Override + public Collection getActions() { + return actions; + } + + + @Override + public void fillLocalToolBar(IToolBarManager manager) { + + } + + @Override + public void fillLocalPullDown(IMenuManager manager) { + + } + + @Override + public void dispose() { + + } + + @Override + public void run() { + + } + +} diff --git a/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/tools/ParameterizationContribution.java b/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/tools/ParameterizationContribution.java new file mode 100644 index 00000000..3f1fefad --- /dev/null +++ b/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/tools/ParameterizationContribution.java @@ -0,0 +1,680 @@ +package org.simantics.proconf.g3d.shapeeditor.tools; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.IToolBarManager; +import org.eclipse.jface.dialogs.InputDialog; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.layout.FormAttachment; +import org.eclipse.swt.layout.FormData; +import org.eclipse.swt.layout.FormLayout; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Sash; +import org.eclipse.swt.widgets.Tree; +import org.eclipse.ui.forms.IFormColors; +import org.eclipse.ui.forms.events.ExpansionAdapter; +import org.eclipse.ui.forms.events.ExpansionEvent; +import org.eclipse.ui.forms.widgets.FormToolkit; +import org.eclipse.ui.forms.widgets.ScrolledForm; +import org.eclipse.ui.forms.widgets.Section; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Resource; +import org.simantics.equation.stubs.SecondOrderScalarPolynomial; +import org.simantics.g2d.stubs.anim.Animation; +import org.simantics.g2d.stubs.anim.Interpolator; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.layer0.utils.ResourceDebugUtils; +import org.simantics.proconf.browsing.GraphExplorer; +import org.simantics.proconf.browsing.GraphExplorerInputFactory; +import org.simantics.proconf.browsing.views.PropertyTable; +import org.simantics.proconf.g3d.actions.ContextAction; +import org.simantics.proconf.g3d.base.EditorContribution; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.common.StructuredResourceSelection; +import org.simantics.proconf.g3d.shapeeditor.ShapeEditorResources; +import org.simantics.proconf.g3d.shapeeditor.common.ViewpointGenerator; +import org.simantics.proconf.g3d.shapeeditor.views.ShapeEditorBase; +import org.simantics.proconf.g3d.stubs.G3DModel; +import org.simantics.proconf.g3d.tools.OESelectionListener; +import org.simantics.proconf.g3d.tools.PropertyTree; +import org.simantics.utils.ui.jface.BaseSelectionProvider; + + +public class ParameterizationContribution implements EditorContribution { + + private ShapeEditorBase parent; + private List actions = new ArrayList(); + private Composite sideComposite; + private Sash sash; + + + public ParameterizationContribution(ThreeDimensionalEditorBase parent) { + this.parent = (ShapeEditorBase) parent; + } + + @Override + public void createControl(final Composite parentComposite) { + FormLayout flayout = new FormLayout(); + parentComposite.setLayout(flayout); + sash = new Sash(parentComposite,SWT.VERTICAL); + + sideComposite = new Composite(parentComposite,SWT.BORDER); + FormData data = new FormData(); + data.top = new FormAttachment(0, 0); + data.left = new FormAttachment(0, 0); + data.right = new FormAttachment(sash, 0, SWT.LEFT); + data.bottom = new FormAttachment(100,0); + this.parent.getRenderingComposite().setLayoutData(data); + sideComposite.setLayout(new FillLayout(SWT.VERTICAL)); + data = new FormData(); + data.top = new FormAttachment(0, 0); + data.bottom = new FormAttachment(100,0); + data.right = new FormAttachment(100,0); + data.left = new FormAttachment(sash,0,SWT.RIGHT); + sideComposite.setLayoutData(data); + + final int limit = 20, percent = 50; + final FormData sashData = new FormData(); + sashData.left = new FormAttachment (percent, 0); + sashData.top = new FormAttachment(0, 0); + sashData.bottom = new FormAttachment(100,0); + + sash.setLayoutData (sashData); + sash.addListener (SWT.Selection, new Listener () { + public void handleEvent (Event e) { + Rectangle sashRect = sash.getBounds (); + Rectangle shellRect = parentComposite.getClientArea (); + int right = shellRect.width - sashRect.width - limit; + e.x = Math.max (Math.min (e.x, right), limit); + if (e.x != sashRect.x) { + sashData.left = new FormAttachment (0, e.x); + parentComposite.layout (); + } + } + }); + createForm(sideComposite); + + hierarchyExplorer.setInput(parent.getSessionContext(),GraphExplorerInputFactory.clone(hierarchyExplorer.getInput()) + .input(parent.getModelResource()) + .viewpoint(ViewpointGenerator.createObjectStructureViewpoint()) + .toInput()); + +// parameterExplorer.setInput(parent.getSessionContext(),GraphExplorerInputFactory.clone(parameterExplorer.getInput()) +// .input(parent.getModelResource()) +// .viewpoint(ViewpointGenerator.createObjectSizingParameterViewpoint(ShapeEditorResources.g3dResource.HasSizingParameter)) +// .toInput()); + parameterTable.setSession(parent.getSession()); + parameterTable.setInput(new StructuredResourceSelection(parent.getModelResource())); + + } + + @Override + public void disposeControl() { + sideComposite.dispose(); + sash.dispose(); + + } + + @Override + public void dispose() { + + } + + @Override + public void fillContextMenu(Graph graph, IMenuManager manager, + StructuredResourceSelection selection) { + + } + + @Override + public void fillLocalPullDown(IMenuManager manager) { + + } + + @Override + public void fillLocalToolBar(IToolBarManager manager) { + + } + + @Override + public Collection getActions() { + return actions; + } + + @Override + public String getName() { + return "Parameterization"; + } + + @Override + public void initialize(Graph graph) { + + } + + @Override + public void run() { + + } + + private ScrolledForm form; + private BaseSelectionProvider defaultInputSelectionProvider = new BaseSelectionProvider(); + protected FormToolkit toolkit; + + + + private void createForm(Composite parent) { + toolkit = new FormToolkit(parent.getDisplay()); + form = getToolkit().createScrolledForm(parent); + + GridLayout layout = new GridLayout(2, false); + form.getBody().setLayout(layout); + form.getBody().setLayoutData( + new GridData(GridData.FILL, GridData.FILL, true, true)); + + // By default make this ViewPart use a default ISelectionProvider + // that will offer the viewparts input resource as its selection. + // The Resource is wrapped into a ResourceSelection object. + // Any widgets created in createWidgets may override the default + // selection provider. + //getEditorSite().setSelectionProvider(defaultInputSelectionProvider); + + beforeCreateWidgets(); + createWidgets(); + + //reload(); + + form.setText(getFormText()); + + // Finally Set the default selection which will have an effect only + // if nothing in createWidgets has overridden the default selection + // provider. +// ISelection s = ISelectionUtils +// .createSelection(new StructuredResourceSelection( +// getInputResource())); +// defaultInputSelectionProvider.setSelection(s); + } + + + public ScrolledForm getActiveForm() { + return form; + } + + protected Composite getBody() { + return form.getBody(); + } + + public Composite newGridSection(int formColumns, int childColumns, + boolean equalWidth, boolean grabVertical, String text, + String description) { + return newGridSection(getBody(), formColumns, childColumns, equalWidth, + grabVertical, text, description); + } + + public Composite newGridSection(Composite parent, int formColumns, + int childColumns, boolean equalWidth, boolean grabVertical, + String text, String description) { + FormToolkit toolkit = getToolkit(); + + Section section = toolkit.createSection(parent, Section.DESCRIPTION + | Section.TWISTIE | Section.TITLE_BAR | Section.EXPANDED); + section.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, + grabVertical, formColumns, 1)); + section.addExpansionListener(new ExpansionAdapter() { + public void expansionStateChanged(ExpansionEvent e) { + //System.out.println("SinglePageTypeEditor: expansionStateChanged " + e); + //reflow(true); + } + }); + section.setText(text); + section.setDescription(description); + Composite sectionClient = toolkit.createComposite(section); + sectionClient.setLayout(new GridLayout(childColumns, equalWidth)); + sectionClient.setLayoutData(new GridData()); + section.setClient(sectionClient); + return sectionClient; + } + + public FormToolkit getToolkit() { + return toolkit; + } + + public void reflow(boolean flushCache) { + //System.out.println("FormTypeEditorBase.reflow(" + flushCache + ")"); + getActiveForm().reflow(flushCache); + } + + protected void beforeCreateWidgets() { + } + +// private TrackedText modelName = null; + StructuredResourceSelection hierarchySelection = new StructuredResourceSelection(); + StructuredResourceSelection parameterSelection = new StructuredResourceSelection(); + //GraphExplorer parameterExplorer; + PropertyTable parameterTable; + GraphExplorer hierarchyExplorer; + Button deleteParameterButton; + Button clearButton; + PropertyTree propertiesTree; + Button generateButton; + Button askButton; + Button overrideButton; + + protected String getFormText() { + return "Parameterization Editor"; + } + + protected void createWidgets() { + createModelPropertiesGroup(newGridSection(2, 1, false, false, "Model Properties", + "Basic properties for this viewpoint")); + createParametrizationGroup(newGridSection(2, 1, false, false, "Parameterization", + "Create parameterization for selected shapes")); + //getSite().setSelectionProvider(this); + } + + private void createParametrizationGroup(Composite parent) { + toolkit.paintBordersFor(parent); + toolkit.setBorderStyle(SWT.BORDER); + + overrideButton = toolkit.createButton(parent, "Overwrite previous parameterizations", SWT.CHECK); + overrideButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + askButton.setEnabled(overrideButton.getSelection()); + + } + }); + + + askButton = toolkit.createButton(parent, "Ask before overwriting", SWT.CHECK); + askButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + + + } + }); + askButton.setEnabled(false); + + generateButton = toolkit.createButton(parent, "Generate linear parameterization", SWT.PUSH); + generateButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + generateMappings(); + + } + }); + generateButton.setEnabled(false); + + + } + + private void createModelPropertiesGroup(final Composite parent) { + + toolkit.paintBordersFor(parent); + toolkit.setBorderStyle(SWT.BORDER); + + GridData gridData1 = new GridData(SWT.FILL, SWT.TOP, false, false, 1, 1); + + + // Parameters + Label parameterLabel = toolkit.createLabel(parent, "Parameters:"); + parameterLabel.setForeground(toolkit.getColors().getColor(IFormColors.TITLE)); + parameterLabel.setLayoutData(gridData1); + +// parameterExplorer = new GraphExplorer(parent, SWT.SINGLE); //new OntologyExplorer("ParameterExplorer", this, getInput("ParameterExplorer", model.getId())); +// parameterExplorer.getViewer().addPostSelectionChangedListener(new OESelectionListener() { +// +// protected void resourceSelectionUpdated(StructuredResourceSelection sel) { +// parameterSelection = sel; +// if (parameterSelection.size() == 0) { +// deleteParameterButton.setEnabled(false); +// clearButton.setEnabled(false); +// } else { +// deleteParameterButton.setEnabled(true); +// clearButton.setEnabled(true); +// } +// updateGenerateButtonStatus(); +// } +// +// }); +// Tree oe = parameterExplorer.getTree(); +// toolkit.adapt(oe, true, true); + + parameterTable = new PropertyTable(parent,SWT.NONE); + parameterTable.getViewer().addPostSelectionChangedListener(new OESelectionListener() { + + protected void resourceSelectionUpdated(StructuredResourceSelection sel) { + parameterSelection = sel; + if (parameterSelection.size() == 0) { + deleteParameterButton.setEnabled(false); + clearButton.setEnabled(false); + } else { + deleteParameterButton.setEnabled(true); + clearButton.setEnabled(true); + } + updateGenerateButtonStatus(); + } + + }); + + GridData gd3 = new GridData(GridData.FILL, GridData.FILL, true, true,1,1); + gd3.heightHint = 50; + //oe.setLayoutData(gd3); + + parameterTable.setLayoutData(gd3); + + // Buttons to add and remove parameters + toolkit.createLabel(parent, ""); + Composite buttons = toolkit.createComposite(parent); + + buttons.setLayout(new FillLayout(SWT.HORIZONTAL)); + Button newParameterButton = toolkit.createButton(buttons, "New Parameter", SWT.PUSH); + newParameterButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + InputDialog dialog = new InputDialog(ParameterizationContribution.this.parent.getRenderingComposite().getShell(),"New Parameter","Enter parameter's name","new parameter",null); + if (dialog.open() == InputDialog.CANCEL) + return; + final String name = dialog.getValue(); + if (name.length() < 1) + return; // TODO : show error + + ParameterizationContribution.this.parent.getSession().asyncWrite(new GraphRequestAdapter() { + public GraphRequestStatus perform(Graph g) throws Exception { + //fi.vtt.simantics.layer0.stubs.Double parameter = DoubleFactory.createDefault(g); + //getModel(g).addStatement(ShapeEditorResources.g3dResource.HasSizingParameter, parameter); + //parameter.setValue(new double[]{1.0}); + //parameter.setName(name); + Resource parameter = ParameterizationContribution.this.parent.getModel(g).addRelatedScalarDouble(ShapeEditorResources.g3dResource.HasSizingParameter, 1.0).getResource(); + IEntity thing = EntityFactory.create(g,parameter); + thing.setName(name); + return GraphRequestStatus.transactionComplete(); + }; + }); + + + } + }); + deleteParameterButton = toolkit.createButton(buttons, "Delete Parameter", SWT.PUSH); + deleteParameterButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + //StructuredResourceSelection s = (StructuredResourceSelection)parameterScheme.getSelection(); + final StructuredResourceSelection s = parameterSelection; + if (s.size() != 1) + return; + // we'll have to start write transaction, since we may have to change the graph + ParameterizationContribution.this.parent.getSession().asyncWrite(new GraphRequestAdapter() { + boolean proceed; + IEntity selectedParameter; + public GraphRequestStatus perform(Graph g) throws Exception { + selectedParameter = EntityFactory.create(g,s.getSelectionList().get(0)); + + Collection parameters = selectedParameter.getRelatedObjects(ShapeEditorResources.g3dResource.HasSizingParameter); + if (parameters.size() > 0) { + final MessageDialog dialog = new MessageDialog(ParameterizationContribution.this.parent.getRenderingComposite().getShell(),"Deleting a parameter",null,"Parameter is in use, doe you wan't to remove it?",MessageDialog.QUESTION,new String[]{"OK","Cancel"},1); + parent.getDisplay().syncExec(new Runnable() { + @Override + public void run() { + proceed = (dialog.open() != 1); + } + }); + if (proceed) { + ParameterizationContribution.this.parent.getModel(g).removeStatement(ShapeEditorResources.g3dResource.HasSizingParameter,selectedParameter); + } + } + + return GraphRequestStatus.transactionComplete(); + } + }); + } + }); + deleteParameterButton.setEnabled(false); + + clearButton = toolkit.createButton(buttons, "Clear Parameter", SWT.PUSH); + clearButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + final StructuredResourceSelection s = parameterSelection; + if (s.size() != 1) + return; + ParameterizationContribution.this.parent.getSession().asyncWrite(new GraphRequestAdapter() { + boolean proceed; + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + IEntity selectedParameter = EntityFactory.create(g,s.getSelectionList().get(0)); + Collection equations = selectedParameter.getRelatedObjects(ShapeEditorResources.equationResource.HasTarget); + final String name = selectedParameter.getName(); + if (equations.size() > 0) { + final MessageDialog dialog = new MessageDialog(ParameterizationContribution.this.parent.getRenderingComposite().getShell(),"Clearing a parameter",null,"Do you wan't to clear parameterization for "+ name + " ?\nIt has " + equations.size() + " mappings.",MessageDialog.QUESTION,new String[]{"OK","Cancel"},1); + parent.getDisplay().syncExec(new Runnable() { + public void run() { + proceed = (dialog.open() != 1); + }; + }); + if (proceed) { + for (IEntity eq : equations) { + eq.removeRelatedStatements(ShapeEditorResources.equationResource.HasSource); + eq.removeRelatedStatements(ShapeEditorResources.equationResource.HasTarget); + } + return GraphRequestStatus.transactionComplete(); + } + } + return GraphRequestStatus.transactionCancel(); + } + }); + + + } + }); + clearButton.setEnabled(false); + + Label hierarchyLabel = toolkit.createLabel(parent, "Model Hierarchy:"); + hierarchyLabel.setForeground(toolkit.getColors().getColor(IFormColors.TITLE)); + hierarchyLabel.setLayoutData(gridData1); + + hierarchyExplorer = new GraphExplorer(parent,SWT.MULTI); //new OntologyExplorer("HierarchyExplorer", this, getInput("HierarchyExplorer", model.getId())); + Tree oeh = hierarchyExplorer.getTree();//hierarchyExplorer.getControl(parent, 1, OntologyExplorer.OntologyTree, SWT.MULTI); + toolkit.adapt(oeh, true, true); + + GridData gd4 = new GridData(GridData.FILL, GridData.FILL, true, true,1,1); + gd4.heightHint = 200; + oeh.setLayoutData(gd4); + hierarchyExplorer.getViewer().addPostSelectionChangedListener(new OESelectionListener() { + + protected void resourceSelectionUpdated(StructuredResourceSelection sel) { + hierarchySelection = sel; + updatePropertiesTable(); + updateGenerateButtonStatus(); + } + + private void updatePropertiesTable() { + propertiesTree.setProperties(hierarchySelection); + + } + + }); + + Label propertiesLabel = toolkit.createLabel(parent, "Available properties:"); + propertiesLabel.setForeground(toolkit.getColors().getColor(IFormColors.TITLE)); + propertiesLabel.setLayoutData(gridData1); + + //propertiesTable = toolkit.createTable(parent, SWT.MULTI); + Tree tree = toolkit.createTree(parent, SWT.MULTI); + propertiesTree = new PropertyTree(tree,ParameterizationContribution.this.parent.getSession()); + // + GridData gd5 = new GridData(GridData.FILL, GridData.FILL, true, true,1,1); + gd5.heightHint = 200; + //propertiesTable.setLayoutData(gd5); + tree.setLayoutData(gd5); + tree.addSelectionListener(new SelectionAdapter() { + + @Override + public void widgetSelected(SelectionEvent e) { + updateGenerateButtonStatus(); + } + + }); + + + } + + private void updateGenerateButtonStatus() { + if (parameterSelection.size() == 0) { + generateButton.setEnabled(false); + return; + } + if (hierarchySelection.size() == 0) { + generateButton.setEnabled(false); + return; + } + if (propertiesTree.getTree().getSelection().length == 0) { + generateButton.setEnabled(false); + return; + } + generateButton.setEnabled(true); + } + + List res; + + private void generateMappings() { + final StructuredResourceSelection selectedShapes = hierarchySelection; + final StructuredResourceSelection selectedParameter = parameterSelection; + + final boolean override = overrideButton.getSelection(); + final boolean ask = askButton.getSelection(); + //TreeItem[] selectedProperties = propertiesTree.getTree().getSelection(); + + assert (selectedParameter.size() == 1); + assert (selectedShapes.size() > 0); + //assert(selectedProperties.length > 0); + parent.getSession().asyncWrite(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + //fi.vtt.simantics.layer0.stubs.Double parameter = DoubleFactory.create(g,selectedParameter.getSelectionList().get(0)); + IEntity parameter = EntityFactory.create(g,selectedParameter.getSelectionList().get(0)); + Collection prop = parameter.getRelatedObjects(ShapeEditorResources.g3dResource.HasDefaultDoubleValue); + //fi.vtt.simantics.layer0.stubs.Double defaultValue; + double value = g.getScalarDouble(parameter.getResource()); + if (prop.size() == 0) { + //defaultValue = DoubleFactory.createDefault(g); + //parameter.addStatement(ShapeEditorResources.g3dResource.HasDefaultDoubleValue, defaultValue); + parameter.addRelatedScalarDouble(ShapeEditorResources.g3dResource.HasDefaultDoubleValue, value); + } else { + //defaultValue = DoubleFactory.create(prop.iterator().next()); + g.setScalarDouble(prop.iterator().next().getResource(),value); + } + //defaultValue.setValue(parameter.getValue()); + final Graph graph = g; + parent.getRenderingComposite().getDisplay().syncExec(new Runnable() { + public void run() { + res = propertiesTree.findLeafPropertyInstances(graph, selectedShapes.getSelectionList()); + }; + }); + + + double refValue = parameter.toProperty().getScalarDouble(); + ArrayList mappedProperties = new ArrayList(); + + for (Resource r : res) { + IEntity propertyThing = EntityFactory.create(g,r); + assert (propertyThing.isInstanceOf(g.getBuiltins().Double)); + final String name = ResourceDebugUtils.getReadableNameForEntity(propertyThing); + double rb = propertyThing.toProperty().getScalarDouble(); + System.out.println("Mapping to " + name + " " + rb); + Collection equations = propertyThing.getRelatedObjects(ShapeEditorResources.equationResource.HasSource); + if (equations.size() != 0) { + mappedProperties.add(propertyThing.getResource()); + if (override) { + System.out.println("Override"); + boolean over = true; + if (ask) { + IEntity t = propertyThing; + while (t.isInstanceOf(g.getBuiltins().Property)) { + Collection ts = t.getRelatedObjects(g.getBuiltins().PropertyOf); + // FIXME : traverse all possible routes + t = ts.iterator().next(); + } + //StructuredResourceSelection selection = new StructuredResourceSelection(t.getResource()); + // TODO : do the selection! + //hierarchyScheme.setSelection(selection); + //fireSelectionChanged(); + MessageDialog dialog = new MessageDialog(ParameterizationContribution.this.parent.getRenderingComposite().getShell(), + "Override mapping", + null, + "Override mapping to property of highlighted shape?", + MessageDialog.QUESTION, new String[] { + "Yes","No", "Cancel" }, 0); + int i = dialog.open(); + if (i == 2) + return GraphRequestStatus.transactionCancel(); + over = (i == 0); + } + if (over) { + + } + } else { + if (equations.size() != 1) { + throw new RuntimeException("One property can have only one euquation as source function."); + } + IEntity equation = equations.iterator().next(); + if (!equation.isInstanceOf(ShapeEditorResources.equationResource.SecondOrderScalarPolynomial)) { + throw new RuntimeException("Only Second order scalar polynomials are supported"); + } + SecondOrderScalarPolynomial s = new SecondOrderScalarPolynomial(equation); + s.setA(new double[]{0.0}); + s.setB(new double[]{rb / refValue}); + s.setC(new double[]{0.0}); + + } + } else { //override + // create relation + SecondOrderScalarPolynomial s = SecondOrderScalarPolynomial.createDefault(g); + s.setA(new double[]{0.0}); + s.setB(new double[]{rb / refValue}); + s.setC(new double[]{0.0}); + + // these relations have been instantiated, but addStatements won't delete them so we have to delete them manually. + s.removeRelatedStatements(ShapeEditorResources.equationResource.HasTarget); + s.removeRelatedStatements(ShapeEditorResources.equationResource.HasSource); + + parameter.addStatement(ShapeEditorResources.equationResource.HasTarget, s); + + s.addStatement(ShapeEditorResources.equationResource.HasTarget, propertyThing); + mappedProperties.add(propertyThing.getResource()); + } + + } + G3DModel model = parent.getModel(g); + Collection animations = model.getAnimation(); + for (Animation animation : animations) { + Collection interpolators = animation.getInterpolator(); + for (Interpolator interpolator : interpolators) { + IEntity target = interpolator.getTarget(); + for (Resource property : mappedProperties) { + if (target.getResource().equals(property)) { + ShapeEditorResources.curveBuilder.createDefault(interpolator); + } + } + } + } + return GraphRequestStatus.transactionComplete(); + } + }); + + + + } + +} diff --git a/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/views/CSGModellingView.java b/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/views/CSGModellingView.java new file mode 100644 index 00000000..f2b8c84b --- /dev/null +++ b/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/views/CSGModellingView.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.shapeeditor.views; + +import org.eclipse.swt.widgets.Composite; + +import org.simantics.db.management.ISessionContext; +import org.simantics.layer0.utils.viewpoints.ResourceViewpoint; +import org.simantics.proconf.browsing.GraphExplorer; +import org.simantics.proconf.browsing.views.GraphExplorerView; +import org.simantics.proconf.g3d.shapeeditor.common.ViewpointGenerator; + +public class CSGModellingView extends GraphExplorerView { + + @Override + protected GraphExplorer createExplorer(Composite parent) { + return super.createExplorer(parent); + } + + @Override + protected ResourceViewpoint getViewpoint(ISessionContext context) { + return ViewpointGenerator.createViewpoint(); + } + +} diff --git a/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/views/ParameterizationEditor.java b/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/views/ParameterizationEditor.java new file mode 100644 index 00000000..07dc17cd --- /dev/null +++ b/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/views/ParameterizationEditor.java @@ -0,0 +1,587 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.shapeeditor.views; + + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.eclipse.jface.dialogs.InputDialog; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Text; +import org.eclipse.swt.widgets.Tree; +import org.eclipse.ui.forms.IFormColors; +import org.simantics.proconf.g3d.csg.stubs.CSGModel; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Resource; +import org.simantics.equation.stubs.SecondOrderScalarPolynomial; +import org.simantics.g2d.stubs.anim.Animation; +import org.simantics.g2d.stubs.anim.Interpolator; +import org.simantics.layer0.utils.ResourceDebugUtils; +import org.simantics.layer0.utils.IEntity; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.proconf.browsing.GraphExplorer; +import org.simantics.proconf.browsing.GraphExplorerInputFactory; +import org.simantics.proconf.g3d.common.StructuredResourceSelection; +import org.simantics.proconf.g3d.shapeeditor.ShapeEditorResources; +import org.simantics.proconf.g3d.shapeeditor.common.ViewpointGenerator; +import org.simantics.proconf.g3d.tools.OESelectionListener; +import org.simantics.proconf.g3d.tools.PropertyTree; +import org.simantics.proconf.g3d.views.SinglePageResourceEditor; +import org.simantics.utils.ui.widgets.TrackedModifyEvent; +import org.simantics.utils.ui.widgets.TrackedModifyListener; +import org.simantics.utils.ui.widgets.TrackedText; + + +public class ParameterizationEditor extends SinglePageResourceEditor { //implements ISelectionProvider{ + + //ParameterizedCSGModel model; + Resource modelResource; + private TrackedText modelName = null; + StructuredResourceSelection hierarchySelection = new StructuredResourceSelection(); + StructuredResourceSelection parameterSelection = new StructuredResourceSelection(); + GraphExplorer parameterExplorer; + GraphExplorer hierarchyExplorer; + Button deleteParameterButton; + Button clearButton; + PropertyTree propertiesTree; + Button generateButton; + Button askButton; + Button overrideButton; + Composite parent; + + + @Override + protected String getFormText() { + return "Parameterization Editor"; + } + +// @Override +// protected void beforeCreateWidgets() { +// if (!(getInputResource().isInstanceOf(GlobalIdMap.get(CSGModelingOntologyMapping.PARAMETERIZED_CSG_MODEL)))) +// throw new RuntimeException("Trying to open resource that is not paramaterized CSG model"); +// model = ParameterizedCSGModelFactory.create(getInputResource()); +// } + + + + @Override + protected void createWidgets() { + createModelPropertiesGroup(newGridSection(2, 2, false, false, "Model Properties", + "Basic properties for this viewpoint")); + createParametrizationGroup(newGridSection(2, 2, false, false, "Parameterization", + "Create parameterization for selected shapes")); + //getSite().setSelectionProvider(this); + } + + @Override + public void reload(Graph graph) { + modelResource = getInputResource(); + parent.getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + reload(); + } + }); + + } + + public void reload() { + + hierarchyExplorer.setInput(getSessionContext(),GraphExplorerInputFactory.clone(hierarchyExplorer.getInput()) + .input(modelResource) + .viewpoint(ViewpointGenerator.createObjectStructureViewpoint()) + .toInput()); + + parameterExplorer.setInput(getSessionContext(),GraphExplorerInputFactory.clone(parameterExplorer.getInput()) + .input(modelResource) + .viewpoint(ViewpointGenerator.createObjectSizingParameterViewpoint(ShapeEditorResources.g3dResource.HasSizingParameter)) + .toInput()); + + } + + private void createParametrizationGroup(Composite parent) { + toolkit.paintBordersFor(parent); + toolkit.setBorderStyle(SWT.BORDER); + + overrideButton = toolkit.createButton(parent, "Overwrite previous parameterizations", SWT.CHECK); + overrideButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + askButton.setEnabled(overrideButton.getSelection()); + + } + }); + + + askButton = toolkit.createButton(parent, "Ask before overwriting", SWT.CHECK); + askButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + + + } + }); + askButton.setEnabled(false); + + generateButton = toolkit.createButton(parent, "Generate linear parameterization", SWT.PUSH); + generateButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + generateMappings(); + + } + }); + generateButton.setEnabled(false); + + + } + + private CSGModel getModel(Graph graph) { + return new CSGModel(graph, modelResource); + } + + private void createModelPropertiesGroup(Composite p) { + parent = p; + toolkit.paintBordersFor(parent); + toolkit.setBorderStyle(SWT.BORDER); + + GridData gridData1 = new GridData(SWT.FILL, SWT.TOP, false, false, 1, 1); + GridData gridData2 = new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1); + + // Name + Label l1 = toolkit.createLabel(parent, "Name:"); + l1.setForeground(toolkit.getColors().getColor(IFormColors.TITLE)); + Text text = toolkit.createText(parent, "TODO: Insert model's name here", SWT.SINGLE); + GridData textLayout = new GridData(GridData.FILL, GridData.FILL, true, true); + text.setLayoutData(textLayout); + modelName = new TrackedText(text); + modelName.addModifyListener(new TrackedModifyListener(){ + @Override + public void modifyText(TrackedModifyEvent e) { + final String name = e.getText(); + getSession().asyncWrite(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + getModel(g).setName(name); + return GraphRequestStatus.transactionComplete(); + } + }); + } + }); + + l1.setLayoutData(gridData1); + text.setLayoutData(gridData2); + + + // Parameters + Label parameterLabel = toolkit.createLabel(parent, "Parameters:"); + parameterLabel.setForeground(toolkit.getColors().getColor(IFormColors.TITLE)); + parameterLabel.setLayoutData(gridData1); + + parameterExplorer = new GraphExplorer(parent, SWT.SINGLE); //new OntologyExplorer("ParameterExplorer", this, getInput("ParameterExplorer", model.getId())); + parameterExplorer.getViewer().addPostSelectionChangedListener(new OESelectionListener() { + + protected void resourceSelectionUpdated(StructuredResourceSelection sel) { + parameterSelection = sel; + if (parameterSelection.size() == 0) { + deleteParameterButton.setEnabled(false); + clearButton.setEnabled(false); + } else { + deleteParameterButton.setEnabled(true); + clearButton.setEnabled(true); + } + updateGenerateButtonStatus(); + } + + }); + Tree oe = parameterExplorer.getTree(); + toolkit.adapt(oe, true, true); + GridData gd3 = new GridData(GridData.FILL, GridData.FILL, true, true,1,1); + gd3.heightHint = 50; + oe.setLayoutData(gd3); +// parameterExplorer.init(getLastMemento(), ViewpointUtils.getModelledHandler(parameterExplorer.getGraph(), Builtins.DefaultViewpointId), null, ViewLabelProviderDecorationSettings.DEFAULT, new MenuAboutToShowAction(), new NullAdditionAction(), false); +// parameterScheme = new ParameterSelectionScheme(parameterExplorer); +// parameterExplorer.setSelectionScheme(parameterScheme); + + // Buttons to add and remove parameters + toolkit.createLabel(parent, ""); + Composite buttons = toolkit.createComposite(parent); + + buttons.setLayout(new FillLayout(SWT.HORIZONTAL)); + Button newParameterButton = toolkit.createButton(buttons, "New Parameter", SWT.PUSH); + newParameterButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + InputDialog dialog = new InputDialog(ParameterizationEditor.this.getSite().getShell(),"New Parameter","Enter parameter's name","new parameter",null); + if (dialog.open() == InputDialog.CANCEL) + return; + final String name = dialog.getValue(); + if (name.length() < 1) + return; // TODO : show error + + getSession().asyncWrite(new GraphRequestAdapter() { + public GraphRequestStatus perform(Graph g) throws Exception { + //fi.vtt.simantics.layer0.stubs.Double parameter = DoubleFactory.createDefault(g); + //getModel(g).addStatement(ShapeEditorResources.g3dResource.HasSizingParameter, parameter); + //parameter.setValue(new double[]{1.0}); + //parameter.setName(name); + Resource parameter = getModel(g).addRelatedScalarDouble(ShapeEditorResources.g3dResource.HasSizingParameter, 1.0).getResource(); + IEntity thing = EntityFactory.create(g,parameter); + thing.setName(name); + return GraphRequestStatus.transactionComplete(); + }; + }); + + + } + }); + deleteParameterButton = toolkit.createButton(buttons, "Delete Parameter", SWT.PUSH); + deleteParameterButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + //StructuredResourceSelection s = (StructuredResourceSelection)parameterScheme.getSelection(); + final StructuredResourceSelection s = parameterSelection; + if (s.size() != 1) + return; + // we'll have to start write transaction, since we may have to change the graph + getSession().asyncWrite(new GraphRequestAdapter() { + boolean proceed; + IEntity selectedParameter; + public GraphRequestStatus perform(Graph g) throws Exception { + selectedParameter = EntityFactory.create(g,s.getSelectionList().get(0)); + + Collection parameters = selectedParameter.getRelatedObjects(ShapeEditorResources.g3dResource.HasSizingParameter); + if (parameters.size() > 0) { + final MessageDialog dialog = new MessageDialog(ParameterizationEditor.this.getSite().getShell(),"Deleting a parameter",null,"Parameter is in use, doe you wan't to remove it?",MessageDialog.QUESTION,new String[]{"OK","Cancel"},1); + parent.getDisplay().syncExec(new Runnable() { + @Override + public void run() { + proceed = (dialog.open() != 1); + } + }); + if (proceed) { + getModel(g).removeStatement(ShapeEditorResources.g3dResource.HasSizingParameter,selectedParameter); + } + } + + return GraphRequestStatus.transactionComplete(); + } + }); + } + }); + deleteParameterButton.setEnabled(false); + + clearButton = toolkit.createButton(buttons, "Clear Parameter", SWT.PUSH); + clearButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + final StructuredResourceSelection s = parameterSelection; + if (s.size() != 1) + return; + getSession().asyncWrite(new GraphRequestAdapter() { + boolean proceed; + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + IEntity selectedParameter = EntityFactory.create(g,s.getSelectionList().get(0)); + Collection equations = selectedParameter.getRelatedObjects(ShapeEditorResources.equationResource.HasTarget); + final String name = selectedParameter.getName(); + if (equations.size() > 0) { + final MessageDialog dialog = new MessageDialog(ParameterizationEditor.this.getSite().getShell(),"Clearing a parameter",null,"Do you wan't to clear parameterization for "+ name + " ?\nIt has " + equations.size() + " mappings.",MessageDialog.QUESTION,new String[]{"OK","Cancel"},1); + parent.getDisplay().syncExec(new Runnable() { + public void run() { + proceed = (dialog.open() != 1); + }; + }); + if (proceed) { + for (IEntity eq : equations) { + eq.removeRelatedStatements(ShapeEditorResources.equationResource.HasSource); + eq.removeRelatedStatements(ShapeEditorResources.equationResource.HasTarget); + } + return GraphRequestStatus.transactionComplete(); + } + } + return GraphRequestStatus.transactionCancel(); + } + }); + + + } + }); + clearButton.setEnabled(false); + + Label hierarchyLabel = toolkit.createLabel(parent, "Model Hierarchy:"); + hierarchyLabel.setForeground(toolkit.getColors().getColor(IFormColors.TITLE)); + hierarchyLabel.setLayoutData(gridData1); + + hierarchyExplorer = new GraphExplorer(parent,SWT.MULTI); //new OntologyExplorer("HierarchyExplorer", this, getInput("HierarchyExplorer", model.getId())); + Tree oeh = hierarchyExplorer.getTree();//hierarchyExplorer.getControl(parent, 1, OntologyExplorer.OntologyTree, SWT.MULTI); + toolkit.adapt(oeh, true, true); + + GridData gd4 = new GridData(GridData.FILL, GridData.FILL, true, true,1,1); + gd4.heightHint = 200; + oeh.setLayoutData(gd4); + hierarchyExplorer.getViewer().addPostSelectionChangedListener(new OESelectionListener() { + + protected void resourceSelectionUpdated(StructuredResourceSelection sel) { + hierarchySelection = sel; + updatePropertiesTable(); + updateGenerateButtonStatus(); + } + + private void updatePropertiesTable() { + propertiesTree.setProperties(hierarchySelection); + + } + + }); + //hierarchyExplorer.init(getLastMemento(), ViewpointUtils.getModelledHandler(hierarchyExplorer.getGraph(), CSGModelingOntologyMapping.CSG_MODEL_HIERARCHY_VIEWPOINT), null, ViewLabelProviderDecorationSettings.DEFAULT, new MenuAboutToShowAction(), new NullAdditionAction(), false); +// hierarchyScheme = new HierarchySelectionScheme(hierarchyExplorer); +// hierarchyExplorer.setSelectionScheme(hierarchyScheme); +// hierarchyExplorer.hookPageSelection(this); + Label propertiesLabel = toolkit.createLabel(parent, "Available properties:"); + propertiesLabel.setForeground(toolkit.getColors().getColor(IFormColors.TITLE)); + propertiesLabel.setLayoutData(gridData1); + + //propertiesTable = toolkit.createTable(parent, SWT.MULTI); + Tree tree = toolkit.createTree(parent, SWT.MULTI); + propertiesTree = new PropertyTree(tree,getSession()); + // + GridData gd5 = new GridData(GridData.FILL, GridData.FILL, true, true,1,1); + gd5.heightHint = 200; + //propertiesTable.setLayoutData(gd5); + tree.setLayoutData(gd5); + tree.addSelectionListener(new SelectionAdapter() { + + @Override + public void widgetSelected(SelectionEvent e) { + updateGenerateButtonStatus(); + } + + }); + + + } + +// private class ParameterSelectionScheme extends AbstractSelectionScheme { +// +// public ParameterSelectionScheme(OntologyExplorer explorer) { +// super(explorer); +// } +// +// @Override +// protected Resource getResourceForSelection(TreeNode selected) { +// Resource resource = explorer.getCoreResource(selected); +// System.out.println("Parameter Tree Selection : " + resource.getId()); +// return resource; +// } +// +// @Override +// protected void resourceSelectionUpdated() { +// if (selection.size() == 0) { +// deleteParameterButton.setEnabled(false); +// clearButton.setEnabled(false); +// } else { +// deleteParameterButton.setEnabled(true); +// clearButton.setEnabled(true); +// } +// updateGenerateButtonStatus(); +// } +// } +// +// private class HierarchySelectionScheme extends AbstractSelectionScheme { +// +// public HierarchySelectionScheme(OntologyExplorer explorer) { +// super(explorer); +// } +// +// @Override +// protected Resource getResourceForSelection(TreeNode selected) { +// Resource resource = explorer.getCoreResource(selected); +// System.out.println("Hierarchy Tree Selection : " + resource.getId()); +// return resource; +// } +// +// @Override +// protected void resourceSelectionUpdated() { +// updatePropertiesTable(); +// updateGenerateButtonStatus(); +// } +// +// private void updatePropertiesTable() { +// propertiesTree.setProperties(selection); +// +// } +// +// } + +// private boolean contains(Resource list[], Resource value) { +// for (int i = 0; i < list.length; i++) { +// if (list[i].equals(value)) +// return true; +// } +// return false; +// } + + private void updateGenerateButtonStatus() { + if (parameterSelection.size() == 0) { + generateButton.setEnabled(false); + return; + } + if (hierarchySelection.size() == 0) { + generateButton.setEnabled(false); + return; + } + if (propertiesTree.getTree().getSelection().length == 0) { + generateButton.setEnabled(false); + return; + } + generateButton.setEnabled(true); + } + + List res; + + private void generateMappings() { + final StructuredResourceSelection selectedShapes = hierarchySelection; + final StructuredResourceSelection selectedParameter = parameterSelection; + + final boolean override = overrideButton.getSelection(); + final boolean ask = askButton.getSelection(); + //TreeItem[] selectedProperties = propertiesTree.getTree().getSelection(); + + assert (selectedParameter.size() == 1); + assert (selectedShapes.size() > 0); + //assert(selectedProperties.length > 0); + getSession().asyncWrite(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + //fi.vtt.simantics.layer0.stubs.Double parameter = DoubleFactory.create(g,selectedParameter.getSelectionList().get(0)); + IEntity parameter = EntityFactory.create(g,selectedParameter.getSelectionList().get(0)); + Collection prop = parameter.getRelatedObjects(ShapeEditorResources.g3dResource.HasDefaultDoubleValue); + //fi.vtt.simantics.layer0.stubs.Double defaultValue; + double value = g.getScalarDouble(parameter.getResource()); + if (prop.size() == 0) { + //defaultValue = DoubleFactory.createDefault(g); + //parameter.addStatement(ShapeEditorResources.g3dResource.HasDefaultDoubleValue, defaultValue); + parameter.addRelatedScalarDouble(ShapeEditorResources.g3dResource.HasDefaultDoubleValue, value); + } else { + //defaultValue = DoubleFactory.create(prop.iterator().next()); + g.setScalarDouble(prop.iterator().next().getResource(),value); + } + //defaultValue.setValue(parameter.getValue()); + final Graph graph = g; + parent.getDisplay().syncExec(new Runnable() { + public void run() { + res = propertiesTree.findLeafPropertyInstances(graph, selectedShapes.getSelectionList()); + }; + }); + + + double refValue = parameter.toProperty().getScalarDouble(); + ArrayList mappedProperties = new ArrayList(); + + for (Resource r : res) { + IEntity propertyThing = EntityFactory.create(g,r); + assert (propertyThing.isInstanceOf(g.getBuiltins().Double)); + final String name = ResourceDebugUtils.getReadableNameForEntity(propertyThing); + double rb = propertyThing.toProperty().getScalarDouble(); + System.out.println("Mapping to " + name + " " + rb); + Collection equations = propertyThing.getRelatedObjects(ShapeEditorResources.equationResource.HasSource); + if (equations.size() != 0) { + mappedProperties.add(propertyThing.getResource()); + if (override) { + System.out.println("Override"); + boolean over = true; + if (ask) { + IEntity t = propertyThing; + while (t.isInstanceOf(g.getBuiltins().Property)) { + Collection ts = t.getRelatedObjects(g.getBuiltins().PropertyOf); + // FIXME : traverse all possible routes + t = ts.iterator().next(); + } + //StructuredResourceSelection selection = new StructuredResourceSelection(t.getResource()); + // TODO : do the selection! + //hierarchyScheme.setSelection(selection); + //fireSelectionChanged(); + MessageDialog dialog = new MessageDialog(ParameterizationEditor.this.getSite().getShell(), + "Override mapping", + null, + "Override mapping to property of highlighted shape?", + MessageDialog.QUESTION, new String[] { + "Yes","No", "Cancel" }, 0); + int i = dialog.open(); + if (i == 2) + return GraphRequestStatus.transactionCancel(); + over = (i == 0); + } + if (over) { + + } + } else { + if (equations.size() != 1) { + throw new RuntimeException("One property can have only one euquation as source function."); + } + IEntity equation = equations.iterator().next(); + if (!equation.isInstanceOf(ShapeEditorResources.equationResource.SecondOrderScalarPolynomial)) { + throw new RuntimeException("Only Second order scalar polynomials are supported"); + } + SecondOrderScalarPolynomial s = new SecondOrderScalarPolynomial(equation); + s.setA(new double[]{0.0}); + s.setB(new double[]{rb / refValue}); + s.setC(new double[]{0.0}); + + } + } else { //override + // create relation + SecondOrderScalarPolynomial s = SecondOrderScalarPolynomial.createDefault(g); + s.setA(new double[]{0.0}); + s.setB(new double[]{rb / refValue}); + s.setC(new double[]{0.0}); + + // FIXME : these relations have been instantiated, but addStatements won't delete them so we have to delete them manually. + s.removeRelatedStatements(ShapeEditorResources.equationResource.HasTarget); + s.removeRelatedStatements(ShapeEditorResources.equationResource.HasSource); + + parameter.addStatement(ShapeEditorResources.equationResource.HasTarget, s); + + s.addStatement(ShapeEditorResources.equationResource.HasTarget, propertyThing); + mappedProperties.add(propertyThing.getResource()); + } + + } + CSGModel model = getModel(g); + Collection animations = model.getAnimation(); + for (Animation animation : animations) { + Collection interpolators = animation.getInterpolator(); + for (Interpolator interpolator : interpolators) { + IEntity target = interpolator.getTarget(); + for (Resource property : mappedProperties) { + if (target.getResource().equals(property)) { + ShapeEditorResources.curveBuilder.createDefault(interpolator); + } + } + } + } + return GraphRequestStatus.transactionComplete(); + } + }); + + + + } + +} + diff --git a/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/views/ShapeEditorBase.java b/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/views/ShapeEditorBase.java new file mode 100644 index 00000000..9c1490d7 --- /dev/null +++ b/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/views/ShapeEditorBase.java @@ -0,0 +1,628 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.shapeeditor.views; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IStatusLineManager; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.views.contentoutline.IContentOutlinePage; +import org.simantics.db.ContextGraph; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.GraphRequestWithResult; +import org.simantics.db.Resource; +import org.simantics.db.Session; +import org.simantics.db.management.ISessionContext; +import org.simantics.equation.solver.Solver; +import org.simantics.layer0.stubs.Property; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.proconf.g3d.actions.InteractiveAction; +import org.simantics.proconf.g3d.actions.TranslateAction; +import org.simantics.proconf.g3d.base.G3DTools; +import org.simantics.proconf.g3d.base.JmeRenderingComponent; +import org.simantics.proconf.g3d.base.ScenegraphAdapter; +import org.simantics.proconf.g3d.base.ScenegraphAdapterImpl; +import org.simantics.proconf.g3d.base.SelectionAdapter; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorProvider; +import org.simantics.proconf.g3d.common.StructuredResourceSelection; +import org.simantics.proconf.g3d.csg.stubs.CSGModel; +import org.simantics.proconf.g3d.csg.stubs.Primitive; +import org.simantics.proconf.g3d.dnd.DropListener; +import org.simantics.proconf.g3d.scenegraph.AbstractGraphicsNode; +import org.simantics.proconf.g3d.scenegraph.IGeometryNode; +import org.simantics.proconf.g3d.scenegraph.IGraphicsNode; +import org.simantics.proconf.g3d.scenegraph.ISelectableNode; +import org.simantics.proconf.g3d.shapeeditor.ShapeEditorResources; +import org.simantics.proconf.g3d.shapeeditor.actions.ExportAction; +import org.simantics.proconf.g3d.shapeeditor.actions.ImportAction; +import org.simantics.proconf.g3d.shapeeditor.scenegraph.CSGShapeNode; +import org.simantics.proconf.g3d.shapeeditor.tools.AnimationContribution; +import org.simantics.proconf.g3d.shapeeditor.tools.CSGModellingContribution; +import org.simantics.proconf.g3d.shapeeditor.tools.ParameterizationContribution; +import org.simantics.proconf.g3d.shapes.GridShape; +import org.simantics.proconf.g3d.stubs.G3DModel; +import org.simantics.proconf.g3d.stubs.G3DNode; +import org.simantics.proconf.g3d.stubs.Shape; +import org.simantics.utils.ErrorLogger; +import org.simantics.utils.ui.jface.MenuTools; + +public class ShapeEditorBase extends ThreeDimensionalEditorBase { + + // currently each 3D-model has a root object which is ShapeGroup + protected Resource model = null; + + protected boolean isParameterized; + + private Action exportAction; + private Action importAction; + + public ShapeEditorBase(ISessionContext session) { + super(session); + addEditorContribution(new CSGModellingContribution(this)); + addEditorContribution(new AnimationContribution(this)); + addEditorContribution(new ParameterizationContribution(this)); + } + + public ShapeEditorBase(ISessionContext session, JmeRenderingComponent component) { + super(session,component); + addEditorContribution(new CSGModellingContribution(this)); + addEditorContribution(new AnimationContribution(this)); + addEditorContribution(new ParameterizationContribution(this)); + } + + @Override + protected ScenegraphAdapter createScenegraphAdapter() { + return new ShapeEditorAdapter(session, getRenderingComponent()); + } + + @Override + public void createControl(Graph graph,Composite parent) { + super.createControl(graph,parent); + getRenderingComponent().getNoCastRoot().attachChild(GridShape.getShape(getRenderingComponent().getDisplaySystem().getRenderer(), 10, 1.f)); + } + +// private void loadGroup(Graph graph) { +// assert (model != null); +// adapter.addOutbound(EntityFactory.create(graph,model)); +// //assert (abstractGraphicsNodes.size() == 1); +// +// } + + protected void makeActions(Graph graph) { + super.makeActions(graph); + exportAction = new ExportAction(this); + importAction = new ImportAction(this); + } + + @Override + protected void fillLocalPullDown() { + super.fillLocalPullDown(); + MenuTools.getOrCreate(getMenuID(),"Model", menuManager).add(exportAction); + MenuTools.getOrCreate(getMenuID(),"Model", menuManager).add(importAction); + } + + + + /* + * These are used for updating CSG models geometry when internal shapes are moved. Interactive update is not possible + * because recalculation of geometry takes too much time. There are several problems in this method: + * 1. it relies on instanceof check + * 2. when shape is moved, transformations of its children are updated, which causes all + * child geometries to be updated, which is not necessary. We want to update only moved + * shape, since updateAllGemetry method takes care of parents. + * + * TODO : this functionality should be moved to TranslateAction + * TODO : prevent moved shape's children to be updated. + */ + + @Override + public void setCurrentAction(InteractiveAction action) { + if (getCurrentAction() == action) + return; + if (getCurrentAction() != null && getCurrentAction() instanceof TranslateAction) { + runGeometryUpdates(); + } + super.setCurrentAction(action); + } + + private void runGeometryUpdates() { + // now we'll just filter out all parents so that they won't be updated multiple times. + HashSet parents = new HashSet(); + for (CSGShapeNode n : geometryUpdates) { + IGraphicsNode parent = n.getParent(); + if (parent instanceof CSGShapeNode) + parents.add((CSGShapeNode)parent); + } + for (CSGShapeNode n : geometryUpdates) { + if (!parents.contains(n)) + n.updateAllGeometry(); + } + geometryUpdates.clear(); + } + + private HashSet geometryUpdates = new HashSet(); + + private void geometryUpdate(CSGShapeNode shape) { + + if (!(getCurrentAction() instanceof TranslateAction)) { + shape.updateAllGeometry(); + } else { + geometryUpdates.add(shape); + } + } + + public Graph createParameterization(Graph g) { + if (isParameterized) { + ContextGraph graph; + if (!(g instanceof ContextGraph)) { + graph = new ContextGraph(g); + graph.setContext(model); + } else { + graph = (ContextGraph)g; + } + Solver solver = new Solver(); + Collection parameters = getModel(graph).getRelatedProperties(ShapeEditorResources.g3dResource.HasSizingParameter); + for (org.simantics.layer0.utils.Property p : parameters) { + IEntity t = EntityFactory.create(graph, p.getResource()); + Collection exp = t.getRelatedObjects(ShapeEditorResources.equationResource.HasTarget); + if (exp.size() > 0) { + Iterator i = exp.iterator(); + while (i.hasNext()) + solver.evaluate(i.next()); + } else { + ErrorLogger.defaultLogWarning("Model property " + p + " is not bound to a expression", null); + } + } + solver.pushToGraph(graph); + return graph; + } else { + return g; + } + } + + + + protected class ShapeEditorAdapter extends ScenegraphAdapterImpl { + + public ShapeEditorAdapter(Session session,JmeRenderingComponent component) { + super(session,component); + } + + @Override + public synchronized void updateGeometry(Graph graph) { + if (isParameterized) { + graph = createParameterization(graph); + } + super.updateGeometry(graph); + } + + + + protected AbstractGraphicsNode instantiateNode(IGraphicsNode comp, + G3DNode node) { + CSGShapeNode mo = new CSGShapeNode(ShapeEditorBase.this, comp, node.getGraph(),node.getResource()); + updateGeometry(mo); + return mo; + } + + + private class ShapeEditorScenegraphQuery extends ScenegraphQuery { + + public ShapeEditorScenegraphQuery(Resource nodeResource) { + super(nodeResource); + } + + @Override + public void shapeAdded(Graph graph,IGraphicsNode n) { + updateGeometry((CSGShapeNode) n); + + if (n.getG3DNode(graph).getParent() == null) { + if (DEBUG)System.out.println("ShapeSubnodeListener " + + n.getResource() + + " has no parent"); + return; + } + if (DEBUG) System.out.print("ShapeSubnodeListener " + n.getResource()); + if (n.getG3DNode(graph).getRelatedObjects(ShapeEditorResources.g3dResource.GeometryDefinitionOf).size() == 0) { + if (DEBUG) System.out.println(" visible"); + ((ISelectableNode)n).setVisible(true); + } else { + if (DEBUG) System.out.println(" invisible"); + ((ISelectableNode)n).setVisible(false); + } + } + +// @Override +// public NodeQuery instantiateQuery(Resource node) { +// return new ShapeEditorScenegraphQuery(node); +// } + } + + @Override + protected ScenegraphQuery newSubnodeListener(G3DNode node) { + return new ShapeEditorScenegraphQuery(node.getResource()); + } + + private class ShapeEditorNodePropertyQuery extends NodePropertyQuery { + public ShapeEditorNodePropertyQuery(Resource nodeResource) { + super(nodeResource); + } + + @Override + public void shapeUpdated(Graph graph,final IGraphicsNode shape) { + if (DEBUG) System.out.println("Tri - Shape id " + shape + " modified"); + ((CSGShapeNode) shape).updateAllGeometry(); + } + +// @Override +// public NodeQuery instantiateQuery(Resource node) { +// return new ShapeEditorNodePropertyQuery(node); +// } + } + + @Override + protected NodePropertyQuery newPropertyListener(G3DNode node) { + return new ShapeEditorNodePropertyQuery(node.getResource()); + } + + private class ShapeEditorNodeTransformationQuery extends NodeTransformationQuery { + public ShapeEditorNodeTransformationQuery(Resource nodeResource) { + super(nodeResource); + } + + @Override + public void shapeUpdated(Graph graph,final IGraphicsNode shape) { + if (DEBUG) System.out.println("Tra - Shape id " + shape + " modified"); + ((CSGShapeNode) shape).updateTransform(graph); + geometryUpdate((CSGShapeNode)shape); + } + +// @Override +// public NodeQuery instantiateQuery(Resource node) { +// return new ShapeEditorNodePropertyQuery(node); +// } + } + + @Override + protected NodeTransformationQuery newTransformationListener(G3DNode node) { + return new ShapeEditorNodeTransformationQuery(node.getResource()); + } + + private class ShapeEditorRootPropertyQuery extends NodePropertyQuery { + public ShapeEditorRootPropertyQuery(Resource nodeResource) { + super(nodeResource); + } + + @Override + public void shapeUpdated(Graph graph, final IGraphicsNode shape) { + if (DEBUG)System.out.println("Tri - Shape id " + shape + " modified"); + + updateParameterizationStatus(graph); + if (isParameterized) { + for (IGraphicsNode n : getNodes()) + if (n instanceof IGeometryNode) + updateGeometry((IGeometryNode) n); + } + } + +// @Override +// public NodeQuery instantiateQuery(Resource node) { +// return new ShapeEditorRootPropertyQuery(node); +// } + } + + @Override + protected NodePropertyQuery newRootPropertyListener(G3DNode root) { + return new ShapeEditorRootPropertyQuery(root.getResource()); + } + + } + + protected void contributeStatusBar(IStatusLineManager manager) { + } + + /** + * Loads the initial scene: all further updates to the view are done by + * listening changes in the shapes and int the shape group + * + * @param resource + */ + protected void reloadFrom(IEntity thing) { + if (model != null) { + throw new UnsupportedOperationException( + "Reloading instantiated viewer not supported"); + + } + if (thing.isInstanceOf(ShapeEditorResources.csgResource.CSGModel)) { + //System.out.print("ShapeEditorView.reloadFrom() : model"); + Graph g = thing.getGraph(); + model = thing.getResource(); + //System.out.println(" " + model.getResource()); + adapter.setRootNode(new G3DNode(thing)); + updateParameterizationStatus(g); + + //loadGroup(thing.getGraph()); + + } else { + throw new UnsupportedOperationException("Cannot load ShapeViewer for Resource:" + thing); + } + + } + + private void updateParameterizationStatus(Graph graph) { + G3DModel model = getModel(graph); + if(model.getRelatedObjects(ShapeEditorResources.g3dResource.HasSizingParameter).size() > 0) { + isParameterized = true; + } else { + isParameterized = false; + } + parent.getDisplay().asyncExec(new Runnable() { + @Override + public void run() { +// for (Action a : addActions) +// a.setEnabled(!isParameterized); +// unionAction.setEnabled(!isParameterized); +// differenceAction.setEnabled(!isParameterized); +// intersectionAction.setEnabled(!isParameterized); +// linkAction.setEnabled(!isParameterized); +// unlinkAction.setEnabled(!isParameterized); +// translateAction.setEnabled(!isParameterized); +// rotateAction.setEnabled(!isParameterized); +// removeAction.setEnabled(!isParameterized); + } + + }); + } + + public Resource getModelResource() { + return model; + } + + public G3DModel getModel(Graph graph) { + return new G3DModel(graph, model); + } + + @Override + protected SelectionAdapter createSelectionAdapter() { + return new ShapeEditorSelectionAdapter(adapter); + } + + protected class ShapeEditorSelectionAdapter extends SelectionAdapter { + + public ShapeEditorSelectionAdapter(ScenegraphAdapter adapter) { + super(adapter); + } + + public void setEditorSelection() { + List sel = getSelectedObjects(); + for (IGraphicsNode o : adapter.getNodes()) + if (o instanceof ISelectableNode) { + ISelectableNode n = (ISelectableNode)o; + if (sel.contains(o)) + n.setSelected(true); + else + n.setSelected(false); + } + List selected = getSelectedResources(); + for (Resource r : selected) { + if (!adapter.hasNode(r)) { + //adapter.addInbound(r).setSelected(true); + } + } + } + + public void setEditorHighlightSelection() { + List sel = getInteractiveSelectedObjects(); + for (IGraphicsNode o : adapter.getNodes()) + if (o instanceof CSGShapeNode) { + if (sel.contains(o)) + ((CSGShapeNode) o).setHighlighted(true); + else + ((CSGShapeNode) o).setHighlighted(false); + } + } + + public void setEditorSelection(boolean addShapes) { + + List sel = getSelectedObjects(); + for (IGraphicsNode o : adapter.getNodes()) + if (o instanceof ISelectableNode) { + ISelectableNode n = (ISelectableNode)o; + if (sel.contains(o)) + n.setSelected(true); + else + n.setSelected(false); + } + viewChanged = true; + if (addShapes) { + session.syncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + List selected = getSelectedResources(); + for (Resource r : selected) { + if (!adapter.hasNode(r)) { + IEntity t = EntityFactory.create(g, r); + if (t.isInstanceOf(ShapeEditorResources.g3dResource.Shape)) { + G3DNode group = G3DTools.getModelFromResource(g,r); + if (group != null + && group.getResource().equals(model.getResource())) { + //adapter.addInbound(g).setSelected(true); + } + + } + } + } + return GraphRequestStatus.transactionComplete(); + } + }); + + } + } + + public StructuredResourceSelection filterSelection(ISelection selection) { + if (!(selection instanceof StructuredResourceSelection)) + return new StructuredResourceSelection(); + return (StructuredResourceSelection) selection; + } + + } + + /** + * Receives selection changes + * + * @param part + * @param selection + */ + protected void pageSelectionChanged(IWorkbenchPart part, ISelection selection) { + + StructuredResourceSelection s = SelectionAdapter.transformSelection(selection); + //System.out.println("ShapeEditorBase.pageSelectionChanged " + s); + selectionAdapter.setCurrentSelection(s); + + if (!(part instanceof ThreeDimensionalEditorProvider)) { + ((ShapeEditorSelectionAdapter) selectionAdapter).setEditorSelection(true); + return; + } + ThreeDimensionalEditorBase e = ((ThreeDimensionalEditorProvider)part).getEditor(); + if (!(e instanceof ShapeEditorBase)) { + ((ShapeEditorSelectionAdapter) selectionAdapter).setEditorSelection(true); + return; + } + + ShapeEditorBase editor = (ShapeEditorBase)e; + + if (!editor.getModelResource().equals(model.getResource())) { + selectionAdapter.setCurrentSelection(new StructuredResourceSelection()); + ((ShapeEditorSelectionAdapter) selectionAdapter).setEditorSelection(false); + return; + } + selectionAdapter.setEditorSelection(); + } + + @Override + protected void hookDragAndDrop() { + super.hookDragAndDrop(); + dropTarget.addDropListener(new DropListener() { + public boolean acceptDrop(StructuredResourceSelection s, Resource[] ids) { + if (!s.isEmpty()) + return false; + if (ids == null) + return false; + if (ids.length != 1) + return false; + final Resource r = ids[0]; + GraphRequestWithResult rq = new GraphRequestWithResult() { + @Override + public Boolean performWithResult(Graph g) throws Exception { + IEntity t = EntityFactory.create(g, r); + return t.isInstanceOf(ShapeEditorResources.csgResource.Primitive); + } + }; + session.syncRead(rq); + return rq.getResult(); + } + + public void doDrop(StructuredResourceSelection s, Resource[] ids) { + session.asyncWrite(new GraphRequestAdapter() { + Resource r; + + public GraphRequestStatus perform(Graph g) throws Exception { + IEntity type = EntityFactory.create(g); + IEntity instance = type.instantiate(); + Shape shape = new Shape(instance); + resetShape(shape); + CSGModel m = new CSGModel(g, model); + m.getChild().add(shape.toG3DNode()); // FIXME : stubcast + return GraphRequestStatus.transactionComplete(); + + }; + + @Override + public void requestCompleted(GraphRequestStatus status) { + selectionAdapter + .updateSelection(new StructuredResourceSelection(r)); + super.requestCompleted(status); + } + } + ); + + } + }); + } + + private void resetShape(Shape shape) { + G3DTools.resetTransformation(shape); + Graph graph = shape.getGraph(); + if (shape.isInstanceOf(ShapeEditorResources.csgResource.Primitive)) { + Primitive prim = new Primitive(shape); + Collection c = prim.getSizingProperty(); + if (c.size() == 0) + ErrorLogger.getDefault().logWarning("Shape does not contain sizing properties.", null); + + for (Property p : c) { + if (p.isInstanceOf(graph.getBuiltins().Double)) { + graph.setScalarDouble(p.getResource(), 1.0); + } else if (p.isInstanceOf(graph.getBuiltins().Integer)) { + graph.setScalarInteger(p.getResource(), 1); + } else { + ErrorLogger.getDefault().logWarning("Cannot handle sizing property " + p.getName() , null); + } + } + } + + } + + @Override + public Object getAdapter(Class adapter) { + if (adapter == IContentOutlinePage.class) { + if (getModelResource() == null) + return null; + final StructureOutlinePage page = new StructureOutlinePage(sessionContext,getModelResource()); + + getSelectionAdapter().addSelectionChangedListener(new ISelectionChangedListener() { + @Override + public void selectionChanged(SelectionChangedEvent event) { + page.setSelection(event.getSelection()); + + } + }); + parent.getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + page.addSelectionChangedListener(new ISelectionChangedListener() { + @Override + public void selectionChanged(SelectionChangedEvent event) { + selectionAdapter.setSelection(SelectionAdapter.transformSelection(event.getSelection())); + } + }); + } + }); + + + + return page; + } + return null; + } + +} diff --git a/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/views/ShapeEditorView.java b/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/views/ShapeEditorView.java new file mode 100644 index 00000000..8fa7a37b --- /dev/null +++ b/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/views/ShapeEditorView.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.shapeeditor.views; + +import org.simantics.db.management.ISessionContext; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorPart; + + + + +/** + * Shape Editor / CGS-modeling + * + * + * @author Marko Luukkainen + * + */ +public class ShapeEditorView extends ThreeDimensionalEditorPart { + + + @Override + protected ThreeDimensionalEditorBase createEditor(ISessionContext session) { + return new ShapeEditorBase(session); + } + +} + diff --git a/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/views/StructureOutlinePage.java b/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/views/StructureOutlinePage.java new file mode 100644 index 00000000..c0ddb2af --- /dev/null +++ b/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/views/StructureOutlinePage.java @@ -0,0 +1,21 @@ +package org.simantics.proconf.g3d.shapeeditor.views; + +import org.simantics.db.Resource; +import org.simantics.db.management.ISessionContext; +import org.simantics.layer0.utils.viewpoints.ResourceViewpoint; +import org.simantics.proconf.browsing.views.GraphExplorerOutlinePage; +import org.simantics.proconf.g3d.shapeeditor.common.ViewpointGenerator; + +public class StructureOutlinePage extends GraphExplorerOutlinePage { + + + public StructureOutlinePage(ISessionContext session, Resource model) { + super(session,model); + } + + @Override + public ResourceViewpoint getViewPoint(ISessionContext sessionContext) { + return ViewpointGenerator.createObjectStructureViewpoint(); + } + +} diff --git a/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/views/StructureView.java b/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/views/StructureView.java new file mode 100644 index 00000000..f747d49c --- /dev/null +++ b/org.simantics.proconf.g3d.shapeeditor/src/org/simantics/proconf/g3d/shapeeditor/views/StructureView.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.shapeeditor.views; + +import org.simantics.db.management.ISessionContext; +import org.simantics.layer0.utils.viewpoints.ResourceViewpoint; +import org.simantics.proconf.browsing.views.GraphExplorerView; +import org.simantics.proconf.g3d.shapeeditor.common.ViewpointGenerator; + +public class StructureView extends GraphExplorerView { + + @Override + protected void contributeActions() { + } + + @Override + protected ResourceViewpoint getViewpoint(ISessionContext context) { + return ViewpointGenerator.createStuctureViewpoint(); + } + + /* + @Override + public String getContributorId() { + return "fi.vtt.simantics.shapeeditor.pcid"; + } + + @Override + public Object getAdapter(Class adapter) { + if (adapter == IPropertySheetPage.class) { + return new TabbedPropertySheetPage(this); + } + return super.getAdapter(adapter); + } + */ + +} diff --git a/org.simantics.proconf.g3d/.classpath b/org.simantics.proconf.g3d/.classpath new file mode 100644 index 00000000..2e6482e2 --- /dev/null +++ b/org.simantics.proconf.g3d/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/org.simantics.proconf.g3d/.project b/org.simantics.proconf.g3d/.project new file mode 100644 index 00000000..a27da2fb --- /dev/null +++ b/org.simantics.proconf.g3d/.project @@ -0,0 +1,28 @@ + + + org.simantics.proconf.g3d + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/org.simantics.proconf.g3d/META-INF/MANIFEST.MF b/org.simantics.proconf.g3d/META-INF/MANIFEST.MF new file mode 100644 index 00000000..75a57e01 --- /dev/null +++ b/org.simantics.proconf.g3d/META-INF/MANIFEST.MF @@ -0,0 +1,44 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: G3D Plug-in +Bundle-SymbolicName: org.simantics.proconf.g3d;singleton:=true +Bundle-Version: 1.0.0 +Bundle-Activator: org.simantics.proconf.g3d.Activator +Bundle-Vendor: VTT +Require-Bundle: org.eclipse.ui, + org.eclipse.core.runtime, + org.simantics.g2d.stubs, + javax.vecmath, + com.jme.eclipse, + org.simantics.proconf.image, + org.eclipse.ui.views, + org.simantics.proconf.animation, + org.simantics.db, + org.simantics.layer0.stubs, + org.simantics.layer0.utils, + org.simantics.image.stubs, + org.simantics.utils, + org.simantics.utils.datastructures, + org.simantics.utils.ui, + org.simantics.proconf.ui, + org.simantics.proconf.ui.workbench, + org.simantics.equation, + org.simantics.proconf.browsing, + org.eclipse.ui.forms, + org.eclipse.core.expressions +Eclipse-LazyStart: true +Export-Package: org.simantics.proconf.g3d.actions, + org.simantics.proconf.g3d.animation, + org.simantics.proconf.g3d.animation.ui, + org.simantics.proconf.g3d.base, + org.simantics.proconf.g3d.common, + org.simantics.proconf.g3d.dialogs, + org.simantics.proconf.g3d.dnd, + org.simantics.proconf.g3d.gizmo, + org.simantics.proconf.g3d.input, + org.simantics.proconf.g3d.preferences, + org.simantics.proconf.g3d.scenegraph, + org.simantics.proconf.g3d.shapes, + org.simantics.proconf.g3d.stubs, + org.simantics.proconf.g3d.tools, + org.simantics.proconf.g3d.views diff --git a/org.simantics.proconf.g3d/build.properties b/org.simantics.proconf.g3d/build.properties new file mode 100644 index 00000000..6f20375d --- /dev/null +++ b/org.simantics.proconf.g3d/build.properties @@ -0,0 +1,5 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + plugin.xml diff --git a/org.simantics.proconf.g3d/data/defaultfont.tga b/org.simantics.proconf.g3d/data/defaultfont.tga new file mode 100644 index 0000000000000000000000000000000000000000..e215541cb3234e1016821985558e8b0a7c4f2459 GIT binary patch literal 1048594 zcmeFaJC-ClkR;eMCs}fjHiwua>yojKcA4-(?2pR-=ZX3Meqf*3 z?*u!3o*&o{g#%sC3EfC77?5ZB>nudsLOsxV5a1(6eFYXVYq^;b?rRO#+y9ps^8cM> z?_W^|4ioTKVBF~>{+(R*KQlk?5_jGAe?7Doo`^NqAM+hH5Q{l6S!d4n6}j%W#|cP` zT08qAa-4H_DdH>yr+Mx>9@&)4{BL7cQm0` zJ_~`zv?K1|*KvOS_xZtH6J>l5Tim_TPp+aZKN*7^9MFC5uQ%e|>FTGnBi5e)&k8YX z?d*@t4*}D6pSAWVY`pVl!n3g62T<1i7@VBJ{Y9WN=d->(-=p946Mw}yMBOxt>rBr- z^p)&#JEQ8fg?W_T9z7bD**WjQg)H!xR?NBEgSpiNOnkH*WgoYyuC}1O3Mcixc5Ib@ z+$-N<&Ys}^A)qKT&b4;-N9MZc>U`JQqp(#!eg*(~nNZgI0Ay!ysTaBGskQ4lyy96< zaj$IhKD9l%e27sfN9(`ShdYoay^G$Bjp*0!yI=?JWD&YcI( zbVRnDaGz47?$ot^J&nX1d}G>q_Z+b`dW@b&v*%5#Z9f?7GshmlakX~#&*TExU7W%7 zu?o&Uwy_?SQ!jGWS!*X3R`I~U`{!AscOKZba}BQKoW{IX)|jk{dkvfIoOi??_ON|r zj=QhoqRjj7N?g}{!hTBLpY=U_crwn|hnRkzg(q#y`KEC^7(&x-tdxTBI z8_6T^sYCZX`c9iD6P1_VY1Qt!u!V_sMcF|;e$FEnXw#U$hMmvAD>+BMYq`z^{MNg0 zZOn>xeGZ2mtDnF1><8C42T$Aq;IF0?@lBn3&Xv(P zUU9R#*ox62=Xs?pR;FbHoK5v&MV%6QFCvLlB^|=GFc*=L> z1nj_hyfOy7m+F0o>i~T#v0XR()#UwI-#Z^q#G8Bs4_5AdPxy9+srxa{h`TXgy`Osx z=3AdNYweN#`ZF+WV8VH<_RQjf%X+R82RYiwbv}Qg9X8D3-i<#1WC?2!vAG-jo%#`L zO;7pnoLtQTJpY3OK9^`)`5l19x~J@RX8qrD_f=zpJ&*}|&{y?i)NZ}|KlS`EYWwIo z%rg_uKi2%H5L=u~r-(K+^dob$D$&*#zD zs&5zn^*i61&wBpBF1@3u&EKWWI~n8gq+hgw`IEM+!lrM%`6_!-??3zRQ?bCA&xAea zDLbCR)pvio|2}2UYFz#QPKV5Qt$npUI2UVa$9+`qAUto81Dod)a@5)18xxG9uCw?% z;dx)*J)sdYkkva0+9JOb>9u{O{OQ`Kv=Zx1_a{Tn%ANdI>~|kq>tE5=7Mt(Mvwa*ENYY*hKm7l*2boPx_{Ip!}pQJF(x@Z^Za6?VN`vu&}Q%t=?;&@UIn< zF=&Z32#R674Io^_=CqA3dviPU~|z`g?8iXMa75J*S@FZ z;h(0b>;SH(CvDk@{jPqO=KS4aq0c`f``S*PCRYEsqcL-C_taI-Y+27jo`bZ7x>-lg zw&+~n`y7I!cLLg{cM|mX+5$f``FOows2s|?m-v|PP**O%*C%}fKGVn?KWY06HhpG3 zqwA}UrO&netNGJwFV1`>+y#2ar~KE7nVw_VdpUo#cJ@c+2MKrPIQO8N31ziqIvi2wkwRU*ms!2Px%U5O|a`L#&g7G^&9089XaM} z#!dGe?7QzckMG3)+Ryma+E?&F|Gx!dukWCMr@w=M@86^C(Ea{6F;zcoVrpqunOa%z z+0c#e__^M27dX&(k$6w4>Hn(jm|sm#o&U;z*z;ZEUE+zxALWwF%C@KRSNhhX`zil- zJ!iGV;7OUM;{Sxt`kq<$xLW%v8~u6M=Kyuc@QjSM;}AeUb4qvO*|mc4Ek27`|0?q5 z6Qg7Cq`p@acazHhlkaoF7g2KA_|`?gEHO>E{KaIzy@Ll1Q$G7Y!%h4=Og{HN6Z_g)%=Vm* zyQo;l7qXPlD*$${iRav(X797ql%2a*HHf#g7P zAUTj6NDd?ik^{+sgsX6Rfbq-^0@6zh|_jqD2_T(~Ab^Sdvj_LI%OxM%G zffaM${NS5$wnV=RD`DKV zMfgk|J^X`REAGIh^}%;Wd9jA?sJTh4y22dtIo*y>)7GS`{!4J*z+^#ypf z=WvyaEc@Am_|kuz3%)mDt|IaAZb#E`R`|Ztd9h;dOTNH{QYy(tv?<<>?^@hu#fRT` z_dyw-1I!oucI3VuqT}QI1IKvAm-rv;zdw5bpZxcCP>98jm?uU#&X}v?o6Q0IS@~Y; zj!UI?pSs3NXQKAs>A&lD{2w;IzW=Rw2E~5kIA_zRbmzxtzn|~!A8gYUy$2!Q$Hxaa z-23Pc+BC6!RqlK44s5-DMsm9)Mn1oekNH5tydNK*7QGQNel}x`MCer=r^-*s`A7d% zNXO5X4^@1Yef?oRGhX12}G z7w6xs{=4yhzWDifH-1$=_99KI=3X&SF8R|UQySOOcBk9Ocui?5}l>dh*=DR=Y_va(Xvo9)F6A*vLM1K_4h#t3Z zL`Ux!@ZeD3vs}6x_UgToS3JM>!IZ19qkWF^^Tbg*aPF=2Td}~sQ9q)``M$gAUgYn; zeE&gR6XYX(Roy6;bgRr!ktvNEZBsmyNA--3dlDb>jWu|cM*S*{yTZBZE9n|(yTU*m zd_9a{%#K<4{Ez)rQ^{8ChkQw9rj7cKv%q+>jrolJnXx!~G(~^^S+Wgr@U;55N8kI? zN4KG5>uekRYDv-O4(-qw)jvNQ z6J-N*YAWf~{vCHT#Y4Gd)5^9d@WF$_fu)XhfVJw+hqG}Ih_2!+F2}&+px#{b$(QSHKt5RdlX^_fY_@t(v-y#0h3%0Sc|Lf9{RkiYu)Ww;p=gN;DZDob^k{h zZJM+{!XDLqSB_qLCHwu^e;4O)x4|8!lvdt-e2-I}m!5rKUny?cHWruCd}BX|UT0rz ze&GL63eMTK!D$wD06Y9VbQ@{wXzo7Voj*9QMzLDP`F)36Xc;>ygT1aLtvVBYt=-u&>SvDoH+MDG z%KePh-?8#N81Y&io6>s3eP9Ky&VS9f7MW<zDopBi+~_@@ILNvGU-`y9 z7ubficbp$4tj`F)Q^((N1jjVKj5Bl0fpa1< zcEst;BW<8A_~~mYviGm3``M2@Xvcit z`LZe&uD7**XK!@B+ZCz*Fy$rPCbEo+Eq9TUeKTz>zO~5A*l;&i<8qwF+{tHue~j>6 z$M1qV@0f!h=O_AENHKcKQF9D`;FogD?Lb^sy!Wd4;P^GUh<3m4xSyzNLaZWi?{p|8 z%6Ia!{T>JKA)4zY8xhar<8x+3Khe$vyGnXS+NiTPAHf^MQMLhd7k>gDC7* z(DRoC06wc-zCW&f7o@mm)+d`(E~4!3IDzf=pa`6j4u9u>`A|8ZAKXQ?f2IsSN74+Y zk3CKU@ZtU2*PH+RANc4xX6iooe!h4=Y@NZYjdefWj@r1{_FtzzntXk`|B#=>)bYou z4bk5eB7_`7TEy-FN?j(PSW*S_erf91c=%a!bG zpZW;gT|fH*yLucjU?dkPzL|)^8@`#R^F;C;W?cluf z!27>)ow0_0tJZdJd}tH%-toQizRrm2`Of$_cCSyZ^6;rQwd!t_^E0Mq&(E`?RcC~p z+YzDDb>NKk`arZ0v zV^b0Ca|u)1p2k;Ow2Zy-I6vC<)ywc_=egDruP5gJhl5)EJDxq53xEDFw~N)5Iqa3W zy94ZwKkWC^>r<;do^|ieAn>zQ--sOcfGZnTp8c@b(})kFV{q5N^Uqa6|EfC)-YHzA zmDr`2xh*A`m2FSsuku z_fY&^67QqlITq=A&VO4xN{0$t;Gk^aZ4Z!^4 z_rd;kekdD}Q$O=Nos?sKCqLRx{me)8M2w>i%p-JC2X!)Mdnw1>;D4(O^@zX8NPOlc z{OC4fd0yi<+G}alHrI#0LwTjk<*#H%`ru<}{qyWu^>_Gyi#?__K{omhH~K9KFM<_2XPU8jV0KBGx=?8A(6RK{Y={+DB~Qm=V0v80zcIOS(qddgdQ{ ze$?7?fA4JXmA}(h>)(Y_!`JqewzTSAdG^CsPwM}wvSYGd+h5RLOQSZrzPsPI?DC_y zJ`VHSdj3Z4|FGk5r#kAmtGF+tb?kvx>D8V+qt4*c+P;bd`c~ch?{L{4Iq%dtl8P&O)eOxA19 zdT6huQJYHoYWELdcpAmkak$I(Cd_}ty8w?V?jZ2Lq?_+1fvqX(EU3NvC)SGZ0H}K; z$NN~F$B{DbG#<}ZTQFB6m^!8vt0Wh3{=k-*q`u6QM{StF#Mqhn2XAKY#P0WX zrn@mJi}IcPX#Xyp7W-D(a;3X;Hq7q%HGi+{sEwIzcTC-1O8lq1%CT+K7LND)I2%ej zU9Ke4(*_(*Xe;?&lkLHyEcOjee3tWbj{A#aLyxx2K8xbMrHN;Y&voryM!$M<#YFjT ze6ReKKE&D+=b<*v&w$yuJAMrp?IZSH>0@7y4IC4lKVgG&9yZ+F!JnLe#N1Q#JW$^* z9O7N&D{ZOi-g)-JcTZRGi0X69LmGJQ5DRrCm17&_dUK91<)wGvF4v2v^3d-I&%7$* zW%PRjS6uF@?)whU9NaldNn?+GeGb?2nR>3UYkmIipK)-1XPRPia@+3z;Pj=M2;{htg7(07Md>VLupkLA(eJJ$M>^S>)j zyKqWe@V1q#;lpnQ^y_@`Mepya zkF0;_KgA}UG%>-Q-i*rQJa`u;U-Sc%Ww7th3$m;w8lkY$LPU5`i#c_G}&-+=& znsgiQp4B+EmLCRApKJ0f+RcPp9{HUWKFr$HYr`yFY5Ws5AaO`YIdUj#W4< zdRN-wy8Ri0{eBL$*xe&T9OgY^M`ek{9OoaNWtn(3=`#oVA?GQ|2I$eV(9fbMT;O=> zIoEt_tN(g;;2EapuluX#J25#g#AG{iw)Nz-cmLF(^8pOKe^6#LhrZs#xQ$|Roa3^6 zXFg)X$e1giTwiPbN@s6hE2hfzVz|8OLfQLScR8<9ZX|bIz4Z~ymN9Ne%a~O%D{XPz zwYu-i(Y`uvwEmJl$Hcj!XFK1o>hnJO^*%ryCH*aJ9M2qMa31Qj8SOxyrxuKw%#5zl zv3i!$FFk*8zjAx;u(aRDw$%O3i#gVD$_Zdaoxi{sO|W71ot$H<&%4SaHjIq9^2hbH z)~|H-_O)WFTrY;pt1gtipLLh>I^{-k*VS7e!E71hcC?IHC9~2N*UdW4AG}Z1guVMK z`dG7BeM6bgm25xG0>&a|LVfl54-CC?0GrR|C~Jc3=tuRS+@oi7>>&dgZ*B9l7dB}E zC*4l%_rANjzI%Y4+C5kAW02!~-08pThpy2Cn`Z2A+&f!W^pDsuGUm#5*VkIV(%IYB zim7tF7%tz+X~is+U2jjlq_3x~2dhWcZRi;rExXbd*UftEIhT9(SMsrDD}7~7-}K&t zu}nOBcAWpf)%D4{7j0o)^R1a*k`w z_1%Noc2|!24#07)?1r!Yu7bR{8dvK(47_yr^0Al?tOMZUyBwb{m%po@Dn6w~37I{GGm9|1O*wzP7Kl#dV{uJn-KS zfwix;MU~x-D7{yD9Fyli_BJMc4o5rm`5pw>E1au7jMb#Fel|to0_RZRv#j&3c6b?b znxMyJYIPk)nNl139E;x>u>X+3BWJRor=sq%7;)~v2T$~?miv7Occ+@{UHcCM_q$bT zypNgP56pyHUvzC^EZ1bo*4DOO8(Q`D$UR|$?=P*Kj{(?Z^Jgbg&?~%lFiMFK=D{ zZU^+V;)>~i#+2Hq&-Z)I5&Cr=M$SP$OVy5+^6axOeDFlSukw*GC4Cw{>h$%m<4Qk^ zIlC7Sm$~A3xrBdZuaB?QiOswwx3Zns%vWMjcZvTk_bJ-Qoccy`>R^7SgL2I8W@;&vEA9w5D&turZxV2!@Zse5LHNY67ue3jL4CHj&$T{S^zVqGR zh4DT}n?`cPLDQ8E#M$3h{5spN#@zKC3jR?>9CS`G4~TCm&F%xPvt%zYaL(&|V;t%w z`QA3@($qUXLSFGvj?menqqLrn6Tfs0;hyhvFl#HuYr3;pWl_G9AMM|TgIH_A`sSKK z?&}@$qdt|!DK^R_8MM8M9X0z#+TC~E^SlprVnEIl`+D;hJ%mT)+ ztn0k0D~}j&Jy-b-y2O3B4c&egK<5=^txs)%Zui;80aw!~uIg2NBW3K#s;{@~_oyBl zM($j0Uk{$kVm@5oNZs}J)JO12V;r+2v#PChrn^10`s^BTy>~wL%HQd$_3y&*XAsBr zdc-q_`t16(Ps`XRJl*Y=I{vQgx?AgadawE&LuC)^L|yx>`%|CF-IZJPlvK$%_xGLttaCM1_1u+P_2{{&WA5~~^pBjsnER3EFU3+mAL`Uc z8U0sl1AJ`puO#F5ZoYRY$!eRvtALrj!>CM889GMN$ldG8E}Q{JqaibKcN-cZKZ!-+ z!=9Ps{*2b$hEYAE<8Y5X+=xmYYZB{t6idfBg!Yxnz49d;Ep5ASU`xyW3wt5tT5Ru; z>Gjk1qD*HrS<{12*JlpS#`H*8L1}nxMyH*;7|tcV)!pI6rkV-}%plA^c;WltET+NSuBBf2QTuk`sC`)1 zzV0v&v(Ffc;pJXG{anQOh*AUTj6NDlnztZQw zzw+*H>)`*oYQp#{{iQy~tgR*gz1lS_{68E`HMx>4Xmg*StMq?*OL8;+2gvOPZVSIx z{QVnXkEU8&XWOsrnbmzYUin$$=GFMwzNh?FyMKxiC~Mz$EQ`BMMVv>aJz^#{*bjWq zs~H2inY~BttYO@>x9nAlb618x{{JmYHo*5gT|NCJjGne0tdgu_m1MN7S6;_@8FyJt zsJo2T{cn=r$?I5_{qI-T){)x9a%n&Ib9vstmFL9Ugl`iG~zpTG52_a|Lm*f zdOpFPh`+_De)X1XcFwk6*)gm8YP@pcuhWPt*%f_H`AuK2#ypkQ9p%46?*6vau~wtv z0-lYe2!4*>a!i!}(9?4E6F2e>K%JxcEdL$%PG7J5l|DZ^@8WtGcCsrN4T^Ze>w;l5(*o&J`7^{uzuqJKo@%8n6ztz&dA z#$BLwT$J2Xe$#%v|In5v;y`_fBf0ZMvX+amnO{FXR(X9K<` zh~UN@&Rzek4X*!AU$6X~K0o)ark>AXW*DV1cMJ0o`z_zXU2Qf@m2&WNix z_4Ii>U_)t5`yB*wqrSR*&^3}YMy_+Ver3v{M)J(pcYzAzPA*YNIX8qx8BS>Syl#UZ)&$@9(YSSyof+T=6ric28)* z*L|h*Y@zn}8gc!4cZ6Q=@2NW$)|#)knYDIh%P)2MEMs0M?{_cAvTsN39GQ)Ci_I2} zt^Vqq>pZmB9VxRr2D+B;K1|<F=u^bF=Xr~E*_ z>cw~_=+(ZFvcKb^ZsarT?9LYT8(6yEs{iPlxqIE&;r+Pp=(&LMjp1h7 zA~-c_D{Wvts;6a~`V2hGv7dL4Y0>r7WZG zUCvCX>cRfx{@2b5$GEHOdndIA`hT3C*0|i^^z^G8DEEx*k?qClm2a`-Fr}q2Dl+@- zSD!1OSI>0i0{31$ll48MpPA5Gvc0Dbd!C+mun$Sk;~srIvg#)=!F`Pf+Gb>fX3r}~fbjIO(}@RLdRb=~uyjK!V(GyU|tH`l#r1mE#m zbtpfnqjjvyar{UgvER}j0jLv&;dgWW}_4C;8Tc~TAop(RCbxscf zV!PUhe)@!dO;Kl)pSi%GEyP}x>v^lbp}gY`qJHV#5Byy*fDNA1t{r9FkFekFz;ujV zF}Paay7pj??+tGASFC%STj~*O(Q$fWH#1goTu*CV?}(~zw2U?8`%TRj$VKh-HG3Vq zCO6yOi_=LuI!KMqtDEv^tS5xN#HZzdGAsC#Dw2P?TaiQ2E=s-4Bs0d8;Si2y3GCC zD(;36=Z^#R#A0Tw;<%ocI@X5jh%95R`QB5q33CvM>$)7%`=jc;IKA?%b|Rik9$USa zMcw-jf}J_auv6a)xDEPT%(GZ|LLJaE`_WjO>VBsvzguimzla~{-<=J9-}`wQaW^Kq zpMEos)_bo>P{Nt~OS{Hk^_;dgNrPED`Q0rviy z+{*T+W3bYsj z&92#Y#X$K^U$6X~KKARgH!#RW=UT*jFJSsPgSG>}ABp(1Prru*574g3w{R=b7_Bx$??sHu zm7a(`^$q0+omV;#Kb?P+5%a4tEBj99PiZAqO}BDC;(l4fskMI!z*(uuW&2!go{F>Y zEwID)m&1%xPO@u;o7BO)#3g?QglyD%VE2#Db|pJX@hZthv@sscBXpK@90d5tul)CS z(->RQIohV&`t_k3ITQLvb(hBJd85zw#P%^Yd9=H1Z{4|dh)$F>LAFZ)V|Wl$a;!z3>A08c-Y8#O>1f z+pDpFjTqxHk#%5biqx&TaMzkisw=YWHbv_0(WUpoi07Ri>{p3FkIi3E_USldA0Isf zXU~8h-}O6Kj*Hj_OW!Y0e=T4A4Cc5idHut|8tPZy6U^8Oy`{7QuQuUQv+ zY2|#E{2(s#l1#SEuMNhR`I9lla|X_WgT{R1I2+N1{TUxWE73P%_c`oSYSDo`T2th+ zA$)@`?jN4_vHnWWW-T`N%A8Q2Qt$W?d7Ou(xrZUU{4br!z#s9aWsJ}B-5z_u7)jt_ z3rc};p97ql%2a*G?%z=NOe*d(*vfZ<`{p01oOS8IP zZT!DI>}z>7f6|`ZQSfcmBuCC@8|iQVx)if)cwXC;45*v#a8#R zWz0&Mr|sE|zZ>sv?q1EFJA1P~c2Ckfz&pGHNWS0m=bd7NzjazmSR3DMzj0rm_U~zX zcH{5HyPMxvv**s|A=U6gF=(R(NBenK8U193T9{VM+0`#eSALXW4bxmd-2^~deez8&S=_*Zy8taHa**dRmKo$Gf0 zw4YpC%}2#V`RY8v-DCv^vBshMDxrVJ{IBq@rW4<%-uca#tU3dzzcoKj!J0oK?N@8S zZ30h5Fs{ZN4$@G+(%0M9>i_EJ&jz={V~<$f#lN&ZdSiSg-{QB*?4E}!+gJ3duPCp; zP@OeAzxUx>(s8TGHG3lPT=!kQ#C;z#%SYFDSI2%85ew?@dA`H{PImy^`*GjXpRe+J z->=}fGybJ`>-!dzJw=_vc$cRMeCIkxEd05UcVgN;o0qt!>#5{B?48Bsc=)IZ{*&Lx zef=vxs3SU8dr*$nulnGlC*>aIqLfs}Y}xfI2ci2gfoKl8{RX!*{*H~hr;qcGq?t4DvRi^ZNIeP6-d17czyd8V6&NFO)f86JgyT6cE`@eD- zXF8LAuLa*dt?<<`^!y{9^AdByzM0(hIyPc}7(ovA0`g)8Q^z_!>e`R8%bZRBlJPOE zb-n*VFYi7a@Ang~OZKnGVTYy_7}V*p-5r0};mJAZcT~vJ{uQ~~vjXEv=WhHG-XV=B zU)dYoC(yr(k@{V?bFH-JyG%46?`$gF(W7F5{Y=wwR!X|ju4%_USh8bxoBE9M3Vg@# zdk8R{1HXc7@#p*K^ZhPf@IzCJ?~uRK+uHB`m&U1mM<8|y3vHfiauMzB|L*vg{4LqA zGbTH+N^`gy-|_TJh}vgLe%9LDo|@c9yX$V@T8qqxEgUmq6UWZxhk@7LEBkX0#?4~C z;&_~Y@D;(K_ns&YeP+XKtF&b@a(H$kzYU6G^wd*kOcl-X|-2cQiKXW0g zv5P9Z4W*y$_n%XbT9449$$!=r`@paB13CO`eDrgG3zb(vG-Uot+XweGs%W9!&e za_~>nDjeu_|4Z@rJ2GsGv`Kxf>28sUvS}w)$>!boH9Y4=>26rEf3~e=&#YdI_f*mu zB~#K}YTJ#cHt5fK!j9woXg|wn*YsU}{$G7Undcw4?$1W(XFMWv==G%gu+I@>qt+ty zXu@|PJOgpodklV^ZIQk^K5XF}00-q#in77+;lJL25qtQI`B-uPDfw|ieM%*ns5bW> zz`C~KcPT~TLyxDD?iQKSxRJJcv@cMf1q6gKqK&Ny-V zPw@!GF8T2X?4wYUiEM*UR|)IgQzU+i?iQISn|5NAY~GE3h3DMBouFiMWZRWJvp6lf zqhwlb-HqpV;kl+Y;jXazJ7TvtvJPMT{=-;c-}AE(v5LfpE>DiB{dgXa#)rO^GfwTq7ExKD|qT;d>t7P+T{42aC-T_?M zQ;JtlTZ`@}nO3`Yf7qt-c$tW(V5w-QQsbp|0NvUX9Pb`1?V|G-LWC2X@?npY-q5uxYUk&Yy#L zr};lB6Yw2>-s+v^HGN&bhh>a2#>s&>4&di|@T^(73mj)V-udTq|6Gi(IEonS&)s4! z^6Xz1@2k1UzKnZvAUTj6NDd?ik^{+s3;!t``r3luBio`cWxhYZM&_72 zV?LrI$0WCs17jS}-vRx^-+kx0N4|Rw;V%>7up56j9(`@W?U8NKmondEraNQw)B8Kmdzcc2Hbqi*XY>Ph1P%m?|Iblj`=Rh9v^_Ucc97>=qu^CYs2@enrgNv7Uc2sA$Pi4 z`dhH6$8BJHM6PzUlp`>&bf^tia;y5@9e-6^OL`gWQlGc=$okl;I`uOD$wDC?-D|G! z(WiT&!~XDwvwo*H~EjmElV9OtD)wnv6~HP^GQbVfz3LEr0OgJS!$5^e19uT_@1nPcyZ^0Q`x?ytag zZlV6`{NS9zzCXLy*X+>t6XsLWz7^$9U}vR-(IQhCch}};kk7aC6LWBM>c!~p_)}GI=bl>&;I`uN4T#|2*DUFM0!+dK(Od|Bwbokw{ zCbzO({auMu)2;Zc_dCpIErIh`i{w3WzO$;?-rG*>mT^6@E&3=!z06A-_c)bgsIMn) z(d#m>vj?M9mi{xx+_#P$l_M5&a&1&!#5mf*JVNJ{4&pE`$+C}mNoKT7?_fOps0(#X zY@f~bUi<3=P<^}`pdHE2c($X@?~AIZr>uS=9)9jc;kZp$W15`*sB7~1aea|>j{)|f zNc|;Uis|!Sl3&rL@m`_-PUj&8ARc$}GyMY9Rh+@pu>{q&TDeEIrlZtOz07?LVvIir z`JPqM+tQ|c8Swr23p#ucfLx32UK!}sRI;U4=bgO!4}9D)@mzX0c2z%Y(6kDNdKC+0 zwrk!Zqw+mv?CVU&SV+jxwV;?;XTv9_hE+=5hFOf~pMa znlw%-7hU%ELOaf4U|!utqkXLD(|FfpR<`?Hbmd;CzV?)({3m9Mz8={YeUzbI=4|(z z{mi|8q)uJTYdYA^ye2o(PTkCR>@~W_6PG#m0-Q}d?9jLopSkv}C=-Wy34?viOERNv zy4NG-sz>)@%$4@dmiaCbKJodQw%}d}{lw=UsC@R8^@sO^pUy8!EIbwrwzzg;#}!2-9@kDNBiI-c*SR4?6p{n%Dc1rDMh}6 zqT&|&dt_VmQHFY%v)yy{Gxz?HI(0Fx>0m$en%qn~bu*vQ)iV}+)BT3{njdFn*F8XS zQSR|&M79O5MP>w>V>JHU3;aB!Y*b!4%YS}2iX1q#I>e&yBf#^0_c+_4{H^KHIKZ!3 z{CNke>4|6uwsHYw+7qF_rUQO!+O^h8_NX1D{vB<;_F&TrT;97&y1_TSqoW-CP8fb6 zmGHgoZ^<@UAA41&UgkAf_A{@^^|VtL^V(SUGq1_bv{N_p8C@e|u@5TWXb1DB_M#DA zddAQ{=B2UhV_uS(Y2!Hy{k-2}Z(zc_%;>L;rGCsUWPW`#@NDPVh<5br*;Lax+OGb7 znDINi+9OA?e4P44Jhg}Z`?%=3-hXzjH~8Rbm%pX>sV$}c9c{`7+Oq?9H%5;*M>cwdi-mZ-GR|+3+|aXhYmAp$G%{YOU^xw!yO);g*@r_ zh_Z5wG1l1gJdVIp9eUqW8&rnAYk%~81Tik{xxhxd+Owkk6F?t{dyDQ3ypyfKrcT9! zDXZq3c%EZ^bq;p;>^7jTsnox^4Sq8r9*E0o%%}9z&ldb1*%p12ptz2yfxKXR;B zj-Sb0FY2!EFlCH6xGpg_}ku#O{ga};fz?^IH`s(-LdjEhO(eb69ce(Q6IPJKTU(v7g zutNWxPV)W9dAPGNs-LlL(bpr}qK`7vtGS-a)-N^XES20OV(V)$xAU0UrAOP7t-`6TKa-YM$KU52>rw66SqASl?ZhV5 zE8%k=pl#nRXRKTN>XB{HM;YpE&7;?&?=vlS(DumOaU*rtbR7GWTvP0 zJ*j4YRJ+;|rL#xRyW{u7YF3u9Zqd^t+oF#$)XN;}t(I0jf7Z?%*ikwkXnSPtK1b@l z(skv#+VtbBT97e)9Z9zI*=R6Kv1~8&>%0I_Y-}5A8^i=b?Z1hBYb1C2bo!6^y$-e_(Yfi$&O_e;FgCm5K|JJ7U;-EZzvFj5yW*`lh_@!~dzG@hV91N?aed=HJYpWnYD&pG-2G06G<{&Sq`IOjMykQ^v+0RQK(l-~9K zB9>zGo!fH$b6@z*{7&DJ-^qb%4&ZkVYeGF^_C7Jl`G23e&UKx0og7FGBnOfM$$`H) zfbYHVvk?3)1b1P4|AjX6t%_6a-OCC2J3aBcFjx87qL=>%nErDP@?GRQ4q{$Bwaitd z%+vT-gWw-I*WAi|@6N6j{n$%Of8UFHi-n=7 zI&0?>`+t*T6`@&wef$&ts|~={Gr!{YvNid%{~C*@%l^05buM=Ai%-X5H@?Oi<#)oz z`HM5pQ|YX3jZ2Noz(Jqt`6MV#@C#&P%oRE0*Ew-5&4vKaWGLJ{ylG_WznM zE$y@Z`uHdOrwy%hew=~fnCM*nN16IL7w`1^uYU)F{xioO$=GBb9}C8r`R*7Km-$Y7 zJ`>_>#-6~tz|7g_XS(h+&Sl~u-{E)dZo=4mJ`;x>{@h_OzV25<{SN!C|B3y7#_v0S zdi$U7A2#An*qV-0u-C6v`KSDEwQr}~VH3i4u(-Qp|J-TIyJ1=Ax5xS^d_Si#?^kDa zD=+lS;TZa;=X?Yf^|$8gGi|!dxfWY7UPW%i*SlC~|E!-+?Eh+iPZ_bC_1DKg;XiEP zouB?=O@ib4ZVqLv&z0PN%734SSE%crd4~PZTp&g|FRx(hce4TU*0j<;#px-pv?*G* z`bFKPHraKrSVVrk2%-$B)6aNzcdf8(57>O@+;W%E;j6py<@f3ztUW&Pqf?HbnWllgVYX` zX`kk$vs3%OLK)9(ntq*?n%(I0RFjQtR}P>|-L&P2?|=236zo{Z%_scFeOHslo$=q5 zKjHr_-&$~V9%|(lJt_0g-fE9+Po_Kbo$-UqN4QiipXp?f-uEU&ZXJ`42wzCOwlQ{B<3# zHvewl>Uzt3thV9Z^tZ&kB(pM3j<*tPhi-q4qJMmz(&tT_xjSr941Whe`!vV%^Un7Y zuuspQ*}YeNL0SDTm0kX>UeeLq_DcJ|-##|gUHegX zeMdbO>gMXoShx`@v3BXk9YEhfqs-?iJ%3leU#ALUx}JAEzvud@GZ?BV~e_s&oF@AKO-Ppf2}@PCyrGkW#jkNJ6GPn@y;tB-wp zO+1aibN+PAAE)Cxu^kJ~c)s`hT%eBoijR$~>wACTAx5+Mp-0o5K9y}L-|1`VS1zc} z#NTla|E$bT{}oI9t(A|nW7faB@oLjk^M7aKj((qm9hiyn55J#||I_$8 zxuEAQ-?3i3E1+#HGL#+3aR%cosJ$0hc^2vY|2SH-fJ=OnHp_+ z{;?lzeD8iGv*KMDbm~0?HqqYbSRGIITQDG z-H-4*rq5(t3oSA&KKMQ3?(RTanYUo{%HW-Yrl|ec?=Qfq+2%IDo|`7zr6g#V+qt{SI%8`j;`|I=M%!@KK6+%@fvhhn3=8-Ewx zFL9J-ub#=YgJS4ITZ;_GUgZZBf8;nLYx24`aac`uwq5;$jkEeN-k&QN%aU%zU+t^n zYm8B5A8p_rk?m1=&%2Q*%#xm`{MU7eSfh?}o@)}e;-0`eWXbl3wx|4$usur0amHDb zu7fCy)br2YQi_GfALWwF%C@KRSNcZX`rM)CuKG?{Z}U3jG;!Qrjy=v3Y~l9|91l4^ z6YrjrICdo0*ucJsJpg;TC-?v?+6Wv!3ps`|EAuDz|AP*G>Gw zt9s|hX#Z3GyS?tP_phu!gVgqGY_UhdPd!zP^mR0AKk0X7fHgVkU{eQ$q z9YedL^4N>e@Y*oN%Xk{eXv_)aDMA|+mz|?4?0@U#pA<<9{r=T zdN+x}#k<~L=jSTj_1DIZ`pI#+|Dnuw;yG8?KblkTXg-Qt8@Jp4njKhkc>knp0-V6w z(s`+kA8l9vPpE&T==rbN>A*F)=yv$03HxL;MopjMqD;A3JNtX`7F|&?J$AWliw!)q7uyeUUQQYy7)@_|Bg< zK8xLH*1p~Qf474+VAfwBzuSMuf4cr^{$sjv?^zWW>}R;+Q$O|?O-To%t zevW0#Gv>*GG6(ox3}^Go82R(Q?)$5;-7nlVfQh8<9ct}9{yWwGj>13x?)L2;;vfe7CaB1IoModm4YY zzlpb>V;S>|d2--c4&d1u_Y6LFW8cSli|++?&rR*lgZ7<2hq&AC65i?Zr&N+z+4c$i ztgOUJ-5KBHKyn~CkQ_)3BnOfM$${iRav(X797ql%2a*HHf#g7PAUTj6NDd?ik^{+s zN54wDeD> zG;52F=kNOlHh=#Hawhbve3s+m;q%MbGhcoF?Bal~C;CRtUGa*)hn-`PL)X=qp1!B! zueLtZ!-_70#bs9B?kTaE!Kb4Mg9EH2x@)tE=#+-*d(W zF;P2QZdINBGGB$Gdhu+J>$?9D1Njqs(5x?CalFP~W6rsVKJQ8~QX7c7 ziUWS0>s{Av+1Vc@rMt`hm-p5Z`QY-@r*I^p0T5{N5$t_`zTIr9DQX@ zIo6r8J@feW_iiz*afJt}f8Vnh`zOzzT^!K!mVTG+ z*tm;(()dJiN9|Gl#NKiLf-g)_evRsZ9V_lxC3|W<*V;=uBHC(rwe|?i)UoC)d-b^1 zIK}qAJ_>ja;NHYGbiKNNXlo-~TD8~vGbQmx^QgV@sq?4T@7B5Ok<;fL*aNORHzCubvsd=1 z_`99(Uz7KL$GZB9GJUMIvp*`Y-FeW?eK!j0N{_Dt^?x=0uk6ace>fQx3(l?U({??p zcphrMkL|7dT~ptEK^N+H2E!Tm*ZEof{I7ekJ_q*tbtUgUV_nfN&aeCK?RRw_-&3b<=CANQ(?Mg-Jo?Uy`-~=FmExr~P@eZM$m_if{SohmU+w(a zdG?oL%D5xf*q7!jqV3hb%R{f4=*;8#miu zdiQcjEN1mzjen*1U)h;`|E!Jg7K;-9x&EV{g{XHV?}__}{?Rc#cBSm!@APZ2#yeNM z?~Qo3-5cvejEa2sD{6liuk3Q!t2*vcSGrpIUgiAppF!Gn_9I5%nx|d-dzJXNa3y8t z*V`+`(AOT<0`|b@ceB(zlJ~@JME~fR9=lTZ?=^&X;^5a+I?m2r`!ME3_hQ%;b@zoX zO;;RHxt8*ku9iOa8D)+k_KxR&-+xx@JM^oT(_iK_x#;#+h<~(Csqde4^i^VkHK^|a zP>w$P5sR7B6U!N#-myJ)rR?Xmf$w{jcOLtlXMyg;up`g^n4dAY8Z0HK6_#uR_9N~f3@1OC0Q@4u|$UBK$OI0$y;E8n-{4uI$PtAzUpp7YhFl6=%Vk*Cg|l22D{t2yA< ztMRB`+|S$ieKq`KTd!Bdl1Iw z?D~@+7x_Nqsq^QLLyd*i^Y3P?#-skH;!pg{|Gh6|Ofn|Pf#kqDa3Ig0F-$iu!OK zXhIBD+o}6Luo>%Gd!#+O$LjuCYmdZ+F6?u<_riZq5r6a3=T$LU?f^Xdkw>4&hKLIf**TXhRt?l+Qe4v4aE0$vLKX z;-C5r|6867XXk@)MvmtY>Z`T0KO#Q_MCZBI9)U?6y658D0Y1+|?0b3^VK3yk-du5h zik`FhC)IR9p6Rc%P?H;NS08~x`xpmekLvFoM?B=p#a=x#@`oC6mX((?dauTMyl3y5 zS6JG2n6ITOWOU4mvg5A6NS*8FF(SrTZ%oHoh|u{}bm(&jVz6T$V62hr8B=SIjHP0z z-delL%$9M+GcnFM=aFy@>Yj{qauiR`Sm>mlv-l^mO>@0B%-lazrO0Dj zx>MKJiKp(1$D8rM_kdl`9$b6A&)3>#))RG(&*{>*-Ztt)&aryF z`d*J`GTOF!A3oH$vkY7GXVG9sWGv`^EvGro#hQF%yS{IM9X>CSSS4Nb9rpkob0-m{k?~HcuAnbo+ZC<>OBKd`@;^@5FLHTkAV*Osu_U@F67d=c0F+3*G0xyU(@z z9?mu+aNnw>)n}n%>w6!Kh1)iI2hevA(227S_@y%tcQMBQJFiK9_rH^O8s9VA zpA!4NTmH$(j>>n71N_nFol+?9T=E_LR-bBTfy%r?`S>6J^6%j(-CSYKBjI`EPWG$z|8{WjpOrrI zyvKS3j^E2yVBAPTogX_@Z90^J=>A94>ss|G-H#FMOpD!hX1^ixcpHW!?9mAcR!za20?5! zedlL@5>M23luI(-vCZ$~9tYizzN7z#IQ+!A`;IaF3O>oSe_HFc_DG-nY~?#RtVQDJ zcfycodsKdiqk6tmzjXh;pP*gu$|E-Uxn5gu{w^A}VC;9@i{PIo&cV*y=LYYFcH%#c zrSV7kX?qfX{T%3icD(tVEB~<8+JQY+6ZYwqcu(ur^Yw@LT5FHC7o7L!EsejHqvt~B`bxLH zqrkbVKPv#+;X`j+di>THusn*}Yv*ox`p0}XK6s$1b|>6z*E`_pdc+*O+s|FN|5tlb zBp-G?>qXkUN|&#H%*iUOSJ12es;{;76*fEXb^m4gNANr-=kMO%`!gYJLas6EjScP* zzf{>p8S|lYf^sk3SCH4c7Q(UHX1$A|yc_?W@s!_~`;qr*Upap6|IFUf6NdxA{z&iq z?2nlJVjw>9k!QP}*gq|+`>noHuC=eS7rawUgdcURiD*vh^E)tFe8L?-?ZdN4lwDZo z(C25*akk<4Q#pux5Mt6|^H-FC&zg4npzpk3!@He7J7ZnK^1U}|eU-3YvCaM0b-&79 z#F*(g3#)KaZ^rhH131@^aK_!qX8-q$k)Odk_CRvU?_X@sd>_{^-$?oHWnavb-x=#y z-~jKx`X1sH>`EKZ`Mv+XIoI`t_h3kP7SQ%AXFQSv$${j+_vQef z|9&3==Rf$~W%ZovJ5b;r8!%V<^wsoZp85Wz^*gz*=40Bsel2H=Gsek*ugw9z2f|sr z<2!i8%lFRDa0k!(n1>zno%_QxbDVL{xF-ja19u$Ick!$L57>cAhNNBJH{8V_`*WQn z2a*HHf#kruaR5L6!GveRRsQ3dQxksnU=>#C&DbUfk^{+su*KuQ)kBY)i{9lcbp$hyUrl|-(T!4wS>K3*YAh-zeR$Wteh*4 zc_{{~&H(s@J?<{8#IMB`cMnagekTlg-{9%S2XWe5pQwLU0(sen5t7F}NaGo)C z9;`Tn4+{V=VP9$et=b1P9$7AP9I;<9|4+pmzC6t*aNHBtBiA2tUxUZl78x_w&-F(P zw=o(Ydo6Tcr4`RS@Xv95e|6tsBgRF29N%LP98Xc$H9c4pwNx83)9!dX_n6ZB^6aNi zhz0J)$H#~5J91r{C2mC6@Cyz~D)}$nVcdu9xbtf|&Wiekb+2jH{a0;x=Q7sEkMpC? zhu8(Pg9hgzW*T>CEbdRa!F>S&G8+F^%31IV{qPMPdPq- zN*tgK%v=Ut-#fUxzPUEvSUAe|D`{^ z?rQrY<)ibb@Nwt#Innt?Im%bp+ggvp_qDJ1h{4Y1kSm{jAC6pu9)r?*_FeZ6tTABW zPNeC_S-FbO%06EUux%wCbt4YopU)4@Xv#$9n0Lj3pFR&OeD^!Y30qCkXLAV~T+=yU zdH1-QKiu<}BG-Ef)8`rM5OUyz#sc<~_J@+r);8$Wd^&REo{6xpVFFWqm%Pc}JYP9JXotbyn`i%=Y`7DE_KAfKR&idEU7Hux-{qA7A3P`t0S% z=V0)zHLZ%h#{+dgk9BR7$!*dFSn zm2n5fGsr664X(MWaf&R%SG{+;L5S7PeV{Zqk@!E%LGJq=Q{RtZm&-)fo%>PuogN#V z2iX61*x_@6DS|Dlu(7uF><1R(r0r+(l6^q$ddG>OcMP02J`XsjXy0rOyq>h;{44pO zagX%3gvGYfyC%j4aiUywez(?vtqHM-w&7j%XHR$$6=kd`*Baa?_{yIG;u!e#*Oxa*UACK*77R;L9Zs* zLSMWOa)eC7RDQVwK`IFMK;``t3JCNhK zJu|-6#{RM(D98N#)xMg(-gfud%=uS!^|ME>{a;!BU%@>au;*ajbuakJK91Oq{T?y! z{r7D8okn!Fj`1}I8&;hCu*Xx$M#MrB>?z4bwPBCZv}?V?PoHm`k5PV&=<&PIuRwba z4f0ubj`=*S*!x>!Vy1@8iR&%hYh9+*<`FrM`RYB`@k(n={g33I#s}PMO{FAbzT(Ku;`gvALa#3ym zzQxa_C>+&OI{R1qsrXlAjXla&vaNkR`>o?+eYE04$oc*A2*h{aO7^zMl*Wy;>HTv@ zoPnXKw9jil$|HWYjKSWgYah1#1fZnV&mJvyen%P1J7TT;ld%6T9_PQ&d$D7*)+6Tt zKEbzILQH;~pVHchv;(@F@3@adW2nAU{imdTEITJwKa*hHYg&2#fsduLzxHzwj7da} zxjjBU@VBNDeN0jNpYx3RTXKx8+1lGq|2gNS@raYA$TdM+>UVsV?ckxW3!Q^V4yfLqa?~98*`_ui28cxzR*N3D zXZ4-qP>0X5@mNpN8XLx4(A{0E7ycR zZ^CEC_x{ox&2U}EI@aoYFR(qSJt%{3nqZ^L%+!xlA3mI8*LBAam(P0K{P_DA?~k+iK7Qx(7O;KKz2hMEBe!|9?y*OFm3L3X zpT6KbE=|W-VP9nK=L_yca?#8Z9x<{V~E8-{Y=qSo!SfzW6+#?lKW|a9;P7EB}v0 zHnh$`^x3EJ^Lxlj-Yag;8dzbI`(2y==yj(t(6ZaJ3zs%HzCMpp=E)rPVZA(QLnJnQ zflrY-M|Jt!@8VwR`|mR(f093!j{4U!&YwqC&JE(*n^xF!cm5#$JMLaOKZgZoCH@`% zV9Jm4qxMCXf&U92m9!)N&ij?|_SpHpQwqbX`yXt%TZg;$!ICX2*1N}F>mG}haaY_d zuiIZ*W9xIjn|t8eFIoIJmv-|{@nOo!_c5){of48|_F%3L1^TE*e%Id0L&$k-R?Y+P zp#R7D(Yp}1fHkoin{ffx6@MrHJ>IlwSB^UnVy)|MXZ*o`jXmN4dse=4DaBU(KjF7= zkG44eZvSaV=KJphKKHx!y`1a)bDc5Im?sC410@b%-$%k7sMMcr8JFZhav(X797qm) zKMwG_AiV#``OO$42a*HHf#g7P;CpibKl8!wf$&{O&UeNjIglJk4kQPX1K*zm`1u!n z2fX`du992dpIbS{ImgL?YY)w4)z#JLZ$W z2kV6UlvZGW0=TH)cXHu(a<2ZH9Qd0*h_}XobAZ2-5*>q6 ziwme~SF{b7U;O@8=+(56dy0edT}*rB@ATFBcj46VwVl6{pEhAlX#Y%^I+@pWVecuW zs6D}T*X)RBzxun=SNkh|M^Y)x%!li{!iVpkBH}?ET>tvFuzgZ0VvqX`o37Th%a7u^tv%~M>g?g)nSjrTE6yMA-1ipL(T;wN z|BB~9U|l7|-(xpZ2iHc^6;FF?!d>dufDsX~81+Bu{x^z`a7FEXn5$7cB5XJY<{sS>jkB+m_sW-aw6yKQX|V+|ZV&3MW3S{~Zz=w@vp;GLmi#N(apgyEU&*I4 zq`y-wwxf53E89H&w4pY}@rAyc4F@_U-K`hJDwRDBqWZQ7TS_|b+K7pKbpL|iOi^nAws`XS!QJD| zzn*^QQ7s;52PZuBV3lM!7pfOF;ZCNuV7+@RFsAqJ<~FqWkNG_SW@(oDu%!jxZC+7# zJEHg3lFdIYo~U9U1jl_%A=Yl=*)+WG(H_@%=Xb9>aeDJzIIVW+`GmN)j=Ph)^0Txz zpzTiQNdJ``Bl_;fAcmR_sg%xM{r&~EdTeyByu;Rh_nT&*UFBGI9^9=Ljw|I@=bpI! zRWHvT$HrLSCrUWlM$8hAu*V!?5MqG20KO*J0i8S#Yq3(?ma?C3um%2ULR*WjRvFbz zzplor{H))MpX&U1<6kL8SN7iZDfXTJhYFu%*m9@;u3uH&;os?+=~p{Yp3&7Z)_D!g zySay6-}h$c0Jxg&Y*$&7@8n1Ocj2_y=lkF6x>wAapFYo!o1JUL^>WP)my4*ExUYL5 z%8ql0fjFl$&FmYh$IJds!Fd3Ax3jfgiUH;v7&RTZ6TnwZEqey_VLX%GFVOGj3gwVH z=5e-BC)NUz$BO-}c_|*S(PKU{*KUhr9w(m5unzxxO_q2{`Ih`DuC?)u2jYHwd}^|H z?LGcOm&?!YgRT$$+}XUM{|P(btESeyowkCD(9t@s6gTRk9ne>jV_UC0$MxpBa9Zv1 z^JXUIidpm1_ZiGj&pxjhE#;aWEn`Py{Cj-(tLHzSQB^PZJj4NeW|Y0I2l_SnJnK6M z$Q|cL?d&OItftnz)VbI?4z|G`BtN&<{&(*`@01bu5*KxTIG3~h^mwQ~+Qqyl&R4R^ zIqGiB)xIl?TA$A&a1rmC{EBw>-+58O^!SuyTH74ob=T@WoNuwk?NENVjPI4vdpLZI zywmpB((8Axe2*SP=cWOdi_d~=% zZB=>L$}@*LM&sjt1J{%8$u2({C%w-Q4|fsu`Krt@%&%nGrN`0#Pl(&j@_wG{8{5vUNqD``_{o2exXOvCHvQ?^QWE zRwH)&It?849s7o+Xn$Jm8u450#@^A2)g$M2t-@)w=}@Q7a>V)vw)<%?f2zQ5wRJ?! z?N}Xe_@fDDj-CPTuilApE?~WAYT36+adE$4hwIk6h1)$EC%?bAza?9>O?^jM`)Xxk z!e^Dy*w*$m$8-L(U-kBs{T+kvhdw8xad(^G?@0P_4su<+b@zFc!@amF@BZtZOXale z@zTEDvg5n%T0Lt1Y43;~KPNbFm}9=4Fb}PXK8)leeyd&n9pZ=$r7>>TDx4B_sZD)G zxg;~v=6*Vk)}13Gc(pNZ$Le^iUnm2wcK+)#_s>%fKKS0*vTv1qcfVnS+HqEY|I97N zqONH)PKPQv%e{NQ4sU&T$h!{i0rUs^sHWPvrZOmVJahK5-jllx@WnD6J6NrYj$%?Pwx7A#`@lHoVK-$=bZ_0ro3~kcBY*}{-hHB z*-5=UxyPb(w!$64vYD9I|{p!-TE=AQ9`EK>B|Te5LwTaW*=liMz?Df&Xo; zwgXpF>AWoI;~4Gx#m0}kwx_8W@Kp!n=xv;uKL}- zE7=u&z5c@ne{RM6joRk;KPGgI+JJFS*m1&sN^ZZe%TK~m*%|*`aoUCBF|XBe9&6I~ zr?oLH?d~Tq(57P@8@$l|h_c(^Hbh{k4yyYah%0?Ct#Ee2&Be^E{ep-)QdhNq$}Fb6c-u z@A};LzfR?MV>tiEDT|NK#oc)A@AV(+L(|NAH`w9$E&i+hQROG>@V%vld+^se)4KLc zvFi1^SH6VV(zXi+wt&;e$LGw7>n}3q>c9J0x>s<$!#1Xpoa*f@yB)1u?8Tw{K}SAv zu6y@Y-?w89I6lf=*W+;oH?9)xrd>U`bE;LBk3%e5ap{Z7vyHj-vHXLbAGzDgy{z`` zfOH2V(1`3HMEMp}ozj5Y0;Isbe7|4Bf}XRt@&ud#?M zdmLtY)nc2^{c*;%Wt@cncd=zmO{UlHUiljCUHdK^*x|`-^D_yyxy)$Y{jBXjhZ#A0 z?{<4z?eKA&w6>Re~O@viAm>a+J$)el>0wj%cQQ^(+5R2$RM4o-W59m;j+fuGJ7 zjKh4k;M8QGgQ?^{cmnK$LXyv7!zN87{F>d-?P>?g(fUjJN^^gl*dx3M@9VKk^`KlDTRL+&t|Z^uR+>}zf_c^R8FHn)A2#%I@xY)n=^o>{{p=~7d-Rb$ zjGP6ow?&7KL7ler=Cu8HKnDNOdFsWdJp3L_STEGmo6q_`gAH3}@LRaj8V|SQn22dB zCgo=49-Qf2|HMV!>vylbV)c}F;m{_34}-W~rHC~@691!MRD>-a?*dG*X><+Ze9;8I zI2XuENqO$}`gqlKRc_Ve_R_vlT(t>0M$-sB-(UYcL1~BIxiGKX+bQohVl4Y`XQ4cG z-sRve#%V&F@5cFDs2_J@z2EN=YD-HQ{=3eRI%4OsxWk9M-r+`YNBswO%Us>rG>VVd z%*?yn<#zly^}Ecf`pDeFf28C5%N@J2X04e zEJm>rLru;j?PFPa?)Lh4&g)(7damZSv_FsHx?R8MWJf+4d&H4RWBL~xJ9E4n={@`5 zKkV0ZoE48tsqSl_bzDhT@4a8`jXL{j7h>4T1Nf|SM;*QSi2uMIneUQqBlw&H@U^6K zq|NP^y;t?x&@=b&|2RKb2fa8h-|Kg;yyLajcj2f#z8@jZo<{dv#nJMJpNAWD)@RqF z+fjfhHjS=9_rcejgL&NDULUV9zAC$(D}PG-7{x8wR{T%;M5-R2TH4(X*I%oTt`pbidc5Cb@Amrm7M~&G zdam|X^m!V^t=R`Zf1V#-|EQyV_S`3~`Z9WkQ;-BZO?MXBRP;9NDd?ik^`^7 z0X$1EMSPDzeYiVE-;0tnufds|hn$DxKyn~C@I5$ycM43$S@8EPE%S^q7>k6n|LPq| zi@uck9^A@#%y~=>BnOfMugw9xv-j`2ew=OiuAy|65JQLc@QdvYK-kQ_)3BnOfM$${iRav(X797ql%2a*HHf#g7PAUTj6NDd?i zk^{+sA*x=k2Y zlVv+(G_{Q3@B7wqSg+LClRG~CZ*j|btP@Y8HV|)g4a{<%_@29eT3>|;8}xU=xlKFj z_`l_~1lxAl;A?5szPrPhI}G==7JF}>U2kp|*0gfZ@w9%N6(2uZAN3#hM8yDmkKcEo zzm%ddHD0Ctw1i!2o3Y8`e>b=vx z={P%QF?Brlu$eRy1CRgR-qtIxetOyc#N;V+3tK$ z->3ay+vh6=J^+C2`kQh_^VSKg?E9L8XXLs%Jd(55# z&pvzmIRd(Y`(EF{uhcuw`Fj0_y}+Ylf%?zJfVOx{DHpo#JO`}EL%s25tVa1cuhni0 z_)lBHp~nKOSL&eSNbOS}nQzoY>XFXp%1qBJ>1{+pI(_) z`AW5a_A{|RU*KGJ)sNBne-P*&x+@3y+Ru)IKUWg#zW2d58qY`N_u5nP4gTZ4KMMdJ zXWxH1#Nx5n$FykM2e0ZlvY|A-V*h#kkNh0vFZt#7 zycPqS&g0m}9OoIi_SouNt-;{Km=bwCFKs&$$IiBHm+C!Qo3lD~p6V<0XV+e}<&N49 z{f@^KaaX_5-z4~~gU&PiT5W(iv*Vy=9`x0})|m1=TVMT>CGYB9*^9omBj*Tzcfe<) zGqJzoKY|25&gk_y@L%&jWIMsu*?U0kno(<2KKdU2qi5<-e%DvJ_L}#x+ogPnxzZK9 zQLgLc{ZCP(dgS(B+cv$q_oMQ(iT%1L z1EkV)j$=gS zp6#P9cxQTRY zY;Ngpjrrc9-qxJRF^>WDqn(-m-3PD1SM#0AZ(Xa;=(l)hjp_T@8F}u=?h+1;=3E)y zEa;9kTq}Y9ioQpf>v>Q8YxS`=JU*lTxcrg%n@v7@K0V_?sNG2)l z=)9=D??2?fDA|{M2*QwtV$E9rX<8a$zIRbxN>{w(EV|^RpRZN#3(< zt@cCrY`m$>9tY@$ZOSvV@B40L?e{$aTW0!NldX1aH`p+1uh;y2$NQdx_GPXTFo1m- zRr_2~DgMyudB=0qmAd5qf9(3y4&-0lbBcZ_Pso&55|bV*ee*-~I5q z;Mj2fk!!?M33IXjz?V`~9daCNzJ)&cs`k4Ldc7I1&g<>FewB~@m3`K01Nj^m9t-l# zXdPql9kH3At0YsOyP4R!`AVE?_Vvb}^L_2FzJsD%v>O5{gq-iS z06aS9O5f|P>(^(0=uz^$bG1H|_7$ExUC*i9kGAAq8S{O;LbSo z*!zq;3N^%gr4Rmo8MeR%ob$NfOSuVrAn;zrxg(khEl7>x_;EBmc3WU z+%~SsRk=FfYb^4O#{hmiA7U19{!&}~ya^pjrJAhsNBh2>s;d-h9oIhOjOtc?&GC@y z`|6J>+xyXRP+QQ4?@AH-%ysy6>70Y-aOYcbt-hnbLT62f?mOR?wK);@9RqjAA;PCe zli~Siy8&y^d4@bkor&!k|J~lJHOQYi;1_a{=702Y4`WJK^L{I4zW-1ITKs3nN_kg( zto3Ku<9JZrh`p}KS$}n2O<%3Psy*y)dq-uC_PzE)uIKsE8b!xK?S_7(t3ImiT3_{z z^rLZz=NToePtE2P_w`JCHP?;U>lnB@4kNZd3$Ly%Ft>7jHAdJ&qZDDQ`~R^Up>~z} zUKddpN_@TdAkXW1Pb_+D?X{uA=Q)4oyM|H?YQ+HYy87Oy4>+7N*^*ICn7JJ+c_ z?ALf*SLu4A5NWaQJ-jpV;QMk$?A1rFH4=`)Ztbk5@<;l<@1o_8*aBX)XQeHUft9*P zWAv>2`fdk6_jCVBzqZ4j_FsmN{niy5&-xE6D%EmkuWhJhBQy{Bc9hzU4*s;W^O9rT z)Hg3%F)R6YbkA+M`#W#C?pT*2`=iD^H{TtHD8C*_4)U53o=5Jq4_HH9QoHc12P|Np zA@BRMGRDr@ta^4a-S2mGPheiuyD8*3_`gA@5PZfx{a(abpL^%I4YP8++EZG8gaPqI zTxQn+*y4Wgx0-cP?LX6pe5F>Ll@I+EZ_5_M(y1rEdTemr(sOpq_xS9*`scT}tCK?)jQLLL6rJnKH*PKJOY& zo;ldQYaG(=|L!N8xwrkN=b0tr_uu$sOfn{kfycuD@|sfAd&Os4Ydq^K;a$M9`H=SJ znk5Dj1BrpeKraUH`IZtsr|F&hN__s^zbl{dzEWJ$m-pNcx$e2{iGkP0fY&`e3%v3( zFh0X=(d_RY=iYk#y_IX6Yn&KJ3_LOhwnh=e{|k6z+ppN>|L4KO@XFu)b6-cVuf#p) zzV4pNwav9n3_KSG{JVcz3tstq&i-A0^&98i5vA7ecsRZcP!p5PS^|jf0gk6 zwYL4|)qX$8qpj=R_N>;wTHjG#do+8F?9K7tdHQNR@O!99+upe>TH6~Epo zPQbg8Vgi4&CHil`Us;!{bKhxQuf}S|{6~xbquDbf<|#9495JAu?;_{FQf{Y@5v|AR zm482}*8W$=#5=8P#6F0Y@o4dXG<%}so$?;D_Tw1~XHWl~*xP;&?_+1J+b;SqK{xc^ z9hmL|*nsE0SvEi}&K)27kACh9dk~WqpT8jfsvG_z4)l5N{vzIwYT@JO{-be6ANN+A z$&UUe*>1*{ZBhQZ9LJolJN#E7PF=>CYn6*WWR$Q7Z0LKCGrD@_zy_tBIgvc78~sSx zC0R%MfPbf%>)^UdHlMxcdkp&oI%$0yU;!E$dkG&Xe1LOh6NA$5X%+L*)t@vZi|4#W9Y>V#wUG#ql zYcl(N1LAu`Gu8lp0e3Y5=4Qp;@sD*q!s6AO+rn_ko)&-f*lPVp`g~tvAIz);NA_He zH*8nJzHjY2?zdKcz}Q*4O7`GcvsD9T;J@V`<29rHosC=MJjXcwEw$10_bAtuY``9g z^dCO;(u{WyJ@NPbzTOltNx-`Q)dr&160H=R)FV;`Nd>5M(md8jx4!FBMS z@$*sVINso&*4I*PjP#{+?!x-g2DFaRE9XtO-Tj9y{j9_N-}Z5rapk(C|DPWn*i$uZ zlIMzU%q{J|R_wulRp-(CZP%ehdyeLv8FyWZf9S2nKk6JeWzJ5aeJb0*1I;V z^_TR)XU{pn!Py$u>pS>L_KeIw;@uob`?X`f!19X+XCSAucr4ii*~p8G_e}hI{)2Aa zd)ViWh1GlFXicw-qrPDcnCBRCmAMc9A|1Qh_vb1o@-w!-d&PQO)yw(5ww~7!4-o9! zettMNqILbHedIi_$76KH7WxKxB-ih;2TsoD8ks{|*pAE{;Vt=JifbwUrF}A@o4k&H z=qlO3SgM!M_2wVK@ zTU*;1v9H;We5X{(Pqn$D_x;^V4SOCZLjI8q*I)D9>lEf4$?h3Py;p*s(mdrs zzr+)D4;WMe4x?ndoJ|$&{nhbz{MXK3&Ih~Qmx$|CdTO?=*6;cZ4u3DBpTY0)-}hGO zZ0#}W;n_~&(e0_7wXiRh&g%2HLyi*caUNbPANsui%q?(TdbV_5^&0qy^4aSe^ps@J zI{*3ECepW(AAZmE!%yeI^@hL*eeC@b-{?INIn*81Gr|wwlxk;^5t%jK-uTb5$?;!X zSLd4*6W3F-rxwqv_gCw8eTqBnuZn})6Ro#LeiTm+7F<{D{hRaQx<~#IkFGKLwfyV# z2fRnJAAKCP-}4`yKY+P^_8-(je?J5MNWV&FkCOaZ=fB;ZUsTdP^WHDz`$bI`&frQ| zpBnGTeU;hUuRWuV=xyaT(0yC9ObjhaeJcUzZu|5IC2|$c+T3{V-Mof%Lm?(9}7oyF8ou1JtKM^ zk=NI`w1&P9FelO%uWN{LNj}bnN>T6WRVMl+-81j?=tuo?ih3XE=f9c0_R4mfYG?9Z zc`ZJVYl*iM|0tUr|24V2d?ouw?zx^Qob}qUTEFYVHGTFm-tYD04Bu>>J$uV-C}Glh z&c>$49>lSiZ#3pT`yVnlV~l$LFluikzqwSbeZJ07b(em)4Y>Am2(aZ;!X#ymwEkS@ za+&+L-2nVVue;;geTOe@BVsY)V~f|%fHR-9TXt{^@mE58I5wm8_?Mn_JpPe3_4?Y& zcQr<;2mPz^M(3~A-_rMCgSZ~`XO!PmhU)9xTWUiM>&k=vsGs2PwWpWwj18MPQmSvr z$xg88jJ`*j<31_Akq15Rf&c6|ujDsttJ?w0u@0g29IbYi z$mj3B_o47-Kh-mk&wU%cUZtmIm+QxQv&I{7zek_vhMDJI zw+Gh|eo{t{{3sskY_&bQFu#|trK>eodd{uof!X=5WoPsluJk;50d+fpdUcQ#Dqp?!0 zvv7UA|2&fOY~y(T1;(}hZTmI%g2#aOBmDHd%J;6&q3eNuq~4P4jDy;QK4OFOL1|9p zy^_y3_dh~XmKaD3BnHl5 zU@zrg?>n}=<+~P-CEk4~mA)VBbMkt8Jv`31&NyZa5(9~W#6V(T1_rdQqp!6c@1Fg8 zN8p+LPI`u)k1CU~EPW3t-?!$Te^lJ2U5U-a!1H5ZLqQ*)d?t-sbAR8j%Ye_9bAM$F z5(9~W#6V(T76wYsomz*qkM97@vf~})BAz9}cdzoK+$RRsV*u~{xBW-I z_lw%Z@BXg%{~zzR?*2V%#6G`gy&n7ThP(7PF_sue3?v2;1BrpeKw=;Ma5X6Q(niQU9N83X_9`)}KS_;u7v3{Re zGrw~WvYqui3Mn7$N}Oq)Q5*2SW2GIBpbP%@`aQz?2)?Ba&x2=RODWgxdDbr1>iO3S z=WQjt2bg^ZSABP22+tf&ci3^4PQLr^d7nSRdzU|{_c`;B@5621l)07}gT%l(4EW!F z?0Fx2b$ztF43zcO<>`_;*l===EhSy^tW_)!SlQXhw zb6jUlM=xJZPw75%DV2D54|`GxnBdrGt8z+nbq|2od7{o|n;NqBYZ&9R2HAl}x9RLP zWwNcwai75-^*rp@qAjJiW?%IE&6G#WFUeDtrSaMKe2ur=pxHVfNj~D=Th~T-TRwWs zk$XJ+F+i@ks>|oQZs;k|$9~i2MqWdHi)QG@ znNO*PFOSic`pcNL2*^tbjdwrS?D<$?@d-5qz|l?Z(MJZOd-XDYdQ(a-GlP zURxiZ*Lw|}N;O}cFY>!#N4Qt}di}b}r#g`vugdG0uR449qj@~vMy_$Rtl3jSj{RQUSN|{MCJy^v@-qooH6A@RTltUrt@tAzO5i<`H#+YA zmhkO9_dX-_+H!<@jX|%>D}4Sw;ws*HZCUN7+vQmBz2W>3*U+JQfd$~amFpsMkK4ZO zI)Uq!Ud~}HjEIl=zN`Nt_|NAX=zv{Hm_u8xww~9ai+LC}&{x%ueuVF8`{oMvYqdpr zBm3^3?seos&rRTu)L)Y2p(yc0-E;qH_}|Q^i1mjIrP9839@uf!clAZ<9q?Wv)u(g8 ztMiqwx9>W!9+(TcN|AeBZSyl&X$>|tWbc=FRAxlq{f7z2ixIMqWcWKV=HjDySI6Na z>8h+V^F0^L_S?_5^quXtcUX(y4{`zSfzJ3>o5MZGy;tMI{Sn@l9FBR+OZ(j8)MF>* zAGKe>lz&Qj-OnFjKax8-E+%|+p|e(tMrF77U9amzJYdVV{~+%v9$RwHj(OgL-m|if z<`K)giZ6nnwK6pzw##pQXp;QYTs;TXC)WSJ>eCMy?~{ z!9C#EFX}~IqiY=$U(!$IoA| z1O6g5wY9javo#;}NJ;BcYu=eLKWmigFXZ|;A*${{w#I+kuhoxPu~0l~d|7kYavf+B z>{E)usK-}z%&h(J%j-LQq`zo!trX?6>hQjw`LG_V_To`I+}6lzjdP^jURkOi{oZ+J z`CQ+~^;w;zdBj`Kv&9H+NtfOm!J5ZL<(%zn9)$eb-u^Js^aWN#50an;C!_eN|>{e($>Wo)c<%TK64;VzT;N>S9Y)ODf2tdOB_CUH?Xk!8 zOug`T+kbR@5pTBxd`gk^hxq@qD>(9Xg!f1m#x>`_znWjv3m#IB{39O6I`ow0@XSNq z(R;#k-)!8ukI?V2ps#FKox92p9xFvz-F#JeBuxMQR02~IdToCLtD>>unG5+XGY&+4=f-D z&Gy%Q*;W1}A6s?3{k7n`gILVc-O3}tKE|1&ke{(8JI{;XRUtarmQD ziwAOz(zajp$Uovyndq1Ju?|ipzAN`OQxJW==(P=T_UBPG4eQk_>kOagAz=QDoZdO= z8~U|*n=wY_MaWXZHTN0s^BKKn-{^g<|Hv=8zo<)nb{l8pMCLjAjJB2!M*ThFhd)Z# z^X@a_awO~Qxa)&Gv-cZqMebKx6?f`qt2Xf7$`)(jSU_x6+OS#|_g&AqVuZKH56a`Z z*KoIy;iru{6PwuLI%}>3KWy&tZG^|4y;nW=v}{C8@Vx;4TXU|C&8~ZDpXb}H;+vmI zX2bw8Nys;fhZ$!etgRA!Cm}9~lj2^-!H4G>AEfdEb5d9{u-UACJ6-JxWpMypoN6 z*4TE%&WE+}+SIdGT+Y#TDgQDK(X|$~_}PcL)HkjF97n4>M}GB;YkYxy>@TIy{h~+C z6&}~=IGk;R#sIz}4y)@9d{kPMhjiUkzuuqSFYSk!xo5UNz4Dm@durMUZ;$@ca~0NK z_Zo5^aH!N{Yma{L_&$d&)Gb9 z?Vnw~(#$>R^-b3vzGK|62is=Ez;OsYpl$z|5$96AgFan<^h*@EChj-)mg4~HF(VF? z=~z&|fdTT(Xnl`CH{&ovUrVO?jed)F#+d4#A-^Wm@diB9cwgy0>s!xRbA-1iMxI|v zxmNLjK5Xcb-OE$UgRWPvqjQnxo>ka`A3ZTw-+OS<8~YNU>e7DnxP_*Vb-U+gpN^BT>l0kHK*r`ppKt6u-f zx2b}?zw+!4?8B!cLTy-Km&by3MLu&f?r6QXQy*IT>^7k;s*H$!sn*V{JFwZw^_B9X z^PKhF_ng*#%G}Jr8F8nsQv9KQ#(t+xw4MXa)#rW%Nt=p;u22ALN&G(r?;{ywxLbgvX!3XFc<^ zY=ZyT?{3Ss-y<99z^|YEhqke&jWLRf;<6jo7IAN9JAO z)w~b=cldq9{=D3Z+!jP7r6=f@txMx z&t-fbTNwkb39Iy~PV`s2=UnC6qw3-335edJMYsN3r#j#5olkUZd*y8!^u7OxpSk$w zVRxK|d*hjW*Xu#X@V#PaDd_LzBj%zN*!=h#f!`h6U!fm5lxFFy`HAPfSvphh@7O-W z=j#65+{o`fCLVs{A>)zpSd9U^&(l1F>v!Mdc*fcGAElKsQN6S9pm`nd`*9w4$M-$6 z;+t|amnQ}i1Brog3~W*WS(E&8>U>TekLxpHF|qI->->z^Oq&y%iGg?wpth6n`6Hga z^&Lgl{`i>my5iG}xG|3|}P+LL%p49vv< zK7&`n8DQmS@VUNo*LNhoiG{~mi;;Cp-dwlDKw=;F+4TyxH+D<-1+&*YBwN*xQvkZ?>(o?z@?Q1DsEBsfzz`5d~|*U>Se4#i1y{#U$HUr!tDYY9)ZW2XPq z+Z%`3d$MGYp7TmE;ha}!iEsL;?W)+nLLATfaQE-WzEi*E0ALNZLh*?4(YXE*0OM=} znIw$4JbmVw{hXn;(WX|r73_8UANg9>x8*0sMq`6HXYf&rm)bfr|9`^p6BOxdDF&h1R$zUwY)6d7g*ABSg&f z*mK0QD*t=F?e#a(*HSE2`42yE)>pzcu&?_8eb}V;N_I!x+f{v$*1u9rqVzq29IS=Y zBiQv$Huzqcz0WYD98d{M&suU>2V%vNKrw$M(E z3Fka(OP`Kf?A2%W@e%FDIra=;e?<6mxBdtpj$~-f;Xc;At(exc!isk;zVc{a7$>dD|7r(yuc-a1cc%ZPwO;jnuj}o7<^s(R zwV3$aXSyDFCx<=!Oujw3tsmUbgDvJo_;$Dc2p^7QXlTjHy^S&KY1~IXC+VK&oEa_k zv4vjEwKH_yB~#B~@b@Uj8-w!G;(Dd+#E9AntdLf$6YAh-+@fMM+keVuJdfJd>rZ=_ z9}rjCtltNSiuYY|H1E;pT8p#7U3R{rUOdO2p{Vom-TGIosrrbx>3Ns?7`dEzcI9&> z^NC{s&vz^8ODq0b>tG*jYVo(m^g9)h1v>I?`)2F@7wg=zVRVd&@5=wB+E2WW`f`SU zw*R^>sjJnltUZc-jUDY<_3lS?uj~v%}Vc` z5n9xFVq0UrGTzYNBG{$%XJ(vKw&p+B2TbVrX#WF3gnG^roACE^dt~<7t^VsA+A%x- z-(CAx`tR$!a{uYtYM(h!aj!8sI=iZ@XX+#NPS0fjE7*E>{QX@13Rp+JreCQ0S}XMZ z7wXh%4B>pmcMp5FNU$CGXN7HkCW(0F+{~*UU$|a2wR+hjvp0Ts=YPap39;z4J%Vqg z|LQ0DkC1O@lVYkAlZaS9k_`B(wCxv{W^pE1=`vB{7 zG$(5O&iwD|en;(J-m@v#QXy}I`i8~E7E*NVpmB|NxN&d4dv zfh;9GUpc??VjgUBz8Tkddvf;KfO$djsrJpl+@r`u z9#s0XUp$I!?_h_=A6Q)Jx99&?U4Q+I<3nPsXCKxZtrTjPrZj9$8U5y*4?Y#~-=a zd1hWC|0=Cm|C#=jWY<2=2d@(6A_gSp1YV;p@wI9>`Mu5}|3N-5NFMZY&vRo`O{N}g zeGhD6kMf=AyC1vgFp9{P>O0pOe$LGQX9E!7udm@9{?i7}J+-*Z{2qwrU)oiR3CAN_ zU`}au{{2wpdw*uE8Ml_ttufB;ZCzHWwnp*v+T?s*6JU??L|tngv}JEz&d57aKK009 zE{Bu)?1{PXjf63c5#~{TFCY0!E%M5ldiWuBl;lR-+jbpFQRj``9Iv{2``9~IeP5mb zuf!w5Uys*n|6M=w-O-+i!lLWOwdRHr?n-ka?_o`qR@7g$e^cdqe`c(yx8-wdjPrY2 zmsP5*Q9QjiIo}_Pzt<<{zjBQ_a)wsapDTW~=IVR@(%#Z>jSX^=u0=0j%NC45=26a3 zJ4!Ym={PfveXq3b7iZ*@<{agC#M<|P+EVM6_H#*p>)z2?wC0`}JG%!Fg9v}!=GFeY zeqICTn=Lf15ijyYxB8rKs=qE*Jc~Q-SJYpPqo2JH6CIz?Z~5FB8@0t{m3)ih8MTf4 zjyv9;(Ymj$yLPR0aE4v8WWsI|@?1?1at~vJ{qR}g?d7ZK(ffD~gr05xQG$Nl!*f{) zuPWo2`tSw0TFf^U!|lkgmoD^IJ3{|HJ3Abk$$S%N_o^4SD^Ie_#T8V0Anc zi!1dLdnKK%vDNXJsc+^pSC8F{GcizFiyk@2vwq)Z%roYRf!DwQzi))I@X9s4v;MSv z=Ge@4KP%&0(}m|rrPcoWXOY`(OwHE3pRq{{BnA=#aTq}U#WNSE^?ouk=K3y|b@tnW zHQ)V%&wK~wKHm|K$k>j`^7#L=$7WQ<6@EW|;QETZoSX4W3?v2;1AQ34^FC_fs=TY; z_1x9|hfsfKuN|IoYd*KeX4`d#e4c~25O^QI(vFRaf7%u6ztX?dwH8kq?~He1;Bhga z-@UQaANqU05(AHm0bLuudm^}!)a-DLW5(CeP0es%icMii^6qW}XK#xmLMW z&xnCdk{h4D(CYu!)%UW`=;O25yt@7*27c!*|J`V^MZUV+Co^z`vjz4ZKL3~@za|qt zDdGJ~jd#ZVmfx+hE4H+JZjD{hnRD0TsyE)-5BRb7`1f!4H+-)AZ35j>r9SLaD(Ujy zmC)-`51-Z=pvnqYybV2=5lBaU>=-Re^y`szvEM>bk=oj`*{@exBbWYqOLXX>vKNs)-{RJ z2|3h@n4ljiyGIuBML!Yuo_SY!T7Gj3nAeKkNKM-F)|=dTMLJIT0=MO)DM|dTKIsUC^)bMc;4v%`wD3S})|O&%h(||IyeC zTTHF^YXMX5w?%^KzB-7sd{JeghnA}x=R$)kMDIkrrW=%J-4?fU} zbLqFH-|yc`Yf`iM%zgc=Sy>wgk9tZtY>l1Km2=kM z>QUqTwYds=i}$(za1HFi50Z{Os()$Mb$oNZ^*!_K`m=i7{JE?2%PANV+DG`u%ee#3xdIk1Y6(8VH&lXWG;9yEVr75iR%D$L_bwYmGT?UjH|K8I#{J z`Py6soaue$M(juCBjy9;i-;|99B{u;@J|bUpZm|MJP_eaj|{v|hQD50;J@c~_>LGb zC+^+2vJ)965<(biEzDG;>wKd^*M9a_k=reE^ zA-7is^`gc8=$&_!ujO}Z?5bYO$N2(z4upK5GBL(|?_>+*f~`#$y`2$(<~0C7)#U;TH!%j>z;yhgdDmb!anJ~9vETJn+iu;+P3;Js3d z*v;^jd0<8T>4^t@pW!R>D|PT405Q+|Xjj!k>eTh+n#`;N8x{Yws((i8T_)7R2Gl(t zn|TeLO6qrOEW#$>AN8NOQ<<$X<-6KPuJL_?A!LAD|&k8BIYEW!+ZXINO`XIxzDL<2DYx+IAeax@7CB1Tkep_z0Gyk zR-Xaxuq}1Q=N+!E$JXy_ZbqN{&d2+st=B`%ZK(CCA3A3~`=H({ZTrQjKP`To<(<@D zkn-$oeLQQ@NDM*FDoL?3618UcTfOP?QkO*<4Hr8SAvnX-QG zv3H9HF;{EfEgrA#FW1@q^!vzrB+Y@m=krIe{rMhpk?ZhW994TqZ1Q&iQO}(4M`_zH zYIZ3f`dSA#$9Z@^qNQxryR!cH`wi6J*;pu@&lm^AeMEd)G88AuM_Y7FbUgd@{gkme zjt%!Wai%TCB4ensNBbjojLN>sKVn<*eq*ZiIjgP%YQgH9x2XYpKce=y%$854zNp`M zqVRNg{V6?%&-fljDPASrt#vBNxO$IgAI-V2fpk@V&X28SuM$t3aZ8^)&Up7lET3sd z;(bQ`l{q7}CGWrc5NCiA_H->~zyHiLKIYHPyrY}c+)#yjJk7?_U%)Zjmsk8wFW_Bih<;k`tJPL+v%P3Go|4c?lJv-j_+ zKd5p3{wL~8GZG880d|edzsg&B_flGut9o+&+I7u%XS@>wzcGM!t$5bo_8(B~Gv4pf zfB&5sN3TPu2T||8=qEkV_q+6|_UvDa4d+F*chw*2Wo#nj-WwZz&W0VZp?7WspXyg^ zFgDmL5qeTa#xXIF7`Ph)c(<#Be5-j6`OtZ0=RoFK+7(s%5o`FS1b_AYGM@8ruSBqm zX8^?Ik-;8f!;9m@&-Xh2O`+#k~hv(8) zi&e>AoP$vJ`JSIX<2h7oGx(xw;a&9yzVuSmdk)6cTgM(^;yihsF-Z(01`-2_fy6*! zATf{_NDL$f5(9~W#6V&oF_0KY3?v2;1BrpeKw=;cmD;AsWbR}pGuK6Hn+pDLc8C9*|D699#u(~x{SF-%x@$Gk z)qu3;fmCV=lXu}m*B=-gyWF46=#INi6Zc;Q1PJbLa7XsC3JC;lWv9F zt$xf5!N6@qbBYJ4Ml#7HSQbPP_&&HEl*>>oL2(i$iZD@Rs2Z^SRzF4o*otg2NhXd< z96z!XDZvnh2?8?JfGluMoWEi^S{E?dIv+=vUu@m72msqo z01$@3j9%Mz=sED1RLcg&C(znwt&C#2;}|ENdrO|b7@_c^%Gk%4d-s2^YRx9XP&4xK z63HYa6F9&g8HS{T5W*0G+AM)FpcEt$g0}W{+S-=SY?e@9+aM+DmG6`Geb7EwVwT|8 z(W9iAnyFT66bj$?@ctF;i&v7_aS9{AQlJ!RbgTwohJ`UGk-Aqm=3h zJe|PP4aBt4(%M01S04ac7x`WoC5j-9d95lQgHm!#fFtWPjJNXL^0Gt zbT#0l_Q~D6To + + + + + + + + + + + + + + image/svg+xml + + + + + + + B + + diff --git a/org.simantics.proconf.g3d/icons/delete.png b/org.simantics.proconf.g3d/icons/delete.png new file mode 100644 index 0000000000000000000000000000000000000000..31f061a0230c2fa748dcfe1d16562ddfb9cb02e4 GIT binary patch literal 479 zcmV<50U-W~P)L z(>rTaQ4|H>??@nmi7!xm5r2TKjqQvUc1~|;Yh@9%NRgnB!cyXI(8@-zFjiI;Hlp}I zh)Bi<#v+A?#j=<^$y{TqY`C1mxqGd(_d5HuB=!>fwsx%zv^LaQf7k5RdX+QSI!hu9 z!g}}_-iLk?osWKa6F!EuFi4^$p|v6Q<12pP0B%U0mU17<7~%+yVODZ#stUP^`vv}j z4J>M{)&B)N!$JJP;lfk}+bVbQqLemp8Nmb0;5aVf*0{RXxrGtQA|7JBNPc6w%D#r% zlGUz>U9&ERC$*jnbG1JDpSj!D*o~C(rsNYg>ug7K2}Ug}RL|3x)!H0pv4VN6^(G-x z|A3dv?V0NNdMU5q5FTSmYsNl|=b(ps_)zA3#|7Le`uPGM#Yvnunv>PZLHbqTZ#a#c zTW*g8mhierPT;KM%;YGqg}33=E~DHFFT?ZjE?h}sGGY84dON^flFwuC_FLFP`~@0z V?huKr + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + diff --git a/org.simantics.proconf.g3d/icons/eye.png b/org.simantics.proconf.g3d/icons/eye.png new file mode 100644 index 0000000000000000000000000000000000000000..0e78cfd616eaac75e4461560d6d933cbb5a21716 GIT binary patch literal 310 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#VfERCL1A#WBR9_v|D?u0sI=F88|_`4g)4 zHl;e8;4Na+_U?Yb`9S?fo;pfdKu8&*UbQ-lcD9iZY zyu#{t$TR0v(?bn5zImHj-rP*!p3}Hf<;0XnDvNH)`Y8p!+R43uY1^bYCliH?xk-n) zs@oRtxXLB(w8kUs>2`s&FQ?v~v+?2r-@pH+T1($y5UHM&7UQ@6E6`62p00i_>zopr E05N`ceE + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/org.simantics.proconf.g3d/icons/ff.png b/org.simantics.proconf.g3d/icons/ff.png new file mode 100644 index 0000000000000000000000000000000000000000..9fb120a6720da5bfd7f34a2afc1d8a4cba30ad4b GIT binary patch literal 472 zcmV;}0Vn>6P)r zlRZj9K@^3*`zB7zGX#q~un-bMD&e^T!5`F0LCgxQQUy{7aVaUS-GGIK!A`6s3&;Y} zh>=Jh>ahqmv``?f$z}gz@?7+nZ`Amizpd5ynzpWV28%Ll}0ElNiqCAOlLORmpn|K>KM9 zoRc;-G+bVupM?|=xC~mYM{;{u_Wx@f8!Sk7u_|l%#IcS O0000 + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/org.simantics.proconf.g3d/icons/geometry.png b/org.simantics.proconf.g3d/icons/geometry.png new file mode 100644 index 0000000000000000000000000000000000000000..b06b5534a8ec98b088f46217b0001a38320ce236 GIT binary patch literal 942 zcmV;f15x~mP)vM8|uL*i-gijib`py`+~dOx9N0e=086VB7x`fT%J6)j}j3c z%gkHMRU*Q_Yvd%K7r}Z;KD^)&B=?lx9>)cTFXfGozGB1`^PU z)~J~V6;q`gRw$W&yh2z$Sv9q@l3f-68(_Nlmg=?A7t+?o@h;tgt!zRGX+|yyV$ikUQ+WF*4Jr#|A!rOSN&!x!w|vyZZ=uo4t`;-#k< znH=Mt=ia0+`zNWXt#s;SvKh5ru{~MOdC@xcW{ry41cCu(8JMR^;Ydk<03p5^Z;#9b-GW8&(M+JU+V@jmA_lCVyW&Ff4zU5 zQlUi8fqp#NxRFaUaw!%|T$}xc)>4C>p}9#zvv?5m7#n;Czt1^$_QO0gfc5ph$j~ Q3IG5A07*qoM6N<$f?LtNy#N3J literal 0 HcmV?d00001 diff --git a/org.simantics.proconf.g3d/icons/geometry.svg b/org.simantics.proconf.g3d/icons/geometry.svg new file mode 100644 index 00000000..e0e8ab76 --- /dev/null +++ b/org.simantics.proconf.g3d/icons/geometry.svg @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + image/svg+xml + + + + + + + G + + diff --git a/org.simantics.proconf.g3d/icons/node.png b/org.simantics.proconf.g3d/icons/node.png new file mode 100644 index 0000000000000000000000000000000000000000..a2cb4c46a998d81d83266b19c5391a309ea0cd73 GIT binary patch literal 772 zcmV+f1N;1mP)38!|W21ta&zK5mZPaBVuDAM35z5CmJDQA%s{YMNrw+u!w~wcJU8L zEVN1x{0CCGDeMfSFtAznHT#-mX6I>f&Bk0fTrQmRopZkLej<)zE}YfXY2tVu&oenW zF=@BKvWnDdMXJ>;s?~%4(?uWP^=m;UvrH;gKnNY*2it~L3mOfmR-saHD3|kC)&~Cy zH2_vt1eY)GGCZ6kod!*VAb@TcQYlbXh+_yt9nbqnuXi6I=7{510bpQY8N8gkz~rQi@o^X(g>07h^*XEFE?l~l1D53k3k%asO%>2I!bE}}`}_RZ-{< + + + + + + + + + + + + + + image/svg+xml + + + + + + + N + + diff --git a/org.simantics.proconf.g3d/icons/play.png b/org.simantics.proconf.g3d/icons/play.png new file mode 100644 index 0000000000000000000000000000000000000000..10f00bbc589e9b0b39958c47e7dda29e52b9bc5d GIT binary patch literal 530 zcmV+t0`2{YP)L zletO*Q51&%yG)!h8>msiUE+dij7zYyv(VZXP_VNSQBV*e79zfYVC-xxENsL_khp+? z3xT*HXfT>MW@2W!Rth>v+)j1jp8vbwIdF*(0{DBmA#8wh z7G)7OP38$LlFI`CAoEhq?+rR-?w+A_{E$RQ+phosz^MZvU%#uXqAws3DauyaR52Ud zg-3Fu+1-f2+95g~m~>S;Yi4=9RM5r-s8W1raMhyC+k%j<2jd+RuC9u{00rC2XJZ3+ zB@ZfPAN-ysw0iugRw@xJ@1-r?Zl^4{XK5WjBpbx>G4fY{#3U$8MtMmY6fUEbD{xQ; zIAuTEfo|&1%q$*Wlep6o$QT-qlLywx + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + diff --git a/org.simantics.proconf.g3d/icons/rotate.png b/org.simantics.proconf.g3d/icons/rotate.png new file mode 100644 index 0000000000000000000000000000000000000000..bcc829f0a0976dfab22de448a3ab974598d19035 GIT binary patch literal 718 zcmV;<0x|uGP)L zl09fsQ547j=e?WvlDwCsO;TIaf`S#nrAko{1h<0dAQVyD`hmDf2Ny?C5f{-(#a7Y5 z(ZR_<2cZm`C|GZM=XUkrPwaourxGo3iusj+vP;2vt8?Ow<~c z9ia{)ZK$iH=_WH1kMU8laoJLd*V~<4Iw{g~0DAYd$z;sc~@-|Gu1}%hGXO| z`FdgEpC?!7*U*6*%YMwnvR*#k_qEIJxfp4~^H&#I4rq!7 zI<4-*Ns+1pfEWDetcCMc$?_UB_snlrt1%-B@<^zbTjyN8+ZV0Kku`mgMOAUoVCfFWp%7!%yk=t~Hm^T7`ay$Oj|Q za=U>eo!q%ffL9J?;YXD(P2Ic&4K@sOgb0I*)i96p{3ZYZ*bkCV`kdYS z62dKMzzgJxS_&(+);daC9iL3Hzt63GKFvy<;j>)Y1faW=v8?!Xud^qL3#a(!BY9x* z0PPXTD>uFsYC&m8kLlx^002Ofloh5m>59(Yw3RD6A~ge;o-Y@z<)Bgs + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + diff --git a/org.simantics.proconf.g3d/icons/rw.png b/org.simantics.proconf.g3d/icons/rw.png new file mode 100644 index 0000000000000000000000000000000000000000..ccc1ce6e88a4235c7e40d388c3e0e9fe98b23531 GIT binary patch literal 477 zcmV<30V4j1P)r zlRryBQ5eR5?>*Nm_i`~X1Z%PA9};&7YH}zkq1i18`WStcroKTD4Gj&pIz~%d?rxff zQ9cc&nPy8v2M!#b!}EI|4$m=3{AGE6a{mS}BQoRGjOv(PG2?D1NSfH7$T`)`^aeT^ z(RV#hZBQTNNt#SxM&$d{3I&q+`LBC3%D&IV<|Z-lI!N!0o6V>#Es-1@5oWVPecL%M z4-Sa8w!jQc0L+MhS~g2^cu2Uu4l^?VECN@R3URp%D=Xgt{z!luASo6J=jNbTgnl1@ z<2WW*TZ7eAXf~$<0PuZ?B3M}XI0HBb=``eW(CZBWZu|}Qfcu9Bo;w|AG$0HCIBT_d zdVKtt-fB%rAkj5rr`e=-dP + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/org.simantics.proconf.g3d/icons/silk/control_eject.png b/org.simantics.proconf.g3d/icons/silk/control_eject.png new file mode 100644 index 0000000000000000000000000000000000000000..924d817bb6dba773de390723aa4ad985a9821713 GIT binary patch literal 603 zcmV-h0;K(kP)Z_%TCJAaY&Mm8y)OMIz{xTv zv-NsS=ku8!kB7kNbfU##LA6?qRjXC`TY(o@zh19|h5c|ikgn@=xm-jHqLoTTFPF>m z7lD^;W{`Kg9c{N;S}s?#-|uO&*$`YABC4vgLZKj;0=!W)hfz>i`(r+i9|v(1^AeR0PN$?YPB*gBP$$Dr&9sLMLZsV3p5%H6&*(z zAR#L<0v3x!z~yq$WHJ$x84iaOi^bk0@cAnE`FuV_2CvskilUIm<1u%{Mxznk?{_Md zN)(Ai-c96lm5Rk8Ll3YFyAU0Z$AXBgNPurnW*pL&iN~IVtNi+^ULCu&uzdXc=%tD#Ux p3j_ihC#gQ4PvPIvUti*a1jn*n;#uCM}X>FjAph?v>HMSz1 zf;3HmQp)fUut1?Oj4&`TKsnC2z=)5XlYE)v=6sKH?ztlXFfxpDv!GF+Q=nI1=tJK> z)BIUKOgy7Nd;3kr=-fVHy#5%we{jeLLt%bvH^RPlC7E$Y*@!h*`a}?GjY$GGq&7@a%@Tx%C8vwF8lXfELN2$TzXkYy*Ch+<~�$xF_*&%15 zB*T_3AX-q$zz}$UIw`+p!e)WS?n33<^>s&1&I(xCtWah->dvT zlk;@30hM|iP6P?&m*26-MFB%#|A5C~VO%V{IK>h&5)otfwqcaoAZ=g@xqS*twq+i< zM8F>m5dn;kMH#-KMn+dml*sqcOVNV)g;%P8{>x676~rb~r8XfEXT=e5{>~?YOAmbz zKdzITiDd+!tv0mR{WeIgd~}QXa<5RRwMm-P ziA0tOonx6Yn5=ejf?oZ#NW-fNn9t`>tyXEJQW3uee2VqU%jL3O zDwV`9fKS`>DOS~Au-R-t(=;CI^%~IC6G8}~xm->#0IXj5xnaBAg4Jq;LZM)Y&1MTY zogdr{KK*_l(&@Bp09dmKlF=%PEEX#Z3*_^8ST2_gVCI0`ZpZt9?&9${F#xSrOT%X2 z1_WS647=S9i9`Y<$qWvMle=3i7I3{@Argsb27rx;18@VDf?}J^#xp0ANidltP!tFM zkJCUG;c)l`sMqTRJC0>w1{7mfbTpk#8NkE=XdU+r1_KC%La!3oeC6?Y43EcyXOJX` zizkx_4@FVn{axYZ-EKE17K;!F1YS*Ka}`uor6_t%0)+@2jYh^eQ9K+DQA}9~Uk*|> zn-w#ejE-YNCx^prAM7yza-4I45g$8m^55K?|L?r+odSTVNnJ96LXt|7TGI4L>d~Fz z&-h8>1xd<>>vgSt=Y;X^$Jv9(As-4y`R%SPp?5wYYBW2LD^|g`7v>f>k`%^{A!C3N&EeR0q1EmI9?j zT<^fuCti3LD9UEdoCoe2BcvKUvD7KhHa~-21gL%Aj#%s&OGVR_$6iSuSoaqp%eN%J z76DWmU8pyEP^yWrwDz7wF9N262N52Jg#ie_jHv7Leqfv#&`?`&#}Fpfom5)T>7B!> zWsOHK0qlpu1b_k9E1Iu8-65F`u4B0T$PKrdAs|z3NmX=VY5BDbP=DEtvNfR%4Y5Zu z5VMpOD@qkb3GkT!aIm-Gn* z`85iZ>7zVE#RF?u>-GjXzTT2IfyTsX6XN-%yiPPHr0n_^E8Hzpe7MH(L!#e?D90zS zP^g}fN@{04Qcb!flJ%iEo~?q;Y!zl{=dXt}`IHwd0cyqO;QYY^WD0dM6YM#f=E3C+ z!2-R=&FDY;{gfv^)4f+|?c7Tj^US!+(gqX%T+i_HIx{<~voklC*uOv1|9t14Z-oeY TX1>|Jb)Dfc3=%9wAxt9|F z+d&sV7i|Ri?b*J^NGvsH()NE*Nyw=rHOq z9m05cXZVv}DLkU1y6J^t9{Ie+&$xra;?lD0_4(zg1yOkVF~Tl8PyD8)GkMUbW%rR#bC7lH zW%k*fs%0@X=TU8A0Wzs(2GkeDrphJpj*`W_=V8Q>S%%hUVMG&|vdP5cv~+zSM(r5L zpk_q)&Qt7?cq5sCsciwPJ89hPlW@GQ1=qU$Sc|6_M~rNO8=m1wO9sa2uK|I2rl?eL zT~6cT0}tkd3eMer$IdfNqs&lA<*}XA&^z>6AT1e~Jc~;*4J*EzV+KU5Yj?Brt{(qr zZ8L5S1Q6NMSc+`^00WL8nY7Hn?e#GOich5aUJ=JG++neU8!4Q(I1!F%48;^V^!D|a z4UC`W{X$aBU{}jyHt+*yo5%4bq~LVpD~Qp(vO#Dw#r{liJqga{D7R4KaEAERXdHzC zu(GYOsh_;Up{YN>64bT|>t2 zQspYQIp!?(;ZbSE6T)gtVKbqg{VOuYU0$?tJyJvGo4;4N@-ba~vSMy|JkGaw^$FY~ utNgH&m+yDjgvO2${t_?#`!W5`bN&ejO$WoA0n6Y30000VN9{w9DwJzd%Gm5%l6k(Srw1f=C@i5k%a|<)Grew%RTzD&|xaqcXf< z9*@@$bXSuRnUR_GMnrG_gFk+>+ij)QYU#~plQkL*gL7`wYBg4^R`qhZto$k<$f_Xo z<#I{K-n-q7Ow**(=_LO_v`{FR`Fvje zCh%1@e~?F`5v|v2G7LjvFc=W3dWbN_cqWrko&v(J{s`D?He|Qk1!*YBtJR9ERvYzt zJ(|zwGN#k%P%@d+p8}#;49X}KB%94HV55G&Pm9Gu2v{Y$-LC8hs*A_t>?u&M*9|ml zyWL6wWCWZ}Ck=-~vRJGF7W(*b$n)iLp-3cRJO#v!q9QpfKQN-6~U9q_TF$F*h9sL-j zNpc$weSXQZ6Gag%5kOy9HfA1@g zVA*&|VjFHeVhIV!`DzQM7F-a@NRTNvNlYYp4z%6NAQuJno^MeOJ!7dzy8e(=;etr6 z4q2h83Vb36o=G4!6u79$u)6u4LoN!;_)kItHmh9g5CP1HxVh+sSiS*Mlqx_uVfwL~ z+}p|}Y*;r1{g* z9DE4_W&SW~qUN5hWN@-RUJ#q3Ngxr&iJp;+4aEd;HM{A>I)B?7>yL4`Nc6h^we^ve z3YC6fwXTqAQWr8=Cd?emR={YnNptkhuSFVP{Q?6Lt^ zqF4A?)Arx1JpP&Pyh<4sUhXnam)AJ@xmkE-VuVGbg_|=vm|INb-=FD!zVlDxJ_uiv SXLQ>D0000yhD literal 0 HcmV?d00001 diff --git a/org.simantics.proconf.g3d/icons/silk/control_pause.png b/org.simantics.proconf.g3d/icons/silk/control_pause.png new file mode 100644 index 0000000000000000000000000000000000000000..2d9ce9c4ec4b787b77e2407809c8887b6252dc6e GIT binary patch literal 598 zcmV-c0;&CpP)U3VE{tZoOXQ3gborPd)C!*bfsFfgUA%b`K z{k54{z0H}ACRrHvW^d-rdyicUV+{VYtX~gCqfs0|(-=vN2o1PiuPW{>+#Atov}dlj zm>FQRf_YAoB-!b7g57TC=llI0*6TIQX0twmlwz@1Su_y<#c()O27`fy#f%p1x~?-# z)7Wme<7b=AhIKj}t=(=bMjvNzr~MuZg=Ct#TCD`Id5F*FgY9+;-ENndyrfd8-V+sI zk|x?lbD>axN~J2Ai^W%{R^I>_0Z9u6gEF#73lqsO`axO|3~qzj{hRS`0}LC%>-AD? zlFkeU5t@ED93Che0EA(j5rE6(g7f(t5ddbb)O7oPG}&BpJRae6I)RyiO6J&XwmSe5 z5%qypxm=P~KCwUk1<-E^%&v%&sfQfOPbAd^dMUz$2)JWFR zn(5E_apM_H=DRN?Tj1j{9obJa2Z=)=&L)N3y%h6eCr3~F>o%;x+TQ>p^I2c0Y>yvi zIld-=tn@%V9S}8IT_{!R5Z+_Ch0UxTYjubYFr%4GeU;lC74TEKeW=Sl5HvMAeX=Gi zUD%DrWY78$Ld*n!b75@ktedM+7b-uxz>7nb#SWC}9Rsqt73OZQ@HmbM0hR#sjmFrz z`Qn2R+;S%k^W^LfTz4f%8vIhZ??Cw@GT3qQ2$+f;Bm~?nEIi6bESWz7m0cmx39em$$Y&@l88-}q`@)p_|Tj# z*1_TN$urdYuZuK(mFK)s`?7zHi^MWe;3cvrICC;Dz(yzzbJPMi?R@k1RUUs#H=pHg zvrjkZN3JD?ns*D2owV@K;bCSR0s0c1`uAh{pXdA&89xkjaU%7W00000NkvXXu0mjf DW6MO* literal 0 HcmV?d00001 diff --git a/org.simantics.proconf.g3d/icons/silk/control_play.png b/org.simantics.proconf.g3d/icons/silk/control_play.png new file mode 100644 index 0000000000000000000000000000000000000000..0846555d0ca84cb99d4c70dad80144a232604041 GIT binary patch literal 592 zcmV-W0k7R5;6} zlgp~&KoEw{L*wq6jM9+RMU)_iNO6K~b@$|K=nj zb2!5=4Mjq_zrU*f>U2#vSVnMZ9ja4cY`AdOM*t}k^goWqfa3Iq(>2kSH;P81hAqIyBm_{t1>+!KRdtb~{1AK7>C~ zD-Nov`UX!X6ET_La7f{B_|*cRuZGR%^C`gjd@jmW6h*+;8;{2{8ja|Fzf-YTq+l@k zGLg?!DijI~9$+CG0*bxx-)TO!p6i!Q&%N5)kR|pVJuNho7M&@5o@ZpsgYXg z6pCpqAEgW*0v6~{n89ISU>M4A&V?DNy7MOQX68Ka`MBqf0l?U(ZY+X9l}VLZ)#Om- z;Wxvd@uT21RmKNz1dH$Bj0zp6>Db9B7mX*l{i7uPYA;7kd3g)QVC)rxA$;8vC|jea zS%$3%AWB_OF8f4{mJFo|55c22v$T`7VytGO85j|cC%=pBjskcjxd*)11x{77(<9$R zNrwG!M09PX(8Nd#urDkdGiz{FkfHKZhPUAguyq;A^$wKyj&8EE8)WXSvDl6Q4NN}z z2Zd#i!U*1a7=Vq#3W3jRZ6Z9$+&MVBAqrVEFbBV-XzUqFMNrFnb9RsDb%-T!q1pza zrNBj9g5~vhG_q(g8Ht^6IILQuOJK}cdY)autaf$;u_Hxz{;liNSF+ zP7JVo4aPtM&mF+{jGz3=veK}ME-bIS)D6sEz9#6p*nx(m=)Gd##2kGE&YZW%&7_NU zaJbxh3nsTeLlsIj==Xtu`3s4ZJ3jM?zzC+xEl8DG(CzhM_b>rg=Lda=hWnnX#UBVW zoG_R&W`Q?ax-3JI?gr8ns1oY(%Y_9|I!G4+85=MXv^z2{WgQJlI?w zaoVx2#b| zLX6^UF84fh?wy$kBLC~BD2js0>zp+XR}r`}LU#$3n|fVSTQ&_fqK z-dP1W_0w_)Fx(96Hd?S$6Ag!Gb0{2;SA#|hQKxxo4lC@GkWvoF>433OT)ML_c*YrK zxk(GV+5xw=j}C#*d_)ZQm|^vSE$e_Rfi{EB*{sr@#u0%!GuA`kT6eip5)*9h(VoI2 z7I~jC*1{1PRmB(0C&t&XN#G6@eBuONxMW%!n+~_GQB^!(14SOFz%!m0KGcES_nU0K zx*VUU%kcb!9C_-b+%XxB2spb0jf9EGvCrBTt7=&<*|?4A1r-;+e)BJV19u#CG)&jc Qk^lez07*qoM6N<$f+7R3%K!iX literal 0 HcmV?d00001 diff --git a/org.simantics.proconf.g3d/icons/silk/control_repeat_blue.png b/org.simantics.proconf.g3d/icons/silk/control_repeat_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..406ec333bc036690d4639cbec70e8f586e977699 GIT binary patch literal 750 zcmV`dI4bfJkF0x@cXCL|Igq$5O2KprVjQ%O+X7O;#( z4BD1bI(<+cEez0UoerJ8pvUZH<2j7y zcZNUt)xrxJYFpmPCdcPpZrKy&*VZ>ApFbcitp@qg#TeIQPnn2A+}{k&#TSQNduHE8 zR1lLg6t#%bX_+CDEg*4_f_v33^v*=h#I2ZA3~EX24{j>CdV}A=`*V zT4vz!`I!OrPI2eFNk)w9XPLPE(JbD&MP{&ll+#ia(bqqy8yG)*4e)6tkBnME*Ypl9 z-y3DbfrSJUUwt@@D-R}c|4op+OgNr~#cI=AsIxgE+;$>~av4mxb*QrFQBlRSu^2P( z#4-pavM8REG5;k1bN7TkM8nPocv)tTbCDe=Sn=D!1EK%memuVc8qO zwkWfiP|txa2~#c~+AY08Q|E`jSGoE#-RjvgwZ5L>o_F>0mY3bqi%w2z>#*|89S-gW g7yS2U`k(Lo6ZXgk;$VJhmjD0&07*qoM6N<$g5UmA*#H0l literal 0 HcmV?d00001 diff --git a/org.simantics.proconf.g3d/icons/silk/control_rewind.png b/org.simantics.proconf.g3d/icons/silk/control_rewind.png new file mode 100644 index 0000000000000000000000000000000000000000..c0294477171e87351813135e50e05766b5607b0a GIT binary patch literal 614 zcmV-s0-61ZP)jUp9KZp49DjNvG4H?RHybjH%6LlQtR+QmfUZ9|2q} zb1_@3R&Y9<;C{c0I3ABMpUdND#U4V-<+4^P zmE;$|hi&#L-fp+BSS&zQRT1m;8m7~!4xyB?d_FJf0A4Ra+kcClPUnkQQ53O{tKaWK zCX*pLfH#XG8LeWiR_h-DK5r;AuD_5{@H zb&4IwGM39FxLj^tf(vG|nGhgMQJgRykHusLg8@XN(Ps&Kz61{+kB1PTO^?STGGd^0 zLI@0pL%7{;P%IW991cI5$mc2*3I&EG;6f2*N9brY5<+}p0(|FU#zT6!NV!~2&StY3 zjt&2KI2?o<1mR`E%xIkpwLl;se|weF>9m|oCK)eD*v6h<%{X^{d4LO<&*zhW{FoAn zgcONHNGKGd!C+AJ`~4~xQLooa_`CG$*Z8mT4&e|nrfoDRBme*a07*qoM6N<$f-U?5 AUH||9 literal 0 HcmV?d00001 diff --git a/org.simantics.proconf.g3d/icons/silk/control_rewind_blue.png b/org.simantics.proconf.g3d/icons/silk/control_rewind_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..15d1584bdbb2c26a9fc4c8269aa54615a58a4657 GIT binary patch literal 745 zcmV1hlor z)=Ec^h7>5J3?Bj(D6|X+0|UcQj&m*_Qg!D|-c07sd7pF6opXl(U}#WhWg0W$d_xV%ATb~UcS*dC+@kfS*m{?64KBH-eM78JQAu#&2c z7TM!?0X98;&a@msh@1ehFDx4~_smCS0rm@Z$dv@5Y^ec>Jl}_`uDh5!i#cpZh5&_) z{y|~cgJzZ1d%`?CxkdJIg%by0u(~PqB0%Zdj?maMmYO=M!=;B#0>~5_5YO>&?w*4H z@LRbi!eNPrxg`gUUIeK8JG(3%R{o~|7so$K+8_qZe0Iz($pKd%d&oOhA&AGYXkKE` zO8~w=kN^smCS05H!-WT*2mpbXAJK6B{s*`+;U?8|s%XO8{Hs1d`DH6am$(L0coEX9 z)c+Ho)WS9-4?6~g4NrO@c2FaKCYmmR!DQ~YpfIn+s8pr^?KThtmU&}3Kr*7R^y^Rk z5Xsb_*=oc3w-9KI@B4=+yK6a8uQ@#oTkf1PnlL+NjAm=Zh)+xqld|idFEF=^(avw| z4U*w)Kx6;tnV0ZXQD@SHtHr7{`Y12 bpX>Y!%!CO%>C8GV00000NkvXXu0mjfJYGkQ literal 0 HcmV?d00001 diff --git a/org.simantics.proconf.g3d/icons/silk/control_start.png b/org.simantics.proconf.g3d/icons/silk/control_start.png new file mode 100644 index 0000000000000000000000000000000000000000..7dd1c07fbade1ec8d985d95fd89385667bf83e3a GIT binary patch literal 604 zcmV-i0;BzjP)V=42{wMyJ==FL^x7*b^oepca+Xm;{Xf~Uy(P(J3T21*D zAjGN=^W}0$$K#Q1x0{T^;Xw2GoT}9-uT(1Pmw*qkc|M;B58k`oj!e^})9EDV04fefqL?N$IB5&$S;dHP}hDFLVh>akw0DUnDp3(#t{3=|9E&1OS( zyMvrg7bTNPIYt05old2T%jH7RXwM2F~VlEOTqhl>IpEJOe`0XNaO*i*Xs-w zM;fqav)QCzHk(OTpMddrEITt83@989KT;6=)$sFvzsthux=wFzy4(=~R{#u$L%LqC zR4f)L7z{p&DEg`t3I&ecu;80x$iEP)ITpohD^Ctgf=H~o==W*|y0)VM;-LQd9lR=YF)677| z!Jh8V_;KSkP5LJrlF9S+j0qkk+2iPm7~x{#{$ZSbvzK9J-4zqYVC)27V7~717pTZd znit9v$VwYJS3ROyLxp^?0)a!0U)oMn7(0Xv0eUoZ@gH)t)d5_J+J%bT22oSJ)g^nf zqQZVCEIYOm2+rB;rB+cID%~N1o%g50=A<=fWgC_GFUb) z%s4&22M=t~3G+RMgR^pz#KbcfK)ZtsdJ$j@d{400GnQJeAz+sPu#&f$`6hKh0J%~V zq(%oWs|qZyzh}{lfSK@dRK#JSxg@DDP3^*cD+kP0j(npKkSQvp3bk_uYtD5My##O+ z;RpcDs9R5c#9;NFP5{z^GN_^r%PX%(0OOZ~7+aNFP*XZk{E2|i#E`vI`YjCrsfz|V zndEsDXoqvug2CxaF}ZvhdOaY6!{9q~KO+jO!o5Vk0qt%NcD}`cvVR;6QTNzYGWq-= zUX+?7V0e7VLW2m6_>T!vT6W8eRsOC$*+0hNMWWwDsLfA)S*X-WV71;M{bCzP)O;^z5vZ zY!uIB*x&E}vNJj4{?GTJBigE^o7UKdzE#&EBXnfjM2N9qUNJ=7T*(!I*v$dVF@wV! zPcbfCO)dpCHwm6#49koVc}1IZ;f0opGWdxBx;Rl@XzG}46S&UgQ6wI6lQE987w+r= zQ{sp)?}bM^PSu zImdUlKjSCCE4u7+Z)8{a(f*WH^6Vt$sa4Pdn>Gm|hqxOd&DgzL7wR=Ny zr>K3{Pb3xpRu)a{!~pxkvN5v>H{?FlfAoQu4ArC_RK=cUva=WC?yvFKjtvbQVdguH zW&aC4ZFY(9WQu1%h2k`_XyA-}%`(_CmTH1G9&H+WxB<7lEP>07F324X&LtI=*Ebks z(O^1xbS&VonymqWF(ZPe(4cg#Lb0wAqrP?lYk_qESz>U=ricNSk8nlkTJZI`2;B0p zP~cS}qly76ue`DhoFBiW8A<6uOVzAiF)Myh40}1zPD8j{)c_{NT znF;osE(x$5WnrFL;%2<>{$AzD&vfr)$@TcfHvM#Qg`uALgat1xJn{IMSx=b0LuW4k dO#kzpe*)_`5%$M*g6RMN002ovPDHLkV1l_FIQ#$r literal 0 HcmV?d00001 diff --git a/org.simantics.proconf.g3d/icons/silk/lock.png b/org.simantics.proconf.g3d/icons/silk/lock.png new file mode 100644 index 0000000000000000000000000000000000000000..2ebc4f6f9663e32cad77d67ef93ab8843dfea3c0 GIT binary patch literal 749 zcmVe|tv9>?g+k#9o0pTxd@;_sq{kwlU;^VvV*?BV8P@}BoaZTQUROpWV6|-M`|^n&)=+8tHo3*<<$NU zU`%V~ZF;?hBSYsjJ6%JzV}E(D{pOLqQklliUf9um_tGl-wty`y*p?eYNW56P>X@1s zZs7KrRZKtmV7Lqj^5Fgr7_`LjhdJK@ltF&O`j7?*NUM$KvmNGz)3WjM?V$vHlPT0AFyF?kLE<#HZabCSW3-oa*6;Z zrXD`Ulwd<^2glP%1Y1Kc1Ij%DU^=ME(jKf6APNlA$Uu;J4bVilQHSWX5uJ$9Zsp4M z0%!@LvyTxz=Z6stxlichODIY+yNGt%RM;m`>H4LOKLFs9Y%b5aUN|2|{0Zw|<_~i} fmXz*V19AKYarLKlJyH=-*k3W|aiVYC~e{STzB+=%NyKm^5w z3m4+bm8cXnzG}0Gw2c^Ol0K$0_ity0#@^}dhsl97GUJu9lkxh`Okt_0|=(|h`!tol*)tahk*i! zgS8GLCq{|Gd7N1T=a4u`0gM4BU}M^~w|L$b3WtyL{rO$Q?PPfL6z$J7;&2In&vryC zqT@6`g9u_Zg@Xt1vO7RIY-D-g8eo{1!oIz%ujUZ52IBq#JOI%e5ertc^kIf}?KOA? zx9*6-2qdQcN5WDRs@&WP6I?Nxm{No*quRTbIBKa{opLb zA%3`w)e+)sGB0CNfHr zlR=JxKoCV=Lq`HpV<1LDJc9R_E6mcPxtvqEK;0Tbhy;T4EPj~Q(OJ2ePCDHb)T{bc zg>laD&I;c02CTo?Phf{J5CmY1?8d;DrE@S0;M|_R|9S+#j`jM3JclHKIEKkYuwj6% zgQkJ=8Hxhn7r+?EbJ%Vn%V0hi$Xe)oxL%>E^n5(NkPrlN$TC=`l zTx1)D7l2{VkXWl$#j!wPsI=Qw&WFPv5}eyp6dIDTpkr}I2aPfG{r;!+|Nb|A14~tk U;PNP~pa1{>07*qoM6N<$f+0@2`v3p{ literal 0 HcmV?d00001 diff --git a/org.simantics.proconf.g3d/icons/stop.svg b/org.simantics.proconf.g3d/icons/stop.svg new file mode 100644 index 00000000..58381c76 --- /dev/null +++ b/org.simantics.proconf.g3d/icons/stop.svg @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + diff --git a/org.simantics.proconf.g3d/icons/translate.png b/org.simantics.proconf.g3d/icons/translate.png new file mode 100644 index 0000000000000000000000000000000000000000..21f528479e112a28df292e9c4839846348daa870 GIT binary patch literal 573 zcmV-D0>b@?P)L zQoU-FQ4l?6=6;`vO;*7|g0Q;o#&j00+Qmu`MD`Un8xU4R(rBl>2wG?*cOM}n5Vi3I z1QUpjCh;$bA|jF$qMPsDI~KBm=w?lD+BtLPoH;`?!~c{FYSQyEJ8TWa?4*DlUUkez zVUUo*noY$AyH=oH+Yb3e?O^@USgHQRiMya)+x@Vv?{?wGm_h|9Rg)FN5#g|apZ=*p zyr&a4Vq|W}SBp?dX+l%X&AU=d{wDPiBWiWZ96;oG6`LOcwU9 zt}l)Y`8-;vs^s5d+?t5mZ8%vv=e%o#sW3Az#w|5wl}z%lM!Z&&mrk

+ + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + diff --git a/org.simantics.proconf.g3d/logging.properties b/org.simantics.proconf.g3d/logging.properties new file mode 100644 index 00000000..d8ec9e42 --- /dev/null +++ b/org.simantics.proconf.g3d/logging.properties @@ -0,0 +1,54 @@ +############################################################ +# Default Logging Configuration File +# +# You can use a different file by specifying a filename +# with the java.util.logging.config.file system property. +# For example java -Djava.util.logging.config.file=myfile +############################################################ + +############################################################ +# Global properties +############################################################ + +# "handlers" specifies a comma separated list of log Handler +# classes. These handlers will be installed during VM startup. +# Note that these classes must be on the system classpath. +# By default we only configure a ConsoleHandler, which will only +# show messages at the INFO and above levels. +handlers= java.util.logging.ConsoleHandler + +# To also add the FileHandler, use the following line instead. +#handlers= java.util.logging.FileHandler, java.util.logging.ConsoleHandler + +# Default global logging level. +# This specifies which kinds of events are logged across +# all loggers. For any given facility this global level +# can be overriden by a facility specific level +# Note that the ConsoleHandler also has a separate level +# setting to limit messages printed to the console. +.level= OFF + +############################################################ +# Handler specific properties. +# Describes specific configuration info for Handlers. +############################################################ + +# default file output is in user's home directory. +java.util.logging.FileHandler.pattern = %h/java%u.log +java.util.logging.FileHandler.limit = 50000 +java.util.logging.FileHandler.count = 1 +java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter + +# Limit the message that are printed on the console to INFO and above. +java.util.logging.ConsoleHandler.level = OFF +java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter + + +############################################################ +# Facility specific properties. +# Provides extra control for each logger. +############################################################ + +# For example, set the com.xyz.foo logger to only log SEVERE +# messages: +# com.xyz.foo.level = SEVERE diff --git a/org.simantics.proconf.g3d/plugin.xml b/org.simantics.proconf.g3d/plugin.xml new file mode 100644 index 00000000..bb32772c --- /dev/null +++ b/org.simantics.proconf.g3d/plugin.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.simantics.proconf.g3d/schema/geometry.exsd b/org.simantics.proconf.g3d/schema/geometry.exsd new file mode 100644 index 00000000..f6af1286 --- /dev/null +++ b/org.simantics.proconf.g3d/schema/geometry.exsd @@ -0,0 +1,112 @@ + + + + + + + + + [Enter description of this extension point.] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [Enter the first release in which this extension point appears.] + + + + + + + + + [Enter extension point usage example here.] + + + + + + + + + [Enter API information here.] + + + + + + + + + [Enter information about supplied implementation of this extension point.] + + + + + + + + + + + + + diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/Activator.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/Activator.java new file mode 100644 index 00000000..38b8b6ff --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/Activator.java @@ -0,0 +1,94 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d; + +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.BundleContext; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.management.ISessionContext; +import org.simantics.db.management.ISessionContextChangedListener; +import org.simantics.db.management.SessionContextChangedEvent; +import org.simantics.proconf.ui.ProConfUI; + +/** + * The activator class controls the plug-in life cycle + */ +public class Activator extends AbstractUIPlugin { + + // The plug-in ID + public static final String PLUGIN_ID = "org.simantics.proconf.g3d"; + + // The shared instance + private static Activator plugin; + + /** + * The constructor + */ + public Activator() { + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext) + */ + public void start(BundleContext context) throws Exception { + super.start(context); + plugin = this; + ProConfUI.getSessionContextProvider().addContextChangedListener(new ISessionContextChangedListener() { + @Override + public void sessionContextChanged(SessionContextChangedEvent event) { + ISessionContext ctx = event.getNewValue(); + if (ctx != null) { + ctx.getSession().asyncRead(new GraphRequestAdapter() { + public GraphRequestStatus perform(Graph g) throws Exception { + Resources.initialize(g); + return GraphRequestStatus.transactionComplete(); + }; + }); + } else { + Resources.deinitialize(); + } + } + }); + try { + ProConfUI.getSession().asyncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + Resources.initialize(g); + return GraphRequestStatus.transactionComplete(); + } + }); + } catch (Exception e) { + + } + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext) + */ + public void stop(BundleContext context) throws Exception { + plugin = null; + super.stop(context); + } + + /** + * Returns the shared instance + * + * @return the shared instance + */ + public static Activator getDefault() { + return plugin; + } + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/Resources.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/Resources.java new file mode 100644 index 00000000..17231ff2 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/Resources.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d; + +import org.simantics.db.Graph; +import org.simantics.equation.stubs.EquationResource; +import org.simantics.g2d.stubs.anim.AnimationResource; +import org.simantics.proconf.animation.curve.CurveBuilder; +import org.simantics.proconf.animation.curve.CurveBuilderImpl; +import org.simantics.proconf.g3d.base.G3DTools; +import org.simantics.proconf.g3d.stubs.G3DResource; + +public class Resources { + public static AnimationResource animationResource; + public static G3DResource g3dResource; + public static CurveBuilder curveBuilder; + public static EquationResource equationResource; + + public static void initialize(Graph g) { + animationResource = AnimationResource.getInstance(g); + g3dResource = G3DResource.getInstance(g); + curveBuilder = new CurveBuilderImpl(Resources.animationResource); + equationResource = EquationResource.getInstance(g); + G3DTools.initialize(); + } + + public static void deinitialize() { + animationResource = null; + g3dResource = null; + curveBuilder = null; + equationResource = null; + G3DTools.deinitialize(); + } + + + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/CameraAction.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/CameraAction.java new file mode 100644 index 00000000..2f619046 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/CameraAction.java @@ -0,0 +1,134 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.actions; + +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.util.List; + +import javax.vecmath.Vector3d; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.proconf.g3d.base.JmeRenderingComponent; +import org.simantics.proconf.g3d.base.MathTools; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.common.OrbitalCamera; + + + +public class CameraAction extends InteractiveAction{ + + private JmeRenderingComponent component; + private OrbitalCamera camera; + + public CameraAction(ThreeDimensionalEditorBase parent) { + super(parent); + component = parent.getRenderingComponent(); + camera = parent.getCamera(); + } + + @Override + public void activate() { + + } + + @Override + public void deactivate() { + + } + + @Override + public boolean usable(Graph graph,List resources) { + return true; + } + + Vector3d prevIntersectPoint = new Vector3d(); + @Override + public void update() { + double scale = 1.0; + if (input.keyDown(KeyEvent.VK_CONTROL)) + scale = -1.0; + if (input.keyPressed(KeyEvent.VK_NUMPAD5)) { + if (component.getProjectionPolicy() == JmeRenderingComponent.PERSPECTIVE_PROJECTION) + component.setProjectionPolicy(JmeRenderingComponent.PARALLEL_PROJECTION); + else + component.setProjectionPolicy(JmeRenderingComponent.PERSPECTIVE_PROJECTION); + parent.setViewChanged(true); + } + if (input.keyPressed(KeyEvent.VK_NUMPAD7)) { + camera.setCameraPosRelativeToTarget(new Vector3d(camera.getDistanceToTarget() * scale, 0, 0)); + parent.setViewChanged(true); + } + if (input.keyPressed(KeyEvent.VK_NUMPAD1)) { + camera.setCameraPosRelativeToTarget(new Vector3d(0, 0, camera.getDistanceToTarget() * scale)); + parent.setViewChanged(true); + } + if (input.keyPressed(KeyEvent.VK_NUMPAD9)) { + camera.setCameraPosRelativeToTarget(new Vector3d(0, camera.getDistanceToTarget() * scale, 0)); + parent.setViewChanged(true); + } + + if (input.mousePressed() && ((input.pressModifiers() & MouseEvent.BUTTON1_MASK) > 0)) { + Vector3d o = new Vector3d(); + Vector3d d = new Vector3d(); + parent.createPickRay(o, d); + Vector3d point = new Vector3d(camera.getTarget()); + Vector3d normal = camera.getUnNormalizedHeading(); + normal.normalize(); + MathTools.intersectStraightPlane(o, d, point, normal, prevIntersectPoint); + } + if (!input.mouseDragged()) + return; + parent.setViewChanged(true); + Vector3d msTmp = new Vector3d(); + msTmp.x = (input.prevMouseX() - input.mouseX()) / 100f; + msTmp.y = (input.prevMouseY() - input.mouseY()) / 100f; + + if ((input.dragModifiers() & MouseEvent.BUTTON1_MASK) > 0) { + if ((input.dragModifiers() & MouseEvent.CTRL_MASK) > 0) { + Vector3d o = new Vector3d(); + Vector3d d = new Vector3d(); + parent.createPickRay(o, d); + Vector3d point = new Vector3d(camera.getTarget()); + Vector3d normal = camera.getUnNormalizedHeading(); + normal.normalize(); + Vector3d intersectPoint = new Vector3d(); + if (MathTools.intersectStraightPlane(o, d, point, normal, intersectPoint)) { + Vector3d delta = new Vector3d(intersectPoint); + delta.sub(prevIntersectPoint); + prevIntersectPoint = intersectPoint; + delta.negate(); + camera.translate(delta); + prevIntersectPoint.add(delta); + } else { + camera.moveRight((float) msTmp.x); + camera.moveUp(-(float) msTmp.y); + } + } else { + camera.rotateRight((float) msTmp.x); + camera.rotateUp((float) msTmp.y); + } + } else if ((input.dragModifiers() & MouseEvent.BUTTON2_MASK) > 0) { + // System.out.println("zoom"); + if (component.getProjectionPolicy() == JmeRenderingComponent.PERSPECTIVE_PROJECTION) { + camera.moveScaledToTarget((float) msTmp.y * 0.5f); + } else { + component.setScreenScale(component.getScreenScale() - (float) msTmp.y * 0.5f * component.getScreenScale()); + } + } +// } else { +// System.out.println("cameraAction!"); +// System.out.println(input); +// } + + } +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/ConstrainedTransformAction.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/ConstrainedTransformAction.java new file mode 100644 index 00000000..1cd0b595 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/ConstrainedTransformAction.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.actions; + +import java.util.List; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IToolBarManager; +import org.eclipse.jface.resource.ImageDescriptor; +import org.simantics.proconf.g3d.Activator; +import org.simantics.proconf.g3d.base.ConstraintDetector; +import org.simantics.proconf.g3d.base.JmeRenderingComponent; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.common.OrbitalCamera; + + +public abstract class ConstrainedTransformAction extends WriteInteractiveAction { + private static final ImageDescriptor LOCK_ICON = Activator.imageDescriptorFromPlugin("org.simantic.proconf.g3d", "icons/silk/lock.png"); + private static final ImageDescriptor LOCK_OPEN_ICON = Activator.imageDescriptorFromPlugin("org.simantic.proconf.g3d", "icons/silk/lock_open.png"); + + protected JmeRenderingComponent component; + protected OrbitalCamera camera; + + protected boolean useConstraints = false; + protected ConstraintDetector detector; + + protected Action useConstraintsAction; + + //protected IToolBarManager manager; + + public ConstrainedTransformAction(ThreeDimensionalEditorBase editor) { + super(editor, true); + component = parent.getRenderingComponent(); + camera = parent.getCamera(); + detector = new ConstraintDetector(parent); + useConstraintsAction = new Action("Constraints", Action.AS_CHECK_BOX) { + public void run() { + useConstraints = this.isChecked(); + } + + public void setChecked(boolean b) { + super.setChecked(b); + if (b) { + setImageDescriptor(LOCK_ICON); + } else { + setImageDescriptor(LOCK_OPEN_ICON); + } + } + }; + useConstraintsAction.setImageDescriptor(LOCK_OPEN_ICON); + + } + + @Override + public void deactivate() { + detector.clearConstraintHighlights(); + } + + @Override + public void fillToolBar(IToolBarManager manager) { + //this.manager = manager; + useConstraintsAction.setChecked(useConstraints); + manager.add(useConstraintsAction); + } + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/ContextAction.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/ContextAction.java new file mode 100644 index 00000000..c86858d8 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/ContextAction.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.actions; + +import java.util.List; + +import org.eclipse.jface.action.Action; +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; + + +/** + * Context / selection dependent action + * + * @author Marko Luukkainen + * + */ +public abstract class ContextAction extends Action { + protected ThreeDimensionalEditorBase parent; + + public ContextAction(ThreeDimensionalEditorBase parent) { + this.parent = parent; + init(); + } + + /** + * Initialization + */ + public void init(){}; + + /** + * Runs the action + */ + public abstract void run(); + + /** + * Used to check if action is usable for given resources + * @param resources + * @return + */ + public abstract boolean usable(Graph graph, List resources); + + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/ContextActionFactory.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/ContextActionFactory.java new file mode 100644 index 00000000..ce6638aa --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/ContextActionFactory.java @@ -0,0 +1,20 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.actions; + +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; + + +public interface ContextActionFactory { + + + public ContextAction createAction(ThreeDimensionalEditorBase editor); +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/ContextActionRegistry.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/ContextActionRegistry.java new file mode 100644 index 00000000..bb8ffbce --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/ContextActionRegistry.java @@ -0,0 +1,54 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.actions; + +import java.util.ArrayList; +import java.util.List; + +import org.simantics.utils.ui.plugin.Extension; +import org.simantics.utils.ui.plugin.ExtensionLoader; + + + +public class ContextActionRegistry { + /* + private static ContextActionRegistry instance; + public final static String ELEMENT_NAME = "ContextAction"; + public final static String NAME_SPACE = "org.simantics.proconf.g3d"; + public final static String EP_NAME = "contextaction"; + + private ExtensionLoader loader; + + private ContextActionRegistry() { + loader = new ExtensionLoader(ELEMENT_NAME, NAME_SPACE, EP_NAME); + } + + public static ContextActionRegistry getInstance() { + if (instance==null) instance = new ContextActionRegistry(); + return instance; + } + + public Extension[] getExtensions() { + return loader.getExtensions(); + } + + + public static ContextActionFactory[] getActions(String editorID) { + List list = new ArrayList(); + for (Extension e : getInstance().getExtensions()) { + if(e.getStringField("editorid").compareTo(editorID) == 0) { + list.add(e.getInstance()); + } + } + return list.toArray(new ContextActionFactory[0]); + } + */ +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/FocusAction.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/FocusAction.java new file mode 100644 index 00000000..7893f230 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/FocusAction.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.actions; + +import java.util.Collection; +import java.util.List; + +import javax.vecmath.Vector3d; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.layer0.utils.IEntity; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.proconf.g3d.Activator; +import org.simantics.proconf.g3d.Resources; +import org.simantics.proconf.g3d.base.G3DTools; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.common.OrbitalCamera; +import org.simantics.proconf.g3d.stubs.Tuple3; + +public class FocusAction extends ContextAction{ + + private OrbitalCamera camera; + + Vector3d focusPoint = null; + + public FocusAction(ThreeDimensionalEditorBase parent) { + super(parent); + camera = parent.getCamera(); + } + + public void init() { + this.setText("Focus"); + this.setToolTipText("Focus"); + this.setImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/eye.png")); + } + + + + @Override + public boolean usable(Graph graph,List resources) { + if (resources.size() != 1) + return false; + IEntity t = EntityFactory.create(graph, resources.get(0)); + + if (t.isInstanceOf(Resources.g3dResource.G3DNode)) { + Collection p = t.getRelatedObjects(Resources.g3dResource.HasWorldPosition); + if (p == null || p.size() != 1) + return false; + else + //focusPoint = new Vector3d(G3DTools.getPoint(new Position(graph,p.iterator().next().getResource()))); + focusPoint = new Vector3d(G3DTools.getPoint(new Tuple3(graph,p.iterator().next().getResource()))); + } + return true; + } + + public void run() { + camera.setTarget(focusPoint); + parent.setViewChanged(true); + } + + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/InteractiveAction.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/InteractiveAction.java new file mode 100644 index 00000000..a7974345 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/InteractiveAction.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.actions; + +import org.eclipse.jface.action.IToolBarManager; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.input.InputProvider; + + + +/** + * Context / selection dependent action that requires user's interaction + * + * @author Marko Luukkainen + * + */ +public abstract class InteractiveAction extends ContextAction { + protected InputProvider input; + + public InteractiveAction(ThreeDimensionalEditorBase parent) { + super(parent); + input = parent.getInputProvider(); + } + + public abstract void update() ; + + /** + * Activates the action + */ + public abstract void activate(); + + /** + * Deactivates / ends the action + */ + public abstract void deactivate(); + + /** + * Activates the action in the viewer. Normally there's no need to override this method. + */ + public final void run() { + parent.setCurrentAction(this); + } + + /** + * This method is used to end the action, call this from update(). + * + */ + public void end() { + parent.setCurrentAction(parent.getDefaultAction()); + } + + public void fillToolBar(IToolBarManager manager) { + + } + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/ReadAction.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/ReadAction.java new file mode 100644 index 00000000..36fcc4bf --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/ReadAction.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.actions; + +import org.simantics.db.Graph; +import org.simantics.db.GraphRequest; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Session; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; + +public abstract class ReadAction extends ContextAction { + boolean sync; + public ReadAction(ThreeDimensionalEditorBase parent, boolean sync) { + super(parent); + this.sync = sync; + } + + @Override + public final void run() { + Session session = parent.getSession(); + if(!canActivate()) { + return; + } + GraphRequest r = new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + doChanges(g); + return GraphRequestStatus.transactionComplete(); + } + }; + if (sync) { + session.syncRead(r); + } else { + session.asyncRead(r); + } + } + + public abstract void doChanges(Graph graph) throws Exception; + + public boolean canActivate() { + return true; + } +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/ReadInteractiveAction.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/ReadInteractiveAction.java new file mode 100644 index 00000000..9bd972c6 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/ReadInteractiveAction.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.actions; + +import org.simantics.db.Graph; +import org.simantics.db.GraphRequest; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Session; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; + +public abstract class ReadInteractiveAction extends InteractiveAction { + boolean sync; + + public ReadInteractiveAction(ThreeDimensionalEditorBase parent, boolean sync) { + super(parent); + this.sync = sync; + } + + @Override + public final void update(){ + Session session = parent.getSession(); + GraphRequest r = new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + doChanges(g); + return GraphRequestStatus.transactionComplete(); + } + }; + if (sync) { + session.syncRead(r); + } else { + session.asyncRead(r); + } + } + + + public abstract void doChanges(Graph graph) throws Exception; + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/RemoveAction.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/RemoveAction.java new file mode 100644 index 00000000..ac9bdfa4 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/RemoveAction.java @@ -0,0 +1,56 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.actions; + +import java.util.List; + +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Resource; +import org.simantics.layer0.utils.IEntity; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.proconf.g3d.Activator; +import org.simantics.proconf.g3d.Resources; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.common.StructuredResourceSelection; + +public class RemoveAction extends WriteAction { + + public RemoveAction(ThreeDimensionalEditorBase parent) { + super(parent,false); + } + + public void init() { + setText("Remove"); + setToolTipText("Remove the object"); + this.setImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/delete.png")); + } + public GraphRequestStatus doChanges(Graph graph) { + StructuredResourceSelection sel = parent.getSelectionAdapter().getCurrentSelection(); + List res = sel.getSelectionList(); + for (Resource r : res) { + IEntity t = EntityFactory.create(graph, r); + if (t.isInstanceOf(Resources.g3dResource.G3DNode)) { + IEntity parentNode = t.getSingleRelatedObject(Resources.g3dResource.HasParent); + parentNode.removeStatement(Resources.g3dResource.HasChild, t); + } + + } + return GraphRequestStatus.transactionComplete(); + + } + + @Override + public boolean usable(Graph graph,List resources) { + return resources.size() > 0; + } + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/RotateAction.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/RotateAction.java new file mode 100644 index 00000000..fe6fc71b --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/RotateAction.java @@ -0,0 +1,453 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.actions; + +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.vecmath.AxisAngle4d; +import javax.vecmath.AxisAngle4f; +import javax.vecmath.Quat4d; +import javax.vecmath.Vector3d; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IToolBarManager; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequest; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Session; +import org.simantics.db.Resource; +import org.simantics.layer0.utils.IEntity; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.proconf.g3d.Activator; +import org.simantics.proconf.g3d.Resources; +import org.simantics.proconf.g3d.base.G3DTools; +import org.simantics.proconf.g3d.base.JmeRenderingComponent; +import org.simantics.proconf.g3d.base.MathTools; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.base.VecmathJmeTools; +import org.simantics.proconf.g3d.common.OrbitalCamera; +import org.simantics.proconf.g3d.gizmo.RotateGizmo; +import org.simantics.proconf.g3d.scenegraph.IGraphicsNode; +import org.simantics.proconf.g3d.stubs.G3DNode; + +public class RotateAction extends WriteInteractiveAction { + + private JmeRenderingComponent component; + + private RotateGizmo gizmo; + + private OrbitalCamera camera; + + private Map rotations = new HashMap(); + + private int steps; + private double angles[]; + + private Action csAction; + private boolean worldCoord = true; + private IToolBarManager manager; + + private List mos; + AxisAngle4d aa; + Quat4d q; + + public RotateAction(ThreeDimensionalEditorBase parent) { + super(parent,true); + component = parent.getRenderingComponent(); + camera = parent.getCamera(); + gizmo = new RotateGizmo(component.getDisplaySystem().getRenderer()); + csAction = new Action("World",Action.AS_CHECK_BOX) { + public void run() { + GraphRequest r = new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + setWorldCoord(g,!isChecked()); + return GraphRequestStatus.transactionComplete(); + } + }; + RotateAction.this.parent.getSession().asyncRead(r); + + } + }; + } + + public void init() { + this.setText("Rotate"); + this.setToolTipText("Rotate the object"); + this.setImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/rotate.png")); + steps = 36; + angles = new double[steps+1]; + for (int i = 0; i < angles.length; i++) { + angles[i] = - Math.PI + (Math.PI * i * 2.0 / steps); + } + } + + @Override + public boolean usable(Graph graph, List resources) { + if (resources.size() == 0) + return false; + for (Resource r : resources) { + IEntity t = EntityFactory.create(graph,r); + if (t.isInstanceOf(Resources.g3dResource.G3DNode)) { + Collection p = t.getRelatedObjects(Resources.g3dResource.HasLocalOrientation); + if (p == null || p.size() != 1) + return false; + } + + } + return true; + + } + + @Override + public void deactivate() { + inputType = InputType.NONE; + parent.setGizmo(null); + mos = null; + + } + + public void fillToolBar(IToolBarManager manager) { + super.fillToolBar(manager); + this.manager = manager; + csAction.setChecked(!worldCoord); + manager.add(csAction); + + } + + private void setWorldCoord(Graph graph,boolean b) { + if (worldCoord == b) + return; + worldCoord = b; + updateWorldCoord(graph); + } + + private void updateWorldCoord(Graph graph) { + if (worldCoord) { + csAction.setText("World"); + gizmo.setRotation(new AxisAngle4f()); + aa = null; + q = null; + } else { + csAction.setText("Local"); + aa = G3DTools.getOrientation(mos.get(0).getParent().getG3DNode(graph).getWorldOrientation()); + if (aa == null) + aa = new AxisAngle4d(); + gizmo.setRotation(new AxisAngle4f(aa)); + q = new Quat4d(); + q.set(aa); + } + if (manager != null) + manager.update(true); + this.parent.setViewChanged(true); + } + + @Override + public void activate() { + + Session session = parent.getSession(); + + GraphRequest r = new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + parent.setGizmo(gizmo); + + component.getNoShadowRoot().attachChild(gizmo.getNode()); + updateGizmo(); + + String text = ""; + mos = parent.getSelectionAdapter().getSelectedObjects(); + rotations = new HashMap(); + for (IGraphicsNode mo : mos) { + G3DNode n = mo.getG3DNode(g); + rotations.put(mo,G3DTools.getOrientation(n.getLocalOrientation())); + text += G3DTools.getOrientation(n.getLocalOrientation()) + " " + MathTools.getEuler(G3DTools.getOrientation(mo.getG3DNode(g).getLocalOrientation())) + " "; + } + setInfoText(text); + parent.setViewChanged(true); + inputType = InputType.NONE; + return GraphRequestStatus.transactionComplete(); + } + }; + + session.syncRead(r); + + + } + + + private Vector3d getRotationAxis() { + switch (gizmo.getSelected()) { + case RotateGizmo.X: + return new Vector3d(1.0,0.0,0.0); + case RotateGizmo.Y: + return new Vector3d(0.0,1.0,0.0); + case RotateGizmo.Z: + return new Vector3d(0.0,0.0,1.0); + case RotateGizmo.XYZ: + Vector3d axis = camera.getUnNormalizedHeading(); + axis.normalize(); + return axis; + default: + return null; + } + } + private double prevS = 0.0; + + private Vector3d i = new Vector3d(); + private Vector3d j = new Vector3d(); + private double prevAngle = 0; + + enum InputType{INTERSECT,NONINTERSECT,KEY,NONE}; + InputType inputType; + private boolean useStep = false; + + @Override + public void doChanges(Graph graph) throws Exception { + + if (input.mousePressed()) { + Vector3d axis = getRotationAxis(); + if (axis != null) { + if (!worldCoord) { + MathTools.rotate(q, axis, axis); + } + Vector3d o = new Vector3d(); + Vector3d d = new Vector3d(); + parent.createPickRay(o, d); + Vector3d p = gizmo.getPosition(); + double s[] = new double[2]; + Vector3d i2 = new Vector3d(); + if ((input.pressModifiers() & MouseEvent.CTRL_MASK) > 0) { + useStep = true; + } else { + useStep = false; + } + if (MathTools.intersectStraightPlane(o, d, p, axis, i2, s) && Math.abs(d.dot(axis)) > 0.2) + inputType = InputType.INTERSECT; + else + inputType = InputType.NONINTERSECT; + + + if (inputType == InputType.INTERSECT) { + // picking ray and plane defined by gizmo's center point and + // rotation axis can intersect + // vector from center point to intersection point + i2.sub(p); + // creating vectors i and j that are lying on the plane and + // are perpendicular + // vectors are used to calculate polar coordinate for + // intersection point + j.set(i2); + i.cross(j, axis); + double angleI = i2.angle(i); + double angleJ = i2.angle(j); + prevAngle = Math.atan2(Math.cos(angleJ), Math.cos(angleI)); + } else { + // picking ray and plane defined by gizmo's center point and + // rotation axis are parallel, + // so we'll use cross product of rotation axis and picking + // ray to detect amount of rotation + i.cross(d, axis); + MathTools.intersectStraightStraight(o, d, p, i, new Vector3d(), new Vector3d(), s); + prevS = s[1]; + } + } + + + } + if (input.mouseClicked()) { + end(); + return; + } + Vector3d axis = null; + if (input.keyPressed(KeyEvent.VK_LEFT)) { + inputType = InputType.KEY; + axis = new Vector3d(0.0,1.0,0.0); + } else if (input.keyPressed(KeyEvent.VK_RIGHT)) { + inputType = InputType.KEY; + axis = new Vector3d(0.0,-1.0,0.0); + } else if (input.keyPressed(KeyEvent.VK_UP)) { + inputType = InputType.KEY; + axis = new Vector3d(1.0,0.0,0.0); + } else if (input.keyPressed(KeyEvent.VK_DOWN)) { + inputType = InputType.KEY; + axis = new Vector3d(-1.0,0.0,0.0); + } else if (!input.mouseDragged()) { + parent.getDefaultAction().update(); + return; + } + parent.setViewChanged(true); + + + updateGizmo(); + List mos = parent.getSelectionAdapter().getSelectedObjects(); + if (inputType != InputType.KEY) + axis = getRotationAxis(); + if (axis == null) { + parent.getDefaultAction().update(); + return; + } + Vector3d taxis = null; + if (!worldCoord) { + taxis = new Vector3d(axis); + MathTools.rotate(q, axis, axis); + } + String text = ""; + if (inputType == InputType.INTERSECT) { + Vector3d o = new Vector3d(); + Vector3d d = new Vector3d(); + parent.createPickRay(o, d); + Vector3d p = gizmo.getPosition(); + double s[] = new double[2]; + Vector3d i2 = new Vector3d(); + MathTools.intersectStraightPlane(o, d, p, axis, i2, s); + i2.sub(p); + double angleI = i2.angle(i); + double angleJ = i2.angle(j); + double angle = Math.atan2(Math.cos(angleJ), Math.cos(angleI)); + if(!worldCoord) + axis = taxis; + if (false && useStep) { + for (IGraphicsNode mo : mos) { + G3DTools.setOrientation(mo.getG3DNode(graph).getLocalOrientation(), rotations.get(mo)); + // FIXME : commit + G3DTools.multiplyOrientation(mo.getG3DNode(graph).getWorldOrientation(), new AxisAngle4d(axis,angle-prevAngle)); + //mo.setRotation(rotations.get(mo)); + //mo.modifyWorldRotation(axis, angle - prevAngle); + AxisAngle4d aa = G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation()); + rotations.put(mo, aa); + prevAngle = angle; + Vector3d euler = MathTools.getEuler(aa); + euler.x = roundAngle(euler.x); + euler.y = roundAngle(euler.y); + euler.z = roundAngle(euler.z); + aa = MathTools.getFromEuler2(euler); + G3DTools.setOrientation(mo.getG3DNode(graph).getLocalOrientation(), aa); + //mo.setRotation(aa); + Vector3d e = MathTools.getEuler(G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation())); + e.scale(180.0/Math.PI); + text += G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation()) + " " + e + " "; + } + } else { + for (IGraphicsNode mo : mos) { + if (worldCoord) + G3DTools.multiplyOrientation + (mo.getG3DNode(graph).getWorldOrientation(), new AxisAngle4d(axis,angle-prevAngle)); + else + G3DTools.multiplyOrientation(mo.getG3DNode(graph).getLocalOrientation(), new AxisAngle4d(axis,angle-prevAngle)); + text += G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation()) + " " + MathTools.getEuler(G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation())) + " "; + } + prevAngle = angle; + } + + } else if (inputType == InputType.NONINTERSECT){ + Vector3d o = new Vector3d(); + Vector3d d = new Vector3d(); + parent.createPickRay(o, d); + Vector3d p = gizmo.getPosition(); + double s[] = new double[2]; + MathTools.intersectStraightStraight(o, d, p, i, new Vector3d(), new Vector3d(), s); + if(!worldCoord) + axis = taxis; + if (false && useStep) { + for (IGraphicsNode mo : mos) { + G3DTools.setOrientation(mo.getG3DNode(graph).getLocalOrientation(), rotations.get(mo)); + G3DTools.multiplyOrientation(mo.getG3DNode(graph).getWorldOrientation(), new AxisAngle4d(axis,s[1] - prevS)); + //mo.setRotation(rotations.get(mo)); + //mo.modifyWorldRotation(axis, s[1] - prevS); + AxisAngle4d aa = G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation()); + rotations.put(mo, aa); + Vector3d euler = MathTools.getEuler(aa); + euler.x = roundAngle(euler.x); + euler.y = roundAngle(euler.y); + euler.z = roundAngle(euler.z); + aa = MathTools.getFromEuler2(euler); + prevS = s[1]; + G3DTools.setOrientation(mo.getG3DNode(graph).getLocalOrientation(), aa); + //mo.setRotation(aa); + Vector3d e = MathTools.getEuler(G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation())); + e.scale(180.0/Math.PI); + text += G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation()) + " " + e + " "; + } + } else { + for (IGraphicsNode mo : mos) { + if (worldCoord) + G3DTools.multiplyOrientation(mo.getG3DNode(graph).getWorldOrientation(), new AxisAngle4d(axis,s[1] - prevS)); + else + G3DTools.multiplyOrientation(mo.getG3DNode(graph).getLocalOrientation(), new AxisAngle4d(axis,s[1] - prevS)); + text += G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation()) + " " + MathTools.getEuler(G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation())) + " "; + } + prevS = s[1]; + + } + + } else { + for (IGraphicsNode mo : mos) { + if (worldCoord) + G3DTools.multiplyOrientation(mo.getG3DNode(graph).getWorldOrientation(), new AxisAngle4d(axis,Math.PI * 0.5)); + else + G3DTools.multiplyOrientation(mo.getG3DNode(graph).getLocalOrientation(), new AxisAngle4d(axis,Math.PI * 0.5)); + text += G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation()) + " " + MathTools.getEuler(G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation())) + " "; + } + } + setInfoText(text); + + } + /* + private double roundAngle(double current, double modify) { + double angle = roundAngle(current+modify); + if (Double.isNaN(angle)) { + angle = current+modify; + } + //System.out.println(angle + " " + (current+modify)); + return angle; + } + */ + + private double roundAngle(double angle) { + while (angle < - Math.PI) + angle += Math.PI*2.0; + while (angle > Math.PI) + angle -= Math.PI*2.0; + + + int index = 0; + while (angle > angles[index]) + index++; + if (index == 0) { + angle = angles[0]; + } else { + double d = angle - angles[index - 1]; + double d2 = angles[index] - angle; + if (d < d2) + angle = angles[index - 1]; + else + angle = angles[index]; + } + return angle; + } + + private void updateGizmo() { + List mos = parent.getSelectionAdapter().getSelectedObjects(); + //gizmo.update(XithTools.getPosition(mos.get(0).getGroup()),camera.getCameraPos(),component); + gizmo.update(VecmathJmeTools.getD(mos.get(0).getGroup().getWorldTranslation()),camera.getCameraPos(),component); + } + + public void setInfoText(String text) { + + } +} \ No newline at end of file diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/TranslateAction.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/TranslateAction.java new file mode 100644 index 00000000..d4630a1c --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/TranslateAction.java @@ -0,0 +1,422 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.actions; + +import java.awt.event.MouseEvent; +import java.math.BigDecimal; +import java.util.Collection; +import java.util.List; + +import javax.vecmath.AxisAngle4d; +import javax.vecmath.AxisAngle4f; +import javax.vecmath.Point3d; +import javax.vecmath.Quat4d; +import javax.vecmath.Vector3d; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IToolBarManager; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequest; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Resource; +import org.simantics.layer0.utils.IEntity; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.proconf.g3d.Activator; +import org.simantics.proconf.g3d.Resources; +import org.simantics.proconf.g3d.base.G3DTools; +import org.simantics.proconf.g3d.base.MathTools; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.gizmo.TransformGizmo; +import org.simantics.proconf.g3d.scenegraph.IGraphicsNode; +import org.simantics.proconf.g3d.stubs.Orientation; +import org.simantics.proconf.g3d.stubs.Position; + + +public class TranslateAction extends ConstrainedTransformAction { + + + private TransformGizmo gizmo; + + private double istep = 10.0; + private int decimals = 2; + + + private Action csAction; + List mos = null; + + private boolean worldCoord = true; + + + private AxisAngle4d aa; + private Quat4d q; + + public TranslateAction(ThreeDimensionalEditorBase parent) { + super(parent); + + csAction = new Action("World",Action.AS_CHECK_BOX) { + public void run() { + GraphRequest r = new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + setWorldCoord(g,!isChecked()); + return GraphRequestStatus.transactionComplete(); + } + }; + TranslateAction.this.parent.getSession().asyncRead(r); + + } + }; + gizmo = new TransformGizmo(component.getDisplaySystem().getRenderer()); + } + + public void init() { + this.setText("Translate"); + this.setToolTipText("Translate the object"); + this.setImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/translate.png")); + } + + @Override + public boolean usable(Graph graph, List resources) { + if (resources.size() == 0) + return false; + for (Resource r : resources) { + IEntity t = EntityFactory.create(graph,r); + if (t.isInstanceOf(Resources.g3dResource.G3DNode)) { + Collection p = t.getRelatedObjects(Resources.g3dResource.HasLocalPosition); + if (p == null || p.size() != 1) + return false; + } + + } + return true; + + } + + @Override + public void deactivate() { + super.deactivate(); + parent.setGizmo(null); + mos = null; + } + + private void setWorldCoord(Graph graph,boolean b) { + if (worldCoord == b) + return; + worldCoord = b; + updateWorldCoord(graph); + } + + private void updateWorldCoord(Graph graph) { + if (worldCoord) { + csAction.setText("World"); + gizmo.setRotation(new AxisAngle4f()); + aa = null; + q = null; + } else { + csAction.setText("Local"); + Orientation o = mos.get(0).getParent().getG3DNode(graph).getWorldOrientation(); + if (o == null) { + aa = new AxisAngle4d(); + } else { + aa = G3DTools.getOrientation(o); + } + + gizmo.setRotation(new AxisAngle4f(aa)); + q = new Quat4d(); + q.set(aa); + } +// if (manager != null) +// parent.getRenderingComposite().getDisplay().asyncExec(new Runnable() { +// public void run() { +// manager.update(true); +// } +// }); + + this.parent.setViewChanged(true); + } + + public void fillToolBar(IToolBarManager manager) { + super.fillToolBar(manager); + csAction.setChecked(!worldCoord); + manager.add(csAction); + } + + @Override + public void activate() { + GraphRequest r = new GraphRequestAdapter() { + public GraphRequestStatus perform(Graph g) throws Exception { + parent.setGizmo(gizmo); + + updateGizmo(g); + + component.getNoShadowRoot().attachChild(gizmo.getNode()); + + String text = ""; + mos = parent.getSelectionAdapter().getSelectedObjects(); + for (IGraphicsNode mo : mos) { + if (worldCoord) + text += G3DTools.getVector(mo.getG3DNode(g).getWorldPosition()) + " ";//mo.getWorldPosition() + " "; + else + text += G3DTools.getVector(mo.getG3DNode(g).getLocalPosition()) + " "; + } + final String fText = text; + parent.getRenderingComposite().getDisplay().asyncExec(new Runnable() { + public void run() { + setInfoText(fText); + } + }); + + Resource r[] = new Resource[mos.size()]; + for (int i = 0; i < mos.size(); i++) { + r[i] = mos.get(i).getResource(); + } + + TranslateActionConstraints.addConstraints(r, detector); + updateWorldCoord(g); + return GraphRequestStatus.transactionComplete(); + }; + + }; + parent.getSession().asyncRead(r); + + } + + Vector3d getTranslate(Graph graph) { + return getTranslate(graph,new Vector3d()); + } + + Vector3d getTranslate(Graph graph,Vector3d offset) { + Vector3d translate = new Vector3d(); + Vector3d o = new Vector3d(); + Vector3d d = new Vector3d(); + parent.createPickRay(o, d); + Vector3d p = G3DTools.getVector(mos.get(0).getG3DNode(graph).getWorldPosition());//gizmo.getPosition(); + Vector3d dir = null; + switch (gizmo.getSelected()) { + case TransformGizmo.XYZ : + Vector3d normal = camera.getUnNormalizedHeading(); + if(!worldCoord) + MathTools.rotate(q, normal, normal); + normal.normalize(); + double s[] = new double[1]; + Vector3d r = new Vector3d(); + if (MathTools.intersectStraightPlane(o, d, p, normal, r)) { + r.sub(p); + translate.x = r.x; + translate.y = r.y; + translate.z = r.z; + } + break; + case TransformGizmo.X : + dir = new Vector3d(1.0,0.0,0.0); + if(!worldCoord) + MathTools.rotate(q, dir, dir); + Vector3d i1 = new Vector3d(); + Vector3d i2 = new Vector3d(); + s = new double[2]; + MathTools.intersectStraightStraight( p, dir,o, d, i2, i1,s); + translate.x = s[0]; + + break; + case TransformGizmo.Y : + dir = new Vector3d(0.0,1.0,0.0); + if(!worldCoord) + MathTools.rotate(q, dir, dir); + i1 = new Vector3d(); + i2 = new Vector3d(); + s = new double[2]; + MathTools.intersectStraightStraight( p, dir,o, d, i2, i1,s); + translate.y = s[0]; + break; + case TransformGizmo.Z : + dir = new Vector3d(0.0,0.0,1.0); + if(!worldCoord) + MathTools.rotate(q, dir, dir); + i1 = new Vector3d(); + i2 = new Vector3d(); + s = new double[2]; + MathTools.intersectStraightStraight( p, dir,o, d, i2, i1,s); + translate.z = s[0]; + break; + case TransformGizmo.XY : + normal = new Vector3d(0.0,0.0,1.0); + if(!worldCoord) + MathTools.rotate(q, normal, normal); + r = new Vector3d(); + if (MathTools.intersectStraightPlane(o, d, p, normal, r)) { + r.sub(p); + translate.x = r.x; + translate.y = r.y; + } + break; + case TransformGizmo.XZ : + normal = new Vector3d(0.0,1.0,0.0); + if(!worldCoord) + MathTools.rotate(q, normal, normal); + r = new Vector3d(); + if (MathTools.intersectStraightPlane(o, d, p, normal, r)) { + r.sub(p); + translate.x = r.x; + translate.z = r.z; + } + break; + case TransformGizmo.YZ : + normal = new Vector3d(1.0,0.0,0.0); + if(!worldCoord) + MathTools.rotate(q, normal, normal); + r = new Vector3d(); + if (MathTools.intersectStraightPlane(o, d, p, normal, r)) { + r.sub(p); + translate.y = r.y; + translate.z = r.z; + } + break; + default : + + return null; + } + translate.sub(offset); + + if (useConstraints && dir != null) { + switch (gizmo.getSelected()) { + case TransformGizmo.X: + case TransformGizmo.Y: + case TransformGizmo.Z: + Vector3d t = new Vector3d(translate); + // TODO : to the test against all translated objects and snap to closest one + Point3d pos = G3DTools.getPoint(mos.get(0).getG3DNode(graph).getWorldPosition()); + t.add(pos); + Point3d snap = detector.getPointSnap2(t, dir); + if (snap != null) { + // System.out.print("t: " + translate); + translate = new Vector3d(snap); + translate.sub(pos); + // System.out.println(" " + translate); + } + break; + + } + } + return translate; + } + + Vector3d prevTranslate = new Vector3d(); + + @Override + public void doChanges(Graph graph) throws Exception { + if (input.mousePressed()) { + boolean b = useConstraints; + useConstraints = false; + prevTranslate = getTranslate(graph); + useConstraints = b; + } + if (input.mouseClicked()) { + end(); + return; + } + if (!input.mouseDragged()) { + parent.getDefaultAction().update(); + return; + } + detector.clearConstraintHighlights(); + parent.setViewChanged(true); + + + + Vector3d translate = getTranslate(graph,prevTranslate); + + if (translate == null) { + //cameraRotateAction.update(); + parent.getDefaultAction().update(); + updateGizmo(graph); + return; + } + //translate.sub(prevTranslate); + + if ((input.dragModifiers() & MouseEvent.CTRL_MASK) > 0) { + String text = ""; + for (IGraphicsNode mo : mos) { + + Point3d p; + if (worldCoord) + p = G3DTools.getPoint(mo.getG3DNode(graph).getWorldPosition());//mo.getWorldPosition(); + else + p = G3DTools.getPoint(mo.getG3DNode(graph).getLocalPosition()); + p.add(translate); + if (gizmo.getSelected() == TransformGizmo.X || gizmo.getSelected() == TransformGizmo.XY || gizmo.getSelected() == TransformGizmo.XZ || gizmo.getSelected() == TransformGizmo.XYZ) { + p.x = Math.round(istep * p.x) / istep; + BigDecimal bx = new BigDecimal(p.x); + bx.setScale(decimals, BigDecimal.ROUND_HALF_UP); + p.x = bx.doubleValue(); + } + if (gizmo.getSelected() == TransformGizmo.Y || gizmo.getSelected() == TransformGizmo.XY || gizmo.getSelected() == TransformGizmo.YZ || gizmo.getSelected() == TransformGizmo.XYZ) { + p.y = Math.round(istep * p.y) / istep; + BigDecimal by = new BigDecimal(p.y); + by.setScale(decimals, BigDecimal.ROUND_HALF_UP); + p.y = by.doubleValue(); + } + if (gizmo.getSelected() == TransformGizmo.Z || gizmo.getSelected() == TransformGizmo.YZ || gizmo.getSelected() == TransformGizmo.XZ || gizmo.getSelected() == TransformGizmo.XYZ) { + p.z = Math.round(istep * p.z) / istep; + BigDecimal bz = new BigDecimal(p.z); + bz.setScale(decimals, BigDecimal.ROUND_HALF_UP); + p.z = bz.doubleValue(); + } + text += p + " "; + if (worldCoord) + G3DTools.setTuple3(mo.getG3DNode(graph).getWorldPosition(), p); + else + G3DTools.setTuple3(mo.getG3DNode(graph).getLocalPosition(), p); + //mo.setWorldTranslation(p); + + } + if (useConstraints) + text+=detector.getSnapString(); + setInfoText(text); + + } else { + String text = ""; + for (IGraphicsNode mo : mos) { + Position pos; + if (worldCoord) { + pos = mo.getG3DNode(graph).getWorldPosition(); + } else { + pos = mo.getG3DNode(graph).getLocalPosition(); + } + Point3d p = G3DTools.getPoint(pos); + p.add(translate); + text += p; + G3DTools.setTuple3(pos, p); + } + if (useConstraints) + text+=detector.getSnapString(); + setInfoText(text); + // parent.getGraph().commitChanges(CommitMessage.CHANGE_MESSAGE); + } + updateGizmo(graph); + + } + + protected void updateGizmo(Graph graph) { + List mos = parent.getSelectionAdapter().getSelectedObjects(); + if (mos.size() == 0) { + end(); + return; + } + gizmo.update(G3DTools.getVector(mos.get(0).getG3DNode(graph).getWorldPosition()),camera.getCameraPos(),component); + + } + + public void setInfoText(String text) { + + } + +} \ No newline at end of file diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/TranslateActionConstraints.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/TranslateActionConstraints.java new file mode 100644 index 00000000..c1a7236d --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/TranslateActionConstraints.java @@ -0,0 +1,147 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.actions; + +import org.simantics.db.Resource; +import org.simantics.proconf.g3d.base.ConstraintDetector; + + +/** + * Temporary class to handle "Automatic" constraints for translation + * TODO : create extension point / extension that can provide constraints + * TODO : how to override previously added constraints ? + * + * @author Marko Luukkainen + * + */ +public class TranslateActionConstraints { + + + public static void addConstraints(Resource translated[], ConstraintDetector detector) { + detector.clearConstraints(); + // these must be provided through extension point ! +// if (isElbow(translated)) { +// addElbowConstraints(translated, detector); +// } else if (isPipeControlPoint(translated)) { +// addPipeControlPointConstraints(translated, detector); +// } else if (isEndComponent(translated)) { +// addEndComponentConstraints(translated, detector); +// } + + + } + + /* + * These methods must be inserted into extension + */ + +// private static boolean isElbow(Resource translated[]) { +// for (Resource r : translated) { +// if (!r.isInstanceOf(GlobalIdMap.get(PSK3DModelingOntologyMapping.ELBOW))) { +// return false; +// } +// } +// return true; +// } +// +// private static boolean isEndComponent(Resource translated[]) { +// for (Resource r : translated) { +// if (!r.isInstanceOf(GlobalIdMap.get(PSK3DModelingOntologyMapping.END_COMPONENT))) { +// return false; +// } +// } +// return true; +// } +// +// private static boolean isPipeControlPoint(Resource translated[]) { +// for (Resource r : translated) { +// if (!r.isInstanceOf(GlobalIdMap.get(PSK3DModelingOntologyMapping.PIPE_CONTROL_POINT))) { +// return false; +// } +// } +// return true; +// } +// +// private static void addElbowConstraints(Resource translated[], ConstraintDetector detector) { +// Set res = new HashSet(); +// // add all controlpoints connected to every elbow's controlpoint +// for (Resource r : translated) { +// Elbow elbow = ElbowFactory.create(r); +// PipeControlPoint p = elbow.getHasControlPoint(); +// PipeControlPoint next = PipingTools.findNextEnd(p); +// PipeControlPoint previous = PipingTools.findPreviousEnd(p); +// if (next != null) +// res.add(next.getResource()); +// if (previous != null) +// res.add(previous.getResource()); +// +// } +// // remove all controlpoints that are elbows' controlpoints +// for (Resource r : translated) { +// Elbow elbow = ElbowFactory.create(r); +// res.remove(elbow.getHasControlPoint().getResource()); +// } +// for (Resource r : res) { +// PipeControlPoint p = PipeControlPointFactory.create(r); +// detector.addContraintPoint(GraphicsNodeTools.getPoint(p.getLocalPosition())); +// } +// } +// +// private static void addEndComponentConstraints(Resource translated[], ConstraintDetector detector) { +// Set res = new HashSet(); +// // add all controlpoints connected to every elbow's controlpoint +// for (Resource r : translated) { +// EndComponent elbow = EndComponentFactory.create(r); +// PipeControlPoint p = elbow.getHasControlPoint(); +// PipeControlPoint next = PipingTools.findNextEnd(p); +// PipeControlPoint previous = PipingTools.findPreviousEnd(p); +// if (next != null) +// res.add(next.getResource()); +// if (previous != null) +// res.add(previous.getResource()); +// +// } +// // remove all controlpoints that are elbows' controlpoints +// for (Resource r : translated) { +// EndComponent elbow = EndComponentFactory.create(r); +// res.remove(elbow.getHasControlPoint().getResource()); +// } +// for (Resource r : res) { +// PipeControlPoint p = PipeControlPointFactory.create(r); +// detector.addContraintPoint(GraphicsNodeTools.getPoint(p.getLocalPosition())); +// } +// } +// +// +// private static void addPipeControlPointConstraints(Resource translated[], ConstraintDetector detector) { +// Set res = new HashSet(); +// // add all controlpoints connected to every elbow's controlpoint +// for (Resource r : translated) { +// PipeControlPoint p = PipeControlPointFactory.create(r); +// PipeControlPoint next = PipingTools.findNextEnd(p); +// PipeControlPoint previous = PipingTools.findPreviousEnd(p); +// if (next != null) +// res.add(next.getResource()); +// if (previous != null) +// res.add(previous.getResource()); +// +// } +// // remove all controlpoints that are elbows' controlpoints +// for (Resource r : translated) { +// res.remove(r); +// } +// for (Resource r : res) { +// PipeControlPoint p = PipeControlPointFactory.create(r); +// detector.addContraintPoint(GraphicsNodeTools.getPoint(p.getLocalPosition())); +// } +// } + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/WriteAction.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/WriteAction.java new file mode 100644 index 00000000..58aa02a7 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/WriteAction.java @@ -0,0 +1,61 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.actions; + +import org.simantics.db.Graph; +import org.simantics.db.GraphRequest; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Session; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; + +public abstract class WriteAction extends ContextAction { + boolean sync; + public WriteAction(ThreeDimensionalEditorBase parent, boolean sync) { + super(parent); + this.sync = sync; + } + + @Override + public final void run() { + Session session = parent.getSession(); + if(!canActivate()) { + return; + } + GraphRequest r = new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + return doChanges(g); + } + + @Override + public void requestCompleted(GraphRequestStatus status) { + afterChanges(status); + } + }; + if (sync) { + session.syncWrite(r); + } else { + session.asyncWrite(r); + } + } + + public abstract GraphRequestStatus doChanges(Graph graph) throws Exception; + + public void afterChanges(GraphRequestStatus status) { + + } + + public boolean canActivate() { + return true; + } + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/WriteInteractiveAction.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/WriteInteractiveAction.java new file mode 100644 index 00000000..1208b75c --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/WriteInteractiveAction.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.actions; + +import org.simantics.db.Graph; +import org.simantics.db.GraphRequest; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Session; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; + + +public abstract class WriteInteractiveAction extends InteractiveAction { + boolean sync; + + public WriteInteractiveAction(ThreeDimensionalEditorBase parent, boolean sync) { + super(parent); + this.sync = sync; + } + + @Override + public final void update(){ + Session session = parent.getSession(); + GraphRequest r = new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + doChanges(g); + return GraphRequestStatus.transactionComplete(); + } + }; + if (sync) { + session.syncWrite(r); + } else { + session.asyncWrite(r); + } + } + + + public abstract void doChanges(Graph graph) throws Exception; + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/AbstractScalarInterpolator.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/AbstractScalarInterpolator.java new file mode 100644 index 00000000..5777f8e8 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/AbstractScalarInterpolator.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.animation; + +public abstract class AbstractScalarInterpolator implements ScalarInterpolator { + public void interpolate(double delta) { + throw new UnsupportedOperationException(""); + + } + + public void setTarget(Object target) { + throw new UnsupportedOperationException(""); + + } + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/Animatable.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/Animatable.java new file mode 100644 index 00000000..435cb0dd --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/Animatable.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.animation; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; + + +/** + * + * TODO : multiple animations + * TODO : remove setRandomAnimation + * + * @author Marko Luukkainen + * + */ +public interface Animatable { + + /** + * Sets used animation + * @param animation + */ + public boolean setAnimation(Graph graph, Resource animation); + + /** + * Updates animation + * @param delta + */ + public void animate(double delta, double frameTime); + + /** + * Sets random animation + * (Testing purposes) + */ + public boolean setRandomAnimation(Graph graph); + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/Animation.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/Animation.java new file mode 100644 index 00000000..9dd7f5ea --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/Animation.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.animation; + +import java.util.ArrayList; +import java.util.List; + +public class Animation { + private List interpolators = new ArrayList(); + + + public void addInterpolator(Interpolator i) { + interpolators.add(i); + } + + public void removeInterpolator(Interpolator i) { + interpolators.remove(i); + } + + public void interpolate(double delta) { + for (Interpolator i : interpolators) { + i.interpolate(delta); + } + } +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/AnimationController.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/AnimationController.java new file mode 100644 index 00000000..809ec605 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/AnimationController.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.animation; + +import org.simantics.db.Graph; + + +public interface AnimationController { + + public void updateAnimation(Graph graph, double frameTime); + public void setAnimatable(Animatable animatable); + public void addAnimatable(Animatable animatable); + public void dispose(); + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/AnimationSystem.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/AnimationSystem.java new file mode 100644 index 00000000..8085405a --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/AnimationSystem.java @@ -0,0 +1,94 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.animation; + +import java.util.ArrayList; +import java.util.List; + +import org.simantics.db.Graph; +import org.simantics.proconf.g3d.base.ScenegraphAdapter; + + +public class AnimationSystem { + private ScenegraphAdapter adapter; + private List animationControllers = new ArrayList(); + + private List listeners = new ArrayList(); + + private boolean pause = false; + + public AnimationSystem(ScenegraphAdapter adapter) { + if (adapter == null) + throw new IllegalArgumentException("ScenegraphAdapter must not be null"); + this.adapter = adapter; + } + + public void add(AnimationController controller) { + animationControllers.add(controller); + for (AnimationSystemListener l : listeners) + l.animationAdded(this, controller); + } + + public void addListener(AnimationSystemListener l) { + listeners.add(l); + } + + public void removeListener(AnimationSystemListener l) { + listeners.remove(l); + } + + public boolean isRunning() { + return animationControllers.size() > 0; + } + + public void pause() { + if (pause) + return; + pause = true; + for (AnimationSystemListener l : listeners) + l.animationPaused(this); + } + + public void play() { + if(!pause) + return; + pause = false; + for (AnimationSystemListener l : listeners) + l.animationPlay(this); + } + + public void stop() { + for (AnimationController c : animationControllers) + c.dispose(); + animationControllers.clear(); + for (AnimationSystemListener l : listeners) + l.animationStopped(this); + } + + public boolean isPause() { + return pause; + } + + public void run(Graph graph, double frameTime) { + if (pause) + return; + if (animationControllers.size() > 0) { + for (AnimationController c : animationControllers) + c.updateAnimation(graph, frameTime); + adapter.setChanged(true); + } + } + + public List getAnimationControllers() { + return animationControllers; + } + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/AnimationSystemListener.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/AnimationSystemListener.java new file mode 100644 index 00000000..f45c3b49 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/AnimationSystemListener.java @@ -0,0 +1,18 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.animation; + +public interface AnimationSystemListener { + public void animationStopped(AnimationSystem animationSystem); + public void animationPaused(AnimationSystem animationSystem); + public void animationPlay(AnimationSystem animationSystem); + public void animationAdded(AnimationSystem animationSystem, AnimationController animationController); +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/ChanneledColorInterpolator.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/ChanneledColorInterpolator.java new file mode 100644 index 00000000..5a80e834 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/ChanneledColorInterpolator.java @@ -0,0 +1,68 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.animation; + +import com.jme.renderer.ColorRGBA; +import com.jme.scene.state.MaterialState; + +public class ChanneledColorInterpolator implements Interpolator { + private ScalarInterpolator rInterpolator; + private ScalarInterpolator gInterpolator; + private ScalarInterpolator bInterpolator; + + //Material m = null; + MaterialState m = null; + int type = 1; + + public static final int AMBIENT = 0; + public static final int DIFFUSE = 1; + public static final int SPECULAR = 2; + public static final int EMISSIVE = 3; + + + public ChanneledColorInterpolator(ScalarInterpolator rInterpolator, ScalarInterpolator gInterpolator, ScalarInterpolator bInterpolator) { + this.rInterpolator = rInterpolator; + this.gInterpolator = gInterpolator; + this.bInterpolator = bInterpolator; + } + + public void interpolate(double delta) { + double r = rInterpolator.evaluate(delta); + double g = gInterpolator.evaluate(delta); + double b = bInterpolator.evaluate(delta); + + ColorRGBA c = new ColorRGBA((float)r, (float)g, (float)b,0.f); + switch (type) { + case AMBIENT : + m.setAmbient(c); + break; + case DIFFUSE: + m.setDiffuse(c); + break; + case SPECULAR: + m.setSpecular(c); + break; + case EMISSIVE: + m.setEmissive(c); + break; + } + } + + public void setTarget(Object target) { + // m = (Material)target; + m = (MaterialState)target; + } + + public void setType(int type) { + this.type = type; + } + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/ChanneledPositionInterpolator.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/ChanneledPositionInterpolator.java new file mode 100644 index 00000000..5b6aeb60 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/ChanneledPositionInterpolator.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.animation; + + +import com.jme.math.Vector3f; +import com.jme.scene.Node; + + +public class ChanneledPositionInterpolator implements Interpolator { + private ScalarInterpolator xInterpolator; + private ScalarInterpolator yInterpolator; + private ScalarInterpolator zInterpolator; + + Node node; + + public ChanneledPositionInterpolator(ScalarInterpolator xInterpolator, ScalarInterpolator yInterpolator, ScalarInterpolator zInterpolator) { + this.xInterpolator = xInterpolator; + this.yInterpolator = yInterpolator; + this.zInterpolator = zInterpolator; + } + + public void interpolate(double delta) { + double x = xInterpolator.evaluate(delta); + double y = yInterpolator.evaluate(delta); + double z = zInterpolator.evaluate(delta); + + node.setLocalTranslation(new Vector3f((float)x,(float)y,(float)z)); + } + + public void setTarget(Object target) { + node = (Node)target; + } + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/ConstantInterpolator.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/ConstantInterpolator.java new file mode 100644 index 00000000..5e273d1e --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/ConstantInterpolator.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.animation; + +public class ConstantInterpolator extends AbstractScalarInterpolator{ + double constant; + + + public ConstantInterpolator(double constant) { + this.constant = constant; + } + + public double evaluate(double delta) { + return constant; + } + + + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/Interpolator.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/Interpolator.java new file mode 100644 index 00000000..630434f6 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/Interpolator.java @@ -0,0 +1,18 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.animation; + +public interface Interpolator { + + public void interpolate(double delta); + public void setTarget(Object target); + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/ResourceAnimationController.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/ResourceAnimationController.java new file mode 100644 index 00000000..d359c341 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/ResourceAnimationController.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.animation; + +import java.util.ArrayList; +import java.util.List; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; + +public class ResourceAnimationController implements AnimationController { + List animatables = new ArrayList(); + + Resource source; + + public ResourceAnimationController(Resource source) { + this.source = source; + } + + public void addAnimatable(Animatable animatable) { + animatables.add(animatable); + + } + + public void setAnimatable(Animatable animatable) { + animatables.clear(); + animatables.add(animatable); + + } + + protected double getValue(Graph graph) { + //return PropertyUtils.getScalarDoubleValue(source); + return graph.getScalarDouble(source); + //source.getDoubleValue(); + } + + public void updateAnimation(Graph graph, double frameTime) { + double d = getValue(graph); + d = d - Math.floor(d); + if (d > 1.0) { + d = 1.0; + } else if (d < 0.0) { + d = 0.0; + } + for (Animatable a : animatables) + a.animate(d,frameTime); + } + + public void dispose() { + + } + + + + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/ScalarInterpolator.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/ScalarInterpolator.java new file mode 100644 index 00000000..afe75976 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/ScalarInterpolator.java @@ -0,0 +1,17 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.animation; + +public interface ScalarInterpolator extends Interpolator{ + + public double evaluate(double delta); + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/ScaledResourceAnimationController.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/ScaledResourceAnimationController.java new file mode 100644 index 00000000..c3562693 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/ScaledResourceAnimationController.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.animation; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; + +public class ScaledResourceAnimationController extends ResourceAnimationController { + double min; + double max; + double irange; + + public ScaledResourceAnimationController(Resource source, double min, double max) { + super(source); + this.max = max; + this.min = min; + this.irange = 1.0/(max - min); + } + + + @Override + public void updateAnimation(Graph graph, double frameTime) { + double d = (getValue(graph) - min) * irange; + if (d > 1.0) { + d = 1.0; + } else if (d < 0.0) { + d = 0.0; + } + for (Animatable a : animatables) + a.animate(d,frameTime); + } +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/SlerpInterpolator.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/SlerpInterpolator.java new file mode 100644 index 00000000..581836c0 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/SlerpInterpolator.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.animation; + +import javax.vecmath.Quat4d; + +import org.simantics.proconf.g3d.base.VecmathJmeTools; + + +import com.jme.scene.Node; + +import org.simantics.proconf.animation.curve.SlerpCurve; + + +public class SlerpInterpolator implements Interpolator{ + private SlerpCurve curve; + + //private TransformGroup group; + //private Transform3D transform; + private Node node = null; + + public SlerpInterpolator(SlerpCurve curve) { + this.curve = curve; + //transform = new Transform3D(); + } + + public void interpolate(double delta) { + Quat4d q = curve.evaluate(delta); + //transform.set(new Quat4f(q)); + //group.setTransform(transform); + node.setLocalRotation(VecmathJmeTools.get(q)); + } + + public void setTarget(Object target) { + //group = (TransformGroup)target; + node = (Node)target; + } + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/TCBInterpolator.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/TCBInterpolator.java new file mode 100644 index 00000000..e40d63d0 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/TCBInterpolator.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.animation; + +import org.simantics.proconf.animation.curve.TCBCurve; + + +public class TCBInterpolator extends AbstractScalarInterpolator{ + TCBCurve curve; + + public TCBInterpolator(TCBCurve curve) { + this.curve = curve; + } + + public double evaluate(double delta) { + return curve.evaluate(delta); + + } +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/TestAnimationController.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/TestAnimationController.java new file mode 100644 index 00000000..ec40dea7 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/TestAnimationController.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.animation; + +import java.util.ArrayList; +import java.util.List; + +import org.simantics.db.Graph; + +public class TestAnimationController implements AnimationController { + List animatables = new ArrayList(); + + private double d = 0.0; + private double delta = 0.01; + + public void addAnimatable(Animatable animatable) { + animatables.add(animatable); + + } + + public void setAnimatable(Animatable animatable) { + animatables.clear(); + animatables.add(animatable); + + } + + public void updateAnimation(Graph graph, double frameTime) { + d += delta; + if (d > 1.0) { + d = 1.0; + delta = -delta; + } else if (d < 0.0) { + delta = -delta; + d = 0.0; + } + for (Animatable a : animatables) + a.animate(d,frameTime); + } + + public void dispose() { + + } + + + + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/ui/AnimationControlCreator.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/ui/AnimationControlCreator.java new file mode 100644 index 00000000..b433d22c --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/ui/AnimationControlCreator.java @@ -0,0 +1,139 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.animation.ui; + +import org.eclipse.jface.action.Action; +import org.simantics.proconf.g3d.Activator; +import org.simantics.proconf.g3d.animation.AnimationController; +import org.simantics.proconf.g3d.animation.AnimationSystem; +import org.simantics.proconf.g3d.animation.AnimationSystemListener; + + + +public class AnimationControlCreator { + + private AnimationSystem animationSystem; + + public AnimationControlCreator(AnimationSystem animationSystem) { + if (animationSystem == null) + throw new IllegalArgumentException("AnimationSystem must not be null"); + this.animationSystem = animationSystem; + } + + public Action createStopAction() { + return new StopAction(); + } + + public Action createPauseAction() { + return new PauseAction(); + } + + public Action createPlayAction() { + return new PlayAction(); + } + + private class StopAction extends Action implements AnimationSystemListener { + + public StopAction() { + super(); + this.setImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/silk/control_stop_blue.png")); + this.setDisabledImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/silk/control_stop.png")); + animationSystem.addListener(this); + if (!animationSystem.isRunning()) + this.setEnabled(false); + } + + public void run() { + animationSystem.stop(); + } + + public void animationAdded(AnimationSystem animationSystem, AnimationController animationController) { + this.setEnabled(true); + } + + public void animationPaused(AnimationSystem animationSystem) { + this.setEnabled(true); + } + + public void animationPlay(AnimationSystem animationSystem) { + this.setEnabled(true); + } + + public void animationStopped(AnimationSystem animationSystem) { + this.setEnabled(false); + } + } + + private class PlayAction extends Action implements AnimationSystemListener { + + public PlayAction() { + super(); + this.setImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/silk/control_play_blue.png")); + this.setDisabledImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/silk/control_play.png")); + animationSystem.addListener(this); + if (!animationSystem.isPause() || !animationSystem.isRunning()) + this.setEnabled(false); + } + + public void run() { + animationSystem.play(); + } + + public void animationAdded(AnimationSystem animationSystem, AnimationController animationController) { + this.setEnabled(animationSystem.isPause()); + } + + public void animationPaused(AnimationSystem animationSystem) { + this.setEnabled(true); + } + + public void animationPlay(AnimationSystem animationSystem) { + this.setEnabled(false); + } + + public void animationStopped(AnimationSystem animationSystem) { + this.setEnabled(false); + } + } + + private class PauseAction extends Action implements AnimationSystemListener { + + public PauseAction() { + super(); + this.setImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/silk/control_pause_blue.png")); + this.setDisabledImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/silk/control_pause.png")); + animationSystem.addListener(this); + if (animationSystem.isPause() || !animationSystem.isRunning()) + this.setEnabled(false); + } + + public void run() { + animationSystem.pause(); + } + + public void animationAdded(AnimationSystem animationSystem, AnimationController animationController) { + this.setEnabled(!animationSystem.isPause()); + } + + public void animationPaused(AnimationSystem animationSystem) { + this.setEnabled(false); + } + + public void animationPlay(AnimationSystem animationSystem) { + this.setEnabled(true); + } + + public void animationStopped(AnimationSystem animationSystem) { + this.setEnabled(false); + } + } + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/AppearanceTools.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/AppearanceTools.java new file mode 100644 index 00000000..5cc4304b --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/AppearanceTools.java @@ -0,0 +1,454 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.base; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.swt.graphics.Device; +import org.simantics.layer0.utils.IEntity; +import org.simantics.layer0.utils.StubLinkedList; +import org.simantics.proconf.g3d.Resources; +import org.simantics.proconf.g3d.stubs.Appearance; +import org.simantics.proconf.g3d.stubs.Color; +import org.simantics.proconf.g3d.stubs.G3DResource; +import org.simantics.proconf.g3d.stubs.ImageTexture; +import org.simantics.proconf.g3d.stubs.Material; +import org.simantics.proconf.g3d.stubs.MultiTexture; +import org.simantics.proconf.g3d.stubs.MultiTextureMode; +import org.simantics.proconf.g3d.stubs.Shader; +import org.simantics.proconf.g3d.stubs.Texture; +import org.simantics.utils.ErrorLogger; + +import com.jme.image.Image; +import com.jme.renderer.ColorRGBA; +import com.jme.renderer.Renderer; +import com.jme.scene.Geometry; +import com.jme.scene.state.AlphaState; +import com.jme.scene.state.FragmentProgramState; +import com.jme.scene.state.MaterialState; +import com.jme.scene.state.RenderState; +import com.jme.scene.state.TextureState; +import com.jme.scene.state.VertexProgramState; + + +public class AppearanceTools { + + + + + public static void setColor(Color color, org.eclipse.swt.graphics.Color c) { + color.setRed(new double[]{(double)c.getRed() / 255.0}); + color.setGreen(new double[]{(double)c.getGreen() / 255.0}); + color.setBlue(new double[]{(double)c.getBlue() / 255.0}); + } + + public static org.eclipse.swt.graphics.Color getColor(Color color, Device device) { + org.eclipse.swt.graphics.Color c = new org.eclipse.swt.graphics.Color(device, (int)(color.getRed()[0] * 255.0), (int)(color.getGreen()[0] * 255.0),(int)(color.getBlue()[0] * 255.0)); + return c; + } + + /** + * Returns collection of renderstates that represent the given appearance. + * Note : if collection contains an alphastate, node must be inserted to transparent rendering queue.! + * @param appearance + * @param renderer + * @return + */ + public static Collection getAppearance(Appearance appearance, Renderer renderer) { + Material m = appearance.getMaterial(); + List states = new ArrayList(); + if (m != null) { + states.addAll(getMaterial(m, renderer)); + } + Texture t = appearance.getTexture(); + if (t != null) { + if (t.isInstanceOf(Resources.g3dResource.ImageTexture)) { + states.addAll(getPatternTexture(t, renderer)); + } else if (t.isInstanceOf(Resources.g3dResource.Texture3D)) { + ErrorLogger.getDefault().logWarning("JME doesn't support volume textures!", null); + } else if (t.isInstanceOf(Resources.g3dResource.MultiTexture)) { + states.addAll(getMultiTexture(t, renderer)); + } else if (t.isInstanceOf(Resources.g3dResource.CubeMapTexture)) { + ErrorLogger.getDefault().logWarning("JME doesn't support cubemap textures!", null); + } else { + throw new UnsupportedOperationException("Unsupported texture"); + } + } + Shader s = appearance.getShader(); + if (s != null) { + states.addAll(getShader(s, renderer)); + } + return states; + + } + + private static ColorRGBA getJMEColor(Color color) { + return new ColorRGBA((float)color.getRed()[0],(float)color.getGreen()[0],(float)color.getBlue()[0],0.f); + } + + private static ColorRGBA getJMEColor(Color color, float alpha) { + return new ColorRGBA((float)color.getRed()[0],(float)color.getGreen()[0],(float)color.getBlue()[0],alpha); + } + + private static Collection getMaterial(Material m , Renderer renderer) { + float alpha = 0.f; + MaterialState ms = renderer.createMaterialState(); + List states = new ArrayList(); + if (m.getTransparency()[0] > 0.0) { + AlphaState as = renderer.createAlphaState(); + as.setBlendEnabled(true); + as.setSrcFunction(AlphaState.DB_SRC_ALPHA); + as.setDstFunction(AlphaState.DB_ONE_MINUS_SRC_ALPHA); + states.add(as); + alpha = 1.f - (float)m.getTransparency()[0]; + //node.setRenderQueueMode(Renderer.QUEUE_TRANSPARENT); + ms.setMaterialFace(MaterialState.MF_FRONT_AND_BACK); + } else { + //node.setRenderQueueMode(Renderer.QUEUE_OPAQUE); + } + + ms.setEmissive(getJMEColor(m.getEmissiveColor())); + ms.setSpecular(getJMEColor(m.getSpecularColor())); + ms.setAmbient(getJMEColor(m.getAmbientColor())); + ms.setDiffuse(getJMEColor(m.getDiffuseColor(),alpha)); + ms.setShininess((float) m.getShininess()[0]); + //node.setRenderState(ms); + states.add(ms); + return states; + } + + private static Collection getShader(Shader s , Renderer renderer) { + List states = new ArrayList(); + VertexProgramState vs = renderer.createVertexProgramState(); + vs.load(s.getVertexShader()[0]); + FragmentProgramState fs = renderer.createFragmentProgramState(); + fs.load(s.getFragmentShader()[0]); + states.add(vs); + states.add(fs); + return states; + } + + private static Collection getPatternTexture(Texture t, Renderer renderer) { + + List states = new ArrayList(); + com.jme.image.Texture texture = ResourceTextureCache.getInstance().loadTexture(t.getGraph(), t.getResource()); + if (texture == null) + return states; + TextureState state = renderer.createTextureState(); + state.setTexture(texture); + state.setEnabled(true); + states.add(state); + return states; + + } + + private static Image getPatternTexture(ImageTexture t) { + return ResourceTextureCache.getInstance().loadImage(t.getGraph(), t.getResource()); + } + + + + + + private static Collection getMultiTexture(Texture t, Renderer renderer) { + List states = new ArrayList(); + TextureState state = renderer.createTextureState(); + MultiTexture t3 = new MultiTexture(t); + Collection mtList = t3.getRelatedObjects(Resources.g3dResource.HasMultiTextureElementList); + assert (mtList.size() == 1); //this is required in the ontology! + StubLinkedList list = new StubLinkedList(mtList.iterator().next()); + + for (int i = 0; i < list.size(); i++) { + IEntity ie = list.get(i); + //MultiTextureElement e = new MultiTextureElement(ie); + Texture tex = new Texture(ie); //e.getTexture(); + MultiTextureMode mode = tex.getTextureMode();//e.getTextureMode(); + com.jme.image.Texture texture = new com.jme.image.Texture(); + texture.setFilter(com.jme.image.Texture.FM_LINEAR); + texture.setMipmapState(com.jme.image.Texture.MM_LINEAR_LINEAR); + texture.setWrap(com.jme.image.Texture.WM_WRAP_S_WRAP_T); + if (mode.getResource().equals(Resources.g3dResource.MultiTextureMode_add)) { + texture.setApply(com.jme.image.Texture.AM_ADD); + } else if (mode.getResource().equals(Resources.g3dResource.MultiTextureMode_modulate)) { + texture.setApply(com.jme.image.Texture.AM_MODULATE); + } else if (mode.getResource().equals(Resources.g3dResource.MultiTextureMode_decal)) { + texture.setApply(com.jme.image.Texture.AM_DECAL); + } else if (mode.getResource().equals(Resources.g3dResource.MultiTextureMode_blend)) { + texture.setApply(com.jme.image.Texture.AM_BLEND); + } else if (mode.getResource().equals(Resources.g3dResource.MultiTextureMode_replace)) { + texture.setApply(com.jme.image.Texture.AM_REPLACE); + } else if (mode.getResource().equals(Resources.g3dResource.MultiTextureMode_combine)) { + texture.setApply(com.jme.image.Texture.AM_COMBINE); + //CombineMode cm = e.getCombineMode(); + //CombineSource cs = e.getCombineSource(); + StubLinkedList combine = new StubLinkedList(tex.getCombineDefinition()); + setCombineAttributes(texture, combine); + + + + //att.setBlendColor(blendColor) + //att.setTexBlendColor(texBlendColor) + //att.setTextureBlendColor(color) + //att.setTextureTransform(transform) + } else { + throw new UnsupportedOperationException("Texture mode not supported"); + } + + + if (tex.isInstanceOf(Resources.g3dResource.MultiTexture)) { + ErrorLogger.defaultLogError("MultiTexture contains another MultiTexture which is not allowed", null); + continue; + } else if (tex.isInstanceOf(Resources.g3dResource.ImageTexture)) { + Image image = getPatternTexture(new ImageTexture(tex)); + if (image != null) + texture.setImage(image); + + } else if (tex.isInstanceOf(Resources.g3dResource.Texture3D)) { + ErrorLogger.getDefault().logWarning("JME doesn't support volume textures!", null); + + } else if (tex.isInstanceOf(Resources.g3dResource.CubeMapTexture)) { + ErrorLogger.getDefault().logWarning("JME doesn't support cubemap textures!", null); + + } else { + throw new UnsupportedOperationException("Unsupported texture"); + } + + state.setTexture(texture, i); + } + states.add(state); + return states; + + //MultiTextureElementList texturesList = t3.getMultiTextureElementList(); + //List textures = texturesList.toStandAloneList(); + //ArrayList states = new ArrayList(); + // for (MultiTextureElement e : textures) { + // Texture tex = e.getTexture(); + + //int index = e.getMultiTextureIndexValue(); + //String mode = e.getMultiTextureModeValue(); + + // com.jme.image.Texture texture = new com.jme.image.Texture(); + // texture.setFilter(com.jme.image.Texture.FM_LINEAR); + // texture.setMipmapState(com.jme.image.Texture.MM_LINEAR_LINEAR); + // texture.setWrap(com.jme.image.Texture.WM_WRAP_S_WRAP_T); +// if (mode.startsWith(TEXTURE_MODE_MODULATE)) { +// texture.setApply(com.jme.image.Texture.AM_MODULATE); +// } else if (mode.startsWith(TEXTURE_MODE_DECAL)) { +// texture.setCombineFuncRGB(com.jme.image.Texture.AM_DECAL); +// } else if (mode.startsWith(TEXTURE_MODE_BLEND)) { +// texture.setCombineFuncRGB(com.jme.image.Texture.AM_MODULATE); +// } else if (mode.startsWith(TEXTURE_MODE_REPLACE)) { +// texture.setCombineFuncRGB(com.jme.image.Texture.AM_REPLACE); +// } else if (mode.startsWith(TEXTURE_MODE_COMBINE)) { +// texture.setCombineFuncRGB(com.jme.image.Texture.AM_COMBINE); +// +// mode = mode.substring(TEXTURE_MODE_COMBINE.length()+1); +// setCombineAttributes(texture, mode); + + + + //att.setBlendColor(blendColor) + //att.setTexBlendColor(texBlendColor) + //att.setTextureBlendColor(color) + //att.setTextureTransform(transform) +// } else { +// throw new UnsupportedOperationException("Texture mode not supported"); +// } +// +// +// if (tex.isInstanceOf(Resources.g3dResource.MultiTexture)) { +// ErrorLogger.defaultLogError("MultiTexture contains another MultiTexture which is not allowed", null); +// continue; +// } else if (tex.isInstanceOf(Resources.g3dResource.ImageTexture)) { +// Image image = getPatternTexture(ImageTextureFactory.create(tex)); +// if (image != null) +// texture.setImage(image); +// +// } else if (tex.isInstanceOf(Resources.g3dResource.Texture3D)) { +// ErrorLogger.getDefault().logWarning("JME doesn't support volume textures!", null); +// +// } else if (tex.isInstanceOf(Resources.g3dResource.CubeMapTexture)) { +// ErrorLogger.getDefault().logWarning("JME doesn't support cubemap textures!", null); +// +// } else { +// throw new UnsupportedOperationException("Unsupported texture"); +// } + + //FIXME ! + //state.setTexture(texture, index); + // } + // node.setRenderState(state); + + + + } + + + private static void setCombineAttributes(com.jme.image.Texture texture, StubLinkedList definition) { + // TODO : rgb and alpha scale + Iterator it = definition.iterator(); + IEntity mode = it.next(); + if (mode.getResource().equals(Resources.g3dResource.CombineMode_add)) { + texture.setCombineFuncRGB(com.jme.image.Texture.ACF_ADD); + } else if (mode.getResource().equals(Resources.g3dResource.CombineMode_addsigned)) { + texture.setCombineFuncRGB(com.jme.image.Texture.ACF_ADD_SIGNED); + } else if (mode.getResource().equals(Resources.g3dResource.CombineMode_dot3)) { + texture.setCombineFuncRGB(com.jme.image.Texture.ACF_DOT3_RGB); + } else if (mode.getResource().equals(Resources.g3dResource.CombineMode_interpolate)) { + texture.setCombineFuncRGB(com.jme.image.Texture.ACF_INTERPOLATE); + } else if (mode.getResource().equals(Resources.g3dResource.CombineMode_modulate)) { + texture.setCombineFuncRGB(com.jme.image.Texture.ACF_MODULATE); + } else if (mode.getResource().equals(Resources.g3dResource.CombineMode_replace)) { + texture.setCombineFuncRGB(com.jme.image.Texture.ACF_REPLACE); + } else if (mode.getResource().equals(Resources.g3dResource.CombineMode_subtract)) { + texture.setCombineFuncRGB(com.jme.image.Texture.ACF_SUBTRACT); + } else { + throw new UnsupportedOperationException("Unsupported combine mode"); + } + mode = it.next(); + int i = 0; + for (i = 0; i < 3; i++) { + int m; + if (mode.getResource().equals(Resources.g3dResource.CombineSource_constantcolor)) { + m = com.jme.image.Texture.ACS_CONSTANT; + } else if (mode.getResource().equals(Resources.g3dResource.CombineSource_objectcolor)) { + m = com.jme.image.Texture.ACS_PRIMARY_COLOR; + } else if (mode.getResource().equals(Resources.g3dResource.CombineSource_previousstate)) { + m = com.jme.image.Texture.ACS_TEXTURE; + } else if (mode.getResource().equals(Resources.g3dResource.CombineSource_texturecolor)) { + m = com.jme.image.Texture.ACS_TEXTURE; + } else if (mode.getResource().equals(Resources.g3dResource.CombineSource_texture0)) { + m = com.jme.image.Texture.ACS_TEXTURE; + } else if (mode.getResource().equals(Resources.g3dResource.CombineSource_texture1)) { + m = com.jme.image.Texture.ACS_TEXTURE; + } else { + break; + //throw new UnsupportedOperationException("Texture combine source not supported"); + } + mode = it.next(); + switch (i) { + case 0: + texture.setCombineSrc0RGB(m); + break; + case 1: + texture.setCombineSrc1RGB(m); + break; + case 2: + texture.setCombineSrc2RGB(m); + break; + + } + } + if (i > 0) { + for (i = 0; i < 3; i++) { + int m; + if (mode.getResource().equals(Resources.g3dResource.CombineFunction_srccolor)) { + m = com.jme.image.Texture.ACO_SRC_COLOR; + } else if (mode.getResource().equals(Resources.g3dResource.CombineFunction_srcalpha)) { + m = com.jme.image.Texture.ACO_SRC_ALPHA; + } else if (mode.getResource().equals(Resources.g3dResource.CombineFunction_oneminussrccolor)) { + m = com.jme.image.Texture.ACO_ONE_MINUS_SRC_COLOR; + } else if (mode.getResource().equals(Resources.g3dResource.CombineFunction_oneminussrcalpha)) { + m = com.jme.image.Texture.ACO_ONE_MINUS_SRC_ALPHA; + } else { + break; + } + mode = it.next(); + switch (i) { + case 0: + texture.setCombineOp0RGB(m); + break; + case 1: + texture.setCombineOp1RGB(m); + break; + case 2: + texture.setCombineOp2RGB(m); + break; + + } + } + } + + for (i = 0; i < 3; i++) { + int m; + if (mode.getResource().equals(Resources.g3dResource.CombineSource_constantcolor)) { + m = com.jme.image.Texture.ACS_CONSTANT; + } else if (mode.getResource().equals(Resources.g3dResource.CombineSource_objectcolor)) { + m = com.jme.image.Texture.ACS_PRIMARY_COLOR; + } else if (mode.getResource().equals(Resources.g3dResource.CombineSource_previousstate)) { + m = com.jme.image.Texture.ACS_TEXTURE; + } else if (mode.getResource().equals(Resources.g3dResource.CombineSource_texturecolor)) { + m = com.jme.image.Texture.ACS_TEXTURE; + } else if (mode.getResource().equals(Resources.g3dResource.CombineSource_texture0)) { + m = com.jme.image.Texture.ACS_TEXTURE; + } else if (mode.getResource().equals(Resources.g3dResource.CombineSource_texture1)) { + m = com.jme.image.Texture.ACS_TEXTURE; + } else { + break; + //throw new UnsupportedOperationException("Texture combine source not supported"); + } + mode = it.next(); + switch (i) { + case 0: + texture.setCombineSrc0Alpha(m); + break; + case 1: + texture.setCombineSrc1Alpha(m); + break; + case 2: + texture.setCombineSrc2Alpha(m); + break; + + } + } + if (i > 0) { + for (i = 0; i < 3; i++) { + int m; + if (mode.getResource().equals(Resources.g3dResource.CombineFunction_srccolor)) { + m = com.jme.image.Texture.ACO_SRC_COLOR; + } else if (mode.getResource().equals(Resources.g3dResource.CombineFunction_srcalpha)) { + m = com.jme.image.Texture.ACO_SRC_ALPHA; + } else if (mode.getResource().equals(Resources.g3dResource.CombineFunction_oneminussrccolor)) { + m = com.jme.image.Texture.ACO_ONE_MINUS_SRC_COLOR; + } else if (mode.getResource().equals(Resources.g3dResource.CombineFunction_oneminussrcalpha)) { + m = com.jme.image.Texture.ACO_ONE_MINUS_SRC_ALPHA; + } else { + break; + } + mode = it.next(); + switch (i) { + case 0: + texture.setCombineOp0Alpha(m); + break; + case 1: + texture.setCombineOp1Alpha(m); + break; + case 2: + texture.setCombineOp2Alpha(m); + break; + + } + } + } + } + + public static void copyMaterial(Geometry from, Geometry to) { + for (int i = RenderState.RS_ALPHA; i < RenderState.RS_MAX_STATE; i++) { + RenderState rs = from.getRenderState(i); + if (rs != null) + to.setRenderState(rs); + } + + } +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/Constraint.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/Constraint.java new file mode 100644 index 00000000..9d48d3ed --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/Constraint.java @@ -0,0 +1,19 @@ +package org.simantics.proconf.g3d.base; + +import java.util.ArrayList; +import java.util.List; + +import javax.vecmath.Point3d; +import javax.vecmath.Vector3d; + +public class Constraint { + + public Constraint() { + points = new ArrayList(); + dirs = new ArrayList(); + } + + public List points; + public List dirs; + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/ConstraintDetector.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/ConstraintDetector.java new file mode 100644 index 00000000..3a18c27c --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/ConstraintDetector.java @@ -0,0 +1,442 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.base; + +import java.util.ArrayList; +import java.util.List; + +import javax.vecmath.Point3d; +import javax.vecmath.Vector3d; + +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestWithResult; +import org.simantics.db.Resource; +import org.simantics.db.adaption.AdaptionException; +import org.simantics.proconf.g3d.Resources; +import org.simantics.utils.ErrorLogger; + +import com.jme.renderer.ColorRGBA; +import com.jme.scene.Geometry; +import com.jme.scene.Line; +import com.jme.scene.state.MaterialState; +import com.jme.util.geom.BufferUtils; + +public class ConstraintDetector { + + private static final int X = 0; + private static final int Y = 1; + private static final int Z = 2; + + + private ThreeDimensionalEditorBase editor; + //private G3DNode constraintReference = null; + private Resource constraintReference = null; + private ArrayList constraintPoints = new ArrayList(); + private ArrayList constraintDirections = new ArrayList(); + private MaterialState ms; + + private ColorRGBA xColor = new ColorRGBA(1.f,0.f,0.f,1.f); + private ColorRGBA yColor = new ColorRGBA(0.f,1.f,0.f,1.f); + private ColorRGBA zColor = new ColorRGBA(0.f,0.f,1.f,1.f); + + + public ConstraintDetector(ThreeDimensionalEditorBase editor) { + this.editor = editor; + ms = editor.getRenderingComponent().getDisplaySystem().getRenderer().createMaterialState(); + ms.setEmissive(new ColorRGBA(1.f,1.f,1.f,1.f)); + ms.setColorMaterial(MaterialState.CM_EMISSIVE); + } + + + public void clearConstraints() { + //System.out.println("ConstraintDetector.clearConstraints()"); + constraintPoints.clear(); + constraintDirections.clear(); + } + + private void updateConstraints() { + clearConstraints(); + if (constraintReference == null) + return; + GraphRequestWithResult request = new GraphRequestWithResult() { + @Override + public Constraint performWithResult(Graph g) throws Exception { + try { + return g.adapt(constraintReference, Resources.g3dResource.HasConstraints); + } catch (AdaptionException e) { + ErrorLogger.defaultLogWarning("Cannot add constraint", e); + return null; + } + } + }; + editor.getSession().syncRead(request); + Constraint c = request.getResult(); + if (c == null) + return; + constraintPoints.addAll(c.points); + constraintDirections.addAll(c.dirs); + } + + + public ArrayList getConstraintPoints() { + return constraintPoints; + } + + public ArrayList getConstraintDirections() { + return constraintDirections; + } + + public void updateConstraintReference() { + + Resource interactive = null; + if (editor.getSelectionAdapter().getHighlightSelection().size() > 0) { + interactive = editor.getSelectionAdapter().getInteractiveSelectedObjects().iterator().next().getResource(); + if (constraintReference == null) { + constraintReference = interactive; + updateConstraints(); + } else if (!constraintReference.getResource().equals(interactive.getResource())) { + constraintReference = interactive; + updateConstraints(); + } + } else { + constraintReference = null; + updateConstraints(); + } + + } + + public void addContraintPoint(Point3d p) { + //System.out.println("ConstraintDetector.addConstraintPoint() " + p); + constraintPoints.add(p); + } + + public void addContraintDirection(Vector3d v) { + //System.out.println("ConstraintDetector.addConstraintDirection() " + v); + constraintDirections.add(v); + } + + private double snapAngle = 0.1; + private String snapString = ""; + + private ArrayList constraintHighlights = new ArrayList(); + + public Point3d getSnappedPoint(Vector3d pickPoint, Vector3d pickDir, Vector3d requestedPoint) { + + + Vector3d snappedPoint = new Vector3d(); + Vector3d t = new Vector3d(); + Point3d currentPoint = null; + // TODO : snap to closest angle + for (Vector3d constraintDir : constraintDirections) { + + MathTools.intersectStraightStraight(pickPoint,pickDir, requestedPoint, constraintDir, t, snappedPoint); + t.sub(snappedPoint); + if (t.lengthSquared() < snapAngle) { + + snapString += "Angle snap "; + currentPoint = new Point3d(snappedPoint); + break; + } + } + if (currentPoint != null) { + Vector3d dir = new Vector3d(currentPoint); + dir.sub(requestedPoint); + Point3d p = getPointSnap(requestedPoint, dir); + if (p != null) + currentPoint = p; + } else { + List distances = new ArrayList(); + List snapPoints = new ArrayList(); + List snapStrings = new ArrayList(); + List snapColors = new ArrayList(); + for (Point3d constraintPoint : constraintPoints) { + distances.clear(); + snapPoints.clear(); + snapStrings.clear(); + MathTools.intersectStraightStraight(new Vector3d(constraintPoint), new Vector3d(1.0, 0.0, 0.0), + pickPoint, pickDir, snappedPoint, t); + t.sub(snappedPoint); + double distance = t.lengthSquared(); + if (distance < snapAngle) { + distances.add(distance); + snapPoints.add(new Point3d(snappedPoint)); + snapStrings.add("Point x-snap "); + snapColors.add(xColor); + } + MathTools.intersectStraightStraight(new Vector3d(constraintPoint), new Vector3d(0.0, 1.0, 0.0), + pickPoint, pickDir, snappedPoint, t); + t.sub(snappedPoint); + distance = t.lengthSquared(); + if (distance < snapAngle) { + distances.add(distance); + snapPoints.add(new Point3d(snappedPoint)); + snapStrings.add("Point y-snap "); + snapColors.add(yColor); + } + MathTools.intersectStraightStraight(new Vector3d(constraintPoint), new Vector3d(0.0, 0.0, 1.0), + pickPoint, pickDir, snappedPoint, t); + t.sub(snappedPoint); + distance = t.lengthSquared(); + if (distance < snapAngle) { + distances.add(distance); + snapPoints.add(new Point3d(snappedPoint)); + snapStrings.add("Point z-snap "); + snapColors.add(zColor); + + } + if (distances.size() > 0) { + if (distances.size() > 1) { + // more than one axes snape + Vector3d ref = MathTools.closestPointOnStraight(constraintPoint, new Point3d(pickPoint), pickDir); + ref.sub(constraintPoint); + distance = ref.lengthSquared(); + if (distance < snapAngle) { + // we are close enought to point, so we'll just snap there + currentPoint = new Point3d(constraintPoint); + snapString += "Point snap "; + } else { + // select the closest of axes snap to + int min = 0; + for (int i = 1; i < distances.size(); i++) { + if (distances.get(i) < distances.get(min)) + min = i; + } + currentPoint = snapPoints.get(min); + addConstrainLineHighlight(currentPoint, constraintPoint,snapColors.get(min)); + snapString += snapStrings.get(min); + } + } else { + // only one of the axes snaps + currentPoint = snapPoints.get(0); + addConstrainLineHighlight(currentPoint, constraintPoint,snapColors.get(0)); + snapString += snapStrings.get(0); + } + break; + } + } + } + return currentPoint; + + } + + public void clearConstraintHighlights() { + snapString = ""; + + for (Geometry s : constraintHighlights) + s.removeFromParent(); + + constraintHighlights.clear(); + } + + private void addConstrainLineHighlight(Point3d p1, Point3d p2, ColorRGBA color) { + + float coord[] = new float[6]; + ColorRGBA colors[] = new ColorRGBA[2]; + colors[0] = color; + colors[1] = color; + coord[0] = (float)p1.x; + coord[1] = (float)p1.y; + coord[2] = (float)p1.z; + coord[3] = (float)p2.x; + coord[4] = (float)p2.y; + coord[5] = (float)p2.z; + Line shape = new Line("",BufferUtils.createFloatBuffer(coord),null,BufferUtils.createFloatBuffer(colors),null); + editor.getRenderingComponent().getNoShadowRoot().attachChild(shape); + shape.setRenderState(ms); + constraintHighlights.add(shape); + } + + private void addConstrainPlaneHighlight(Point3d p1, Point3d p2, int axis) { + + float coord[] = new float[9]; + ColorRGBA colors[] = new ColorRGBA[3]; + coord[0] = (float)p1.x; + coord[1] = (float)p1.y; + coord[2] = (float)p1.z; + switch (axis) { + case X: + coord[3] = (float)p1.x; + coord[4] = (float)p1.y; + coord[5] = (float)p2.z; + colors[0] = colors[1] = colors[2] = xColor; + break; + case Y: + coord[3] = (float)p1.x; + coord[4] = (float)p1.y; + coord[5] = (float)p2.z; + colors[0] = colors[1] = colors[2] = yColor; + break; + case Z: + coord[3] = (float)p1.x; + coord[4] = (float)p2.y; + coord[5] = (float)p2.z; + colors[0] = colors[1] = colors[2] = zColor; + break; + + } + coord[6] = (float)p2.x; + coord[7] = (float)p2.y; + coord[8] = (float)p2.z; + Line shape = new Line("",BufferUtils.createFloatBuffer(coord),null,BufferUtils.createFloatBuffer(colors),null); + shape.setMode(Line.CONNECTED); + editor.getRenderingComponent().getNoShadowRoot().attachChild(shape); + shape.setRenderState(ms); + constraintHighlights.add(shape); + } + + /** + * Snaps position to axis-aligned planes defined by constraint points + * Form of position is p+v, meaning that the position that is snapped is requestedPoint + requestedDir + * @param requestedPoint one part of the position to be snapped + * @param requestedDir second part of the position to be snapped and direction that the position is allowed to move + * @return + */ + public Point3d getPointSnap(Vector3d requestedPoint, Vector3d requestedDir) { + + Vector3d snappedPoint = new Vector3d(); + Point3d currentPoint = null; + double u[] = new double[1]; + List p1s = new ArrayList(); + List p2s = new ArrayList(); + List axes = new ArrayList(); + + for (Point3d constraintPoint : constraintPoints) { + boolean snap = false; + + if (MathTools.intersectStraightPlane(requestedPoint, requestedDir, new Vector3d(constraintPoint), getAxialVector(X), snappedPoint,u) && Math.abs(1.0 - u[0]) < snapAngle) { + currentPoint = new Point3d(snappedPoint); + //snapString += "Point/Plane x-snap "; + snap = true; + //addConstrainPlaneHighlight(constraintPoint, currentPoint,X); + p1s.add(constraintPoint); + p2s.add(currentPoint); + axes.add(X); + } + + if (MathTools.intersectStraightPlane(requestedPoint, requestedDir, new Vector3d(constraintPoint), getAxialVector(Y), snappedPoint,u) && Math.abs(1.0 - u[0]) < snapAngle) { + currentPoint = new Point3d(snappedPoint); + //snapString += "Point/Plane y-snap "; + snap = true; + //addConstrainPlaneHighlight(constraintPoint, currentPoint,Y); + p1s.add(constraintPoint); + p2s.add(currentPoint); + axes.add(Y); + } + + if (MathTools.intersectStraightPlane(requestedPoint, requestedDir, new Vector3d(constraintPoint), getAxialVector(Z), snappedPoint,u) && Math.abs(1.0 - u[0]) < snapAngle) { + currentPoint = new Point3d(snappedPoint); + //snapString += "Point/Plane z-snap "; + snap = true; + //addConstrainPlaneHighlight(constraintPoint, currentPoint,Z); + p1s.add(constraintPoint); + p2s.add(currentPoint); + axes.add(Z); + } + if (snap) + break; + } + if (p1s.size() == 0) + return null; + if (p1s.size() == 1) { + snapString += "Point/Plane "; + switch (axes.get(0)) { + case X: + snapString += "x"; + break; + case Y: + snapString += "y"; + break; + case Z: + snapString += "z"; + break; + } + snapString += "-snap "; + addConstrainPlaneHighlight(p1s.get(0), p2s.get(0),axes.get(0)); + return currentPoint; + } else if (p1s.size() == 3){ + // all axial planes are intersecting, snapping point must be the constraint point + // all constraint points are the same, so just pick the first in the list + snapString += "Point/Point "; + return p1s.get(0); + } else { + Vector3d dir = new Vector3d(); + dir.cross(getAxialVector(axes.get(0)), getAxialVector(axes.get(1))); + currentPoint = new Point3d(MathTools.closestPointOnStraight(currentPoint, p1s.get(0), dir)); + addConstrainLineHighlight(p1s.get(0), currentPoint, xColor); + snapString += "Point/Line "; + return currentPoint; + } + + } + + private Vector3d getAxialVector(int axis) { + switch (axis) { + case X: + return new Vector3d(1.0,0.0,0.0); + case Y: + return new Vector3d(0.0,1.0,0.0); + case Z: + return new Vector3d(0.0,0.0,1.0); + } + throw new RuntimeException("Unknown axis " + axis); + } + + /** + * Snaps the position to axis-aligned planes defined by constraint points + * @param requestedPoint point that is snapped + * @param requestedDir direction that point is allowed to move + * @return + */ + + public Point3d getPointSnap2(Vector3d requestedPoint, Vector3d requestedDir) { + + Vector3d snappedPoint = new Vector3d(); + Point3d currentPoint = null; + double u[] = new double[1]; + //System.out.println(requestedPoint + " " + requestedDir); + for (Point3d constraintPoint : constraintPoints) { + boolean snap = false; + //System.out.print(constraintPoint + " "); + if (MathTools.intersectStraightPlane(requestedPoint, requestedDir, new Vector3d(constraintPoint), new Vector3d(1.0,0.0,0.0), snappedPoint,u) && Math.abs(u[0]) < snapAngle) { + currentPoint = new Point3d(snappedPoint); + snapString += "Point/Plane x-snap "; + snap = true; + addConstrainPlaneHighlight(constraintPoint, currentPoint,X); + //System.out.print(" x " + u[0]); + } + + if (MathTools.intersectStraightPlane(requestedPoint, requestedDir, new Vector3d(constraintPoint), new Vector3d(0.0,1.0,0.0), snappedPoint,u) && Math.abs(u[0]) < snapAngle) { + currentPoint = new Point3d(snappedPoint); + snapString += "Point/Plane y-snap "; + snap = true; + addConstrainPlaneHighlight(constraintPoint, currentPoint,Y); + //System.out.print(" y " + u[0]); + } + + + if (MathTools.intersectStraightPlane(requestedPoint, requestedDir, new Vector3d(constraintPoint), new Vector3d(0.0,0.0,1.0), snappedPoint,u) && Math.abs(u[0]) < snapAngle) { + currentPoint = new Point3d(snappedPoint); + snapString += "Point/Plane z-snap "; + snap = true; + addConstrainPlaneHighlight(constraintPoint, currentPoint,Z); + //System.out.print(" z " + u[0]); + } + //System.out.println(); + if (snap) + break; + } + return currentPoint; + } + + public String getSnapString() { + return snapString; + } +} \ No newline at end of file diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/EditorContribution.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/EditorContribution.java new file mode 100644 index 00000000..0cca6ecb --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/EditorContribution.java @@ -0,0 +1,70 @@ +package org.simantics.proconf.g3d.base; + +import java.util.Collection; + +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.IToolBarManager; +import org.eclipse.swt.widgets.Composite; +import org.simantics.db.Graph; +import org.simantics.proconf.g3d.actions.ContextAction; +import org.simantics.proconf.g3d.common.StructuredResourceSelection; + +public interface EditorContribution { + + public String getName(); + + /** + * Initializes the contribution + * @param graph + */ + void initialize(Graph graph); + + + /** + * Allows contribution to modify current ui. + * @param parent + */ + void createControl(Composite parent); + + /** + * Removes all changes created by createControl + */ + void disposeControl(); + + /** + * Fills context menu + * @param graph + * @param manager + */ + void fillContextMenu(Graph graph, IMenuManager manager, StructuredResourceSelection selection); + + /** + * Fills toolbar + * + * @param manager + */ + void fillLocalToolBar(IToolBarManager manager); + + /** + * Fills menumanager + * + * + * @param manager + */ + void fillLocalPullDown(IMenuManager manager); + + + /** + * Returns context dependent actions + * @return + */ + Collection getActions(); + + /** + * + */ + void run(); + + void dispose(); + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/G3DAPI.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/G3DAPI.java new file mode 100644 index 00000000..3bec68d2 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/G3DAPI.java @@ -0,0 +1,94 @@ +package org.simantics.proconf.g3d.base; + +import javax.vecmath.AxisAngle4d; +import javax.vecmath.Tuple3d; + +import org.simantics.db.Resource; +import org.simantics.layer0.utils.IEntity; +import org.simantics.proconf.g3d.Resources; + +/** + * Set of methods that make scene-graph handling easier. + * + * + * @author Marko Luukkainen + * + */ +public class G3DAPI { + + + public static void setWorldPosition(IEntity node, Tuple3d position) { + G3DTools.setTuple3(node.getSingleRelatedObject(Resources.g3dResource.HasWorldPosition), position); + //G3DTools.transformationUpdate(node.getGraph(), node.getResource()); + G3DTools.propagateWorldTransformChange(node.getSingleRelatedObject(Resources.g3dResource.HasParent), node); + } + + public static void setLocalPosition(IEntity node, Tuple3d position) { + G3DTools.setTuple3(node.getSingleRelatedObject(Resources.g3dResource.HasLocalPosition), position); + //G3DTools.transformationUpdate(node.getGraph(), node.getResource()); + G3DTools.propagateLocalTransformChange(node.getSingleRelatedObject(Resources.g3dResource.HasParent), node); + + } + + public static void setWorldOrientation(IEntity node, AxisAngle4d orientation) { + G3DTools.setOrientation(node.getSingleRelatedObject(Resources.g3dResource.HasWorldOrientation), orientation); + //G3DTools.transformationUpdate(node.getGraph(), node.getResource()); + G3DTools.propagateWorldTransformChange(node.getSingleRelatedObject(Resources.g3dResource.HasParent), node); + + } + + public static void setLocalOrientation(IEntity node, AxisAngle4d orientation) { + G3DTools.setOrientation(node.getSingleRelatedObject(Resources.g3dResource.HasLocalOrientation), orientation); + //G3DTools.transformationUpdate(node.getGraph(), node.getResource()); + G3DTools.propagateLocalTransformChange(node.getSingleRelatedObject(Resources.g3dResource.HasParent), node); + + + } + + public static void setWorldTransformation(IEntity node, Tuple3d position, AxisAngle4d orientation) { + G3DTools.setTuple3(node.getSingleRelatedObject(Resources.g3dResource.HasWorldPosition), position); + G3DTools.setOrientation(node.getSingleRelatedObject(Resources.g3dResource.HasWorldOrientation), orientation); + //G3DTools.transformationUpdate(node.getGraph(), node.getResource()); + G3DTools.propagateWorldTransformChange(node.getSingleRelatedObject(Resources.g3dResource.HasParent), node); + + } + + public static void setLocalTransformation(IEntity node, Tuple3d position, AxisAngle4d orientation) { + G3DTools.setTuple3(node.getSingleRelatedObject(Resources.g3dResource.HasLocalPosition), position); + G3DTools.setOrientation(node.getSingleRelatedObject(Resources.g3dResource.HasLocalOrientation), orientation); + //G3DTools.transformationUpdate(node.getGraph(), node.getResource()); + G3DTools.propagateLocalTransformChange(node.getSingleRelatedObject(Resources.g3dResource.HasParent), node); + } + + public static void addNodeWorld(IEntity parent, IEntity node) { + parent.addStatement(Resources.g3dResource.HasChild, node); + G3DTools.propagateWorldTransformChange(parent,node); + } + + public static void addNodeLocal(IEntity parent, IEntity node) { + parent.addStatement(Resources.g3dResource.HasChild, node); + G3DTools.propagateLocalTransformChange(parent,node); + } + + public static void addNodeWorld(IEntity parent, Resource relation, IEntity node) { + assert(parent.getGraph().isSubrelationOf(relation, Resources.g3dResource.HasChild)); + parent.addStatement(relation, node); + G3DTools.propagateWorldTransformChange(parent,node); + } + + public static void addNodeLocal(IEntity parent, Resource relation, IEntity node) { + assert(parent.getGraph().isSubrelationOf(relation, Resources.g3dResource.HasChild)); + parent.addStatement(relation, node); + G3DTools.propagateLocalTransformChange(parent,node); + } + + public static void removeNode(IEntity node) { + node.removeRelatedStatements(Resources.g3dResource.HasParent); + } + + public static void moveNode(IEntity node, IEntity newParent) { + node.removeRelatedStatements(Resources.g3dResource.HasParent); + newParent.addStatement(Resources.g3dResource.HasChild, node); + G3DTools.propagateWorldTransformChange(newParent,node); + } +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/G3DTools.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/G3DTools.java new file mode 100644 index 00000000..0b088807 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/G3DTools.java @@ -0,0 +1,399 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.base; + +import java.util.Collection; +import java.util.Set; +import java.util.Stack; + +import javax.vecmath.AxisAngle4d; +import javax.vecmath.AxisAngle4f; +import javax.vecmath.Point3d; +import javax.vecmath.Point3f; +import javax.vecmath.Quat4d; +import javax.vecmath.Tuple3d; +import javax.vecmath.Tuple3f; +import javax.vecmath.Vector3d; +import javax.vecmath.Vector3f; + +import org.simantics.db.Builtins; +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.layer0.utils.Statement; +import org.simantics.layer0.utils.IEntity; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.viewpoints.State; +import org.simantics.layer0.utils.viewpoints.TraversalDecision; +import org.simantics.layer0.utils.viewpoints.TraversalResult; +import org.simantics.layer0.utils.viewpoints.TraversalRule; +import org.simantics.layer0.utils.viewpoints.TraversalUtils; +import org.simantics.proconf.g3d.Resources; +import org.simantics.proconf.g3d.stubs.G3DNode; +import org.simantics.proconf.g3d.stubs.Orientation; +import org.simantics.proconf.g3d.stubs.Position; + +/** + * Basic ThreeDimensionalModelingOntology tools + * + * @author Marko Luukkainen + * + */ +public class G3DTools { + + private static boolean DEBUG = false; + + private static TransformationTools tt; + + public static void initialize() { + tt = new TransformationTools(Resources.g3dResource.HasChild, Resources.g3dResource.HasParent); + } + + public static void deinitialize() { + tt = null; + } + + public static Point3d getPoint(IEntity p) { + return new Point3d(p.getSingleRelatedScalarDouble(Resources.g3dResource.HasX), + p.getSingleRelatedScalarDouble(Resources.g3dResource.HasY), + p.getSingleRelatedScalarDouble(Resources.g3dResource.HasZ)); + } + + public static Point3f getPointFloat(IEntity p) { + return new Point3f((float)p.getSingleRelatedScalarDouble(Resources.g3dResource.HasX), + (float)p.getSingleRelatedScalarDouble(Resources.g3dResource.HasY), + (float)p.getSingleRelatedScalarDouble(Resources.g3dResource.HasZ)); + } + + + public static Vector3d getVector(IEntity p) { + return new Vector3d(p.getSingleRelatedScalarDouble(Resources.g3dResource.HasX), + p.getSingleRelatedScalarDouble(Resources.g3dResource.HasY), + p.getSingleRelatedScalarDouble(Resources.g3dResource.HasZ)); + } + + public static Vector3f getVectorFloat(IEntity p) { + return new Vector3f((float)p.getSingleRelatedScalarDouble(Resources.g3dResource.HasX), + (float)p.getSingleRelatedScalarDouble(Resources.g3dResource.HasY), + (float)p.getSingleRelatedScalarDouble(Resources.g3dResource.HasZ)); + } + + + public static void setTuple3(IEntity d, Tuple3d translation) { + d.setRelatedScalarDouble(Resources.g3dResource.HasX, translation.x); + d.setRelatedScalarDouble(Resources.g3dResource.HasY, translation.y); + d.setRelatedScalarDouble(Resources.g3dResource.HasZ, translation.z); + } + + public static void setTuple3(IEntity d, Tuple3f translation) { + d.setRelatedScalarDouble(Resources.g3dResource.HasX, translation.x); + d.setRelatedScalarDouble(Resources.g3dResource.HasY, translation.y); + d.setRelatedScalarDouble(Resources.g3dResource.HasZ, translation.z); + } + + public static void setTuple3(IEntity d, double x, double y, double z) { + d.setRelatedScalarDouble(Resources.g3dResource.HasX, x); + d.setRelatedScalarDouble(Resources.g3dResource.HasY, y); + d.setRelatedScalarDouble(Resources.g3dResource.HasZ, z); + } + + public static void addTuple3(IEntity d, Tuple3d translation) { + d.setRelatedScalarDouble(Resources.g3dResource.HasX, translation.x + d.getSingleRelatedScalarDouble(Resources.g3dResource.HasX)); + d.setRelatedScalarDouble(Resources.g3dResource.HasY, translation.y + d.getSingleRelatedScalarDouble(Resources.g3dResource.HasY)); + d.setRelatedScalarDouble(Resources.g3dResource.HasZ, translation.z + d.getSingleRelatedScalarDouble(Resources.g3dResource.HasZ)); + } + + public static void addTuple3(IEntity d, Tuple3f translation) { + d.setRelatedScalarDouble(Resources.g3dResource.HasX, translation.x + d.getSingleRelatedScalarDouble(Resources.g3dResource.HasX)); + d.setRelatedScalarDouble(Resources.g3dResource.HasY, translation.y + d.getSingleRelatedScalarDouble(Resources.g3dResource.HasY)); + d.setRelatedScalarDouble(Resources.g3dResource.HasZ, translation.z + d.getSingleRelatedScalarDouble(Resources.g3dResource.HasZ)); + } + + public static void addTuple3(IEntity d, double x, double y, double z) { + d.setRelatedScalarDouble(Resources.g3dResource.HasX, x + d.getSingleRelatedScalarDouble(Resources.g3dResource.HasX)); + d.setRelatedScalarDouble(Resources.g3dResource.HasY, y + d.getSingleRelatedScalarDouble(Resources.g3dResource.HasY)); + d.setRelatedScalarDouble(Resources.g3dResource.HasZ, z + d.getSingleRelatedScalarDouble(Resources.g3dResource.HasZ)); + } + + public static AxisAngle4d getOrientation(IEntity r) { + return new AxisAngle4d(r.getSingleRelatedScalarDouble(Resources.g3dResource.HasX), + r.getSingleRelatedScalarDouble(Resources.g3dResource.HasY), + r.getSingleRelatedScalarDouble(Resources.g3dResource.HasZ), + r.getSingleRelatedScalarDouble(Resources.g3dResource.HasAngle)); + } + + public static AxisAngle4f getOrientationFloat(IEntity r) { + return new AxisAngle4f((float)r.getSingleRelatedScalarDouble(Resources.g3dResource.HasX), + (float)r.getSingleRelatedScalarDouble(Resources.g3dResource.HasY), + (float)r.getSingleRelatedScalarDouble(Resources.g3dResource.HasZ), + (float)r.getSingleRelatedScalarDouble(Resources.g3dResource.HasAngle)); + } + + public static void setOrientation(IEntity r, AxisAngle4d aa) { + r.setRelatedScalarDouble(Resources.g3dResource.HasX, aa.x); + r.setRelatedScalarDouble(Resources.g3dResource.HasY, aa.y); + r.setRelatedScalarDouble(Resources.g3dResource.HasZ, aa.z); + r.setRelatedScalarDouble(Resources.g3dResource.HasAngle, aa.angle); + } + + + public static void multiplyOrientation(IEntity r, AxisAngle4d rot) { + AxisAngle4d current = getOrientation(r); + Quat4d q1 = new Quat4d(); + q1.set(current); + Quat4d q2 = new Quat4d(); + // q2.set(rot); + q2.set(rot); + q2.mul(q1); + rot.set(q2); + setOrientation(r, rot); + } + + + public static AxisAngle4d getWorldFromLocal(IEntity node, AxisAngle4d localRot) { + return tt.getWorldFromLocal(node, localRot); + } + + public static Point3d getWorldFromLocal(IEntity node, Point3d localRot) { + return tt.getWorldFromLocal(node, localRot); + } + + public static AxisAngle4d getLocalFromWorld(IEntity node, AxisAngle4d localRot) { + return tt.getLocalFromWorld(node, localRot); + } + + public static Point3d getLocalFromWorld(IEntity node, Point3d localRot) { + return tt.getLocalFromWorld(node, localRot); + } + + public static void propagateLocalTransformChange(IEntity node, IEntity child) { + tt.propagateLocalTransformChange(node, child); + } + + public static void propagateWorldTransformChange(IEntity node, IEntity child) { + tt.propagateWorldTransformChange(node, child); + } + + public static void transformationUpdate(Graph graph, Resource resource) { + tt.transformationUpdate(graph, resource); + } + + public static void resetTransformation(IEntity shape) { + Graph graph = shape.getGraph(); + if (shape.getAtMostOneRelatedObject(Resources.g3dResource.HasLocalPosition) == null) { + + // LocalPosition p = LocalPosition.createDefault(graph); + Position p = Position.createDefault(graph); + shape.addStatement(Resources.g3dResource.HasLocalPosition, p); + // WorldPosition p2 = WorldPosition.createDefault(graph); + Position p2 = Position.createDefault(graph); + shape.addStatement(Resources.g3dResource.HasWorldPosition, p2); + p.setX(new double[] { 0.0 }); + p.setY(new double[] { 0.0 }); + p.setZ(new double[] { 0.0 }); + + p2.setX(new double[] { 0.0 }); + p2.setY(new double[] { 0.0 }); + p2.setZ(new double[] { 0.0 }); + + } else { + G3DTools.setTuple3(shape.getSingleRelatedObject(Resources.g3dResource.HasLocalPosition), 0.0, 0.0, 0.0); + G3DTools.setTuple3(shape.getSingleRelatedObject(Resources.g3dResource.HasWorldPosition), 0.0, 0.0, 0.0); + } + if (shape.getAtMostOneRelatedObject(Resources.g3dResource.HasLocalOrientation) == null) { + + // LocalOrientation r = LocalOrientationFactory.create(graph); + Orientation r = Orientation.createDefault(graph); + shape.addStatement(Resources.g3dResource.HasLocalOrientation, r); + // WorldOrientation r2 = WorldOrientationFactory.create(graph); + Orientation r2 = Orientation.createDefault(graph); + shape.addStatement(Resources.g3dResource.HasWorldOrientation, r2); + r.setAngle(new double[] { 0.0 }); + r.setX(new double[] { 1.0 }); + r.setY(new double[] { 0.0 }); + r.setZ(new double[] { 0.0 }); + r2.setAngle(new double[] { 0.0 }); + r2.setX(new double[] { 1.0 }); + r2.setY(new double[] { 0.0 }); + r2.setZ(new double[] { 0.0 }); + + } else { + G3DTools.setOrientation(shape.getSingleRelatedObject(Resources.g3dResource.HasLocalOrientation), + new AxisAngle4d(0.0, 1.0, 0.0, 0.0)); + G3DTools.setOrientation(shape.getSingleRelatedObject(Resources.g3dResource.HasWorldOrientation), + new AxisAngle4d(0.0, 1.0, 0.0, 0.0)); + } + } + + + public static G3DNode getModelFromResource(Graph graph,Resource resource) { + G3DNode node = new G3DNode(graph, resource); + while (true) { + G3DNode parent = node.getParent(); + if (parent == null) + break; + node = parent; + } + return node; + } + + /** + * Checks if instance has a certain property instance + * @param instance + * @param propertyInstance + * @return + */ + public static boolean hasProperty(Graph graph,Resource instance, Resource propertyInstance) { + Builtins builtins = graph.getBuiltins(); + Stack props = new Stack(); + IEntity IEntity = EntityFactory.create(graph, instance); + Collection res = IEntity.getRelatedObjects(builtins.HasProperty); + for (IEntity t : res) + props.add(t); + + while (!props.isEmpty()) { + IEntity property = props.pop(); + if (property.getResource().equals(propertyInstance)) { + return true; + } + res = property.getRelatedObjects(builtins.HasProperty); + for (IEntity r : res) { + props.add(r); + } + } + return false; + } + + /** + * Checks if one of shapes subshapes has a certain property + * @param instance shape instance + * @param propertyInstance instance of a property + * @return + * + */ + public static boolean hasSubProperty(Graph graph,Resource instance, Resource propertyInstance) { + Builtins builtins = graph.getBuiltins(); + Stack instances = new Stack(); + + //Resource res[] = instance.getRelatedResources(Builtins.HasProperty); + IEntity entity = EntityFactory.create(graph, instance); + Collection res; +// res = entity.getRelatedObjects(Resources.g3dResource.HasChild); +// for (IEntity t : res) { +// Collection sub = t.getRelatedObjects(Resources.g3dResource.HasGeometryDefinition); +// if (sub.size() > 0) +// instances.addAll(sub); +// } + { + Collection sub = entity.getRelatedObjects(Resources.g3dResource.HasGeometryDefinition); + if (sub.size() > 0) + instances.addAll(sub); + } + while (!instances.isEmpty()) { + IEntity i = instances.pop(); + Stack props = new Stack(); + res = i.getRelatedObjects(builtins.HasProperty); + for (IEntity r : res) { + props.add(r); + } + while (!props.isEmpty()) { + IEntity property = props.pop(); + if (property.equals(propertyInstance)) { + return true; + } + res = property.getRelatedObjects(builtins.HasProperty); + for (IEntity r : res) { + props.add(r); + } + } + res = i.getRelatedObjects(Resources.g3dResource.HasGeometryDefinition); + for (IEntity r : res) { + // TODO : unnecessary check + Collection sub = r.getRelatedObjects(Resources.g3dResource.GeometryDefinitionOf); + if (sub.size() > 0) + instances.add(r); + } + + } + return false; + } + + + + + + + /** + * Loads positions of control point to rule cache + * + * @param root resource of the modeled plant + */ + public static void reloadCache(Graph graph, Resource root) { +// TraverseHandler handler = new TraverseHandler() { +// public boolean addToResult(Resource r) { +// if (r.isInstanceOf(GlobalIdMap.get(ThreeDimensionalModelingOntologyMapping.GRAPHICS_NODE))) +// return true; +// return false; +// } +// +// public TraverseRelation[] traverseFromResource(Resource resource) { +// return new TraverseRelation[] { new TraverseRelation( +// ThreeDimensionalModelingOntologyMapping.HAS_SUBNODES, +// TraverseDirection.OUTBOUND)}; +// } +// +// +// }; + + IEntity IEntity = EntityFactory.create(graph, root); + State s = new State() {}; + TraversalResult res = TraversalUtils.traverse(new TraversalRule (){ + + + @Override + public boolean areAllStatesRelevant() { + return true; + } + + @Override + public TraversalDecision makeTraversalDecision(State state, + Statement statement) { + if (statement.getPredicate().isInstanceOf(Resources.g3dResource.HasChild)) + return TraversalDecision.continueTraversal(state); + else + return TraversalDecision.stopTraversal; + } + + @Override + public Collection relevantStates() { + return null; + } + }, IEntity,s + ); + + + Set cps = res.get(s); + + //Collection cps = TraverseUtils.traverseGraph(root, handler); + for (Resource r : cps) { + G3DNode cp = new G3DNode(graph,r); + if (cp.getLocalPosition() != null) + tt.storeProperty(cp.getLocalPosition().getResource(),G3DTools.getPoint(cp.getLocalPosition())); + if (cp.getWorldPosition() != null) + tt.storeProperty(cp.getWorldPosition().getResource(),G3DTools.getPoint(cp.getWorldPosition())); + if (cp.getLocalOrientation() != null) + tt.storeProperty(cp.getLocalOrientation().getResource(),G3DTools.getOrientation(cp.getLocalOrientation())); + if (cp.getWorldOrientation() != null) + tt.storeProperty(cp.getWorldOrientation().getResource(),G3DTools.getOrientation(cp.getWorldOrientation())); + + } + } + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/GeometryProvider.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/GeometryProvider.java new file mode 100644 index 00000000..8ebb5066 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/GeometryProvider.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.base; + +import org.simantics.layer0.utils.IEntity; + + +/** + * Interface for geometryProviders + * + * TODO : instead of using Geometry array, create class that is passed through + * TODO : Current animation system links resources; what about code generated meshes ? + * + * @author Marko Luukkainen + * + */ +public interface GeometryProvider { + + /** + * Used to check if GeometryProvider can generate mesh + * @param instance + * @return + */ + public boolean canHandle(IEntity instance); + + /** + * Generates mesh + * @param instance + * @param transform + * @return + */ + public com.jme.scene.Geometry[] getGeometryFromResource(IEntity instance, boolean transform); + + /** + * Updates mesh + * @param instance + * @param transform + * @param geometry + * @return + */ + public boolean reconstructGeometry(IEntity instance, boolean transform, com.jme.scene.Geometry[] geometry); +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/GeometryProviderRegistry.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/GeometryProviderRegistry.java new file mode 100644 index 00000000..fa92b87f --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/GeometryProviderRegistry.java @@ -0,0 +1,77 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.base; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import org.simantics.db.Resource; +import org.simantics.layer0.utils.IEntity; +import org.simantics.utils.ui.plugin.Extension; +import org.simantics.utils.ui.plugin.ExtensionLoader; + +import com.jme.scene.Geometry; + +public class GeometryProviderRegistry { + private static GeometryProviderRegistry instance; + public final static String ELEMENT_NAME = "Geometry"; + public final static String NAME_SPACE = "org.simantics.proconf.g3d"; + public final static String EP_NAME = "geometry"; + + private ExtensionLoader loader; + private Map providers; + + private GeometryProviderRegistry() { + loader = new ExtensionLoader(ELEMENT_NAME, NAME_SPACE, EP_NAME); + providers = new HashMap(); + } + + public static GeometryProviderRegistry getInstance() { + if (instance==null) instance = new GeometryProviderRegistry(); + return instance; + } + + public Extension[] getExtensions() { + return loader.getExtensions(); + } + + private Map getProviderMap() { + return providers; + } + + public static Geometry[] getGeometry(IEntity thing, boolean transform) { + GeometryProvider provider = getGeometryProvider(thing); + return provider.getGeometryFromResource(thing, transform); + } + + public static GeometryProvider getGeometryProvider(IEntity thing) { + Collection types = thing.getRelatedObjects(thing.getGraph().getBuiltins().InstanceOf); + + //Resource types[] = OntologyUtils.getTypes(resource); + for (IEntity t : types) { + GeometryProvider provider = getInstance().getProviderMap().get(t.getResource()); + if (provider == null) { + for (Extension e : getInstance().getExtensions()) { + if (e.getInstance().canHandle(thing)) { + getInstance().getProviderMap().put(t.getResource(), e.getInstance()); + return e.getInstance(); + } + } + + } else { + return provider; + } + } + + throw new UnsupportedOperationException("Cannot handle resource " + thing); + } +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/JmeRenderingComponent.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/JmeRenderingComponent.java new file mode 100644 index 00000000..4e4905d3 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/JmeRenderingComponent.java @@ -0,0 +1,93 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.base; + +import com.jme.renderer.Camera; +import com.jme.scene.Node; +import com.jme.system.DisplaySystem; + + + + +/** + * Rendering component + * Allows to change underlying rendering so that + * additional information can be presented to the user + * + * @author Marko Luukkainen + * + */ +public abstract class JmeRenderingComponent { + public static final int PARALLEL_PROJECTION = 0; + public static final int PERSPECTIVE_PROJECTION = 1; + + /** + * Returns root node for nodes that cast and receive shadows. + * @return + */ + public abstract Node getShadowRoot(); + + /** + * Returns root node for nodes that do not cast shadows. + * @return + */ + public abstract Node getNoCastRoot(); + + /** + * Returns root node of the scenegraph + * @return + */ + public abstract Node getRoot(); + + /** + * Returns root node of orthogonal nodes (nodes that always face the camera) + * @return + */ + public abstract Node getOrthoNode(); + + /** + * Returns root node for nodes that do not cast or receive shadows. + * @return + */ + public abstract Node getNoShadowRoot(); + + public abstract void init(DisplaySystem displaySystem); + + /** + * Sets projection policy. + * FIXME : this was for Xith compatibility! + * @param policy + */ + public abstract void setProjectionPolicy(int policy); + public abstract int getProjectionPolicy(); + + public abstract float getScreenScale(); + public abstract void setScreenScale(float screenScale); + public abstract float getFieldOfView(); + public abstract void dispose(); + + /** + * Update flag (Return true if view needs to be rendered) + * @return + */ + public boolean update() {return false;} + public abstract Camera getCamera(); + + public abstract void render(); + public abstract void resize(int width, int height); + public abstract DisplaySystem getDisplaySystem(); + + /** + * TODO : this is for debugging purposes and will be removed. + * @param text + */ + public abstract void setDebugText(String text); +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/MathTools.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/MathTools.java new file mode 100644 index 00000000..2a89a4af --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/MathTools.java @@ -0,0 +1,395 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.base; + +import javax.vecmath.AxisAngle4d; +import javax.vecmath.Matrix3d; +import javax.vecmath.Point3d; +import javax.vecmath.Quat4d; +import javax.vecmath.Tuple3d; +import javax.vecmath.Vector3d; + +import com.jme.math.Vector2f; + +/** + * Some useful geometry related math functions. Beware, methods may modify their input parameters! + * + * @author Marko Luukkainen + * + */ +public class MathTools { + + static double EPS = 0.001; + + public static Vector3d closestPointOnEdge(Vector3d point, Vector3d edgePoint1, Vector3d edgePoint2) { + point.sub(edgePoint1); + Vector3d v = new Vector3d(edgePoint2); + v.sub(edgePoint1); + double t = v.dot(point); + t /= v.lengthSquared(); + if (t <= 0.0f) + return edgePoint1; + if (t >= 1.0f) + return edgePoint2; + v.scale(t); + v.add(edgePoint1); + return v; + } + + public static Vector3d closestPointOnStraight(Point3d point, Point3d straightPoint, Vector3d straightDir) { + Vector3d v = new Vector3d(point); + v.sub(straightPoint); + double t = straightDir.dot(v); + t /= straightDir.lengthSquared(); + v.set(straightDir); + v.scale(t); + v.add(straightPoint); + return v; + } + + public static Vector3d closestPointOnStraight(Point3d point, Point3d straightPoint, Vector3d straightDir, double u[]) { + Vector3d v = new Vector3d(point); + v.sub(straightPoint); + u[0] = straightDir.dot(v); + u[0] /= straightDir.lengthSquared(); + v.set(straightDir); + v.scale(u[0]); + v.add(straightPoint); + return v; + } + + public static double distanceFromPlane(Vector3d point, Vector3d planeNormal, Tuple3d planePoint) { + point.sub(planePoint); + + return planeNormal.dot(point); + } + + public static double distanceFromPlane(Vector3d point, Vector3d planeNormal, float d) { + return (planeNormal.dot(point) + d); + } + + public static boolean intersectStraightPlane(Tuple3d linePoint, Vector3d lineDir, Tuple3d planePoint, Vector3d planeNormal, Tuple3d intersectPoint) { + intersectPoint.set(planePoint); + intersectPoint.sub(linePoint); + double u = planeNormal.dot(new Vector3d(intersectPoint)); + double v = planeNormal.dot(lineDir); + if (Math.abs(v) < EPS) + return false; + u /= v; + intersectPoint.set(lineDir); + intersectPoint.scale(u); + intersectPoint.add(linePoint); + return true; + } + + public static boolean intersectStraightPlane(Tuple3d linePoint, Vector3d lineDir, Tuple3d planePoint, Vector3d planeNormal, Vector3d intersectPoint, double[] u) { + intersectPoint.set(planePoint); + intersectPoint.sub(linePoint); + u[0] = planeNormal.dot(intersectPoint); + double v = planeNormal.dot(lineDir); + if (Math.abs(v) < EPS) + return false; + u[0] /= v; + intersectPoint.set(lineDir); + intersectPoint.scale(u[0]); + intersectPoint.add(linePoint); + return true; + } + + public static boolean intersectLineLine(Vector3d p1,Vector3d p2,Vector3d p3,Vector3d p4,Vector3d pa,Vector3d pb) { + Vector3d p13 = new Vector3d(); + Vector3d p43 = new Vector3d(); + Vector3d p21 = new Vector3d(); + double d1343,d4321,d1321,d4343,d2121; + double numer,denom; + p13.sub(p1, p3); + p43.sub(p4,p3); + if (Math.abs(p43.x) < EPS && Math.abs(p43.y) < EPS && Math.abs(p43.z) < EPS) + return false; + p21.sub(p2,p1); + if (Math.abs(p21.x) < EPS && Math.abs(p21.y) < EPS && Math.abs(p21.z) < EPS) + return false; + + d1343 = p13.dot(p43); + d4321 = p43.dot(p21); + d1321 = p13.dot(p21); + d4343 = p43.lengthSquared(); + d2121 = p21.lengthSquared(); + + denom = d2121 * d4343 - d4321 * d4321; + if (Math.abs(denom) < EPS) + return false; + numer = d1343 * d4321 - d1321 * d4343; + + double mua = numer / denom; + double mub = (d1343 + d4321 * mua) / d4343; + + pa.x = p1.x + mua * p21.x; + pa.y = p1.y + mua * p21.y; + pa.z = p1.z + mua * p21.z; + pb.x = p3.x + mub * p43.x; + pb.y = p3.y + mub * p43.y; + pb.z = p3.z + mub * p43.z; + + return true; + } + + public static boolean intersectStraightStraight(Vector3d p1,Vector3d p21,Vector3d p3,Vector3d p43,Tuple3d pa,Tuple3d pb) { + Vector3d p13 = new Vector3d(); + + double d1343,d4321,d1321,d4343,d2121; + double numer,denom; + + p13.sub(p1, p3); + if (Math.abs(p43.x) < EPS && Math.abs(p43.y) < EPS && Math.abs(p43.z) < EPS) + return false; + if (Math.abs(p21.x) < EPS && Math.abs(p21.y) < EPS && Math.abs(p21.z) < EPS) + return false; + + d1343 = p13.dot(p43); + d4321 = p43.dot(p21); + d1321 = p13.dot(p21); + d4343 = p43.lengthSquared(); + d2121 = p21.lengthSquared(); + + denom = d2121 * d4343 - d4321 * d4321; + if (Math.abs(denom) < EPS) + return false; + numer = d1343 * d4321 - d1321 * d4343; + + double mua = numer / denom; + double mub = (d1343 + d4321 * mua) / d4343; + + pa.x = p1.x + mua * p21.x; + pa.y = p1.y + mua * p21.y; + pa.z = p1.z + mua * p21.z; + pb.x = p3.x + mub * p43.x; + pb.y = p3.y + mub * p43.y; + pb.z = p3.z + mub * p43.z; + + return true; + } + + /** + * Calculate the line segment PaPb that is the shortest route between + * two lines P1P2 and P3P4. Calculate also the values of mua and mub where + * Pa = P1 + mua (P2 - P1) + * Pb = P3 + mub (P4 - P3) + * @param p1 + * @param p21 + * @param p3 + * @param p43 + * @param pa + * @param pb + * @param mu + * @return + */ + public static boolean intersectStraightStraight(Tuple3d p1,Vector3d p21,Tuple3d p3,Vector3d p43,Tuple3d pa,Tuple3d pb, double mu[]) { + Vector3d p13 = new Vector3d(); + + double d1343,d4321,d1321,d4343,d2121; + double numer,denom; + double EPS = 0.001; + p13.sub(p1, p3); + if (Math.abs(p43.x) < EPS && Math.abs(p43.y) < EPS && Math.abs(p43.z) < EPS) + return false; + if (Math.abs(p21.x) < EPS && Math.abs(p21.y) < EPS && Math.abs(p21.z) < EPS) + return false; + + d1343 = p13.dot(p43); + d4321 = p43.dot(p21); + d1321 = p13.dot(p21); + d4343 = p43.lengthSquared(); + d2121 = p21.lengthSquared(); + + denom = d2121 * d4343 - d4321 * d4321; + if (Math.abs(denom) < EPS) + return false; + numer = d1343 * d4321 - d1321 * d4343; + + mu[0] = numer / denom; + mu[1] = (d1343 + d4321 * mu[0]) / d4343; + + pa.x = p1.x + mu[0] * p21.x; + pa.y = p1.y + mu[0] * p21.y; + pa.z = p1.z + mu[0] * p21.z; + pb.x = p3.x + mu[1] * p43.x; + pb.y = p3.y + mu[1] * p43.y; + pb.z = p3.z + mu[1] * p43.z; + + return true; + } + + public static AxisAngle4d getFromEuler2(Vector3d euler) { + AxisAngle4d aa = new AxisAngle4d(); + aa.angle = euler.length(); + Vector3d normal = new Vector3d(euler); + if (aa.angle > EPS) { + normal.normalize(); + aa.x = normal.x; + aa.y = normal.y; + aa.z = normal.z; + } else { + aa.x = 1.0; + aa.y = 0.0; + aa.z = 0.0; + } + + return aa; + } + + public static Vector3d getEuler(AxisAngle4d aa) { + Vector3d euler = new Vector3d(aa.x,aa.y,aa.z); + euler.scale(aa.angle); + return euler; + } + + public static void rotate(Quat4d q, Tuple3d in, Tuple3d out) { + // p' = q * p * q' + double tw = - q.x*in.x - q.y*in.y - q.z*in.z; + double tx = q.w*in.x + q.y*in.z - q.z*in.y; + double ty = q.w*in.y - q.x*in.z + q.z*in.x; + double tz = q.w*in.z + q.x*in.y - q.y*in.x ; + + //temp * q' -> x = -x, y = -y z = -z + //out.w = tw*q.w + tx*q.x + ty*q.y + tz*q.z; + out.x = -tw*q.x + tx*q.w - ty*q.z + tz*q.y; + out.y = -tw*q.y + tx*q.z + ty*q.w - tz*q.x; + out.z = -tw*q.z - tx*q.y + ty*q.x + tz*q.w; + } + + public static void getMatrix(Quat4d quat, Matrix3d m) { + m.m00 = 1.0f - 2.0 * (quat.y * quat.y + quat.z * quat.z); + m.m01 = 2.0 * (quat.x * quat.y + quat.w * quat.z); + m.m02 = 2.0 * (quat.x * quat.z - quat.w * quat.y); + m.m10 = 2.0 * (quat.x * quat.y - quat.w * quat.z); + m.m11 = 1.0 - 2.0f * (quat.x * quat.x + quat.z * quat.z); + m.m12 = 2.0 * (quat.y * quat.z + quat.w * quat.x); + m.m20 = 2.0 * (quat.x * quat.z + quat.w * quat.y); + m.m21 = 2.0 * (quat.y * quat.z - quat.w * quat.x); + m.m22 = 1.0 - 2.0f * (quat.x * quat.x + quat.y * quat.y); + + } + + public static void getQuat(Matrix3d mat, Quat4d quat) { + double tr = mat.m00 + mat.m11 + mat.m22; + if (tr > 0.0) { + double s = Math.sqrt(tr + 1.0); + quat.w = 0.5 * s; + s = 0.5 / s; + quat.x = (mat.m21 - mat.m12) * s; + quat.y = (mat.m02 - mat.m20) * s; + quat.z = (mat.m10 - mat.m01) * s; + } else { + int i = 0, j, k; + if (mat.m11 > mat.m00) + i = 1; + if (mat.m22 > mat.getElement(i, i)) + i = 2; + int nxt[] = { 1, 2, 0 }; + + j = nxt[i]; + k = nxt[j]; + + double s = Math + .sqrt((mat.getElement(i, i) - (mat.getElement(j, j) + mat + .getElement(k, k))) + 1.0); + + double q[] = new double[3]; + q[i] = s * 0.5; + + if (Math.abs(s) > 0.001) + s = 0.5 / s; + + quat.w = (mat.getElement(k, j) - mat.getElement(j, k)) * s; + q[j] = (mat.getElement(j, i) + mat.getElement(i, j)) * s; + q[k] = (mat.getElement(k, i) + mat.getElement(i, k)) * s; + + quat.x = q[0]; + quat.y = q[1]; + quat.z = q[2]; + } + } + + + /* + * Cohen-Sutherland + */ + + private static final int IN = 0; + private static final int LEFT = 1; + private static final int RIGHT = 2; + private static final int BOTTOM = 4; + private static final int TOP = 8; + + + private static int bitcode(Vector2f p1, Vector2f min, Vector2f max) { + int code = IN; + if (p1.x < min.x) + code |= LEFT; + else if (p1.x > max.x) + code |= RIGHT; + if (p1.y < min.y) + code |= BOTTOM; + else if (p1.y > max.y) + code |= TOP; + return code; + } + + public static boolean clipLineRectangle(Vector2f p1,Vector2f p2, Vector2f min, Vector2f max, Vector2f r1, Vector2f r2) { + while (true) { + int o1 = bitcode(p1, min, max); + int o2 = bitcode(p2, min, max); + int and = o1 & o2; + int or = o1 | o2; + if (and != IN) { + return false; + } + if (or == IN) { + r1.set(p1); + r2.set(p2); + return true; + } + if (o1 == IN) { + Vector2f t = p1; + p1 = p2; + p2 = t; + int t2 = o1; + o1 = o2; + o2 = t2; + } + if ((o1 & TOP) != IN) { + float t = (max.y - p1.y) / (p2.y - p1.y); + p1.x += t * (p2.x - p1.x); + p1.y = max.y; + } else if ((o1 & BOTTOM) != IN) { + float t = (min.y - p1.y) / (p2.y - p1.y); + p1.x += t * (p2.x - p1.x); + p1.y = min.y; + } else if ((o1 & LEFT) != IN) { + float t = (min.x - p1.x) / (p2.x - p1.x); + p1.y += t * (p2.y - p1.y); + p1.x = min.x; + } else if ((o1 & RIGHT) != IN) { + float t = (max.x - p1.x) / (p2.x - p1.x); + p1.y += t * (p2.y - p1.y); + p1.x = max.x; + } else { + throw new RuntimeException("Error in clipping code"); + } + } + + } + + public static double square(double d) { + return d * d; + } +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/ResourceTextureCache.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/ResourceTextureCache.java new file mode 100644 index 00000000..bbba901f --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/ResourceTextureCache.java @@ -0,0 +1,220 @@ +package org.simantics.proconf.g3d.base; + +import java.nio.ByteBuffer; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.swt.graphics.ImageData; +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.proconf.g3d.Resources; +import org.simantics.proconf.g3d.stubs.ImageTexture; +import org.simantics.proconf.g3d.stubs.TextureCoordinateGenerator; +import org.simantics.proconf.image.interfaces.IImage; +import org.simantics.proconf.image.interfaces.IImageFactory; +import org.simantics.utils.ErrorLogger; +import org.simantics.utils.ui.gfx.ImageUtils; +import org.simantics.utils.ui.gfx.PixelDimension; + +import com.jme.image.Image; +import com.jme.image.Texture; +import com.jme.util.TextureManager; + +/** + * Caches resource based textures. + * TODO : use queries to update textures, now textures are read once and cannot be updated + * TODO : either use shared context or use separate cache for each editor + * TODO : ShapeNode implementation won't use release texture yet + * TODO : Texture is released when reference count goes to zero; we probably want to wait for a while before texture is released because it might be used again. + * + * @author Marko Luukkainen + * + */ +public class ResourceTextureCache { + + public static PixelDimension DEFAULT_SIZE = new PixelDimension(128,128); + + private static ResourceTextureCache instance = new ResourceTextureCache(); + + private Map images = new HashMap(); + private Map imageReferences = new HashMap(); + + private Map textures = new HashMap(); + private Map textureReferences = new HashMap(); + + + private ResourceTextureCache() { + + } + + public Texture loadTexture(Graph g, Resource res) { + Texture t = textures.get(res); + if (t == null) { + ImageTexture it = new ImageTexture(g,res); + org.simantics.image.stubs.Image pattern = it.getImage(); + Image image = loadImage(g, pattern.getResource()); +// image.getData().rewind(); +// while (image.getData().hasRemaining()) +// image.getData().put((byte)(Math.random()*256.0 - 127.0)); + if (image == null) { + return null; + } + t = new Texture(); + t.setImage(image); + + //t = TextureManager.loadTexture(image, Texture.MM_LINEAR, Texture.FM_LINEAR); +// t.setImageLocation(res.toString()); +// URL url = FileLocator.find(com.jme.eclipse.Activator.getDefault().getBundle(),new Path("data/texture/clouds.png"),null); +// t = TextureManager.loadTexture(url, Texture.MM_LINEAR, Texture.FM_LINEAR); + + t.setFilter(com.jme.image.Texture.FM_LINEAR); + t.setMipmapState(com.jme.image.Texture.MM_LINEAR); + t.setApply(Texture.AM_COMBINE); + t.setCombineFuncRGB(Texture.ACF_MODULATE); + t.setCombineScaleRGB(2.f); + + //t.setWrap(com.jme.image.Texture.WM_WRAP_S_WRAP_T); + + TextureCoordinateGenerator gen = it.getTextureCoordinateGenerator(); + setTextureCoordGenerator(gen, t); + textures.put(res, t); + } + addTextureReference(res); + return t; + } + + public void releaseTexture(Graph g, Resource res) { + Integer i = textureReferences.get(res); + if (i != null) { + i = i - 1; + if (i == 0) { + Texture t = textures.get(res); + ImageTexture it = new ImageTexture(g,res); + org.simantics.image.stubs.Image pattern = it.getImage(); + releaseImage(pattern.getResource()); + t.setImage(null); + textureReferences.remove(res); + //FIXME : release the texture + } else { + textureReferences.put(res, i); + } + + } else { + throw new RuntimeException("Cannot released texture that does not exist " + res); + } + } + + public Image loadImage(Graph g, Resource res) { + Image image = images.get(res); + if (image == null) { + org.simantics.image.stubs.Image pattern = new org.simantics.image.stubs.Image(g,res); + IImageFactory f = org.simantics.proconf.image.ImageUtils.getImageFactoryForResource(g,pattern.getResource()); + try { + IImage p = f.createImageForResource(g,pattern.getResource()); + PixelDimension pd = p.getDimensions().getPixelDimension(); + if (pd==null) pd = DEFAULT_SIZE; + ImageData data = p.rasterize(pd.getWidth(), pd.getHeight()); + image = getImage(data); + images.put(res, image); + + } catch (Exception e) { + ErrorLogger.defaultLogError("Cannor create pattern texture for resource " + pattern, e); + return null; + } + } + addImageReference(res); + return image; + + } + + private void addTextureReference(Resource res) { + Integer i = textureReferences.get(res); + if (i != null) { + imageReferences.put(res, i + 1); + } else { + imageReferences.put(res, 1); + } + } + + private void addImageReference(Resource res) { + Integer i = imageReferences.get(res); + if (i != null) { + imageReferences.put(res, i + 1); + } else { + imageReferences.put(res, 1); + } + } + + public void releaseImage(Resource res) { + Integer i = imageReferences.get(res); + if (i != null) { + i = i - 1; + if (i == 0) { + Image image = images.get(res); + image.getData().clear(); + image.setData(null); + images.remove(res); + imageReferences.remove(res); + } else { + imageReferences.put(res, i); + } + } else { + throw new RuntimeException("Cannot release image that does not exist."); + } + } + + public static ResourceTextureCache getInstance() { + return instance; + } + + private static Image getImage(ImageData imageData) { + int width = imageData.width; + int height = imageData.height; + int type = 0; + + int components = 3; + + type = Image.RGB888; + if (imageData.alphaData != null) { + type = Image.RGBA8888; + components = 4; + } + + ByteBuffer buf = ByteBuffer.allocateDirect(components * width * height); + ImageUtils.convertToRGBA(imageData, buf); + return new Image(type,width,height,buf); + } + + + public static void setTextureCoordGenerator(TextureCoordinateGenerator gen, com.jme.image.Texture texture) { + if (gen == null) + return ; + + //g3dResource. + if (gen.equals(Resources.g3dResource.TextureCoordinateGenerator_sphere)) + texture.setEnvironmentalMapMode(com.jme.image.Texture.EM_SPHERE); + else if (gen.equals(Resources.g3dResource.TextureCoordinateGenerator_eyelinear)) + texture.setEnvironmentalMapMode(com.jme.image.Texture.EM_EYE_LINEAR); + else if (gen.equals(Resources.g3dResource.TextureCoordinateGenerator_objectlinear)) + texture.setEnvironmentalMapMode(com.jme.image.Texture.EM_OBJECT_LINEAR); + else if (gen.equals(Resources.g3dResource.TextureCoordinateGenerator_normal)) + ErrorLogger.getDefault().logWarning("JME doesn't support normal texture coordinate generation", null); + else if (gen.equals(Resources.g3dResource.TextureCoordinateGenerator_reflection)) + ErrorLogger.getDefault().logWarning("JME doesn't support reflection texture coordinate generation", null); + else + ErrorLogger.getDefault().logWarning("Unsupported TexGen type " + gen.getName(), null); + } + + public void clear() { + for (Image i : images.values()) + i.setData(null); + for (Texture t : textures.values()) + t.setImage(null); + imageReferences.clear(); + textureReferences.clear(); + images.clear(); + textures.clear(); + + } + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/ScenegraphAdapter.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/ScenegraphAdapter.java new file mode 100644 index 00000000..e2d02874 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/ScenegraphAdapter.java @@ -0,0 +1,122 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.base; + +import java.util.Collection; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.layer0.utils.IEntity; +import org.simantics.proconf.g3d.scenegraph.IGeometryNode; +import org.simantics.proconf.g3d.scenegraph.IGraphicsNode; +import org.simantics.proconf.g3d.stubs.G3DNode; + +import com.jme.scene.Node; + +public interface ScenegraphAdapter { + + /** + * Disposes the adapter + */ + public void dispose(); + + /** + * Returns scene-graph node of the resource + * @param resource + * @return + */ + public IGraphicsNode getNode(Resource resource); + + /** + * Returns scene-graph node of the resource + * @param thing + * @return + */ + public IGraphicsNode getNode(IEntity thing); + + /** + * Returns node (resource) for the uid. + * @param uid + * @return the node (resource) + */ + public Resource getNodeResource(String uid); + + /** + * @return all nodes in the scene-graph + */ + public Collection getNodes(); + + /** + * Returns uid of the node. + * @param nodeResource + * @return + */ + public String getNodeUID(Resource nodeResource); + + public JmeRenderingComponent getRenderingComponent(); + + public Node getRoot(); + + public IGraphicsNode getRootNode(); + + public Resource getRootResource(); + + /** + * Returns true if the scene-graph contains the node + * @param resource + * @return + */ + public boolean hasNode(Resource resource); + + /** + * Checks if the view has been changed (and needs redrawing). + * @return + */ + public boolean isChanged(); + + /** + * Checks if any geometries needs updating + * @return + */ + public boolean needsUpdateGeometry(); + + /** + * + * @param changed + */ + public void setChanged(boolean changed); + + /** + * Sets the root node of the scene-graph + * @param rootNode + */ + public void setRootNode(G3DNode rootNode); + + /** + * Updates requested geometries. + * + * @param graph + */ + public void updateGeometry(Graph graph); + + /** + * Updates node's geometry + * @param node + */ + public void updateGeometry(IGeometryNode node); + + /** + * Updates node's geometry + * @param nodeResource + */ + public void updateGeometry(Resource nodeResource); + +} \ No newline at end of file diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/ScenegraphAdapterImpl.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/ScenegraphAdapterImpl.java new file mode 100644 index 00000000..43a53a27 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/ScenegraphAdapterImpl.java @@ -0,0 +1,828 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.base; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Queue; +import java.util.Set; +import java.util.Stack; +import java.util.concurrent.ConcurrentLinkedQueue; + +import org.simantics.db.AbstractQuery; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Resource; +import org.simantics.db.Session; +import org.simantics.db.queries.IGraphQuery; +import org.simantics.db.queries.IQuery; +import org.simantics.db.queries.IQueryListener; +import org.simantics.db.utils.transaction.MergingTransactionRunner; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.layer0.utils.Property; +import org.simantics.proconf.g3d.Resources; +import org.simantics.proconf.g3d.scenegraph.IGeometryNode; +import org.simantics.proconf.g3d.scenegraph.IGraphicsNode; +import org.simantics.proconf.g3d.scenegraph.RootGraphicsNode; +import org.simantics.proconf.g3d.stubs.G3DNode; +import org.simantics.utils.ErrorLogger; +import org.simantics.utils.datastructures.BijectionMap; + +import com.jme.scene.Node; + + +/** + * Scene-graph adapter : + * 1. Adapts graph change events into changes in actual scene-graph nodes. + * 2. Handles instantiating and disposing of Scene-graph nodes. + * 3. + * + * @author Marko Luukkainen + * + */ +public abstract class ScenegraphAdapterImpl implements ScenegraphAdapter { + + protected static boolean DEBUG = false; + + private RootGraphicsNode root; + private HashMap scenegraphQueries = new HashMap(); + private HashMap propertyQueries = new HashMap(); + private HashMap transformationQueries = new HashMap(); + private HashMap abstractGraphicsNodes = new HashMap(); + protected Queue geometryUpdates = new ConcurrentLinkedQueue(); + + private BijectionMap nameMap = new BijectionMap(); + + protected JmeRenderingComponent component; + + protected boolean viewChanged = false; + + protected Session session; + + private MergingTransactionRunner transactionRunner; + + public ScenegraphAdapterImpl(Session session, JmeRenderingComponent component) { + this.component = component; + this.session = session; + transactionRunner = new MergingTransactionRunner(session,true); + } + + + @Override + public JmeRenderingComponent getRenderingComponent() { + return component; + } + + /* (non-Javadoc) + * @see fi.vtt.simantics.g3d.scenegraph.IScenegraphAdapter#setRootNode(fi.vtt.simantics.g3d.stubs.G3DNode) + */ + public void setRootNode(G3DNode rootNode) { + addSubnodeListener(rootNode); + root = new RootGraphicsNode(component,rootNode.getResource()); + abstractGraphicsNodes.put(rootNode.getResource(),root); + G3DTools.reloadCache(rootNode.getGraph(),root.getResource()); + addRootPropertyListener(rootNode.getGraph()); + } + + /* (non-Javadoc) + * @see fi.vtt.simantics.g3d.scenegraph.IScenegraphAdapter#needsUpdateGeometry() + */ + public boolean needsUpdateGeometry() { + return geometryUpdates.size() > 0; + } + + /* (non-Javadoc) + * @see fi.vtt.simantics.g3d.scenegraph.IScenegraphAdapter#updateGeometry(fi.vtt.simantics.g3d.scenegraph.IGeometryNode) + */ + public void updateGeometry(IGeometryNode node) { + geometryUpdates.add(node); + } + + /* (non-Javadoc) + * @see fi.vtt.simantics.g3d.scenegraph.IScenegraphAdapter#updateGeometry(fi.vtt.simantics.db.connection.Resource) + */ + public void updateGeometry(Resource nodeResource) { + geometryUpdates.add((IGeometryNode)abstractGraphicsNodes.get(nodeResource)); + } + + + /* (non-Javadoc) + * @see fi.vtt.simantics.g3d.scenegraph.IScenegraphAdapter#updateGeometry(fi.vtt.simantics.db.connection.Graph) + */ + public synchronized void updateGeometry(Graph graph) { + if (geometryUpdates.size() > 0) { + for (IGeometryNode n : geometryUpdates) { + try { + n.updateGeometry(graph); + if (DEBUG) System.out.println("ScenegraphAdapterImpl: geometryUpdated " + n.getResource()); + } catch (Exception e) { + ErrorLogger.defaultLogError("Failed to update geometry of node" + n.getResource(), e); + } + } + geometryUpdates.clear(); + viewChanged = true; + //if (DEBUG) System.out.println("ScenegraphAdapterImpl: geometryUpdated"); + } + } + + /* (non-Javadoc) + * @see fi.vtt.simantics.g3d.scenegraph.IScenegraphAdapter#getNodes() + */ + public Collection getNodes() { + return abstractGraphicsNodes.values(); + } + + /* (non-Javadoc) + * @see fi.vtt.simantics.g3d.scenegraph.IScenegraphAdapter#getNode(fi.vtt.simantics.db.connection.Resource) + */ + public IGraphicsNode getNode(Resource resource) { + return abstractGraphicsNodes.get(resource); + } + + /* (non-Javadoc) + * @see fi.vtt.simantics.g3d.scenegraph.IScenegraphAdapter#getRootNode() + */ + public IGraphicsNode getRootNode() { + return getNode(getRootResource()); + } + + /* (non-Javadoc) + * @see fi.vtt.simantics.g3d.scenegraph.IScenegraphAdapter#getNode(fi.vtt.simantics.layer0.utils.IEntity) + */ + public IGraphicsNode getNode(IEntity IEntity) { + return abstractGraphicsNodes.get(IEntity.getResource()); + } + + /* (non-Javadoc) + * @see fi.vtt.simantics.g3d.scenegraph.IScenegraphAdapter#getNodeResource(java.lang.String) + */ + public Resource getNodeResource(String uid) { + return nameMap.getLeft(uid); + } + + /* (non-Javadoc) + * @see fi.vtt.simantics.g3d.scenegraph.IScenegraphAdapter#getNodeUID(fi.vtt.simantics.db.connection.Resource) + */ + public String getNodeUID(Resource nodeResource) { + String name = nameMap.getRight(nodeResource); + if (name == null) { + //name = UUID.randomUUID().toString(); + name = Long.toString(nodeResource.getResourceId()); + nameMap.map(nodeResource, name); + } + return name; + } + + /* (non-Javadoc) + * @see fi.vtt.simantics.g3d.scenegraph.IScenegraphAdapter#hasNode(fi.vtt.simantics.db.connection.Resource) + */ + public boolean hasNode(Resource resource) { + return abstractGraphicsNodes.containsKey(resource); + } + + /* (non-Javadoc) + * @see fi.vtt.simantics.g3d.scenegraph.IScenegraphAdapter#getRootResource() + */ + public Resource getRootResource() { + if (root == null) + return null; + return root.getResource(); + } + + /* (non-Javadoc) + * @see fi.vtt.simantics.g3d.scenegraph.IScenegraphAdapter#getRoot() + */ + public Node getRoot() { + return root.getGroup(); + } + + /* (non-Javadoc) + * @see fi.vtt.simantics.g3d.scenegraph.IScenegraphAdapter#dispose() + */ + public void dispose() { + Set shapes = new HashSet(abstractGraphicsNodes.keySet()); + for (Resource r : shapes) { + removeNode(r); + } + } + + /* (non-Javadoc) + * @see fi.vtt.simantics.g3d.scenegraph.IScenegraphAdapter#isChanged() + */ + public boolean isChanged() { + return viewChanged; + } + + /* (non-Javadoc) + * @see fi.vtt.simantics.g3d.scenegraph.IScenegraphAdapter#setChanged(boolean) + */ + public void setChanged(boolean changed) { + viewChanged = changed; + } + + + /** + * Instantiates Listener that listens hierarchy changes in the node (subnode + * added and/or removed) + * + * @param node + * @return + */ + protected abstract ScenegraphQuery newSubnodeListener(G3DNode node); + + protected void addSubnodeListener(G3DNode node) { + if (DEBUG) System.out.println("ScenegraphAdapter.addSubnodeListener( " + node.getResource() + " )"); + ScenegraphQuery q = newSubnodeListener(node); + node.getGraph().performQuery(q); + scenegraphQueries.put(node.getResource(), q); + } + + /** + * Returns propertyQuery for a single scene-graph node. + * @param node + * @return + */ + protected abstract NodePropertyQuery newPropertyListener(G3DNode node); + + /** + * Returns transformationQuery for a single scene-graph node + * @param root + * @return + */ + protected abstract NodeTransformationQuery newTransformationListener(G3DNode root); + + /** + * Returns propertyQuery for the root node. + * May return null if root node has no interesting properties. + * + * Potentially root node could contain lighting settings, and so on... + * + * @param root + * @return + */ + protected abstract NodePropertyQuery newRootPropertyListener(G3DNode root); + + protected void addPropertyListener(G3DNode node) { + if (DEBUG) System.out.println("ScenegraphAdapter.addPropertyListener( " + node.getResource() + " )"); + NodePropertyQuery q = newPropertyListener(node); + node.getGraph().performQuery(q); + propertyQueries.put(node.getResource(),q); + } + + + protected void addTransformationListener(G3DNode node) { + if (DEBUG) System.out.println("ScenegraphAdapter.addPropertyListener( " + node.getResource() + " )"); + NodeTransformationQuery q = newTransformationListener(node); + node.getGraph().performQuery(q); + transformationQueries.put(node.getResource(),q); + } + + protected void addRootPropertyListener(Graph g) { + G3DNode node = root.getG3DNode(g); + if (DEBUG) System.out.println("ScenegraphAdapter.addRootPropertyListener( " + node.getResource() + " )"); + NodePropertyQuery q = newRootPropertyListener(node); + if (q == null) + return; + node.getGraph().performQuery(q); + propertyQueries.put(node.getResource(),q); + } + + /** + * Instantiates a new scene-graph node + * + * @param parent the parent of the new node. + * @param node the new node. + * @return + */ + protected abstract IGraphicsNode instantiateNode(IGraphicsNode parent, G3DNode node); + + + /** + * Adds node into scene-graph + * @param parent the parent of the node + * @param r resource of the node + * @return created scene-graph node + */ + protected IGraphicsNode addNode(IEntity parent, IEntity r) { + if (!r.isInstanceOf(Resources.g3dResource.G3DNode)) { + ErrorLogger.defaultLogError("Trying to add node into scenegraph that is not instance of graphicsnode " + r,new Exception("ASSERT!")); + return null; + } + if (parent.equals(r)) { + if (DEBUG) System.out.println("ThreeDimensionalEditorBase.addNodeP(" + r.getResource().getResourceId() + ") adding node to itself?!"); + ErrorLogger.defaultLogError("Adding scnegraphnode " + r.getResource().getResourceId() + " to itself!", new Exception("ASSERT!")); + return abstractGraphicsNodes.get(r); + } + + if (abstractGraphicsNodes.containsKey(r)) { + + IGraphicsNode inView = abstractGraphicsNodes.get(r); + if (inView.getParent() == null) { + //if graphicsNode has no parent it must be the root node + ErrorLogger.defaultLogError("Trying to add rootnode into scenegraph " + r, null); + return null; + } + if (parent.equals(inView.getParent().getResource())) { + if (DEBUG) System.out.println("ThreeDimensionalEditorBase.addNodeP(" + r.getResource().getResourceId() + ") already in view"); + return inView; + } else { + if (DEBUG) System.out.println("ThreeDimensionalEditorBase.addNodeP(" + r.getResource().getResourceId() + ") already in view, but has different parent, current parent is ("+inView.getParent().getResource()+") and node is added to ("+parent+") -> removing from old parent and inserting to new"); + removeNode(inView.getParent().getResource(),r.getResource()); + } + } + + G3DNode node = new G3DNode(r); + + IGraphicsNode mo; + IGraphicsNode parentNode = abstractGraphicsNodes.get(parent); + if (parentNode == null) { + if (DEBUG) System.out.println("No graphicsnode for (" + parent.getResource().getResourceId() + ")"); + return null; + } else { + mo = instantiateNode(parentNode, node); + if (mo == null) { + ErrorLogger.defaultLogError("Could not instantiate scenegraph node for " + r.getResource().getResourceId(), null); + return null; + } + if (DEBUG) System.out.println("ThreeDimensionalEditorBase.addNodeP(" + r.getResource().getResourceId() + ") added to parent (" + parent.getResource().getResourceId() + ") " + mo.getClass()); + } + addSubnodeListener(node); + addPropertyListener(node); + addTransformationListener(node); + + abstractGraphicsNodes.put(r.getResource(), mo); + + + + // FIXME : this is a hack to fix transformations of instantiated nodes +// if (graph.getCurrentTransaction() != null) { +// try { +// G3DTools.propagateWorldTransformChange(parentNode +// .getG3DNode()); +// graph.commitChanges(CommitMessage.CHANGE_MESSAGE); +// // G3DNodeTools.transformationUpdate(graph, r.getId()); +// } catch (Exception e) { +// ErrorLogger.defaultLogError(e); +// } +// } + + + return mo; + } + + /** + * This is used only when view is disposed! + * + * @param r + */ + private void removeNode(Resource r) { + NodeTransformationQuery tq = transformationQueries.get(r); + //StructuralChangeMonitor monitor = monitors.getLeft(r); + if (tq == null) { + if (abstractGraphicsNodes.containsKey(r)) { + // root node has no monitor (no transformation to monitor) + //System.out.println("ThreeDimensionalEditorBase.removeNode(" + r + ") node has no monitor, but has node in scenegraph"); + abstractGraphicsNodes.remove(r); + if(scenegraphQueries.get(r) != null) { + scenegraphQueries.get(r).dispose(); + scenegraphQueries.remove(r); + } + } else { + //System.out.println("ThreeDimensionalEditorBase.removeNode(" + r + ") not in view"); + } + return; + } + // remove listeners + propertyQueries.remove(r).dispose(); + transformationQueries.remove(r).dispose(); + scenegraphQueries.get(r); + scenegraphQueries.remove(r).dispose(); + // remove children + IGraphicsNode node = abstractGraphicsNodes.get(r); + ArrayList children = new ArrayList(node.getChildren()); + for (IGraphicsNode n : children) { + removeNode(n.getResource()); + } + // remove the node + if (DEBUG) System.out.println("ThreeDimensionalEditorBase.removeNode(" + r + ") removed"); + + node.dispose(); + abstractGraphicsNodes.remove(r); + + } + + /** + * Removes a scene-graph node. + * @param parent the parent of the node + * @param r the node. + */ + protected void removeNode(Resource parent,Resource r) { + NodePropertyQuery q = propertyQueries.get(r); + if (q == null) { + assert(!abstractGraphicsNodes.containsKey(r)); + if (DEBUG) System.out.println("ThreeDimensionalEditorBase.removeNodeP(" + r + ") not in view"); + return; + } + + IGraphicsNode node = abstractGraphicsNodes.get(r); + Resource rParent = node.getParent().getResource(); + if (!rParent.equals(parent)) { + // this event may happen, depending of the order of events in transaction + if (DEBUG) System.out.println("ThreeDimensionalEditorBase.removeNodeP(" + r + ") trying to remove from wrong parent current ("+rParent+") remove parentnode null("+parent+")"); + return; + } + // removing listeners + propertyQueries.remove(r).dispose(); + transformationQueries.remove(r).dispose(); + scenegraphQueries.remove(r).dispose(); + // remove node's children + ArrayList children = new ArrayList(node.getChildren()); + for (IGraphicsNode n : children) { + removeNode(r,n.getResource()); + } + if (DEBUG) System.out.println("ThreeDimensionalEditorBase.removeNodeP(" + r + ") from ("+parent+")"); + // remove the node + + abstractGraphicsNodes.remove(r); + if (geometryUpdates.contains(node)) { + geometryUpdates.remove(node); + } + node.dispose(); + } + + + /** + * Query that tracks changes in resources. + * + * @author Marko Luukkainen + * + */ + public abstract class NodeQuery extends AbstractQuery{ + protected Resource nodeResource; + private boolean disposed = false; + private IQueryListener listener; + //private OverridingTransactionRunner runner; + + + public NodeQuery(Resource r) { + this.nodeResource = r; + //runner = new OverridingTransactionRunner(session,true); + + } + + protected abstract Object compute2(Graph graph); + + @Override + public Object performQuery(Graph graph) { + if (disposed) return null; + return compute2(graph); + } + + /** + * + * @param oldResult result of the query before the change. + * @param newResult result of the query after the change. + */ + public abstract boolean updated(Graph graph, Object oldResult, Object newResult); + + @Override + public int getType() { + return IQuery.SCHEDULED_UPDATE; + } + + @Override + public void resultChangedRaw(final Object oldResult, final Object newResult) { + if (disposed) + throw new RuntimeException("Updating disposed query"); //return; + transactionRunner.run(new GraphRequestAdapter() { + //session.asyncWrite(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + if (!disposed) { + if (oldResult == IQueryListener.NO_VALUE) + updated(g, null, newResult); + else + updated(g, oldResult, newResult); + } + return GraphRequestStatus.transactionComplete(); + } + }); + + } + + + @Override + public boolean equalsQuery(IGraphQuery other) { + return nodeResource.equals(((NodeQuery)other).nodeResource); + } + + @Override + final public int hash() { + return nodeResource.hashCode(); + } + + + /** + * Disposes the query + */ + public void dispose() { + disposed = true; + if (DEBUG) System.out.println("NodeQuery " + nodeResource + " disposed()" + " " + this.getClass()); + } + + //public abstract NodeQuery instantiateQuery(Resource node); + //public abstract void attach(); + + @Override + public boolean isDisposed() { + return disposed; + } + + @Override + public IQueryListener getListener() { + if (listener == null) { + listener = new IQueryListener() { + @Override + public boolean isDisposed() { + return NodeQuery.this.disposed; + } + + @Override + public void resultChangedRaw(Object oldResult, Object newResult) { + NodeQuery.this.resultChangedRaw(oldResult, newResult); + } + }; + } + return listener; + } + + } + + /** + * + * Query that tracks changes in scene-graph structure (parent/child relationships). + * + * @author Marko Luukkainen + * + */ + public abstract class ScenegraphQuery extends NodeQuery { + + List added = new ArrayList(); + List removed = new ArrayList(); + + private boolean initialized; + + public ScenegraphQuery(Resource nodeResource) { + super(nodeResource); + initialized = false; + if(DEBUG)System.out.println("ScenegraphQuery created for " + nodeResource); + } + + @Override + public List compute2(Graph g) { + IEntity node = EntityFactory.create(g,nodeResource); + Collection children = node.getRelatedObjects(Resources.g3dResource.HasChild); + List list = new ArrayList(); + for (IEntity n: children) + list.add(n.getResource()); + if (DEBUG) System.out.println("ScenegraphQuery " + nodeResource + " has " + list.size() + " children"); + return list; + } + + @SuppressWarnings("unchecked") + @Override + public boolean updated(Graph graph, Object oldResult, Object newResult) { + List oldChildren; + if (oldResult != null) + oldChildren = (List)oldResult; + else + oldChildren = new ArrayList(); + List newChildren = (List)newResult; + + if (DEBUG) System.out.println("ScenegraphQuery " + nodeResource + " updated: had " + oldChildren.size() + " children, but now has " + newChildren.size() + " children"); + added.clear(); + removed.clear(); + if (initialized) { + for (Resource r : oldChildren) + if (!newChildren.contains(r)) + removed.add(r); + for (Resource r : newChildren) + if (!oldChildren.contains(r)) + added.add(r); + for (Resource r : removed) { + if (DEBUG) + System.out.println("ScenegraphQuery " + nodeResource + + " removed " + r); + removeNode(nodeResource, r); + } + if (added.size() > 0) { + G3DNode parent = new G3DNode(graph, nodeResource); + /* + * try { + * + * G3DTools.propagateTransformChange(parent); } catch + * (Exception e) { ErrorLogger.defaultLogError(e); } + */ + for (Resource r : added) { + IEntity e = EntityFactory.create(graph, r); + G3DTools.propagateLocalTransformChange(parent, e); + IGraphicsNode n = addNode(parent, e); + shapeAdded(graph, n); + } + } + return (added.size() > 0 || removed.size() > 0); + } else { + // when query is run for the first time, we can assume that transformations are correct. + initialized = true; + for (Resource r : newChildren) + added.add(r); + if (added.size() > 0) { + G3DNode parent = new G3DNode(graph, nodeResource); + for (Resource r : added) { + IEntity e = EntityFactory.create(graph, r); + IGraphicsNode n = addNode(parent, e); + shapeAdded(graph, n); + } + return true; + } + return false; + } + + } + + + /** + * This method is run after a node is added to scene-graph. + * + * @param graph Graph of the current transaction. + * @param node the newly added scene-graph node + */ + public abstract void shapeAdded(Graph graph,IGraphicsNode node); + +// @Override +// public void attach() { +// scenegraphQueries.put(nodeResource, this); +// } + + + } + + /** + * Tracks changes in scene-graph nodes' properties + * + * @author Marko Luukkainen + * + */ + public abstract class NodePropertyQuery extends NodeQuery { + + private boolean initialized; + + public NodePropertyQuery(Resource nodeResource) { + super(nodeResource); + initialized = false; + if(DEBUG)System.out.println("NodePropertyQuery created for " + nodeResource); + } + + @Override + public List compute2(Graph g) { + IEntity t = EntityFactory.create(g,nodeResource); + + Collection properties = t.getRelatedProperties(Resources.g3dResource.HasNonTransformation); + List propertyValues = new ArrayList(); + p(properties,propertyValues); + + return propertyValues; + } + + private void p(Collection properties, List propertyValues) { + for (Property p : properties) { + Collection subProperties = p.getRelatedProperties(p.getGraph().getBuiltins().HasProperty); + if (subProperties.size() != 0) { + p(subProperties,propertyValues); + } + if (p.hasValue()){ + propertyValues.add(p.getValue()); + } + } + } + + @Override + public boolean updated(Graph graph, Object oldResult, Object newResult) { + if (initialized) { + if (DEBUG) System.out.println("NodePropertyQuery changed " + nodeResource + " " + abstractGraphicsNodes.size()); + IGraphicsNode mo = abstractGraphicsNodes.get(nodeResource); + if (mo == null) { + if (DEBUG) System.out.println("NodePropertyQuery invalid change " + nodeResource + " " + abstractGraphicsNodes.size()); + ErrorLogger.defaultLogError("Got update from resource " + nodeResource + " but its not part of the scenegraph", null); + dispose(); + return false; + } + shapeUpdated(graph,mo); + return true; + } else { + initialized = true; + return false; + } + } + + + /** + * This method is run when a scene-graph node is changed. + * + * @param shape the changed node + */ + public abstract void shapeUpdated(Graph graph,IGraphicsNode shape); + +// @Override +// public void attach() { +// propertyQueries.put(nodeResource, this); +// } + + } + + public abstract class NodeTransformationQuery extends NodeQuery { + + private boolean initialized; + + public NodeTransformationQuery(Resource nodeResource) { + super(nodeResource); + initialized = false; + if(DEBUG)System.out.println("NodeTransformationQuery created for " + nodeResource); + } + + @Override + public List compute2(Graph g) { + IEntity t = EntityFactory.create(g,nodeResource); + + Collection properties = t.getRelatedProperties(Resources.g3dResource.HasTransformation); + + List propertyValues = new ArrayList(); + p(properties,propertyValues); + return propertyValues; + + } + + private void p(Collection properties, List propertyValues) { + for (Property p : properties) { + Collection subProperties = p.getRelatedProperties(p.getGraph().getBuiltins().HasProperty); + if (subProperties.size() != 0) { + p(subProperties,propertyValues); + } + if (p.hasValue()){ + propertyValues.add(p.getValue()); + } + } + } + + @Override + public boolean updated(Graph graph,Object oldResult, Object newResult) { + if (initialized) { + if (DEBUG) System.out.println("NodeTransformationQuery changed " + nodeResource + " " + abstractGraphicsNodes.size()); + + G3DTools.transformationUpdate(graph, nodeResource); + + IGraphicsNode mo = abstractGraphicsNodes.get(nodeResource); + if (mo == null) { + if (DEBUG) System.out.println("NodeTransformationQuery invalid change " + nodeResource + " " + abstractGraphicsNodes.size()); + ErrorLogger.defaultLogError("Got update from resource " + nodeResource + " but its not part of the scenegraph", null); + dispose(); + return false; + } + shapeUpdated(graph,mo); + return true; + } else { + initialized = true; + return false; + } + } + + + /** + * This method is run when a scene-graph node is changed. + * + * @param shape the changed node + */ + public abstract void shapeUpdated(Graph graph,IGraphicsNode shape); + +// @Override +// public void attach() { +// transformationQueries.put(nodeResource, this); +// } + + } + + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/SelectionAdapter.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/SelectionAdapter.java new file mode 100644 index 00000000..22b6bc6e --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/SelectionAdapter.java @@ -0,0 +1,445 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.base; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.ISelectionProvider; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.simantics.proconf.g3d.common.StructuredResourceSelection; +import org.simantics.proconf.g3d.gizmo.Gizmo; +import org.simantics.proconf.g3d.scenegraph.IGraphicsNode; +import org.simantics.proconf.ui.utils.ResourceAdaptionUtils; + +import com.jme.intersection.PickData; +import com.jme.intersection.PickResults; +import com.jme.intersection.TrianglePickResults; +import com.jme.math.Ray; + +import org.simantics.db.Resource; + +/** + * Manages highlighting and selecting of objects. + * + * @author Marko Luukkainen + * + */ +public abstract class SelectionAdapter implements ISelectionProvider{ + + protected ScenegraphAdapter adapter; + + private Gizmo currentGizmo = null; + + public SelectionAdapter(ScenegraphAdapter adapter) { + this.adapter = adapter; + } + + public enum SelectionType { + SET, MODIFY + }; + + protected SelectionType mouseClickType = SelectionType.SET; + + public SelectionType getSelectionType() { + return mouseClickType; + } + + public void setSelectionType(SelectionType type) { + mouseClickType = type; + } + + public void setCurrentGizmo(Gizmo gizmo) { + currentGizmo = gizmo; + } + + /** + * Lists all selected objects + *

+ * Selection may contain objects that are not in this view: those are NOT + * returned + *

+ * + * @return + */ + public List getSelectedObjects() { + return getSelectedObjects(selection); + } + + /** + * Lists all highlighted objects. + *

+ * Typically there may be only one highlighted object. + *

+ * @return + */ + public List getHighlightedObjects() { + return getSelectedObjects(interactiveSelection); + } + + /** + * Lists all selected objects + *

+ * Selection may contain objects that are not in this view: those are NOT + * returned + *

+ * + * @return + */ + public List getInteractiveSelectedObjects() { + return getSelectedObjects(interactiveSelection); + } + + /** + * Lists all selected objects + *

+ * Selection may contain objects that are not in this view: those are NOT + * returned + *

+ * + * @return + */ + protected List getSelectedObjects(StructuredResourceSelection selection) { + List l = new ArrayList(); + Iterator i = selection.iterator(); + while (i.hasNext()) { + Resource s = i.next(); + IGraphicsNode shape = adapter.getNode(s); + if (shape != null) + l.add(shape); + + } + return l; + } + + /** + * Return selected objects + *

+ * May contain objects that are NOT in this view + *

+ * + * @return + */ + public List getSelectedResources() { + List l = new ArrayList(); + Iterator i = selection.iterator(); + while (i.hasNext()) { + Resource s = (Resource) i.next(); + l.add(s); + + } + return l; + } + + private ArrayList processed = new ArrayList(); + + private class ExtTrianglePickResults extends TrianglePickResults { + public ExtTrianglePickResults() { + this.setCheckDistance(true); + } + + public void processPick() { + processed.clear(); + if (getNumber() > 0) { + for (int j = 0; j < getNumber(); j++) { + PickData pData = getPickData(j); + ArrayList tris = pData.getTargetTris(); + if (tris != null && tris.size() > 0) { + processed.add(pData); + } + } + + } + + } + } + + private PickResults result = new ExtTrianglePickResults(); + + + private void pickPrefix(String prefix) { + + ArrayList r= new ArrayList(); + for (int i = 0; i < processed.size(); i++) { + PickData pData = processed.get(i); + if (pData.getTargetMesh().getParentGeom().getName().startsWith(prefix)) + r.add(pData); + } + processed = r; + } + + /** + * Updates highlighted objects according to mouse position. + * + * @param mouseRay + */ + public void updateHighlights(Ray mouseRay) { + result.clear(); + adapter.getRenderingComponent().getRoot().calculatePick(mouseRay, result); + if (currentGizmo != null) { + pickPrefix(currentGizmo.getPickPrefix()); + } + doHighlightPick(processed); + } + + /** + * Picks highlighted objects + */ + public void pickHighlighted() { + doPick(processed); + } + + /** + * Processes pick. + * @param result + */ + protected void doPick(ArrayList result) { + if (result != null) { + + if (result.size() == 0) { + if (mouseClickType != SelectionType.MODIFY) + updateSelection(new StructuredResourceSelection()); + return; + } + + String nodeName = result.get(0).getTargetMesh().getParentGeom().getName(); + + StructuredResourceSelection s = new StructuredResourceSelection(); + + Resource selectedResource = adapter.getNodeResource(nodeName); + if (adapter.getNode(selectedResource) == null) { + updateSelection(new StructuredResourceSelection()); + return; + //throw new RuntimeException("Picked resource that has no node ?!"); + } + if (mouseClickType == SelectionType.MODIFY) { + ArrayList selected = new ArrayList(getSelectedResources()); + if (selected.contains(selectedResource)) + selected.remove(selectedResource); + else + selected.add(selectedResource); + for (Resource r : selected) + s.add(r); + + } else { + s.add(selectedResource); + } + + updateSelection(s); + } else { + // System.out.println("Picked nothing"); + if (mouseClickType != SelectionType.MODIFY) + updateSelection(new StructuredResourceSelection()); + } + } + + /** + * Processes highlight pick + * @param result + */ + protected void doHighlightPick(ArrayList result) { + if (result != null) { + + if (result.size() == 0) { + updateGizmo(null); + //System.out.println("IPicked nothing"); + updateHighlightSelection(new StructuredResourceSelection()); + return; + } + + String nodeName = result.get(0).getTargetMesh().getParentGeom().getName(); + + updateGizmo(null); + + // System.out.println("hits: " + result); + StructuredResourceSelection s = new StructuredResourceSelection(); + + Resource selectedResource = adapter.getNodeResource(nodeName); + + if (selectedResource == null) { + if (currentGizmo != null && nodeName.startsWith(currentGizmo.getPickPrefix())) { + updateGizmo(nodeName); + } + return; + } + + if (adapter.getNode(selectedResource) != null) + s.add(selectedResource); + + updateHighlightSelection(s); + } else { + updateGizmo(null); + // System.out.println("IPicked nothing"); + updateHighlightSelection(new StructuredResourceSelection()); + } + } + + /** + * Updates gizmo according to picked object + * @param pickName + */ + private void updateGizmo(String pickName) { + if (currentGizmo != null) { + currentGizmo.setSelected(pickName); + if (currentGizmo.isChanged()) { + adapter.setChanged(true); + currentGizmo.setChanged(false); + } + } + } + + + /** + * Contains selection + */ + protected StructuredResourceSelection selection = new StructuredResourceSelection(); + + protected StructuredResourceSelection interactiveSelection = new StructuredResourceSelection(); + + public StructuredResourceSelection getCurrentSelection() { + return selection; + } + + public void setCurrentSelection(StructuredResourceSelection s) { + selection = s; + } + + public StructuredResourceSelection getHighlightSelection() { + return interactiveSelection; + } + + protected void setHighlightSelection(StructuredResourceSelection s) { + interactiveSelection = s; + } + + private ArrayList selectionChangedListeners = new ArrayList(); + + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.viewers.ISelectionProvider#addSelectionChangedListener(org.eclipse.jface.viewers.ISelectionChangedListener) + */ + public void addSelectionChangedListener(ISelectionChangedListener listener) { + selectionChangedListeners.add(listener); + + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.viewers.ISelectionProvider#getSelection() + */ + public ISelection getSelection() { + return selection; + } + + + + public static StructuredResourceSelection transformSelection(ISelection sel) { + if (sel instanceof StructuredResourceSelection) + return (StructuredResourceSelection)sel; + StructuredResourceSelection res = new StructuredResourceSelection(); + Resource resources[] = ResourceAdaptionUtils.toResources(sel); + for (Resource r : resources) + res.add(r); + return res; + } + + + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.viewers.ISelectionProvider#removeSelectionChangedListener(org.eclipse.jface.viewers.ISelectionChangedListener) + */ + public void removeSelectionChangedListener(ISelectionChangedListener listener) { + selectionChangedListeners.remove(listener); + + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.viewers.ISelectionProvider#setSelection(org.eclipse.jface.viewers.ISelection) + */ + public void setSelection(ISelection selection) { + // System.out.println(); + StructuredResourceSelection s = filterSelection(selection); + if (this.selection.equals(s)) + return; + this.selection = s; + adapter.setChanged(true); + setEditorSelection(); + + } + + /** + * Filters selection given with setSelection(ISelection selection) This + * allows impemented editors to modify selection before it's applied into + * this editor + * + * @param s + * @return the filtered selection + */ + protected abstract StructuredResourceSelection filterSelection(ISelection s); + + /** + * Updates visual part of selection event. Use getCurrentSelection() to get + * the selection + */ + public abstract void setEditorSelection(); + + /** + * Updates visual part of selection event. Use getInteractiveSelection() to + * get the selection + */ + protected abstract void setEditorHighlightSelection(); + + /** + * Editor's internal selection update
+ * Sends events to other editors and views about changed selection + * + * @param selection + * @return + */ + public boolean updateSelection(StructuredResourceSelection s) { + if (this.selection.equals(s)) + return false; + + this.selection = s; + adapter.setChanged(true); + fireSelectionChangedEvent(); + setEditorSelection(); + return true; + } + + protected boolean updateHighlightSelection(StructuredResourceSelection s) { + if (interactiveSelection.equals(s)) + return false; + this.interactiveSelection = s; + adapter.setChanged(true); + setEditorHighlightSelection(); + return true; + } + + /** + * Fires selection changed events. + */ + protected void fireSelectionChangedEvent() { + SelectionChangedEvent e = new SelectionChangedEvent(this, this.selection); + for (ISelectionChangedListener l : selectionChangedListeners) + l.selectionChanged(e); + } +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/ThreeDimensionalEditorBase.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/ThreeDimensionalEditorBase.java new file mode 100644 index 00000000..0a04a229 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/ThreeDimensionalEditorBase.java @@ -0,0 +1,741 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.base; + +import java.awt.event.MouseEvent; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Stack; + +import javax.vecmath.Tuple3d; +import javax.vecmath.Vector3d; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IContributionItem; +import org.eclipse.jface.action.IMenuListener; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.IToolBarManager; +import org.eclipse.jface.action.MenuManager; +import org.eclipse.jface.action.Separator; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.swt.events.PaintEvent; +import org.eclipse.swt.events.PaintListener; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.ui.IActionBars; +import org.eclipse.ui.IEditorActionBarContributor; +import org.eclipse.ui.ISharedImages; +import org.eclipse.ui.IWorkbenchActionConstants; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.commands.ICommandService; +import org.eclipse.ui.internal.WorkbenchWindow; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Resource; +import org.simantics.db.Session; +import org.simantics.db.events.GraphChangeEvent; +import org.simantics.db.management.ISessionContext; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.proconf.g3d.Activator; +import org.simantics.proconf.g3d.actions.CameraAction; +import org.simantics.proconf.g3d.actions.ContextAction; +import org.simantics.proconf.g3d.actions.InteractiveAction; +import org.simantics.proconf.g3d.base.SelectionAdapter.SelectionType; +import org.simantics.proconf.g3d.common.JmeComposite; +import org.simantics.proconf.g3d.common.JmeSinglePassRenderingComponent; +import org.simantics.proconf.g3d.common.OrbitalCamera; +import org.simantics.proconf.g3d.dialogs.JMEDialog; +import org.simantics.proconf.g3d.dnd.ShapeDropTarget; +import org.simantics.proconf.g3d.gizmo.Gizmo; +import org.simantics.proconf.g3d.input.InputProvider; +import org.simantics.proconf.g3d.input.SWTInputProvider; +import org.simantics.proconf.g3d.scenegraph.IGeometryNode; +import org.simantics.proconf.g3d.scenegraph.IGraphicsNode; +import org.simantics.proconf.g3d.tools.ScenegraphLockTraverser; +import org.simantics.utils.ErrorLogger; +import org.simantics.utils.ui.jface.MenuTools; + +import com.jme.math.Ray; +import com.jme.math.Vector2f; +import com.jme.math.Vector3f; +import com.jme.renderer.ColorRGBA; + + +public abstract class ThreeDimensionalEditorBase implements Runnable { + + private Resource inputResource; + + private List editorContributions = new ArrayList(); + + private EditorContribution currentEditorContribution; + + protected List actions = new ArrayList(); + + private List contributionSelectionActions = new ArrayList(); + + protected Composite parent; + + protected ISessionContext sessionContext; + + protected Session session; + + protected ScenegraphAdapter adapter; + + protected SelectionAdapter selectionAdapter; + + protected Action refreshAction; + + protected Action configureJMEAction; + + private Action lockScenegraphAction; + + protected Menu contextMenu; + + private JmeComposite renderingComposite = null; + + protected OrbitalCamera camera = new OrbitalCamera(); + + protected boolean viewChanged = true; + + private InteractiveAction currentAction = null; + + private Gizmo currentGizmo = null; + + private InteractiveAction cameraAction = null; + + private JmeRenderingComponent component = null; + + protected InputProvider input = null; + + protected ShapeDropTarget dropTarget; + +// protected IEditorActionBarContributor actionBarContributor; + protected IActionBars actionBars; + protected IToolBarManager toolBarManager; + protected IMenuManager menuManager; + + public ThreeDimensionalEditorBase(ISessionContext session) { + this.sessionContext = session; + this.session = session.getSession(); + component = new JmeSinglePassRenderingComponent(); + } + + public ThreeDimensionalEditorBase(ISessionContext session, JmeRenderingComponent component) { + this.sessionContext = session; + this.session = session.getSession(); + this.component = component; + } + +// public void setActionBarContributor(IEditorActionBarContributor contributor) { +// actionBarContributor = contributor; +// } + + public void setActionBars(IActionBars actionBars) { + this.actionBars = actionBars; + this.menuManager = actionBars.getMenuManager(); + this.toolBarManager = actionBars.getToolBarManager(); + } + + + + + public ISessionContext getSessionContext() { + return sessionContext; + } + + public Session getSession() { + return session; + } + + /** + * Creates basic UI for ThreeDimenionalEditors. + * Note : inputResource has not been set at this point. + * + * @param graph + * @param parent + */ + public void createControl(Graph graph, Composite parent) { + this.parent = parent; + renderingComposite = new JmeComposite(parent,component); + // add listeners to force repaint on size changes + renderingComposite.getCanvas().addPaintListener(new PaintListener() { + public void paintControl(PaintEvent e) { + viewChanged = true; + } + }); + + + input = new SWTInputProvider(); + + renderingComposite.initGL(); + camera.setCamera(component.getCamera()); + camera.updateCamera(); + makeActions(graph); + hookContextMenu(); + + // provide selection events for properies view + this.adapter = createScenegraphAdapter(); + this.selectionAdapter = createSelectionAdapter(); + + this.selectionAdapter.addSelectionChangedListener(new ISelectionChangedListener() { + public void selectionChanged(SelectionChangedEvent event) { + setCurrentAction(getDefaultAction()); + } + }); + hookDragAndDrop(); + hookInput(); + VisualizationScheduler.getInstance().addVisualization(this); + + if (editorContributions.size() > 0) { + // setActiveEditorContribution(editorContributions.get(0)); + // } else if (editorContributions.size() > 1) { + // create actions for selecting contribution + for (EditorContribution ec : editorContributions) { + final EditorContribution e = ec; + Action a = new Action(e.getName(),Action.AS_RADIO_BUTTON) { + @Override + public void run() { + + setActiveEditorContribution(e); + } + }; + contributionSelectionActions.add(a); + + } + } + + } + + public void addEditorContribution(EditorContribution e) { + if (parent != null) + throw new RuntimeException("Editor contributions must be added before editor is created."); + editorContributions.add(e); + } + + private void initializeEditorContributions(Graph graph) { + for (EditorContribution e : editorContributions) { + e.initialize(graph); + } + if (editorContributions.size() > 0) + parent.getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + setActiveEditorContribution(editorContributions.get(0)); + } + }); + } + + + private void hookInput() { + renderingComposite.getCanvas().addKeyListener((SWTInputProvider) input); + renderingComposite.getCanvas().addMouseListener((SWTInputProvider) input); + renderingComposite.getCanvas().addMouseMoveListener((SWTInputProvider) input); + renderingComposite.getCanvas().addMouseTrackListener((SWTInputProvider) input); + renderingComposite.getCanvas().addFocusListener((SWTInputProvider) input); + } + + protected abstract ScenegraphAdapter createScenegraphAdapter(); + protected abstract SelectionAdapter createSelectionAdapter(); + + + public JmeComposite getRenderingComposite() { + return renderingComposite; + } + + public JmeRenderingComponent getRenderingComponent() { + return component; + } + + public ScenegraphAdapter getScenegraphAdapter() { + return adapter; + } + + public SelectionAdapter getSelectionAdapter() { + return selectionAdapter; + } + + public OrbitalCamera getCamera() { + return camera; + } + + public void setViewChanged(boolean b) { + viewChanged = b; + } + + protected void hookContextMenu() { + MenuManager menuMgr = new MenuManager("#PopupMenu"); + menuMgr.setRemoveAllWhenShown(true); + menuMgr.addMenuListener(new IMenuListener() { + public void menuAboutToShow(IMenuManager manager) { + final IMenuManager m = manager; + GraphRequestAdapter r = new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + ThreeDimensionalEditorBase.this.fillContextMenu(g,m); + return GraphRequestStatus.transactionComplete(); + } + }; + + session.syncRead(r); + + } + }); + + contextMenu = menuMgr.createContextMenu(renderingComposite); + } + + + + protected void fillContextMenu(Graph graph,IMenuManager manager) { + manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); + + List selected = selectionAdapter.getSelectedResources(); + for (ContextAction action : actions) { + if(action.usable(graph,selected)) { + manager.add(action); + } + } + if (currentEditorContribution != null) { + currentEditorContribution.fillContextMenu(graph, manager, selectionAdapter.getCurrentSelection()); + for (ContextAction action : currentEditorContribution.getActions()) { + if(action.usable(graph,selected)) { + manager.add(action); + } + } + } + + } + + protected void fillLocalToolBar() { + + if (currentEditorContribution != null) + currentEditorContribution.fillLocalToolBar(toolBarManager); + } + + protected void fillLocalPullDown() { + for (Action a : contributionSelectionActions) { + IMenuManager menu = MenuTools.getOrCreate(getMenuID(),"View", menuManager); + menu.add(a); + } + MenuTools.getOrCreate(getMenuID(),"Advanced", menuManager).add(refreshAction); + if (configureJMEAction != null) { + MenuTools.getOrCreate(getMenuID(),"Advanced", menuManager).add(configureJMEAction); + } + + MenuTools.getOrCreate(getMenuID(),"Advanced", menuManager).add(lockScenegraphAction); + if (currentEditorContribution != null) + currentEditorContribution.fillLocalPullDown(menuManager); + } + + public String getMenuID() { + return Long.toString(getInputResource().getResourceId()); + } + + protected void makeActions(Graph graph) { + + refreshAction = new Action() { + + public void run() { + GraphRequestAdapter r = new GraphRequestAdapter() { + public GraphRequestStatus perform(Graph g) throws Exception { +// Stack stack = new Stack(); +// stack.push(adapter.getNode(adapter.getRootResource())); +// while(!stack.isEmpty()) { +// IGraphicsNode node = stack.pop(); +// stack.addAll(node.getChildren()); +// if (node instanceof IGeometryNode) { +// ((IGeometryNode)node).updateGeometry(g); +// } +// } + for (IGraphicsNode node : adapter.getNodes()) + if (node instanceof IGeometryNode) + ((IGeometryNode)node).updateGeometry(g); + viewChanged = true; + return GraphRequestStatus.transactionComplete(); + }; + }; + session.asyncRead(r); + + } + }; + refreshAction.setText("Refresh"); + refreshAction.setToolTipText("Refreshes the visualization"); + refreshAction.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages().getImageDescriptor( + ISharedImages.IMG_TOOL_UP)); + if (getRenderingComponent() instanceof JmeSinglePassRenderingComponent) { + configureJMEAction = new Action() { + public void run() { + JmeSinglePassRenderingComponent c = (JmeSinglePassRenderingComponent)getRenderingComponent(); + JMEDialog dialog = new JMEDialog(ThreeDimensionalEditorBase.this.parent.getShell()); + c.getDisplaySystem().setCurrent(); + dialog.setBounds(c.isShowBounds()); + dialog.setNormals(c.isShowNormals()); + dialog.setWireframe(c.isShowWireframe()); + ColorRGBA col = c.getDisplaySystem().getRenderer().getBackgroundColor(); + dialog.setFloatColor(new float[]{col.r,col.g,col.b}); + if (dialog.open() == JMEDialog.CANCEL) + return; + c.setShowBounds(dialog.isBounds()); + c.setShowNormals(dialog.isNormals()); + c.setShowWireframe(dialog.isWireframe()); + if (dialog.getFloatColor() != null) { + c.getDisplaySystem().setCurrent(); + c.getDisplaySystem().getRenderer().setBackgroundColor(new ColorRGBA(dialog.getFloatColor()[0],dialog.getFloatColor()[1],dialog.getFloatColor()[2],0.f)); + } + } + }; + configureJMEAction.setText("Configure JME"); + configureJMEAction.setImageDescriptor(Activator.imageDescriptorFromPlugin("fi.vtt.proconf.ode", "icons/silk/wrench.png")); + } + + lockScenegraphAction = new Action("Lock scenegraph",Action.AS_CHECK_BOX) { + public void run() { + new ScenegraphLockTraverser(adapter.getRoot(),this.isChecked()); + } + }; + + cameraAction = new CameraAction(this); + currentAction = cameraAction; + + + } + + public InteractiveAction getDefaultAction() { + return cameraAction; + } + + public void createPickRay(Vector3d o, Vector3d d) { + Ray r = createPickRay(); + o.x = r.origin.x; + o.y = r.origin.y; + o.z = r.origin.z; + d.x = r.direction.x; + d.y = r.direction.y; + d.z = r.direction.z; + d.normalize(); + } + + public Ray createPickRay() { + Vector2f screenPos = new Vector2f(); + screenPos.set(input.mouseX(),renderingComposite.getBounds().height - input.mouseY()); + + + Ray mouseRay; + if (component.getCamera().isParallelProjection()) { + Vector3f worldCoords = renderingComposite.getDisplaySystem().getWorldCoordinates(screenPos, 0.0f); + mouseRay = new Ray(worldCoords, + component.getCamera().getDirection()); + } else { + Vector3f worldCoords = renderingComposite.getDisplaySystem().getWorldCoordinates(screenPos, 1.0f); + mouseRay = new Ray(component.getCamera().getLocation(), worldCoords + .subtractLocal(component.getCamera().getLocation())); + } + return mouseRay; + } + + public Vector2f getScreenCoord(Tuple3d worldCoord) { + Vector3f v = renderingComposite.getDisplaySystem().getScreenCoordinates(VecmathJmeTools.get(worldCoord)); + return new Vector2f(v.x,v.y); + } + + + public InputProvider getInputProvider() { + return input; + } + + /** + * Changes current action + * + * @param type + */ + public void setCurrentAction(InteractiveAction action) { + if (currentAction == action) + return; + if (toolBarManager != null) { + toolBarManager.removeAll(); + fillLocalToolBar(); + } + if (currentAction != null) + currentAction.deactivate(); + currentAction = action; + if (currentAction != null) { + currentAction.activate(); + if (toolBarManager != null) { + currentAction.fillToolBar(toolBarManager); + } + } + + updateBars(); + } + + public InteractiveAction getCurrentAction() { + return currentAction; + } + + public void setActiveEditorContribution(EditorContribution contribution) { + if (currentEditorContribution == contribution) + return; + if (currentAction != getDefaultAction()) + return; + if (currentEditorContribution != null) + currentEditorContribution.disposeControl(); + currentEditorContribution = contribution; + int index = editorContributions.indexOf(contribution); + for (int i = 0; i < contributionSelectionActions.size(); i++) { + if (i != index) + contributionSelectionActions.get(i).setChecked(false); + else + contributionSelectionActions.get(i).setChecked(true); + } + if (currentEditorContribution != null) + currentEditorContribution.createControl(parent); + + actionBars.clearGlobalActionHandlers(); + + parent.layout(true, true); + if (toolBarManager != null) { + toolBarManager.removeAll(); + fillLocalToolBar(); + } + if (menuManager != null) { + menuManager.removeAll(); + fillLocalPullDown(); + } + + updateBars(); + } + + protected void updateBars() { + // TODO : actionBars.updateActionBars does not update toolbar, updating toolBar directly layouts code + // generated widgets top of contributed (extension) widgets. Only way to achieve proper update + // is to use WorkbenchWindow.getCoolBarManager.update(true) + actionBars.updateActionBars(); +// if (toolBarManager != null) { +// toolBarManager.update(true); +// } + WorkbenchWindow w = (WorkbenchWindow)PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + w.getCoolBarManager().update(true); + } + + public void setGizmo(Gizmo gizmo) { + if (currentGizmo != null) { + currentGizmo.getNode().removeFromParent(); + } + currentGizmo = gizmo; + selectionAdapter.setCurrentGizmo(gizmo); + viewChanged = true; + } + +// public void setInfoText(String text) { +// if (useInfoComposite) { +// infoText.setText(text); +// } +// } + + public void showMessage(String message) { + MessageDialog.openInformation(parent.getShell(), "Shape Editor", //$NON-NLS-1$ + message); + } + + + /** + * Passing the focus request to the viewer's control. + */ + public void setFocus() { + renderingComposite.getCanvas().setFocus(); + } + + public void dispose() { + //System.out.println("ThreeDimensionalEditorBase.dispose()"); + VisualizationScheduler.getInstance().removeVisualization(this); + + if (currentAction != null) + currentAction.deactivate(); + + for (EditorContribution e : editorContributions) + e.dispose(); + + renderingComposite.dispose(); + + // copy of the set is needed to avoid ConcurrentModificationException + adapter.dispose(); + component.dispose(); + } + + public final void reload(Graph g, Resource res) { + inputResource = res; + reloadFrom(EntityFactory.create(g, res)); + // at this point we can initialize editor contributions, which may require inputResource + initializeEditorContributions(g); + } + + public Resource getInputResource() { + return inputResource; + } + + public void update(GraphChangeEvent event) { +// System.out.println("Transaction " + this + " : " + event.getTransactionId() + " Arg1: " + event.getArg1() +// + " arg2: " + event.getArg2() + " sender: " + event.getSender() + " source: " + event.getSource()); + +// if (event.added.size() > 0) { +// System.out.println("Added:"); +// for (Triplet t : event.added) +// System.out.println(t); +// } +// if (event.changed.size() > 0) { +// System.out.println("Changed:"); +// for (Triplet t : event.changed) +// System.out.println(t); +// } +// if (event.removed.size() > 0) { +// System.out.println("Removed:"); +// for (Triplet t : event.removed) +// System.out.println(t); +// } + + } + + + + /** + * Loads the initial scene: all further updates to the view are done by + * listening changes in the shapes and int the shape group + * + * @param resource + */ + protected abstract void reloadFrom(IEntity thing); + + + protected void viewUpdated() { + + } + + /* + * (non-Javadoc) + * + * @see java.lang.Runnable#run() + */ + public void run() { + if (currentEditorContribution != null) + currentEditorContribution.run(); + if (parent.isDisposed() || !parent.isVisible()) + return; + //renderingComposite.getDisplaySystem().setCurrent(); + input.update(); + if (input.mouseClicked()) { + int downMask = MouseEvent.CTRL_DOWN_MASK; + + if ((input.clickModifiers() & downMask) > 0) { + selectionAdapter.setSelectionType(SelectionType.MODIFY); + } else { + selectionAdapter.setSelectionType(SelectionType.SET); + } + } + if (input.mouseMoved()) { + Ray mouseRay = createPickRay(); + selectionAdapter.updateHighlights(mouseRay); + } + if (currentAction == cameraAction && input.mouseClicked()) { + selectionAdapter.pickHighlighted(); + } + if (currentAction == cameraAction && input.mousePressed() + && (input.pressModifiers() & MouseEvent.BUTTON3_MASK) > 0) { + Point p = renderingComposite.toDisplay(input.mouseX(), input + .mouseY()); + contextMenu.setLocation(p.x, p.y); + contextMenu.setVisible(true); + } + + if (currentAction != null) + try { + currentAction.update(); + } catch (Exception e) { + ErrorLogger.defaultLogError("Action error!", e); + setCurrentAction(getDefaultAction()); + } + + if (component.update()) + viewChanged = true; + + if (!geometryUpdateRequestAdapter.isRunning() && adapter.needsUpdateGeometry()) { + session.asyncRead(geometryUpdateRequestAdapter); + } + + viewChanged |= adapter.isChanged(); + if (viewChanged) { + viewChanged = false; + adapter.setChanged(false); + camera.updateCamera(); + viewUpdated(); + component.render(); + } + } + // TODO : there is some sort of synchronization bug in rendering: + // part of the rendered objects are rendered with different camera transformation than others. + // re-rendering the scene hides the worst problems. + // Using shadows is the reason: shadowed objects are rendered with different transformation than non-shadowed. + //private boolean lastChanged = false; + + private GeometryUpdateRequestAdapter geometryUpdateRequestAdapter = new GeometryUpdateRequestAdapter(); + + private class GeometryUpdateRequestAdapter extends GraphRequestAdapter { + private boolean running; + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + running = true; + adapter.updateGeometry(g); + return GraphRequestStatus.transactionComplete(); + } + @Override + public void requestCompleted(GraphRequestStatus status) { + running = false; + adapter.setChanged(true); + } + + public boolean isRunning() { + return running; + } + } + + + + protected void hookDragAndDrop() { + dropTarget = new ShapeDropTarget(this); + } + + /** + * Receives selection changes + * + * @param part + * @param selection + */ + protected abstract void pageSelectionChanged(IWorkbenchPart part, ISelection selection); + + /** + * EditorPart or ViewPart uses this method to forward getAdapter(Class) + * @see org.eclipse.ui.part.WorkbenchPart.getAdapter(Class adapter) + * @param adapter + * @return + */ + public Object getAdapter(Class adapter) { + return null; + } + +} \ No newline at end of file diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/ThreeDimensionalEditorPart.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/ThreeDimensionalEditorPart.java new file mode 100644 index 00000000..4ad22bd2 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/ThreeDimensionalEditorPart.java @@ -0,0 +1,205 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.base; + +import org.eclipse.jface.action.IStatusLineManager; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.IActionBars; +import org.eclipse.ui.IPartListener; +import org.eclipse.ui.ISelectionListener; +import org.eclipse.ui.IWorkbenchPart; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Session; +import org.simantics.db.Resource; +import org.simantics.db.events.GraphChangeEvent; +import org.simantics.db.management.ISessionContext; +import org.simantics.proconf.ui.workbench.ResourceEditorPart; +import org.simantics.utils.ErrorLogger; + + +public abstract class ThreeDimensionalEditorPart extends ResourceEditorPart implements ThreeDimensionalEditorProvider{ + + protected Composite parent; + + protected ThreeDimensionalEditorBase editor; + + protected ISelectionListener pageSelectionListener; + + protected abstract ThreeDimensionalEditorBase createEditor(ISessionContext session); + + /** + * This is a callback that will allow us to create the viewer and it. + */ + @Override + public void createPartControl(Composite p) { + this.parent = p; + try { + editor = createEditor(getSessionContext()); + + // add partlistener that loads the scene-graph when the view has been created + this.getEditorSite().getPage().addPartListener(new IPartListener() { + + boolean opened = false; + boolean activated = false; + + public void partOpened(IWorkbenchPart part) { + if (part.equals(ThreeDimensionalEditorPart.this.getEditorSite().getPart())) { + opened = true; + } + } + + public void partActivated(IWorkbenchPart part) { + if (part.equals(ThreeDimensionalEditorPart.this.getEditorSite().getPart())) { + if (opened & !activated) { + activated = true; + load(); + } + } + } + + public void partBroughtToTop(IWorkbenchPart part) {} + + public void partClosed(IWorkbenchPart part) {} + + public void partDeactivated(IWorkbenchPart part) {} + + private void load() { + //System.out.println("ThreeDimensionalEditorPart.reload()"); + Session ses = ThreeDimensionalEditorPart.this.getSession(); + GraphRequestAdapter r = new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) + throws Exception { + reload(g); + return GraphRequestStatus.transactionComplete(); + } + }; + ses.asyncRead(r); + } + }); + + IActionBars actionBar = getEditorSite().getActionBars(); +// editor.setActionBarContributor(getEditorSite().getActionBarContributor()); + editor.setActionBars(actionBar); + getSession().syncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + editor.createControl(g,parent); + return GraphRequestStatus.transactionComplete(); + } + }); + + contributeStatusBar(actionBar.getStatusLineManager()); + hookPageSelection(); + getSite().setSelectionProvider(editor.selectionAdapter); + + + + } catch (Exception e) { + Display d = getSite().getShell().getDisplay(); + d.asyncExec(new Runnable() { + public void run() { + getSite().getPage().closeEditor(ThreeDimensionalEditorPart.this,false); + } + }); + + ErrorLogger logger = ErrorLogger.getDefault(); + logger.logError("Shape editor failed to open, see exception for details", e); + } + + } + + + protected void contributeStatusBar(IStatusLineManager manager) { + } + + + @Override + public void reload(Graph g) { + Resource inputResource = getInputResource(); + if (inputResource != null) { + editor.reload(g,inputResource); + } else { + + Display d = getSite().getShell().getDisplay(); + d.asyncExec(new Runnable() { + public void run() { + editor.showMessage("Failed to load model."); + getSite().getPage().closeEditor(ThreeDimensionalEditorPart.this,false); + } + }); + } + } + + @Override + public void update(GraphChangeEvent e) { + editor.update(e); + } + + @Override + public void setFocus() { + editor.setFocus(); + } + + /** + * Hooks selection listening + */ + private void hookPageSelection() { + pageSelectionListener = new ISelectionListener() { + public void selectionChanged(IWorkbenchPart part, ISelection selection) { + if (part == ThreeDimensionalEditorPart.this) + return; + pageSelectionChanged(part, selection); + } + }; + getSite().getPage().addPostSelectionListener(pageSelectionListener); + ISelection sel = getSite().getPage().getSelection(); + IWorkbenchPart wb = getSite().getPage().getActivePart(); + pageSelectionChanged(wb, sel); + } + + /** + * Receives selection changes + * + * @param part + * @param selection + */ + protected void pageSelectionChanged(IWorkbenchPart part, ISelection selection) { + editor.pageSelectionChanged(part, selection); + } + + public void dispose() { + if (pageSelectionListener != null) + getSite().getPage().removePostSelectionListener(pageSelectionListener); + editor.dispose(); + super.dispose(); + } + + public ThreeDimensionalEditorBase getEditor() { + return editor; + } + + @Override + public Object getAdapter(Class adapter) { + Object o = super.getAdapter(adapter); + if (o == null) { + o = editor.getAdapter(adapter); + } + return o; + } + + + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/ThreeDimensionalEditorProvider.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/ThreeDimensionalEditorProvider.java new file mode 100644 index 00000000..df2d14dd --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/ThreeDimensionalEditorProvider.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.base; + +/** + * Interface which selectionProviders containing ThreeDimensionalEditorPart + * must implement. + * + * This enables usage of ThreeDimensionalEditorPart in views, editors, dialogs, and so on. + * + * @author Marko Luukkainen + * + */ +public interface ThreeDimensionalEditorProvider { + + public ThreeDimensionalEditorBase getEditor(); +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/TransformationTools.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/TransformationTools.java new file mode 100644 index 00000000..9ca2754c --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/TransformationTools.java @@ -0,0 +1,520 @@ +package org.simantics.proconf.g3d.base; + +import java.util.Collection; +import java.util.HashMap; + +import javax.vecmath.AxisAngle4d; +import javax.vecmath.Point3d; +import javax.vecmath.Quat4d; +import javax.vecmath.Tuple3d; +import javax.vecmath.Vector3d; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.proconf.g3d.Resources; +import org.simantics.proconf.g3d.stubs.Orientation; +import org.simantics.proconf.g3d.stubs.Position; + +public class TransformationTools { + + private static boolean DEBUG = false; + + private Resource childRelation; + private Resource parentRelation; + + public TransformationTools(Resource childRelation, Resource parentRelation) { + this.childRelation = childRelation; + this.parentRelation = parentRelation; + } + + public IEntity getParent(IEntity node) { + return node.getAtMostOneRelatedObject(parentRelation); + } + + public Point3d getLocalFromWorld(IEntity node, Point3d worldCoord) { + IEntity parent = getParent(node); + if (parent == null) {// this is a rootnode ( has no transformation) + return worldCoord; + } + + Point3d local = getLocalFromWorld2(parent,worldCoord); + return local; + } + + + private Point3d getLocalFromWorld2(IEntity node, Point3d worldCoord) { + IEntity parent = getParent(node); + if (parent == null) {// this is a root node ( has no transformation) + return worldCoord; + } + + Point3d local = getLocalFromWorld2(parent,worldCoord); + if (node.hasStatement(Resources.g3dResource.HasLocalPosition)) + local.sub(G3DTools.getPoint(node.getSingleRelatedObject(Resources.g3dResource.HasLocalPosition))); + if (node.hasStatement(Resources.g3dResource.HasLocalOrientation)) { + Quat4d q = new Quat4d(); + q.set(G3DTools.getOrientation(node.getSingleRelatedObject(Resources.g3dResource.HasLocalOrientation))); + q.inverse(); + MathTools.rotate(q, local, local); + } + return local; + } + + public Point3d getWorldFromLocal(IEntity node,Point3d localCoord) { + IEntity parent = getParent(node); + if (parent == null) // this is a rootnode ( has no transformation) + return localCoord; + return getWorldFromLocal2(parent, localCoord); + } + + private Point3d getWorldFromLocal2(IEntity node,Point3d localCoord) { + + if (node.hasStatement(Resources.g3dResource.HasLocalOrientation)) { + Quat4d q = new Quat4d(); + q.set(G3DTools.getOrientation(node.getSingleRelatedObject(Resources.g3dResource.HasLocalOrientation))); + MathTools.rotate(q, localCoord, localCoord); + } + if (node.hasStatement(Resources.g3dResource.HasLocalPosition)) + localCoord.add(G3DTools.getPoint(node.getSingleRelatedObject(Resources.g3dResource.HasLocalPosition))); + + IEntity parent = getParent(node); + if (parent == null) // this is a rootnode ( has no transformation) + return localCoord; + + return getWorldFromLocal2(parent,localCoord); + } + + + public AxisAngle4d getLocalFromWorld(IEntity node, AxisAngle4d worldRot) { + IEntity parent = getParent(node); + if (parent == null) // this is a rootnode ( has no transformation) + return worldRot; + + AxisAngle4d local = getLocalFromWorld2(parent,worldRot); + + return local; + } + + private AxisAngle4d getLocalFromWorld2(IEntity node, AxisAngle4d worldRot) { + IEntity parent = getParent(node); + if (parent == null) // this is a rootnode ( has no transformation) + return worldRot; + AxisAngle4d local = getLocalFromWorld2(parent,worldRot); + + if (node.hasStatement(Resources.g3dResource.HasLocalOrientation)) { + Quat4d q = new Quat4d(); + q.set(G3DTools.getOrientation(node.getSingleRelatedObject(Resources.g3dResource.HasLocalOrientation))); + q.inverse(); + Quat4d q2 = new Quat4d(); + q2.set(local); + q.mul(q2); + local.set(q); + } + + return local; + } + + public AxisAngle4d getWorldFromLocal(IEntity node,AxisAngle4d localRot) { + IEntity parent = getParent(node); + if (parent == null) + return localRot; + + return getWorldFromLocal2(parent,localRot); + } + + private AxisAngle4d getWorldFromLocal2(IEntity node,AxisAngle4d localRot) { + + //System.out.print("wtl " + node.getResource() + " " + localCoord); + if (node.hasStatement(Resources.g3dResource.HasLocalOrientation)) { + Quat4d q = new Quat4d(); + q.set(G3DTools.getOrientation(node.getSingleRelatedObject(Resources.g3dResource.HasLocalOrientation))); + Quat4d q2 = new Quat4d(); + q2.set(localRot); + q.mul(q2); + localRot.set(q); + } + + IEntity parent = getParent(node); + if (parent == null) // this is a rootnode ( has no transformation) + return localRot; + + //System.out.println(" " + localCoord); + return getWorldFromLocal2(parent,localRot); + } + + public Point3d getLocalFromWorldR(IEntity node, Point3d worldCoord) { + + Point3d local = getLocalFromWorldR(null,worldCoord); + if (node.hasStatement(Resources.g3dResource.HasLocalOrientation)) { + Quat4d q = new Quat4d(); + q.set(G3DTools.getOrientation(node.getSingleRelatedObject(Resources.g3dResource.HasLocalOrientation))); + q.inverse(); + MathTools.rotate(q, local, local); + } + + IEntity parent = getParent(node); + if (parent == null) // this is a rootnode ( has no transformation) + return worldCoord; + + return local; + } + + public Point3d getWorldFromLocalR(IEntity node,Point3d localCoord) { + + if (node.hasStatement(Resources.g3dResource.HasLocalOrientation)) { + Quat4d q = new Quat4d(); + q.set(G3DTools.getOrientation(node.getSingleRelatedObject(Resources.g3dResource.HasLocalOrientation))); + MathTools.rotate(q, localCoord, localCoord); + } + + IEntity parent = getParent(node); + if (parent == null) // this is a rootnode ( has no transformation) + return localCoord; + + return getWorldFromLocalR(parent,localCoord); + } + + /** + * Updates transformations of all children of given node + * @param node + */ + public void propagateTransformChange(IEntity node) { + Collection children = node.getRelatedObjects(childRelation); + IEntity wp = node.getAtMostOneRelatedObject(Resources.g3dResource.HasWorldPosition); + IEntity wr = node.getAtMostOneRelatedObject(Resources.g3dResource.HasWorldOrientation); + Quat4d rot = new Quat4d(); + if (wr != null) + rot.set(G3DTools.getOrientation(wr)); + else + rot.w = 1.0; + Point3d pos = new Point3d(); + if (wp != null) + pos = G3DTools.getPoint(wp); + if (DEBUG) { + if (wr != null) + System.out.println("propagate transform " + node.getResource() + " " + pos + " " + G3DTools.getOrientation(wr)); + else + System.out.println("propagate transform " + node.getResource() + " " + pos); + } + for (IEntity n : children) { + IEntity lPos = n.getAtMostOneRelatedObject(Resources.g3dResource.HasLocalPosition); + IEntity lRot = n.getAtMostOneRelatedObject(Resources.g3dResource.HasLocalOrientation); + if (DEBUG) System.out.print(n); + if (lRot != null) { + AxisAngle4d la = G3DTools.getOrientation(lRot); + AxisAngle4d wa = getWorldFromLocal(n, la); + IEntity wo = n.getSingleRelatedObject(Resources.g3dResource.HasWorldOrientation); + G3DTools.setOrientation(wo,wa); + storeProperty(wo.getResource(), wa); + } + if (lPos != null) { + Point3d lp = G3DTools.getPoint(lPos); + if (DEBUG) System.out.println(lp); + MathTools.rotate(rot, lp, lp); + lp.add(pos); + IEntity nwp = n.getSingleRelatedObject(Resources.g3dResource.HasWorldPosition); + G3DTools.setTuple3(nwp, lp); + if (DEBUG) System.out.print(" " + lp); + storeProperty(nwp.getResource(), lp); + } + if (DEBUG) System.out.println(); + propagateTransformChange(n); + + } + } + + /** + * Updates transformation of one child node without changing its local transformation. + * @param parent + * @param node + */ + public void propagateLocalTransformChange(IEntity parent, IEntity node) { + //Collection children = parent.getRelatedObjects(childRelation); + IEntity parentWP = parent.getAtMostOneRelatedObject(Resources.g3dResource.HasWorldPosition); + IEntity parentWR = parent.getAtMostOneRelatedObject(Resources.g3dResource.HasWorldOrientation); + Quat4d parentWRot = new Quat4d(); + if (parentWR != null) { + parentWRot.set(G3DTools.getOrientation(parentWR)); + + } else + parentWRot.w = 1.0; + Point3d parentWPos = new Point3d(); + if (parentWP != null) { + parentWPos = G3DTools.getPoint(parentWP); + } + if (DEBUG) { + if (parentWR != null) + System.out.println("propagate transform " + parent.getResource() + " " + parentWPos + " " + G3DTools.getOrientation(parentWR)); + else + System.out.println("propagate transform " + parent.getResource() + " " + parentWPos); + } + //for (IEntity n : children) { + // if (!n.equals(node)) + // continue; + IEntity lPos = node.getAtMostOneRelatedObject(Resources.g3dResource.HasLocalPosition); + IEntity lRot = node.getAtMostOneRelatedObject(Resources.g3dResource.HasLocalOrientation); + if (DEBUG) System.out.print(node); + if (lRot != null) { + AxisAngle4d aa = G3DTools.getOrientation(lRot); + storeProperty(lRot.getResource(), aa); + AxisAngle4d la = getWorldFromLocal(node, aa); + IEntity wo = node.getSingleRelatedObject(Resources.g3dResource.HasWorldOrientation); + G3DTools.setOrientation(wo,la); + storeProperty(wo.getResource(), la); + } + if (lPos != null) { + Point3d lp = G3DTools.getPoint(lPos); + storeProperty(lPos.getResource(), lp); + MathTools.rotate(parentWRot, lp, lp); + lp.add(parentWPos); + IEntity nwp = node.getSingleRelatedObject(Resources.g3dResource.HasWorldPosition); + G3DTools.setTuple3(nwp, lp); + storeProperty(nwp.getResource(), lp); + } + if (DEBUG) System.out.println(); + propagateTransformChange(node); + + } +// } + + public static void resetTransformation(IEntity shape) { + Graph graph = shape.getGraph(); + if (shape.getAtMostOneRelatedObject(Resources.g3dResource.HasLocalPosition) == null) { + + // LocalPosition p = LocalPosition.createDefault(graph); + Position p = Position.createDefault(graph); + shape.addStatement(Resources.g3dResource.HasLocalPosition, p); + // WorldPosition p2 = WorldPosition.createDefault(graph); + Position p2 = Position.createDefault(graph); + shape.addStatement(Resources.g3dResource.HasWorldPosition, p2); + p.setX(new double[] { 0.0 }); + p.setY(new double[] { 0.0 }); + p.setZ(new double[] { 0.0 }); + + p2.setX(new double[] { 0.0 }); + p2.setY(new double[] { 0.0 }); + p2.setZ(new double[] { 0.0 }); + + } else { + G3DTools.setTuple3(shape.getSingleRelatedObject(Resources.g3dResource.HasLocalPosition), 0.0, 0.0, 0.0); + G3DTools.setTuple3(shape.getSingleRelatedObject(Resources.g3dResource.HasWorldPosition), 0.0, 0.0, 0.0); + } + if (shape.getAtMostOneRelatedObject(Resources.g3dResource.HasLocalOrientation) == null) { + + // LocalOrientation r = LocalOrientationFactory.create(graph); + Orientation r = Orientation.createDefault(graph); + shape.addStatement(Resources.g3dResource.HasLocalOrientation, r); + // WorldOrientation r2 = WorldOrientationFactory.create(graph); + Orientation r2 = Orientation.createDefault(graph); + shape.addStatement(Resources.g3dResource.HasWorldOrientation, r2); + r.setAngle(new double[] { 0.0 }); + r.setX(new double[] { 1.0 }); + r.setY(new double[] { 0.0 }); + r.setZ(new double[] { 0.0 }); + r2.setAngle(new double[] { 0.0 }); + r2.setX(new double[] { 1.0 }); + r2.setY(new double[] { 0.0 }); + r2.setZ(new double[] { 0.0 }); + + } else { + G3DTools.setOrientation(shape.getSingleRelatedObject(Resources.g3dResource.HasLocalOrientation), + new AxisAngle4d(0.0, 1.0, 0.0, 0.0)); + G3DTools.setOrientation(shape.getSingleRelatedObject(Resources.g3dResource.HasWorldOrientation), + new AxisAngle4d(0.0, 1.0, 0.0, 0.0)); + } + } + + /** + * Updates transformation of one child node without changing its world transformation. + * @param parent + * @param node + */ + public void propagateWorldTransformChange(IEntity parent, IEntity node) { + //Collection children = parent.getRelatedObjects(childRelation); + IEntity parentWP = parent.getAtMostOneRelatedObject(Resources.g3dResource.HasWorldPosition); + IEntity parentWR = parent.getAtMostOneRelatedObject(Resources.g3dResource.HasWorldOrientation); + Quat4d parentWQuat = new Quat4d(); + if (parentWR != null) { + parentWQuat.set(G3DTools.getOrientation(parentWR)); + } + else + parentWQuat.w = 1.0; + Point3d parentWPos = new Point3d(); + if (parentWP != null) { + parentWPos = G3DTools.getPoint(parentWP); + } + if (DEBUG){ + if (parentWR != null) + System.out.println("propagate transform " + parent.getResource() + " " + parentWPos + " " + G3DTools.getOrientation(parentWR)); + else + System.out.println("propagate transform " + parent.getResource() + " " + parentWPos); + } + //for (IEntity n : children) { + // if (!n.equals(node)) + // continue; + IEntity wPos = node.getAtMostOneRelatedObject(Resources.g3dResource.HasWorldPosition); + IEntity wRot = node.getAtMostOneRelatedObject(Resources.g3dResource.HasWorldOrientation); + + if (DEBUG) System.out.print(node); + if (wRot != null) { + AxisAngle4d aa = G3DTools.getOrientation(wRot); + storeProperty(wRot.getResource(), aa); + AxisAngle4d la = getLocalFromWorld(node, aa); + IEntity lRot = node.getSingleRelatedObject(Resources.g3dResource.HasLocalOrientation); + G3DTools.setOrientation(lRot,la); + storeProperty(lRot.getResource(), la); + } + if (wPos != null) { + Point3d lp = G3DTools.getPoint(wPos); + storeProperty(wPos.getResource(), lp); + lp.sub(parentWPos); + parentWQuat.inverse(); + MathTools.rotate(parentWQuat, lp, lp); + IEntity lPos = node.getSingleRelatedObject(Resources.g3dResource.HasLocalPosition); + G3DTools.setTuple3(lPos, lp); + storeProperty(lPos.getResource(), lp); + } + if (DEBUG) System.out.println(); + propagateTransformChange(node); + + // } + } + + public boolean transformationUpdate(Graph graph, Resource resource) { + + //resources.startTransaction("transformationUpdate"); + IEntity entity = EntityFactory.create(graph,resource); + return transformationUpdate(entity); + } + + public boolean transformationUpdate(IEntity node) { + if (DEBUG) System.out.println("Node transformation update " + node.getResource()); + IEntity worldPos = node.getSingleRelatedObject(Resources.g3dResource.HasWorldPosition); + IEntity localPos = node.getSingleRelatedObject(Resources.g3dResource.HasLocalPosition); + IEntity worldOr = node.getAtMostOneRelatedObject(Resources.g3dResource.HasWorldOrientation); + IEntity localOr = node.getAtMostOneRelatedObject(Resources.g3dResource.HasLocalOrientation); + + Tuple3d worldP =G3DTools.getPoint(worldPos); + Tuple3d localP = G3DTools.getPoint(localPos); + + AxisAngle4d worldR = null; + AxisAngle4d localR = null; + if (worldOr != null) { + worldR = G3DTools.getOrientation(worldOr); + localR = G3DTools.getOrientation(localOr); + } + + boolean changed = false; + if (localP != null && worldP != null) { + Tuple3d cachedWorldP = (Tuple3d)getProperty(worldPos.getResource()); + Tuple3d cachedLocalP = (Tuple3d)getProperty(localPos.getResource()); + boolean changedLocalP = false; + boolean changedWorldP = false; + if (cachedLocalP == null) + changedLocalP = true; + else if (changed(cachedLocalP,localP)) + changedLocalP = true; + + if (cachedWorldP == null) { + changedWorldP = true; + } else if (changed(cachedWorldP,worldP)){ + changedWorldP = true; + } + if (changedLocalP) { + storeProperty(localPos.getResource(), localP); + Tuple3d p = getWorldFromLocal(node, new Point3d(localP)); + storeProperty(worldPos.getResource(), p); + G3DTools.setTuple3(worldPos, p); + if (DEBUG) System.out.println("Node changed local: wp " + worldP + " lp " + p + " old " + cachedLocalP); + changed = true; + } else if (changedWorldP) { + storeProperty(worldPos.getResource(), worldP); + Tuple3d p = getLocalFromWorld(node, new Point3d(worldP)); + G3DTools.setTuple3(localPos, p); + storeProperty(localPos.getResource(), p); + if (DEBUG) System.out.println("Node changed world: wp " + worldP + " lp " + p + " old " + cachedWorldP); + changed = true; + } + } + + if (localR != null || worldR != null) { + AxisAngle4d cachedWorldR = (AxisAngle4d)getProperty(worldOr.getResource()); + AxisAngle4d cachedLocalR = (AxisAngle4d)getProperty(localOr.getResource()); + boolean changedLocalR = false; + boolean changedWorldR = false; + + if (cachedLocalR == null) + changedLocalR = true; + else if (changed(cachedLocalR,localR)) + changedLocalR = true; + + if (cachedWorldR == null) { + changedWorldR = true; + } else if (changed(cachedWorldR,worldR)){ + changedWorldR = true; + } + + if (changedLocalR) { + storeProperty(localOr.getResource(), localR); + AxisAngle4d p = getWorldFromLocal(node, new AxisAngle4d(localR)); + G3DTools.setOrientation(worldOr, p); + storeProperty(worldOr.getResource(), p); + if (DEBUG) System.out.println("Node changed localR: wr " + p + " lr " + localR + " old " + cachedLocalR); + changed = true; + } else if (changedWorldR) { + storeProperty(worldOr.getResource(), worldR); + AxisAngle4d p = getLocalFromWorld(node, new AxisAngle4d(worldR)); + G3DTools.setOrientation(localOr, p); + storeProperty(localOr.getResource(), p); + if (DEBUG) System.out.println("Node changed worldR: wr " + worldR + " lr " + p + " old " + cachedWorldR); + changed = true; + } + } + + if (changed) + propagateTransformChange(node); + else if (DEBUG) + System.out.println("No Node transformation change detected " + node.getResource()); + return changed; + } + + public static boolean changed(Tuple3d v1, Tuple3d v2) { + Vector3d t = new Vector3d(v1); + t.sub(v2); + return t.lengthSquared() > 0.00001; + } + + public static boolean changed (double d1 , double d2) { + return (Math.abs(d1 - d2) > 0.00001 ); + + } + + public static boolean changed(AxisAngle4d aa1, AxisAngle4d aa2) { + if (Math.abs(aa1.angle - aa2.angle) > 0.00001) + return true; + Vector3d t1 = new Vector3d(aa1.x-aa2.x,aa1.y-aa2.y,aa1.z-aa2.z); + if (t1.lengthSquared() > 0.00001) { + if (Math.abs(aa1.angle) < 0.0001) + return false; + return true; + } + return false; + } + + + private HashMap properties = new HashMap(); + + public Object getProperty(Object key) { + return properties.get(key); + } + + public void storeProperty(Object key, Object value) { + properties.put(key, value); + } + + + + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/VecmathJmeTools.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/VecmathJmeTools.java new file mode 100644 index 00000000..21cfcff0 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/VecmathJmeTools.java @@ -0,0 +1,78 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.base; + +import javax.vecmath.Color4f; + +import com.jme.renderer.ColorRGBA; + +public class VecmathJmeTools { + + public static javax.vecmath.Vector3f get(com.jme.math.Vector3f v) { + return new javax.vecmath.Vector3f(v.x,v.y,v.z); + } + + public static javax.vecmath.Vector3d getD(com.jme.math.Vector3f v) { + return new javax.vecmath.Vector3d(v.x,v.y,v.z); + } + + public static com.jme.math.Vector3f get(javax.vecmath.Tuple3f v) { + return new com.jme.math.Vector3f(v.x,v.y,v.z); + } + + public static com.jme.math.Vector3f get(javax.vecmath.Tuple3d v) { + return new com.jme.math.Vector3f((float)v.x,(float)v.y,(float)v.z); + } + + public static com.jme.math.Matrix3f get(javax.vecmath.Matrix3d m) { + return new com.jme.math.Matrix3f((float)m.m00,(float)m.m01,(float)m.m02,(float)m.m10,(float)m.m11,(float)m.m12,(float)m.m20,(float)m.m21,(float)m.m22); + } + + public static javax.vecmath.Quat4f get(com.jme.math.Quaternion v) { + return new javax.vecmath.Quat4f(v.x,v.y,v.z,v.w); + } + + public static javax.vecmath.Quat4d getD(com.jme.math.Quaternion v) { + return new javax.vecmath.Quat4d(v.x,v.y,v.z,v.w); + } + + + public static com.jme.math.Quaternion get(javax.vecmath.Quat4f v) { + return new com.jme.math.Quaternion(v.x,v.y,v.z,v.w); + } + + public static com.jme.math.Quaternion get(javax.vecmath.Quat4d v) { + return new com.jme.math.Quaternion((float)v.x,(float)v.y,(float)v.z,(float)v.w); + } + + public static com.jme.math.Quaternion get(javax.vecmath.AxisAngle4f aa) { + javax.vecmath.Quat4f v = new javax.vecmath.Quat4f(); + v.set(aa); + return new com.jme.math.Quaternion(v.x,v.y,v.z,v.w); + + } + + public static com.jme.math.Quaternion get(javax.vecmath.AxisAngle4d aa) { + javax.vecmath.Quat4f v = new javax.vecmath.Quat4f(); + v.set(aa); + return new com.jme.math.Quaternion(v.x,v.y,v.z,v.w); + + } + + public static ColorRGBA get(Color4f c) { + return new ColorRGBA(c.x,c.y,c.z,c.w); + } + + public static Color4f get(ColorRGBA c) { + return new Color4f(c.r,c.g,c.b,c.a); + } + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/VisualizationScheduler.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/VisualizationScheduler.java new file mode 100644 index 00000000..e7011eb7 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/VisualizationScheduler.java @@ -0,0 +1,199 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.base; + +import java.util.ArrayList; + +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.PlatformUI; +import org.simantics.utils.ErrorLogger; + + +/** + * TODO : This is a copy-paste from old proconf.utils plug-ing: + * : PreferencePage is not ported, + * : Using Webmon ? + * + * + * VisualizationScheduler is singleton class that schedules + * visualization redraws. + * + * Scheduler has three behaviour patters: + * + * ONCE : Redraws all visualizations one by one and then sleeps for + * a while so that visualizations won't use all available cpu-time. + * + * ALWAYS : Redraws one visualization and sleeps before updating next + * visualization. + * + * OFF : uses asyncExec busy-loop (doesn't block eclipse, but other applications may suffer) + * + * + * @author Marko Luukkainen + * + */ +public class VisualizationScheduler implements Runnable{ + private static VisualizationScheduler instance; + private Display display; + private ArrayList visualizations; + private boolean isDisposed = false; + private boolean stateFlag = false; + private static int sleepTime = 40; + private int index = 0; + + public enum SleepType{ONCE,ALWAYS,OFF}; + + private static SleepType sleepType = SleepType.ONCE; + + private VisualizationScheduler() { + visualizations = new ArrayList(); + display = PlatformUI.getWorkbench().getDisplay(); + //sleepTime = UtilsPlugin.getDefault().getPreferenceStore().getInt(PreferenceConstants.SLEEP_TIME); + //sleepType = SleepType.valueOf(UtilsPlugin.getDefault().getPreferenceStore().getString(PreferenceConstants.SLEEP_TYPE)); + run(); + } + + /** + * Scheduler's run loop
+ *
+ * Loop contains two stages:
+ * In the first stage scheduler runs asyncExec for each visualization + * and after that it runs itself with asyncExec.
+ * In the second stage scheduler runs itself with timerExec which allows OS to run it's own code. + */ + public void run() { + if (!isDisposed && !display.isDisposed() && !PlatformUI.getWorkbench().isClosing()) { + switch(sleepType) { + case ALWAYS: + stateFlag = !stateFlag; + if (stateFlag) { + if (visualizations.size() > 0) { + if (index >= visualizations.size()) + index = 0; + Runnable scene = visualizations.get(index); + try { + display.asyncExec(scene); + } catch (Exception e) { + ErrorLogger.defaultLogWarning("Scheduler exception", e); + } + index++; + } + display.asyncExec(this); + } else { + display.timerExec(sleepTime, this); + } + break; + case ONCE: + stateFlag = !stateFlag; + if (stateFlag) { + for (Runnable scene : visualizations) { + try { + display.asyncExec(scene); + } catch (Exception e) { + ErrorLogger.defaultLogWarning("Scheduler exception",e); + } + } + display.asyncExec(this); + } else { + display.timerExec(sleepTime,this); + } + break; + case OFF: + for (Runnable scene : visualizations) { + try { + display.asyncExec(scene); + } catch (Exception e) { + ErrorLogger.defaultLogWarning("Scheduler exception",e); + } + } + display.asyncExec(this); + break; + } + } + } + + /** + * Adds visualization into scheduler + * @param scene + */ + public void addVisualization(Runnable scene) { + visualizations.add(scene); + } + + /** + * Removes visualization from scheduler + * @param scene + */ + public void removeVisualization(Runnable scene) { + visualizations.remove(scene); + } + + /** + * disposes scheduler. + * + */ + public void dispose() { + isDisposed = true; + } + + /** + * @return scheduler's instance + */ + public static VisualizationScheduler getInstance() { + if (instance == null) + instance = new VisualizationScheduler(); + + return instance; + } + + /** + * @return the sleep time of the scheduler + */ + public int getSleepTime() { + return sleepTime; + } + + /** + *

+ * Sets scheduler's sleep time. Larger sleep time gives more + * cpu time to other applications, but makes visualizations less + * responsive. + *

+ * + * @param sleepTime + */ + public static void setSleepTime(int time) { + sleepTime = time; + } + +// public boolean isSleepAlways() { +// return sleepAlways; +// } + + /** + * if this flag is set scheludler gives time to other aplications + * between each visualization update. Otherwise all visualizations are updated in row and + * then priority is given to other applications. + * @param sleepAlways + */ +// public static void setSleepAlways(boolean sleep) { +// sleepAlways = sleep; +// } + + public static SleepType getSleepType() { + return sleepType; + } + + public static void setSleepType(SleepType s) { + sleepType = s; + } + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/common/JmeComposite.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/common/JmeComposite.java new file mode 100644 index 00000000..5cff3ffb --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/common/JmeComposite.java @@ -0,0 +1,112 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.common; + + +import java.util.logging.LogManager; + +import org.eclipse.core.runtime.Path; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ControlAdapter; +import org.eclipse.swt.events.ControlEvent; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.opengl.GLCanvas; +import org.eclipse.swt.widgets.Composite; +import org.simantics.proconf.g3d.base.JmeRenderingComponent; +import org.simantics.proconf.g3d.base.ResourceTextureCache; +import org.simantics.utils.ErrorLogger; + +import com.jme.renderer.Renderer; +import com.jme.renderer.lwjgl.LWJGLRenderer; +import com.jme.scene.Node; +import com.jme.system.DisplaySystem; +import com.jme.system.swt.SWTDisplaySystem; +import com.jme.util.TextureManager; + + +public class JmeComposite extends Composite { + protected Node rootNode = new Node("root"); + private SWTDisplaySystem displaySystem; + protected GLCanvas renderingCanvas; + private JmeRenderingComponent component; + + public JmeComposite(Composite parent, JmeRenderingComponent component) { + super(parent,SWT.NONE); + if (component == null) + throw new NullPointerException("Rendering component must not be null."); + disableLog(); + //LoggingSystem.getLogger().setLevel(Level.OFF); + this.component = component; + this.setLayout(new FillLayout()); + displaySystem = (SWTDisplaySystem)DisplaySystem.getDisplaySystem("SWT"); + renderingCanvas = displaySystem.createCanvas(640, 480, this); + renderingCanvas.addControlListener(new ControlAdapter() { + public void controlResized(ControlEvent e) { + resize(); + } + }); + + + } + + private void disableLog() { + //URL url = FileLocator.find(org.simantics.proconf.g3d.Activator.getDefault().getBundle(),new Path("logging.properties"),null); + + try { + LogManager.getLogManager().readConfiguration(org.simantics.proconf.g3d.Activator.getDefault().openStream(new Path("logging.properties"))); + } catch (Exception e) { + ErrorLogger.defaultLogError(e); + } + } + + public void resize() { + displaySystem.setCurrent(); + LWJGLRenderer renderer = (LWJGLRenderer) displaySystem.getRenderer(); + if (renderer!= null) { + Rectangle r = new Rectangle(renderingCanvas.getClientArea().x,renderingCanvas.getClientArea().y, renderingCanvas.getClientArea().width, renderingCanvas.getClientArea().height ); + if (r.width > 0 && r.height > 0) + renderer.reinit(r.width, r.height); + component.resize(r.width, r.height); + } + } + + public GLCanvas getCanvas() { + return renderingCanvas; + } + + public Renderer getRenderer() { + return displaySystem.getRenderer(); + } + + public void initGL() { + component.init(displaySystem); + } + + public void dispose() { + LWJGLRenderer renderer = (LWJGLRenderer) displaySystem.getRenderer(); + renderer.clearVBOCache(); + renderer.clearQueue(); + renderer.clearStatistics(); + renderingCanvas.dispose(); + if (displaySystem.destroy()) { + + TextureManager.doTextureCleanup(); + TextureManager.clearCache(); + ResourceTextureCache.getInstance().clear(); + } + super.dispose(); + } + + public DisplaySystem getDisplaySystem() { + return displaySystem; + } +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/common/JmeSinglePassRenderingComponent.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/common/JmeSinglePassRenderingComponent.java new file mode 100644 index 00000000..fb9aff60 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/common/JmeSinglePassRenderingComponent.java @@ -0,0 +1,411 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.common; + +import java.net.URL; + +import org.eclipse.core.runtime.FileLocator; +import org.eclipse.core.runtime.Path; +import org.simantics.proconf.g3d.Activator; +import org.simantics.proconf.g3d.base.JmeRenderingComponent; +import org.simantics.proconf.g3d.preferences.PreferenceConstants; + +import com.jme.image.Texture; +import com.jme.light.DirectionalLight; +import com.jme.math.Vector3f; +import com.jme.renderer.Camera; +import com.jme.renderer.ColorRGBA; +import com.jme.renderer.pass.BasicPassManager; +import com.jme.renderer.pass.RenderPass; +import com.jme.renderer.pass.ShadowedRenderPass; +import com.jme.renderer.swt.SWTRenderer; +import com.jme.scene.Node; +import com.jme.scene.Spatial; +import com.jme.scene.Text; +import com.jme.scene.state.AlphaState; +import com.jme.scene.state.LightState; +import com.jme.scene.state.TextureState; +import com.jme.scene.state.WireframeState; +import com.jme.scene.state.ZBufferState; +import com.jme.system.DisplaySystem; +import com.jme.util.TextureManager; +import com.jme.util.Timer; +import com.jme.util.geom.Debugger; +import com.jmex.effects.glsl.BloomRenderPass; +import com.jmex.effects.glsl.SketchRenderPass; + + +public class JmeSinglePassRenderingComponent extends JmeRenderingComponent { + protected DisplaySystem displaySystem; + protected Timer timer; + protected Node rootNode = new Node("Root"); + protected Node shadowRootNode = new Node("Shadow"); + protected Node noCastShadowRootNode = new Node("No Cast Shadow"); + protected Node noShadowRootNode = new Node("No Shadow"); + protected Camera cam; + protected float near = .1f; + protected float far = 3000f; + protected float fov = 55f; + + protected int projectionPolicy; + + /** The root node of our text. */ + protected Node orthoNode = new Node("ortho"); + + /** Displays all the lovely information at the bottom. */ + protected Text fps; + protected Text debug; + protected String debugText = ""; + public static String fontLocation = "data/defaultfont.tga";//AppProperties.PATH_DEFAULT_FONT; + + + protected BasicPassManager pManager = new BasicPassManager(); + + private boolean showBounds = false; + private boolean showNormals = false; + private WireframeState ws = null; + + private boolean projectionUpdated = false; + + public JmeSinglePassRenderingComponent() { + + } + + public void init(DisplaySystem displaySystem) { + this.displaySystem = displaySystem; + cam = displaySystem.getRenderer().createCamera( + displaySystem.getRenderer().getWidth(), displaySystem.getRenderer().getHeight()); + displaySystem.getRenderer().setBackgroundColor(new ColorRGBA(0.2f,0.2f,0.2f,0.f));//(0.357F, 0.647F, 0.890F, 1.0F)); + displaySystem.getRenderer().getQueue().setTwoPassTransparency(true); + cam.setFrustumPerspective(fov, + (float) displaySystem.getRenderer().getWidth()/ + (float) displaySystem.getRenderer().getHeight(),near, far); + projectionPolicy = PERSPECTIVE_PROJECTION; + Vector3f loc = new Vector3f(0.0f, 0.0f, 10.0f); + Vector3f left = new Vector3f(-1.0f, 0.0f, 0.0f); + Vector3f up = new Vector3f(0.0f, 1.0f, 0.0f); + Vector3f dir = new Vector3f(0.0f, 0f, -1.0f); + /** Move our camera to a correct place and orientation. */ + cam.setFrame(loc, left, up, dir); + /** Signal that we've changed our camera's location/frustum. */ + cam.update(); + displaySystem.getRenderer().setCamera(cam); + timer = Timer.getTimer(); + displaySystem.setTitle("ShapeEditor"); + displaySystem.getRenderer().enableStatistics(true); + + initRoot(); + } + + protected Texture loadFontTexture() { + URL url = FileLocator.find(org.simantics.proconf.g3d.Activator.getDefault().getBundle(),new Path(fontLocation),null); + return TextureManager.loadTexture(url, Texture.MM_LINEAR, + Texture.FM_LINEAR); + } + + protected void initRoot() { + ZBufferState buf = displaySystem.getRenderer().createZBufferState(); + buf.setEnabled(true); + buf.setFunction(ZBufferState.CF_LEQUAL); + //buf.setWritable(false); + rootNode.setRenderState(buf); + rootNode.attachChild(noShadowRootNode); + rootNode.attachChild(noCastShadowRootNode); + rootNode.attachChild(shadowRootNode); + noShadowRootNode.setCullMode(Spatial.CULL_NEVER); + + //PointLight light = new PointLight(); + DirectionalLight light = new DirectionalLight(); + light.setDiffuse( new ColorRGBA( 0.75f, 0.75f, 0.75f, 0.75f ) ); + light.setAmbient( new ColorRGBA( 0.5f, 0.5f, 0.5f, 0.5f ) ); + //light.setLocation( new Vector3f( 100, 100, 100 ) ); + light.setDirection(new Vector3f( -100, -150, -100 )); + light.setEnabled( true ); + light.setShadowCaster(true); + + LightState lightState = displaySystem.getRenderer().createLightState(); + lightState.setEnabled( true ); + lightState.attach( light ); + lightState.setSeparateSpecular(true); + lightState.setTwoSidedLighting(false); + rootNode.setRenderState( lightState ); + + ws = displaySystem.getRenderer().createWireframeState(); + ws.setEnabled(false); + rootNode.setRenderState(ws); + + AlphaState as1 = displaySystem.getRenderer().createAlphaState(); + as1.setBlendEnabled(true); + as1.setSrcFunction(AlphaState.SB_SRC_ALPHA); + as1.setDstFunction(AlphaState.DB_ONE); + as1.setTestEnabled(true); + as1.setTestFunction(AlphaState.TF_GREATER); + as1.setEnabled(true); + + TextureState font = displaySystem.getRenderer().createTextureState(); + /** The texture is loaded from fontLocation */ + font.setTexture(loadFontTexture()); + + font.setEnabled(true); + + // Then our font Text object. + /** This is what will actually have the text at the bottom. */ + fps = new Text("FPS label", ""); + fps.setCullMode(Spatial.CULL_NEVER); + fps.setTextureCombineMode(TextureState.REPLACE); + + debug = new Text("Debug", "Debug"); + debug.setCullMode(Spatial.CULL_NEVER); + debug.setTextureCombineMode(TextureState.REPLACE); + debug.setLocalTranslation(new Vector3f(1.f,10.f,0.f)); + + // Finally, a stand alone node (not attached to root on purpose) + Node fpsNode = new Node("FPS node"); + fpsNode.attachChild(fps); + fpsNode.attachChild(debug); + fpsNode.setRenderState(font); + fpsNode.setRenderState(as1); + fpsNode.setCullMode(Spatial.CULL_NEVER); + orthoNode.attachChild(fpsNode); + + rootNode.updateGeometricState(0.0f, true); + rootNode.updateRenderState(); + + orthoNode.updateGeometricState(0.0f, true); + orthoNode.updateRenderState(); + if (Activator.getDefault().getPreferenceStore().getBoolean(PreferenceConstants.SHADOWS)) { + ShadowedRenderPass shadowRootPass = new ShadowedRenderPass(); + shadowRootPass.add(shadowRootNode); + shadowRootPass.add(noCastShadowRootNode); + shadowRootPass.addOccluder(shadowRootNode); + pManager.add(shadowRootPass); + //rootPass.setRenderShadows(false); + shadowRootPass.setShadowColor(new ColorRGBA(0.1f,0.1f,0.1f,0.9f)); + shadowRootPass.setLightingMethod(ShadowedRenderPass.MODULATIVE); + RenderPass rootPass = new RenderPass(); + rootPass.add(noShadowRootNode); + pManager.add(rootPass); + } else { + RenderPass rootPass = new RenderPass(); + rootPass.add(rootNode); + pManager.add(rootPass); + } + + String postProcess = Activator.getDefault().getPreferenceStore().getString(PreferenceConstants.POST_PROCESS); + if (postProcess.startsWith("bloom")) { + BloomRenderPass bloomRenderPass = new BloomRenderPass(cam, 4); + if (bloomRenderPass.isSupported()) { + bloomRenderPass.add(rootNode); + bloomRenderPass.setUseCurrentScene(false); + pManager.add(bloomRenderPass); + } + } else if (postProcess.startsWith("sketch")) { + SketchRenderPass sketchRenderPass = new SketchRenderPass(cam, 4); + if (sketchRenderPass.isSupported()) { + sketchRenderPass.add(rootNode); + pManager.add(sketchRenderPass); + } + } + + + RenderPass fpsPass = new RenderPass(); + fpsPass.add(orthoNode); + pManager.add(fpsPass); + } + + public void render() { + displaySystem.setCurrent(); + /** Recalculate the framerate. */ + timer.update(); + + /** Update tpf to time per frame according to the Timer. */ + float tpf = timer.getTimePerFrame(); + /** Send the fps to our fps bar at the bottom. */ + fps.print("FPS: " + (int) timer.getFrameRate() + " - " + + displaySystem.getRenderer().getStatistics()); + /** + * Update the physics for this world. + */ + debug.print(debugText); + + /** Update controllers/render states/transforms/bounds for rootNode. */ + rootNode.updateGeometricState(tpf, true); + rootNode.updateRenderState(); + + orthoNode.updateGeometricState(tpf, true); + orthoNode.updateRenderState(); + + displaySystem.getRenderer().clearStatistics(); + /** Clears the previously rendered information. */ + displaySystem.getRenderer().clearBuffers(); + + pManager.updatePasses(tpf); + + pManager.renderPasses(displaySystem.getRenderer()); + if ( showBounds ) { + Debugger.drawBounds( shadowRootNode, displaySystem.getRenderer(), true ); + } + + if ( showNormals ) { + Debugger.drawNormals( shadowRootNode, displaySystem.getRenderer()); + } + displaySystem.getRenderer().displayBackBuffer(); + + + + //swap buffers + ((SWTRenderer)displaySystem.getRenderer()).swap(); + } + + @Override + public void resize(int width, int height) { + updateProjection(); + } + + @Override + public Node getShadowRoot() { + return shadowRootNode; + } + + @Override + public Node getNoCastRoot() { + return noCastShadowRootNode; + } + + @Override + public Node getRoot() { + return rootNode; + } + + @Override + public Node getOrthoNode() { + return orthoNode; + } + + @Override + public Node getNoShadowRoot() { + return noShadowRootNode; + } + +// public void setRootNode(Node node) { +// rootNode = node; +// initRoot(); +// } + + @Override + public int getProjectionPolicy() { + return projectionPolicy; + } + + @Override + public void setProjectionPolicy(int policy) { + if (policy != projectionPolicy) { + projectionPolicy = policy; + updateProjection(); + } + } + + private void updateProjection() { + switch (projectionPolicy) { + case PERSPECTIVE_PROJECTION: + cam.setParallelProjection(false); + cam.setFrustumPerspective(fov, + (float) displaySystem.getRenderer().getWidth() / + (float) displaySystem.getRenderer().getHeight(),near, far); + break; + + case PARALLEL_PROJECTION: + cam.setParallelProjection(true); + break; + } + cam.update(); + projectionUpdated = true; + } + + @Override + public float getScreenScale() { + //System.out.println(cam.getFrustumLeft() + " " + cam.getFrustumRight() + " " + cam.getFrustumBottom() + " " + cam.getFrustumTop()+ " " + cam.getFrustumNear() + " " + cam.getFrustumFar()); + return Math.abs(cam.getFrustumTop()); + } + + @Override + public void setScreenScale(float screenScale) { + float aspect = (float) displaySystem.getRenderer().getWidth() / + (float) displaySystem.getRenderer().getHeight(); + cam.setFrustum(-screenScale*8.f, cam.getFrustumFar(), -screenScale*aspect, screenScale*aspect, -screenScale, screenScale); + } + + @Override + public float getFieldOfView() { + return fov; + } + + @Override + public void dispose() { + pManager.cleanUp(); + rootNode.dispose(); + rootNode = null; + noShadowRootNode = null; + noCastShadowRootNode = null; + orthoNode = null; + shadowRootNode = null; + } + + @Override + public boolean update() { + if (!projectionUpdated) { + return false; + } + projectionUpdated = false; + return true; + } + + @Override + public Camera getCamera() { + return cam; + } + + @Override + public DisplaySystem getDisplaySystem() { + return displaySystem; + } + + public void setDebugText(String text) { + this.debugText = text; + //System.out.println("JmeSinglePass.setDebugText() " + text); + } + + public void setShowNormals(boolean b) { + showNormals = b; + } + + public void setShowBounds(boolean b) { + showBounds = b; + } + + public void setShowWireframe(boolean b) { + ws.setEnabled(b); + } + + public boolean isShowNormals() { + return showNormals; + } + + public boolean isShowBounds() { + return showBounds; + } + + public boolean isShowWireframe() { + return ws.isEnabled(); + } + + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/common/OrbitalCamera.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/common/OrbitalCamera.java new file mode 100644 index 00000000..4b0aa6fc --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/common/OrbitalCamera.java @@ -0,0 +1,205 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.common; + +import javax.vecmath.AxisAngle4d; +import javax.vecmath.Matrix3d; +import javax.vecmath.Vector3d; + +import org.simantics.proconf.g3d.base.VecmathJmeTools; + +import com.jme.renderer.Camera; + + +/** + * Orbital camera + *

+ * Modified version of fi.vtt.proconf.webmon.graphics3d.utils.OrbitalCamera
+ * Using floats instead of double
+ *

+ * + * + * @author Marko Luukkainen + * + */ +public class OrbitalCamera { + + private Vector3d up = new Vector3d(0.0,1.0,0.0); + private static Vector3d up2 = new Vector3d(0.0,0.0,-1.0); + private static double minDistance = 0.5; + private Vector3d target = new Vector3d(); + private Vector3d cameraPos = new Vector3d(10.0,0.0,0.0); + + + public void translate(Vector3d v) { + target.add(v); + cameraPos.add(v); + } + + public void rotateAroundTarget(Vector3d axis, double angle) { + Vector3d temp = new Vector3d(cameraPos); + temp.sub(target); + Matrix3d rotation = new Matrix3d(); + rotation.set(new AxisAngle4d(axis,angle)); + rotation.transform(temp); + temp.add(target); + cameraPos.set(temp); + } + + public Vector3d getUnNormalizedHeading() { + Vector3d heading = new Vector3d(target); + heading.sub(cameraPos); + return heading; + } + + public Vector3d getUnNormalizedRight() { + Vector3d heading = getUnNormalizedHeading(); + Vector3d right = new Vector3d(); + right.cross(heading,up); + if (right.lengthSquared() < 0.01) + right.cross(heading,up2); + return right; + } + + public double getDistanceToTarget() { + Vector3d t = new Vector3d(target); + t.sub(cameraPos); + return t.length(); + } + + public void moveToTarget(double distance) { + Vector3d heading = getUnNormalizedHeading(); + double length = heading.length(); + if (length + distance < minDistance) { + // cannot move closer + return; + } + heading.scale(distance / length); //normalizing and scaling by distance + cameraPos.add(heading); + } + + public void moveScaledToTarget(double s) { + Vector3d heading = getUnNormalizedHeading(); + double currentLength = heading.length(); + double length = currentLength * (1.0 - s);// heading.length(); + if (length < minDistance) { + s = -minDistance / currentLength + 1.0; + } + heading.scale(s); + //normalizing and scaling by distance + cameraPos.add(heading); + } + + public void rotateUp(double angle) { + Vector3d right = getUnNormalizedRight(); + double length = right.length(); + // TODO : better handling of singular cases + if (length > 0.01) + right.scale(1.0/length); + else + right.set(-1.0,0.0,0.0); + rotateAroundTarget(right,angle); + } + + public void rotateRight(double angle) { + rotateAroundTarget(up,angle); + } + + public void moveRight(double length) { + Vector3d right = getUnNormalizedRight(); + right.normalize(); + right.scale(length); + translate(right); + } + + public void moveUp(double length) { + Vector3d u = new Vector3d(up); + u.scale(length); + translate(u); + } + + public void moveFront(double length) { + Vector3d right = getUnNormalizedRight(); + Vector3d front = new Vector3d(); + front.cross(up,right); + front.normalize(); + front.scale(length); + translate(front); + } + + public void updateCamera() { + Vector3d t = new Vector3d(cameraPos); + t.sub(target); + t.normalize(); + cam.setLocation(VecmathJmeTools.get(cameraPos)); + + if (Math.abs(t.dot(up)) > 0.99) { + cam.lookAt(VecmathJmeTools.get(target), VecmathJmeTools.get(up2)); + } else { + cam.lookAt(VecmathJmeTools.get(target), VecmathJmeTools.get(up)); + } + cam.update(); + cam.apply(); + + } + + /** + * @return Returns the cameraPos. + */ + public Vector3d getCameraPos() { + return cameraPos; + } + + /** + * @param cameraPos The cameraPos to set. + */ + public void setCameraPos(Vector3d cameraPos) { + this.cameraPos = cameraPos; + } + + /** + * @return Returns the target. + */ + public Vector3d getTarget() { + return target; + } + + /** + * @param target The target to set. + */ + public void setTarget(Vector3d target) { + this.target = target; + } + + public void setCameraPosRelativeToTarget(Vector3d targetToCam) { + targetToCam.add(target); + setCameraPos(targetToCam); + } + + public void setUp(Vector3d v) { + up.set(v); + } + + public Vector3d getUp() { + return up; + } + + public void setDefaultUp() { + up.set(0.0,1.0,0.0); + } + + private Camera cam; + + public void setCamera(Camera cam) { + this.cam = cam; + } + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/common/PropertyTester2.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/common/PropertyTester2.java new file mode 100644 index 00000000..0f57f7ae --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/common/PropertyTester2.java @@ -0,0 +1,18 @@ +package org.simantics.proconf.g3d.common; + +import org.eclipse.core.expressions.PropertyTester; + +public class PropertyTester2 extends PropertyTester { + + public PropertyTester2() { + // TODO Auto-generated constructor stub + } + + @Override + public boolean test(Object receiver, String property, Object[] args, + Object expectedValue) { + // TODO Auto-generated method stub + return false; + } + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/common/StructuredResourceSelection.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/common/StructuredResourceSelection.java new file mode 100644 index 00000000..a13062a8 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/common/StructuredResourceSelection.java @@ -0,0 +1,173 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.common; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.jface.viewers.IStructuredSelection; +import org.simantics.db.Resource; + + +/** + * StructuredSelection that contains ResourceSelections + * + * @author Marko Luukkainen + * @author Tuukka Lehtonen + */ +public class StructuredResourceSelection implements IStructuredSelection { + + public static final StructuredResourceSelection EMPTY = new StructuredResourceSelection() { + // Create an empty fixed size List to ensure the list is not modified. + private List empty = Arrays.asList(); + + public void add(Resource rs) { + throw new UnsupportedOperationException("BUG: attempted to modify StructuredResourceSelection.EMPTY"); + } + public List getSelectionList() { + return empty; + } + }; + + private List selections; + + /** + * Creates a new selection that doesn't contain any items + */ + public StructuredResourceSelection() { + } + + public StructuredResourceSelection(Resource rs) { + getSelectionList().add(rs); + } + + public StructuredResourceSelection(Resource... rss) { + List s = getSelectionList(); + for (Resource rs : rss) + s.add(rs); + } + + public void add(Resource rs) { + getSelectionList().add(rs); + } + + public List getSelectionList() { + if (selections == null) { + selections = new ArrayList(); + } + return selections; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.viewers.ISelection#isEmpty() + */ + public boolean isEmpty() { + return selections == null || selections.isEmpty(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.viewers.IStructuredSelection#getFirstElement() + */ + public Object getFirstElement() { + if (!isEmpty()) + return selections.get(0); + return null; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.viewers.IStructuredSelection#iterator() + */ + public Iterator iterator() { + return getSelectionList().iterator(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.viewers.IStructuredSelection#size() + */ + public int size() { + return selections == null ? 0 : selections.size(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.viewers.IStructuredSelection#toArray() + */ + public Object[] toArray() { + return selections == null ? new Object[0] : selections.toArray(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.viewers.IStructuredSelection#toList() + */ + public List toList() { + return selections == null ? Arrays.asList(new Resource[0]) : selections; + } + + /** + * Returns whether this structured selection is equal to the given object. + * Two structured selections are equal iff they contain the same elements + * in the same order. + * + * @param o the other object + * @return true if they are equal, and false otherwise + */ + public boolean equals(Object o) { + if (this == o) { + return true; + } + // null and other classes + if (!(o instanceof StructuredResourceSelection)) { + return false; + } + StructuredResourceSelection other = (StructuredResourceSelection) o; + + // either or both empty? + if (isEmpty()) { + return other.isEmpty(); + } + if (other.isEmpty()) { + return false; + } + + // check size + if (size() != other.size()) + return false; + + // element comparison + Iterator it = iterator(); + Iterator otherIt = other.iterator(); + while (it.hasNext()) { + if (!it.next().equals(otherIt.next())) + return false; + } + + return true; + } + + @Override + public String toString() { + return Arrays.toString(getSelectionList().toArray()); + } + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/dialogs/JMEDialog.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/dialogs/JMEDialog.java new file mode 100644 index 00000000..9e2950db --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/dialogs/JMEDialog.java @@ -0,0 +1,174 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.dialogs; + +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.MouseAdapter; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.RGB; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.ColorDialog; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; + +public class JMEDialog extends Dialog { + private boolean bounds; + private boolean normals; + private boolean wireframe; + private float[] floatColor = null; + private Button boundsButton; + private Button normalsButton; + private Button wireframeButton; + private Composite colorComposite; + private Color color = null; + + public JMEDialog(Shell parentShell) { + super(parentShell); + } + + + @Override + protected void configureShell(Shell newShell) { + super.configureShell(newShell); + newShell.setText("Configure new pipeline"); + } + + @Override + protected Control createDialogArea(Composite parent) { + Composite composite = (Composite) super.createDialogArea(parent); + Label label = new Label(composite, SWT.WRAP); + label.setText("JME Configuration"); + GridData data = new GridData(GridData.GRAB_HORIZONTAL + | GridData.GRAB_VERTICAL | GridData.HORIZONTAL_ALIGN_FILL + | GridData.VERTICAL_ALIGN_CENTER); + + data.widthHint = convertHorizontalDLUsToPixels(IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH); + boundsButton = new Button(composite,SWT.CHECK); + boundsButton.setText("Show bounds"); + boundsButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + bounds = boundsButton.getSelection(); + } + }); + boundsButton.setSelection(bounds); + normalsButton = new Button(composite,SWT.CHECK); + normalsButton.setText("Show normals"); + normalsButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + normals = normalsButton.getSelection(); + } + }); + normalsButton.setSelection(normals); + wireframeButton = new Button(composite,SWT.CHECK); + wireframeButton.setText("Show wireframe"); + wireframeButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + wireframe = wireframeButton.getSelection(); + } + }); + wireframeButton.setSelection(wireframe); + + colorComposite = new Composite(composite,SWT.BORDER); + colorComposite.addMouseListener(new MouseAdapter() { + @Override + public void mouseUp(MouseEvent e) { + ColorDialog dialog = new ColorDialog(JMEDialog.this.getShell()); + RGB rgb = dialog.open(); + if (rgb != null) { + if (color != null) + color.dispose(); + color = new Color(JMEDialog.this.getShell().getDisplay(),rgb); + colorComposite.setBackground(color); + floatColor = new float[]{rgb.red/255.f,rgb.green/255.f,rgb.blue/255.f}; + } + } + }); + updateColor(); + + return composite; + } + + @Override + public int open() { + return super.open(); + } + + + public boolean isBounds() { + return bounds; + } + + + public void setBounds(boolean bounds) { + this.bounds = bounds; + } + + + public boolean isNormals() { + return normals; + } + + + public void setNormals(boolean normals) { + this.normals = normals; + } + + + public boolean isWireframe() { + return wireframe; + } + + + public void setWireframe(boolean wireframe) { + this.wireframe = wireframe; + } + + + public float[] getFloatColor() { + return floatColor; + } + + public void setFloatColor(float[] c) { + this.floatColor = c; + if (floatColor == null) + return; + + updateColor(); + } + + private void updateColor() { + if (colorComposite == null) + return; + if (color != null) + color.dispose(); + RGB rgb = new RGB((int)(floatColor[0]*255.f),(int)(floatColor[1]*255.f),(int)(floatColor[2]*255.f)); + color = new Color(JMEDialog.this.getShell().getDisplay(),rgb); + colorComposite.setBackground(color); + } + + + + + + + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/dnd/DropListener.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/dnd/DropListener.java new file mode 100644 index 00000000..70e9610f --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/dnd/DropListener.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.dnd; + +import org.simantics.db.Resource; +import org.simantics.proconf.g3d.common.StructuredResourceSelection; + + + +public interface DropListener { + + boolean acceptDrop(StructuredResourceSelection s, Resource res[]); + void doDrop(StructuredResourceSelection s, Resource res[]); + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/dnd/ShapeDropTarget.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/dnd/ShapeDropTarget.java new file mode 100644 index 00000000..fe832e65 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/dnd/ShapeDropTarget.java @@ -0,0 +1,124 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.dnd; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.swt.dnd.DND; +import org.eclipse.swt.dnd.DropTarget; +import org.eclipse.swt.dnd.DropTargetEvent; +import org.eclipse.swt.dnd.DropTargetListener; +import org.eclipse.swt.dnd.TextTransfer; +import org.eclipse.swt.dnd.Transfer; +import org.eclipse.swt.dnd.TransferData; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.widgets.Control; +import org.simantics.db.Resource; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.common.StructuredResourceSelection; +import org.simantics.proconf.ui.dnd.ResourceReferenceTransfer; + +public class ShapeDropTarget implements DropTargetListener{ + ThreeDimensionalEditorBase editor; + List listeners; + final Control control; + private DropTarget target; + + public ShapeDropTarget(ThreeDimensionalEditorBase editor) { + this.editor = editor; + listeners = new ArrayList(); + this.control = editor.getRenderingComposite(); + + target = new DropTarget(control, DND.DROP_LINK); + target.setTransfer(new Transfer[] { ResourceReferenceTransfer.getInstance() }); + target.addDropListener(this); + } + + public void addDropListener(DropListener listener) { + listeners.add(listener); + } + + public void removeDropListener(DropListener listener) { + listeners.remove(listener); + } + + @Override + public void dragEnter(DropTargetEvent event) { + event.detail = DND.DROP_LINK; + dragOver(event); + } + + public void dragOperationChanged(DropTargetEvent event) { + } + + public void dropAccept(DropTargetEvent event) { + } + + public void dragLeave(DropTargetEvent event) { + } + + + @Override + public void dragOver(DropTargetEvent event) { + // FIXME : a hack to get the actual data (probably works only in Windows) + TransferData data = event.currentDataType; + if(!TextTransfer.getInstance().isSupportedType(data)) + return; + Object o = TextTransfer.getInstance().nativeToJava(data); + + Point p = getLocalCoords(event); + editor.getInputProvider().setMouseMoved(true); + editor.getInputProvider().setMouseX(p.x); + editor.getInputProvider().setMouseY(p.y); + editor.run(); + StructuredResourceSelection sel = editor.getSelectionAdapter().getHighlightSelection(); + + event.data = o; + Resource ids[] = parseEventData(event); + for (DropListener l : listeners) { + if(l.acceptDrop(sel, ids)) { + event.detail = DND.DROP_LINK; + return; + } + } + event.detail = DND.DROP_NONE; + } + + @Override + public void drop(DropTargetEvent event) { + StructuredResourceSelection sel = editor.getSelectionAdapter().getHighlightSelection(); + Resource ids[] = parseEventData(event); + for (DropListener l : listeners) { + if(l.acceptDrop(sel, ids)) { + l.doDrop(sel, ids); + return; + } + } + } + + protected Point getLocalCoords(DropTargetEvent event) { + return editor.getRenderingComposite().toControl(event.x, event.y); + } + + public void dispose() + { + target.removeDropListener(this); + target = null; + } + + private Resource[] parseEventData(DropTargetEvent event) { + if (ResourceReferenceTransfer.getInstance().isSupportedType(event.currentDataType) && (event.data instanceof Resource[])) { + return (Resource[]) event.data; + } + return null; + } +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/gizmo/AbstractGizmo.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/gizmo/AbstractGizmo.java new file mode 100644 index 00000000..e6f7b61c --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/gizmo/AbstractGizmo.java @@ -0,0 +1,198 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.gizmo; + +import javax.vecmath.AxisAngle4f; +import javax.vecmath.Color4f; +import javax.vecmath.Quat4f; +import javax.vecmath.Tuple3d; +import javax.vecmath.Tuple3f; +import javax.vecmath.Vector3d; +import javax.vecmath.Vector3f; + +import org.simantics.proconf.g3d.Activator; +import org.simantics.proconf.g3d.base.JmeRenderingComponent; +import org.simantics.proconf.g3d.base.VecmathJmeTools; +import org.simantics.proconf.g3d.preferences.PreferenceConstants; + +import com.jme.renderer.Renderer; +import com.jme.scene.Node; + + +public abstract class AbstractGizmo implements Gizmo{ + + private Node position; + private Node rotate; + private Node scale; + + private boolean changed = false; + + private double userScale = 1.0; + + public AbstractGizmo() { + createGroups(); + } + + public void setChanged(boolean b) { + changed = b; + } + + public boolean isChanged() { + return changed; + } + + public double getUserScale() { + return Activator.getDefault().getPreferenceStore().getDouble(PreferenceConstants.GIZMO_SCALE); + } + + + public void setScale(float scale) { + this.scale.setLocalScale(scale); + } + + public void setScale(Vector3f scale) { + this.scale.setLocalScale(VecmathJmeTools.get(scale)); + } + + public Vector3d getPosition() { + return VecmathJmeTools.getD(position.getWorldTranslation()); + } + + public Vector3f getPositionFloat() { + return VecmathJmeTools.get(position.getWorldTranslation()); + } + + public void setPosition(Tuple3d position) { + this.position.setLocalTranslation(VecmathJmeTools.get(position)); + } + + public void setPosition(Vector3f position) { + this.position.setLocalTranslation(VecmathJmeTools.get(position)); + } + + public void setRotation(Quat4f q) { + rotate.setLocalRotation(VecmathJmeTools.get(q)); + } + + public void setRotation(AxisAngle4f q) { + rotate.setLocalRotation(VecmathJmeTools.get(q)); + } + + public Node getNode() { + userScale = getUserScale(); + return position; + } + + protected Node getGizmoNode() { + return scale; + } + + private void createGroups() { + + position = new Node(); + rotate = new Node(); + scale = new Node(); + position.attachChild(rotate); + rotate.attachChild(scale); + position.setRenderQueueMode(Renderer.QUEUE_TRANSPARENT); + } + + public void update(Tuple3d position, Tuple3d cameraPosition, JmeRenderingComponent component) { + setPosition(position); + com.jme.math.Vector3f p = VecmathJmeTools.get(position); + p.subtractLocal(VecmathJmeTools.get(cameraPosition)); + rotate.getLocalRotation().inverse().multLocal(p); + if (component.getProjectionPolicy() == JmeRenderingComponent.PERSPECTIVE_PROJECTION) { + + double distance = p.length(); + // (bug caused in Xith->JME translation ?) + p.negateLocal(); + double fov = component.getFieldOfView(); + float s = (float) (Math.sin(fov) * distance * 0.1); // scaling factor was 0.2 with Xith + s *= (float)userScale; + Vector3f scale = new Vector3f(1.f, 1.f, 1.f); + + if (p.x > 0.f) + scale.x = -1.f; + if (p.y > 0.f) + scale.y = -1.f; + if (p.z > 0.f) + scale.z = -1.f; + scale.scale(s); + setScale(scale); + } else { + Vector3f scale = new Vector3f(1.f, 1.f, 1.f); + float s = component.getScreenScale() / 5.f; + s *= (float)userScale; + if (p.x > 0.f) + scale.x = -1.f; + if (p.y > 0.f) + scale.y = -1.f; + if (p.z > 0.f) + scale.z = -1.f; + scale.scale(s); + setScale(scale); + + } + } + + public void update(Tuple3d cameraPosition, JmeRenderingComponent component) { + + com.jme.math.Vector3f p = VecmathJmeTools.get(getPosition()); + p.subtractLocal(VecmathJmeTools.get(cameraPosition)); + rotate.getLocalRotation().inverse().multLocal(p); + if (component.getProjectionPolicy() == JmeRenderingComponent.PERSPECTIVE_PROJECTION) { + + double distance = p.length(); + double fov = component.getFieldOfView(); + float s = (float)(Math.sin(fov) * distance * 0.1); // scaling factor was 0.2 with Xith + s *= (float)userScale; + Vector3f scale = new Vector3f(1.f,1.f,1.f); + if (p.x > 0.f) + scale.x = -1.f; + if (p.y > 0.f) + scale.y = -1.f; + if (p.z > 0.f) + scale.z = -1.f; + scale.scale(s); + setScale(scale); + } else { + + Vector3f scale = new Vector3f(1.f,1.f,1.f); + float s = component.getScreenScale()/5.f; + s *= (float)userScale; + if (p.x > 0.f) + scale.x = -1.f; + if (p.y > 0.f) + scale.y = -1.f; + if (p.z > 0.f) + scale.z = -1.f; + scale.scale(s); + setScale(scale); + + } + } + + protected void setCoordinate(float array[], int index, Tuple3f c) { + index *= 3; + array[index++] = c.x; + array[index++] = c.y; + array[index] = c.z; + } + + protected void setColor(float array[], int index, Color4f c) { + index *= 4; + array[index++] = c.x; + array[index++] = c.y; + array[index++] = c.z; + array[index] = c.w; + } +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/gizmo/Gizmo.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/gizmo/Gizmo.java new file mode 100644 index 00000000..0e791cac --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/gizmo/Gizmo.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.gizmo; + +import com.jme.scene.Node; + +/** + * Interface for gizmos, interactive components in the scene-graph. + * + * @author Marko Luukkainen + * + */ +public interface Gizmo { + + /** + * Must return unique identifier for this gizmo + * @return + */ + public abstract String getPickPrefix(); + + /** + * Sets selected component (where mouse is hovering) by using its name. + * Name includes pick prefix + * @param name + */ + public abstract void setSelected(String name); + + /** + * Returns root-node of the gizmo. It is used for inserting the gizmo into scenegraph. + * @return + */ + public abstract Node getNode(); + + /** + * Returns true if gizmo needs to be redrawn. + * @return + */ + public boolean isChanged(); + + public void setChanged(boolean b); + +} \ No newline at end of file diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/gizmo/MultiSelectionGizmo.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/gizmo/MultiSelectionGizmo.java new file mode 100644 index 00000000..b73b8865 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/gizmo/MultiSelectionGizmo.java @@ -0,0 +1,110 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.gizmo; + +import java.nio.FloatBuffer; + +import javax.vecmath.Color4f; + +import org.simantics.proconf.g3d.base.VecmathJmeTools; + +import com.jme.renderer.ColorRGBA; +import com.jme.scene.TriMesh; +import com.jme.util.geom.BufferUtils; + + + +public abstract class MultiSelectionGizmo extends AbstractGizmo { + + public static final int UNSELECTED = 0; + public static final int SELECTED = 1; + + private TriMesh geoms[] = new TriMesh[4]; + private ColorRGBA colors[][] = new ColorRGBA[4][2]; + + + private boolean selected[]; + + + private int selectedIndex = -1; + + + public MultiSelectionGizmo() { + super(); + + colors = new ColorRGBA[getCount()][2]; + geoms = new TriMesh[getCount()]; + selected = new boolean[getCount()]; + for (int i = 0; i < selected.length; i++) { + selected[i] = false; + } + } + + protected abstract int getCount(); + protected abstract int getIndexForName(String name); + + public int getSelected() { + return selectedIndex; + } + + private void updateColor(int index, int selected) { + + FloatBuffer buff = geoms[index].getColorBuffer(0); + for (int i = 0; i < geoms[index].getBatch(0).getVertexCount(); i++) { + BufferUtils.setInBuffer(colors[index][selected], buff, i); + } + } + + /* (non-Javadoc) + * @see fi.vtt.proconf.shapeeditor.common.Gizmo#changeSelected(java.lang.String) + */ + public void setSelected(String name) { + + if (name == null) { + for (int j = 0; j < getCount(); j++) { + if (selected[j]) { + selected[j] = false; + updateColor(j,UNSELECTED); + setChanged(true); + } + } + selectedIndex = -1; + return; + } + int index = getIndexForName(name); + if (index == -1) + return; + selectedIndex = index; + if (!selected[index]) { + selected[index] = true; + updateColor(index,SELECTED); + setChanged(true); + } + for (int j = 0; j < getCount(); j++) { + if (j != index) { + if (selected[j]) { + selected[j] = false; + updateColor(j,UNSELECTED); + setChanged(true); + } + } + } + } + + + protected void setGeometry(int index, TriMesh geom) { + geoms[index] = geom; + } + + protected void setColor(int index, int selected, Color4f color) { + colors[index][selected] = VecmathJmeTools.get(color); + } +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/gizmo/RotateGizmo.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/gizmo/RotateGizmo.java new file mode 100644 index 00000000..dcf18d52 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/gizmo/RotateGizmo.java @@ -0,0 +1,308 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.gizmo; + +import javax.vecmath.Color4f; +import javax.vecmath.Point3f; + +import com.jme.bounding.BoundingBox; +import com.jme.renderer.Renderer; +import com.jme.scene.TriMesh; +import com.jme.scene.state.AlphaState; +import com.jme.scene.state.MaterialState; +import com.jme.scene.state.ZBufferState; +import com.jme.util.geom.BufferUtils; + + + +public class RotateGizmo extends MultiSelectionGizmo { + + + public static String PICK_NAME = "rotate"; + public static String X_NAME = "rx"; + public static String Y_NAME = "ry"; + public static String Z_NAME = "rz"; + public static String XYZ_NAME = "ra"; + + public static final int X = 0; + public static final int Y = 1; + public static final int Z = 2; + public static final int XYZ = 3; + + + + + /* (non-Javadoc) + * @see fi.vtt.proconf.shapeeditor.common.Gizmo#getPickPrefix() + */ + public String getPickPrefix() { + return PICK_NAME; + } + + public int getIndexForName(String name) { + if (!name.startsWith(PICK_NAME)) { + return -1; + } + name = name.substring(PICK_NAME.length()); + if (name.startsWith(X_NAME)) + return X; + if (name.startsWith(Y_NAME)) + return Y; + if (name.startsWith(Z_NAME)) + return Z; + if (name.startsWith(XYZ_NAME)) + return XYZ; + return -1; + } + + + @Override + public int getCount() { + return 4; + } + + public RotateGizmo(Renderer renderer) { + super(); + float radius = 2.f; + float radius2 = 1.8f; + int div = 9; + + float x[] = new float[div+1]; + float y[] = new float[div+1]; + float x2[] = new float[div+1]; + float y2[] = new float[div+1]; + x[0] = radius; + y[0] = 0.f; + x[div] = 0.f; + y[div] = radius; + x2[0] = radius2; + y2[0] = 0.f; + x2[div] = 0.f; + y2[div] = radius2; + + for (int i = 1; i < div; i++) { + float angle = (float)i/(float)div; + angle *= Math.PI * 0.5f; + float c = (float)Math.cos(angle); + float s = (float)Math.sin(angle); + x[i] = radius * c; + y[i] = radius * s; + x2[i] = radius2 * c; + y2[i] = radius2 * s; + + } + + Color4f colorx = new Color4f(0.5f,0.f,0.f,0.5f); + Color4f colory = new Color4f(0.f,0.5f,0.f,0.5f); + Color4f colorz = new Color4f(0.f,0.f,0.5f,0.5f); + Color4f scolorx = new Color4f(1.f,0.f,0.f,0.7f); + Color4f scolory = new Color4f(0.f,1.f,0.f,0.7f); + Color4f scolorz = new Color4f(0.f,0.f,1.f,0.7f); + + + Color4f colorxyz = new Color4f(); + colorxyz.x = colorx.x + colory.x + colorz.x; + colorxyz.y = colorx.y + colory.y + colorz.y; + colorxyz.z = colorx.z +colory.z + colorz.z; + colorxyz.w = 0.5f; + + Color4f scolorxyz = new Color4f(); + scolorxyz.x = scolorx.x + scolory.x + scolorz.x; + scolorxyz.y = scolorx.y + scolory.y + scolorz.y; + scolorxyz.z = scolorx.z + scolory.z + scolorz.z; + scolorxyz.w = 0.5f; + + int numVertices = div*2; + float coordinates[] = new float[numVertices*3 + numVertices*3]; + float cols[] = new float[numVertices*4*2]; + int[] indices = new int[numVertices*3-6+numVertices*3 - 12]; + for (int i = 0; i < div; i++) { + if (i == 0) { + indices[0] = 0; + indices[1] = 1; + indices[2] = 2; + continue; + } + int vIndex = i * 2 - 1; + int index = i * 6 - 3; + if (i == div - 1) { + indices[index] = vIndex; + indices[index+1] = vIndex+1; + indices[index+2] = vIndex+2; + + } else { + indices[index] = vIndex; + indices[index+1] = vIndex+1; + indices[index+2] = vIndex+2; + indices[index+3] = vIndex+1; + indices[index+4] = vIndex+3; + indices[index+5] = vIndex+2; + } + } + + for (int i = div+1; i < div * 2 - 1; i++) { + int vIndex = i * 2 - 1; + int index = i * 6 - 12; + + indices[index] = vIndex; + indices[index+1] = vIndex+1; + indices[index+2] = vIndex+2; + indices[index+3] = vIndex+1; + indices[index+4] = vIndex+3; + indices[index+5] = vIndex+2; + } + + for (int i = 0; i < numVertices*2; i++) + setColor(cols,i, colorx); + + setCoordinate(coordinates,0, new Point3f(0.f, x[0], 0.f)); + for (int i = 1; i < div; i++) { + int index = i * 2 - 1; + setCoordinate(coordinates,index,new Point3f(0.f,x[i],y[i])); + setCoordinate(coordinates,index+1,new Point3f(y[1],x[i],y[i])); + } + setCoordinate(coordinates,numVertices - 1, new Point3f(0.f, 0.f, y[div])); + + setCoordinate(coordinates,numVertices, new Point3f(0.f, x2[0], 0.f)); + for (int i = 1; i < div; i++) { + int index = (div+i) * 2 - 1; + setCoordinate(coordinates,index,new Point3f(y[1],x[i],y[i])); + setCoordinate(coordinates,index+1,new Point3f(y2[1],x2[i],y2[i])); + } + setCoordinate(coordinates,numVertices*2 - 1, new Point3f(0.f, 0.f, y2[div])); + + TriMesh linex = new TriMesh(PICK_NAME+X_NAME,BufferUtils.createFloatBuffer(coordinates),null,BufferUtils.createFloatBuffer(cols),null,BufferUtils.createIntBuffer(indices)); + + + for (int i = 0; i < numVertices*2; i++) + setColor(cols,i, colory); + + setCoordinate(coordinates,0, new Point3f(x[0], 0.f, 0.f)); + for (int i = 1; i < div; i++) { + int index = i * 2 - 1; + setCoordinate(coordinates,index,new Point3f(x[i],0.f,y[i])); + setCoordinate(coordinates,index+1,new Point3f(x[i],y[1],y[i])); + } + setCoordinate(coordinates,numVertices - 1, new Point3f(0.f, 0.f, y[div])); + + setCoordinate(coordinates,numVertices, new Point3f(x2[0], 0.f, 0.f)); + for (int i = 1; i < div; i++) { + int index = (div+i) * 2 - 1; + setCoordinate(coordinates,index,new Point3f(x[i],y[1],y[i])); + setCoordinate(coordinates,index+1,new Point3f(x2[i],y2[1],y2[i])); + } + setCoordinate(coordinates,numVertices*2 - 1, new Point3f(0.f, 0.f, y2[div])); + + TriMesh liney = new TriMesh(PICK_NAME+Y_NAME,BufferUtils.createFloatBuffer(coordinates),null,BufferUtils.createFloatBuffer(cols),null,BufferUtils.createIntBuffer(indices)); + + + for (int i = 0; i < numVertices*2; i++) + setColor(cols,i, colorz); + + setCoordinate(coordinates,0, new Point3f(0.f, x[0], 0.f)); + for (int i = 1; i < div; i++) { + int index = i * 2 - 1; + setCoordinate(coordinates,index,new Point3f(y[i],x[i],0.f)); + setCoordinate(coordinates,index+1,new Point3f(y[i],x[i],y[1])); + } + setCoordinate(coordinates,numVertices - 1, new Point3f(y[div],0.f, 0.f)); + + setCoordinate(coordinates,numVertices, new Point3f(0.f, x2[0], 0.f)); + for (int i = 1; i < div; i++) { + int index = (div+i) * 2 - 1; + setCoordinate(coordinates,index,new Point3f(y[i],x[i],y[1])); + setCoordinate(coordinates,index+1,new Point3f(y2[i],x2[i],y2[1])); + } + setCoordinate(coordinates,numVertices*2 - 1, new Point3f(y2[div],0.f, 0.f)); + + TriMesh linez = new TriMesh(PICK_NAME+Z_NAME,BufferUtils.createFloatBuffer(coordinates),null,BufferUtils.createFloatBuffer(cols),null,BufferUtils.createIntBuffer(indices)); + + + numVertices = (div-2)*3+1; + coordinates = new float[numVertices*3]; + cols = new float[numVertices*4]; + indices = new int[(div-2)*3*3]; + + for (int i = 0; i < numVertices; i++) + setColor(cols,i, colorxyz); + float center = radius * 0.5f;//(float)Math.cos(Math.PI*0.25); + setCoordinate(coordinates,0,new Point3f(center,center,center)); + for (int i = 1; i < div; i++) { + int index = i; + setCoordinate(coordinates,index,new Point3f(y2[1],x2[i],y2[i])); + } + for (int i = 1; i < div; i++) { + int index = i + div-1 - 1; + setCoordinate(coordinates,index,new Point3f(y2[i],y2[1],x2[i])); + } + for (int i = 1; i < div-1; i++) { + int index = i + 2*(div-1) -2; + setCoordinate(coordinates,index,new Point3f(x2[i],y2[i],y2[1])); + } + for (int i = 0; i < (div-2)*3; i++) { + int index = i*3; + int iindex = i+1; + indices[index] = 0; + indices[index+1] = iindex; + indices[index+2] = iindex+1; + if (iindex == (numVertices -1)) + indices[index+2] = 1; + + } + + TriMesh trianglexyz = new TriMesh(PICK_NAME+XYZ_NAME,BufferUtils.createFloatBuffer(coordinates),null,BufferUtils.createFloatBuffer(cols),null,BufferUtils.createIntBuffer(indices)); + + + getGizmoNode().attachChild(linex); + getGizmoNode().attachChild(liney); + getGizmoNode().attachChild(linez); + getGizmoNode().attachChild(trianglexyz); + getGizmoNode().setModelBound(new BoundingBox()); + getGizmoNode().updateModelBound(); + + linex.getBatch(0).setCastsShadows(false); + liney.getBatch(0).setCastsShadows(false); + linez.getBatch(0).setCastsShadows(false); + trianglexyz.getBatch(0).setCastsShadows(false); + + setGeometry(0,linex); + setGeometry(1,liney); + setGeometry(2,linez); + setGeometry(3,trianglexyz); + + setColor(0,0,colorx); + setColor(0,1,scolorx); + setColor(1,0,colory); + setColor(1,1,scolory); + setColor(2,0,colorz); + setColor(2,1,scolorz); + setColor(3,0,colorxyz); + setColor(3,1,scolorxyz); + + AlphaState as = renderer.createAlphaState(); + as.setBlendEnabled(true); + as.setSrcFunction(AlphaState.DB_SRC_ALPHA); + as.setDstFunction(AlphaState.DB_ONE_MINUS_SRC_ALPHA); + as.setEnabled(true); + getGizmoNode().setRenderState(as); + MaterialState ms = renderer.createMaterialState(); + ms.setColorMaterial(MaterialState.CM_AMBIENT_AND_DIFFUSE); + ms.setMaterialFace(MaterialState.MF_FRONT_AND_BACK); + getGizmoNode().setRenderState(ms); + ZBufferState zs = renderer.createZBufferState(); + zs.setFunction(ZBufferState.CF_ALWAYS); + zs.setEnabled(true); + getGizmoNode().setRenderState(zs); + + + } + +} \ No newline at end of file diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/gizmo/TransformGizmo.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/gizmo/TransformGizmo.java new file mode 100644 index 00000000..b0e6df44 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/gizmo/TransformGizmo.java @@ -0,0 +1,316 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.gizmo; + +import javax.vecmath.Color4f; +import javax.vecmath.Point3f; + +import com.jme.bounding.BoundingBox; +import com.jme.renderer.Renderer; +import com.jme.scene.TriMesh; +import com.jme.scene.state.AlphaState; +import com.jme.scene.state.MaterialState; +import com.jme.scene.state.ZBufferState; +import com.jme.util.geom.BufferUtils; + + +public class TransformGizmo extends MultiSelectionGizmo { + + + public static String PICK_NAME = "translate"; + public static String X_NAME = "ax"; + public static String Y_NAME = "ay"; + public static String Z_NAME = "az"; + public static String XZ_NAME = "xz"; + public static String XY_NAME = "xy"; + public static String YZ_NAME = "yz"; + public static String XYZ_NAME = "aa"; + + public static final int X = 0; + public static final int Y = 1; + public static final int Z = 2; + public static final int XY = 3; + public static final int XZ = 4; + public static final int YZ = 5; + public static final int XYZ = 6; + + + + /* (non-Javadoc) + * @see fi.vtt.proconf.shapeeditor.common.Gizmo#getPickPrefix() + */ + public String getPickPrefix() { + return PICK_NAME; + } + + public int getIndexForName(String name) { + if (!name.startsWith(PICK_NAME)) { + return -1; + } + name = name.substring(PICK_NAME.length()); + if (name.startsWith(X_NAME)) + return X; + if (name.startsWith(Y_NAME)) + return Y; + if (name.startsWith(Z_NAME)) + return Z; + if (name.startsWith(XY_NAME)) + return XY; + if (name.startsWith(XZ_NAME)) + return XZ; + if (name.startsWith(YZ_NAME)) + return YZ; + if (name.startsWith(XYZ_NAME)) + return XYZ; + return -1; + } + + @Override + public int getCount() { + return 7; + } + + + /* + public TransformGizmo() { + */ + public TransformGizmo(Renderer renderer) { + super(); + float size = 2.f; + float sizeD2 = 1.f; + float offset = 0.2f; + + Color4f colorx = new Color4f(0.5f,0.f,0.f,0.5f); + Color4f colory = new Color4f(0.f,0.5f,0.f,0.5f); + Color4f colorz = new Color4f(0.f,0.f,0.5f,0.5f); + Color4f scolorx = new Color4f(1.f,0.f,0.f,0.7f); + Color4f scolory = new Color4f(0.f,1.f,0.f,0.7f); + Color4f scolorz = new Color4f(0.f,0.f,1.f,0.7f); + + Color4f colorxy = new Color4f(); + colorxy.x = colorx.x + colory.x; + colorxy.y = colorx.y + colory.y; + colorxy.z = colorx.z + colory.z; + colorxy.w = 0.5f; + + Color4f colorxz = new Color4f(); + colorxz.x = colorx.x + colorz.x; + colorxz.y = colorx.y + colorz.y; + colorxz.z = colorx.z + colorz.z; + colorxz.w = 0.5f; + + Color4f coloryz = new Color4f(); + coloryz.x = colory.x + colorz.x; + coloryz.y = colory.y + colorz.y; + coloryz.z = colory.z + colorz.z; + coloryz.w = 0.5f; + + Color4f colorxyz = new Color4f(); + colorxyz.x = colorx.x + colory.x + colorz.x; + colorxyz.y = colorx.y + colory.y + colorz.y; + colorxyz.z = colorx.z +colory.z + colorz.z; + colorxyz.w = 0.5f; + + Color4f scolorxy = new Color4f(); + scolorxy.x = scolory.x + scolorx.x; + scolorxy.y = scolory.y + scolorx.y; + scolorxy.z = scolory.z + scolorx.z; + scolorxy.w = 0.5f; + + Color4f scolorxz = new Color4f(); + scolorxz.x = scolorx.x + scolorz.x; + scolorxz.y = scolorx.y + scolorz.y; + scolorxz.z = scolorx.z + scolorz.z; + scolorxz.w = 0.5f; + + Color4f scoloryz = new Color4f(); + scoloryz.x = scolory.x + scolorz.x; + scoloryz.y = scolory.y + scolorz.y; + scoloryz.z = scolory.z + scolorz.z; + scoloryz.w = 0.5f; + + Color4f scolorxyz = new Color4f(); + scolorxyz.x = scolorx.x + scolory.x + scolorz.x; + scolorxyz.y = scolorx.y + scolory.y + scolorz.y; + scolorxyz.z = scolorx.z + scolory.z + scolorz.z; + scolorxyz.w = 0.5f; + + + float coordinates[] = new float[6*3]; + float cols[] = new float[6*4]; + int[] indices = new int[]{0,1,3, + 1,2,3, + 0,3,5, + 3,4,5}; + for (int i = 0; i < 6; i++) + setColor(cols,i, colorx); + + setCoordinate(coordinates,0, new Point3f(size, 0.f, 0.f)); + setCoordinate(coordinates,1, new Point3f(size - offset, offset, 0.f)); + setCoordinate(coordinates,2, new Point3f(sizeD2 - offset, offset, 0.f)); + setCoordinate(coordinates,3, new Point3f(sizeD2, 0.f, 0.f)); + setCoordinate(coordinates,4, new Point3f(sizeD2 - offset, 0.f, offset)); + setCoordinate(coordinates,5, new Point3f(size - offset, 0.f, offset)); + + TriMesh linex = new TriMesh("",BufferUtils.createFloatBuffer(coordinates),null,BufferUtils.createFloatBuffer(cols),null,BufferUtils.createIntBuffer(indices)); + + for (int i = 0; i < 6; i++) + setColor(cols,i, colory); + + setCoordinate(coordinates,0, new Point3f(0.f, size, 0.f)); + setCoordinate(coordinates,1, new Point3f(offset, size - offset, 0.f)); + setCoordinate(coordinates,2, new Point3f(offset, sizeD2 - offset, 0.f)); + setCoordinate(coordinates,3, new Point3f(0.f, sizeD2, 0.f)); + setCoordinate(coordinates,4, new Point3f(0.f, sizeD2 - offset, offset)); + setCoordinate(coordinates,5, new Point3f(0.f, size - offset, offset)); + + TriMesh liney = new TriMesh("",BufferUtils.createFloatBuffer(coordinates),null,BufferUtils.createFloatBuffer(cols),null,BufferUtils.createIntBuffer(indices)); + + for (int i = 0; i < 6; i++) + setColor(cols,i, colorz); + + setCoordinate(coordinates,0, new Point3f(0.f, 0.f,size)); + setCoordinate(coordinates,1, new Point3f(offset, 0.f, size - offset)); + setCoordinate(coordinates,2, new Point3f(offset, 0.f, sizeD2 - offset)); + setCoordinate(coordinates,3, new Point3f(0.f, 0.f, sizeD2)); + setCoordinate(coordinates,4, new Point3f(0.f, offset, sizeD2 - offset)); + setCoordinate(coordinates,5, new Point3f(0.f, offset, size - offset)); + + TriMesh linez = new TriMesh("",BufferUtils.createFloatBuffer(coordinates),null,BufferUtils.createFloatBuffer(cols),null,BufferUtils.createIntBuffer(indices)); + + // TODO : picking did not work properly without chancing indices; this must be investigated + indices = new int[]{2,1,3,0,1,3};//{0,1,3,1,2,3}; + coordinates = new float[4*3]; + cols = new float[4*4]; + + for (int i = 0; i < 4; i++) + setColor(cols,i, colorxz); + setCoordinate(coordinates,0, new Point3f(offset, 0.f, size-offset)); + setCoordinate(coordinates,1, new Point3f(offset, 0.f, sizeD2 - offset)); + setCoordinate(coordinates,2, new Point3f(sizeD2 - offset, 0.f, offset)); + setCoordinate(coordinates,3, new Point3f(size-offset, 0.f, offset)); + + TriMesh trianglexz = new TriMesh("",BufferUtils.createFloatBuffer(coordinates),null,BufferUtils.createFloatBuffer(cols),null,BufferUtils.createIntBuffer(indices)); + + for (int i = 0; i < 4; i++) + setColor(cols,i, colorxy); + setCoordinate(coordinates,0, new Point3f(offset, size-offset, 0.f)); + setCoordinate(coordinates,1, new Point3f(offset, sizeD2 - offset, 0.f)); + setCoordinate(coordinates,2, new Point3f(sizeD2 - offset, offset, 0.f)); + setCoordinate(coordinates,3, new Point3f(size-offset, offset, 0.f)); + + TriMesh trianglexy = new TriMesh("",BufferUtils.createFloatBuffer(coordinates),null,BufferUtils.createFloatBuffer(cols),null,BufferUtils.createIntBuffer(indices)); + + for (int i = 0; i < 4; i++) + setColor(cols,i, coloryz); + setCoordinate(coordinates,0, new Point3f( 0.f,offset, size-offset)); + setCoordinate(coordinates,1, new Point3f( 0.f,offset, sizeD2 - offset)); + setCoordinate(coordinates,2, new Point3f( 0.f,sizeD2 - offset, offset)); + setCoordinate(coordinates,3, new Point3f( 0.f,size-offset, offset)); + + TriMesh triangleyz = new TriMesh("",BufferUtils.createFloatBuffer(coordinates),null,BufferUtils.createFloatBuffer(cols),null,BufferUtils.createIntBuffer(indices)); + + indices = new int[]{0,1,2, + 0,2,3, + 0,3,4, + 0,4,5, + 0,5,6, + 0,6,7, + 0,7,8, + 0,8,9, + 0,9,1}; + coordinates = new float[10*3]; + cols = new float[10*4]; + + for (int i = 0; i < 10; i++) + setColor(cols,i, colorxyz); + setCoordinate(coordinates,0, new Point3f(0.f, 0.f, 0.f)); + setCoordinate(coordinates,1, new Point3f(sizeD2, 0.f, 0.f)); + setCoordinate(coordinates,2, new Point3f(sizeD2 - offset, offset, 0.f)); + setCoordinate(coordinates,3, new Point3f(offset, sizeD2 - offset, 0.f)); + setCoordinate(coordinates,4, new Point3f(0.f, sizeD2, 0.f)); + setCoordinate(coordinates,5, new Point3f(0.f, sizeD2 - offset, offset)); + setCoordinate(coordinates,6, new Point3f(0.f, offset, sizeD2-offset)); + setCoordinate(coordinates,7, new Point3f(0.f, 0.f, sizeD2)); + setCoordinate(coordinates,8, new Point3f(offset, 0.f, sizeD2-offset)); + setCoordinate(coordinates,9, new Point3f(sizeD2-offset, 0.f, offset)); + + TriMesh trianglexyz = new TriMesh("",BufferUtils.createFloatBuffer(coordinates),null,BufferUtils.createFloatBuffer(cols),null,BufferUtils.createIntBuffer(indices)); + + linex.setName(PICK_NAME+X_NAME); + liney.setName(PICK_NAME+Y_NAME); + linez.setName(PICK_NAME+Z_NAME); + trianglexy.setName(PICK_NAME+XY_NAME); + trianglexz.setName(PICK_NAME+XZ_NAME); + triangleyz.setName(PICK_NAME+YZ_NAME); + trianglexyz.setName(PICK_NAME+XYZ_NAME); + + linex.getBatch(0).setCastsShadows(false); + liney.getBatch(0).setCastsShadows(false); + linez.getBatch(0).setCastsShadows(false); + trianglexy.getBatch(0).setCastsShadows(false); + trianglexz.getBatch(0).setCastsShadows(false); + triangleyz.getBatch(0).setCastsShadows(false); + trianglexyz.getBatch(0).setCastsShadows(false); + + getGizmoNode().attachChild(linex); + getGizmoNode().attachChild(liney); + getGizmoNode().attachChild(linez); + getGizmoNode().attachChild(trianglexy); + getGizmoNode().attachChild(trianglexz); + getGizmoNode().attachChild(triangleyz); + getGizmoNode().attachChild(trianglexyz); + getGizmoNode().setModelBound(new BoundingBox()); + getGizmoNode().updateModelBound(); + + setGeometry(0,linex); + setGeometry(1,liney); + setGeometry(2,linez); + setGeometry(3,trianglexy); + setGeometry(4,trianglexz); + setGeometry(5,triangleyz); + setGeometry(6,trianglexyz); + + + setColor(0,0,colorx); + setColor(0,1,scolorx); + setColor(1,0,colory); + setColor(1,1,scolory); + setColor(2,0,colorz); + setColor(2,1,scolorz); + setColor(3,0,colorxy); + setColor(3,1,scolorxy); + setColor(4,0,colorxz); + setColor(4,1,scolorxz); + setColor(5,0,coloryz); + setColor(5,1,scoloryz); + setColor(6,0,colorxyz); + setColor(6,1,scolorxyz); + + + AlphaState as = renderer.createAlphaState(); + as.setBlendEnabled(true); + as.setSrcFunction(AlphaState.DB_SRC_ALPHA); + as.setDstFunction(AlphaState.DB_ONE_MINUS_SRC_ALPHA); + as.setEnabled(true); + getGizmoNode().setRenderState(as); + MaterialState ms = renderer.createMaterialState(); + ms.setColorMaterial(MaterialState.CM_AMBIENT_AND_DIFFUSE); + ms.setMaterialFace(MaterialState.MF_FRONT_AND_BACK); + getGizmoNode().setRenderState(ms); + ZBufferState zs = renderer.createZBufferState(); + zs.setFunction(ZBufferState.CF_ALWAYS); + zs.setEnabled(true); + zs.setWritable(false); + getGizmoNode().setRenderState(zs); + } + +} \ No newline at end of file diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/gizmo/TransformInlineGizmo.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/gizmo/TransformInlineGizmo.java new file mode 100644 index 00000000..23ba6e00 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/gizmo/TransformInlineGizmo.java @@ -0,0 +1,215 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.gizmo; + +import java.nio.FloatBuffer; + +import javax.vecmath.Color4f; +import javax.vecmath.Point3f; +import javax.vecmath.Vector3f; + +import org.simantics.proconf.g3d.base.VecmathJmeTools; + +import com.jme.bounding.BoundingBox; +import com.jme.renderer.ColorRGBA; +import com.jme.renderer.Renderer; +import com.jme.scene.TriMesh; +import com.jme.scene.state.AlphaState; +import com.jme.scene.state.MaterialState; +import com.jme.scene.state.ZBufferState; +import com.jme.util.geom.BufferUtils; + + +public class TransformInlineGizmo extends AbstractGizmo { + + TriMesh geom = new TriMesh(); + ColorRGBA colors[] = new ColorRGBA[2]; + + + public static String PICK_NAME = "translate"; + public static String X_NAME = "ax"; + + public static final int X = 0; + + public static final int SELECTED = 1; + public static final int UNSELECTED = 0; + + private boolean selected = false; + + + /* (non-Javadoc) + * @see fi.vtt.proconf.shapeeditor.common.Gizmo#getPickPrefix() + */ + public String getPickPrefix() { + return PICK_NAME; + } + + public int getIndexForName(String name) { + if (!name.startsWith(PICK_NAME)) { + return -1; + } + name = name.substring(PICK_NAME.length()); + if (name.startsWith(X_NAME)) + return X; + return -1; + } + + private void updateColor(int sel) { + FloatBuffer buff = geom.getColorBuffer(0); + for (int i = 0; i < geom.getBatch(0).getVertexCount(); i++) { + BufferUtils.setInBuffer(colors[sel], buff, i); + } + } + + /* (non-Javadoc) + * @see fi.vtt.proconf.shapeeditor.common.Gizmo#changeSelected(java.lang.String) + */ + public void setSelected(String name) { + + if (name == null) { + setChanged(true); + updateColor(UNSELECTED); + selected = false; + return; + } + int index = getIndexForName(name); + if (index == -1) { + selected = false; + return; + } + + selected = true; + updateColor(SELECTED); + setChanged(true); + + } + + @Override + public void setScale(Vector3f scale) { + /** + * A bug in JME (?) + * Negative scaling breaks picking (ray hits the bounding box, but ray doesn't intersect any triangles) + */ + scale.x = Math.abs(scale.x); + scale.y = Math.abs(scale.y); + scale.z = Math.abs(scale.z); + + super.setScale(scale); + } + + + /* + public TransformInlineGizmo(){ + */ + public TransformInlineGizmo(Renderer renderer) { + super(); + float size = 2.f; + float sizeD2 = 1.f; + float offset = 0.07f; + + Color4f colorx = new Color4f(0.5f,0.f,0.f,0.5f); + Color4f scolorx = new Color4f(1.f,0.f,0.f,0.7f); + + + float coordinates[] = new float[18*3]; + float cols[] = new float[18*4]; + int[] indices = new int[]{0,2,1, + 0,3,2, + 0,4,3, + 0,1,4, + 1,2,6, + 1,6,5, + 2,3,7, + 2,7,6, + 3,4,8, + 3,8,7, + 4,1,5, + 4,5,8, + 5,6,7, + 5,7,8, + + 9,11,10, + 9,12,11, + 9,13,12, + 9,10,13, + 10,11,15, + 10,15,14, + 11,12,16, + 11,16,15, + 12,13,17, + 12,17,16, + 13,10,14, + 13,14,17, + 14,15,16, + 14,16,17 + + }; + for (int i = 0; i < 18; i++) + setColor(cols,i, colorx); + + setCoordinate(coordinates,0, new Point3f(size, 0.f, 0.f)); + setCoordinate(coordinates,1, new Point3f(size - offset*2, offset, offset)); + setCoordinate(coordinates,2, new Point3f(size - offset*2, offset, -offset)); + setCoordinate(coordinates,3, new Point3f(size - offset*2, -offset, -offset)); + setCoordinate(coordinates,4, new Point3f(size - offset*2, -offset, offset)); + setCoordinate(coordinates,5, new Point3f(sizeD2, offset, offset)); + setCoordinate(coordinates,6, new Point3f(sizeD2, offset, -offset)); + setCoordinate(coordinates,7, new Point3f(sizeD2, -offset, -offset)); + setCoordinate(coordinates,8, new Point3f(sizeD2, -offset, offset)); + + setCoordinate(coordinates,9, new Point3f(-size, 0.f, 0.f)); + setCoordinate(coordinates,10, new Point3f(-size + offset*2, offset, offset)); + setCoordinate(coordinates,11, new Point3f(-size + offset*2, offset, -offset)); + setCoordinate(coordinates,12, new Point3f(-size + offset*2, -offset, -offset)); + setCoordinate(coordinates,13, new Point3f(-size + offset*2, -offset, offset)); + setCoordinate(coordinates,14, new Point3f(-sizeD2, offset, offset)); + setCoordinate(coordinates,15, new Point3f(-sizeD2, offset, -offset)); + setCoordinate(coordinates,16, new Point3f(-sizeD2, -offset, -offset)); + setCoordinate(coordinates,17, new Point3f(-sizeD2, -offset, offset)); + + TriMesh linex = new TriMesh(PICK_NAME+X_NAME,BufferUtils.createFloatBuffer(coordinates),null,BufferUtils.createFloatBuffer(cols),null,BufferUtils.createIntBuffer(indices)); + + getGizmoNode().attachChild(linex); + getGizmoNode().setModelBound(new BoundingBox()); + getGizmoNode().updateModelBound(); + + geom = linex; + geom.getBatch(0).setCastsShadows(false); + + colors[0] = VecmathJmeTools.get(colorx); + colors[1] = VecmathJmeTools.get(scolorx); + + AlphaState as = renderer.createAlphaState(); + as.setBlendEnabled(true); + as.setSrcFunction(AlphaState.DB_SRC_ALPHA); + as.setDstFunction(AlphaState.DB_ONE_MINUS_SRC_ALPHA); + as.setEnabled(true); + getGizmoNode().setRenderState(as); + MaterialState ms = renderer.createMaterialState(); + ms.setColorMaterial(MaterialState.CM_AMBIENT_AND_DIFFUSE); + ms.setMaterialFace(MaterialState.MF_FRONT_AND_BACK); + getGizmoNode().setRenderState(ms); + ZBufferState zs = renderer.createZBufferState(); + zs.setFunction(ZBufferState.CF_ALWAYS); + zs.setEnabled(true); + getGizmoNode().setRenderState(zs); + + } + + + public boolean isSelected() { + return selected; + } + + public void setSelected(boolean selected) { + this.selected = selected; + } +} \ No newline at end of file diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/input/AWTInputProvider.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/input/AWTInputProvider.java new file mode 100644 index 00000000..ec152390 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/input/AWTInputProvider.java @@ -0,0 +1,309 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.input; + +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; + +public class AWTInputProvider implements KeyListener, MouseListener, MouseMotionListener , InputProvider{ + + private boolean keyPressed[] = new boolean[1024]; + private boolean keyTemp[] = new boolean[1024]; + private boolean keyDown[] = new boolean[1024]; + private boolean keyUp[] = new boolean[1024]; + + private int awtMouseX = 0; + private int awtMouseY = 0; + private boolean awtPressed = false; + private boolean awtDragged = false; + private boolean awtReleased = false; + private boolean awtMouseClicked = false; + private boolean awtMouseMoved = false; + + private int awtPressModifiers = 0; + private int awtDragModifiers = 0; + private int awtClickModifiers = 0; + private int awtMoveModifiers = 0; + private int awtClickButton = 0; + + private int mouseX = 0; + private int mouseY = 0; + + private int prevMouseX = 0; + private int prevMouseY = 0; + + private boolean mousePressed = false; + private boolean mouseDragged = false; + private boolean mouseReleased = false; + private boolean mouseClicked = false; + private boolean mouseMoved = false; + + private int pressModifiers = 0; + private int clickModifiers = 0; + private int dragModifiers = 0; + private int clickButton = 0; + private int moveModifiers = 0; + + public AWTInputProvider() { + for (int i = 0; i < keyDown.length; i++) { + keyDown[i] = false; + keyTemp[i] = false; + keyPressed[i] = false; + keyUp[i] = false; + } + } + + public boolean keyPressed(int i) { + return keyPressed[i]; + } + + public boolean keyDown(int i) { + return keyDown[i]; + } + + public boolean keyUp(int i) { + return keyUp[i]; + } + + public int mouseX() { + return mouseX; + } + + public int mouseY() { + return mouseY; + } + + public int prevMouseX() { + return prevMouseX; + } + + public int prevMouseY() { + return prevMouseY; + } + + public boolean mousePressed() { + return mousePressed; + } + + public boolean mouseMoved() { + return mouseMoved; + } + + public boolean mouseReleased() { + return mouseReleased; + } + + public boolean mouseClicked() { + return mouseClicked; + } + + public boolean mouseDragged() { + return mouseDragged; + } + + public int pressModifiers() { + return pressModifiers; + } + + public int clickModifiers() { + return clickModifiers; + } + + public int dragModifiers() { + return dragModifiers; + } + + public int moveModifiers() { + return moveModifiers; + } + + public int clickButton() { + return clickButton; + } + + + public void update() { + prevMouseX = mouseX; + prevMouseY = mouseY; + mouseX = awtMouseX; + mouseY = awtMouseY; + //System.out.println(mouseX + " " + mouseY); + mousePressed = awtPressed; + awtPressed = false; + mouseReleased = awtReleased; + awtReleased = false; + mouseMoved = awtMouseMoved; + awtMouseMoved = false; + mouseDragged = awtDragged; + awtDragged = false; + mouseClicked = awtMouseClicked; + awtMouseClicked = false; + pressModifiers = awtPressModifiers; + // awtPressModifiers = 0; + clickModifiers = awtClickModifiers; + //awtClickModifiers = 0; + dragModifiers = awtDragModifiers; + // awtDragModifiers = 0; + moveModifiers = awtMoveModifiers; + //awtMoveModifiers = 0; + clickButton = awtClickButton; + awtClickButton = 0; + for (int i = 0; i < keyDown.length; i++) { + if (keyDown[i] && !keyTemp[i]) { + keyTemp[i] = true; + keyPressed[i] = true; + } + else if (keyDown[i] && keyTemp[i]) { + keyPressed[i] = false; + } + else if (!keyDown[i] && keyTemp[i]) { + keyUp[i] = true; + keyTemp[i] = false; + keyPressed[i] = false; + } + else if (!keyDown[i]) { + keyTemp[i] = false; + keyPressed[i] = false; + keyUp[i] = false; + } + } + + } + + /* (non-Javadoc) + * @see java.awt.event.MouseMotionListener#mouseDragged(java.awt.event.MouseEvent) + */ + public void mouseDragged(MouseEvent e) { + awtMouseX = e.getX(); + awtMouseY = e.getY(); + awtDragged = true; + awtDragModifiers = e.getModifiers() | e.getButton(); + } + + /* (non-Javadoc) + * @see java.awt.event.MouseListener#mouseReleased(java.awt.event.MouseEvent) + */ + public void mouseReleased(MouseEvent e) { + awtReleased = true; + //ms.set(msTmp); + + } + + /* + * (non-Javadoc) + * + * @see java.awt.event.MouseListener#mouseClicked(java.awt.event.MouseEvent) + */ + public void mouseClicked(MouseEvent e) { + + awtMouseX = e.getX(); + awtMouseY = e.getY(); + e.getButton(); + + awtClickModifiers = e.getModifiersEx(); + awtClickButton = e.getButton(); + awtMouseClicked = true; + + } + + /* + * (non-Javadoc) + * + * @see java.awt.event.MouseListener#mouseEntered(java.awt.event.MouseEvent) + */ + public void mouseEntered(MouseEvent arg0) { + + } + + /* + * (non-Javadoc) + * + * @see java.awt.event.MouseListener#mouseExited(java.awt.event.MouseEvent) + */ + public void mouseExited(MouseEvent arg0) { + + } + + /* + * (non-Javadoc) + * + * @see java.awt.event.MouseMotionListener#mouseMoved(java.awt.event.MouseEvent) + */ + public void mouseMoved(MouseEvent arg0) { + + awtMouseMoved = true; + awtMouseX = arg0.getX(); + awtMouseY = arg0.getY(); + awtMoveModifiers = arg0.getModifiersEx(); + + } + + /* (non-Javadoc) + * @see java.awt.event.KeyListener#keyPressed(java.awt.event.KeyEvent) + */ + public void keyPressed(KeyEvent arg0) { + keyDown[arg0.getKeyCode()] = true; + } + + /* (non-Javadoc) + * @see java.awt.event.KeyListener#keyReleased(java.awt.event.KeyEvent) + */ + public void keyReleased(KeyEvent arg0) { + keyDown[arg0.getKeyCode()] = false; + } + + + /* (non-Javadoc) + * @see java.awt.event.KeyListener#keyTyped(java.awt.event.KeyEvent) + */ + public void keyTyped(KeyEvent e) { + + } + + /* (non-Javadoc) + * @see java.awt.event.MouseListener#mousePressed(java.awt.event.MouseEvent) + */ + public void mousePressed(MouseEvent e) { + awtMouseX = e.getX(); + awtMouseY = e.getY(); + awtPressed = true; + awtPressModifiers = e.getModifiers() | e.getButton(); + } + + public void setMouseMoved(boolean b) { + + } + + public void setMouseX(int x) { + + } + + public void setMouseY(int y) { + + } + + public String toString() { + String s = ""; + s += "(" + mouseX + "," + mouseY + ")\n"; + s += "Pressed " + mousePressed + "\n"; + s += "Released " + mouseReleased + "\n"; + s += "Moved " + mouseMoved + "\n"; + s += "Dragged " + mouseDragged + "\n"; + s += "Clicked " + mouseClicked + "\n"; + s += "DragModifiers " + dragModifiers + "\n"; + s += "ClickModifiers " + clickModifiers + "\n"; + s += "PressModifiers " + pressModifiers + "\n"; + return s; + } +} \ No newline at end of file diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/input/InputProvider.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/input/InputProvider.java new file mode 100644 index 00000000..1f1f56bd --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/input/InputProvider.java @@ -0,0 +1,72 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.input; + + +/** + * InputProvider is used to listen inputs from AWT-thread, + * and then input actions can be polled from the provider. + * + * TODO : use methods instead of public members + * + * @author Marko Luukkainen + * + */ +public interface InputProvider { + + + + public boolean keyPressed(int i); + + public boolean keyDown(int i); + + public boolean keyUp(int i); + + public int mouseX(); + + public int mouseY(); + + public int prevMouseX(); + + public int prevMouseY(); + + public boolean mousePressed(); + + public boolean mouseMoved(); + + public boolean mouseReleased(); + + public boolean mouseClicked(); + + public boolean mouseDragged(); + + public int pressModifiers(); + + public int clickModifiers(); + + public int dragModifiers(); + + public int moveModifiers(); + + public int clickButton(); + + + public void update(); + + // FIXME : when dnd is used, mouse inputs won't get passed + + public void setMouseX(int x); + public void setMouseY(int y); + public void setMouseMoved(boolean b); + + + +} \ No newline at end of file diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/input/SWTInputProvider.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/input/SWTInputProvider.java new file mode 100644 index 00000000..a21d3b79 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/input/SWTInputProvider.java @@ -0,0 +1,511 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.input; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.FocusEvent; +import org.eclipse.swt.events.FocusListener; +import org.eclipse.swt.events.KeyEvent; +import org.eclipse.swt.events.KeyListener; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseListener; +import org.eclipse.swt.events.MouseMoveListener; +import org.eclipse.swt.events.MouseTrackListener; + +public class SWTInputProvider implements KeyListener, MouseListener, MouseMoveListener, MouseTrackListener, InputProvider, FocusListener { + + private static final int PRESS_TIME = 200; + + private boolean keyPressed[] = new boolean[1024]; + private boolean keyTemp[] = new boolean[1024]; + private boolean keyDown[] = new boolean[1024]; + private boolean keyUp[] = new boolean[1024]; + + private int awtMouseX = 0; + private int awtMouseY = 0; + private boolean awtPressed = false; + private boolean awtDragged = false; + private boolean awtReleased = false; + private boolean awtMouseClicked = false; + private boolean awtMouseMoved = false; + + private boolean swtMouse1Down = false; + private boolean swtMouse2Down = false; + private boolean swtMouse3Down = false; + + long mouse1DownTime = 0; + long mouse2DownTime = 0; + long mouse3DownTime = 0; + + private int awtPressModifiers = 0; + private int awtDragModifiers = 0; + private int awtClickModifiers = 0; + private int awtMoveModifiers = 0; + private int awtClickButton = 0; + + private int mouseX = 0; + private int mouseY = 0; + + private int prevMouseX = 0; + private int prevMouseY = 0; + + private boolean mousePressed = false; + private boolean mouseDragged = false; + private boolean mouseReleased = false; + private boolean mouseClicked = false; + private boolean mouseMoved = false; + + private int pressModifiers = 0; + private int clickModifiers = 0; + private int dragModifiers = 0; + private int clickButton = 0; + private int moveModifiers = 0; + + public SWTInputProvider() { + reset(); + } + + private void reset() { + for (int i = 0; i < keyDown.length; i++) { + keyDown[i] = false; + keyTemp[i] = false; + keyPressed[i] = false; + keyUp[i] = false; + } + mousePressed = false; + mouseDragged = false; + mouseReleased = false; + mouseClicked = false; + mouseMoved = false; + + pressModifiers = 0; + clickModifiers = 0; + dragModifiers = 0; + clickButton = 0; + moveModifiers = 0; + } + + public boolean keyPressed(int i) { + return keyPressed[i]; + } + + public boolean keyDown(int i) { + return keyDown[i]; + } + + public boolean keyUp(int i) { + return keyUp[i]; + } + + public int mouseX() { + return mouseX; + } + + public int mouseY() { + return mouseY; + } + + public int prevMouseX() { + return prevMouseX; + } + + public int prevMouseY() { + return prevMouseY; + } + + public boolean mousePressed() { + return mousePressed; + } + + public boolean mouseMoved() { + return mouseMoved; + } + + public boolean mouseReleased() { + return mouseReleased; + } + + public boolean mouseClicked() { + return mouseClicked; + } + + public boolean mouseDragged() { + return mouseDragged; + } + + public int pressModifiers() { + return pressModifiers; + } + + public int clickModifiers() { + return clickModifiers; + } + + public int dragModifiers() { + return dragModifiers; + } + + public int moveModifiers() { + return moveModifiers; + } + + public int clickButton() { + return clickButton; + } + + + public void update() { + prevMouseX = mouseX; + prevMouseY = mouseY; + mouseX = awtMouseX; + mouseY = awtMouseY; + //System.out.println(mouseX + " " + mouseY); + mousePressed = awtPressed; + awtPressed = false; + mouseReleased = awtReleased; + awtReleased = false; + mouseMoved = awtMouseMoved; + awtMouseMoved = false; + mouseDragged = awtDragged; + awtDragged = false; + mouseClicked = awtMouseClicked; + awtMouseClicked = false; + pressModifiers = awtPressModifiers; + // awtPressModifiers = 0; + clickModifiers = awtClickModifiers; + //awtClickModifiers = 0; + dragModifiers = awtDragModifiers; + // awtDragModifiers = 0; + moveModifiers = awtMoveModifiers; + //awtMoveModifiers = 0; + clickButton = awtClickButton; + awtClickButton = 0; + for (int i = 0; i < keyDown.length; i++) { + if (keyDown[i] && !keyTemp[i]) { + keyTemp[i] = true; + keyPressed[i] = true; + } + else if (keyDown[i] && keyTemp[i]) { + keyPressed[i] = false; + } + else if (!keyDown[i] && keyTemp[i]) { + keyUp[i] = true; + keyTemp[i] = false; + keyPressed[i] = false; + } + else if (!keyDown[i]) { + keyTemp[i] = false; + keyPressed[i] = false; + keyUp[i] = false; + } + } + + } + + + + + private int getAWTKeyCode(int swtKeyCode) { + if(swtKeyCode > keyDown.length) { + int keyCode = 0; + switch (swtKeyCode) { + case SWT.CTRL: + keyCode = java.awt.event.KeyEvent.VK_CONTROL; + break; + case SWT.ALT: + keyCode = java.awt.event.KeyEvent.VK_ALT; + break; + + case SWT.SHIFT: + keyCode = java.awt.event.KeyEvent.VK_SHIFT; + break; + case SWT.ARROW_LEFT: + keyCode = java.awt.event.KeyEvent.VK_LEFT; + break; + case SWT.ARROW_RIGHT: + keyCode = java.awt.event.KeyEvent.VK_RIGHT; + break; + case SWT.ARROW_UP: + keyCode = java.awt.event.KeyEvent.VK_UP; + break; + case SWT.ARROW_DOWN: + keyCode = java.awt.event.KeyEvent.VK_DOWN; + break; + case SWT.KEYPAD_0: + keyCode = java.awt.event.KeyEvent.VK_NUMPAD0; + break; + case SWT.KEYPAD_1: + keyCode = java.awt.event.KeyEvent.VK_NUMPAD1; + break; + case SWT.KEYPAD_2: + keyCode = java.awt.event.KeyEvent.VK_NUMPAD2; + break; + case SWT.KEYPAD_3: + keyCode = java.awt.event.KeyEvent.VK_NUMPAD3; + break; + case SWT.KEYPAD_4: + keyCode = java.awt.event.KeyEvent.VK_NUMPAD4; + break; + case SWT.KEYPAD_5: + keyCode = java.awt.event.KeyEvent.VK_NUMPAD5; + break; + case SWT.KEYPAD_6: + keyCode = java.awt.event.KeyEvent.VK_NUMPAD6; + break; + case SWT.KEYPAD_7: + keyCode = java.awt.event.KeyEvent.VK_NUMPAD7; + break; + case SWT.KEYPAD_8: + keyCode = java.awt.event.KeyEvent.VK_NUMPAD8; + break; + case SWT.KEYPAD_9: + keyCode = java.awt.event.KeyEvent.VK_NUMPAD9; + break; + case SWT.KEYPAD_CR: + keyCode = java.awt.event.KeyEvent.VK_ENTER; + break; + case SWT.NUM_LOCK: + keyCode = java.awt.event.KeyEvent.VK_NUM_LOCK; + break; + case SWT.SCROLL_LOCK: + keyCode = java.awt.event.KeyEvent.VK_SCROLL_LOCK; + break; + case SWT.CAPS_LOCK: + keyCode = java.awt.event.KeyEvent.VK_CAPS_LOCK; + break; + case SWT.INSERT: + keyCode = java.awt.event.KeyEvent.VK_INSERT; + break; + case SWT.HOME: + keyCode = java.awt.event.KeyEvent.VK_HOME; + break; + case SWT.END: + keyCode = java.awt.event.KeyEvent.VK_END; + break; + case SWT.PAGE_UP: + keyCode = java.awt.event.KeyEvent.VK_PAGE_UP; + break; + case SWT.PAGE_DOWN: + keyCode = java.awt.event.KeyEvent.VK_PAGE_DOWN; + break; + case SWT.PAUSE: + keyCode = java.awt.event.KeyEvent.VK_PAUSE; + break; + case SWT.BREAK: + keyCode = java.awt.event.KeyEvent.VK_PAUSE; + break; + case SWT.PRINT_SCREEN: + keyCode = java.awt.event.KeyEvent.VK_PRINTSCREEN; + break; + case SWT.HELP: + keyCode = java.awt.event.KeyEvent.VK_HELP; + break; + default : + keyCode = 0; + break; + } + + return keyCode; + } else if (swtKeyCode == 8) { + return java.awt.event.KeyEvent.VK_BACK_SPACE; + } + else if (swtKeyCode >= 97 ) + return swtKeyCode - 32; + else + return swtKeyCode; + } + + + /* (non-Javadoc) + * @see java.awt.event.KeyListener#keyPressed(java.awt.event.KeyEvent) + */ + public void keyPressed(KeyEvent arg0) { + //System.out.println("KeyPressed " + arg0.character + " " + arg0.keyCode + " " + getAWTKeyCode(arg0.keyCode)); + keyDown[getAWTKeyCode(arg0.keyCode)] = true; + } + + /* (non-Javadoc) + * @see java.awt.event.KeyListener#keyReleased(java.awt.event.KeyEvent) + */ + public void keyReleased(KeyEvent arg0) { + //System.out.println("KeyReleased " + arg0.character + " " + arg0.keyCode + " " + getAWTKeyCode(arg0.keyCode)); + + keyDown[getAWTKeyCode(arg0.keyCode)] = false; + } + + public void mouseMove(MouseEvent e) { + awtMouseX = e.x; + awtMouseY = e.y; + if (swtMouse1Down || swtMouse2Down || swtMouse3Down) { + // comparing times so that drag event won't be send at the time when mouse button was pressed + long time = e.time & 0xFFFFFFFFL; + boolean drag = false; + if (swtMouse1Down) { + drag = time > mouse1DownTime; + } else if (swtMouse2Down) { + drag = time > mouse2DownTime; + } else { + drag = time > mouse3DownTime; + } + if (drag) { + awtDragged = true; + awtDragModifiers = createButtonMask(e); + } + } else { + awtMoveModifiers = createButtonMask(e); + awtMouseMoved = true; + } + } + + public void mouseDoubleClick(MouseEvent e) { + /* + awtMouseClicked = true; + awtClickModifiers = createButtonMask(e); + switch (e.button) { + case 1: + awtClickButton = java.awt.event.MouseEvent.BUTTON1; + break; + case 2: + awtClickButton = java.awt.event.MouseEvent.BUTTON2; + break; + case 3: + awtClickButton = java.awt.event.MouseEvent.BUTTON3; + break; + + } + */ + } + + private int createButtonMask(MouseEvent e) { + int mask = 0; + if (swtMouse1Down) + mask |= java.awt.event.MouseEvent.BUTTON1_DOWN_MASK | java.awt.event.MouseEvent.BUTTON1_MASK; + if (swtMouse2Down) + mask |= java.awt.event.MouseEvent.BUTTON2_DOWN_MASK | java.awt.event.MouseEvent.BUTTON2_MASK; + if (swtMouse3Down) + mask |= java.awt.event.MouseEvent.BUTTON3_DOWN_MASK | java.awt.event.MouseEvent.BUTTON3_MASK; + if ((e.stateMask & SWT.CTRL) > 0) + mask |= java.awt.event.MouseEvent.CTRL_DOWN_MASK | java.awt.event.MouseEvent.CTRL_MASK; + if ((e.stateMask & SWT.CTRL) > 0) + mask |= java.awt.event.MouseEvent.ALT_DOWN_MASK | java.awt.event.MouseEvent.ALT_MASK; + + + return mask; + } + + public void mouseDown(MouseEvent e) { + switch (e.button) { + case 1: + swtMouse1Down = true; + mouse1DownTime = e.time & 0xFFFFFFFFL; + break; + case 2: + swtMouse2Down = true; + mouse2DownTime = e.time & 0xFFFFFFFFL; + break; + case 3: + swtMouse3Down = true; + mouse3DownTime = e.time & 0xFFFFFFFFL; + }; + + awtPressed = true; + awtPressModifiers = createButtonMask(e); + } + + public void mouseUp(MouseEvent e) { + long mouseUpTime = e.time & 0xFFFFFFFFL; + long delta = 1000; + switch (e.button) { + case 1: + swtMouse1Down = false; + delta = mouseUpTime - mouse1DownTime; + break; + case 2: + swtMouse2Down = false; + delta = mouseUpTime - mouse2DownTime; + break; + case 3: + swtMouse3Down = false; + delta = mouseUpTime - mouse3DownTime; + }; + awtReleased = true; + + if (delta < PRESS_TIME) { + awtMouseClicked = true; + awtClickModifiers = createButtonMask(e); + switch (e.button) { + case 1: + awtClickButton = java.awt.event.MouseEvent.BUTTON1; + break; + case 2: + awtClickButton = java.awt.event.MouseEvent.BUTTON2; + break; + case 3: + awtClickButton = java.awt.event.MouseEvent.BUTTON3; + break; + + } + } + } + + + public void mouseEnter(MouseEvent e) { + + } + + public void mouseExit(MouseEvent e) { + awtReleased = false; + awtPressed = false; + swtMouse1Down = false; + swtMouse2Down = false; + swtMouse3Down = false; + + + } + + public void focusGained(FocusEvent e) { + + } + + public void focusLost(FocusEvent e) { + reset(); + } + + public void mouseHover(MouseEvent e) { + + } + + public void setMouseMoved(boolean b) { + awtMouseMoved = b; + } + + public void setMouseX(int x) { + awtMouseX = x; + } + + public void setMouseY(int y) { + awtMouseY = y; + } + + public String toString() { + String s = ""; + s += "(" + mouseX + "," + mouseY + ")\n"; + s += "Pressed " + mousePressed + "\n"; + s += "Released " + mouseReleased + "\n"; + s += "Moved " + mouseMoved + "\n"; + s += "Dragged " + mouseDragged + "\n"; + s += "Clicked " + mouseClicked + "\n"; + s += "DragModifiers " + dragModifiers + "\n"; + s += "ClickModifiers " + clickModifiers + "\n"; + s += "PressModifiers " + pressModifiers + "\n"; + return s; + } +} \ No newline at end of file diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/preferences/G3DPreferencesPage.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/preferences/G3DPreferencesPage.java new file mode 100644 index 00000000..98230ebe --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/preferences/G3DPreferencesPage.java @@ -0,0 +1,121 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.preferences; + +import org.eclipse.jface.preference.*; +import org.eclipse.ui.IWorkbenchPreferencePage; +import org.eclipse.ui.IWorkbench; +import org.simantics.proconf.g3d.Activator; + + +/** + * This class represents a preference page that + * is contributed to the Preferences dialog. By + * subclassing FieldEditorPreferencePage, 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. + *

+ * 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 G3DPreferencesPage + extends FieldEditorPreferencePage + implements IWorkbenchPreferencePage { + + public G3DPreferencesPage() { + super(GRID); + setPreferenceStore(Activator.getDefault().getPreferenceStore()); + setDescription("A demonstration of a preference page implementation"); + } + + /** + * 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 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())); + addField(new BooleanFieldEditor(PreferenceConstants.SHADOWS,"Use Shadows",getFieldEditorParent())); + addField(new RadioGroupFieldEditor(PreferenceConstants.POST_PROCESS, "Post Processing", 1, + new String[][] { { "None", "none" }, + { "Sketch", "sketch" }, + { "Bloom", "bloom" }}, + getFieldEditorParent())); + addField(new ScaleFieldEditor(PreferenceConstants.GIZMO_SCALE,"Gizmo scale",getFieldEditorParent(),5,100,1,10) { + private double oldValue; + + @Override + protected void doStore() { + getPreferenceStore() + .setValue(getPreferenceName(), scale.getSelection()*0.1); + } + + @Override + protected void doLoadDefault() { + if (scale != null) { + double value = getPreferenceStore().getDefaultDouble(getPreferenceName()); + scale.setSelection((int)(value*10.0)); + } + valueChanged(); + } + + @Override + protected void doLoad() { + if (scale != null) { + double value = getPreferenceStore().getDouble(getPreferenceName()); + scale.setSelection((int)(value*10.0)); + oldValue = value; + }; + } + + @Override + protected void valueChanged() { + setPresentsDefaultValue(false); + + double newValue = scale.getSelection()*0.1; + if (newValue != oldValue) { + fireStateChanged(IS_VALID, false, true); + fireValueChanged(VALUE, new Double(oldValue), + new Double(newValue)); + oldValue = newValue; + } + } + }); + } + + /* (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.proconf.g3d/src/org/simantics/proconf/g3d/preferences/PreferenceConstants.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/preferences/PreferenceConstants.java new file mode 100644 index 00000000..c0163e7e --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/preferences/PreferenceConstants.java @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.preferences; + +/** + * Constant definitions for plug-in preferences + */ +public class PreferenceConstants { + + public static final String POST_PROCESS = "postProcess"; + public static final String SHADOWS = "shadows"; + public static final String GIZMO_SCALE = "gizmoScale"; + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/preferences/PreferenceInitializer.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/preferences/PreferenceInitializer.java new file mode 100644 index 00000000..5a40d2fb --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/preferences/PreferenceInitializer.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.preferences; + +import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer; +import org.eclipse.jface.preference.IPreferenceStore; +import org.simantics.proconf.g3d.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.P_BOOLEAN, true); +// store.setDefault(PreferenceConstants.P_CHOICE, "choice2"); +// store.setDefault(PreferenceConstants.P_STRING,"Default value"); + store.setDefault(PreferenceConstants.POST_PROCESS, "none"); + store.setDefault(PreferenceConstants.SHADOWS, true); + store.setDefault(PreferenceConstants.GIZMO_SCALE, 1.0); + } + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/AbstractGraphicsNode.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/AbstractGraphicsNode.java new file mode 100644 index 00000000..d1dde38e --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/AbstractGraphicsNode.java @@ -0,0 +1,200 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.scenegraph; + +import java.util.ArrayList; +import java.util.Collection; + +import javax.vecmath.AxisAngle4d; +import javax.vecmath.AxisAngle4f; +import javax.vecmath.Matrix3d; +import javax.vecmath.Quat4d; +import javax.vecmath.Vector3f; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.proconf.g3d.base.G3DTools; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.base.VecmathJmeTools; +import org.simantics.proconf.g3d.stubs.G3DNode; + +import com.jme.scene.Node; + + +public abstract class AbstractGraphicsNode implements ISelectableNode { + + protected ThreeDimensionalEditorBase editor; + + protected IGraphicsNode parent = null; + + protected Resource shapeResource = null; + + protected boolean selected; + + protected Node parentGroup = null; + protected Node transform = null; + // protected Node center = null; + + protected String id; + + private ArrayList children = new ArrayList(); + + public AbstractGraphicsNode(ThreeDimensionalEditorBase editor, IGraphicsNode parent, Graph graph, Resource shapeResource) { + assert (parent != null); + this.editor = editor; + this.parent = parent; + this.parentGroup = parent.getGroup(); + this.shapeResource = shapeResource; + this.id = editor.getScenegraphAdapter().getNodeUID(shapeResource); + createGroups(); + updateTransform(graph); + parent.addChild(this); + } + + @Override + public String getID() { + return id; + } + + public void setID(String id) { + this.id = id; + } + + + /* (non-Javadoc) + * @see fi.vtt.proconf.shapeeditor.geometry.IGraphicsNode#getParent() + */ + public IGraphicsNode getParent() { + return parent; + } + + public Collection getChildren() { + return children; + } + + private void createGroups() { + transform = new Node(); // TODO : uid + parentGroup.attachChild(transform); + } + + public void addChild(IGraphicsNode node) { + children.add(node); + } + + public void removeChild(IGraphicsNode node) { + children.remove(node); + } + + /* (non-Javadoc) + * @see fi.vtt.proconf.shapeeditor.geometry.IGraphicsNode#getGroup() + */ + public Node getGroup() { + //return center; + + return transform; + } + + /** + * Updates rotation and translation of the shape without recalculating + * geometry + */ + public void updateTransform(Graph graph) { + G3DNode shape = getG3DNode(graph); + if (shape.getLocalPosition() != null) + transform.setLocalTranslation(VecmathJmeTools.get(G3DTools.getVectorFloat(shape.getLocalPosition()))); + if (shape.getLocalOrientation() != null) + transform.setLocalRotation(VecmathJmeTools.get(G3DTools.getOrientationFloat(shape.getLocalOrientation()))); +// if (GraphicsNodeTools.hasCenter(shape)) { +// center.setLocalTranslation(VecmathJmeTools.get(GraphicsNodeTools.getCenterFloat(shape))); +// } + // FIXME : typically transforms are updated once per frame (root as initiator) but with threaded access transformation may be read wrong. + transform.updateWorldVectors(); + editor.getScenegraphAdapter().setChanged(true); + } + + + + protected void update(Matrix3d aa) { + transform.setLocalRotation(VecmathJmeTools.get(aa)); + } + protected void update(AxisAngle4f aa) { + transform.setLocalRotation(VecmathJmeTools.get(aa)); + } + + protected void update(AxisAngle4d aa) { + transform.setLocalRotation(VecmathJmeTools.get(aa)); + } + + protected void update(Quat4d q) { + transform.setLocalRotation(VecmathJmeTools.get(q)); + } + + protected void update(Vector3f v) { + transform.setLocalTranslation(VecmathJmeTools.get(v)); + } + + + public void setSelected(boolean selected) { + if (this.selected == selected) + return; + this.selected = selected; + } + + public boolean isSelected() { + return selected; + } + + /* (non-Javadoc) + * @see fi.vtt.proconf.shapeeditor.geometry.IGraphicsNode#getResource() + */ + public Resource getResource() { + return shapeResource; + } + + public G3DNode getG3DNode(Graph graph) { + return new G3DNode(graph,shapeResource); + } + + /* (non-Javadoc) + * @see fi.vtt.proconf.shapeeditor.geometry.IGraphicsNode#dispose() + */ + public void dispose() { +// if (children.size() != 0) { +// System.out.print(getResource() + " contains children: "); +// ArrayList c = new ArrayList(children); +// for (IGraphicsNode n : c) { +// System.out.print(n.getResource() + " "); +// } +// System.out.println(); +// return; +// } + assert (children.size() == 0); + + transform.removeFromParent(); + transform.dispose(); + if (parent != null) + parent.removeChild(this); + } + + + public abstract void setPickable(boolean pickable); + + public String toString() { + return this.getClass().toString(); + } + + @Override + public int hashCode() { + return shapeResource.hashCode(); + } + + +} \ No newline at end of file diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/IGeometryNode.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/IGeometryNode.java new file mode 100644 index 00000000..94d3daed --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/IGeometryNode.java @@ -0,0 +1,19 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.scenegraph; + +import org.simantics.db.Graph; + +public interface IGeometryNode extends IGraphicsNode{ + + public void updateGeometry(Graph graph); + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/IGraphicsNode.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/IGraphicsNode.java new file mode 100644 index 00000000..a72aa5f1 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/IGraphicsNode.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.scenegraph; + +import java.util.Collection; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.proconf.g3d.stubs.G3DNode; + +import com.jme.scene.Node; + +public interface IGraphicsNode { + + public IGraphicsNode getParent(); + + public Node getGroup(); + + public Resource getResource(); + + /** + * Disposes the node. Disposing of node that has children is not allowed. + */ + public void dispose(); + + public void updateTransform(Graph graph); + + public G3DNode getG3DNode(Graph graph); + + public void addChild(IGraphicsNode node); + public void removeChild(IGraphicsNode node); + public Collection getChildren(); + + + +} \ No newline at end of file diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/ISelectableNode.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/ISelectableNode.java new file mode 100644 index 00000000..4abd1b3a --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/ISelectableNode.java @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.scenegraph; + +public interface ISelectableNode extends IGraphicsNode{ + public void setVisible(boolean visible); + public boolean isVisible(); + public void setSelected(boolean selected); + public boolean isSelected(); + public void setHighlighted(boolean higlighted); + public boolean isHighlighted(); + public void setPickable(boolean pickable); + public String getID(); +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/ModelNode.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/ModelNode.java new file mode 100644 index 00000000..40e845a1 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/ModelNode.java @@ -0,0 +1,195 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.scenegraph; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.proconf.g3d.Resources; +import org.simantics.proconf.g3d.animation.Animatable; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.stubs.G3DModel; +import org.simantics.proconf.g3d.stubs.G3DNode; +import org.simantics.utils.ErrorLogger; + +public class ModelNode extends AbstractGraphicsNode implements Animatable, IGeometryNode{ + protected List shapes = new ArrayList(); + private boolean highlighted; + + protected Resource modelResource; + + private boolean geometryCreated = false; + + public ModelNode(ThreeDimensionalEditorBase editor,IGraphicsNode parent, Graph graph, Resource shapeResource) { + super(editor,parent, graph, shapeResource); + + } + + protected void createGeometry(Graph graph) { + + if (modelResource != null) { + G3DModel model = getG3DModel(graph); + Collection nodes = model.getChild(); + if (nodes.size() == 0) { + ErrorLogger.defaultLogError("ModelNode " + model.getResource() + " has no shapes", null); + return; + } + for (G3DNode node: nodes) { + ShapeNode shape = new ShapeNode(editor,this,graph,node.getResource()); + shapes.add(shape); + + shape.setID(getID()); + shape.setVisible(true); + shape.updateGeometry(graph); + createRecursive(graph,shape); + } + geometryCreated = true; + } + } + + private void createRecursive(Graph graph,IGraphicsNode parentNode) { + Collection nodes = parentNode.getG3DNode(graph).getChild(); + for (G3DNode node: nodes) { + if (node.getRelatedObjects(Resources.g3dResource.GeometryDefinitionOf).size() == 0) { + ShapeNode shape = new ShapeNode(editor,parentNode,graph,node.getResource()); + shapes.add(shape); + + shape.setID(getID()); + shape.setVisible(true); + shape.updateGeometry(graph); + createRecursive(graph,shape); + } + } + } + + public void updateGeometry(Graph graph) { + if (!geometryCreated) { + createGeometry(graph); + return; + } + updateTransform(graph); +// for (IGraphicsNode node : getChildren()) { +// ((IGeometryNode)node).updateGeometry(); +// } + for (ShapeNode node : shapes) + node.updateGeometry(graph); + } + + public boolean isVisible() { + for (IGraphicsNode n : getChildren()) + if (n instanceof ISelectableNode) + if (!((ISelectableNode)n).isVisible()) + return false; + return true; + } + + public void setVisible(boolean visible) { + for (IGraphicsNode node : getChildren()) { + if (node instanceof ISelectableNode) + ((ISelectableNode)node).setVisible(visible); + } + } + + @Override + public void dispose() { + // shapes must be removed reverse order (leafs first) + for (int i = shapes.size() - 1; i >= 0; i--) { + shapes.get(i).dispose(); + } + super.dispose(); + } + + + @Override + public void setPickable(boolean pickable) { + for(ShapeNode n : shapes) { + n.setPickable(pickable); + } + } + + public boolean isHighlighted() { + return highlighted; + } + + public void setHighlighted(boolean selected) { + if (this.highlighted == selected) + return; + this.highlighted = selected; + for (ShapeNode n : shapes) + n.setHighlighted(selected); + + } + + @Override + public void setSelected(boolean selected) { + if (this.selected == selected) + return; + this.selected = selected; + for (ShapeNode n : shapes) + n.setSelected(selected); + } + + public void animate(double delta, double frameTime) { + for (ShapeNode n : shapes) + n.animate(delta,frameTime); + } + + public G3DModel getG3DModel(Graph graph) { + return new G3DModel(graph, modelResource); + } + + public boolean setAnimation(Graph graph, Resource animation) { + if (modelResource == null) { + ErrorLogger.getDefault().logWarning("Cannot set animation for " + shapeResource + " since it has no graphics", null); + return false; + } + Collection animations = graph.getObjects(modelResource, Resources.animationResource.HasAnimation); + if (!animations.contains(animation)) { + ErrorLogger.getDefault().logWarning("Cannot set animation for " + shapeResource + " since it doesn't have requested animation " + animation.getResource(), null); + return false; + } + + boolean set = false; + for (ShapeNode n : shapes) { + if (n.setAnimation(graph,animation)) + set = true; + } + return set; + } + + public boolean setRandomAnimation(Graph graph) { + if (modelResource == null) { + ErrorLogger.getDefault().logWarning("Cannot set animation for " + shapeResource + " since it has no graphics", null); + return false; + } + G3DModel model = getG3DModel(graph); + Collection animations = model.getAnimation(); + int num = animations.size(); + if (num == 0) { + ErrorLogger.getDefault().logWarning("Cannot set animation for " + shapeResource + " since it has no animations", null); + return false; + } + int random = (int)Math.round(Math.random() * (num-1)); + Iterator i = animations.iterator(); + while(random > 0) { + i.next(); + random--; + } + return setAnimation(graph,i.next().getResource()); + + } + + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/NonTransformableNode.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/NonTransformableNode.java new file mode 100644 index 00000000..2c020971 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/NonTransformableNode.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.scenegraph; + +import java.util.ArrayList; +import java.util.Collection; + +import org.simantics.proconf.g3d.stubs.G3DNode; + +import com.jme.scene.Node; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; + +public abstract class NonTransformableNode implements IGraphicsNode { + + private IGraphicsNode parent; + private ArrayList children = new ArrayList(); + protected Node parentGroup = null; + protected Resource nodeResource; + + public NonTransformableNode(IGraphicsNode parent, Resource nodeResource) { + this.parent = parent; + this.nodeResource = nodeResource; + parentGroup = parent.getGroup(); + parent.addChild(this); + } + + public void addChild(IGraphicsNode node) { + children.add(node); + + } + + public Collection getChildren() { + return children; + } + + public void removeChild(IGraphicsNode node) { + children.remove(node); + + } + + public void dispose() { + assert(children.size() == 0); + if (parent != null) + parent.removeChild(this); + } + + public G3DNode getG3DNode(Graph graph) { + return new G3DNode(graph, nodeResource); + } + + public Node getGroup() { + return parentGroup; + } + + + public IGraphicsNode getParent() { + return parent; + } + + + public Resource getResource() { + return nodeResource; + } + + public void updateTransform(Graph graph) { + + } + +} \ No newline at end of file diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/ParameterizedModelNode.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/ParameterizedModelNode.java new file mode 100644 index 00000000..511a2fa9 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/ParameterizedModelNode.java @@ -0,0 +1,188 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.scenegraph; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +import org.simantics.db.Builtins; +import org.simantics.db.ContextGraph; +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.equation.solver.Solver; +import org.simantics.g2d.stubs.anim.Animation; +import org.simantics.layer0.utils.Property; +import org.simantics.layer0.utils.IEntity; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.Statement; +import org.simantics.proconf.g3d.Resources; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.stubs.G3DModel; +import org.simantics.proconf.g3d.stubs.G3DNode; +import org.simantics.utils.ErrorLogger; + +/** + * IGraphicsNode for parameterized models. Implementation assumes that G3DNode itself does not contain + * graphical representation but has link to it. + * + * @author Marko Luukkainen + * + */ +public class ParameterizedModelNode extends ModelNode { + + /** + * @param editor + * @param parent + * @param graph + * @param resource this node (G3DNode). + * @param nodeToModelRelation relation from this node to the model, or from type of this node to the model. + * @param modelToParametersRelation relation from the model to its sizing parameters + */ + public ParameterizedModelNode(ThreeDimensionalEditorBase editor, IGraphicsNode parent, Graph graph, Resource resource, Resource nodeToModelRelation) { + super(editor,parent,graph,resource); + G3DNode shape = getG3DNode(graph); + List models = new ArrayList(); + models.addAll(shape.getRelatedObjects(nodeToModelRelation)); + if (models.size() == 0) { + Collection types = shape.getTypes(); + for (IEntity type : types) { + models.addAll(type.getRelatedObjects(nodeToModelRelation)); + } + } + if (models.size() != 1) + throw new IllegalArgumentException("Cannot find proper model: found " + models.size() + " models."); + + this.modelResource = models.iterator().next().getResource(); + } + + @Override + protected void createGeometry(Graph graph) { + super.createGeometry(createParameterization(graph)); + } + + @Override + public void updateGeometry(Graph graph) { + super.updateGeometry(createParameterization(graph)); + } + + private void updateSizeParameters(ContextGraph graph, Solver solver) { + Builtins builtins = graph.getBuiltins(); + + + G3DNode node = getG3DNode(graph); + //Collection nodeProperties = node.getRelatedProperties(builtins.HasProperty); + Collection nodeProperties = node.getRelatedStatements(builtins.HasProperty); + G3DModel model = getG3DModel(graph); + Collection modelProperties = model.getRelatedProperties(Resources.g3dResource.HasSizingParameter); + + // there are no relations between then nodes properties and the model's sizing parameters + // link between them is done by matching names + for (Property m : modelProperties) { + boolean set = false; + //if(m.canBeSet(builtins.HasName)) { + + String modelPropertyname = m.getAtMostOneRelatedProperty(builtins.HasName).getScalarString(); + for (Statement n : nodeProperties) { + String relationName = n.getPredicate().getName(); + if (relationName.startsWith("Has ")) + relationName = relationName.substring(4); + if (relationName.equalsIgnoreCase(modelPropertyname)) { + // found a match + // set property's value for Solver + solver.setValue(m.getResource(), graph.getValueAsObject(n.getObject().getResource())); + set = true; + break; + } + + } + if (!set) { + ErrorLogger.defaultLogError("Cannot map property " + modelPropertyname, null); + } + //} + + } + + for (Property p : modelProperties) { + IEntity t = EntityFactory.create(graph, p.getResource()); + Collection exp = t.getRelatedObjects(Resources.equationResource.HasTarget); + if (exp.size() > 0) { + Iterator i = exp.iterator(); + while(i.hasNext()) + solver.evaluate(i.next()); + } else + ErrorLogger.defaultLogError("Model property " + p + " is not bound to a expression",null); + } + solver.pushToGraph(graph); + Collection animations = model.getAnimation(); + for (Animation animation : animations) { + Collection interpolators = animation.getInterpolator(); + for (org.simantics.g2d.stubs.anim.Interpolator interpolator : interpolators) { + IEntity target = interpolator.getTarget(); + // check all model properties + for (Property p : modelProperties) { + IEntity t = EntityFactory.create(graph,p.getResource()); + // get parameterization equations + Collection equations = t.getRelatedObjects(Resources.equationResource.HasTarget); + // get parameterized values + Collection parameterTargets = new ArrayList(); + for (IEntity eq : equations) { + Collection tgts = eq.getRelatedObjects(Resources.equationResource.HasTarget); + assert(tgts.size() == 1); + parameterTargets.add(tgts.iterator().next()); + } + // do matching between interpolator targets and parameterized values + // TODO : old system did not have inverse relations but current system does. + // it is possible to take interpolation target and find if it is connected to an equation + // this would make code much faster (no more stupid loops over everything) + for (IEntity d : parameterTargets) { + if (d.getResource().equals(target.getResource())) { + // get default value for sizing property + Collection prop = t.getRelatedObjects(Resources.g3dResource.HasDefaultDoubleValue); + if (prop.size() == 1) { + Resources.curveBuilder.parameterize(interpolator, prop.iterator().next().toProperty().getDoubleArray(), p.getDoubleArray()); + } else { + ErrorLogger.defaultLogError("Cannot parameterize interpolator " + interpolator.getResource() + " of animation " + animation.getResource() + " since parameter " + p.getResource() + " has no default value", null); + } + } + } + } + } + } + + } + + protected Graph createParameterization(Graph graph) { + // create ContextGraph if needed + ContextGraph g; + if (!(graph instanceof ContextGraph)) + g = new ContextGraph(graph); + else + g = (ContextGraph)graph; + // set the context + g.setContext(this.shapeResource); + // create solver and calculate parameterized values + Solver solver = new Solver(); + updateSizeParameters(g, solver); + // push parameterized values to context + solver.pushToGraph(g); + // return graph with parameterized values + return g; + } + + @Override + public boolean setAnimation(Graph graph, Resource animation) { + return super.setAnimation(createParameterization(graph), animation); + } + + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/RootGraphicsNode.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/RootGraphicsNode.java new file mode 100644 index 00000000..9937f4cf --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/RootGraphicsNode.java @@ -0,0 +1,77 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.scenegraph; + +import java.util.ArrayList; +import java.util.Collection; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.proconf.g3d.base.JmeRenderingComponent; +import org.simantics.proconf.g3d.stubs.G3DNode; + +import com.jme.scene.Node; + +public class RootGraphicsNode implements IGraphicsNode { + + JmeRenderingComponent component; + Resource rootNode; + private ArrayList children = new ArrayList(); + + + public RootGraphicsNode(JmeRenderingComponent component, Resource rootNode) { + this.component = component; + this.rootNode = rootNode; + } + + public void addChild(IGraphicsNode node) { + children.add(node); + } + + public void removeChild(IGraphicsNode node) { + children.remove(node); + } + + public Collection getChildren() { + return children; + } + + public void dispose() { + //throw new RuntimeException("Root cannot be disposed"); + } + + public Node getGroup() { + return component.getShadowRoot(); + } + + public IGraphicsNode getParent() { + return null; + } + + public Resource getResource() { + return rootNode; + } + + public void updateTransform(Graph graph) { + + } + + public String toString() { + return this.getClass().toString(); + } + + public G3DNode getG3DNode(Graph graph) { + return new G3DNode(graph, rootNode); + } + + + +} \ No newline at end of file diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/ShapeNode.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/ShapeNode.java new file mode 100644 index 00000000..ef89c3a4 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/ShapeNode.java @@ -0,0 +1,719 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.scenegraph; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import javax.vecmath.AxisAngle4d; +import javax.vecmath.Quat4d; + +import org.simantics.g2d.stubs.anim.Interpolator; +import org.simantics.proconf.animation.curve.SlerpCurve; +import org.simantics.proconf.animation.curve.TCBCurve; +import org.simantics.proconf.g3d.Resources; +import org.simantics.proconf.g3d.animation.Animatable; +import org.simantics.proconf.g3d.animation.Animation; +import org.simantics.proconf.g3d.animation.ChanneledColorInterpolator; +import org.simantics.proconf.g3d.animation.ChanneledPositionInterpolator; +import org.simantics.proconf.g3d.animation.ConstantInterpolator; +import org.simantics.proconf.g3d.animation.ScalarInterpolator; +import org.simantics.proconf.g3d.animation.SlerpInterpolator; +import org.simantics.proconf.g3d.animation.TCBInterpolator; +import org.simantics.proconf.g3d.base.AppearanceTools; +import org.simantics.proconf.g3d.base.G3DTools; +import org.simantics.proconf.g3d.base.GeometryProvider; +import org.simantics.proconf.g3d.base.GeometryProviderRegistry; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.stubs.Appearance; +import org.simantics.proconf.g3d.stubs.Color; +import org.simantics.proconf.g3d.stubs.G3DModel; +import org.simantics.proconf.g3d.stubs.G3DNode; +import org.simantics.proconf.g3d.stubs.Orientation; +import org.simantics.utils.ErrorLogger; + +import com.jme.bounding.BoundingBox; +import com.jme.bounding.CollisionTreeManager; +import com.jme.intersection.PickResults; +import com.jme.math.Ray; +import com.jme.renderer.ColorRGBA; +import com.jme.renderer.Renderer; +import com.jme.scene.Geometry; +import com.jme.scene.Node; +import com.jme.scene.SharedMesh; +import com.jme.scene.TriMesh; +import com.jme.scene.state.AlphaState; +import com.jme.scene.state.MaterialState; +import com.jme.scene.state.RenderState; +import com.jme.scene.state.WireframeState; +import com.jme.scene.state.ZBufferState; + +import org.simantics.db.Builtins; +import org.simantics.db.ContextGraph; +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.layer0.utils.IEntity; + +public class ShapeNode extends AbstractGraphicsNode implements Animatable, IGeometryNode{ + + public static final int NORMAL = 0; + public static final int TRANSPARENT = 1; + public static final int SELECTED_EDGE = 2; + public static final int HIGHLIGHTED_EDGE = 3; + + private boolean highlighted = false; + + protected Geometry mesh = null; + protected Geometry lines = null; + protected Geometry[] geometry = null; + + private boolean visible[] = new boolean[4]; + + private Node body; + private Node transparent; + private Node edge; + + private MaterialState selectedEdgeState; + private MaterialState highlightedEdgeState; + + private Collection renderStates; + private boolean isTransparent; + + + public ShapeNode(ThreeDimensionalEditorBase editor,IGraphicsNode parent, Graph graph, Resource shapeResource) { + super(editor,parent, graph, shapeResource); + for (int i = 0; i < visible.length; i++) + visible[i] = false; + + body = new Node(); + + body.setName(id); + + + transparent = new Node() { + private static final long serialVersionUID = 1L; + @Override + public void calculatePick(Ray ray, PickResults results) { + + } + }; + + // transparent.setRenderQueueMode(Renderer.QUEUE_TRANSPARENT); + + edge = new Node(){ + private static final long serialVersionUID = 1L; + @Override + public void calculatePick(Ray ray, PickResults results) { + + } + }; + transparent.setIsCollidable(false); + edge.setIsCollidable(false); + + MaterialState ms = editor.getRenderingComponent().getDisplaySystem().getRenderer().createMaterialState(); + ms.setDiffuse(new ColorRGBA(0.0f, 0.75f, 0.0f,0.3f)); + ms.setEmissive(new ColorRGBA(0f, 0f, 0f,0.3f)); + ms.setSpecular(new ColorRGBA(0.5f, 0.5f, 0.5f,0.3f)); + ms.setAmbient(new ColorRGBA(0.0f, 0.75f, 0.0f,0.3f)); + ms.setShininess(128.f); + ms.setMaterialFace(MaterialState.MF_FRONT_AND_BACK); + transparent.setRenderState(ms); + + AlphaState as = editor.getRenderingComponent().getDisplaySystem().getRenderer().createAlphaState(); + as.setBlendEnabled(true); + as.setDstFunction(AlphaState.DB_ONE_MINUS_SRC_ALPHA); + as.setSrcFunction(AlphaState.DB_SRC_ALPHA); + transparent.setRenderState(as); + + ms = editor.getRenderingComponent().getDisplaySystem().getRenderer().createMaterialState(); + ms.setDiffuse(new ColorRGBA(1.f, 1.f, 1.f, 1.f)); + ms.setEmissive(new ColorRGBA(1.f, 1.f, 1.f, 1.f)); + ms.setSpecular(new ColorRGBA(1.f, 1.f, 1.f, 1.f)); + ms.setAmbient(new ColorRGBA(1.f, 1.f, 1.f, 1.f)); + ms.setShininess(128.f); + selectedEdgeState = ms; + + ms = editor.getRenderingComponent().getDisplaySystem().getRenderer().createMaterialState(); + ms.setDiffuse(new ColorRGBA(1.f, 0.f, 1.f, 1.f)); + ms.setEmissive(new ColorRGBA(1.f, 0.f, 1.f, 1.f)); + ms.setSpecular(new ColorRGBA(1.f, 0.f, 1.f, 1.f)); + ms.setAmbient(new ColorRGBA(1.f, 0.f, 1.f, 1.f)); + ms.setShininess(128.f); + + highlightedEdgeState = ms; + + + } + + + /** + * This method is used to get implementation specific geometry. + * Arrays first element is a mesh, second contains edges. + * @return + */ + public Geometry[] getGeometry(Graph graph, boolean update) { + G3DNode shape = getG3DNode(graph); + final GeometryProvider provider = GeometryProviderRegistry.getGeometryProvider(shape); + if (!update) { + return provider.getGeometryFromResource(shape, false); + } else { + if (geometry == null) { + geometry = provider.getGeometryFromResource(shape, false); + } else { + provider.reconstructGeometry(shape, false, geometry); + } + return geometry; + } + } + + /** + * Updates shapes and it's ancestors geometry + */ + public void updateGeometry(Graph graph) { + updateTransform(graph); + // cleanAnimation(); + //System.out.println("ShapeNode.updateGeometry() " + name); + if (geometry == null) { + Geometry g[] = getGeometry(graph,true); + if (g != null) { + mesh = g[0]; + //TODO : uid + mesh.setName(id); + mesh.setModelBound(new BoundingBox()); + if (g.length > 1) { + lines = g[1]; + } else { + lines = null; + } + body.attachChild(mesh); + transparent.detachAllChildren(); + SharedMesh m = new SharedMesh("",(TriMesh)mesh); + m.setRenderQueueMode(Renderer.QUEUE_TRANSPARENT); + m.getBatch(0).setCastsShadows(false); + transparent.attachChild(m); + + + if (lines == null) { + WireframeState ws = editor.getRenderingComponent().getDisplaySystem().getRenderer().createWireframeState(); + edge.attachChild(new SharedMesh("",(TriMesh)mesh)); + edge.setRenderState(ws); + } else { + ZBufferState zs = editor.getRenderingComponent().getDisplaySystem().getRenderer().createZBufferState(); + zs.setFunction(ZBufferState.CF_ALWAYS); + AlphaState as = editor.getRenderingComponent().getDisplaySystem().getRenderer().createAlphaState(); + as.setBlendEnabled(true); + as.setDstFunction(AlphaState.DB_ONE_MINUS_SRC_ALPHA); + as.setSrcFunction(AlphaState.DB_SRC_ALPHA); + lines.setRenderState(zs); + lines.setRenderState(as); + lines.setRenderQueueMode(Renderer.QUEUE_TRANSPARENT); + edge.attachChild(lines); + } + + } + } + if (geometry != null) { + getGeometry(graph,true); + + + G3DNode shape = getG3DNode(graph); + if (renderStates == null) + updateAppearance(shape); + + if (isVisible()) { + getGroup().attachChild(body); + } else { + body.removeFromParent(); + } + if (isTransparentVisible()) { + getGroup().attachChild(transparent); + //setVisible(TRANSPARENT, true); + } else { + transparent.removeFromParent(); + } + + if (isSelectedVisible() || isHighlightedVisible()) { + getGroup().attachChild(edge); + //setVisible(SELECTED_EDGE, true); + } else { + edge.removeFromParent(); + //setVisible(SELECTED_EDGE,false); + } + + + mesh.updateModelBound(); + CollisionTreeManager.getInstance().updateCollisionTree(mesh); + //mesh.updateCollisionTree(); + + } + } + + protected void updateAppearance(IEntity shape) { + Collection appearanceResource; + if ((appearanceResource = shape.getRelatedObjects(Resources.g3dResource.HasAppearance)) != null && appearanceResource.size() > 0) { + renderStates = AppearanceTools.getAppearance(new Appearance(shape.getGraph(),appearanceResource.iterator().next().getResource()), editor.getRenderingComponent().getDisplaySystem().getRenderer()); + } else { + renderStates = getMaterial(); + } + + isTransparent = false; + for (RenderState s : renderStates) { + if (s instanceof AlphaState) + isTransparent = true; + } + setAppearance(); + } + + protected void setAppearance() { + if (mesh == null || renderStates == null) { + return; + } + for (RenderState s : renderStates) + mesh.setRenderState(s); + if (isTransparent) + mesh.setRenderQueueMode(Renderer.QUEUE_TRANSPARENT); + else + mesh.setRenderQueueMode(Renderer.QUEUE_OPAQUE); + } + + public void setSelected(boolean selected) { + if (this.selected == selected) + return; + this.selected = selected; + if (selected) { + + setSelectedVisible(true); + setTransparentVisible(true); + } else { + setSelectedVisible(false); + setTransparentVisible(false); + } + } + + public boolean isSelected() { + return selected; + } + + + + public boolean isHighlighted() { + return highlighted; + } + + public void setHighlighted(boolean highlighted) { + if (this.highlighted == highlighted) + return; + this.highlighted = highlighted; + if (highlighted) { + setHighlightedVisible(true); + } else { + setHighlightedVisible(false); + } + } + + public boolean isVisible(int shape) { + return visible[shape]; + } + + public void setVisible(int shape, boolean visible) { + if (this.visible[shape] == visible) + return; + this.visible[shape] = visible; + if (mesh == null) { + return; + } + if (this.visible[NORMAL]){ + getGroup().attachChild(body); + } else { + body.removeFromParent(); + } + if (this.visible[TRANSPARENT]) { + getGroup().attachChild(transparent); + } else { + transparent.removeFromParent(); + } + if (this.visible[SELECTED_EDGE] || this.visible[HIGHLIGHTED_EDGE]) { + if (this.visible[HIGHLIGHTED_EDGE]) + edge.setRenderState(highlightedEdgeState); + else + edge.setRenderState(selectedEdgeState); + getGroup().attachChild(edge); + edge.updateRenderState(); + } else { + edge.removeFromParent(); + } + } + + public boolean isVisible() { + return isVisible(NORMAL); + } + + public void setVisible(boolean visible) { + setVisible(NORMAL, visible); + } + + public boolean isSelectedVisible() { + return isVisible(SELECTED_EDGE); + } + + public void setSelectedVisible(boolean visible) { + setVisible(SELECTED_EDGE, visible); + } + + public boolean isHighlightedVisible() { + return isVisible(HIGHLIGHTED_EDGE); + } + + public void setHighlightedVisible(boolean visible) { + setVisible(HIGHLIGHTED_EDGE, visible); + + } + + + + public boolean isTransparentVisible() { + return isVisible(TRANSPARENT); + } + + public void setTransparentVisible(boolean visible) { + setVisible(TRANSPARENT, visible); + } + + public void setPickable(boolean pickable) { + body.setIsCollidable(pickable); + } + + public Collection getMaterial() { + List states = new ArrayList(); + MaterialState ms = editor.getRenderingComponent().getDisplaySystem().getRenderer().createMaterialState(); + ms.setEmissive(new ColorRGBA(0.f,0.f,0.f,0.f)); + ms.setSpecular(new ColorRGBA(1.f,1.f,1.f,1.f)); + ms.setDiffuse(new ColorRGBA(0.75f,0.f,0.f,0.f)); + ms.setAmbient(new ColorRGBA(0.75f,0.f,0.f,0.f)); + ms.setEnabled(true); + ms.setShininess(128.f); + states.add(ms); + + return states; + } + + private Animation animation; + private static int preCalcSteps = 9; + private Geometry[] preCalc = null; + private int currentPreCalc = 0; + + public void animate(double delta,double frameTime) { + if (animation != null) + animation.interpolate(delta); + if (preCalc != null) { + int newPreCalc = (int)Math.round(delta*(preCalc.length-1)); + if (currentPreCalc != newPreCalc) { + + preCalc[currentPreCalc].removeFromParent(); + currentPreCalc = newPreCalc; + + body.attachChild(preCalc[currentPreCalc]); + } + } + } + + private void cleanAnimation() { + this.animation = null; + if (preCalc != null) { + for (Geometry g : preCalc) { + if (g != null) { + g.removeFromParent(); + g.clearBuffers(); + } + } + preCalc = null; + } + } + + /** + * Sets shape's animation + * TODO : multiple animations at the same time! (must check common animatable properties) + * TODO : initial values (material, ..) (requires changes in the ontology) + * TODO : messy code, refactor! + * TODO : calculate number of required pre-calculated geometries + * @param animation + */ + public boolean setAnimation(Graph g, Resource res) { + ContextGraph graph; + if (g instanceof ContextGraph) { + graph = (ContextGraph)g; + } else { + graph = new ContextGraph(g); + graph.setContext(shapeResource); + } + cleanAnimation(); + if (res == null) { + if (isVisible()) + body.attachChild(mesh); + return false; + } + org.simantics.g2d.stubs.anim.Animation animation = new org.simantics.g2d.stubs.anim.Animation(graph,res); + G3DNode shape = getG3DNode(graph); + G3DNode modelResource = G3DTools.getModelFromResource(graph,shape.getResource()); + assert (modelResource != null); + G3DModel model = new G3DModel(graph,modelResource.getResource()); + Collection animations = model.getAnimation(); + boolean found = false; + for (org.simantics.g2d.stubs.anim.Animation a : animations) { + if (a.getResource().equals(animation.getResource())) { + found = true; + break; + } + } + if (!found) { + ErrorLogger.getDefault().logWarning("Shape " + shape.getResource() + " cannot handle animation " + animation.getResource() + " because it isn't model's animation", null); + return false; + } + Collection interpolators = animation.getInterpolator(); + List handled = new ArrayList(); + List precalculated = new ArrayList(); + for (org.simantics.g2d.stubs.anim.Interpolator i : interpolators) { + IEntity target = i.getTarget(); + if (G3DTools.hasProperty(graph,shape.getResource(),target.getResource())) + handled.add(i); + else if (G3DTools.hasSubProperty(graph,shape.getResource(),target.getResource())) { + precalculated.add(i); + } + } + if (handled.size() == 0 && precalculated.size() == 0) { + ErrorLogger.getDefault().logWarning("Shape " + shape.getResource() + " cannot handle animation " + animation.getResource() + " since it doesn't change any of shape's properties", null); + return false; + } + + + this.animation = new Animation(); + + org.simantics.g2d.stubs.anim.Interpolator[] pos = new org.simantics.g2d.stubs.anim.Interpolator[3]; + org.simantics.g2d.stubs.anim.Interpolator[] ambient = new org.simantics.g2d.stubs.anim.Interpolator[3]; + org.simantics.g2d.stubs.anim.Interpolator[] diffuse = new org.simantics.g2d.stubs.anim.Interpolator[3]; + org.simantics.g2d.stubs.anim.Interpolator[] specular = new org.simantics.g2d.stubs.anim.Interpolator[3]; + org.simantics.g2d.stubs.anim.Interpolator[] emissive = new org.simantics.g2d.stubs.anim.Interpolator[3]; + + Builtins builtins = graph.getBuiltins(); + + + for (org.simantics.g2d.stubs.anim.Interpolator i : handled) { + IEntity target = i.getTarget(); + //if (target.isInstanceOf(Resources.g3dResource.LocalOrientation)) { + if (target.isInstanceOf(Resources.g3dResource.Orientation) && target.getRelatedObjects(Resources.g3dResource.LocalOrientationOf).size() == 1) { + SlerpInterpolator si = new SlerpInterpolator((SlerpCurve)Resources.curveBuilder.loadInterpolator(i)); + si.setTarget(transform); + this.animation.addInterpolator(si); + } else if (target.isInstanceOf(builtins.Double)) { + Resource targetResource = target.getResource(); + Collection p = target.getRelatedObjects(builtins.PropertyOf); + if (p.size() == 1) { + IEntity parent = p.iterator().next(); + //if (parent.isInstanceOf(Resources.g3dResource.LocalPosition)) { + if (parent.isInstanceOf(Resources.g3dResource.Position) && parent.getRelatedObjects(Resources.g3dResource.LocalPositionOf).size() == 1) { + if (parent.getSingleRelatedObject(Resources.g3dResource.HasX).getResource().equals(targetResource)) { + pos[0] = i; + } else if (parent.getSingleRelatedObject(Resources.g3dResource.HasY).getResource().equals(targetResource)) { + pos[1] = i; + } else if (parent.getSingleRelatedObject(Resources.g3dResource.HasZ).getResource().equals(targetResource)) { + pos[2] = i; + } else { + ErrorLogger.getDefault().logWarning("Cannot map animation interpolator " + i.getResource() + " to target (Position ?)" + target.getResource(), null); + } + } else if (parent.isInstanceOf(Resources.g3dResource.Color)) { + org.simantics.g2d.stubs.anim.Interpolator[] color = null; + if (parent.isInstanceOf(Resources.g3dResource.Color) && parent.getRelatedObjects(Resources.g3dResource.AmbientColorOf).size() > 0) { + color = ambient; + } else if (parent.isInstanceOf(Resources.g3dResource.Color)&& parent.getRelatedObjects(Resources.g3dResource.DiffuseColorOf).size() > 0) { + color = diffuse; + } else if (parent.isInstanceOf(Resources.g3dResource.Color) && parent.getRelatedObjects(Resources.g3dResource.SpecularColorOf).size() > 0) { + color = specular; + } else if (parent.isInstanceOf(Resources.g3dResource.Color) && parent.getRelatedObjects(Resources.g3dResource.EmissiveColorOf).size() > 0) { + color = emissive; + } else { + ErrorLogger.getDefault().logWarning("Cannot map animation interpolator " + i.getResource() + " to target (Color)" + target.getResource() + " unknown color type", null); + } + if (color != null) { + if (parent.getSingleRelatedObject(Resources.g3dResource.HasRed).getResource().equals(targetResource)) { + color[0] = i; + } else if (parent.getSingleRelatedObject(Resources.g3dResource.HasGreen).getResource().equals(targetResource)) { + color[1] = i; + } else if (parent.getSingleRelatedObject(Resources.g3dResource.HasBlue).getResource().equals(targetResource)) { + color[2] = i; + } else { + ErrorLogger.getDefault().logWarning( + "Cannot map animation interpolator " + i.getResource() + + " to target (Color ?)" + target.getResource(), null); + } + } + } else if (parent.isInstanceOf(Resources.g3dResource.Material)) { + // TODO : transparency or shininess + } else { + ErrorLogger.getDefault().logWarning("Cannot map animation interpolator " + i.getResource() + " to target" + target.getResource() + " adding it to precalculated interpolators", null); + precalculated.add(i); + } + } else { + if (p.size() == 0) { + ErrorLogger.getDefault().logWarning("Cannot map animation interpolator " + i.getResource() + " to target (Double)" + target.getResource() + " since it is not a part of a property", null); + } else { + ErrorLogger.getDefault().logWarning("Cannot map animation interpolator " + i.getResource() + " to target (Double)" + target.getResource() + " since it acts as a property to more than one entity", null); + } + } + } else { + ErrorLogger.getDefault().logWarning("Cannot map animation interpolator " + i.getResource() + " to target" + target.getResource(), null); + } + } + + if (pos[0] != null || pos[1] != null || pos[2] != null) { + ScalarInterpolator xIp; + ScalarInterpolator yIp; + ScalarInterpolator zIp; + if (pos[0] != null) { + xIp = new TCBInterpolator((TCBCurve)Resources.curveBuilder.loadInterpolator(pos[0])); + } else { + xIp = new ConstantInterpolator(shape.getLocalPosition().getX()[0]); + } + if (pos[1] != null) { + yIp = new TCBInterpolator((TCBCurve)Resources.curveBuilder.loadInterpolator(pos[1])); + } else { + yIp = new ConstantInterpolator(shape.getLocalPosition().getY()[0]); + } + if (pos[2] != null) { + zIp = new TCBInterpolator((TCBCurve)Resources.curveBuilder.loadInterpolator(pos[2])); + } else { + zIp = new ConstantInterpolator(shape.getLocalPosition().getZ()[0]); + } + ChanneledPositionInterpolator ip = new ChanneledPositionInterpolator(xIp,yIp,zIp); + ip.setTarget(transform); + this.animation.addInterpolator(ip); + + } + addColorInterpolator(shape, ambient, ChanneledColorInterpolator.AMBIENT); + addColorInterpolator(shape, diffuse, ChanneledColorInterpolator.DIFFUSE); + addColorInterpolator(shape, emissive, ChanneledColorInterpolator.EMISSIVE); + addColorInterpolator(shape, specular, ChanneledColorInterpolator.SPECULAR); + + if (precalculated.size() == 0) { + preCalc = null; + } else { + preCalc = new Geometry[preCalcSteps+1]; + for (int i = 0; i <= preCalcSteps; i++) { + double delta = ((double)i / (double)preCalcSteps); + // TODO : copy-paste from CSGAnimatorView + // FIXME : does not update transformations (since ContextGraph does not support queries for context dependent values) + for (Interpolator ip : precalculated) { + if (ip.isInstanceOf(Resources.animationResource.ScalarInterpolator)) { + // TODO : creating curve each time when time is set is slow. + // Curve should be cached + TCBCurve c = (TCBCurve)Resources.curveBuilder.loadInterpolator(ip); + double out = c.evaluate(delta); + //Double d = DoubleFactory.create(ip.getTarget()); + //d.setValue(new double[]{out}); + IEntity d = ip.getTarget(); + d.toProperty().setDoubleArray(new double[]{out}); + } else if (ip.isInstanceOf(Resources.animationResource.SlerpInterpolator)) { + // TODO : creating curve each time when time is set is slow. + // Curve should be cached + SlerpCurve c = (SlerpCurve)Resources.curveBuilder.loadInterpolator(ip); + Quat4d out = c.evaluate(delta); + Orientation r = new Orientation(ip.getTarget()); + AxisAngle4d aa = new AxisAngle4d(); + aa.set(out); + G3DTools.setOrientation(r, aa); + } + } + preCalc[i] = getGeometry(graph,false)[0]; + preCalc[i].setIsCollidable(false); + AppearanceTools.copyMaterial(mesh, preCalc[i]); + } + + // We'll have to remove original (non-animated) shape from the node + mesh.removeFromParent(); + body.attachChild(preCalc[0]); + + } + return true; + } + + private void addColorInterpolator(G3DNode shape, org.simantics.g2d.stubs.anim.Interpolator[] color, int type) { + if (color[0] != null || color[1] != null || color[2] != null) { + ScalarInterpolator xIp; + ScalarInterpolator yIp; + ScalarInterpolator zIp; + Color col = null; + Collection appearanceResource = shape.getRelatedObjects(Resources.g3dResource.HasAppearance); + if (appearanceResource.size() == 0) { + ErrorLogger.getDefault().logWarning("Cannot create interpolator for color because shape " + shape.getResource() + " has no appearance", null); + } + Appearance a = new Appearance(shape.getGraph(),appearanceResource.iterator().next().getResource()); + switch (type) { + case ChanneledColorInterpolator.AMBIENT: + col = a.getMaterial().getAmbientColor(); + break; + case ChanneledColorInterpolator.DIFFUSE: + col = a.getMaterial().getDiffuseColor(); + break; + case ChanneledColorInterpolator.EMISSIVE: + col = a.getMaterial().getEmissiveColor(); + break; + case ChanneledColorInterpolator.SPECULAR: + col = a.getMaterial().getSpecularColor(); + break; + default: + ErrorLogger.defaultLogError("Unknown color type", null); + return; + } + + if (color[0] != null) { + xIp = new TCBInterpolator((TCBCurve)Resources.curveBuilder.loadInterpolator(color[0]));//CurveUtils.loadCurve(color[0].getResource())); + } else { + xIp = new ConstantInterpolator(col.getRed()[0]); + } + if (color[1] != null) { + yIp = new TCBInterpolator((TCBCurve)Resources.curveBuilder.loadInterpolator(color[1]));//CurveUtils.loadCurve(color[1].getResource())); + } else { + yIp = new ConstantInterpolator(col.getGreen()[0]); + } + if (color[1] != null) { + zIp = new TCBInterpolator((TCBCurve)Resources.curveBuilder.loadInterpolator(color[2]));//CurveUtils.loadCurve(color[2].getResource())); + } else { + zIp = new ConstantInterpolator(col.getBlue()[0]); + } + ChanneledColorInterpolator ip = new ChanneledColorInterpolator(xIp,yIp,zIp); + ip.setType(type); + ip.setTarget(mesh.getRenderState(RenderState.RS_MATERIAL)); + this.animation.addInterpolator(ip); + } + } + + public boolean setRandomAnimation(Graph graph) { + return false; + } + + public void dispose() { +// mesh.clearBuffers(); +// mesh.clearBatches(); +// lines.clearBuffers(); +// lines.clearBatches(); + if (mesh != null) { + mesh.removeFromParent(); + mesh.dispose(); + mesh = null; + } + if (lines != null) { + lines.removeFromParent(); + lines.dispose(); + lines = null; + } + super.dispose(); + } +} \ No newline at end of file diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/shapes/AxesShape.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/shapes/AxesShape.java new file mode 100644 index 00000000..461087cb --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/shapes/AxesShape.java @@ -0,0 +1,51 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.shapes; + +import com.jme.renderer.ColorRGBA; +import com.jme.renderer.Renderer; +import com.jme.scene.Geometry; +import com.jme.scene.Line; +import com.jme.scene.state.MaterialState; +import com.jme.util.geom.BufferUtils; + +public class AxesShape { + + + public static Geometry getShape(Renderer renderer) { + float[] coords = new float[]{0.f,0.f,0.f, + 1.f,0.f,0.f, + 0.f,0.f,0.f, + 0.f,1.f,0.f, + 0.f,0.f,0.f, + 0.f,0.f,1.f}; + float colors[] = new float[]{1.f,0.f,0.f,0.f, + 1.f,0.f,0.f,0.f, + 0.f,1.f,0.f,0.f, + 0.f,1.f,0.f,0.f, + 0.f,0.f,1.f,0.f, + 0.f,0.f,1.f,0.f}; + + + Line shape = new Line("",BufferUtils.createFloatBuffer(coords),null,BufferUtils.createFloatBuffer(colors),null); + shape.setMode(Line.SEGMENTS); + shape.setIsCollidable(false); + shape.setLineWidth(3.f); + MaterialState ms = renderer.createMaterialState(); + ms.setColorMaterial(MaterialState.CM_EMISSIVE); + ms.setEmissive(new ColorRGBA(1.f,1.f,1.f,1.f)); + shape.setRenderState(ms); + + return shape; + + } + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/shapes/FloorShape.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/shapes/FloorShape.java new file mode 100644 index 00000000..cd289ad5 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/shapes/FloorShape.java @@ -0,0 +1,91 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.shapes; + +import java.net.URL; + +import org.eclipse.core.runtime.FileLocator; +import org.eclipse.core.runtime.Path; + +import com.jme.image.Texture; +import com.jme.renderer.ColorRGBA; +import com.jme.renderer.Renderer; +import com.jme.scene.Geometry; +import com.jme.scene.TriMesh; +import com.jme.scene.state.MaterialState; +import com.jme.scene.state.TextureState; +import com.jme.util.TextureManager; +import com.jme.util.geom.BufferUtils; + +public class FloorShape { + + private static String textureLocation = "src/jmetest/data/texture/Detail.jpg"; + + public static Geometry getShape(Renderer renderer, float size, float texScale) { + + float coords[] = new float[3 * 4]; + float normals[] = new float[3 * 4]; + float texcoords[] = new float[2 * 4]; + int indices[] = new int[] { 0, 2, 1, 1, 2, 3 }; + coords[0] = -size; + coords[1] = 0.f; + coords[2] = -size; + coords[3] = size; + coords[4] = 0.f; + coords[5] = -size; + coords[6] = -size; + coords[7] = 0.f; + coords[8] = size; + coords[9] = size; + coords[10] = 0.f; + coords[11] = size; + texcoords[0] = -size*texScale; + texcoords[1] = -size*texScale; + texcoords[2] = size*texScale; + texcoords[3] = -size*texScale; + texcoords[4] = -size*texScale; + texcoords[5] = size*texScale; + texcoords[6] = size*texScale; + texcoords[7] = size*texScale; + normals[0] = 0.f; + normals[1] = 1.f; + normals[2] = 0.f; + normals[3] = 0.f; + normals[4] = 1.f; + normals[5] = 0.f; + normals[6] = 0.f; + normals[7] = 1.0f; + normals[8] = 0.f; + normals[9] = 0.f; + normals[10] = 1.f; + normals[11] = 0.f; + + TriMesh shape = new TriMesh("",BufferUtils.createFloatBuffer(coords),BufferUtils.createFloatBuffer(normals),null,BufferUtils.createFloatBuffer(texcoords),BufferUtils.createIntBuffer(indices)); + MaterialState ms = renderer.createMaterialState(); + ms.setEmissive(new ColorRGBA(0.5f,0.5f,0.5f,0.f)); + ms.setDiffuse(new ColorRGBA(1.f,1.f,1.f,0.f)); + ms.setShininess(128.f); + shape.setRenderState(ms); + shape.setCullMode(Geometry.CULL_NEVER); + + TextureState ts = renderer.createTextureState(); + URL url = FileLocator.find(com.jme.eclipse.Activator.getDefault().getBundle(),new Path(textureLocation),null); + Texture tex = TextureManager.loadTexture(url, Texture.MM_LINEAR_LINEAR, + Texture.FM_LINEAR); + tex.setWrap(Texture.WM_WRAP_S_WRAP_T); + ts.setTexture(tex); + shape.setRenderState(ts); + shape.lockShadows(); + return shape; + + } + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/shapes/GridShape.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/shapes/GridShape.java new file mode 100644 index 00000000..284b357e --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/shapes/GridShape.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.shapes; + +import com.jme.renderer.ColorRGBA; +import com.jme.renderer.Renderer; +import com.jme.scene.Geometry; +import com.jme.scene.Line; +import com.jme.scene.state.MaterialState; +import com.jme.util.geom.BufferUtils; + +public class GridShape { + + + public static Geometry getShape(Renderer renderer, int lineCount, float delta) { + + float[] coords = new float[lineCount*lineCount*2*3]; + float size = delta * lineCount; + float halfSize = size * 0.5f; + + for (int i = 0 ; i <= lineCount; i++) { + int index = i*3*2; + coords[index++] = -halfSize + i * delta; + coords[index++] = 0.f; + coords[index++] = -halfSize; + coords[index++] = -halfSize + i * delta; + coords[index++] = 0.f; + coords[index++] = +halfSize; + } + for (int i = 0 ; i <= lineCount; i++) { + int index = (i + lineCount + 1)*3*2; + coords[index++] = -halfSize; + coords[index++] = 0.f; + coords[index++] = -halfSize + i * delta; + coords[index++] = +halfSize; + coords[index++] = 0.f; + coords[index++] = -halfSize + i * delta; + } + + Line shape = new Line("",BufferUtils.createFloatBuffer(coords),null,null,null); + MaterialState ms = renderer.createMaterialState(); + ms.setEmissive(new ColorRGBA(1.f,1.f,1.f,0.f)); + shape.setRenderState(ms); + shape.setCullMode(Geometry.CULL_NEVER); + return shape; + + } + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/shapes/Quad.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/shapes/Quad.java new file mode 100644 index 00000000..cab5e37e --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/shapes/Quad.java @@ -0,0 +1,130 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.shapes; + +import java.nio.FloatBuffer; + +import com.jme.math.Vector3f; +import com.jme.renderer.ColorRGBA; +import com.jme.scene.TriMesh; +import com.jme.scene.batch.TriangleBatch; +import com.jme.util.geom.BufferUtils; + +public class Quad extends TriMesh { + + private static final long serialVersionUID = 1L; + + public Quad() { + + } + + /** + * Constructor creates a new Quad object. That data for the + * Quad is not set until a call to initialize + * is made. + * + * @param name + * the name of this Quad. + */ + public Quad(String name) { + super(name); + } + + /** + * Constructor creates a new Quade object with the provided + * width and height. + * + * @param name + * the name of the Quad. + * @param width + * the width of the Quad. + * @param height + * the height of the Quad. + */ + public Quad(String name, float width, float height) { + super(name); + initialize(width, height); + } + + /** + * resize changes the width and height of the given quad by + * altering its vertices. + * + * @param width + * the new width of the Quad. + * @param height + * the new height of the Quad. + */ + public void resize(float width, float height) { + TriangleBatch batch = getBatch(0); + batch.getVertexBuffer().clear(); + batch.getVertexBuffer().put(-width / 2f).put(height / 2f).put(0); + batch.getVertexBuffer().put(-width / 2f).put(-height / 2f).put(0); + batch.getVertexBuffer().put(width / 2f).put(-height / 2f).put(0); + batch.getVertexBuffer().put(width / 2f).put(height / 2f).put(0); + } + + /** + * + * initialize builds the data for the Quad + * object. + * + * + * @param width + * the width of the Quad. + * @param height + * the height of the Quad. + */ + public void initialize(float width, float height) { + TriangleBatch batch = getBatch(0); + batch.setVertexCount(4); + batch.setVertexBuffer(BufferUtils.createVector3Buffer(batch.getVertexCount())); + batch.setNormalBuffer(BufferUtils.createVector3Buffer(batch.getVertexCount())); + FloatBuffer tbuf = BufferUtils.createVector2Buffer(batch.getVertexCount()); + setTextureBuffer(0,tbuf); + batch.setTriangleQuantity(2); + batch.setIndexBuffer(BufferUtils.createIntBuffer(batch.getTriangleCount() * 3)); + + batch.getVertexBuffer().put(-width / 2f).put(height / 2f).put(0); + batch.getVertexBuffer().put(-width / 2f).put(-height / 2f).put(0); + batch.getVertexBuffer().put(width / 2f).put(-height / 2f).put(0); + batch.getVertexBuffer().put(width / 2f).put(height / 2f).put(0); + + batch.getNormalBuffer().put(0).put(0).put(1); + batch.getNormalBuffer().put(0).put(0).put(1); + batch.getNormalBuffer().put(0).put(0).put(1); + batch.getNormalBuffer().put(0).put(0).put(1); + + + tbuf.put(0).put(0); + tbuf.put(0).put(1); + tbuf.put(1).put(1); + tbuf.put(1).put(0); + + setDefaultColor(ColorRGBA.white); + + batch.getIndexBuffer().put(0); + batch.getIndexBuffer().put(1); + batch.getIndexBuffer().put(2); + batch.getIndexBuffer().put(0); + batch.getIndexBuffer().put(2); + batch.getIndexBuffer().put(3); + } + + /** + * getCenter returns the center of the Quad. + * + * @return Vector3f the center of the Quad. + */ + public Vector3f getCenter() { + return worldTranslation; + } +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/tools/OEPathSelectionListener.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/tools/OEPathSelectionListener.java new file mode 100644 index 00000000..1af0908d --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/tools/OEPathSelectionListener.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.tools; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.simantics.layer0.utils.viewpoints.TraversalPath; +import org.simantics.proconf.browsing.MutableCachedGraphTreeNode; + +/** + * SelectionListener for OntologyExplorer + * + * Returns Selection as TraversalPath + * + * @author Marko Luukkainen + * + */ +public abstract class OEPathSelectionListener implements ISelectionChangedListener{ + @SuppressWarnings("unchecked") + public void selectionChanged(SelectionChangedEvent event) { + IStructuredSelection s = (IStructuredSelection)event.getSelection(); + List paths = new ArrayList(); + Iterator i = s.iterator(); + while(i.hasNext()) { + MutableCachedGraphTreeNode node = i.next(); + TraversalPath path = (TraversalPath)node.getObject(); + paths.add(path); + } + pathSelectionUpdated(paths); + } + + protected abstract void pathSelectionUpdated(List paths); +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/tools/OESelectionListener.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/tools/OESelectionListener.java new file mode 100644 index 00000000..54e4619b --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/tools/OESelectionListener.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.tools; + +import java.util.Iterator; + +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.simantics.db.Resource; +import org.simantics.proconf.browsing.providers.TreeObject; +import org.simantics.proconf.g3d.common.StructuredResourceSelection; + +/** + * SelectionListener for OntologyExplorer + * + * Returns selection as StrcturedResourceSelection + * + * @author Marko Luukkainen + * + */ +public abstract class OESelectionListener implements ISelectionChangedListener { + @SuppressWarnings("unchecked") + public void selectionChanged(SelectionChangedEvent event) { + IStructuredSelection s = (IStructuredSelection)event.getSelection(); + StructuredResourceSelection sel = new StructuredResourceSelection(); + Iterator i = s.iterator(); + while(i.hasNext()) { + TreeObject node = i.next(); + sel.add((Resource)node.getAdapter(Resource.class)); + } + resourceSelectionUpdated(sel); + } + + protected abstract void resourceSelectionUpdated(StructuredResourceSelection selection); +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/tools/PropertyTree.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/tools/PropertyTree.java new file mode 100644 index 00000000..ea7f62db --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/tools/PropertyTree.java @@ -0,0 +1,313 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.tools; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Tree; +import org.eclipse.swt.widgets.TreeItem; +import org.simantics.db.Builtins; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Resource; +import org.simantics.db.Session; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.layer0.utils.ResourceDebugUtils; +import org.simantics.layer0.utils.Statement; +import org.simantics.proconf.g3d.common.StructuredResourceSelection; + +/** + * PropertyTree finds common properties for set of objects, and + * then based on user's selection returns all property instances. + * + * @author Marko Luukkainen + * + */ +public class PropertyTree { + private Tree tree; + private Session session; + + + public PropertyTree(Tree tree, Session session) { + this.tree = tree; + this.session = session; + } + + public void setProperties(List selectedInstances) { + tree.removeAll(); + addProperties(null,selectedInstances); + tree.redraw(); + } + + public void setProperties(StructuredResourceSelection selection) { + ArrayList selectedInstances = new ArrayList(); + for (Resource r : selection.getSelectionList()) { + if (!contains(selectedInstances,r)) { + selectedInstances.add(r); + + //System.out.println("Added " + name.getName()); + } else { + + // System.out.println("Discarded " + name.getName()); + } + } + setProperties(selectedInstances); + } + + public Tree getTree() { + return tree; + } + + private void addProperties(final TreeItem parent, final List selectedInstances) { + session.asyncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + Builtins builtins = g.getBuiltins(); + ArrayList relationTypes = new ArrayList(); + for (Resource resource : selectedInstances) { + IEntity thing = EntityFactory.create(g, resource); + + Collection properties = thing.getRelatedStatements(builtins.HasProperty); + // RelationSet properties = resource.getRelatedResourcesWithRelationIds(GlobalIdMap.get(Builtins.HasProperty)); + + for (Statement r : properties) { + // Statement contains relation from instance to property(instance) + // Find the property's type(s) + // TODO : seems to be bad way of finding type + Collection types = r.getObject().getRelatedObjects(builtins.InstanceOf); + if (types.size() != 1) + throw new UnsupportedOperationException("Cannot support multi-instances"); + IEntity type = types.iterator().next(); + if (!contains(relationTypes, r.getPredicate().getResource())) { + + if (type.isInheritedFrom(builtins.Double)) { + + relationTypes.add(r.getPredicate().getResource()); + + //System.out.println("Added " + name.getName() + " " + type.getId() + " " + r.getRelationId() + " " + relationType.getId()); + final String name = getNameForThing(r.getPredicate());//getNameForThing(thing); + final Object treeData = r.getPredicate().getResource(); + Display.getDefault().asyncExec(new Runnable() { + //parent.getDisplay().asyncExec(new Runnable() { + TreeItem item = null; + @Override + public void run() { + if (parent != null) + item = new TreeItem(parent,SWT.NONE); + else + item = new TreeItem(tree,SWT.NONE); + item.setData(treeData); + item.setText(name); + + } + }); + + } else { + //Resource pproperties[] = r.getRelatedResources(GlobalIdMap.get(Builtins.PropertyRelationType)); + //Resource pproperties[] = resource.get(r.getObjectId()).getRelatedResources(GlobalIdMap.get(Builtins.HasProperty)); + Collection pproperties = r.getObject().getRelatedObjects(builtins.HasProperty); + if (pproperties.size() > 0) { + final ArrayList list = new ArrayList(); + list.add(r.getObject().getResource()); + + final String name = getNameForThing(r.getPredicate());//getNameForThing(thing); + final Object treeData = r.getPredicate().getResource(); + relationTypes.add(r.getPredicate().getResource()); + Display.getDefault().asyncExec(new Runnable() { + //parent.getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + TreeItem item = null; + if (parent != null) + item = new TreeItem(parent, SWT.NONE); + else + item = new TreeItem(tree, SWT.NONE); + item.setText(name); + item.setData(treeData); + addProperties(item,list); + } + }); + } + } + } + } + } + return GraphRequestStatus.transactionComplete(); + } + }); + + } + + private String getNameForThing(IEntity thing) { + return ResourceDebugUtils.getReadableNameForEntity(thing); + /* + String tName = thing.getName(); + if (tName == null) { + Collection ptypes = thing.getTypes(); + for (Thing pt : ptypes) { + tName = pt.getName(); + if (tName != null) + break; + } + } + if (tName == null) + return "Error / no name for " + thing; + return tName; + */ + } + + private boolean contains(java.util.List list, Resource value) { + for (int i = 0; i < list.size(); i++) { + if (list.get(i).equals(value)) + return true; + } + return false; + } + + /** + * Returns all properties (instances) contained in the list depending on selection in the tree and + * TODO : currently can be run only in UI -thread with transaction. + * + * @param graph + * @param shapes + * @return + */ + public List findLeafPropertyInstances(Graph graph,List shapes) { + TreeItem[] selectedProperties = tree.getSelection(); + List props = new ArrayList(); + for (TreeItem propertyItem : selectedProperties) { + + TreeItem t = propertyItem; + boolean c = false; + // if list contains treeNode's parent, node's property is already mapped / will be mapped later + while (t.getParentItem() != null) { + if (contains(selectedProperties, t.getParentItem())) { + c = true; + break; + } + t = t.getParentItem(); + + } + if (!c) { + props.addAll(findLeafProperties(graph,shapes, propertyItem)); + } + } + return props; + } + + public List findPropertyInstances(Graph graph,List shapes) { + TreeItem[] selectedProperties = tree.getSelection(); + List props = new ArrayList(); + for (TreeItem propertyItem : selectedProperties) { + + TreeItem t = propertyItem; + boolean c = false; + // if list contains treeNode's parent, node's property is already mapped / will be mapped later + while (t.getParentItem() != null) { + if (contains(selectedProperties, t.getParentItem())) { + c = true; + break; + } + t = t.getParentItem(); + + } + if (!c) { + props.addAll(findProperties(graph,shapes, propertyItem)); + } + } + return props; + } + + private List findProperties(Graph graph,java.util.List shapes, TreeItem propertyItem) { + ArrayList propertyChain = new ArrayList(); + TreeItem t = propertyItem; + while (t != null) { + propertyChain.add((Resource) t.getData()); + t = t.getParentItem(); + } + + return findProperties(graph,shapes,propertyChain); + + } + + private List findLeafProperties(Graph graph,java.util.List shapes, TreeItem propertyItem) { + ArrayList propertyChain = new ArrayList(); + TreeItem t = propertyItem; + while (t != null) { + propertyChain.add((Resource)t.getData()); + t = t.getParentItem(); + } + // now propertyChain contains property hierarchy from leaf to root + //Long typeID = (Long) propertyItem.getData(); + if (propertyItem.getItemCount() == 0) { + return findProperties(graph,shapes,propertyChain); + } else { + List props = new ArrayList(); + //Long typeID = (Long) propertyItem.getData(); + TreeItem children[] = propertyItem.getItems(); + //ArrayList props = getPropertiesForType(shapes, typeID); + for (TreeItem i : children) + //mapProperty(parameter,props, i); + props.addAll(findLeafProperties(graph,shapes, i)); + return props; + } + } + + private List findProperties(Graph graph, java.util.List shapes, ArrayList propertyChain) { + ArrayList res = new ArrayList(shapes); + // propertyChain contains hierarhy of properties form leaf to root : + // we'll find root property from shapes and then iterate each property instance + // until we'll fin all requested properties (first element in property chain) + +// System.out.print("instances "); +// for (Resource r : res) { +// System.out.print(r + " "); +// } +// System.out.println(); + + while (propertyChain.size() > 0) { + res = getPropertiesForType(graph, res, propertyChain.get(propertyChain.size() - 1)); +// System.out.print(propertyChain.get(propertyChain.size() - 1) +" instances "); +// for (Resource r : res) { +// System.out.print(r + " "); +// } +// System.out.println(); + propertyChain.remove(propertyChain.size() - 1); + } + // now res contains all instances of requested property + return res; + } + + private ArrayList getPropertiesForType(Graph graph,java.util.List instances, Resource typeID) { + ArrayList properties = new ArrayList(); + for (Resource instance : instances) { + IEntity t = EntityFactory.create(graph,instance); + Collection props = t.getRelatedObjects(typeID); + for (IEntity p : props) + properties.add(p.getResource()); + + } + return properties; + } + + private boolean contains(TreeItem items[], TreeItem item) { + for (TreeItem i : items) + if (i.equals(item)) + return true; + return false; + } +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/tools/ScenegraphLockTraverser.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/tools/ScenegraphLockTraverser.java new file mode 100644 index 00000000..c3bf357d --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/tools/ScenegraphLockTraverser.java @@ -0,0 +1,32 @@ +package org.simantics.proconf.g3d.tools; + +import java.util.ArrayList; + +import com.jme.scene.Node; +import com.jme.scene.Spatial; + +public class ScenegraphLockTraverser { + Node root; + boolean lock; + public ScenegraphLockTraverser(Node root, boolean lock) { + this.root = root; + this.lock = lock; + lock(root); + } + + private void lock(Spatial spatial) { + if (lock) + spatial.lock(); + else + spatial.unlock(); + if (spatial instanceof Node) { + Node node = (Node)spatial; + ArrayList children = node.getChildren(); + for (Spatial s : children) { + s.lock(); + lock(s); + } + } + + } +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/views/AppearanceEditor.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/views/AppearanceEditor.java new file mode 100644 index 00000000..69170787 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/views/AppearanceEditor.java @@ -0,0 +1,1146 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.views; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; + +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.MouseAdapter; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.RGB; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.ColorDialog; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Slider; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.IWorkbenchPart; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Resource; +import org.simantics.layer0.utils.IEntity; +import org.simantics.layer0.utils.StubLinkedList; +import org.simantics.layer0.utils.internal.Entity; +import org.simantics.proconf.g3d.Resources; +import org.simantics.proconf.g3d.base.AppearanceTools; +import org.simantics.proconf.g3d.stubs.Appearance; +import org.simantics.proconf.g3d.stubs.ImageTexture; +import org.simantics.proconf.g3d.stubs.Material; +import org.simantics.proconf.g3d.stubs.MultiTexture; +import org.simantics.proconf.g3d.stubs.Shader; +import org.simantics.proconf.g3d.stubs.Texture; +import org.simantics.proconf.g3d.stubs.TextureCoordinateGenerator; +import org.simantics.proconf.image.ImageUtils; +import org.simantics.proconf.image.interfaces.IImage; +import org.simantics.proconf.image.interfaces.IImageFactory; +import org.simantics.proconf.image.ui.ImageComposite; +import org.simantics.proconf.ui.utils.ResourceAdaptionUtils; +import org.simantics.utils.ErrorLogger; + + +public class AppearanceEditor extends SinglePageResourceView{ + + //Appearance appearance; + Resource shapeResource; + Resource appearanceResource; + + private enum EditorState{NONE,NO_SHAPE,NO_APPEARANCE, APPEARANCE}; + EditorState state = EditorState.NONE; + + Button materialButton; + + Composite ambientComposite; + Composite diffuseComposite; + Composite specularComposite; + Composite emissiveComposite; + Slider specularSlider; + Slider transparencySlider; + + + Composite textureParent; + + Button textureButton; + Button addTextureButton; + + + //Image image = null; + + boolean updating = false; + + private ArrayList textureComposites = new ArrayList(); + + Button shaderButton; + Text fragmentShaderText; + Text vertexShaderText; + + Button apply3Button; + Button apply2Button; + Button applyButton; + + public AppearanceEditor() { + super(); + //super(Activator.PLUGIN_ID); + + } + + @Override + public void createPartControl(Composite parent) { + super.createPartControl(parent); + createWidgets(); + } + + @Override + protected String getFormText() { + return "Appearance Editor"; + } + +// @Override +// protected void beforeCreateWidgets() { +// if (!(getInputResource().isInstanceOf(GlobalIdMap.get(ThreeDimensionalModelingOntologyMapping.APPEARANCE)))) +// throw new RuntimeException("Trying to open resource that is not appearance"); +// appearance = AppearanceFactory.create(getInputResource()); +// } + + + + @Override + protected void createWidgets() { + + if (shapeResource == null) { + if (state != EditorState.NO_SHAPE) { + clearForm(); + state = EditorState.NO_SHAPE; + toolkit.createLabel(getBody(), "No shape selected"); + getActiveForm().layout(true, true); + } + } else if (appearanceResource == null){ + if (state != EditorState.NO_APPEARANCE) { + clearForm(); + state = EditorState.NO_APPEARANCE; + toolkit.createLabel(getBody(), "Selected shape does not have material definition."); + Button b = toolkit.createButton(getBody(), "Create Appearance", SWT.PUSH); + b.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + getSession().asyncWrite(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + Appearance appearance = Appearance.createDefault(g); + appearanceResource = appearance.getResource(); + g.addStatement(shapeResource, Resources.g3dResource.HasAppearance, appearanceResource); + return GraphRequestStatus.transactionComplete(); + } + + @Override + public void requestCompleted( GraphRequestStatus status) { + reloadInUIThread(); + } + }); + + } + }); + getActiveForm().layout(true, true); + } + } else { + if (state != EditorState.APPEARANCE) { + clearForm(); + state = EditorState.APPEARANCE; + createMaterialGroup(newGridSection(2, 2, false, false, "Material", "Material properties")); + createTextureGroup(newGridSection(1, 1, false, false, "Texture", "Texture properties")); + createShaderGroup(newGridSection(2, 2, false, false, "Shader", "Shader properties")); + getActiveForm().layout(true, true); + } + + } + } + + @Override + public void clearForm() { + super.clearForm(); + textureComposites.clear(); + } + + @Override + protected void pageSelectionChanged(IWorkbenchPart part, ISelection selection) { + Resource res[] = ResourceAdaptionUtils.toResources(selection); + if (res.length == 0) { + shapeResource = null; + appearanceResource = null; + reload(); + return; + } + final Resource sel = res[0]; + if (sel.equals(shapeResource)) + return; + //System.out.println("AppearanceEditor.pageSelectionChanged"); + getSession().asyncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + + shapeResource = null; + appearanceResource = null; + // selected object must be a shape + if (!g.isInstanceOf(sel, Resources.g3dResource.Shape)) { + return GraphRequestStatus.transactionCancel(); + } + // the shape must not be ah geometry definition + if (g.getObjects(sel, Resources.g3dResource.GeometryDefinitionOf).size() > 0) + return GraphRequestStatus.transactionCancel(); + + shapeResource = sel; + Collection res = g.getObjects(shapeResource, Resources.g3dResource.HasAppearance); + if (res.size() == 1) + appearanceResource = res.iterator().next(); + return GraphRequestStatus.transactionComplete(); + } + + @Override + public void requestCompleted(GraphRequestStatus status) { + reloadInUIThread(); + } + }); + } + + public void reloadInUIThread() { + parent.getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + reload(); + } + }); + } + + public void reload() { + if (updating) + return; + createWidgets(); + if (state == EditorState.APPEARANCE) { + getSession().asyncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + reload(g); + return GraphRequestStatus.transactionComplete(); + } + }); + } + } + + @Override + public void reload(Graph g) { + if (updating) + return; + if (state != EditorState.APPEARANCE) { + return; + } + Appearance appearance = new Appearance(g,appearanceResource); + Material m = appearance.getMaterial(); + Texture t = appearance.getTexture(); + Shader s = appearance.getShader(); + loadMaterial(m); + loadTexture(t); + loadShader(s); + + + } + + private void loadMaterial(Material m) { + final boolean hasMaterial; + final Color ambient; + final Color diffuse; + final Color specular; + final Color emissive; + final int shininess; + final int transparency; + if (m == null) { + hasMaterial = false; + ambient = null; + diffuse = null; + specular = null; + emissive = null; + shininess = 0; + transparency = 0; + } else { + hasMaterial = true; + ambient = AppearanceTools.getColor(m.getAmbientColor(), this.getBody().getDisplay()); + diffuse = AppearanceTools.getColor(m.getDiffuseColor(), this.getBody().getDisplay()); + specular = AppearanceTools.getColor(m.getSpecularColor(), this.getBody().getDisplay()); + emissive = AppearanceTools.getColor(m.getEmissiveColor(), this.getBody().getDisplay()); + shininess = (int)m.getShininess()[0]; + transparency = (int)(m.getTransparency()[0]*100.0); + } + parent.getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + boolean t = hasMaterial; + materialButton.setSelection(t); + ambientComposite.setEnabled(t); + diffuseComposite.setEnabled(t); + specularComposite.setEnabled(t); + emissiveComposite.setEnabled(t); + specularSlider.setEnabled(t); + transparencySlider.setEnabled(t); + if (hasMaterial) { + ambientComposite.setBackground(ambient); + diffuseComposite.setBackground(diffuse); + specularComposite.setBackground(specular); + emissiveComposite.setBackground(emissive); + specularSlider.setSelection(shininess); + transparencySlider.setSelection(transparency); + } else { + Color c = parent.getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY); + ambientComposite.setBackground(c); + diffuseComposite.setBackground(c); + specularComposite.setBackground(c); + emissiveComposite.setBackground(c); + } + + }; + }); + + } + + private void loadTexture(Texture t) { + //System.out.println("AppearanceEditor.loadTexture"); + if (t == null) { + parent.getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + textureButton.setSelection(false); + } + }); + + return; + } + parent.getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + textureButton.setSelection(true); + } + }); + + if (t.isInstanceOf(Resources.g3dResource.ImageTexture)) { + //final ImageTexture t2 = new ImageTexture(t); + final Resource t2 = t.getResource(); + parent.getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + while (textureComposites.size() > 1) { + textureComposites.remove(textureComposites.size()-1).dispose(); + } + if (textureComposites.size() == 0) { + textureComposites.add(new TextureComposite(textureParent,SWT.NONE)); + } + getSession().asyncWrite(new GraphRequestAdapter() { + public GraphRequestStatus perform(Graph g) throws Exception { + try { + textureComposites.get(0).update(new ImageTexture(g,t2)); + } catch (Exception e) { + ErrorLogger.defaultLogError(e); + } + return GraphRequestStatus.transactionComplete(); + }; + + }); + } + }); + + + } else if (t.isInstanceOf(Resources.g3dResource.MultiTexture)) { + + MultiTexture mt = new MultiTexture(t); + StubLinkedList elements = new StubLinkedList(mt.getMultiTextureElementList()); + final Resource listResource = mt.getMultiTextureElementList().getResource(); + final int count = elements.size(); + parent.getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + while (textureComposites.size() > count) { + textureComposites.get(textureComposites.size()-1).dispose(); + textureComposites.remove(textureComposites.size()-1); + } + while (textureComposites.size() < count) { + textureComposites.add(new TextureComposite(textureParent,SWT.NONE)); + } + getSession().asyncWrite(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) + throws Exception { + StubLinkedList elements = new StubLinkedList(new Entity(g,listResource)); + Iterator i = elements.iterator(); + int index = 0; + while (i.hasNext()) { + //MultiTextureElement e = new MultiTextureElement(i.next()); + //int index = e.getMultiTextureIndexValue(); + Texture tex = new Texture(i.next());//e.getTexture(); + if (tex.isInstanceOf(Resources.g3dResource.ImageTexture)) { + ImageTexture t2 = new ImageTexture(tex); + try { + textureComposites.get(index).update(t2); + } catch (Exception err) { + ErrorLogger.defaultLogError(err); + } + } + index++; + } + return null; + } + }); + } + }); + + + + } + } + + private void loadShader(Shader s) { + final boolean hasShader = (s != null); + final String vertexShader; + final String fragmentShader; + if (hasShader) { + vertexShader = s.getVertexShader()[0]; + fragmentShader = s.getFragmentShader()[0]; + } else { + vertexShader = null; + fragmentShader = null; + } + parent.getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + if (!hasShader) { + shaderButton.setSelection(false); + } else { + shaderButton.setSelection(true); + vertexShaderText.setText(vertexShader); + fragmentShaderText.setText(fragmentShader); + } + + } + }); + + } + + private void createMaterialGroup(Composite parent) { + toolkit.paintBordersFor(parent); + toolkit.setBorderStyle(SWT.BORDER); + + materialButton = toolkit.createButton(parent, "Has Material", SWT.CHECK); + materialButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + boolean t = materialButton.getSelection(); + ambientComposite.setEnabled(t); + diffuseComposite.setEnabled(t); + specularComposite.setEnabled(t); + emissiveComposite.setEnabled(t); + specularSlider.setEnabled(t); + transparencySlider.setEnabled(t); + + } + }); + GridData data = new GridData(GridData.FILL, GridData.FILL, false, false,2,1); + materialButton.setLayoutData(data); + + data = new GridData(GridData.FILL, GridData.FILL, false, false,1,1); + data.widthHint = 100; + data.heightHint = 20; + + toolkit.createLabel(parent, "Ambient"); + ambientComposite = toolkit.createComposite(parent, SWT.BORDER); + ambientComposite.setLayoutData(data); + ambientComposite.addMouseListener(new MouseAdapter() { + @Override + public void mouseUp(MouseEvent e) { + ColorDialog dialog = new ColorDialog(AppearanceEditor.this.getBody().getShell()); + RGB rgb = dialog.open(); + if (rgb != null) { + ambientComposite.setBackground(new Color(AppearanceEditor.this.getBody().getDisplay(),rgb)); + + } + } + }); + + toolkit.createLabel(parent, "Diffuse"); + diffuseComposite = toolkit.createComposite(parent, SWT.BORDER); + diffuseComposite.setLayoutData(data); + diffuseComposite.addMouseListener(new MouseAdapter() { + @Override + public void mouseUp(MouseEvent e) { + ColorDialog dialog = new ColorDialog(AppearanceEditor.this.getBody().getShell()); + RGB rgb = dialog.open(); + if (rgb != null) { + diffuseComposite.setBackground(new Color(AppearanceEditor.this.getBody().getDisplay(),rgb)); + + } + } + }); + toolkit.createLabel(parent, "Specular"); + specularComposite = toolkit.createComposite(parent, SWT.BORDER); + specularComposite.setLayoutData(data); + specularComposite.addMouseListener(new MouseAdapter() { + @Override + public void mouseUp(MouseEvent e) { + ColorDialog dialog = new ColorDialog(AppearanceEditor.this.getBody().getShell()); + + RGB rgb = dialog.open(); + if (rgb != null) { + specularComposite.setBackground(new Color(AppearanceEditor.this.getBody().getDisplay(),rgb)); + + } + } + }); + toolkit.createLabel(parent, "Emissive"); + emissiveComposite = toolkit.createComposite(parent, SWT.BORDER); + emissiveComposite.setLayoutData(data); + emissiveComposite.addMouseListener(new MouseAdapter() { + @Override + public void mouseUp(MouseEvent e) { + ColorDialog dialog = new ColorDialog(AppearanceEditor.this.getBody().getShell()); + RGB rgb = dialog.open(); + if (rgb != null) { + emissiveComposite.setBackground(new Color(AppearanceEditor.this.getBody().getDisplay(),rgb)); + + } + } + }); + toolkit.createLabel(parent, "Shininess"); + specularSlider = new Slider(parent,SWT.NONE); + specularSlider.setValues(20, 0, 255, 1, 1, 10); + toolkit.adapt(specularSlider, true, true); + toolkit.createLabel(parent, "Transparency"); + transparencySlider = new Slider(parent,SWT.NONE); + transparencySlider.setValues(0, 0, 100, 1, 1, 10); + toolkit.adapt(transparencySlider, true, true); + apply2Button = toolkit.createButton(parent, "Apply", SWT.PUSH); + apply2Button.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + convertMaterial(); + } + }); + + } + + private void createTextureGroup(Composite parent) { + textureParent = parent; + toolkit.paintBordersFor(parent); + toolkit.setBorderStyle(SWT.BORDER); + + textureButton = toolkit.createButton(parent, "Has Texture", SWT.CHECK); + textureButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + //loadImageButton.setEnabled(textureButton.getSelection()); + //imageComposite.setEnabled(textureButton.getSelection()); + //textureButton.setEnabled(textureButton.getSelection()); + + } + }); + + + + textureButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + //loadImageButton.setEnabled(textureButton.getSelection()); + //imageComposite.setEnabled(textureButton.getSelection()); + //textureButton.setEnabled(textureButton.getSelection()); + + } + }); + addTextureButton = toolkit.createButton(parent, "Add Texture", SWT.PUSH); + addTextureButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + textureComposites.add(new TextureComposite(textureParent,SWT.NONE)); + } + }); + applyButton = toolkit.createButton(parent, "Apply", SWT.PUSH); + applyButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + convertImage(); + } + }); + + } + + private void createShaderGroup(Composite parent) { + toolkit.paintBordersFor(parent); + toolkit.setBorderStyle(SWT.BORDER); + GridData data = new GridData(SWT.FILL,SWT.FILL,true,true,2,1); + shaderButton = toolkit.createButton(parent, "Has Shader", SWT.CHECK); + shaderButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + + + } + }); + shaderButton.setLayoutData(data); + data = new GridData(SWT.FILL,SWT.FILL,true,true,1,1); + data.widthHint = 400; + data.heightHint = 200; + toolkit.createLabel(parent, "Vertex Shader"); + vertexShaderText = toolkit.createText(parent,"", SWT.MULTI); + vertexShaderText.setLayoutData(data); + toolkit.createLabel(parent, "Fragment Shader"); + fragmentShaderText = toolkit.createText(parent,"", SWT.MULTI); + fragmentShaderText.setLayoutData(data); + apply3Button = toolkit.createButton(parent, "Apply", SWT.PUSH); + apply3Button.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + convertShader(); + } + }); + } + + + + private void convertShader() { + updating = true; + final boolean hasShader = shaderButton.getSelection(); + final String vertexShader = vertexShaderText.getText(); + final String fragmentShader = fragmentShaderText.getText(); + getSession().asyncWrite(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + Appearance appearance = new Appearance(g,appearanceResource); + if (hasShader) { + Shader s = appearance.getShader(); + if (s == null) { + s = Shader.createDefault(g); + appearance.setShader(s); + + } + s.setVertexShader(vertexShader); + s.setFragmentShader(fragmentShader); + } else { + appearance.setShader(null); + } + + updating = false; + return GraphRequestStatus.transactionComplete(); + } + }); + + + } + + private void convertMaterial() { + updating = true; + + final boolean hasMaterial = materialButton.getSelection(); + final Color ambientColor = ambientComposite.getBackground(); + final Color diffuseColor = diffuseComposite.getBackground(); + final Color specularColor = specularComposite.getBackground(); + final Color emissiveColor = emissiveComposite.getBackground(); + final double shininess = (double)specularSlider.getSelection(); + final double transparency = (double)transparencySlider.getSelection()/ 100.0; + + getSession().asyncWrite(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + Appearance appearance = new Appearance(g,appearanceResource); + if (hasMaterial) { + Material m = appearance.getMaterial(); + if (m == null) { + m = Material.createDefault(g); + } + org.simantics.proconf.g3d.stubs.Color aColor = m.getAmbientColor(); + org.simantics.proconf.g3d.stubs.Color dColor = m.getDiffuseColor(); + org.simantics.proconf.g3d.stubs.Color sColor = m.getSpecularColor(); + org.simantics.proconf.g3d.stubs.Color eColor = m.getEmissiveColor(); + AppearanceTools.setColor(aColor,ambientColor); + AppearanceTools.setColor(dColor,diffuseColor); + AppearanceTools.setColor(sColor, specularColor); + AppearanceTools.setColor(eColor, emissiveColor); + m.setShininess(shininess); + m.setTransparency(transparency); + appearance.setMaterial(m); + } else { + appearance.removeRelatedStatements(Resources.g3dResource.HasMaterial); + } + + updating = false; + return GraphRequestStatus.transactionComplete(); + } + }); + + } + + private void convertImage() { + updating = true; + getSession().syncWrite(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + Appearance appearance = new Appearance(g,appearanceResource); + Texture t = appearance.getTexture(); + if (textureComposites.size() == 1) { + ImageTexture t2 = null; + if (t != null && t.isInstanceOf(Resources.g3dResource.ImageTexture)) { + t2 = new ImageTexture(t); + } else { + t2 = ImageTexture.createDefault(g); + appearance.setTexture(t2); + } + final Resource mode = textureComposites.get(0).getModeType(); + + + if (mode != null) + t2.setTextureMode(mode); + textureComposites.get(0).getTexture(t2); + + } else if (textureComposites.size() > 1) { + MultiTexture mt = null; + if (t != null + && t.isInstanceOf(Resources.g3dResource.MultiTexture)) { + mt = new MultiTexture(t); + } else { + mt = MultiTexture.createDefault(g); + appearance.setTexture(mt); + } + StubLinkedList elements = new StubLinkedList(mt.getMultiTextureElementList()); + //PropertyTypeSet elements = mt.getMultiTextureElementSet(); + Iterator it = elements.iterator(); + for (int i = 0; i < textureComposites.size(); i++) { + TextureComposite tc = textureComposites.get(i); + + ImageTexture tex = null; + if (it.hasNext()) + tex = new ImageTexture(it.next()); + else { + tex = ImageTexture.createDefault(g); + elements.add(i,tex); + } + Resource mode = tc.getModeType(); + if (mode == null) + tex.setTextureMode(Resources.g3dResource.CombineMode_modulate); + else + tex.setTextureMode(mode); + + textureComposites.get(i).getTexture(tex); + + } + } else { + appearance.setTexture(null); + } + + updating = false; + return GraphRequestStatus.transactionComplete(); + } + }); + + + + + } + + private class TextureComposite extends Composite { + private Button textureGeneratorButton; + private Button sphereMapButton; + private Button eyeLinearButton; + private Button objectLinearButton; + private Button normalMapButton; + private Button reflectionMapButton; + + private Button modulateButton; + private Button replaceButton; + private Button decalButton; + private Button blendButton; + + + + private Button loadImageButton; + private ImageComposite imageComposite; + private Button removeButton; + + + public TextureComposite(Composite parent, int style) { + super(parent,style); + GridLayout layout = new GridLayout(2,false); + this.setLayout(layout); + + loadImageButton = toolkit.createButton(this, "Load Texture", SWT.PUSH); + loadImageButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + + IImage[] images = ImageUtils.loadImagesDialog(getSite().getShell(), false, ImageUtils.getImageFactories()); + if (images == null) + return; + IImage image = images[0]; + setImage(image); + + } + }); + GridData data = new GridData(SWT.LEFT,SWT.FILL,false,false,2,1); + + loadImageButton.setLayoutData(data); + data = new GridData(SWT.FILL,SWT.FILL,true,true,2,1); + imageComposite = new ImageComposite(this,SWT.BORDER); + imageComposite.setLayoutData(data); + + Composite texGenComposite = toolkit.createComposite(this, SWT.BORDER); + layout = new GridLayout(1,false); + texGenComposite.setLayout(layout); + data = new GridData(SWT.FILL,SWT.FILL,true,true,1,1); + data.heightHint = 140; + texGenComposite.setLayoutData(data); + textureGeneratorButton = toolkit.createButton(texGenComposite, "Has Texture Coordinate Generator", SWT.CHECK); + textureGeneratorButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + sphereMapButton.setEnabled(textureGeneratorButton.getSelection()); + eyeLinearButton.setEnabled(textureGeneratorButton.getSelection()); + objectLinearButton.setEnabled(textureGeneratorButton.getSelection()); + normalMapButton.setEnabled(textureGeneratorButton.getSelection()); + reflectionMapButton.setEnabled(textureGeneratorButton.getSelection()); + + } + }); + + sphereMapButton = toolkit.createButton(texGenComposite, "Shpere Map", SWT.RADIO); + sphereMapButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + if (!sphereMapButton.getSelection()) { + sphereMapButton.setSelection(true); + } else { + eyeLinearButton.setSelection(false); + objectLinearButton.setSelection(false); + normalMapButton.setSelection(false); + reflectionMapButton.setSelection(false); + } + } + }); + eyeLinearButton = toolkit.createButton(texGenComposite, "Eye Linear", SWT.RADIO); + eyeLinearButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + if (!eyeLinearButton.getSelection()) { + eyeLinearButton.setSelection(true); + } else { + sphereMapButton.setSelection(false); + objectLinearButton.setSelection(false); + normalMapButton.setSelection(false); + reflectionMapButton.setSelection(false); + } + } + }); + objectLinearButton = toolkit.createButton(texGenComposite, "Object Linear", SWT.RADIO); + objectLinearButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + if (!objectLinearButton.getSelection()) { + objectLinearButton.setSelection(true); + } else { + eyeLinearButton.setSelection(false); + sphereMapButton.setSelection(false); + normalMapButton.setSelection(false); + reflectionMapButton.setSelection(false); + } + } + }); + normalMapButton = toolkit.createButton(texGenComposite, "Normal Map", SWT.RADIO); + normalMapButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + if (!normalMapButton.getSelection()) { + normalMapButton.setSelection(true); + } else { + eyeLinearButton.setSelection(false); + objectLinearButton.setSelection(false); + sphereMapButton.setSelection(false); + reflectionMapButton.setSelection(false); + } + } + }); + reflectionMapButton = toolkit.createButton(texGenComposite, "Reflection Map", SWT.RADIO); + reflectionMapButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + if (!reflectionMapButton.getSelection()) { + reflectionMapButton.setSelection(true); + } else { + eyeLinearButton.setSelection(false); + objectLinearButton.setSelection(false); + normalMapButton.setSelection(false); + sphereMapButton.setSelection(false); + } + } + }); + + Composite texModeComposite = toolkit.createComposite(this, SWT.BORDER); + texModeComposite.setLayout(layout); + texModeComposite.setLayoutData(data); + modulateButton = toolkit.createButton(texModeComposite, "Modulate", SWT.RADIO); + modulateButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + modulateButton.setSelection(true); + replaceButton.setSelection(false); + blendButton.setSelection(false); + decalButton.setSelection(false); + + } + }); + blendButton = toolkit.createButton(texModeComposite, "Blend", SWT.RADIO); + blendButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + modulateButton.setSelection(false); + replaceButton.setSelection(false); + blendButton.setSelection(true); + decalButton.setSelection(false); + + } + }); + replaceButton = toolkit.createButton(texModeComposite, "Replace", SWT.RADIO); + replaceButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + modulateButton.setSelection(false); + replaceButton.setSelection(true); + blendButton.setSelection(false); + decalButton.setSelection(false); + + } + }); + decalButton = toolkit.createButton(texModeComposite, "Decal", SWT.RADIO); + decalButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + modulateButton.setSelection(false); + replaceButton.setSelection(false); + blendButton.setSelection(false); + decalButton.setSelection(true); + + } + }); + + removeButton = toolkit.createButton(this, "Remove texture", SWT.PUSH); + parent.getParent().getParent().layout(true, true); + } + + public void setImage(IImage image) { + imageComposite.setImage(image); + } + + public IImage getImage() { + return imageComposite.getImage(); + } + + public void update(ImageTexture t2) throws Exception { + Graph graph = t2.getGraph(); + org.simantics.image.stubs.Image i = t2.getImage(); + IImageFactory f = ImageUtils.getImageFactoryForResource(graph,i.getResource()); + final IImage p = f.createImageForResource(graph,i.getResource()); +// PixelDimension pd = p.getDimensions().getPixelDimension(); +// if (pd==null) pd = AppearanceTools.DEFAULT_SIZE; +// final ImageData id = p.rasterize(pd.getWidth(), pd.getHeight()); + + parent.getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + //Image im = new Image(AppearanceEditor.this.getBody().getDisplay(),id); + //imageComposite.setImage(im); + //showImage(); + setImage(p); + + } + }); + + TextureCoordinateGenerator gen = t2.getTextureCoordinateGenerator(); + final boolean tg; + final boolean sm; + final boolean el; + final boolean ol; + final boolean nm; + final boolean rm; + if (gen == null) { + tg = false; + sm = false; + el = false; + ol = false; + nm = false; + rm = false; + } else { + //type = gen.getTextureCoordinateGeneratorTypeValue(); + //textureGeneratorButton.setSelection(true); + tg = true; + if (gen.equals(Resources.g3dResource.TextureCoordinateGenerator_sphere)) { + sm = true; + el = false; + ol = false; + nm = false; + rm = false; + } else if (gen.equals(Resources.g3dResource.TextureCoordinateGenerator_eyelinear)) { + sm = false; + el = true; + ol = false; + nm = false; + rm = false; + } else if (gen.equals(Resources.g3dResource.TextureCoordinateGenerator_objectlinear)) { + sm = false; + el = false; + ol = true; + nm = false; + rm = false; + } else if (gen.equals(Resources.g3dResource.TextureCoordinateGenerator_normal)) { + sm = false; + el = false; + ol = false; + nm = true; + rm = false; + } else if (gen.equals(Resources.g3dResource.TextureCoordinateGenerator_reflection)) { + sm = false; + el = false; + ol = false; + nm = false; + rm = true; + } else { + sm = false; + el = false; + ol = false; + nm = false; + rm = false; + } + + } + + parent.getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + textureGeneratorButton.setSelection(tg); + sphereMapButton.setSelection(sm); + eyeLinearButton.setSelection(el); + objectLinearButton.setSelection(ol); + normalMapButton.setSelection(nm); + reflectionMapButton.setSelection(rm); + sphereMapButton.setEnabled(textureGeneratorButton.getSelection()); + eyeLinearButton.setEnabled(textureGeneratorButton.getSelection()); + objectLinearButton.setEnabled(textureGeneratorButton.getSelection()); + normalMapButton.setEnabled(textureGeneratorButton.getSelection()); + reflectionMapButton.setEnabled(textureGeneratorButton.getSelection()); + + } + }); + } + + + public Resource getGenType() { + if (sphereMapButton.getSelection()) + return Resources.g3dResource.TextureCoordinateGenerator_sphere; + else if (eyeLinearButton.getSelection()) + return Resources.g3dResource.TextureCoordinateGenerator_eyelinear; + else if (objectLinearButton.getSelection()) + return Resources.g3dResource.TextureCoordinateGenerator_objectlinear; + else if (normalMapButton.getSelection()) + return Resources.g3dResource.TextureCoordinateGenerator_normal; + else if (reflectionMapButton.getSelection()) + return Resources.g3dResource.TextureCoordinateGenerator_reflection; + return null; + } + + public Resource getModeType() { + if (modulateButton.getSelection()) + return Resources.g3dResource.MultiTextureMode_modulate; + else if (replaceButton.getSelection()) + return Resources.g3dResource.MultiTextureMode_replace; + else if (blendButton.getSelection()) + return Resources.g3dResource.MultiTextureMode_blend; + else if (decalButton.getSelection()) + return Resources.g3dResource.MultiTextureMode_decal; + + return null; + } + + public void getTexture(ImageTexture t2) throws Exception{ + Graph g = t2.getGraph(); + IImage image = getImage(); + if (image != null) { + Resource res = image.instantiateAsResource(g); + t2.setImage(res); + } + final Resource t2res = t2.getResource(); + + if (textureGeneratorButton.getSelection()) { + final Resource type; + if (sphereMapButton.getSelection()) + type = Resources.g3dResource.TextureCoordinateGenerator_sphere; + else if (eyeLinearButton.getSelection()) + type = Resources.g3dResource.TextureCoordinateGenerator_eyelinear; + else if (objectLinearButton.getSelection()) + type = Resources.g3dResource.TextureCoordinateGenerator_objectlinear; + else if (normalMapButton.getSelection()) + type = Resources.g3dResource.TextureCoordinateGenerator_normal; + else if (reflectionMapButton.getSelection()) + type = Resources.g3dResource.TextureCoordinateGenerator_reflection; + else + type = null; + if (type != null) { + getSession().asyncWrite(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) + throws Exception { + ImageTexture t2 = new ImageTexture(g, t2res); + t2.setTextureCoordinateGenerator(type); + return GraphRequestStatus.transactionComplete(); + } + }); + + } + + } + } + + /* + * public void getTexture(ImageTexture t2) { if + * (imageComposite.getImage() != null) { ImageData data = + * imageComposite.getImage().getImageData(); if (!data.palette.isDirect) { + * throw new RuntimeException("Not direct"); } int bytes = 0; String + * type = ""; if (data.depth != 32 && data.depth != 24) { throw new + * UnsupportedOperationException("Cannot handle bitdepth " + + * data.depth); } if (data.depth == 32) { bytes = 4; type = "RGBA"; } + * else if (data.depth == 24) { bytes = 3; type = "RGB"; } String size = + * data.width + " " + data.height; byte texturedata[] = new + * byte[data.width * data.height * bytes]; for (int y = 0; y < + * data.height; y++) { for (int x = 0; x < data.width; x++) { int index = + * (y * data.width + x) * bytes; + * + * texturedata[index] = data.data[index]; texturedata[index + 1] = + * data.data[index + 1]; texturedata[index + 2] = data.data[index + 2]; + * if (bytes == 4) texturedata[index + 3] = data.data[index + 3]; + * } } String base64 = new + * sun.misc.BASE64Encoder().encode(texturedata); // if + * (coreTC.getCurrentTransaction() == null) + * + * + * + * fi.vtt.proconf.threedimensionalmodeling.stub.v1_0.Image i = + * t2.getImage(); if (i == null) { i = ImageFactory.instantiate(graph); + * graph.commitChanges(this); t2.setImage(i); } + * i.setImageDataValue(base64); i.setImageTypeValue(type); + * i.setImageSizeValue(size); graph.commitChanges(this); if + * (textureGeneratorButton.getSelection()) { type = null; if + * (sphereMapButton.getSelection()) type = + * AppearanceTools.TEXTURE_COORD_GEN_SPHERE; else if + * (eyeLinearButton.getSelection()) type = + * AppearanceTools.TEXTURE_COORD_GEN_EYE_LINEAR; else if + * (objectLinearButton.getSelection()) type = + * AppearanceTools.TEXTURE_COORD_GEN_OBJECT_LINEAR; else if + * (normalMapButton.getSelection()) type = + * AppearanceTools.TEXTURE_COORD_GEN_NORMAL; else if + * (reflectionMapButton.getSelection()) type = + * AppearanceTools.TEXTURE_COORD_GEN_REFLECTION; else type = null; if + * (type != null) { TextureCoordinateGenerator gen = + * t2.getTextureCoordinateGenerator(); if (gen == null) { gen = + * TextureCoordinateGeneratorFactory.instantiate(graph); + * graph.commitChanges(this); t2.setTextureCoordinateGenerator(gen); } + * gen.setTextureCoordinateGeneratorTypeValue(type); + * graph.commitChanges(this); } + * } else { //t2.setTextureCoordinateGenerator(null); + * graph.commitChanges(this); } + * } } + */ + } +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/views/ScenegraphViewPart.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/views/ScenegraphViewPart.java new file mode 100644 index 00000000..ee3f1277 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/views/ScenegraphViewPart.java @@ -0,0 +1,610 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.views; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.IToolBarManager; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.viewers.ITreeContentProvider; +import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.jface.viewers.TreeViewer; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.ui.IActionBars; +import org.eclipse.ui.IPartListener; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.part.ViewPart; +import org.eclipse.ui.views.properties.ComboBoxPropertyDescriptor; +import org.eclipse.ui.views.properties.IPropertyDescriptor; +import org.eclipse.ui.views.properties.IPropertySource; +import org.eclipse.ui.views.properties.TextPropertyDescriptor; +import org.simantics.proconf.g3d.Activator; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorPart; +import org.simantics.proconf.g3d.scenegraph.IGeometryNode; +import org.simantics.proconf.g3d.scenegraph.IGraphicsNode; +import org.simantics.proconf.g3d.scenegraph.ISelectableNode; +import org.simantics.utils.ui.gfx.ImageCache; + +import com.jme.scene.Geometry; +import com.jme.scene.Node; +import com.jme.scene.SceneElement; +import com.jme.scene.Spatial; +import com.jme.scene.batch.GeomBatch; + +public class ScenegraphViewPart extends ViewPart{ + + private static final ImageDescriptor GEOMETRY_IMAGE = Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/geometry.png"); + private static final ImageDescriptor BATCH_IMAGE = Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/batch.png"); + private static final ImageDescriptor NODE_IMAGE = Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/node.png"); + + + TreeViewer viewer; + + IPartListener listener; + + Action showJMEAction; + + @Override + public void createPartControl(Composite parent) { + + viewer = new TreeViewer(parent, SWT.SINGLE | SWT.H_SCROLL| SWT.V_SCROLL); + viewer.setContentProvider(new GNScenegraphContentProvider()); + viewer.setLabelProvider(new GNScenegraphLabelProvider()); + getSite().setSelectionProvider(viewer); + + makeActions(); + + IActionBars actionBar = getViewSite().getActionBars(); + contributeToActionBars(actionBar); + + listener = new IPartListener() { + @Override + public void partActivated(IWorkbenchPart part) { + if (part instanceof ThreeDimensionalEditorPart) { + ThreeDimensionalEditorPart p = (ThreeDimensionalEditorPart)part; + Object newInput = p.getEditor(); + if (viewer.getInput() != newInput) + viewer.setInput(newInput); + } else { + //viewer.setInput(null); + } + + } + + @Override + public void partBroughtToTop(IWorkbenchPart part) { + + } + + @Override + public void partClosed(IWorkbenchPart part) { + + } + + @Override + public void partDeactivated(IWorkbenchPart part) { + + } + + @Override + public void partOpened(IWorkbenchPart part) { + + } + }; + for (IWorkbenchWindow w : PlatformUI.getWorkbench().getWorkbenchWindows()) { + w.getPartService().addPartListener(listener); + + } + + } + + protected void makeActions() { + showJMEAction = new Action("jME",Action.AS_CHECK_BOX) { + @Override + public void run() { + Object input = viewer.getInput(); + viewer.setInput(null); + if (this.isChecked()) { + viewer.setContentProvider(new JMEScenegraphContentProvider()); + viewer.setLabelProvider(new JMEScenegraphLabelProvider()); + } else { + viewer.setContentProvider(new GNScenegraphContentProvider()); + viewer.setLabelProvider(new GNScenegraphLabelProvider()); + } + viewer.setInput(input); + } + }; + } + + protected void contributeToActionBars(IActionBars bars) { + fillLocalToolBar(bars.getToolBarManager()); + fillLocalPullDown(bars.getMenuManager()); + bars.updateActionBars(); + } + + protected void fillLocalToolBar(IToolBarManager manager) { + manager.add(showJMEAction); + } + + protected void fillLocalPullDown(IMenuManager manager) { + + } + + @Override + public void setFocus() { + viewer.getControl().setFocus(); + } + + public void dispose() { + for (IWorkbenchWindow w : PlatformUI.getWorkbench().getWorkbenchWindows()) { + w.getPartService().removePartListener(listener); + + } + super.dispose(); + } + + + private class JMEScenegraphContentProvider implements ITreeContentProvider { + @Override + public Object[] getChildren(Object parentElement) { + if (parentElement instanceof JMEAdaptable) + parentElement = ((JMEAdaptable)parentElement).getElement(); + + if (parentElement instanceof Node) { + Node n = (Node)parentElement; + Object o[] = new Object[n.getChildren().size()]; + for (int i = 0; i < n.getChildren().size(); i++) { + o[i] = new JMEAdaptable(n.getChild(i)); + } + return o; + } + if (parentElement instanceof Geometry) { + Geometry g = (Geometry)parentElement; + Object o[] = new Object[g.getBatchCount()]; + for (int i = 0 ; i < g.getBatchCount(); i++) + o[i] = new JMEAdaptable(g.getBatch(i)); + return o; + } + return null; + } + + @Override + public Object[] getElements(Object inputElement) { + if (inputElement instanceof ThreeDimensionalEditorBase) { + SceneElement root = ((ThreeDimensionalEditorBase)inputElement).getRenderingComponent().getRoot(); + if (root != null) + return new Object[]{new JMEAdaptable(root)}; + } + return new Object[0]; + } + + @Override + public Object getParent(Object element) { + SceneElement e; + if (element instanceof JMEAdaptable) + e = ((JMEAdaptable)element).getElement(); + else + e = (SceneElement)element; + if (e instanceof Spatial) { + Spatial s = (Spatial)e; + return s.getParent(); + } + if (e instanceof GeomBatch) { + GeomBatch g = (GeomBatch)e; + return g.getParentGeom(); + } + return null; + } + + @Override + public boolean hasChildren(Object element) { + if (element instanceof JMEAdaptable) + element = ((JMEAdaptable)element).getElement(); + if (element instanceof Node) { + Node n = (Node)element; + if (n.getChildren() == null) + return false; + return n.getChildren().size() > 0; + } + if (element instanceof Geometry) { + Geometry g = (Geometry)element; + return g.getBatchCount() > 0; + } + return false; + } + + @Override + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + + } + + @Override + public void dispose() { + + } + } + + private class JMEScenegraphLabelProvider extends LabelProvider { + @Override + public String getText(Object element) { + if (element == null) + return null; + if (element instanceof JMEAdaptable) + element = ((JMEAdaptable)element).getElement(); + SceneElement e = (SceneElement)element; + return e.getName() + " : " + e.getClass(); + } + + @Override + public Image getImage(Object element) { + if (element == null) + return null; + if (element instanceof JMEAdaptable) + element = ((JMEAdaptable)element).getElement(); + ImageDescriptor desc = null; + if (element instanceof GeomBatch) + desc = BATCH_IMAGE; + else if (element instanceof Geometry) + desc = GEOMETRY_IMAGE; + else if (element instanceof Node) + desc = NODE_IMAGE; + else + return null; + return ImageCache.getInstance().getImage(desc); + } + } + + private class GNScenegraphContentProvider implements ITreeContentProvider { + @Override + public Object[] getChildren(Object parentElement) { + if (parentElement instanceof GNAdaptable) + parentElement = ((GNAdaptable)parentElement).getNode(); + IGraphicsNode node = (IGraphicsNode)parentElement; + Object children[] = new Object[node.getChildren().size()]; + Iterator it = node.getChildren().iterator(); + for (int i = 0; i < node.getChildren().size(); i++) { + children[i] = new GNAdaptable(it.next()); + } + return children; + } + + @Override + public Object[] getElements(Object inputElement) { + if (inputElement instanceof ThreeDimensionalEditorBase) { + IGraphicsNode root = ((ThreeDimensionalEditorBase)inputElement).getScenegraphAdapter().getRootNode(); + if (root != null) + return new Object[]{new GNAdaptable(root)}; + } + return new Object[0]; + } + + @Override + public Object getParent(Object element) { + if (element instanceof GNAdaptable) + element = ((GNAdaptable)element).getNode(); + IGraphicsNode node = (IGraphicsNode)element; + return node.getParent(); + } + + @Override + public boolean hasChildren(Object element) { + if (element instanceof GNAdaptable) + element = ((GNAdaptable)element).getNode(); + IGraphicsNode node = (IGraphicsNode)element; + return node.getChildren().size() > 0; + } + + @Override + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + + } + + @Override + public void dispose() { + + } + } + + private class GNScenegraphLabelProvider extends LabelProvider { + @Override + public String getText(Object element) { + if (element instanceof GNAdaptable) + element = ((GNAdaptable)element).getNode(); + IGraphicsNode node = (IGraphicsNode)element; + return node.getGroup().getName() + " : " + node.getClass(); + } + + @Override + public Image getImage(Object element) { + ImageDescriptor desc = NODE_IMAGE; +// if (element instanceof GeomBatch) +// desc = BATCH_IMAGE; +// else if (element instanceof Geometry) +// desc = GEOMETRY_IMAGE; +// else if (element instanceof Node) +// desc = NODE_IMAGE; +// else +// return null; + return ImageCache.getInstance().getImage(desc); + } + } + + private class JMEAdaptable implements IAdaptable { + SceneElement element; + + public JMEAdaptable(SceneElement element) { + assert (element != null); + this.element = element; + } + + @SuppressWarnings("unchecked") + @Override + public Object getAdapter(Class adapter) { + if (adapter == IPropertySource.class) { + return new JMEProperties(element); + } + return null; + } + + public SceneElement getElement() { + return element; + } + } + + private class GNAdaptable implements IAdaptable { + IGraphicsNode node; + + public GNAdaptable(IGraphicsNode node) { + assert (node != null); + this.node = node; + } + + @SuppressWarnings("unchecked") + @Override + public Object getAdapter(Class adapter) { + if (adapter == IPropertySource.class) { + return new GNProperties(node); + } + return null; + } + + public IGraphicsNode getNode() { + return node; + } + } + + private static final String NAME = "name"; + private static final String CULL_MODE = "cullmode"; + private static final String CULL_MODES[] = {"Inherit","Dynamic","Always","Never"}; + private static final String LIGHT_MODE = "lightmode"; + private static final String LIGHT_MODES[] = {"Off","Combine First","Combine Closest","Combine Recent Enabled","Inherit","Replace"}; + private static final String LOCAL_CULL_MODE = "localcullmode"; + private static final String LOCAL_LIGHT_MODE = "locallightmode"; + private static final String LOCAL_NORMALS_MODE = "localnormalsmode"; + private static final String LOCAL_RENDER_QUEUE_MODE ="localrenderqueuemode"; + private static final String LOCAL_TEXTURE_COMBINE_MODE = "localtexturecombinemode"; + private static final String LOCKS = "locks"; + private static final String NORMALS_MODE = "normalsmode"; + private static final String NORMALS_MODES[] = {"Inherit","Use Provided","Normalize Provided","Normalize if scaled","Off"}; + private static final String RENDER_QUEUE_MODE = "renderqueuemode"; + private static final String RENDER_QUEUE_MODES[] = {"Inherit","Skip","Opaque","Transparent","Ortho"}; + private static final String TEXTURE_COMBINE_MODE = "texturecombinemode"; + private static final String TEXTURE_COMBINE_MODES[] = {"Off","First","Closest","Recent enabled","Inherit","Replace"}; + + private static final String BOOLEAN_VALUES[] = {"False","True"}; + + private class JMEProperties implements IPropertySource { + + SceneElement element; + + public JMEProperties(SceneElement element) { + this.element = element; + } + + @Override + public Object getEditableValue() { + return this; + } + + @Override + public IPropertyDescriptor[] getPropertyDescriptors() { + List desc = new ArrayList(); + desc.add(new TextPropertyDescriptor(NAME,"Name")); + desc.add(new ComboBoxPropertyDescriptor(CULL_MODE,"Cull Mode",CULL_MODES)); + desc.add(new ComboBoxPropertyDescriptor(LIGHT_MODE,"Light Combine Mode",LIGHT_MODES)); + desc.add(new ComboBoxPropertyDescriptor(LOCAL_CULL_MODE,"Local Cull Mode",CULL_MODES)); + desc.add(new ComboBoxPropertyDescriptor(LOCAL_LIGHT_MODE,"Local Light Combine Mode",LIGHT_MODES)); + desc.add(new ComboBoxPropertyDescriptor(LOCAL_NORMALS_MODE,"Local Normals Mode",NORMALS_MODES)); + desc.add(new ComboBoxPropertyDescriptor(LOCAL_RENDER_QUEUE_MODE,"Local Render Queue Mode",RENDER_QUEUE_MODES)); + desc.add(new ComboBoxPropertyDescriptor(LOCAL_TEXTURE_COMBINE_MODE,"Local Texture Combine Mode",TEXTURE_COMBINE_MODES)); + desc.add(new TextPropertyDescriptor(LOCKS,"Locks")); + desc.add(new ComboBoxPropertyDescriptor(NORMALS_MODE,"Normals Mode",NORMALS_MODES)); + desc.add(new ComboBoxPropertyDescriptor(RENDER_QUEUE_MODE,"Render Queue Mode",RENDER_QUEUE_MODES)); + desc.add(new ComboBoxPropertyDescriptor(TEXTURE_COMBINE_MODE,"Texture Combine Mode",TEXTURE_COMBINE_MODES)); + return desc.toArray(new IPropertyDescriptor[desc.size()]); + + } + + @Override + public Object getPropertyValue(Object id) { + if (id == NAME) { + return element.getName(); + } else if (id == CULL_MODE) { + return element.getCullMode(); + } else if (id == LIGHT_MODE) { + return element.getLightCombineMode(); + } else if (id == LOCAL_CULL_MODE) { + return element.getLocalCullMode(); + } else if (id == LOCAL_LIGHT_MODE) { + return element.getLocalLightCombineMode(); + } else if (id == LOCAL_NORMALS_MODE) { + return element.getLocalNormalsMode(); + } else if (id == LOCAL_RENDER_QUEUE_MODE) { + return element.getLocalRenderQueueMode(); + } else if (id == LOCAL_TEXTURE_COMBINE_MODE) { + return element.getLocalTextureCombineMode(); + } else if (id == LOCKS) { + return element.getLocks(); + } else if (id == NORMALS_MODE) { + return element.getNormalsMode(); + } else if (id == RENDER_QUEUE_MODE) { + return element.getRenderQueueMode(); + } else if (id == TEXTURE_COMBINE_MODE) { + return element.getTextureCombineMode(); + } + +// element.getZOrder(); +// element.isCollidable(); + + return null; + } + + @Override + public boolean isPropertySet(Object id) { + return false; + } + + @Override + public void resetPropertyValue(Object id) { + + } + + @Override + public void setPropertyValue(Object id, Object value) { + if (id == NAME) { + element.setName((String)value); + } else if (id == CULL_MODE) { + element.setCullMode((Integer)value); + } else if (id == LIGHT_MODE) { + element.setLightCombineMode((Integer)value); + } else if (id == LOCAL_CULL_MODE) { + + } else if (id == LOCAL_LIGHT_MODE) { + + } else if (id == LOCAL_NORMALS_MODE) { + + } else if (id == LOCAL_RENDER_QUEUE_MODE) { + + } else if (id == LOCAL_TEXTURE_COMBINE_MODE) { + + } else if (id == LOCKS) { + element.setLocks((Integer)value); + } else if (id == NORMALS_MODE) { + element.setNormalsMode((Integer)value); + } else if (id == RENDER_QUEUE_MODE) { + element.setRenderQueueMode((Integer)value); + } else if (id == TEXTURE_COMBINE_MODE) { + element.setTextureCombineMode((Integer)value); + } + + } + + } + + private static final String SELECTED = "selected"; + private static final String HIGHLIGHTED = "highlighted"; + private static final String VISIBLE = "visible"; + + private class GNProperties implements IPropertySource { + IGraphicsNode node; + + public GNProperties(IGraphicsNode node) { + this.node = node; + } + + + @Override + public Object getEditableValue() { + return this; + } + + @Override + public IPropertyDescriptor[] getPropertyDescriptors() { + List desc = new ArrayList(); + if (node instanceof ISelectableNode) { + //ISelectableNode n = (ISelectableNode)node; + + desc.add(new ComboBoxPropertyDescriptor(SELECTED,"Selected",BOOLEAN_VALUES)); + desc.add(new ComboBoxPropertyDescriptor(HIGHLIGHTED,"Highlighted",BOOLEAN_VALUES)); + desc.add(new ComboBoxPropertyDescriptor(VISIBLE,"Visible",BOOLEAN_VALUES)); + + } + return desc.toArray(new IPropertyDescriptor[desc.size()]); + } + + @Override + public Object getPropertyValue(Object id) { + if (node instanceof ISelectableNode) { + ISelectableNode n = (ISelectableNode)node; + if (id == SELECTED) { + if (n.isSelected()) + return 1; + return 0; + } else if (id == HIGHLIGHTED) { + if (n.isHighlighted()) + return 1; + return 0; + } else if (id == VISIBLE) { + if (n.isVisible()) + return 1; + return 0; + } + } + if (node instanceof IGeometryNode) { + //IGeometryNode n = (IGeometryNode)node; + } + + return null; + } + + @Override + public boolean isPropertySet(Object id) { + return false; + } + + @Override + public void resetPropertyValue(Object id) { + + } + + @Override + public void setPropertyValue(Object id, Object value) { + if (node instanceof ISelectableNode) { + ISelectableNode n = (ISelectableNode)node; + boolean b = ((Integer)value) == 1; + if (id == SELECTED) { + n.setSelected(b); + } else if (id == HIGHLIGHTED) { + n.setHighlighted(b); + } else if (id == VISIBLE) { + n.setVisible(b); + } + } + + } + + + } + +} + + diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/views/SinglePageResourceEditor.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/views/SinglePageResourceEditor.java new file mode 100644 index 00000000..1caba9d0 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/views/SinglePageResourceEditor.java @@ -0,0 +1,233 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.views; + +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.IPartListener; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.forms.events.ExpansionAdapter; +import org.eclipse.ui.forms.events.ExpansionEvent; +import org.eclipse.ui.forms.widgets.FormToolkit; +import org.eclipse.ui.forms.widgets.ScrolledForm; +import org.eclipse.ui.forms.widgets.Section; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Session; +import org.simantics.proconf.g3d.common.StructuredResourceSelection; +import org.simantics.proconf.ui.workbench.ResourceEditorPart; +import org.simantics.utils.ErrorLogger; +import org.simantics.utils.ui.ISelectionUtils; +import org.simantics.utils.ui.jface.BaseSelectionProvider; + + + +public abstract class SinglePageResourceEditor extends ResourceEditorPart { + private ScrolledForm form; + private BaseSelectionProvider defaultInputSelectionProvider = new BaseSelectionProvider(); + protected FormToolkit toolkit; + + @Override + public void createPartControl(Composite parent) { + this.getEditorSite().getPage().addPartListener(new IPartListener() { + + boolean opened = false; + boolean activated = false; + + public void partOpened(IWorkbenchPart part) { + if (part.equals(SinglePageResourceEditor.this.getEditorSite().getPart())) { + opened = true; + } + } + + public void partActivated(IWorkbenchPart part) { + if (part.equals(SinglePageResourceEditor.this.getEditorSite().getPart())) { + if (opened & !activated) { + activated = true; + load(); + } + } + } + + public void partBroughtToTop(IWorkbenchPart part) {} + + public void partClosed(IWorkbenchPart part) {} + + public void partDeactivated(IWorkbenchPart part) {} + + private void load() { + Session ses = SinglePageResourceEditor.this.getSession(); + GraphRequestAdapter r = new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) + throws Exception { + reload(g); + return GraphRequestStatus.transactionComplete(); + } + }; + ses.asyncRead(r); + } + }); + try { + toolkit = new FormToolkit(parent.getDisplay()); + form = getToolkit().createScrolledForm(parent); + + GridLayout layout = new GridLayout(2, false); + form.getBody().setLayout(layout); + form.getBody().setLayoutData( + new GridData(GridData.FILL, GridData.FILL, true, true)); + + // By default make this ViewPart use a default ISelectionProvider + // that will offer the viewparts input resource as its selection. + // The Resource is wrapped into a ResourceSelection object. + // Any widgets created in createWidgets may override the default + // selection provider. + getEditorSite().setSelectionProvider(defaultInputSelectionProvider); + + beforeCreateWidgets(); + createWidgets(); + + //reload(); + + form.setText(getFormText()); + + // Finally Set the default selection which will have an effect only + // if nothing in createWidgets has overridden the default selection + // provider. + ISelection s = ISelectionUtils + .createSelection(new StructuredResourceSelection( + getInputResource())); + defaultInputSelectionProvider.setSelection(s); + + } catch (Exception e) { + Display d = getSite().getShell().getDisplay(); + d.asyncExec(new Runnable() { + public void run() { + getSite().getPage().closeEditor( + SinglePageResourceEditor.this, false); + } + }); + + ErrorLogger.defaultLogError("Single-page type editor failed to open, see exception for details",e); + } + } + + public ScrolledForm getActiveForm() { + return form; + } + + protected Composite getBody() { + return form.getBody(); + } + + public Composite newGridSection(int formColumns, int childColumns, + boolean equalWidth, boolean grabVertical, String text, + String description) { + return newGridSection(getBody(), formColumns, childColumns, equalWidth, + grabVertical, text, description); + } + + public Composite newGridSection(Composite parent, int formColumns, + int childColumns, boolean equalWidth, boolean grabVertical, + String text, String description) { + FormToolkit toolkit = getToolkit(); + + Section section = toolkit.createSection(parent, Section.DESCRIPTION + | Section.TWISTIE | Section.TITLE_BAR | Section.EXPANDED); + section.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, + grabVertical, formColumns, 1)); + section.addExpansionListener(new ExpansionAdapter() { + public void expansionStateChanged(ExpansionEvent e) { + //System.out.println("SinglePageTypeEditor: expansionStateChanged " + e); + //reflow(true); + } + }); + section.setText(text); + section.setDescription(description); + Composite sectionClient = toolkit.createComposite(section); + sectionClient.setLayout(new GridLayout(childColumns, equalWidth)); + sectionClient.setLayoutData(new GridData()); + section.setClient(sectionClient); + return sectionClient; + } + + + + //---------------------------------------------------------------------- + // Getters + + public FormToolkit getToolkit() { + return toolkit; + } + + //---------------------------------------------------------------------- + // Event utilities + + public void reflow(boolean flushCache) { + //System.out.println("FormTypeEditorBase.reflow(" + flushCache + ")"); + getActiveForm().reflow(flushCache); + } + + @Override + public void dispose() { + if (toolkit != null) { + toolkit.dispose(); + } + super.dispose(); + } + + @Override + public void setFocus() { + //System.out.println("FormTypeEditorBase.setFocus(): Input = " + getInput()); + ScrolledForm form = getActiveForm(); + if (form != null) { + form.setFocus(); + } + } + + protected abstract String getFormText(); + + /** + * Returns null by default which makes {@link #updateTitle()} not set the + * part name programmatically, i.e. the plugin-defined view name will stay. + * + * @return + */ + protected String getTitleText() { + return null; + } + + /** + * Return null by default which makes {@link #updateTitle()} clear the + * tooltip. + * + * @return + */ + protected String getTitleTooltip() { + return null; + } + + /** + * A method for performing initializations just before UI initialization. + */ + protected void beforeCreateWidgets() { + } + + /** + * A method for initializing the UI of the view. + */ + protected void createWidgets() { + } +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/views/SinglePageResourceView.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/views/SinglePageResourceView.java new file mode 100644 index 00000000..d1d3dfd3 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/views/SinglePageResourceView.java @@ -0,0 +1,155 @@ +package org.simantics.proconf.g3d.views; + +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.ui.ISelectionListener; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.forms.events.ExpansionAdapter; +import org.eclipse.ui.forms.events.ExpansionEvent; +import org.eclipse.ui.forms.widgets.FormToolkit; +import org.eclipse.ui.forms.widgets.ScrolledForm; +import org.eclipse.ui.forms.widgets.Section; +import org.simantics.proconf.ui.workbench.GraphAccessViewPart; +import org.simantics.utils.ui.jface.BaseSelectionProvider; + +public abstract class SinglePageResourceView extends GraphAccessViewPart{ + protected Composite parent; + private ScrolledForm form; + private BaseSelectionProvider defaultInputSelectionProvider = new BaseSelectionProvider(); + protected FormToolkit toolkit; + protected ISelectionListener pageSelectionListener; + + @Override + public void createPartControl(Composite parent) { + super.createPartControl(parent); + this.parent = parent; + + toolkit = new FormToolkit(parent.getDisplay()); + form = getToolkit().createScrolledForm(parent); + + GridLayout layout = new GridLayout(2, false); + form.getBody().setLayout(layout); + form.getBody().setLayoutData( + new GridData(GridData.FILL, GridData.FILL, true, true)); + + getViewSite().setSelectionProvider(defaultInputSelectionProvider); + + // createWidgets(); + + form.setText(getFormText()); + + hookPageSelection(); + + } + + + /** + * Receives selection changes + * + * @param part + * @param selection + */ + protected void pageSelectionChanged(IWorkbenchPart part, ISelection selection) { + + } + + + + + + protected abstract String getFormText(); + + protected abstract void createWidgets(); + + @Override + public void setFocus() { + //System.out.println("FormTypeEditorBase.setFocus(): Input = " + getInput()); + ScrolledForm form = getActiveForm(); + if (form != null) { + form.setFocus(); + } + } + + public FormToolkit getToolkit() { + return toolkit; + } + + public ScrolledForm getActiveForm() { + return form; + } + + public void clearForm() { + for (Control c : form.getBody().getChildren()) + c.dispose(); + + } + + protected Composite getBody() { + return form.getBody(); + } + + public Composite newGridSection( + int formColumns, + int childColumns, + boolean equalWidth, + boolean grabVertical, + String text, + String description) + { + return newGridSection(getBody(), formColumns, childColumns, equalWidth, grabVertical, text, description); + } + + public Composite newGridSection( + Composite parent, + int formColumns, + int childColumns, + boolean equalWidth, + boolean grabVertical, + String text, + String description) + { + FormToolkit toolkit = getToolkit(); + + Section section = toolkit.createSection(parent, + Section.DESCRIPTION | Section.TWISTIE | Section.TITLE_BAR | Section.EXPANDED); + section.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, grabVertical, formColumns, 1)); + section.addExpansionListener(new ExpansionAdapter() { + public void expansionStateChanged(ExpansionEvent e) { + //System.out.println("SinglePageTypeEditor: expansionStateChanged " + e); + //reflow(true); + } + }); + section.setText(text); + section.setDescription(description); + Composite sectionClient = toolkit.createComposite(section); + sectionClient.setLayout(new GridLayout(childColumns, equalWidth)); + sectionClient.setLayoutData(new GridData()); + section.setClient(sectionClient); + return sectionClient; + } + + public void dispose() { + if (pageSelectionListener != null) + getSite().getPage().removePostSelectionListener(pageSelectionListener); + + super.dispose(); + } + + private void hookPageSelection() { + pageSelectionListener = new ISelectionListener() { + public void selectionChanged(IWorkbenchPart part, ISelection selection) { + if (part == SinglePageResourceView.this) + return; + pageSelectionChanged(part, selection); + } + }; + getSite().getPage().addPostSelectionListener(pageSelectionListener); + ISelection sel = getSite().getPage().getSelection(); + IWorkbenchPart wb = getSite().getPage().getActivePart(); + pageSelectionChanged(wb, sel); + } + +} diff --git a/org.simantics.proconf.processeditor/.classpath b/org.simantics.proconf.processeditor/.classpath new file mode 100644 index 00000000..02159672 --- /dev/null +++ b/org.simantics.proconf.processeditor/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/org.simantics.proconf.processeditor/.project b/org.simantics.proconf.processeditor/.project new file mode 100644 index 00000000..4f2fb460 --- /dev/null +++ b/org.simantics.proconf.processeditor/.project @@ -0,0 +1,28 @@ + + + org.simantics.proconf.processeditor + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/org.simantics.proconf.processeditor/META-INF/MANIFEST.MF b/org.simantics.proconf.processeditor/META-INF/MANIFEST.MF new file mode 100644 index 00000000..9784c3eb --- /dev/null +++ b/org.simantics.proconf.processeditor/META-INF/MANIFEST.MF @@ -0,0 +1,28 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Processeditor Plug-in +Bundle-SymbolicName: fi.vtt.simantics.processeditor;singleton:=true +Bundle-Version: 1.0.0 +Bundle-Activator: fi.vtt.simantics.processeditor.Activator +Bundle-Vendor: VTT +Require-Bundle: org.eclipse.ui, + org.eclipse.core.runtime, + com.jme.eclipse, + org.simantics.proconf.animation, + org.simantics.g2d.stubs, + org.simantics.proconf.ui, + org.simantics.proconf.g3d, + org.simantics.proconf.image, + org.simantics.layer0.stubs, + org.simantics.layer0.utils, + org.simantics.utils, + org.simantics.utils.datastructures, + javax.vecmath, + org.simantics.proconf.ui.workbench, + org.simantics.proconf.ode, + org.simantics.proconf.browsing, + org.simantics.utils.ui, + org.simantics.utils.ui.workbench, + org.simantics.proconf.g3d.shapeeditor, + org.eclipse.ui.views +Eclipse-LazyStart: true diff --git a/org.simantics.proconf.processeditor/build.properties b/org.simantics.proconf.processeditor/build.properties new file mode 100644 index 00000000..6f20375d --- /dev/null +++ b/org.simantics.proconf.processeditor/build.properties @@ -0,0 +1,5 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + plugin.xml diff --git a/org.simantics.proconf.processeditor/data/dcp.mtl b/org.simantics.proconf.processeditor/data/dcp.mtl new file mode 100644 index 00000000..e30d811c --- /dev/null +++ b/org.simantics.proconf.processeditor/data/dcp.mtl @@ -0,0 +1,2 @@ +# Blender3D MTL File: dcp.blend +# Material Count: 0 diff --git a/org.simantics.proconf.processeditor/data/dcp.obj b/org.simantics.proconf.processeditor/data/dcp.obj new file mode 100644 index 00000000..8b19e699 --- /dev/null +++ b/org.simantics.proconf.processeditor/data/dcp.obj @@ -0,0 +1,476 @@ +# Blender v242 OBJ File: dcp.blend +# www.blender3d.org +mtllib dcp.mtl +o Sphere_Sphere +v 0.092388 -0.000000 -0.038268 +v -0.092388 0.014645 -0.035355 +v -0.070711 0.027060 -0.065328 +v -0.038268 0.035355 -0.085355 +v 0.000000 0.038268 -0.092388 +v 0.038268 0.035355 -0.085355 +v 0.070711 0.027060 -0.065328 +v 0.092388 0.014645 -0.035355 +v 0.092388 0.027060 -0.027060 +v 0.070711 0.050000 -0.050000 +v 0.038268 0.065328 -0.065328 +v 0.000000 0.070711 -0.070711 +v -0.038268 0.065328 -0.065328 +v -0.070711 0.050000 -0.050000 +v -0.092388 0.027060 -0.027060 +v -0.092388 0.035355 -0.014645 +v -0.070711 0.065328 -0.027060 +v -0.038268 0.085355 -0.035355 +v 0.000000 0.092388 -0.038268 +v 0.038268 0.085355 -0.035355 +v 0.070711 0.065328 -0.027060 +v 0.092388 0.035355 -0.014645 +v 0.092388 0.038268 0.000000 +v 0.070711 0.070711 0.000000 +v 0.038268 0.092388 0.000000 +v 0.000000 0.100000 0.000000 +v -0.038268 0.092388 -0.000000 +v -0.070711 0.070711 -0.000000 +v -0.092388 0.038268 -0.000000 +v -0.092388 0.035355 0.014645 +v -0.070711 0.065328 0.027060 +v -0.038268 0.085355 0.035355 +v 0.000000 0.092388 0.038268 +v 0.038268 0.085355 0.035355 +v 0.070711 0.065328 0.027060 +v 0.092388 0.035355 0.014645 +v 0.092388 0.027060 0.027060 +v 0.070711 0.050000 0.050000 +v 0.038268 0.065328 0.065328 +v 0.000000 0.070711 0.070711 +v -0.038268 0.065328 0.065328 +v -0.070711 0.050000 0.050000 +v -0.092388 0.027060 0.027060 +v -0.092388 0.014645 0.035355 +v -0.070711 0.027060 0.065328 +v -0.038268 0.035355 0.085355 +v -0.000000 0.038268 0.092388 +v 0.038268 0.035355 0.085355 +v 0.070711 0.027060 0.065328 +v 0.092388 0.014645 0.035355 +v 0.092388 -0.000000 0.038268 +v 0.070711 -0.000000 0.070711 +v 0.038268 -0.000000 0.092388 +v -0.000000 0.000000 0.100000 +v -0.038268 -0.000000 0.092388 +v -0.070711 -0.000000 0.070711 +v -0.092388 0.000000 0.038268 +v -0.092388 -0.014645 0.035355 +v -0.070711 -0.027060 0.065328 +v -0.038268 -0.035355 0.085355 +v -0.000000 -0.038268 0.092388 +v 0.038268 -0.035355 0.085355 +v 0.070711 -0.027060 0.065328 +v 0.092388 -0.014645 0.035355 +v 0.092388 -0.027060 0.027060 +v 0.070711 -0.050000 0.050000 +v 0.038268 -0.065328 0.065328 +v -0.000000 -0.070711 0.070711 +v -0.038268 -0.065328 0.065328 +v -0.070711 -0.050000 0.050000 +v -0.092388 -0.027060 0.027060 +v -0.100000 -0.000000 0.000000 +v -0.092388 -0.035355 0.014645 +v -0.070711 -0.065328 0.027060 +v -0.038268 -0.085355 0.035355 +v -0.000000 -0.092388 0.038268 +v 0.038268 -0.085355 0.035355 +v 0.070711 -0.065328 0.027060 +v 0.092388 -0.035355 0.014645 +v 0.092388 -0.038268 0.000000 +v 0.070711 -0.070711 0.000000 +v 0.038268 -0.092388 0.000000 +v 0.000000 -0.100000 0.000000 +v -0.038268 -0.092388 -0.000000 +v -0.070711 -0.070711 -0.000000 +v -0.092388 -0.038268 -0.000000 +v -0.092388 -0.035355 -0.014645 +v -0.070711 -0.065328 -0.027060 +v -0.038268 -0.085355 -0.035355 +v 0.000000 -0.092388 -0.038268 +v 0.038268 -0.085355 -0.035355 +v 0.070711 -0.065328 -0.027060 +v 0.092388 -0.035355 -0.014645 +v 0.092388 -0.027060 -0.027060 +v 0.070711 -0.050000 -0.050000 +v 0.038268 -0.065328 -0.065328 +v 0.000000 -0.070711 -0.070711 +v -0.038268 -0.065328 -0.065328 +v -0.070711 -0.050000 -0.050000 +v -0.092388 -0.027060 -0.027060 +v -0.092388 -0.014645 -0.035355 +v -0.070711 -0.027060 -0.065328 +v -0.038268 -0.035355 -0.085355 +v 0.000000 -0.038268 -0.092388 +v 0.038268 -0.035355 -0.085355 +v 0.070711 -0.027060 -0.065328 +v 0.092388 -0.014645 -0.035355 +v 0.070711 0.000000 -0.070711 +v 0.038268 0.000000 -0.092388 +v 0.000000 0.000000 -0.100000 +v -0.038268 0.000000 -0.092388 +v -0.070711 0.000000 -0.070711 +v -0.092388 0.000000 -0.038268 +v 0.232388 -0.014645 -0.035355 +v 0.232388 -0.027060 -0.027060 +v 0.232388 -0.035355 -0.014645 +v 0.232388 -0.038268 0.000000 +v 0.232388 -0.035355 0.014645 +v 0.232388 -0.027060 0.027060 +v 0.232388 -0.014645 0.035355 +v 0.232388 -0.000000 0.038268 +v 0.232388 0.014645 0.035355 +v 0.232388 0.027060 0.027060 +v 0.232388 0.035355 0.014645 +v 0.232388 0.038268 0.000000 +v 0.232388 0.035355 -0.014645 +v 0.232388 0.027060 -0.027060 +v 0.232388 0.014645 -0.035355 +v 0.232388 -0.000000 -0.038268 +v 0.231045 -0.000000 -0.153073 +v 0.231045 0.058579 -0.141421 +v 0.511493 -0.000000 0.000000 +v 0.231045 0.108239 -0.108239 +v 0.231045 0.141421 -0.058579 +v 0.231045 0.153073 0.000000 +v 0.231045 0.141421 0.058579 +v 0.231045 0.108239 0.108239 +v 0.231045 0.058579 0.141421 +v 0.231045 -0.000000 0.153073 +v 0.231045 -0.058579 0.141421 +v 0.231045 -0.108239 0.108239 +v 0.231045 -0.141421 0.058579 +v 0.231045 -0.153073 0.000000 +v 0.231045 -0.141421 -0.058579 +v 0.231045 -0.108239 -0.108239 +v 0.231045 -0.058579 -0.141421 +vn -0.999929 -0.002325 0.011699 +vn -0.999929 -0.006629 0.009917 +vn -0.999929 -0.009918 0.006627 +vn -0.999929 -0.011699 0.002327 +vn -0.999929 -0.011699 -0.002327 +vn -0.999929 -0.009918 -0.006627 +vn -0.999929 -0.006627 -0.009918 +vn -0.999929 -0.002327 -0.011699 +vn -0.999929 0.002327 -0.011699 +vn -0.999929 0.006627 -0.009918 +vn -0.999929 0.009918 -0.006627 +vn -0.999929 0.011699 -0.002327 +vn -0.999929 0.011699 0.002327 +vn -0.999929 0.009918 0.006627 +vn -0.999929 0.006627 0.009918 +vn -0.999929 0.002327 0.011699 +vn -1.000000 0.000000 0.000000 +vn -0.924070 0.146245 -0.353099 +vn -0.924070 0.000000 -0.382183 +vn -0.707602 0.270394 -0.652791 +vn -0.707602 0.000000 -0.706565 +vn -0.383129 0.353465 -0.853359 +vn -0.383129 0.000000 -0.923673 +vn 0.000000 0.382672 -0.923856 +vn 0.000000 0.000000 -1.000000 +vn 0.383129 0.353465 -0.853359 +vn 0.383129 0.000000 -0.923673 +vn 0.707602 0.270394 -0.652791 +vn 0.707602 0.000000 -0.706565 +vn 0.474532 0.336833 -0.813227 +vn 0.474532 0.000000 -0.880215 +vn 0.707602 0.499619 -0.499619 +vn 0.474532 0.622395 -0.622395 +vn 0.383129 0.653127 -0.653127 +vn 0.000000 0.707083 -0.707083 +vn -0.383129 0.653127 -0.653127 +vn -0.707602 0.499619 -0.499619 +vn -0.924070 0.270241 -0.270241 +vn -0.924070 0.353099 -0.146245 +vn -0.707602 0.652791 -0.270394 +vn -0.383129 0.853359 -0.353465 +vn 0.000000 0.923856 -0.382672 +vn 0.383129 0.853359 -0.353465 +vn 0.707602 0.652791 -0.270394 +vn 0.474532 0.813227 -0.336833 +vn 0.707602 0.706565 0.000000 +vn 0.474532 0.880215 0.000000 +vn 0.383129 0.923673 0.000000 +vn 0.000000 1.000000 0.000000 +vn -0.383129 0.923673 0.000000 +vn -0.707602 0.706565 0.000000 +vn -0.924070 0.382183 0.000000 +vn -0.924070 0.353099 0.146245 +vn -0.707602 0.652791 0.270394 +vn -0.383129 0.853359 0.353465 +vn 0.000000 0.923856 0.382672 +vn 0.383129 0.853359 0.353465 +vn 0.707602 0.652791 0.270394 +vn 0.474532 0.813227 0.336833 +vn 0.707602 0.499619 0.499619 +vn 0.474532 0.622395 0.622395 +vn 0.383129 0.653127 0.653127 +vn 0.000000 0.707083 0.707083 +vn -0.383129 0.653127 0.653127 +vn -0.707602 0.499619 0.499619 +vn -0.924070 0.270241 0.270241 +vn -0.924070 0.146245 0.353099 +vn -0.707602 0.270394 0.652791 +vn -0.383129 0.353465 0.853359 +vn 0.000000 0.382672 0.923856 +vn 0.383129 0.353465 0.853359 +vn 0.707602 0.270394 0.652791 +vn 0.474532 0.336833 0.813227 +vn 0.707602 0.000000 0.706565 +vn 0.474532 0.000000 0.880215 +vn 0.383129 0.000000 0.923673 +vn 0.000000 0.000000 1.000000 +vn -0.383129 0.000000 0.923673 +vn -0.707602 0.000000 0.706565 +vn -0.924070 0.000000 0.382183 +vn -0.924070 -0.146245 0.353099 +vn -0.707602 -0.270394 0.652791 +vn -0.383129 -0.353465 0.853359 +vn 0.000000 -0.382672 0.923856 +vn 0.383129 -0.353465 0.853359 +vn 0.707602 -0.270394 0.652791 +vn 0.474532 -0.336833 0.813227 +vn 0.707602 -0.499619 0.499619 +vn 0.474532 -0.622395 0.622395 +vn 0.383129 -0.653127 0.653127 +vn 0.000000 -0.707083 0.707083 +vn -0.383129 -0.653127 0.653127 +vn -0.707602 -0.499619 0.499619 +vn -0.924070 -0.270241 0.270241 +vn -0.924070 -0.353099 0.146245 +vn -0.707602 -0.652791 0.270394 +vn -0.383129 -0.853359 0.353465 +vn 0.000000 -0.923856 0.382672 +vn 0.383129 -0.853359 0.353465 +vn 0.707602 -0.652791 0.270394 +vn 0.474532 -0.813227 0.336833 +vn 0.707602 -0.706565 0.000000 +vn 0.474532 -0.880215 0.000000 +vn 0.383129 -0.923673 0.000000 +vn 0.000000 -1.000000 0.000000 +vn -0.383129 -0.923673 0.000000 +vn -0.707602 -0.706565 0.000000 +vn -0.924070 -0.382183 0.000000 +vn -0.924070 -0.353099 -0.146245 +vn -0.707602 -0.652791 -0.270394 +vn -0.383129 -0.853359 -0.353465 +vn 0.000000 -0.923856 -0.382672 +vn 0.383129 -0.853359 -0.353465 +vn 0.707602 -0.652791 -0.270394 +vn 0.474532 -0.813227 -0.336833 +vn 0.707602 -0.499619 -0.499619 +vn 0.474532 -0.622395 -0.622395 +vn 0.383129 -0.653127 -0.653127 +vn 0.000000 -0.707083 -0.707083 +vn -0.383129 -0.653127 -0.653127 +vn -0.707602 -0.499619 -0.499619 +vn -0.924070 -0.270241 -0.270241 +vn -0.924070 -0.146245 -0.353099 +vn -0.707602 -0.270394 -0.652791 +vn -0.383129 -0.353465 -0.853359 +vn 0.000000 -0.382672 -0.923856 +vn 0.383129 -0.353465 -0.853359 +vn 0.707602 -0.270394 -0.652791 +vn 0.474532 -0.336833 -0.813227 +vn -0.718070 0.000000 -0.695944 +vn -0.718070 -0.266305 -0.642964 +vn -0.718070 -0.492080 -0.492080 +vn -0.718070 -0.642964 -0.266305 +vn -0.718070 -0.695944 0.000000 +vn -0.718070 -0.642964 0.266305 +vn -0.718070 -0.492080 0.492080 +vn -0.718070 -0.266305 0.642964 +vn -0.718070 0.000000 0.695944 +vn -0.718070 0.266305 0.642964 +vn -0.718070 0.492080 0.492080 +vn -0.718070 0.642964 0.266305 +vn -0.718070 0.695944 0.000000 +vn -0.718070 0.642964 -0.266305 +vn -0.718070 0.492080 -0.492080 +vn -0.718070 0.266305 -0.642964 +vn -0.526292 0.000000 -0.850276 +vn -0.526292 0.325388 -0.785546 +vn 1.000000 0.000000 0.000000 +vn -0.526292 0.601245 -0.601245 +vn -0.526292 0.785546 -0.325388 +vn -0.526292 0.850276 0.000000 +vn -0.526292 0.785546 0.325388 +vn -0.526292 0.601245 0.601245 +vn -0.526292 0.325388 0.785546 +vn -0.526292 0.000000 0.850276 +vn -0.526292 -0.325388 0.785546 +vn -0.526292 -0.601245 0.601245 +vn -0.526292 -0.785546 0.325388 +vn -0.526292 -0.850276 0.000000 +vn -0.526292 -0.785546 -0.325388 +vn -0.526292 -0.601245 -0.601245 +vn -0.526292 -0.325388 -0.785546 +usemtl (null) +usemtl (null) +s off +f 129//1 128//1 131//1 130//1 +f 128//2 127//2 133//2 131//2 +f 127//3 126//3 134//3 133//3 +f 126//4 125//4 135//4 134//4 +f 125//5 124//5 136//5 135//5 +f 124//6 123//6 137//6 136//6 +f 123//7 122//7 138//7 137//7 +f 122//8 121//8 139//8 138//8 +f 121//9 120//9 140//9 139//9 +f 120//10 119//10 141//10 140//10 +f 119//11 118//11 142//11 141//11 +f 118//12 117//12 143//12 142//12 +f 117//13 116//13 144//13 143//13 +f 116//14 115//14 145//14 144//14 +f 115//15 114//15 146//15 145//15 +f 114//16 129//16 130//16 146//16 +s 1 +f 72//17 2//18 113//19 +f 113//19 2//18 3//20 112//21 +f 112//21 3//20 4//22 111//23 +f 111//23 4//22 5//24 110//25 +f 110//25 5//24 6//26 109//27 +f 109//27 6//26 7//28 108//29 +f 8//30 1//31 108//29 7//28 +f 7//28 10//32 9//33 8//30 +f 6//26 11//34 10//32 7//28 +f 5//24 12//35 11//34 6//26 +f 4//22 13//36 12//35 5//24 +f 3//20 14//37 13//36 4//22 +f 2//18 15//38 14//37 3//20 +f 72//17 15//38 2//18 +f 72//17 16//39 15//38 +f 15//38 16//39 17//40 14//37 +f 14//37 17//40 18//41 13//36 +f 13//36 18//41 19//42 12//35 +f 12//35 19//42 20//43 11//34 +f 11//34 20//43 21//44 10//32 +f 10//32 21//44 22//45 9//33 +f 21//44 24//46 23//47 22//45 +f 20//43 25//48 24//46 21//44 +f 19//42 26//49 25//48 20//43 +f 18//41 27//50 26//49 19//42 +f 17//40 28//51 27//50 18//41 +f 16//39 29//52 28//51 17//40 +f 72//17 29//52 16//39 +f 72//17 30//53 29//52 +f 29//52 30//53 31//54 28//51 +f 28//51 31//54 32//55 27//50 +f 27//50 32//55 33//56 26//49 +f 26//49 33//56 34//57 25//48 +f 25//48 34//57 35//58 24//46 +f 24//46 35//58 36//59 23//47 +f 35//58 38//60 37//61 36//59 +f 34//57 39//62 38//60 35//58 +f 33//56 40//63 39//62 34//57 +f 32//55 41//64 40//63 33//56 +f 31//54 42//65 41//64 32//55 +f 30//53 43//66 42//65 31//54 +f 72//17 43//66 30//53 +f 72//17 44//67 43//66 +f 43//66 44//67 45//68 42//65 +f 42//65 45//68 46//69 41//64 +f 41//64 46//69 47//70 40//63 +f 40//63 47//70 48//71 39//62 +f 39//62 48//71 49//72 38//60 +f 38//60 49//72 50//73 37//61 +f 49//72 52//74 51//75 50//73 +f 48//71 53//76 52//74 49//72 +f 47//70 54//77 53//76 48//71 +f 46//69 55//78 54//77 47//70 +f 45//68 56//79 55//78 46//69 +f 44//67 57//80 56//79 45//68 +f 72//17 57//80 44//67 +f 72//17 58//81 57//80 +f 57//80 58//81 59//82 56//79 +f 56//79 59//82 60//83 55//78 +f 55//78 60//83 61//84 54//77 +f 54//77 61//84 62//85 53//76 +f 53//76 62//85 63//86 52//74 +f 52//74 63//86 64//87 51//75 +f 63//86 66//88 65//89 64//87 +f 62//85 67//90 66//88 63//86 +f 61//84 68//91 67//90 62//85 +f 60//83 69//92 68//91 61//84 +f 59//82 70//93 69//92 60//83 +f 58//81 71//94 70//93 59//82 +f 72//17 71//94 58//81 +f 72//17 73//95 71//94 +f 71//94 73//95 74//96 70//93 +f 70//93 74//96 75//97 69//92 +f 69//92 75//97 76//98 68//91 +f 68//91 76//98 77//99 67//90 +f 67//90 77//99 78//100 66//88 +f 66//88 78//100 79//101 65//89 +f 78//100 81//102 80//103 79//101 +f 77//99 82//104 81//102 78//100 +f 76//98 83//105 82//104 77//99 +f 75//97 84//106 83//105 76//98 +f 74//96 85//107 84//106 75//97 +f 73//95 86//108 85//107 74//96 +f 72//17 86//108 73//95 +f 72//17 87//109 86//108 +f 86//108 87//109 88//110 85//107 +f 85//107 88//110 89//111 84//106 +f 84//106 89//111 90//112 83//105 +f 83//105 90//112 91//113 82//104 +f 82//104 91//113 92//114 81//102 +f 81//102 92//114 93//115 80//103 +f 92//114 95//116 94//117 93//115 +f 91//113 96//118 95//116 92//114 +f 90//112 97//119 96//118 91//113 +f 89//111 98//120 97//119 90//112 +f 88//110 99//121 98//120 89//111 +f 87//109 100//122 99//121 88//110 +f 72//17 100//122 87//109 +f 72//17 101//123 100//122 +f 100//122 101//123 102//124 99//121 +f 99//121 102//124 103//125 98//120 +f 98//120 103//125 104//126 97//119 +f 97//119 104//126 105//127 96//118 +f 96//118 105//127 106//128 95//116 +f 95//116 106//128 107//129 94//117 +f 1//31 107//129 106//128 108//29 +f 105//127 109//27 108//29 106//128 +f 104//126 110//25 109//27 105//127 +f 103//125 111//23 110//25 104//126 +f 102//124 112//21 111//23 103//125 +f 101//123 113//19 112//21 102//124 +f 72//17 113//19 101//123 +f 107//129 1//31 129//130 114//131 +f 94//117 107//129 114//131 115//132 +f 93//115 94//117 115//132 116//133 +f 80//103 93//115 116//133 117//134 +f 79//101 80//103 117//134 118//135 +f 65//89 79//101 118//135 119//136 +f 64//87 65//89 119//136 120//137 +f 51//75 64//87 120//137 121//138 +f 50//73 51//75 121//138 122//139 +f 37//61 50//73 122//139 123//140 +f 36//59 37//61 123//140 124//141 +f 23//47 36//59 124//141 125//142 +f 22//45 23//47 125//142 126//143 +f 9//33 22//45 126//143 127//144 +f 8//30 9//33 127//144 128//145 +f 1//31 8//30 128//145 129//130 +f 130//146 131//147 132//148 +f 131//147 133//149 132//148 +f 133//149 134//150 132//148 +f 134//150 135//151 132//148 +f 135//151 136//152 132//148 +f 136//152 137//153 132//148 +f 137//153 138//154 132//148 +f 138//154 139//155 132//148 +f 139//155 140//156 132//148 +f 140//156 141//157 132//148 +f 141//157 142//158 132//148 +f 142//158 143//159 132//148 +f 143//159 144//160 132//148 +f 144//160 145//161 132//148 +f 145//161 146//162 132//148 +f 146//162 130//146 132//148 diff --git a/org.simantics.proconf.processeditor/icons/Component.png b/org.simantics.proconf.processeditor/icons/Component.png new file mode 100644 index 0000000000000000000000000000000000000000..0d43ef5b4718a1d7d94eb0bf8ce357d53cfef487 GIT binary patch literal 511 zcmVjEtjR z14t(?M05(k+v9&{W`8F@O8Mxz?sYz&U)i<|+qMzMF_cnJN}=2BGJwLq1Xit9%T}vZ zlu9Kyj)O1^5d;B(Ab{`t!OuvP9HNx+%CfBcR4R2Qgz%)4yj(7!lp3&JAs!ly2DjU7ZZ@0jdEN+s_{*DKM=t=l_=09Kne*Xrh)$=2D2gzj&usvgM6^iM zer4u2VrFEs*{4dSax0|-04x>@gkeZT1ZIX|7|7*vn_lBMMz7a + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/org.simantics.proconf.processeditor/icons/Elbow.png b/org.simantics.proconf.processeditor/icons/Elbow.png new file mode 100644 index 0000000000000000000000000000000000000000..bbaa16eaade500534559ad606a0c4a129d3f0925 GIT binary patch literal 668 zcmV;N0%QG&P)S4k@H7!oJO(3WkC^zv>^4&=lk8G zb1o^RaGOg1ZzB=i<(xlbj6EVEmx$hv$K#j(1c>N?l(Ox4-fp#8-7S~Pnh*l5R_o>o zh)Bz3v#&hQdwzU;?B?@%aL!>E26SBqW9)i>hz_KbuMZCo4{EhqMhF4RvS6Af48s6p z47#pw2Z*R#EEeB2o6SAfbs?ohE|-IC+b~TNoO7&JD-h9kKnU^X0fo!0C1hm}eNj^iMo&!bQ%AW0JVzK<{rF&qxj>-E%f zxl~sGBDz;9l};OthLy|ZAf<%kIEdpIqtOWcejn|2``c_b`w&IZ+r?sWegzOhoE;q< zl`PAGZQBq+fQT@eOmJ~=vFLWYAA=xxs+977pE~vH^%Up){?5)0Ow&X*n}u!L2*VJA z!2sQE_e&52kN*sB006c9{rx+cOa`2DaLy6OF`_6!r_=c!1i=%f)Q@c^PXU0YX + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + diff --git a/org.simantics.proconf.processeditor/icons/Nozzle.png b/org.simantics.proconf.processeditor/icons/Nozzle.png new file mode 100644 index 0000000000000000000000000000000000000000..48cf03e84d06cb054c09a8b71616c29ca1953d46 GIT binary patch literal 421 zcmV;W0b2fvP)L z)4ys0K@i9B@3|{-_y<9ED-#k3NE)j=LdtaZR%!Drd4d%75wSM-9#)bf&54EhXK%UP zyA&a36V4p|`uQ-!%mi7MaY-r{RhI=CjmDeSde!ZAKby_wD}XEmNGY#}!{Lp!mf37} zRT>aNpp+txV}uaoK&#by7DBuL{!9mVT5F6k1VM0{1GQT1VKf>Ilv0HqOs7+{)*KE8 zs?};c2f{F<-|y4w^$LN-Vu4bMFbt7Wo<>O16z3eyxk4aKQ;abfWB9!v31F>dxm>c@ zYzl$xc1sjR9FIqmBsl?b9M8w&@qJ-6Af+6v*Xy=12Jd~81H0XB0!+>Uola*SMbV?R z7VrI64*WOHIaaF`Ns{3G&&Go?&s4A1pDLBg6F`<_@B97!qZII0F8;=EYQ})S1$e9A P00000NkvXXu0mjf3ox$a literal 0 HcmV?d00001 diff --git a/org.simantics.proconf.processeditor/icons/Nozzle.svg b/org.simantics.proconf.processeditor/icons/Nozzle.svg new file mode 100644 index 00000000..0dd815c8 --- /dev/null +++ b/org.simantics.proconf.processeditor/icons/Nozzle.svg @@ -0,0 +1,110 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/org.simantics.proconf.processeditor/icons/Straight.png b/org.simantics.proconf.processeditor/icons/Straight.png new file mode 100644 index 0000000000000000000000000000000000000000..459919e55ac8003536d5cef3d71e67a2b3f4de6a GIT binary patch literal 298 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf4nJ zFsXwu<36Df4xpf9iEBhjaDG}zd16s2LwR|*US?i)adKios$PCk`s{Z$Qb0w^JzX3_ zEPCHwQsiqk5IOeIUYm0zL;K;!%XXZsx%#GTMrzSRHfsTQ2LX;1YPD~Vxa3aWm3qE@ z|NFg9L={@oc)I$ztaD0e0s!{CbJqX> literal 0 HcmV?d00001 diff --git a/org.simantics.proconf.processeditor/icons/Straight.svg b/org.simantics.proconf.processeditor/icons/Straight.svg new file mode 100644 index 00000000..117e6ec1 --- /dev/null +++ b/org.simantics.proconf.processeditor/icons/Straight.svg @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + diff --git a/org.simantics.proconf.processeditor/icons/bubble.png b/org.simantics.proconf.processeditor/icons/bubble.png new file mode 100644 index 0000000000000000000000000000000000000000..410e2686d9a56e96bdc7e945b37ce5a7dadde5e6 GIT binary patch literal 1049 zcmV+!1m^pRP)zeyP#1xw!1n7y;gk{c~Um zSj9Y30d|Q%6BsCf9{>&lrC@gwI0d|lV3DP-+`*p$*MYadJg^9?1OmNU{dZsi3(1=7 zl;x#;!S;x3pNyV}1TxI+4t@=o#oWFu;|@>)z5!oE&Yx!iye5({Cq{&E7Ue`FFowna zy;eReZENML1p;N=YwPItdIVe-cqD)@#(hCjz{3znvzE@g$!*x!j)w{_x%<7jcz1-n@WjERpN&&iCs}XDaVER~+}Pv; z?~rl$D3O=#UUpW3FQS1Y&gfZ6X?zE>|L@AUusZ%1G=N9g?Dj8YlEP40Y!Y+W=sfw4 zz)w;9H`wHtsqvS?F)o`Mu(tYd%Th`gQcAD?0Qj|RtjByO1pfQaX(##Xzvn*z>4jjZ TBw5Tp00000NkvXXu0mjfF4Not literal 0 HcmV?d00001 diff --git a/org.simantics.proconf.processeditor/icons/bubble.svg b/org.simantics.proconf.processeditor/icons/bubble.svg new file mode 100644 index 00000000..f52235f8 --- /dev/null +++ b/org.simantics.proconf.processeditor/icons/bubble.svg @@ -0,0 +1,127 @@ + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + diff --git a/org.simantics.proconf.processeditor/icons/crosshair.png b/org.simantics.proconf.processeditor/icons/crosshair.png new file mode 100644 index 0000000000000000000000000000000000000000..379424ea7545e074b949490baca6eb300352ace3 GIT binary patch literal 661 zcmV;G0&4wR9J=0 zmoZNpK@f#MBETSns0~P|5?NSspH#F_04Y)`3TX2$qWlZmq##1+3{l$r21`T^X~C|M zjQ~-YV&2BXzJPSRZ@30rHC>)EksvemFRu#_~e%mKSPn>>_sDO&%MS;y79B0K(X6?XJ3K-gfSq38& z>};RM4x#A55nyu+0VUv-di*`M|BGqpn~7aa-4TPMH3cb#q>An8AK=g>!yRZVu8q+= z6^^s*Cqn_9e;}aaC$n~79h+)JVM&~RkEnny_Uz}dky;eC#n~coOR;~!32=?g^Lhcz z>*Bf=_Yh(Nt}rJ9HqTckXucv2#QDIYWt{`3z%O6{_&~m$sO#DVaYe1!C`Z&#+yLHT zh9b0NG5D4YHE(1U&m?>qjWVTss`m@=e8`K|a}*rwVWgKTP(O v|I8DAm^gHS-&!!3YKQUi$1(M3ICTN{x@CL|H`YoB00000NkvXXu0mjf^`#ut literal 0 HcmV?d00001 diff --git a/org.simantics.proconf.processeditor/icons/crosshair.svg b/org.simantics.proconf.processeditor/icons/crosshair.svg new file mode 100644 index 00000000..8c73e69d --- /dev/null +++ b/org.simantics.proconf.processeditor/icons/crosshair.svg @@ -0,0 +1,78 @@ + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/org.simantics.proconf.processeditor/icons/factory.png b/org.simantics.proconf.processeditor/icons/factory.png new file mode 100644 index 0000000000000000000000000000000000000000..aad23e326f7983c5bfabdfb00dc7f54b0570cb63 GIT binary patch literal 468 zcmV;_0W1EAP)T z)4_|)Q5eSY&$-<@3(Z6!W@@IaSjkotWn{A8+S%Cp50p~FM9Rj(A0S!SAX&+zS&c23 zjc}D_)R^IC#t3uon0YPcjDFoAH$0oC&U@bPdEfV(lOh77l)5p11}fNNRa4l6R}s189 zPVB|@44lMtu41y>LKXVizmMTQZoS|Uwq^KoKCK(iBciEI)%JymSiy8k=^et)HP zfD&locd@c6oowo;f));Q?qW(sCyB3la3f;$C!mR=oSbo>_RLB4T# ze`BeiS|=^s=Iltsm46=M|G9;NqQR3nYVTJsI=V8eJ0000< KMNUMnLSTYCW87;1 literal 0 HcmV?d00001 diff --git a/org.simantics.proconf.processeditor/icons/factory.svg b/org.simantics.proconf.processeditor/icons/factory.svg new file mode 100644 index 00000000..e05205cb --- /dev/null +++ b/org.simantics.proconf.processeditor/icons/factory.svg @@ -0,0 +1,308 @@ + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.simantics.proconf.processeditor/icons/middle.png b/org.simantics.proconf.processeditor/icons/middle.png new file mode 100644 index 0000000000000000000000000000000000000000..4e3d03e7280286f7d28c28f26d64f3c4a2c4e76a GIT binary patch literal 2273 zcmV<72p;!|P)0s-oz zML`9k@`##7Nh?+AhxS81R8gdUXrrpC)Q?r9R*I@NQlf@Fpot))O-N0EU_u;XNT3ej z7z4KPW7m(hclSQ#o_;tsG2klD9%(eYduQ+eKQm|M%u!lv?q(^a93WO!Ru&C{AnN;m zMHq(F0G4G9L?V%_<2c^v=%@#{TI=Ah-uq<)lv0sYDwPhyu<4OUHhh20nl)?cY8TE< zr&G~nG8GLZATv1V4rMaM8~p>>wziMjPMtda#~=vWft=Rb|DOmbr7WPVrlw}olTYsX z`PUzN^uc7ZBxWm75l57z1PBR3AqWK56Y_;n=L-_{4`lLZ&wcvuLx&Fka%gDi1Td<# z4)2b|eWLp_VQ}Wm`A`1(w*x-_&fT7pTL>tn>_j55`nl(R z@|V@Cme*FK#adV+RHTKHxL{j?;#T0BS_=@MwMofXPPpDLw0|aiel?V{pLTxs#v2Ep z1=_XNGKJ|(&v`r^uY2~Hr+>e^adGXe(!5nSN2n?nVv##N{%=}gB2=Ch;xY4Ce6hzT zYLctJvb42;|)pp=SKR#tA>`i;jnl|&0pMOqll3fU2%vRqhFXSCV* zGl2%Td>1kMpnpiHstB1otAmGX&(Tm%ye-ey@&(o_rH*K={iz6~9&O(8)6#^MDvjqE z9uYdbh0Lf>mK5BguxznO#~qQlO+*av`yUDCF9}tp=V@MZnWhI}{c2QqA9H(d@S{NZ z0LVH@DJLF}H?3H)tg$3IVWmoiE7yeH0ijqFMn{Ew-jvzO2BD^M8j0J8hzK_Zh4)Si z@16`ecH&cP-9t75d$&RJdN^}|$j~rNL7tULspB?~SiXGO^D7=&vUWj@XVuO1@O_WW zu*cY#N1@;`n)4VQ@d&j?D&bLD;$c}HXb&(t5RV%J9xbgNhmMT$&b#Nhc71?C5j4=$ z2y?38N)KGVLab0EuQl&EK&1Y@+SQiITh+4zYN|}VyPom9=Z4_A!gx-Y$P1n;tXnC} zulb@G1)h@>IQ>x{p09~GuwV{sS_k!YkW4_+GH5x4lO1727!q*+r>rbl z93IVyCke@KA*|1hvI7hH7q4!3>fkVB#^y+mkcL{y~ z5eMpP;i;YQu(9|dl4hcPd z1~dqS@p04f5+y#Rv0*00v;6762(KRS>ADJj0L~Qn6Gj%*8A4$QsT8D=VB3@evz;&u ztHV&@BA!wRs7XNxMQ~l8T+SzxDU!>L<9ic`JI=t8F|wJEcTd2d4{{S6pezMjx4@q5 zu&CaEPc7SlXcVO^l0dZ+1c5$!^oSo8eYQO!=n5ea;bLdV{x^l!{{bDBp-_Za6qep^ za=PJRC`$uss+Dr*y8W2~tXpkuphSYg-g(t-*_QRbDk}@P_<6|wH#G+iL&qg3x|84! z!0zp^>zmN9#DsEoIY+x~rQ(&*vo@P>#)a zs;j74|1c_FfWN;5`wzjzPH?^3z;{5yVu(h;vLT&@1@nwo*Lw|#ATauRpZR^kJVPSX z&~**|*#g&k==B4BX9F={XFSfr`|GhpjKPN=8_%Or1GsyK0bjZpBGJh(D&tw%3?zJi zl0>huslU%e;QbHb$T7mfAv(g4*X+sjV7XGPnq7g@xYUHOrw=Cb@W3JizI*4L;CGOi zKS`qJ3ldX}XnCX2Z@vv}?fByp9M+n5Y#`K{JetQ7C8XD_g%!&n7BeOD=w|rVc9Zj& zz;BYU?~FvD01Fqu_Q&BXYvEci9DEBpyXf~keg%B)XsrXK)LGY~{bDE8$4?P?_S>*` z7i`%Cb8FzfT8PAE*yXpaNDLM&f~WSHs2o2Dn>N7iCk&~U6L7H;-}Pt*&T6d#CMTi@ zuq~0Gd-F!Z*Iq^sbfMi0T1L@2cW>fl(cKr&Er-!pE};85(XYLX-n@}8k)Rvc21K;h zSOAlATC3}F^g;*4{jbBBvrup+>-HWc5`zT`Vco-~O3r=)`(K9(9TZ)cqd@D_Y&d-) z8WZ7#kx}LyZ)Hm?P6P|qu7+8&OpfnmX>A;6I|HxmgX69EBcr@8!VAFIG(&w;FpX)A z))C3JnO^Mo*36ubGIq3Kd+S`r3bdg{% zL$B-7BEm1Y+l$FG5*APfeARLIVJya~WRl9tN}QT%tW?UJY5<;x&gGzgfN*GtV0@e* z*X83N;J3gj?)7RmLrPM>O3PxGW${onN|kMsP>Ljg){Kjg_dEu}kWa#p1Hf7SpUdeC vL>$by5doq=1yDWtcmT)(9^i8i*Yp1XtDgNS^Y&Cz00000NkvXXu0mjfe9%Op literal 0 HcmV?d00001 diff --git a/org.simantics.proconf.processeditor/icons/middle.svg b/org.simantics.proconf.processeditor/icons/middle.svg new file mode 100644 index 00000000..670c3b42 --- /dev/null +++ b/org.simantics.proconf.processeditor/icons/middle.svg @@ -0,0 +1,190 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/org.simantics.proconf.processeditor/icons/plus.png b/org.simantics.proconf.processeditor/icons/plus.png new file mode 100644 index 0000000000000000000000000000000000000000..1d6b816ff72c869fcb19beae7dc84d4e506f9a6c GIT binary patch literal 2098 zcmV-22+jA2P)j%Zi6Us(k6A{sQXpjR~l9@-{S+B$U|$4=AKZtA8D zX-Fw>Z{M659=>&a$yQ0rkw)LQv*$bi|D4Or8D*{IYD6jJ0kKRb6KJi2Fbunm zF}(nekWLDz4T9$iAYcV!gjP#fC=2sNp->WvC1Ymi zOXWi^{QKq6H^v?V&UFgQWdxK`emb2VeB`?i{rTX*dv+uf#?7XL-mI{3gAjOv?+Qvq z;Hyc5p-^uMrLu7Lyzs%S*tvqybu4bChaUXXjXSUJ?@HF3>#h-USs~`Ftk@V~t{_ajE!67K@4y#^b_iQ~ zBa*%=WYa=C7QIU-Zgr_|`xkGy`H9y@#~xHleXyJp-ik9w4-ens6{g=4N)=T!nV%{qJ^1vXWX+h)skJY%lR_8XQ)Qi^IaM=T?1H*Uyd}G2%^>o$f%?fdU6)AAf#X6Z z4V!zR*;;GE+Gw?l68s5>#rS4P?6D z(MRB$UyVLkEnx^J-h@B?6&6a-TqX^VJ`8(yf$y)?cOB^KjcjTYVN{ktge9Qh0Xo#= z=kl1T8QdM)p(_J>c7y5At27!>fyIKgs~p?~2M#p~xBp>s+l=G#5`qN!Lk?fkFu;PC>qi7Q;y(bby92JX@`j zpFRU;|4Wp3>I!4MTtUCljBHPzfohe!F+2-2oOYWu*=#ZK&J5wpN8!Reh>ccz+2}-K z^<0N<#6~t>J__&55H?#(0F%~Q?X*o)wC2f+1!hM^v15}^s(}3%gE(9+AERegWNT~^ zMnzMTWa_uYmX z9)@k#MMr8f8P)ZrM6{qaRI5-Z!rAxX@L_mu1bcdlMybSWTJuw`)RwOz;Q{@w%P(Rv zhBx)F<@zt+4Qz+OK^WK`ooa47fTE#NfvIVjn24Td-a%h1aG}}cun526YA+_MNH{?P;oY0y-0LS>GSF;WwNdY%G z4&QPdb_D^OT$hAWBmu0YDnhN*;-WFUX$;Q*ll(uI(+)&DAO`qA0CWSr?Z4-NBG3Xt cKEd_;f0wF@FkrQV4FCWD07*qoM6N<$f?ay!P5=M^ literal 0 HcmV?d00001 diff --git a/org.simantics.proconf.processeditor/icons/plus.svg b/org.simantics.proconf.processeditor/icons/plus.svg new file mode 100644 index 00000000..7338a019 --- /dev/null +++ b/org.simantics.proconf.processeditor/icons/plus.svg @@ -0,0 +1,184 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/org.simantics.proconf.processeditor/icons/tank.png b/org.simantics.proconf.processeditor/icons/tank.png new file mode 100644 index 0000000000000000000000000000000000000000..44015a37104357c720234e16a8932442708ceb4e GIT binary patch literal 428 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4w z)A}ZAbKmKs=PpCfl%|8ft8Df?fBI@>-1~+9zD+AjOG`hQG9~9)_xZB5Vy4E$4oXwc zyK9Kph%Twwcfxh`)DMjROrO`x%Sm|lL-s;u*y`rXA1e-fJ8lk>W{_3StP=$HvPd$HI_DI4keB%0tTe(viR1B+oH!@7=GSEDv!mw1}iPMDWCk}5e z&*tAesf76o1LMp4J5+4)>kab+w@jCbIrjE-zRBjV25*>o9{OGS?f)nGVEiY>huZ!A U?w#r_z>sC|boFyt=akR{0MgH`0ssI2 literal 0 HcmV?d00001 diff --git a/org.simantics.proconf.processeditor/icons/tank.svg b/org.simantics.proconf.processeditor/icons/tank.svg new file mode 100644 index 00000000..8e8784f1 --- /dev/null +++ b/org.simantics.proconf.processeditor/icons/tank.svg @@ -0,0 +1,184 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/org.simantics.proconf.processeditor/icons/translate_d.png b/org.simantics.proconf.processeditor/icons/translate_d.png new file mode 100644 index 0000000000000000000000000000000000000000..f4b3b6088d19e913aacba188588c001ca91bd2a9 GIT binary patch literal 363 zcmV-x0hIoUP)hM_!|ulpyOe}JWxb~VAi!(CWD|$KHAfxC-uQXfdYr9jS-I2IWa0}!nkp}|jkX}SRI(_yuzu$Y$ zi#v_lNqlco0Duu8IbbvaC4m9pl>rZeN{|7m0L+jTD-rxEEcTPy4QD)q2m>9U0m?Zm zW#wVv#p`EYOw%Y`0{|o~WsQx!@uRNSl~4S{YP;xq{D0;CfG^}Oi8C(bXEXo+002ov JPDHLkV1iKplV$(_ literal 0 HcmV?d00001 diff --git a/org.simantics.proconf.processeditor/icons/translate_d.svg b/org.simantics.proconf.processeditor/icons/translate_d.svg new file mode 100644 index 00000000..16669294 --- /dev/null +++ b/org.simantics.proconf.processeditor/icons/translate_d.svg @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + diff --git a/org.simantics.proconf.processeditor/icons/x-axis.png b/org.simantics.proconf.processeditor/icons/x-axis.png new file mode 100644 index 0000000000000000000000000000000000000000..8eb8a0d501db42ac4a22fcac9306857c57fcf42c GIT binary patch literal 380 zcmV-?0fYXDP)L z(!VRlVH5@M&-IE(QDnAA5{pHV + + + + + + + + image/svg+xml + + + + + + + X + + + diff --git a/org.simantics.proconf.processeditor/icons/x-plane.png b/org.simantics.proconf.processeditor/icons/x-plane.png new file mode 100644 index 0000000000000000000000000000000000000000..6b57f1ee7e80bbffce05b5de0d7477bf195ed6dc GIT binary patch literal 439 zcmV;o0Z9IdP)?~Fl$5DBIa=>md3Qy7Gh%2d99LeNJ@ks@hr?8M4KOG`n8K*}T!kU$z6 z38WB#heLe?)>P21NZK=&$?@`yG4YEfGM2j=NjJNRfjM7MzM+)5usC@ z!8xvq#t*p0Y(-!T7kHZA)$s?v(I^@dKH(=G<=PTjSS*9%|=8tOR_fPVh5Y~@@H(Nlpc4nh1H%Ba;=Hi zMIMJe8T1nAR|AfS&6H9TllWc=j3DKZ zj`PtIS{u8#O({Jr1?m{b-vO@r;XHNLF{ShjFSY;qFpOdcPq5Inb$6XS=0}`i>i;I* h7kLZ6VId-p;2+vrAPR&5^yB~l002ovPDHLkV1k^rxJ&>5 literal 0 HcmV?d00001 diff --git a/org.simantics.proconf.processeditor/icons/x-plane.svg b/org.simantics.proconf.processeditor/icons/x-plane.svg new file mode 100644 index 00000000..316d3ce6 --- /dev/null +++ b/org.simantics.proconf.processeditor/icons/x-plane.svg @@ -0,0 +1,89 @@ + + + + + + + + + image/svg+xml + + + + + + + X + + + + diff --git a/org.simantics.proconf.processeditor/icons/y-axis.png b/org.simantics.proconf.processeditor/icons/y-axis.png new file mode 100644 index 0000000000000000000000000000000000000000..ca60724b69e1fba257632d01d2f964f9d6ac2767 GIT binary patch literal 340 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#VfERP@Z##WBR9cj+ZVFXlvnqaW`dnc(Eo z%@X*5sY`5;c?5U<14)~Pr3n+YBO)p|yn|Owy|F@l!&ad!Q#Te&OquL^=gC2l{2A}h ze|Xk?W=luZVKt>P + + + + + + + + image/svg+xml + + + + + + + Y + + + diff --git a/org.simantics.proconf.processeditor/icons/y-plane.png b/org.simantics.proconf.processeditor/icons/y-plane.png new file mode 100644 index 0000000000000000000000000000000000000000..59c3a2bb81906070ac3ce618f5d2f9243406a3b9 GIT binary patch literal 371 zcmV-(0gV2MP)* z(y>ZIK@bJdvr#N8G$2@8S{Nj@VwIl=h+yjnXzw4`iM3cN+6!9Ss-0FMf)Nw~Dqk*&uQhfuZ(41X_wOydFf3XZtavlv4Fq&L?&hWX^ryD;KC^ z3eO`{)vGRb$1$Zehh@d|4YLXCVFr!9!5HS{Gf(h{+Ngunvxw;60*#2cgm2S@+u!#6 Rh7JG#002ovPDHLkV1g1qm>2*6 literal 0 HcmV?d00001 diff --git a/org.simantics.proconf.processeditor/icons/y-plane.svg b/org.simantics.proconf.processeditor/icons/y-plane.svg new file mode 100644 index 00000000..69d38142 --- /dev/null +++ b/org.simantics.proconf.processeditor/icons/y-plane.svg @@ -0,0 +1,89 @@ + + + + + + + + + image/svg+xml + + + + + + + Y + + + + diff --git a/org.simantics.proconf.processeditor/icons/z-axis.png b/org.simantics.proconf.processeditor/icons/z-axis.png new file mode 100644 index 0000000000000000000000000000000000000000..11a574179c2b2cea5920ef2a9f50b2f89c7217dd GIT binary patch literal 357 zcmV-r0h<1aP)L z(y=atQ4j^-Z`i186hxvEjVMH-@Bmh!(})M)8N7i+sZw|V51?cpK%$a}XlaGShH4W# znl1KU|K80q$rSg_oH=vOy^)#z6OF+`L^RPZ^dDvBV+Av~K}0mLQv*E4GBz`_Q>kQT zF>!!Ttk>4ZfH&}k{gFKd@B*H3QX;8%FyuwM&%T$Ly-}_ + + + + + + + + image/svg+xml + + + + + + + Z + + + diff --git a/org.simantics.proconf.processeditor/icons/z-plane.png b/org.simantics.proconf.processeditor/icons/z-plane.png new file mode 100644 index 0000000000000000000000000000000000000000..d6e9f708adbedd26ad8725e4c6dfa35243f80a2a GIT binary patch literal 422 zcmV;X0a^ZuP)-gIQ4j>+XKyYcpaemKg&$a?4HB?RVG+baA*8ePS6HM|NMUCe`~m5;u@DPwO(h~W zDu_tb2nuOJFpkB218?M>+$@}GcV=g2&sGvpRSS5Q)|rK;3Z~~7~lq8;T{fJdaLRjo_EbwlI+1D^8k17yV3b{ zC-(!+_jALJb%707*qoM6N<$f*7i}ssI20 literal 0 HcmV?d00001 diff --git a/org.simantics.proconf.processeditor/icons/z-plane.svg b/org.simantics.proconf.processeditor/icons/z-plane.svg new file mode 100644 index 00000000..d1a654c3 --- /dev/null +++ b/org.simantics.proconf.processeditor/icons/z-plane.svg @@ -0,0 +1,89 @@ + + + + + + + + + image/svg+xml + + + + + + + Z + + + + diff --git a/org.simantics.proconf.processeditor/plugin.xml b/org.simantics.proconf.processeditor/plugin.xml new file mode 100644 index 00000000..55bc77f3 --- /dev/null +++ b/org.simantics.proconf.processeditor/plugin.xml @@ -0,0 +1,266 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/Activator.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/Activator.java new file mode 100644 index 00000000..9f2ad49d --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/Activator.java @@ -0,0 +1,97 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor; + +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.BundleContext; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.management.ISessionContext; +import org.simantics.db.management.ISessionContextChangedListener; +import org.simantics.db.management.SessionContextChangedEvent; +import org.simantics.proconf.ui.ProConfUI; + + + + +/** + * The activator class controls the plug-in life cycle + */ +public class Activator extends AbstractUIPlugin { + + // The plug-in ID + public static final String PLUGIN_ID = "fi.vtt.simantics.processeditor"; + + // The shared instance + private static Activator plugin; + + /** + * The constructor + */ + public Activator() { + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext) + */ + public void start(BundleContext context) throws Exception { + super.start(context); + plugin = this; + ProConfUI.getSessionContextProvider().addContextChangedListener(new ISessionContextChangedListener() { + @Override + public void sessionContextChanged(SessionContextChangedEvent event) { + ISessionContext ctx = event.getNewValue(); + if (ctx != null) { + ctx.getSession().asyncRead(new GraphRequestAdapter() { + public GraphRequestStatus perform(Graph g) throws Exception { + ProcessResource.initialize(g); + return GraphRequestStatus.transactionComplete(); + }; + }); + } else { + ProcessResource.deinitialize(); + } + } + }); + try { + ProConfUI.getSession().asyncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + ProcessResource.initialize(g); + return GraphRequestStatus.transactionComplete(); + } + }); + } catch (Exception e) { + + } + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext) + */ + public void stop(BundleContext context) throws Exception { + plugin = null; + super.stop(context); + } + + /** + * Returns the shared instance + * + * @return the shared instance + */ + public static Activator getDefault() { + return plugin; + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/ProcessResource.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/ProcessResource.java new file mode 100644 index 00000000..a7df93c9 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/ProcessResource.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor; + +import org.simantics.db.Builtins; +import org.simantics.db.Graph; +import org.simantics.proconf.g3d.stubs.G3DResource; + +import fi.vtt.simantics.processeditor.common.ControlPointTools; +import fi.vtt.simantics.processeditor.stubs.Plant3DResource; + +public class ProcessResource { + public static Builtins builtins; + public static G3DResource g3dResource; + public static Plant3DResource plant3Dresource; + + + public static void initialize(Graph g) { + ProcessResource.builtins = Builtins.getInstance(g); + ProcessResource.g3dResource = G3DResource.getInstance(g); + ProcessResource.plant3Dresource = Plant3DResource.getInstance(g); + ControlPointTools.initialize(); + } + + public static void deinitialize() { + builtins = null; + g3dResource = null; + plant3Dresource = null; + ControlPointTools.deinitialize(); + } + + public static boolean isInitialized() { + return builtins != null; + } +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/InsertComponentAction.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/InsertComponentAction.java new file mode 100644 index 00000000..50f8fed4 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/InsertComponentAction.java @@ -0,0 +1,403 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.actions; + +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.util.ArrayList; +import java.util.List; + +import javax.vecmath.Point3d; + +import org.eclipse.swt.widgets.Display; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.GraphRequestWithResult; +import org.simantics.db.Resource; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.proconf.g3d.actions.InteractiveAction; +import org.simantics.proconf.g3d.base.G3DAPI; +import org.simantics.proconf.g3d.base.G3DTools; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.common.StructuredResourceSelection; +import org.simantics.proconf.g3d.dnd.DropListener; +import org.simantics.proconf.g3d.scenegraph.IGraphicsNode; +import org.simantics.utils.datastructures.Pair; + +import fi.vtt.simantics.processeditor.Activator; +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.common.ControlPointTools; +import fi.vtt.simantics.processeditor.common.PipingTools2; +import fi.vtt.simantics.processeditor.common.PipingTools2.Direction; +import fi.vtt.simantics.processeditor.dialogs.PipelineComponentDialog; +import fi.vtt.simantics.processeditor.gizmo.PositionSelectionGizmo; +import fi.vtt.simantics.processeditor.stubs.PipeControlPoint; +import fi.vtt.simantics.processeditor.stubs.PipelineComponent; + + + +/** + * Action that inserts new components into pipe run. + * - VariableLengthInlineComponents cannot be inserted with this action + * - Assumes that SizeChangeComponent is dual connected + * + * + * @author Marko Luukkainen + * + */ +public class InsertComponentAction extends InteractiveAction implements DropListener, SplitPointListener { + + Resource typeResource; // type of inserted component + Resource targetResource; // component where we are inserting new one + Resource selectedPosition; // selected control point for insertion + PositionType selectedType; // selected position type + List> insertPositions; + List> insertPoints; + PositionSelectionGizmo gizmo = null; + + boolean activated = false; + + private SelectSplitPointAction splitPointAction; + + public InsertComponentAction(ThreeDimensionalEditorBase parent) { + super(parent); + splitPointAction = new SelectSplitPointAction(parent,this); + } + + @Override + public void init() { + this.setText("Insert Component"); + this.setToolTipText("Inserts a Component into Pipeline"); + this.setImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/Component.png")); + } + + @Override + public boolean usable(Graph graph, List resources) { + if (!(resources.size() == 1)) { + return false; + } + IEntity target = EntityFactory.create(graph,resources.get(0)); + + if (!target.isInstanceOf(ProcessResource.plant3Dresource.PipelineComponent)) { + return false; + } + PipelineComponent ic = new PipelineComponent(target); + PipeControlPoint pcp = ic.getControlPoint(); + // one possibility: adding new component to unconnected position + // TODO : how about inserting new components between existing ones. + // TODO : can there be fixed length components that can be split (for example fixed length pipe) + if (pcp.getNext() == null && pcp.getPrevious() == null) + return true; + if (ic.isInstanceOf(ProcessResource.plant3Dresource.InlineComponent) && (pcp.getNext() == null || pcp.getPrevious() == null)) + return true; + for (PipeControlPoint p : pcp.getSubPoint()) + // SubPoint's other connection is always null + // Exception: size change components offset point (that is subpoint) + // does have one or both ends connected, but it won't matter + // here because previous test fould return true, if insertion + // is possible: + // TODO : here we assume that Size Change Component is dual connected + if (p.getNext() == null && p.getPrevious() == null) + return true; + + if (target.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent)) { + // last option to insert component is split variable length component. + // If user chooses to split the component, inserted component must be + // inline component, but not size change component + return true; + } + return false; + } + + @Override + public void activate() { + insertPositions = null; + if (targetResource == null) { + List mos = parent.getSelectionAdapter().getSelectedObjects(); + if (mos.size() != 1) { + end(); + return; + } + IGraphicsNode startNode = mos.get(0); + targetResource = startNode.getResource(); + } + if (selectedPosition == null) { + updateInsertPositions(); + } + if (typeResource == null) { + + List filter = new ArrayList(); + filter.add(ProcessResource.plant3Dresource.VariableLengthInlineComponent); + + boolean containsEnd = false; + for (Pair p : insertPoints) { + if (p.second == PositionType.NEXT || p.second == PositionType.PREVIOUS) { + containsEnd = true; + break; + } + + } + if(!containsEnd) + filter.add(ProcessResource.plant3Dresource.EndComponent); + + PipelineComponentDialog dialog = new PipelineComponentDialog(Display.getCurrent().getActiveShell(),null, filter , parent.getSession()); + if (dialog.open() == PipelineComponentDialog.CANCEL) { + end(); + return; + } + typeResource = dialog.getComboValue(); + updateInsertPositions(); + } + + activated = true; + } + + private void updateInsertPositions() { + parent.getSession().syncRead(new GraphRequestAdapter() { + + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + insertPositions = getInsertPositions(g,targetResource,typeResource); + insertPoints = new ArrayList>(); + for (Pair p : insertPositions) { + IEntity entity = EntityFactory.create(g,p.first); + Point3d pos = ControlPointTools.getRealPosition(entity, p.second); + insertPoints.add(new Pair(pos,p.second)); + } + return GraphRequestStatus.transactionComplete(); + } + }); + } + + /** + * Finds possible locations of inserted component + * + * TODO (s): currently allows only inline, non size change components to split variable length component + * assumes that size change component is DualConnected component + * + * @param g + * @param target + * @param acceptSplit + * @return + */ + private List> getInsertPositions(Graph g, Resource target, Resource typeResource) { + + boolean acceptSplit = true; + boolean checkSubPoints = !g.isInstanceOf(target, ProcessResource.plant3Dresource.DualInlineControlPoint); + if (typeResource != null) + acceptSplit = g.isInstanceOf(typeResource, ProcessResource.plant3Dresource.InlineComponent) && + !g.isInstanceOf(typeResource, ProcessResource.plant3Dresource.SizeChangeComponent); + + + List> insertPositions = new ArrayList>(); + PipelineComponent ic = new PipelineComponent(g,target); + PipeControlPoint pcp = ic.getControlPoint(); + if (pcp.getNext() == null) { + insertPositions.add(new Pair(pcp.getResource(),PositionType.NEXT)); + } + if (pcp.getPrevious() == null) { + insertPositions.add(new Pair(pcp.getResource(),PositionType.PREVIOUS)); + } + if (checkSubPoints) { + for (PipeControlPoint p : pcp.getSubPoint()) { + if (p.getNext() == null && p.getPrevious() == null) { + insertPositions.add(new Pair(p.getResource(),PositionType.PORT)); + } + } + } + if (acceptSplit && ic.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent)) { + insertPositions.add(new Pair(pcp.getResource(),PositionType.SPLIT)); + } + return insertPositions; + } + + @Override + public void update() { + if (splitPointAction.active()) { + splitPointAction.update(); + return; + } + if (!activated) { + return; + } + if (insertPositions == null) + return; + if (insertPositions.size() == 0) { + end(); + return; + } + if (insertPositions.size() == 1) { + activated = false; + insertComponent(insertPositions.get(0)); + return; + } + + if (gizmo == null) { + gizmo = new PositionSelectionGizmo(parent,insertPoints); + parent.setGizmo(gizmo); + parent.getRenderingComponent().getNoShadowRoot().attachChild(gizmo.getNode()); + } + gizmo.update(); + if (gizmo.getSelected() >= 0 && input.mouseClicked() && input.clickButton() == MouseEvent.BUTTON1) { + activated = false; + insertComponent(insertPositions.get(gizmo.getSelected())); + } + if (input.keyPressed(KeyEvent.VK_ESCAPE)) { + end(); + } + } + + private void insertComponent(Pair position) { + selectedPosition = position.first; + selectedType = position.second; + switch (selectedType) { + case NEXT: + case PREVIOUS: + case PORT: + parent.getSession().asyncWrite(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + IEntity pcp = EntityFactory.create(g,selectedPosition); + Point3d point = ControlPointTools.getRealPosition(pcp, selectedType); + IEntity component = instantiateComponent(g,point); + PipingTools2.insertComponent(component, EntityFactory.create(g, targetResource), pcp , Direction.NEXT); + endThreaded(); + return GraphRequestStatus.transactionComplete(); + } + + + }); + break; + case SPLIT: + parent.getSession().asyncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + PipeControlPoint pcp = new PipeControlPoint(g,selectedPosition); + Point3d p1 = new Point3d(); + Point3d p2 = new Point3d(); + ControlPointTools.getInlineControlPointEnds(pcp, p1, p2); + splitPointAction.setSplit(p1, p2); + splitPointAction.activate(); + return GraphRequestStatus.transactionComplete(); + } + }); + break; + } + } + + private void endThreaded() { + parent.getRenderingComposite().getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + end(); + } + }); + } + + @Override + public void setSplitPoint(final Point3d point) { + splitPointAction.deactivate(); + if (point == null) { + end(); + return; + } + parent.getSession().asyncWrite(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + IEntity component = instantiateComponent(g,point); + PipingTools2.splitVariableLengthComponent(component, EntityFactory.create(g,targetResource)); + + return GraphRequestStatus.transactionComplete(); + } + + @Override + public void requestCompleted(GraphRequestStatus status) { + parent.getRenderingComposite().getDisplay().asyncExec(new Runnable(){ + @Override + public void run() { + end(); + + } + }); + } + }); + } + + /** + * instantiates selected component + * @param worldPosition position of the new component + */ + private PipelineComponent instantiateComponent(Graph g,Point3d worldPosition) { + PipelineComponent target = new PipelineComponent(g,targetResource); + IEntity piperun = target.getParent(); + PipelineComponent instance = PipingTools2.instantiatePipelineComponent(g,piperun.getResource(), typeResource); + G3DTools.resetTransformation(instance); + //G3DAPI.addNodeWorld(piperun, instance); + G3DAPI.setWorldPosition(instance, worldPosition); + return instance; + } + + @Override + public void deactivate() { + typeResource = null; + targetResource = null; + selectedPosition = null; + selectedType = null; + insertPoints = null; + insertPositions = null; + if (gizmo != null) { + parent.setGizmo(null); + gizmo = null; + } + } + + public boolean acceptDrop(StructuredResourceSelection s, Resource[] ids) { + if(s.size() != 1) + return false; + if (ids == null) + return false; + if (ids.length != 1) + return false; + + final Resource type = ids[0]; + final Resource target = s.getSelectionList().get(0); + GraphRequestWithResult query = new GraphRequestWithResult() { + @Override + public Boolean performWithResult(Graph g) throws Exception { + IEntity entity = EntityFactory.create(g, type); + // dropped type must be pipeline component + if (!entity.isInstanceOf(ProcessResource.plant3Dresource.PipelineComponent)) + return false; + // but not variable length inline component + if (entity.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent)) + return false; + if (entity.getRelatedObjects(ProcessResource.plant3Dresource.HasGraphics).size() != 1) + return false; + + List> insertPositions = getInsertPositions(g,target,type); + return insertPositions.size() > 0; + } + }; + + parent.getSession().syncRead(query); + + return query.getResult(); + } + + public void doDrop(StructuredResourceSelection s, Resource[] ids) { + typeResource = ids[0]; + targetResource = s.getSelectionList().get(0); + parent.setCurrentAction(this); + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/InsertEquipmentAction.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/InsertEquipmentAction.java new file mode 100644 index 00000000..26556b82 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/InsertEquipmentAction.java @@ -0,0 +1,115 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.actions; + +import java.util.List; + +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.GraphRequestWithResult; +import org.simantics.db.Resource; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.proconf.g3d.actions.ContextAction; +import org.simantics.proconf.g3d.base.G3DAPI; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.common.StructuredResourceSelection; +import org.simantics.proconf.g3d.dnd.DropListener; +import org.simantics.proconf.g3d.stubs.G3DNode; + + + +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.common.PipingTools2; +import fi.vtt.simantics.processeditor.dialogs.EquipmentDialog; +import fi.vtt.simantics.processeditor.stubs.Equipment; + +public class InsertEquipmentAction extends ContextAction implements DropListener{ + + + public InsertEquipmentAction(ThreeDimensionalEditorBase parent) { + super(parent); + this.setText("Insert Equipment"); + } + + @Override + public void run() { + EquipmentDialog dialog = new EquipmentDialog(parent.getRenderingComposite().getShell(),"Insert Equipment",parent.getSession()); + if (dialog.open() == EquipmentDialog.CANCEL) + return; + final Resource typeResource = dialog.getComboValue(); + parent.getSession().asyncWrite(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + createEquipment(g,typeResource); + return GraphRequestStatus.transactionComplete(); + } + }); + } + + + + + private void createEquipment(Graph graph,Resource typeResource) { + + //G3DNode instanceNode = new G3DNode(graph, instance); + Equipment instanceNode = PipingTools2.instantiateEquipment(graph, typeResource); + G3DNode plant = parent.getScenegraphAdapter().getRootNode().getG3DNode(graph); + + G3DAPI.addNodeWorld(plant, instanceNode); + + //parent.getSelectionAdapter().updateSelection(new StructuredResourceSelection(instance))); + } + + public boolean usable(Graph graph,List resources) { + return (resources.size() == 0); + } + + + + public boolean acceptDrop(StructuredResourceSelection s, Resource[] ids) { + if(!s.isEmpty()) + return false; + if (ids == null) + return false; + if (ids.length != 1) + return false; + final Resource r = ids[0]; + GraphRequestWithResult query = new GraphRequestWithResult() { + @Override + public Boolean performWithResult(Graph g) throws Exception { + IEntity t = EntityFactory.create(g, r); + if(!t.isInheritedFrom(ProcessResource.plant3Dresource.Equipment)) + return false; + if (t.getRelatedObjects(ProcessResource.plant3Dresource.HasGraphics).size() == 1) + return true; + return false; + } + }; + + parent.getSession().syncRead(query); + return query.getResult(); + } + + public void doDrop(StructuredResourceSelection s, Resource[] ids) { + final Resource typeResource = ids[0]; + parent.getSession().asyncWrite(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + createEquipment(g,typeResource); + return GraphRequestStatus.transactionComplete(); + } + }); + + + } +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/InsertNozzleAction.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/InsertNozzleAction.java new file mode 100644 index 00000000..91733ab0 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/InsertNozzleAction.java @@ -0,0 +1,139 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.actions; + +import java.util.List; + +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.GraphRequestWithResult; +import org.simantics.db.Resource; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.layer0.utils.instantiation.Instance; +import org.simantics.layer0.utils.instantiation.InstanceFactory; +import org.simantics.proconf.g3d.actions.WriteAction; +import org.simantics.proconf.g3d.base.G3DAPI; +import org.simantics.proconf.g3d.base.G3DTools; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.common.StructuredResourceSelection; +import org.simantics.proconf.g3d.dnd.DropListener; + +import fi.vtt.simantics.processeditor.Activator; +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.common.PipingTools2; +import fi.vtt.simantics.processeditor.dialogs.NozzleDialog; +import fi.vtt.simantics.processeditor.stubs.Equipment; +import fi.vtt.simantics.processeditor.stubs.Nozzle; + + + +public class InsertNozzleAction extends WriteAction implements DropListener { + + Resource equipmentResource = null; + Resource nozzleType = null; + + public InsertNozzleAction(ThreeDimensionalEditorBase parent) { + super(parent,false); + } + + @Override + public boolean canActivate() { + NozzleDialog dialog = new NozzleDialog(parent.getRenderingComposite().getShell(),"Select a nozzle", parent.getSession()); + if (dialog.open() == NozzleDialog.CANCEL) { + equipmentResource = null; + return false; + } + Resource type = dialog.getComboValue(); + if (type == null) { + equipmentResource = null; + return false; + } + nozzleType = type; + return true; + } + + @Override + public GraphRequestStatus doChanges(Graph graph) throws Exception { + createNozzle(graph); + return GraphRequestStatus.transactionComplete(); + } + + private void createNozzle(Graph graph) { + assert(nozzleType != null); + assert(equipmentResource != null); + + Nozzle n = PipingTools2.instantiateNozzle(graph, nozzleType); + + Equipment equipment = new Equipment(graph, equipmentResource); + + G3DAPI.addNodeLocal(equipment,ProcessResource.plant3Dresource.HasNozzle, n); + //parent.getSelectionAdapter().updateSelection(new StructuredResourceSelection(n.getResource())); + equipment = null; + } + + public boolean usable(Graph graph, List resources) { + if (resources.size() != 1) { + return false; + } + Resource r = resources.iterator().next(); + IEntity t = EntityFactory.create(graph,r); + if (t.isInstanceOf(ProcessResource.plant3Dresource.Equipment)) { + equipmentResource = r; + return true; + } + return false; + } + + @Override + public void init() { + setText("Insert Nozzle"); + this.setImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/Nozzle.png")); + } + + public boolean acceptDrop(StructuredResourceSelection s, Resource[] ids) { + if(s.size() != 1) + return false; + if (ids == null) + return false; + if (ids.length != 1) + return false; + final Resource r = ids[0]; + final Resource selectedResource = s.iterator().next(); + GraphRequestWithResult query = new GraphRequestWithResult() { + @Override + public Boolean performWithResult(Graph g) throws Exception { + IEntity t = EntityFactory.create(g,r); + if (!t.isInheritedFrom(ProcessResource.plant3Dresource.Nozzle)) + return false; + t = EntityFactory.create(g,selectedResource); + if (t.isInstanceOf(ProcessResource.plant3Dresource.Equipment)) { + return true; + } + return false; + } + }; + parent.getSession().syncRead(query); + return query.getResult(); + } + + public void doDrop(StructuredResourceSelection s, Resource[] ids) { + equipmentResource = s.iterator().next(); + parent.getSession().asyncWrite(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + createNozzle(g); + return GraphRequestStatus.transactionComplete(); + } + }); + } +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/PositionType.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/PositionType.java new file mode 100644 index 00000000..0ab3a5b7 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/PositionType.java @@ -0,0 +1,15 @@ +package fi.vtt.simantics.processeditor.actions; + + +/** + * Position types for inserting new components and routing new pipe + * + * @author Marko Luukkainen + * + */ +public enum PositionType { + SPLIT, + NEXT, + PREVIOUS, + PORT +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/ReversePipelineAction.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/ReversePipelineAction.java new file mode 100644 index 00000000..a75d7e0d --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/ReversePipelineAction.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.actions; + +import java.util.List; + +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Resource; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.proconf.g3d.actions.WriteAction; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; + + +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.common.PipingTools2; +import fi.vtt.simantics.processeditor.stubs.PipelineComponent; + +public class ReversePipelineAction extends WriteAction { + + public ReversePipelineAction(ThreeDimensionalEditorBase parent) { + super(parent,false); + } + + @Override + public boolean usable(Graph graph, List resources) { + if (resources.size() != 1) + return false; + IEntity t = EntityFactory.create(graph, resources.get(0)); + return (t.isInstanceOf(ProcessResource.plant3Dresource.PipelineComponent)); + } + + @Override + public GraphRequestStatus doChanges(Graph graph) throws Exception { + Resource r = parent.getSelectionAdapter().getSelectedResources().get(0); + PipelineComponent comp = new PipelineComponent(graph, r); + PipingTools2.reversePipeRun(PipingTools2.getPipeRun(comp)); + + return GraphRequestStatus.transactionComplete(); + } + + + @Override + public void init() { + this.setText("Reverse pipeline"); + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/RoutePipeAction.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/RoutePipeAction.java new file mode 100644 index 00000000..00d7ac34 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/RoutePipeAction.java @@ -0,0 +1,1342 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.actions; + +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; + +import javax.vecmath.Point3d; +import javax.vecmath.Vector3d; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IToolBarManager; +import org.eclipse.jface.resource.ImageDescriptor; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.GraphRequestWithResult; +import org.simantics.db.Resource; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.proconf.g3d.actions.InteractiveAction; +import org.simantics.proconf.g3d.base.ConstraintDetector; +import org.simantics.proconf.g3d.base.G3DAPI; +import org.simantics.proconf.g3d.base.G3DTools; +import org.simantics.proconf.g3d.base.MathTools; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.common.StructuredResourceSelection; +import org.simantics.proconf.g3d.dnd.DropListener; +import org.simantics.proconf.g3d.scenegraph.IGraphicsNode; +import org.simantics.utils.datastructures.Pair; + +import com.jme.renderer.ColorRGBA; +import com.jme.scene.Geometry; +import com.jme.scene.Line; +import com.jme.scene.state.MaterialState; + +import fi.vtt.simantics.processeditor.Activator; +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.common.ControlPointTools; +import fi.vtt.simantics.processeditor.common.PipeComponentProvider; +import fi.vtt.simantics.processeditor.common.PipingTools2; +import fi.vtt.simantics.processeditor.common.PipingTools2.Direction; +import fi.vtt.simantics.processeditor.dialogs.PipelineDialog; +import fi.vtt.simantics.processeditor.gizmo.PositionSelectionGizmo; +import fi.vtt.simantics.processeditor.stubs.BranchEndControlPoint; +import fi.vtt.simantics.processeditor.stubs.PipeControlPoint; +import fi.vtt.simantics.processeditor.stubs.PipeRun; +import fi.vtt.simantics.processeditor.stubs.PipelineComponent; +import fi.vtt.simantics.processeditor.stubs.VariableLengthInlineComponent; +import fi.vtt.simantics.processeditor.views.ProcessEditor; + +/** + * Action for Routing Pipes + * + * FIXME : does several thing that should be done by PipingTools. + * TODO : instead of using lines to show route of pipe, generate pipe and change it real-time + * + * @author MLMARKO + * + */ +public class RoutePipeAction extends InteractiveAction implements DropListener, SplitPointListener { + + + private static final ImageDescriptor X_AXIS_ICON = Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/x-axis.png"); + private static final ImageDescriptor Y_AXIS_ICON = Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/y-axis.png"); + private static final ImageDescriptor Z_AXIS_ICON = Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/z-axis.png"); + private static final ImageDescriptor X_PLANE_ICON = Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/x-plane.png"); + private static final ImageDescriptor Y_PLANE_ICON = Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/y-plane.png"); + private static final ImageDescriptor Z_PLANE_ICON = Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/z-plane.png"); + + private static final ImageDescriptor CAMERA_ICON = Activator.imageDescriptorFromPlugin("org.simantics.proconf.g3d", "icons/eye.png"); + + + private Action xAxisAction; + private Action yAxisAction; + private Action zAxisAction; + private Action xPlaneAction; + private Action yPlaneAction; + private Action zPlaneAction; + + private Action cameraAction; + + ConstraintDetector detector = null; + + public RoutePipeAction(ThreeDimensionalEditorBase parent) { + super(parent); + detector = new ConstraintDetector(parent); + xAxisAction = new Action("X",Action.AS_RADIO_BUTTON) { + public void run() { + if (lock == LockType.X) + setLockType(LockType.NONE,false); + else + setLockType(LockType.X,false); + } + }; + xAxisAction.setImageDescriptor(X_AXIS_ICON); + xAxisAction.setToolTipText("Lock X-Axis"); + yAxisAction = new Action("Y",Action.AS_RADIO_BUTTON) { + public void run() { + if (lock == LockType.Y) + setLockType(LockType.NONE,false); + else + setLockType(LockType.Y,false); + } + }; + yAxisAction.setImageDescriptor(Y_AXIS_ICON); + yAxisAction.setToolTipText("Lock Y-Axis"); + zAxisAction = new Action("Z",Action.AS_RADIO_BUTTON) { + public void run() { + if (lock == LockType.Z) + setLockType(LockType.NONE,false); + else + setLockType(LockType.Z,false); + } + }; + zAxisAction.setImageDescriptor(Z_AXIS_ICON); + zAxisAction.setToolTipText("Lock Z-Axis"); + xPlaneAction = new Action("X",Action.AS_RADIO_BUTTON) { + public void run() { + if (lock == LockType.YZ) + setLockType(LockType.NONE,false); + else + setLockType(LockType.YZ,false); + } + }; + xPlaneAction.setImageDescriptor(X_PLANE_ICON); + xPlaneAction.setToolTipText("Lock X-Plane"); + yPlaneAction = new Action("Y",Action.AS_RADIO_BUTTON) { + public void run() { + if (lock == LockType.XZ) + setLockType(LockType.NONE,false); + else + setLockType(LockType.XZ,false); + } + }; + yPlaneAction.setImageDescriptor(Y_PLANE_ICON); + yPlaneAction.setToolTipText("Lock Y-Plane"); + zPlaneAction = new Action("Z",Action.AS_RADIO_BUTTON) { + public void run() { + if (lock == LockType.XY) + setLockType(LockType.NONE,false); + else + setLockType(LockType.XY,false); + } + }; + zPlaneAction.setImageDescriptor(Z_PLANE_ICON); + zPlaneAction.setToolTipText("Lock Z-Plane"); + cameraAction = new Action("C", Action.AS_CHECK_BOX) { + public void run() { + useCamera = this.isChecked(); + } + }; + cameraAction.setImageDescriptor(CAMERA_ICON); + cameraAction.setToolTipText("Use camera"); + splitPointAction = new SelectSplitPointAction(parent,this); + + } + + public void fillToolBar(IToolBarManager manager) { + + manager.add(cameraAction); + cameraAction.setChecked(useCamera); + manager.add(xAxisAction); + manager.add(yAxisAction); + manager.add(zAxisAction); + manager.add(xPlaneAction); + manager.add(yPlaneAction); + manager.add(zPlaneAction); + + } + + enum LockType {NONE,X,Y,Z,XY,YZ,XZ,CUSTOM}; + LockType lock = LockType.NONE; + + private void setLockType(LockType type, boolean force) { + if (force || lock != LockType.CUSTOM) { + lock = type; + } + xAxisAction.setChecked(false); + yAxisAction.setChecked(false); + zAxisAction.setChecked(false); + xPlaneAction.setChecked(false); + yPlaneAction.setChecked(false); + zPlaneAction.setChecked(false); + xAxisAction.setEnabled(true); + yAxisAction.setEnabled(true); + zAxisAction.setEnabled(true); + xPlaneAction.setEnabled(true); + yPlaneAction.setEnabled(true); + zPlaneAction.setEnabled(true); + switch (lock) { + case X: + xAxisAction.setChecked(true); + break; + case Y: + yAxisAction.setChecked(true); + break; + case Z: + zAxisAction.setChecked(true); + break; + case XY: + zPlaneAction.setChecked(true); + break; + case XZ: + yPlaneAction.setChecked(true); + break; + case YZ: + xPlaneAction.setChecked(true); + break; + case CUSTOM: + xAxisAction.setEnabled(false); + yAxisAction.setEnabled(false); + zAxisAction.setEnabled(false); + xPlaneAction.setEnabled(false); + yPlaneAction.setEnabled(false); + zPlaneAction.setEnabled(false); + break; + } + } + + private double BRANCH_SNAP_DISTANCE = 0.05; + private double NOZZLE_SNAP_DISTANCE = 0.05; + + private double istep = 10.0; + private int decimals = 2; + + private double pipeDiameter = 0.2; + private double elbowRadius = 0.5; + private double eps = 0.001; + + private ArrayList controlPoints = new ArrayList(); + + private Point3d currentPoint = new Point3d(); + private Point3d lastPoint = new Point3d(); + + private Vector3d customLockDir = null; + + private Line selectionLine; + private List pipeShapes = new ArrayList(); + private MaterialState ms; + + + private Resource selectedPort = null; + private PositionType selectedType = null; + private Resource beginComponentResource = null; + + private Resource endComponentResource = null; + private Resource endComponentPort = null; + private PositionType endPortType = null; + + private Resource highlightedResource = null; + + private boolean useCamera = false; + + private List> positions = null; + + private SelectSplitPointAction splitPointAction; + private PositionSelectionGizmo gizmo = null; + + + + private enum ToolState{NOT_ACTIVE, INITIALIZING, SELECTING_POSITION, SELECTING_SPLIT, ROUTING}; + private ToolState state = ToolState.NOT_ACTIVE; + + @Override + public void activate() { + state = ToolState.INITIALIZING; + controlPoints.clear(); + if (beginComponentResource == null) { + List mos = parent.getSelectionAdapter().getSelectedObjects(); + if (mos.size() != 1) { + end(); + return; + } + beginComponentResource = mos.get(0).getResource(); + } + parent.getSession().asyncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + positions = checkStartNode(g,beginComponentResource); + if (positions.size() == 0) { + positions = null; + end(); + } else { + state = ToolState.SELECTING_POSITION; + } + return GraphRequestStatus.transactionComplete(); + } + }); + + if (ms == null) { + ms = parent.getRenderingComponent().getDisplaySystem().getRenderer().createMaterialState(); + ms.setEmissive(new ColorRGBA(1.f,1.f,1.f,1.f)); + } + + } + + + + @Override + public void deactivate() { + for (Line l : pipeShapes) + l.removeFromParent(); + pipeShapes.clear(); + if (selectionLine != null) + selectionLine.removeFromParent(); + selectionLine = null; + customLockDir = null; + + setLockType(LockType.NONE,true); + beginComponentResource = null; + endComponentResource = null; + detector.clearConstraintHighlights(); + state = ToolState.NOT_ACTIVE; + selectedPort = null; + selectedType = null; + + } + + private List> checkStartNode(Graph g, Resource resource) { + List> positions = new ArrayList>(); + + IEntity beginComponent = EntityFactory.create(g, resource); + + if (beginComponent.isInstanceOf(ProcessResource.plant3Dresource.Nozzle)) { + if (PipingTools2.isFreeNozzle(beginComponent)) { + + positions.add(new Pair(beginComponent.getSingleRelatedObject(ProcessResource.plant3Dresource.HasControlPoint).getResource(),PositionType.NEXT)); + } + } else if (beginComponent.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent)) { + // variable length inline component is exception from other pipeline components, + // since a new pipe can branch it + VariableLengthInlineComponent vlic = new VariableLengthInlineComponent(beginComponent); + PipeControlPoint pcp = vlic.getControlPoint(); + if (pcp.getNext() == null) { + + positions.add(new Pair(pcp.getResource(),PositionType.NEXT)); + } else if (pcp.getPrevious() == null) { + + positions.add(new Pair(pcp.getResource(),PositionType.PREVIOUS)); + } + positions.add(new Pair(pcp.getResource(),PositionType.SPLIT)); + } else if (beginComponent.isInstanceOf(ProcessResource.plant3Dresource.EndComponent)) { + PipelineComponent component = new PipelineComponent(beginComponent); + PipeControlPoint pcp = component.getControlPoint(); + if (pcp.getNext() == null && pcp.getPrevious() == null) { + throw new RuntimeException("End component " + beginComponent.getResource() + " is not connected to anything."); + //positions.add(new Pair(pcp.getResource(),PositionType.NEXT)); + } + for (PipeControlPoint p : pcp.getSubPoint()) { + if (p.getNext() == null && p.getPrevious() == null) { + positions.add(new Pair(p.getResource(),PositionType.NEXT)); + } + } + } else if (beginComponent.isInstanceOf(ProcessResource.plant3Dresource.PipelineComponent)) { + + PipelineComponent component = new PipelineComponent(beginComponent); + + PipeControlPoint pcp = component.getControlPoint(); + if (pcp.getNext() == null) { + positions.add(new Pair(pcp.getResource(),PositionType.NEXT)); + } else if (pcp.getPrevious() == null) { + positions.add(new Pair(pcp.getResource(),PositionType.PREVIOUS)); + } + if (!beginComponent.isInstanceOf(ProcessResource.plant3Dresource.SizeChangeComponent)|| + !beginComponent.isInstanceOf(ProcessResource.plant3Dresource.OffsetComponent)) { + for (PipeControlPoint p : pcp.getSubPoint()) { + if (p.getNext() == null && p.getPrevious() == null) { + positions.add(new Pair(p.getResource(),PositionType.NEXT)); + } + } + } + } else { + return positions; + } + return positions; + } + + @Override + public void update() { + + switch (state) { + case NOT_ACTIVE: + return; // TODO : throw Exception? + case INITIALIZING: + return; + case SELECTING_POSITION: + updateSelectPosition(); + break; + case SELECTING_SPLIT: + updateSelectSplit(); + break; + case ROUTING: + updateRouting(); + break; + } + return; + } + + private void updateSelectPosition() { + + if (positions == null) { + throw new RuntimeException("positions must be loaded before select position can be activated"); + } + if (selectedPort != null) { + throw new RuntimeException("position is already selected"); + } + if (positions.size() == 1) { + selectedPort = positions.get(0).first; + selectedType = positions.get(0).second; + state = ToolState.INITIALIZING; + + + + if (requiresNewPipeRun()){ + if(!getNewPipeRunSpecs()) { + end(); + return; + } + } + if (selectedType == PositionType.SPLIT) { + startSplitting(); + } else { + startRouting(); + } + + } else if (gizmo == null) { + state = ToolState.INITIALIZING; // asyncRead! + parent.getSession().asyncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + List> pos = new ArrayList>(); + for (Pair p : positions) { + IEntity entity = EntityFactory.create(g,p.first); + Point3d position = ControlPointTools.getRealPosition(entity, p.second); + pos.add(new Pair(position,p.second)); + } + gizmo = new PositionSelectionGizmo(parent, pos); + parent.setGizmo(gizmo); + parent.getRenderingComponent().getNoShadowRoot().attachChild(gizmo.getNode()); + state = ToolState.SELECTING_POSITION; + return GraphRequestStatus.transactionComplete(); + } + }); + + } else { + gizmo.update(); + + if (input.keyPressed(KeyEvent.VK_ESCAPE)) { + state = ToolState.INITIALIZING; + parent.setGizmo(null); + gizmo = null; + end(); + return; + } + + if (gizmo.getSelected() >= 0 && input.mouseClicked() && input.clickButton() == MouseEvent.BUTTON1) { + state = ToolState.INITIALIZING; // asyncRead! + parent.setGizmo(null); + selectedPort = positions.get(gizmo.getSelected()).first; + selectedType = positions.get(gizmo.getSelected()).second; + gizmo = null; + + if (selectedType == PositionType.SPLIT) { + startSplitting(); + return; + } else { + startRouting(); + } + } + + if (useCamera) { + parent.getDefaultAction().update(); + return; + } + } + + } + + private boolean requiresNewPipeRun() { + GraphRequestWithResult createsNewPipeline = new GraphRequestWithResult() { + @Override + public Boolean performWithResult(Graph g) throws Exception { + if(g.isInstanceOf(selectedPort, ProcessResource.plant3Dresource.NozzleControlPoint)) + return true; + if (selectedType == PositionType.SPLIT) + return true; + return false; + + } + }; + parent.getSession().syncRead(createsNewPipeline); + return createsNewPipeline.getResult(); + } + + private boolean getNewPipeRunSpecs() { + PipelineDialog dialog; + dialog = new PipelineDialog(parent.getRenderingComposite().getShell(),pipeDiameter,elbowRadius); + if (dialog.open() == PipelineDialog.CANCEL) { + end(); + return false; + } + pipeDiameter = dialog.getPipeDiameter(); + elbowRadius = dialog.getTurnRadius(); + return true; + } + + private void startRouting() { + state = ToolState.INITIALIZING; + parent.getSession().asyncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + PipeControlPoint pcp = new PipeControlPoint(g,selectedPort); + lastPoint = ControlPointTools.getRealPosition(pcp, selectedType);//G3DTools.getPoint(pcp.getWorldPosition()); + if (pcp.isInstanceOf(ProcessResource.plant3Dresource.DirectedControlPoint)) { + lock = LockType.CUSTOM; + customLockDir = ControlPointTools.getDirectedControlPointDirection(pcp); + } else if (pcp.isInstanceOf(ProcessResource.plant3Dresource.FixedLengthControlPoint)|| + pcp.isInstanceOf(ProcessResource.plant3Dresource.TurnControlPoint)) { + lock = LockType.CUSTOM; + if (selectedType == PositionType.NEXT) + customLockDir = ControlPointTools.getPathLegDirection(pcp, Direction.NEXT); + else + customLockDir = ControlPointTools.getPathLegDirection(pcp, Direction.PREVIOUS); + } else { + lock = LockType.NONE; + } + IEntity pipeRun = ControlPointTools.getPipeRun(pcp); + if (pipeRun != null) { + pipeDiameter = pipeRun.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasPipeDiameter); + elbowRadius = pipeRun.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasTurnRadius); + } + return GraphRequestStatus.transactionComplete(); + } + + @Override + public void requestCompleted(GraphRequestStatus status) { + createLine(); + state = ToolState.ROUTING; + } + }); + } + + private void startSplitting() { + parent.getSession().asyncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + PipeControlPoint pcp = new PipeControlPoint(g,selectedPort); + Point3d p1 = new Point3d(); + Point3d p2 = new Point3d(); + ControlPointTools.getInlineControlPointEnds(pcp, p1, p2); + splitPointAction.setSplit(p1, p2); + splitPointAction.activate(); + state = ToolState.SELECTING_SPLIT; + return GraphRequestStatus.transactionComplete(); + } + }); + } + + + private void updateSelectSplit() { + if (splitPointAction.active()) { + splitPointAction.update(); + return; + } else { + throw new RuntimeException("SplitPointAction should be active"); + } + } + + @Override + public void setSplitPoint(Point3d point) { + splitPointAction.deactivate(); + if (point == null) { + end(); + return; + } else { + + + lastPoint = point; + createLine(); + state = ToolState.ROUTING; + } + } + + private void updateRouting() { + if(input.keyPressed(KeyEvent.VK_ESCAPE)) { + controlPoints.clear(); + end(); + return; + } + if (input.keyPressed(KeyEvent.VK_C)) { + useCamera = !useCamera; + cameraAction.setChecked(useCamera); + } + if (useCamera) { + parent.getDefaultAction().update(); + return; + } + + parent.getSession().syncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + + Vector3d o = new Vector3d(); + Vector3d d = new Vector3d(); + parent.createPickRay(o, d); + if (!updateCurrentPoint(o, d)) + return GraphRequestStatus.transactionComplete(); + //Point3d startPoint = new Point3d(); + double mu[] = new double[2]; + + IEntity endTo = null; + PositionType endType = null; + IEntity endPort = null; + + if (parent.getSelectionAdapter().getHighlightSelection().size() > 0) { + highlightedResource = parent.getSelectionAdapter().getHighlightSelection().getSelectionList().get(0); + } else { + highlightedResource = null; + } + + if (highlightedResource != null) { + IEntity highlightNode = EntityFactory.create(g,highlightedResource); + + if (lock == LockType.NONE) { + if (highlightNode.isInstanceOf(ProcessResource.plant3Dresource.Nozzle) && endingToNozzle(highlightNode,o,d)) { + endTo = highlightNode; + } else if (highlightNode.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent)) { + endTo = highlightNode; + endType = endingToStraight(new VariableLengthInlineComponent(highlightNode),mu,o,d); + } else if (highlightNode.isInstanceOf(ProcessResource.plant3Dresource.PipelineComponent) && (endPort = endingToComponent(highlightNode,o,d)) != null) { + endTo = highlightNode; + } else { + updateRoute(o,d); + } + } else { + if (highlightNode.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent) && (endType = endingLockToStraight(new VariableLengthInlineComponent(highlightNode),mu)) != null) { + endTo = highlightNode; + } else if (highlightNode.isInstanceOf(ProcessResource.plant3Dresource.Nozzle) && endingLockToNozzle(highlightNode)) { + endTo = highlightNode; + } else if (highlightNode.isInstanceOf(ProcessResource.plant3Dresource.PipelineComponent) && (endPort = endingLockToComponent(highlightNode)) != null) { + endTo = highlightNode; + } else { + updateRoute(o,d); + } + } + + + } else { + updateRoute(o,d); + } + + parent.setViewChanged(true); + if (input.mouseClicked()) { + if (input.clickButton() == MouseEvent.BUTTON1) { + if (controlPoints.size() > 0) { + addPoint(); + setLockType(LockType.NONE,true); + if (endTo != null) { + endComponentResource = endTo.getResource(); + if (endPort != null) + endComponentPort = endPort.getResource(); + endPortType = endType; + + endPiping(); + } + } else { + throw new RuntimeException("kjf"); +// // user was selecting position of branch +// lastPoint.set(startPoint); +// controlPoints.add(new Point3d(startPoint)); +// if (selectionLine != null) +// selectionLine.removeFromParent(); +// selectionLine = null; + } + } else if (input.clickButton() == MouseEvent.BUTTON2){ + detector.updateConstraintReference(); + } else if (input.clickButton() == MouseEvent.BUTTON3){ + endPiping(); + } + } + + return GraphRequestStatus.transactionComplete(); + } + }); + + } + + private void createLine() { + controlPoints.add(new Point3d(lastPoint)); + Line line = new Line(); + line.setRenderState(ms); + + PipeComponentProvider.createStraightEdges(line, currentPoint, currentPoint, pipeDiameter*0.5); + pipeShapes.add(line); + parent.getRenderingComponent().getNoShadowRoot().attachChild(line); + line.setCullMode(Geometry.CULL_NEVER); + } + + + /** + * Adds current point to pipeline + * + */ + private void addPoint() { + + controlPoints.add(new Point3d(currentPoint)); + Line line = new Line(); + line.setRenderState(ms); + PipeComponentProvider.createStraightEdges(line, controlPoints.get(controlPoints.size() - 1), currentPoint, pipeDiameter*0.5); + pipeShapes.add(line); + parent.getRenderingComponent().getNoShadowRoot().attachChild(line); + line.setCullMode(Geometry.CULL_NEVER); + lastPoint.set(currentPoint); + } + + /** + * Updates tool graphics for current point + */ + private void updateCurrentPoint() { + PipeComponentProvider.createStraightEdges(pipeShapes.get(pipeShapes.size() - 1), controlPoints.get(controlPoints.size() - 1), currentPoint, pipeDiameter*0.5); + } + + /** + * Removes last point from pipeline + */ + public void removePoint() { + if (controlPoints.size() < 2) + return; + controlPoints.remove(controlPoints.size() - 1); + + pipeShapes.get(pipeShapes.size() - 1).removeFromParent(); + pipeShapes.remove(pipeShapes.size() - 1); + PipeComponentProvider.createStraightEdges(pipeShapes.get(pipeShapes.size() - 1), controlPoints.get(controlPoints.size() - 1), currentPoint, pipeDiameter*0.5); + + lastPoint.set(controlPoints.get(controlPoints.size()-1)); + if (controlPoints.size() < 2 && customLockDir != null) { + setLockType(LockType.CUSTOM, true); + } + } + + + + private boolean endingToNozzle(IEntity nozzle,Vector3d o, Vector3d d) { + IEntity pcp = nozzle.getSingleRelatedObject(ProcessResource.plant3Dresource.HasControlPoint); + if (pcp != null && (pcp.getAtMostOneRelatedObject(ProcessResource.plant3Dresource.HasNext) != null || + pcp.getAtMostOneRelatedObject(ProcessResource.plant3Dresource.HasPrevious) != null)) + return false; // nozzle is already connected to pipe + currentPoint = G3DTools.getPoint(nozzle.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition)); + Point3d previousPipePoint = controlPoints.get(controlPoints.size() - 1); + Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint)); + if (p != null) { + if (p.distance(currentPoint) > NOZZLE_SNAP_DISTANCE) { + return false; + } + } + + updateCurrentPoint(); + + setInfoText("Connect to nozzle " + currentPoint); + return true; + + } + + private PositionType endingToStraight(VariableLengthInlineComponent s, double mu[], Vector3d o, Vector3d d) { + String info = ""; + Point3d sStart = new Point3d(); + Point3d sEnd = new Point3d(); + //detector.clearConstraintHighlights(); + + Point3d previousPipePoint = controlPoints.get(controlPoints.size() - 1); + //String st = ""; + if (lock == LockType.NONE) { + Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint)); + if (p != null) { + currentPoint = p; + // snapping is detected, check if snapped point can create branch with straight + PositionType t = endingLockToStraight(s, mu); + if (t != null) + return t; + // if not, we'll have to remove highlight that was added when snapped point was detected + detector.clearConstraintHighlights(); + } + + PipingTools2.getInlineComponentEnds(s, sStart, sEnd); + Vector3d sDir = new Vector3d(sEnd); + sDir.sub(sStart); + MathTools.intersectStraightStraight(sStart, sDir, o, d, currentPoint, new Point3d(), mu); + + + } else { + throw new RuntimeException("Lock shouldn't be on"); + + } + + updateCurrentPoint(); + + // branch point must lie between straight's ends. If connection point is exactly + // on straight end user may want to connect pipes to each other + // TODO : take account sizes of inline components) + // TODO : actually make connection if its detected + boolean connectPrev = false; + boolean connectNext = false; + + if (mu[0] < 0.0) { + currentPoint.set(sStart); + connectPrev = true; + } + else if (mu[0] > 1.0) { + currentPoint.set(sEnd); + connectNext = true; + } + boolean connect = false; + if (connectPrev) { + PipeControlPoint pcp = s.getControlPoint(); + if (pcp.getPrevious() == null) + connect = true; + } else if (connectNext) { + PipeControlPoint pcp = s.getControlPoint(); + if (pcp.getNext() == null) + connect = true; + } + + updateCurrentPoint(); + + if (connect) + info += "Connect pipes :"; + else + info += "Make Branch :"; + + setInfoText(info + currentPoint + " " + Math.max(0.0, Math.min(mu[0], 1.0))); + if (connect) { + if (connectNext) { + return PositionType.NEXT; + } else { + return PositionType.PREVIOUS; + } + + } + return PositionType.SPLIT; + + } + + private IEntity endingToComponent(IEntity component, Vector3d o, Vector3d d) { + // TODO : scan all empty pcps of the component and select closest one. + return null; + } + + private PositionType endingLockToStraight(VariableLengthInlineComponent s, double mu[]) { + + Point3d sStart = new Point3d();//G3DTools.getPoint(s.getHasControlPoint().getPreviousPoint().getLocalPosition()); + Point3d sEnd = new Point3d(); //G3DTools.getPoint(s.getHasControlPoint().getNextPoint().getLocalPosition()); + PipingTools2.getInlineComponentEnds(s, sStart, sEnd); + Vector3d sDir = new Vector3d(sEnd); + sDir.sub(sStart); + Vector3d dir = new Vector3d(currentPoint); + Point3d prev = controlPoints.get(controlPoints.size() - 1); + dir.sub(prev); + // intersection point in pipe where branch would be inserted to + Vector3d branchPoint = new Vector3d(); + // intersection point in straight pipe that is currently routed + Vector3d routePoint = new Vector3d(); + MathTools.intersectStraightStraight(sStart, sDir, new Vector3d(prev), dir, branchPoint, routePoint, mu); + routePoint.sub(branchPoint); + // startPoint of branch must be between pipe ends + // TODO : take account sizes of elbows (or other components) + // branch point must be between pipe ends and intersection points must be quite close to each othert + if (mu[0] > 0.0 && mu[0] < 1.0 && routePoint.lengthSquared() < BRANCH_SNAP_DISTANCE) { + currentPoint.set(branchPoint); + + updateCurrentPoint(); + + setInfoText("Make branch (l) :" + currentPoint + " " + Math.max(0.0, Math.min(mu[0], 1.0)) + " " + routePoint.lengthSquared()); + return PositionType.SPLIT; + } + return null; + } + + private boolean endingLockToNozzle(IEntity nozzle) { + Vector3d dir = new Vector3d(currentPoint); + Point3d prev = controlPoints.get(controlPoints.size() - 1); + dir.sub(prev); + Point3d nozzleLoc = G3DTools.getPoint(nozzle.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition)); + double u[] = new double[1]; + Vector3d closest = MathTools.closestPointOnStraight(new Point3d(nozzleLoc), new Point3d(prev), new Vector3d(dir), u); + double dist = nozzleLoc.distanceSquared(new Point3d(closest)); + if (dist < BRANCH_SNAP_DISTANCE) { + // FIXME : directions should be checked (insert an elbow) + currentPoint.set(nozzleLoc); + updateCurrentPoint(); + setInfoText("Connect to nozzle (l) :" + currentPoint); + return true; + } + //System.out.println(u[0]); + return false; + } + + private IEntity endingLockToComponent(IEntity component) { + // we'll must scan all free pcp's and their direction to accept the connection. + return null; + } + + private void updateRoute(Vector3d o, Vector3d d) { + detector.clearConstraintHighlights(); + Point3d previousPipePoint = controlPoints.get(controlPoints.size() - 1); + String s = ""; + if (lock == LockType.NONE) { + Point3d p = detector.getSnappedPoint(o, d, new Vector3d(previousPipePoint)); + if (p != null) + currentPoint = p; + s += detector.getSnapString(); + + } else { + Vector3d dir = new Vector3d(currentPoint); + dir.sub(previousPipePoint); + Point3d p = detector.getPointSnap(new Vector3d(previousPipePoint), dir); + if (p != null) + currentPoint = p; + s += detector.getSnapString(); + + } + + updateCurrentPoint(); + s += currentPoint.toString(); + setInfoText(s); + } + + private boolean updateCurrentPoint(Vector3d o, Vector3d d) { + if (lock != LockType.CUSTOM) { + if (input.keyPressed(KeyEvent.VK_X)) { + if (lock == LockType.X) + setLockType(LockType.YZ,false); + else + setLockType(LockType.X,false); + } + if (input.keyPressed(KeyEvent.VK_Y)) { + if (lock == LockType.Y) + setLockType(LockType.XZ,false); + else + setLockType(LockType.Y,false); + } + if (input.keyPressed(KeyEvent.VK_Z)) { + if (lock == LockType.Z) + setLockType(LockType.XY,false); + else + setLockType(LockType.Z,false); + } + if (input.keyPressed(KeyEvent.VK_N)) { + setLockType(LockType.NONE,false); + } + if (input.keyPressed(KeyEvent.VK_BACK_SPACE)) { + removePoint(); + } + } + Vector3d point = new Vector3d(lastPoint); + boolean step = ((input.moveModifiers() & MouseEvent.CTRL_DOWN_MASK) > 0); + switch(lock) { + case X: + MathTools.intersectStraightStraight(point, new Vector3d(1.0,0.0,0.0), o,d, currentPoint, new Vector3d()); + if (step) { + currentPoint.x = Math.round(istep * currentPoint.x) / istep; + BigDecimal bx = new BigDecimal(currentPoint.x); + bx.setScale(decimals, BigDecimal.ROUND_HALF_UP); + currentPoint.x = bx.doubleValue(); + } + break; + case Y: + MathTools.intersectStraightStraight(point, new Vector3d(0.0,1.0,0.0), o,d, currentPoint, new Vector3d()); + if (step) { + currentPoint.y = Math.round(istep * currentPoint.y) / istep; + BigDecimal bx = new BigDecimal(currentPoint.y); + bx.setScale(decimals, BigDecimal.ROUND_HALF_UP); + currentPoint.y = bx.doubleValue(); + } + break; + case Z: + MathTools.intersectStraightStraight(point, new Vector3d(0.0,0.0,1.0), o,d, currentPoint, new Vector3d()); + if (step) { + currentPoint.z = Math.round(istep * currentPoint.z) / istep; + BigDecimal bx = new BigDecimal(currentPoint.z); + bx.setScale(decimals, BigDecimal.ROUND_HALF_UP); + currentPoint.z = bx.doubleValue(); + }break; + case XY: + MathTools.intersectStraightPlane(o, d, point, new Vector3d(0.0,0.0,1.0), currentPoint); + break; + case XZ: + MathTools.intersectStraightPlane(o, d, point, new Vector3d(0.0,1.0,0.0), currentPoint); + break; + case YZ: + MathTools.intersectStraightPlane(o, d, point, new Vector3d(1.0,0.0,0.0), currentPoint); + break; + case NONE: + Vector3d normal = parent.getCamera().getUnNormalizedHeading(); + normal.normalize(); + + MathTools.intersectStraightPlane(o, d, point, normal, currentPoint); + break; + case CUSTOM: + MathTools.intersectStraightStraight(point, new Vector3d(customLockDir), o,d, currentPoint, new Vector3d()); + double dist = MathTools.distanceFromPlane(new Vector3d(currentPoint), customLockDir, lastPoint); + if (dist < 0.0) + currentPoint.set(lastPoint); + break; + default: + return false; + } + return true; + } + + + private ArrayList filterPoints() { + ArrayList filteredControlPoints = new ArrayList(); + + // this loop filters control points that are not needed + for (int i = 0; i < controlPoints.size() - 2; i++) { + Point3d start = controlPoints.get(i); + if (i == 0) + filteredControlPoints.add(start); + + Point3d middle = controlPoints.get(i+1); + Point3d end = controlPoints.get(i+2); + + Vector3d dir1 = new Vector3d(middle); + dir1.sub(start); + Vector3d dir2 = new Vector3d(end); + dir2.sub(middle); + double angle = dir1.angle(dir2); + if (angle > eps && angle < (Math.PI - eps)) + filteredControlPoints.add(middle); + // if angle is near PI pipe turns back to where it started + // if angle is near zero, pipe is straight and there's no need for control point + + if (i == controlPoints.size() - 3) + filteredControlPoints.add(end); + + } + return filteredControlPoints; + } + + private PipeControlPoint connectPipeStart(Graph graph, PipeRun pipeRun, boolean reversed) { + PipeControlPoint pcp = new PipeControlPoint(graph,selectedPort); + IEntity beginComponent = EntityFactory.create(graph,beginComponentResource); + if (beginComponent.isInstanceOf(ProcessResource.plant3Dresource.Nozzle)) { + PipingTools2.linkNozzleAndPipeRun(beginComponent, pipeRun); + // TODO : set diameters same + //reversed = false; + + } else if (beginComponent.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent)) { + switch (selectedType) { + case NEXT: + { + PipeControlPoint tcp = createTurn(graph, pipeRun, 0); + connectControlPoints(pcp, tcp, reversed); + return tcp; + } + case PREVIOUS: + { + PipeControlPoint tcp = createTurn(graph, pipeRun, 0); + connectControlPoints(pcp, tcp, reversed); + return tcp; + } + case SPLIT: + //reversed = false; + // 1. create (non visible) splitting component. + PipelineComponent newComponent = PipingTools2.instantiatePipelineComponent(graph, PipingTools2.getPipeRun(beginComponent).getResource(), ProcessResource.plant3Dresource.BranchSplitComponent); + PipeControlPoint mainCP = newComponent.getControlPoint(); + // 2. create control point for the branch + BranchEndControlPoint becp = BranchEndControlPoint.createDefault(graph); + mainCP.addSubPoint(becp); + pipeRun.addControlPoints(becp); + pcp = becp.toPipeControlPoint(); + ControlPointTools.setWorldPosition(mainCP, controlPoints.get(0)); + + PipingTools2.splitVariableLengthComponent(newComponent, beginComponent); + } + } else if (beginComponent.isInstanceOf(ProcessResource.plant3Dresource.PipelineComponent)) { + //if (selectedType == PositionType.PREVIOUS) + //reversed = true; + //else + //reversed = false; + } else { + throw new RuntimeException("unknown starting component"); + } + + return pcp; + } + + private PipeControlPoint connectPipeEnd(Graph graph, PipeRun pipeline, boolean reversed) { + PipeControlPoint pcp = null; + IEntity endComponent = null; + if (endComponentResource != null) + endComponent = EntityFactory.create(graph, endComponentResource); + if (endComponent == null) { + return null; + } else if (endComponent.isInstanceOf(ProcessResource.plant3Dresource.Nozzle)){ + pcp = new PipeControlPoint(endComponent.getSingleRelatedObject(ProcessResource.plant3Dresource.HasControlPoint)); + PipingTools2.linkNozzleAndPipeRun(endComponent, pipeline); + } else if (endComponent.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent)) { + assert(endPortType != null); + if (endPortType == PositionType.SPLIT) { + //System.out.println(lastPoint + " " + currentPoint + " " + positions.get(positions.size() - 1)); + Point3d pos = lastPoint; + // 1. create (non visible) splitting component. + PipelineComponent newComponent = PipingTools2.instantiatePipelineComponent(graph, PipingTools2.getPipeRun(endComponent).getResource(), ProcessResource.plant3Dresource.BranchSplitComponent); + + PipeControlPoint mainCP = newComponent.getControlPoint(); + // 2. create control point for the branch + BranchEndControlPoint becp = BranchEndControlPoint.createDefault(graph); + mainCP.addSubPoint(becp); + pipeline.addControlPoints(becp); + pcp = becp.toPipeControlPoint(); + ControlPointTools.setWorldPosition(mainCP, pos); + + PipingTools2.splitVariableLengthComponent(newComponent, endComponent); + } else { + + } + } else if (endComponent.isInstanceOf(ProcessResource.plant3Dresource.FixedLengthInlineComponent)) { + // attach to selected port, reverse the piperun if needed + pcp = new PipeControlPoint(graph,endComponentPort); + if (!reversed && pcp.getPrevious() != null || reversed && pcp.getNext() != null) { + PipingTools2.reversePipeRun(ControlPointTools.getPipeRun(pcp)); + } + } + return pcp; + } + + private PipeControlPoint createTurn(Graph coreTC,PipeRun pipeRun, int i) { + PipelineComponent elbow = PipingTools2.instantiatePipelineComponent(coreTC,pipeRun.getResource(), ProcessResource.plant3Dresource.Elbow); + G3DAPI.setWorldPosition(elbow, controlPoints.get(i)); + return elbow.getControlPoint(); + } + + private PipeControlPoint createInline(Graph graph, PipeRun pipeRun, int i) { + Point3d p1 = controlPoints.get(i-1); + Point3d p2 = controlPoints.get(i); + Vector3d v = new Vector3d(p2); + v.sub(p1); + double length = v.length(); + v.scale(0.5); + v.add(p1); + PipelineComponent straight = PipingTools2.instantiatePipelineComponent(graph,pipeRun.getResource(), ProcessResource.plant3Dresource.Straight); + G3DAPI.setWorldPosition(straight, v); + straight.setRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength, length); + return straight.getControlPoint(); + + } + + private void connectControlPoints(PipeControlPoint previous, PipeControlPoint pcp, boolean reversed) { + if (previous != null) { + PipeControlPoint sccp; + PipeControlPoint ocp; + if (previous.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)) { + sccp = previous; + ocp = sccp.getSubPoint().iterator().next(); + } else if (previous.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)) { + ocp = previous; + sccp = ocp.getSubPointOf(); + } else { + if (!reversed) { + previous.setNext(pcp); + pcp.setPrevious(previous); + } else { + previous.setPrevious(pcp); + pcp.setNext(previous); + } + return; + } + if (!reversed) { + sccp.setNext(pcp); + ocp.setNext(pcp); + pcp.setPrevious(ocp); + } else { + sccp.setPrevious(pcp); + ocp.setPrevious(pcp); + pcp.setNext(sccp); + } + + } + } + + private void endPiping() { + state = ToolState.NOT_ACTIVE; + + if (controlPoints.size() > 2) // if there's only two control points, filtering does nothing + controlPoints = filterPoints(); + + if (controlPoints.size() > 1) { + parent.getSession().asyncWrite(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph graph) throws Exception { + PipeRun pipeline = null; + boolean reversed; + PipelineComponent beginComponent = new PipelineComponent(graph,beginComponentResource); + if (beginComponent.isInstanceOf(ProcessResource.plant3Dresource.Nozzle) || + selectedType == PositionType.SPLIT) { + + +// + pipeline = PipeRun.createDefault(graph); + ((ProcessEditor) parent).getPlant(graph).addChild(pipeline); + pipeline.setPipeDiameter(pipeDiameter); + pipeline.setTurnRadius(elbowRadius); + reversed = false; + } else if (beginComponent.isInstanceOf(ProcessResource.plant3Dresource.SizeChangeComponent)|| + beginComponent.isInstanceOf(ProcessResource.plant3Dresource.OffsetComponent)){ + PipeControlPoint pcp = new PipeControlPoint(graph,selectedPort); + if (selectedType == PositionType.NEXT) { + // get the piperun from offsetpoint + reversed = false; + pipeline = pcp.getSubPoint().iterator().next().getControlPointOfPipeRun(); + } else if (selectedType == PositionType.PREVIOUS) { + reversed = true; + pipeline = pcp.getControlPointOfPipeRun(); + } else { + throw new RuntimeException("Wrong PsoitionType " + selectedType + " for a SizeChangeComponent"); + } + + } else if (beginComponent.isInstanceOf(ProcessResource.plant3Dresource.PipelineComponent)) { + + pipeline = new PipeRun(beginComponent.getParent()); + if (selectedType == PositionType.PREVIOUS) { + reversed = true; + } else { + reversed = false; + } + } else { + throw new RuntimeException("Cannot start routing pipe : object not supported!"); + } + + PipeControlPoint previous = null; + for (int i = 0; i < controlPoints.size(); i++) { + PipeControlPoint pcp = null; + if (i == 0) { + pcp = connectPipeStart(graph, pipeline,reversed); + + } else { + pcp = createInline(graph, pipeline, i); + connectControlPoints(previous, pcp, reversed); + previous = pcp; + if (i == controlPoints.size() - 1) { + pcp = connectPipeEnd(graph, pipeline, reversed); + } else { + + pcp = createTurn(graph,pipeline,i); + } + } + + if (pcp != null) { + connectControlPoints(previous, pcp, reversed); + //pipeline.addSgetHasControlPointSet().add(pcp); + previous = pcp; + } + } + return GraphRequestStatus.transactionComplete(); + } + + @Override + public void requestCompleted(GraphRequestStatus status) { + endThreaded(); + } + }); + + + + } else { + endThreaded(); + } + } + + private void endThreaded() { + parent.getRenderingComposite().getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + end(); + } + }); + } + + @Override + public void init() { + this.setText("Route pipe"); + this.setToolTipText("Starts routing a new pipeline"); + this.setImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/Straight.png")); + } + + @Override + public boolean usable(Graph g, List resources) { + if (resources.size() != 1) { + return false; + } + return checkStartNode(g,resources.get(0)).size() > 0; + } + + + + public boolean acceptDrop(StructuredResourceSelection s, Resource[] ids) { + if (s.size() != 1) + return false; + if (ids == null) + return false; + if (ids.length != 1) + return false; + final Resource dropped = ids[0]; + final Resource target = s.iterator().next(); + GraphRequestWithResult query = new GraphRequestWithResult() { + @Override + public Boolean performWithResult(Graph g) throws Exception { + if(!g.isInstanceOf(dropped, ProcessResource.plant3Dresource.VariableLengthInlineComponent)) + return false; + // TODO : check that type is not abstract + List list = new ArrayList(); + list.add(target); + return usable(g, list); + } + }; + parent.getSession().syncRead(query); + return query.getResult(); + } + + public void doDrop(StructuredResourceSelection s, Resource[] ids) { + beginComponentResource = s.iterator().next(); + parent.setCurrentAction(this); + } + + public void setInfoText(String text) { + + } + +} \ No newline at end of file diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/SelectSplitPointAction.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/SelectSplitPointAction.java new file mode 100644 index 00000000..1b004e98 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/SelectSplitPointAction.java @@ -0,0 +1,135 @@ +package fi.vtt.simantics.processeditor.actions; + +import java.awt.event.MouseEvent; +import java.util.List; + +import javax.vecmath.Point3d; +import javax.vecmath.Vector3d; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.proconf.g3d.actions.InteractiveAction; +import org.simantics.proconf.g3d.base.MathTools; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.base.VecmathJmeTools; + +import com.jme.math.Vector3f; +import com.jme.renderer.ColorRGBA; +import com.jme.scene.Line; +import com.jme.scene.state.MaterialState; +import com.jme.util.geom.BufferUtils; + +public class SelectSplitPointAction extends InteractiveAction { + + Point3d start; + Point3d end; + Vector3d dir; + + Line line; + + boolean activated; + + SplitPointListener listener; + + public SelectSplitPointAction(ThreeDimensionalEditorBase parent, SplitPointListener listener) { + super(parent); + this.listener = listener; + } + + + public void setSplit(Point3d start, Point3d end) { + this.start = start; + this.end = end; + dir = new Vector3d(end); + dir.sub(start); + } + + + @Override + public void activate() { + if (start == null) throw new RuntimeException("Starting split action without information about range"); + +// start = new Point3d(); +// end = new Point3d(); +// PipingTools.getStraightPipeEnds(PipingTools.getPipeline(straight), +// straight, startStart, startEnd); + + line = new Line(); + MaterialState ms = parent.getRenderingComponent().getDisplaySystem().getRenderer().createMaterialState(); + ms.setEmissive(new ColorRGBA(1.f,1.f,1.f,1.f)); + line.setRenderState(ms); + parent.getRenderingComponent().getNoShadowRoot().attachChild(line); + activated = true; + + } + + @Override + public boolean usable(Graph graph, List resources) { +// if (resources.size() != 1) +// return false; +// IEntity entity = EntityFactory.create(graph, resources.get(0)); +// if (entity.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent)) { +// return true; +// } + // This is not a standalone action + return false; + } + + @Override + public void deactivate() { + line.removeFromParent(); + activated = false; + start = null; + end = null; + dir = null; + + } + + public boolean active() { + return activated; + } + + @Override + public void update() { + if (!activated) { + return; + } + if (input.mouseClicked() && input.clickButton() == MouseEvent.BUTTON3) { + listener.setSplitPoint(null); + activated = false; + return; + } + Vector3d o = new Vector3d(); + Vector3d d = new Vector3d(); + parent.createPickRay(o, d); + + Vector3d normal = parent.getCamera().getUnNormalizedHeading(); + normal.normalize(); + normal.negate(); + // reference point for selection line + Vector3d point = new Vector3d(start); + Vector3d currentPoint = new Vector3d(); + MathTools.intersectStraightPlane(o, d, point, normal, currentPoint); + Point3d startPoint = new Point3d(); + double mu[] = new double[2]; + MathTools.intersectStraightStraight(start, dir, o, d, startPoint, + new Point3d(), mu); + // startPoint of branch must be between pipe ends + // TODO : take account sizes of elbows (or other components) + if (mu[0] < 0.0) + startPoint.set(start); + else if (mu[0] > 1.0) + startPoint.set(end); + + Vector3f verts[] = new Vector3f[2]; + verts[0] = VecmathJmeTools.get(startPoint); + verts[1] = VecmathJmeTools.get(currentPoint); + line.reconstruct(BufferUtils.createFloatBuffer(verts), null, null, null); + + parent.setViewChanged(true); + if (input.mouseClicked() && input.clickButton() == MouseEvent.BUTTON1) { + listener.setSplitPoint(new Point3d(startPoint)); + } + + } +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/SplitPointListener.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/SplitPointListener.java new file mode 100644 index 00000000..d766ad39 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/SplitPointListener.java @@ -0,0 +1,19 @@ +package fi.vtt.simantics.processeditor.actions; + +import javax.vecmath.Point3d; + +/** + * SplitPointListener is used by SplitPointAction to pass the selected split point. + * Implementing class must set itself as active action into editor (SplitPointAction won't close automatically). + * + * @author Marko Luukkainen + * + */ +public interface SplitPointListener { + + /** + * Sets selected split point, or null if user cancelled the action. + * @param point + */ + public void setSplitPoint(Point3d point); +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/TranslateElbowAction.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/TranslateElbowAction.java new file mode 100644 index 00000000..b500e0c2 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/TranslateElbowAction.java @@ -0,0 +1,232 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.actions; + +import java.util.List; + +import javax.vecmath.AxisAngle4f; +import javax.vecmath.Point3d; +import javax.vecmath.Vector3d; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.proconf.g3d.actions.ConstrainedTransformAction; +import org.simantics.proconf.g3d.actions.TranslateActionConstraints; +import org.simantics.proconf.g3d.base.G3DAPI; +import org.simantics.proconf.g3d.base.G3DTools; +import org.simantics.proconf.g3d.base.MathTools; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.gizmo.TransformInlineGizmo; +import org.simantics.proconf.g3d.scenegraph.IGraphicsNode; +import org.simantics.proconf.g3d.stubs.G3DNode; + +import fi.vtt.simantics.processeditor.Activator; +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.common.ControlPointTools; +import fi.vtt.simantics.processeditor.stubs.DirectedControlPoint; +import fi.vtt.simantics.processeditor.stubs.PipeControlPoint; +import fi.vtt.simantics.processeditor.stubs.VariableAngleTurnComponent; + +public class TranslateElbowAction extends ConstrainedTransformAction { + + TransformInlineGizmo gizmo; + List mos; + Vector3d dir; + Vector3d orgPos; + double istep = 10.0; + int decimals = 2; + + private Resource pcpResource; + + public TranslateElbowAction(ThreeDimensionalEditorBase parent) { + super(parent); + gizmo = new TransformInlineGizmo(component.getDisplaySystem().getRenderer()); + + + } + + public void init() { + this.setText("Translate directed"); + this.setToolTipText("Translate the elbow in connections direction"); + this.setImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/translate_d.png")); + } + + + + @Override + public boolean usable(Graph graph, List resources) { + // TODO : it should be possible to move multiple components on the same straight + // TODO : checking against elbow and dcp; these are not correct! + if (resources.size() != 1) + return false; + IEntity r = EntityFactory.create(graph,resources.get(0)); + if (r.isInstanceOf(ProcessResource.plant3Dresource.VariableAngleTurnComponent)) { + VariableAngleTurnComponent e = new VariableAngleTurnComponent(r); + PipeControlPoint pcp = e.getControlPoint(); + PipeControlPoint prev = ControlPointTools.findPreviousEnd(pcp); + PipeControlPoint next = ControlPointTools.findNextEnd(pcp); + DirectedControlPoint dcp = null; + int directedCount = 0; + if (prev != null && prev.isInstanceOf(ProcessResource.plant3Dresource.DirectedControlPoint)) { + directedCount++; + dcp = new DirectedControlPoint(prev); + } + if (next != null && next.isInstanceOf(ProcessResource.plant3Dresource.DirectedControlPoint)) { + directedCount++; + dcp = new DirectedControlPoint(next); + } + if (directedCount == 1) { + orgPos = G3DTools.getVector(dcp.getWorldPosition()); + dir = ControlPointTools.getDirectedControlPointDirection(dcp); + pcpResource = pcp.getResource(); + return true; + } + } + return false; + + } + + @Override + public void deactivate() { + parent.setGizmo(null); + super.deactivate(); + } + + @Override + public void activate() { + parent.setGizmo(gizmo); + + String text = ""; + mos = parent.getSelectionAdapter().getSelectedObjects(); +// for (IGraphicsNode mo : mos) { +// text += GraphicsNodeTools.getWorldTranslation(mo.getGraphicsNode());//mo.getWorldPosition() + " "; +// } + + mos.iterator().next().getGroup().attachChild(gizmo.getNode()); + setInfoText(text); + + Vector3d front = new Vector3d(1.0,0.0,0.0); + Vector3d current = new Vector3d(dir); + float angle = (float)current.angle(front); + AxisAngle4f aa; + if (angle < 0.01 || (Math.PI - angle) < 0.01) { + aa = new AxisAngle4f(); + } else { + current.normalize(); + Vector3d right = new Vector3d(); + right.cross(front, current); + + right.normalize(); + if (right.lengthSquared() < 0.01) { + aa = new AxisAngle4f(); + } else { + aa = new AxisAngle4f((float) right.x, (float) right.y, (float) right.z, angle); + } + } + gizmo.setRotation(aa); + + updateGizmo(); + TranslateActionConstraints.addConstraints(new Resource[]{pcpResource}, detector); + parent.setViewChanged(true); + } + + + + Vector3d getTranslate() { + Vector3d translate = new Vector3d(); + Vector3d o = new Vector3d(); + Vector3d d = new Vector3d(); + parent.createPickRay(o, d); + //Vector3d p = gizmo.getPosition(); + if (gizmo.isSelected()) { + double s[] = new double[1]; + + Vector3d i1 = new Vector3d(); + Vector3d i2 = new Vector3d(); + s = new double[2]; + MathTools.intersectStraightStraight(orgPos, dir,o, d, i2, i1,s); + translate.set(dir); + if (s[0] < 0.0) + s[0] = 0.0; + + translate.scale(s[0]); + translate.add(orgPos); + + if (useConstraints) { + Vector3d t = new Vector3d(translate); +// FIXME : snapped point may be outside of proper range + Point3d snap = detector.getPointSnap2(t, dir); + if (snap != null) { + translate = new Vector3d(snap); + } + } + + return translate; + } + return null; + } + + Vector3d prevTranslate = new Vector3d(); + + @Override + public void doChanges(Graph g) throws Exception { + if (input.mousePressed()) { + //prevTranslate = getTranslate(); + + } + if (input.mouseClicked()) { + end(); + return; + } + if (!input.mouseDragged()) { + parent.getDefaultAction().update(); + return; + } + parent.setViewChanged(true); + + + List mos = parent.getSelectionAdapter().getSelectedObjects(); + Vector3d translate = getTranslate(); + + if (translate == null) { + //cameraRotateAction.update(); + parent.getDefaultAction().update(); + updateGizmo(); + return; + } + + String text = ""; + for (IGraphicsNode mo : mos) { + G3DNode node = mo.getG3DNode(g); + G3DAPI.setWorldPosition(node, translate); + //G3DTools.setTuple3(node.getW, translation) + //G3DTools.setLocalTranslation(node,translate); + // mo.setLocalTranslation(translate); + text += G3DTools.getVector(node.getWorldPosition()) + " " + translate;// mo.getWorldPosition() + " " + + + } + setInfoText(text); + + updateGizmo(); + + } + + protected void updateGizmo() { + gizmo.update(camera.getCameraPos(),component); + } + + public void setInfoText(String text) { + + } + +} \ No newline at end of file diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/TranslateInlineComponentAction.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/TranslateInlineComponentAction.java new file mode 100644 index 00000000..ebb66498 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/TranslateInlineComponentAction.java @@ -0,0 +1,234 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.actions; + +import java.util.List; + +import javax.vecmath.Point3d; +import javax.vecmath.Vector3d; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IToolBarManager; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Resource; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.proconf.g3d.actions.ConstrainedTransformAction; +import org.simantics.proconf.g3d.base.G3DAPI; +import org.simantics.proconf.g3d.base.G3DTools; +import org.simantics.proconf.g3d.base.MathTools; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.gizmo.TransformInlineGizmo; +import org.simantics.proconf.g3d.scenegraph.IGraphicsNode; +import org.simantics.proconf.g3d.stubs.G3DNode; + +import fi.vtt.simantics.processeditor.Activator; +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.common.PipingTools2; +import fi.vtt.simantics.processeditor.stubs.InlineComponent; +import fi.vtt.simantics.processeditor.stubs.PipeControlPoint; + + +public class TranslateInlineComponentAction extends ConstrainedTransformAction { + + TransformInlineGizmo gizmo; + List mos; + Point3d start; + Point3d end; + Vector3d dir; + double istep = 10.0; + int decimals = 2; + + public TranslateInlineComponentAction(ThreeDimensionalEditorBase parent) { + super(parent); + gizmo = new TransformInlineGizmo(component.getDisplaySystem().getRenderer()); + + } + + public void init() { + this.setText("Translate"); + this.setToolTipText("Translate the object"); + this.setImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/translate_d.png")); + } + + + + @Override + public boolean usable(Graph graph, List resources) { + // TODO : it should be possible to move multiple components on the same straight + if (resources.size() != 1) + return false; + IEntity r = EntityFactory.create(graph,resources.get(0)); + PipeControlPoint pcp = null; + if (r.isInstanceOf(ProcessResource.plant3Dresource.FixedLengthInlineComponent)) { + InlineComponent component = new InlineComponent(r); + pcp = component.getControlPoint(); + } else { + return false; + } + if (pcp.getNext() == null || pcp.getPrevious() == null) + return false; + return true; + } + + @Override + public void deactivate() { + parent.setGizmo(null); + super.deactivate(); + } + + @Override + public void activate() { + parent.setGizmo(gizmo); + + String text = ""; + mos = parent.getSelectionAdapter().getSelectedObjects(); +// for (IGraphicsNode mo : mos) { +// text += GraphicsNodeTools.getWorldTranslation(mo.getGraphicsNode());//mo.getWorldPosition() + " "; +// } + + mos.iterator().next().getGroup().attachChild(gizmo.getNode()); + setInfoText(text); + + + start = new Point3d(); + end = new Point3d(); + dir = new Vector3d(); + parent.getSession().syncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + + InlineComponent ic = new InlineComponent(mos.iterator().next().getG3DNode(g)); + PipingTools2.getInlineMovement(ic, start, end); + + //PipingTools2.getInlineComponentEnds(ic, start, end); + dir.set(end); + dir.sub(start); + + return GraphRequestStatus.transactionComplete(); + } + }); + + updateGizmo(); + parent.setViewChanged(true); + } + + + + Vector3d getTranslate() { + Vector3d translate = new Vector3d(); + Vector3d o = new Vector3d(); + Vector3d d = new Vector3d(); + parent.createPickRay(o, d); + //Vector3d p = gizmo.getPosition(); + if (gizmo.isSelected()) { + double s[] = new double[1]; + + Vector3d i1 = new Vector3d(); + Vector3d i2 = new Vector3d(); + s = new double[2]; + MathTools.intersectStraightStraight( start, dir,o, d, i2, i1,s); + translate.set(dir); + if (s[0] < 0.0) + s[0] = 0.0; + else if (s[0] > 1.0) + s[0] = 1.0; + translate.scale(s[0]); + translate.add(start); + + if (useConstraints) { + Vector3d t = new Vector3d(translate); +// FIXME : snapped point may be outside of proper range + Point3d snap = detector.getPointSnap2(t, dir); + if (snap != null) { + translate = new Vector3d(snap); + } + } + + return translate; + } + return null; + } + + Vector3d prevTranslate = new Vector3d(); + + @Override + public void doChanges(Graph graph) throws Exception { + if (input.mousePressed()) { + //prevTranslate = getTranslate(); + + } + if (input.mouseClicked()) { + end(); + return; + } + if (!input.mouseDragged()) { + parent.getDefaultAction().update(); + return; + } + parent.setViewChanged(true); + + + List mos = parent.getSelectionAdapter().getSelectedObjects(); + Vector3d translate = getTranslate(); + + if (translate == null) { + //cameraRotateAction.update(); + parent.getDefaultAction().update(); + updateGizmo(); + return; + } + //translate.sub(prevTranslate); + +// if ((input.dragModifiers() & MouseEvent.CTRL_MASK) > 0) { +// String text = ""; +// for (IGraphicsNode mo : mos) { +// +// Point3d p = mo.getWorldPosition(); +// p.add(translate); +// p.x = Math.round(istep * p.x) / istep; +// BigDecimal bx = new BigDecimal(p.x); +// bx.setScale(decimals, BigDecimal.ROUND_HALF_UP); +// p.x = bx.doubleValue(); +// +// +// text += p + " "; +// mo.setWorldTranslation(p); +// +// } +// this.parent.setInfoText(text); +// +// } else { + String text = ""; + for (IGraphicsNode mo : mos) { + G3DNode node = mo.getG3DNode(graph); + G3DAPI.setWorldPosition(node, translate); + //G3DTools.setLocalTranslation(node, translate); + //mo.setLocalTranslation(translate); + text += G3DTools.getVector(node.getWorldPosition()) +" " + translate;//mo.getWorldPosition() + " " + translate; + } + setInfoText(text); +// } + updateGizmo(); + + } + + protected void updateGizmo() { + gizmo.update(camera.getCameraPos(),component); + } + + public void setInfoText(String text) { + + } + +} \ No newline at end of file diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/TranslateStraightAction.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/TranslateStraightAction.java new file mode 100644 index 00000000..84d3a641 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/TranslateStraightAction.java @@ -0,0 +1,404 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.actions; + +import java.util.List; + +import javax.vecmath.AxisAngle4f; +import javax.vecmath.Point3d; +import javax.vecmath.Vector3d; + +import org.eclipse.jface.action.IToolBarManager; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Resource; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.proconf.g3d.actions.ConstrainedTransformAction; +import org.simantics.proconf.g3d.actions.TranslateActionConstraints; +import org.simantics.proconf.g3d.base.G3DTools; +import org.simantics.proconf.g3d.base.MathTools; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.gizmo.AbstractGizmo; +import org.simantics.proconf.g3d.gizmo.TransformGizmo; +import org.simantics.proconf.g3d.gizmo.TransformInlineGizmo; + +import fi.vtt.simantics.processeditor.common.ControlPointTools; +import fi.vtt.simantics.processeditor.common.PipingTools2; +import fi.vtt.simantics.processeditor.stubs.FixedLengthInlineComponent; +import fi.vtt.simantics.processeditor.stubs.PipeControlPoint; + +import fi.vtt.simantics.processeditor.Activator; +import fi.vtt.simantics.processeditor.ProcessResource; + + +/** + * Action that allows translating VariableLengthInlineComontolPoints. + * + * TODO : Action won't show two gizmos when both ends can be moved + * TODO : With loose ends, gizmo is in the middle of component, when it should be positioned on the end of the component + * + * + * @author Marko Luukkainen + * + */ +public class TranslateStraightAction extends ConstrainedTransformAction { + + private static final int CONNECTED = 0; + private static final int LOOSE = 1; + + private AbstractGizmo gizmo; + private TransformGizmo transformGizmo; + private TransformInlineGizmo transformInlineGizmo; + + + //private Straight straight; + //private PipeControlPoint pcp; + + private Resource pcpResource; + + private int type; + + Vector3d prevTranslate = new Vector3d(); + + Point3d start; + Point3d end; + Vector3d dir; + double istep = 10.0; + int decimals = 2; + public TranslateStraightAction(ThreeDimensionalEditorBase parent) { + super(parent); + transformGizmo = new TransformGizmo(component.getDisplaySystem().getRenderer()); + transformInlineGizmo = new TransformInlineGizmo(component.getDisplaySystem().getRenderer()); + } + + public void init() { + this.setText("Translate"); + this.setToolTipText("Translate one end of a straight"); + this.setImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/translate_d.png")); + } + + @Override + public boolean usable(Graph graph, List resources) { + if (resources.size() != 1) + return false; + + IEntity r = EntityFactory.create(graph,resources.get(0)); + if (!r.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent)) { + return false; + } + FixedLengthInlineComponent flic = new FixedLengthInlineComponent(r); + PipeControlPoint scp = flic.getControlPoint(); + PipeControlPoint start = scp.getPrevious(); + PipeControlPoint end = scp.getNext(); + + if (start == null) { + pcpResource = scp.getResource(); + type = LOOSE; + return true; + } + if (end == null) { + pcpResource = scp.getResource(); + type = LOOSE; + return true; + } + if (start.isInstanceOf(ProcessResource.plant3Dresource.BranchEndControlPoint)) { + pcpResource = graph.getObjects(start.getResource(), ProcessResource.plant3Dresource.SubPointOf).iterator().next(); + type = CONNECTED; + return true; + } + if (end.isInstanceOf(ProcessResource.plant3Dresource.BranchEndControlPoint)) { + pcpResource = graph.getObjects(end.getResource(), ProcessResource.plant3Dresource.SubPointOf).iterator().next(); + type = CONNECTED; + return true; + } + + + return false; + + } + + @Override + public void deactivate() { + super.deactivate(); + parent.setGizmo(null); + + } + + @Override + public void activate() { + parent.getSession().syncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + PipeControlPoint pcp = new PipeControlPoint(g,pcpResource); + if (type == CONNECTED) { + gizmo = transformInlineGizmo; + + start = new Point3d(); + end = new Point3d(); + dir = new Vector3d(); + //ControlPointTools.getInlineControlPointEnds(pcp, start, end, dir); + ControlPointTools.getInlineMovement(pcp, start, end); + + //PipingTools2.getInlineComponentEnds(ic, start, end); + dir.set(end); + dir.sub(start); + + //System.out.println(start + " " + end + " " + dir); + Vector3d front = new Vector3d(1.0,0.0,0.0); + Vector3d current = new Vector3d(dir); + float angle = (float)current.angle(front); + AxisAngle4f aa; + if (angle < 0.01 || (Math.PI - angle) < 0.01) { + aa = new AxisAngle4f(); + } else { + current.normalize(); + Vector3d right = new Vector3d(); + right.cross(front, current); + + right.normalize(); + if (right.lengthSquared() < 0.01) { + aa = new AxisAngle4f(); + } else { + aa = new AxisAngle4f((float) right.x, (float) right.y, (float) right.z, angle); + } + } + transformInlineGizmo.setRotation(aa); + + } else { + gizmo = transformGizmo; + } + parent.setGizmo(gizmo); + + component.getNoShadowRoot().attachChild(gizmo.getNode()); + + updateGizmo(pcp); + TranslateActionConstraints.addConstraints(new Resource[]{pcpResource}, detector); + parent.setViewChanged(true); + + return GraphRequestStatus.transactionComplete(); + } + }); + + } + + + // FIXME : copy-paste from TranslateInlineAction.getTranslate() + Vector3d getTranslate() { + Vector3d translate = new Vector3d(); + Vector3d o = new Vector3d(); + Vector3d d = new Vector3d(); + parent.createPickRay(o, d); + // Vector3d p = gizmo.getPosition(); + if (((TransformInlineGizmo) gizmo).isSelected()) { + double s[] = new double[1]; + + Vector3d i1 = new Vector3d(); + Vector3d i2 = new Vector3d(); + s = new double[2]; + MathTools.intersectStraightStraight(start, dir, o, d, i2, i1, s); + translate.set(dir); + if (s[0] < 0.0) + s[0] = 0.0; + else if (s[0] > 1.0) + s[0] = 1.0; + translate.scale(s[0]); + translate.add(start); + + if (useConstraints) { + Vector3d t = new Vector3d(translate); + // FIXME : snapped point may be outside of proper range + Point3d snap = detector.getPointSnap2(t, dir); + if (snap != null) { + translate = new Vector3d(snap); + } + } + + return translate; + } + return null; + } + // FIXME : copy-paste from TranslateAction.getTranslate(Vector3d v) + Vector3d getTranslate(PipeControlPoint pcp, Vector3d offset) { + Vector3d translate = new Vector3d(); + Vector3d o = new Vector3d(); + Vector3d d = new Vector3d(); + parent.createPickRay(o, d); + Vector3d p = ((TransformGizmo)gizmo).getPosition(); + Vector3d dir = null; + switch (((TransformGizmo)gizmo).getSelected()) { + case TransformGizmo.XYZ : + Vector3d normal = camera.getUnNormalizedHeading(); + normal.normalize(); + double s[] = new double[1]; + Vector3d r = new Vector3d(); + if (MathTools.intersectStraightPlane(o, d, p, normal, r)) { + r.sub(p); + translate.x = r.x; + translate.y = r.y; + translate.z = r.z; + } + break; + case TransformGizmo.X : + dir = new Vector3d(1.0,0.0,0.0); + Vector3d i1 = new Vector3d(); + Vector3d i2 = new Vector3d(); + s = new double[2]; + MathTools.intersectStraightStraight( p, dir,o, d, i2, i1,s); + translate.x = s[0]; + + break; + case TransformGizmo.Y : + dir = new Vector3d(0.0,1.0,0.0); + i1 = new Vector3d(); + i2 = new Vector3d(); + s = new double[2]; + MathTools.intersectStraightStraight( p, dir,o, d, i2, i1,s); + translate.y = s[0]; + break; + case TransformGizmo.Z : + dir = new Vector3d(0.0,0.0,1.0); + i1 = new Vector3d(); + i2 = new Vector3d(); + s = new double[2]; + MathTools.intersectStraightStraight( p, dir,o, d, i2, i1,s); + translate.z = s[0]; + break; + case TransformGizmo.XY : + normal = new Vector3d(0.0,0.0,1.0); + s = new double[1]; + r = new Vector3d(); + if (MathTools.intersectStraightPlane(o, d, p, normal, r)) { + r.sub(p); + translate.x = r.x; + translate.y = r.y; + } + break; + case TransformGizmo.XZ : + normal = new Vector3d(0.0,1.0,0.0); + s = new double[1]; + r = new Vector3d(); + if (MathTools.intersectStraightPlane(o, d, p, normal, r)) { + r.sub(p); + translate.x = r.x; + translate.z = r.z; + } + break; + case TransformGizmo.YZ : + normal = new Vector3d(1.0,0.0,0.0); + s = new double[1]; + r = new Vector3d(); + if (MathTools.intersectStraightPlane(o, d, p, normal, r)) { + r.sub(p); + translate.y = r.y; + translate.z = r.z; + } + break; + default : + + return null; + } + //System.out.println(translate + " " + offset); + translate.sub(offset); + + if (useConstraints) { + switch (((TransformGizmo)gizmo).getSelected()) { + case TransformGizmo.X: + case TransformGizmo.Y: + case TransformGizmo.Z: + Vector3d t = new Vector3d(translate); + // TODO : to the test against all translated objects and snap to closest one + Point3d pos = G3DTools.getPoint(pcp.getLocalPosition()); + t.add(pos); + Point3d snap = detector.getPointSnap2(t, dir); + if (snap != null) { + // System.out.print("t: " + translate); + translate = new Vector3d(snap); + translate.sub(pos); + // System.out.println(" " + translate); + } + break; + + } + } + //System.out.println(translate); + return translate; + } + + + + @Override + public void doChanges(Graph graph) throws Exception { + PipeControlPoint pcp = new PipeControlPoint(graph, pcpResource); + if (input.mousePressed()) { + if (type == LOOSE) + prevTranslate = getTranslate(pcp,new Vector3d()); + + } + if (input.mouseClicked()) { + //System.out.println("end"); + end(); + return; + } + if (!input.mouseDragged()) { + parent.getDefaultAction().update(); + return; + } + detector.clearConstraintHighlights(); + parent.setViewChanged(true); + + + Vector3d translate; + if (type == CONNECTED) + translate = getTranslate(); + else + translate = getTranslate(pcp,prevTranslate); + + if (translate == null) { + //cameraRotateAction.update(); + parent.getDefaultAction().update(); + updateGizmo(pcp); + return; + } + + String text = ""; + + if (type == CONNECTED) { + G3DTools.setTuple3(pcp.getWorldPosition(), translate); + // mo.setLocalTranslation(translate); + //text += GraphicsNodeTools.getWorldTranslation(mo.getGraphicsNode()) + " " + translate;// mo.getWorldPosition() + if (useConstraints) + text+=detector.getSnapString(); + + } else { + G3DTools.addTuple3(pcp.getWorldPosition(), translate); + // mo.modifyWorldTranslation(translate); + //text += GraphicsNodeTools.getWorldTranslation(mo.getGraphicsNode()) + " ";//mo.getWorldPosition() + " "; + if (useConstraints) + text+=detector.getSnapString(); + + } + + setInfoText(text); + updateGizmo(pcp); + + } + + protected void updateGizmo(PipeControlPoint pcp) { + gizmo.update(G3DTools.getVector(pcp.getWorldPosition()), camera.getCameraPos(), component); + } + + public void setInfoText(String text) { + + } + +} \ No newline at end of file diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/adapters/InlineComponentConstraintAdapter.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/adapters/InlineComponentConstraintAdapter.java new file mode 100644 index 00000000..e21bda74 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/adapters/InlineComponentConstraintAdapter.java @@ -0,0 +1,36 @@ +package fi.vtt.simantics.processeditor.adapters; + +import javax.vecmath.Point3d; +import javax.vecmath.Vector3d; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.db.adaption.AdaptionException; +import org.simantics.db.adaption.ResourceAdapter; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.proconf.g3d.base.Constraint; + +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.common.PipingTools2; + +public class InlineComponentConstraintAdapter implements ResourceAdapter { + @SuppressWarnings("unchecked") + @Override + public T adapt(Graph graph, Resource resource, Resource mia) throws AdaptionException { + Constraint c = new Constraint(); + assert(graph.isInstanceOf(resource, ProcessResource.plant3Dresource.InlineComponent)); + IEntity ent = EntityFactory.create(graph,resource); + Point3d center = new Point3d(); + Point3d p1 = new Point3d(); + Point3d p2 = new Point3d(); + Vector3d dir = new Vector3d(); + PipingTools2.getInlineComponentEnds(ent, center, p1, p2, dir); + c.points.add(center); + c.points.add(p1); + c.points.add(p2); + c.dirs.add(dir); + return (T) c; + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/adapters/NozzleConstraintAdapter.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/adapters/NozzleConstraintAdapter.java new file mode 100644 index 00000000..33b8075f --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/adapters/NozzleConstraintAdapter.java @@ -0,0 +1,32 @@ +package fi.vtt.simantics.processeditor.adapters; + +import javax.vecmath.Point3d; +import javax.vecmath.Vector3d; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.db.adaption.AdaptionException; +import org.simantics.db.adaption.ResourceAdapter; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.proconf.g3d.base.Constraint; +import org.simantics.proconf.g3d.base.G3DTools; + +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.common.PipingTools2; + +public class NozzleConstraintAdapter implements ResourceAdapter { + @SuppressWarnings("unchecked") + @Override + public T adapt(Graph graph, Resource resource, Resource mia) throws AdaptionException { + Constraint c = new Constraint(); + assert(graph.isInstanceOf(resource, ProcessResource.plant3Dresource.Nozzle)); + IEntity ent = EntityFactory.create(graph,resource); + Vector3d dir = PipingTools2.getNozzleDirection(ent); + Point3d center = G3DTools.getPoint(ent.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition)); + c.points.add(center); + c.dirs.add(dir); + return (T) c; + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/adapters/TurnComponentConstraintAdapter.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/adapters/TurnComponentConstraintAdapter.java new file mode 100644 index 00000000..4df00b55 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/adapters/TurnComponentConstraintAdapter.java @@ -0,0 +1,42 @@ +package fi.vtt.simantics.processeditor.adapters; + +import javax.vecmath.Point3d; +import javax.vecmath.Vector3d; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.db.adaption.AdaptionException; +import org.simantics.db.adaption.ResourceAdapter; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.proconf.g3d.base.Constraint; +import org.simantics.proconf.g3d.base.G3DTools; + +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.actions.PositionType; +import fi.vtt.simantics.processeditor.common.ControlPointTools; +import fi.vtt.simantics.processeditor.common.PipingTools2.Direction; + +public class TurnComponentConstraintAdapter implements ResourceAdapter { + @SuppressWarnings("unchecked") + @Override + public T adapt(Graph graph, Resource resource, Resource mia) throws AdaptionException { + Constraint c = new Constraint(); + assert(graph.isInstanceOf(resource, ProcessResource.plant3Dresource.TurnComponent)); + IEntity ent = EntityFactory.create(graph,resource); + IEntity pcp = ent.getSingleRelatedObject(ProcessResource.plant3Dresource.HasControlPoint); + + Point3d center = G3DTools.getPoint(pcp.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition)); + Point3d p1 = ControlPointTools.getRealPosition(pcp, PositionType.NEXT); + Point3d p2 = ControlPointTools.getRealPosition(pcp, PositionType.PREVIOUS); + Vector3d dir1 = ControlPointTools.getPathLegDirection(pcp, Direction.NEXT); + Vector3d dir2 = ControlPointTools.getPathLegDirection(pcp, Direction.PREVIOUS); + c.points.add(center); + c.points.add(p1); + c.points.add(p2); + c.dirs.add(dir1); + c.dirs.add(dir2); + return (T) c; + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/animations/PipeAnimationController.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/animations/PipeAnimationController.java new file mode 100644 index 00000000..0524171f --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/animations/PipeAnimationController.java @@ -0,0 +1,141 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.animations; + +import java.net.URL; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.runtime.FileLocator; +import org.eclipse.core.runtime.Path; +import org.simantics.db.Graph; +import org.simantics.layer0.utils.IEntity; +import org.simantics.proconf.g3d.animation.Animatable; +import org.simantics.proconf.g3d.animation.AnimationController; +import org.simantics.proconf.g3d.base.JmeRenderingComponent; + +import com.jme.bounding.BoundingBox; +import com.jme.image.Texture; +import com.jme.intersection.PickResults; +import com.jme.math.Ray; +import com.jme.renderer.Renderer; +import com.jme.scene.Node; +import com.jme.scene.state.AlphaState; +import com.jme.scene.state.TextureState; +import com.jme.scene.state.ZBufferState; +import com.jme.util.TextureManager; +import com.jmex.effects.particles.ParticleGeometry; + +import fi.vtt.simantics.processeditor.Activator; +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.stubs.PipeRun; +import fi.vtt.simantics.processeditor.stubs.VariableLengthInlineComponent; + + +public class PipeAnimationController implements AnimationController { + private List pipeAnimations = new ArrayList(); + + List animatables = new ArrayList(); + + private double d = Math.random(); + private double delta = 0.01; + + AlphaState as1; + TextureState ts; + Node particleNode = new Node() { + private static final long serialVersionUID = 7477121374264124684L; + + // Without this picking code tries to pick particles which doesn't work (Causes class cast exception) + public void findPick(Ray toTest, PickResults results) { + return; + } + }; + + public PipeAnimationController(JmeRenderingComponent component, PipeRun pipeline) { + as1 = component.getDisplaySystem().getRenderer().createAlphaState(); + as1.setBlendEnabled(true); + as1.setSrcFunction(AlphaState.SB_SRC_ALPHA); + as1.setDstFunction(AlphaState.DB_ONE); + //as1.setDstFunction(AlphaState.DB_ONE_MINUS_SRC_ALPHA); + as1.setTestEnabled(true); + as1.setTestFunction(AlphaState.TF_GREATER); + as1.setEnabled(true); + + TextureState ts = component.getDisplaySystem().getRenderer().createTextureState(); + //URL url = FileLocator.find(com.jme.eclipse.Activator.getDefault().getBundle(),new Path("data/textures/flaresmall.jpg"),null); + URL url = FileLocator.find(Activator.getDefault().getBundle(),new Path("icons/bubble.png"),null); + + ts.setTexture( + TextureManager.loadTexture(url, + Texture.MM_LINEAR_LINEAR, + Texture.FM_LINEAR)); + ts.setEnabled(true); + + ZBufferState zs = component.getDisplaySystem().getRenderer().createZBufferState(); + zs.setFunction(ZBufferState.CF_LEQUAL); + zs.setWritable(false); + //zs.setFunction(ZBufferState.CF_ALWAYS); + particleNode.setRenderState(as1); + particleNode.setRenderState(ts); + particleNode.setRenderState(zs); + particleNode.setRenderQueueMode(Renderer.QUEUE_TRANSPARENT); + component.getShadowRoot().attachChild(particleNode); + createAnimations(pipeline); + } + + public void addAnimatable(Animatable animatable) { + animatables.add((PipeFlowAnimation)animatable); + + } + + public void setAnimatable(Animatable animatable) { + animatables.clear(); + animatables.add((PipeFlowAnimation)animatable); + + } + + + public void updateAnimation(Graph g, double frameTime) { + d += delta; + if (d > 1.0) { + d = 1.0; + delta = -delta; + } else if (d < 0.0) { + delta = -delta; + d = 0.0; + } + for (Animatable a : animatables) + a.animate(d,frameTime); + } + + public void dispose() { + for (ParticleGeometry p : pipeAnimations) + p.removeFromParent(); + pipeAnimations.clear(); + + } + + private void createAnimations(PipeRun pipeline) { + List straights = new ArrayList(); + for (IEntity t : pipeline.getChild()) { + if (t.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent)) + straights.add(t); + } + + for (IEntity r : straights) { + animatables.add(new PipeFlowAnimation(pipeAnimations, particleNode, new VariableLengthInlineComponent(r),false)); + } + particleNode.setModelBound(new BoundingBox()); + particleNode.updateModelBound(); + particleNode.updateRenderState(); + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/animations/PipeFlowAnimation.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/animations/PipeFlowAnimation.java new file mode 100644 index 00000000..d86358da --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/animations/PipeFlowAnimation.java @@ -0,0 +1,144 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.animations; + +import java.util.List; + +import javax.vecmath.Point3d; +import javax.vecmath.Vector3d; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.proconf.g3d.animation.Animatable; +import org.simantics.proconf.g3d.base.G3DTools; +import org.simantics.proconf.g3d.base.VecmathJmeTools; + +import com.jme.renderer.ColorRGBA; +import com.jme.scene.Node; +import com.jmex.effects.particles.ParticleFactory; +import com.jmex.effects.particles.ParticleGeometry; + + +import fi.vtt.simantics.processeditor.common.ControlPointTools; +import fi.vtt.simantics.processeditor.common.PipingTools2; +import fi.vtt.simantics.processeditor.stubs.PipeControlPoint; +import fi.vtt.simantics.processeditor.stubs.VariableLengthInlineComponent; + + +public class PipeFlowAnimation implements Animatable{ + + ParticleGeometry particle; + float length; + int numParticles; + + public PipeFlowAnimation(List pipeAnimations, Node particleNode, VariableLengthInlineComponent s, boolean reversed) { + PipeControlPoint pcp = s.getControlPoint(); + + Point3d p1 = new Point3d(); + Point3d p2 = new Point3d(); + + ControlPointTools.getInlineControlPointEnds(pcp, p2, p1); + + if (reversed) { + Point3d t = p1; + p1 = p2; + p2 = t; + } + + + Vector3d dir = new Vector3d(p2); + dir.sub(p1); + length = (float)dir.length(); + //if (length < 0.1f) + // return; + //continue; + // with longer pipes particles will travel too far so the length of the pipe must be scaled + length *= 0.83f; + float vel = 0.1f; + //float size = (float)s.getPipeRadiusValue() + 0.1f; + //size *= 2.f; + float size = (float)s.getPipeDiameter()[0]; + //size *= 1.2f; + float life = length/vel; + + //int releaseRate = 40; + //int numParticles = (int)(releaseRate * life / 100.f);//(int)(releaseRate * life / 500.f); + + numParticles = (int)(length * 2.0); + int releaseRate = (int)((numParticles * 500.0) / life); + + if (numParticles < 2) + numParticles = 2; + + particle = ParticleFactory.buildParticles("Animation of " + s.getResource().getResourceId(),numParticles, ParticleGeometry.PT_QUAD);//new ParticleMesh("Animation of " + r.getId(),40); + particle.setEmissionDirection(VecmathJmeTools.get(dir).normalize()); + particle.setLocalTranslation(VecmathJmeTools.get(p1)); + particle.setEmitType(ParticleGeometry.ET_POINT); + particle.setInitialVelocity(vel); + particle.setMinimumAngle(0.f); + particle.setMaximumAngle(0.f); + particle.setReleaseRate(releaseRate); + particle.getParticleController().setReleaseVariance(0.f); + particle.getParticleController().setControlFlow(true); + particle.setStartColor(new ColorRGBA(1.f,1.f,0.f,1.f)); + particle.setEndColor(new ColorRGBA(1.f,1.f,0.f,1.f)); + particle.setStartSize(size); + particle.setEndSize(size); + setFlow(vel); + particle.getParticleController().setSpeed(vel); + particle.warmUp(60); + pipeAnimations.add(particle); + particleNode.attachChild(particle); + } + + ParticleGeometry getParticleGeometry() { + return particle; + } + + private void setFlow(float vel) { + float life; + if (vel > 0.f) + life = length/vel; + else + life = 0.f; + particle.setInitialVelocity(vel); + particle.setMaximumLifeTime(life); + particle.setMinimumLifeTime(life); + particle.getParticleController().setSpeed(vel); + + } + + private void setReleaserate(float vel) { + float life; + if (vel > 0.f) + life = length/vel; + else + life = 0.f; + particle.setInitialVelocity(vel); + particle.setMaximumLifeTime(life); + particle.setMinimumLifeTime(life); + particle.setReleaseRate((int)((numParticles * 500.0) / life)); + } + + public void animate(double delta,double frameRate) { + //setFlow(0.1f*(float)delta); + setReleaserate(0.05f*(float)delta); + } + + public boolean setAnimation(Graph graph, Resource animation) { + return false; + } + + public boolean setRandomAnimation(Graph graph) { + return false; + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/animations/ResourcePipeAnimationController.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/animations/ResourcePipeAnimationController.java new file mode 100644 index 00000000..43505000 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/animations/ResourcePipeAnimationController.java @@ -0,0 +1,72 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.animations; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.proconf.g3d.base.JmeRenderingComponent; + +import com.jme.renderer.ColorRGBA; + +import fi.vtt.simantics.processeditor.stubs.PipeRun; + +// TODO : this class won't work with valueSets +public class ResourcePipeAnimationController extends PipeAnimationController { + Resource color; + Resource velocity; + + ColorRGBA minColor = new ColorRGBA(0.f,0.f,1.f,1.f); + ColorRGBA maxColor = new ColorRGBA(1.f,0.f,0.f,1.f); + ColorRGBA currentColor = new ColorRGBA(1.f,1.f,1.f,1.f); + + double colorMin; + double colorMax; + double iColorRange; + + double velMin; + double velMax; + double iVelRange; + public ResourcePipeAnimationController(JmeRenderingComponent component, PipeRun pipeline, Resource color,double colorMin, double colorMax, Resource velocity, double velMin, double velMax) { + super(component, pipeline); + this.color = color; + this.velocity = velocity; + + this.colorMin = colorMin; + this.colorMax = colorMax; + this.iColorRange = 1.0/(colorMax-colorMin); + this.velMin = velMin; + this.velMax = velMax; + this.iVelRange = 1.0/(velMax-velMin); + } + + private double getVelocity(Graph graph) { + return graph.getScalarDouble(velocity); + //velocity.getDoubleScalarValue(); + } + + private double getColor(Graph graph) { + return graph.getScalarDouble(color); + } + public void updateAnimation(Graph g,double frameTime) { + double d = (getVelocity(g)-velMin)*iVelRange; + float f = (float)((getColor(g)-colorMin)*iColorRange); + currentColor.interpolate(minColor, maxColor, f); + for (PipeFlowAnimation a : animatables) { + a.animate(d,frameTime); + //a.getParticleGeometry().setDefaultColor(currentColor); + a.getParticleGeometry().setStartColor(currentColor); + a.getParticleGeometry().setEndColor(currentColor); + } + } + + + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/ControlPointTools.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/ControlPointTools.java new file mode 100644 index 00000000..077ea704 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/ControlPointTools.java @@ -0,0 +1,1198 @@ +package fi.vtt.simantics.processeditor.common; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Stack; + +import javax.vecmath.AxisAngle4d; +import javax.vecmath.Matrix3d; +import javax.vecmath.Point3d; +import javax.vecmath.Quat4d; +import javax.vecmath.Tuple3d; +import javax.vecmath.Vector3d; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.proconf.g3d.base.G3DTools; +import org.simantics.proconf.g3d.base.MathTools; +import org.simantics.proconf.g3d.base.TransformationTools; +import org.simantics.utils.ErrorLogger; +import org.simantics.utils.datastructures.Pair; + +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.actions.PositionType; +import fi.vtt.simantics.processeditor.common.PipingTools2.Direction; +import fi.vtt.simantics.processeditor.stubs.PipeControlPoint; +import fi.vtt.simantics.processeditor.stubs.PipeRun; + +public class ControlPointTools { + + private static boolean DEBUG = false; + + private static TransformationTools tt; + + public static void initialize() { + tt = new TransformationTools(ProcessResource.plant3Dresource.HasSubPoint,ProcessResource.plant3Dresource.SubPointOf) { + @Override + public IEntity getParent(IEntity node) { + IEntity parent = super.getParent(node); + if (parent == null) { + parent = node.getAtMostOneRelatedObject(ProcessResource.plant3Dresource.ControlPointOf); + if (parent != null) + parent = parent.getAtMostOneRelatedObject(ProcessResource.g3dResource.HasParent); + else + parent = node.getAtMostOneRelatedObject(ProcessResource.g3dResource.HasParent); + + } + return parent; + } + }; + } + + public static void deinitialize() { + tt = null; + } + + /** + * Adds new control point between given control points. + * New pcp must be already part of the same piperun as previous CP and nextCP + * + * SizeChangeControlPoints cannot be inserted with this method, since it does link two different piperuns to each other + * + * @param newCP + * @param previousCP + * @param nextCP + */ + public static void insertControlPoint(IEntity newCP, IEntity previousCP, IEntity nextCP) { + // inserting an offsetpoint is error, + assert(!newCP.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)); + // size change control point cannot be inserted this way, because it ends PipeRun + assert(!newCP.isInstanceOf(ProcessResource.plant3Dresource.SizeChangeControlPoint)); + + IEntity piperun = previousCP.getSingleRelatedObject(ProcessResource.plant3Dresource.ControlPointOfPipeRun); + // and just to make sure that control point structure is not corrupted + assert(piperun.equals(nextCP.getSingleRelatedObject(ProcessResource.plant3Dresource.ControlPointOfPipeRun))); + assert(piperun.equals(newCP.getSingleRelatedObject(ProcessResource.plant3Dresource.ControlPointOfPipeRun))); + + // insert new BranchControlPoint between straight's control points + IEntity previousNext = previousCP.getAtMostOneRelatedObject(ProcessResource.plant3Dresource.HasNext); + IEntity previousPrevious = previousCP.getAtMostOneRelatedObject(ProcessResource.plant3Dresource.HasPrevious); + + IEntity offsetCP = null; + + if (newCP.isInstanceOf(ProcessResource.plant3Dresource.OffsettingPoint)) { + offsetCP = newCP.getSingleRelatedObject(ProcessResource.plant3Dresource.HasSubPoint); + } + + if (previousNext != null && previousNext.equals(nextCP)) { + assert(!previousCP.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)); + assert(!nextCP.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)); + + setStatement(previousCP, ProcessResource.plant3Dresource.HasNext, newCP); + setStatement(newCP, ProcessResource.plant3Dresource.HasPrevious, previousCP); + + if (previousCP.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)) { + IEntity sccp = previousCP.getSingleRelatedObject(ProcessResource.plant3Dresource.SubPointOf); + setStatement(sccp, ProcessResource.plant3Dresource.HasNext, newCP); + } + + setStatement(newCP, ProcessResource.plant3Dresource.HasNext, nextCP); + + if (offsetCP == null) { + setStatement(nextCP, ProcessResource.plant3Dresource.HasPrevious, newCP); + } else { + setStatement(nextCP, ProcessResource.plant3Dresource.HasPrevious, offsetCP); + setStatement(offsetCP, ProcessResource.plant3Dresource.HasNext, nextCP); + setStatement(offsetCP, ProcessResource.plant3Dresource.HasPrevious, previousCP); + } + + if (nextCP.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)) { + IEntity ocp = nextCP.getSingleRelatedObject(ProcessResource.plant3Dresource.HasSubPoint); + setStatement(ocp, ProcessResource.plant3Dresource.HasPrevious, newCP); + } + + } else if (previousPrevious != null && previousPrevious.equals(nextCP)) { + // control point were given in reverse order + assert(!nextCP.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)); + assert(!previousCP.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)); + + setStatement(newCP, ProcessResource.plant3Dresource.HasNext, previousCP); + if (offsetCP == null) { + setStatement(previousCP, ProcessResource.plant3Dresource.HasPrevious, newCP); + } else { + setStatement(previousCP, ProcessResource.plant3Dresource.HasPrevious, offsetCP); + setStatement(offsetCP, ProcessResource.plant3Dresource.HasNext, previousCP); + setStatement(offsetCP, ProcessResource.plant3Dresource.HasPrevious, nextCP); + } + + if (previousCP.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)) { + IEntity ocp = previousCP.getSingleRelatedObject(ProcessResource.plant3Dresource.HasSubPoint); + setStatement(ocp, ProcessResource.plant3Dresource.HasPrevious, newCP); + } + + setStatement(newCP, ProcessResource.plant3Dresource.HasPrevious, nextCP); + setStatement(nextCP, ProcessResource.plant3Dresource.HasNext, newCP); + if (nextCP.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)) { + IEntity sccp = nextCP.getSingleRelatedObject(ProcessResource.plant3Dresource.SubPointOf); + setStatement(sccp, ProcessResource.plant3Dresource.HasNext, newCP); + } + } else { + ErrorLogger.defaultLogError( + "Route pipe : could not find connection between straight pipe's control points", null); + } + + } + + /** + * Adds new control point attaching it to given control point. + * If the new control point is SizeChangeControlPoint, it must have its offset point set. + * + * @param newCP + * @param pcp + * @param direction + */ + public static void insertControlPoint(IEntity newCP, IEntity pcp, Direction direction) { + assert(!newCP.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)); + if (direction == Direction.NEXT) { + // if direction is next, user must have given OffsetPoint + assert(!pcp.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)); + // basic next/prev links + pcp.removeRelatedStatements(ProcessResource.plant3Dresource.HasNext); + pcp.addStatement(ProcessResource.plant3Dresource.HasNext, newCP); + newCP.removeRelatedStatements(ProcessResource.plant3Dresource.HasPrevious); + newCP.addStatement(ProcessResource.plant3Dresource.HasPrevious, pcp); + // and last take care of sizechange / offset points + if (pcp.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)) { + IEntity sccp = pcp.getSingleRelatedObject(ProcessResource.plant3Dresource.SubPointOf); + sccp.removeRelatedStatements(ProcessResource.plant3Dresource.HasNext); + sccp.addStatement(ProcessResource.plant3Dresource.HasNext, newCP); + } + if (newCP.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)) { + IEntity ocp = newCP.getSingleRelatedObject(ProcessResource.plant3Dresource.HasSubPoint); + ocp.removeRelatedStatements(ProcessResource.plant3Dresource.HasPrevious); + ocp.addStatement(ProcessResource.plant3Dresource.HasPrevious, pcp); + } + } else { + // if direction is previous, user must have given sizechange + assert(!pcp.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)); + // previous direction is more complicated, since if newCP is SizeChangeControlPoint, + // we must link pcp to newCP's OffsetPoint + IEntity nocp = null; + if (newCP.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)) { + nocp = newCP.getSingleRelatedObject(ProcessResource.plant3Dresource.HasSubPoint); + nocp.removeRelatedStatements(ProcessResource.plant3Dresource.HasNext); + nocp.addStatement(ProcessResource.plant3Dresource.HasNext, pcp); + } + pcp.removeRelatedStatements(ProcessResource.plant3Dresource.HasPrevious); + if (nocp == null) + pcp.addStatement(ProcessResource.plant3Dresource.HasPrevious, newCP); + else + pcp.addStatement(ProcessResource.plant3Dresource.HasPrevious, nocp); + + newCP.removeRelatedStatements(ProcessResource.plant3Dresource.HasNext); + newCP.addStatement(ProcessResource.plant3Dresource.HasNext, pcp); + if (pcp.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)) { + IEntity ocp = pcp.getSingleRelatedObject(ProcessResource.plant3Dresource.HasSubPoint); + ocp.removeRelatedStatements(ProcessResource.plant3Dresource.HasPrevious); + if (nocp == null) + ocp.addStatement(ProcessResource.plant3Dresource.HasPrevious, newCP); + else + ocp.addStatement(ProcessResource.plant3Dresource.HasPrevious, nocp); + } + + } + } + + /** + * Returns path legs direction + * @param pcp + * @param direction + * @return + */ + public static Vector3d getPathLegDirection(IEntity pcp,Direction direction) { + IEntity previous = pcp.getAtMostOneRelatedObject(ProcessResource.plant3Dresource.HasPrevious); + IEntity next = pcp.getAtMostOneRelatedObject(ProcessResource.plant3Dresource.HasNext); + if (direction == Direction.NEXT) { + if (next != null) { + if (pcp.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)) + pcp = pcp.getSingleRelatedObject(ProcessResource.plant3Dresource.HasSubPoint); + Point3d p1 = G3DTools.getPoint(pcp.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition)); + Point3d p2 = G3DTools.getPoint(next.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition)); + Vector3d v = new Vector3d(); + v.sub(p2, p1); + return v; + } else { + if (pcp.isInstanceOf(ProcessResource.plant3Dresource.VariableAngleTurnControlPoint)) + throw new RuntimeException("Cannot calculate path leg direction for unconnected variable angle control point " + pcp.getResource()); + if (previous == null) { + if (!pcp.isInstanceOf(ProcessResource.plant3Dresource.DirectedControlPoint)) + throw new RuntimeException("Cannot calculate path leg direction for unconnected control point " + pcp.getResource()); + else + return getDirectedControlPointDirection(pcp); + } else { + if (pcp.isInstanceOf(ProcessResource.plant3Dresource.InlineControlPoint)) { + Point3d p1 = G3DTools.getPoint(previous.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition)); + Point3d p2 = G3DTools.getPoint(pcp.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition)); + Vector3d v = new Vector3d(); + v.sub(p2, p1); + return v; + } + throw new RuntimeException("Missing implementation"); + } + } + } else { + if (previous != null) { + if (pcp.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)) + pcp = pcp.getSingleRelatedObject(ProcessResource.plant3Dresource.SubPointOf); + Point3d p1 = G3DTools.getPoint(pcp.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition)); + Point3d p2 = G3DTools.getPoint(previous.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition)); + Vector3d v = new Vector3d(); + v.sub(p2, p1); + return v; + } else { + if (pcp.isInstanceOf(ProcessResource.plant3Dresource.VariableAngleTurnControlPoint)) + throw new RuntimeException("Cannot calculate path leg direction for unconnected variable angle control point " + pcp.getResource()); + if (next == null) { + if (!pcp.isInstanceOf(ProcessResource.plant3Dresource.DirectedControlPoint)) + throw new RuntimeException("Cannot calculate path leg direction for unconnected control point " + pcp.getResource()); + else { + Vector3d v = getDirectedControlPointDirection(pcp); + v.negate(); + return v; + } + } else { + if (pcp.isInstanceOf(ProcessResource.plant3Dresource.InlineControlPoint)) { + Point3d p1 = G3DTools.getPoint(next.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition)); + Point3d p2 = G3DTools.getPoint(pcp.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition)); + Vector3d v = new Vector3d(); + v.sub(p2, p1); + return v; + } + throw new RuntimeException("Missing implementation"); + } + } + } + + } + + /** + * Return positions (world) of an InlineComponents ends + * @param pcp + * @param p1 + * @param p2 + */ + public static void getInlineControlPointEnds(IEntity pcp, Point3d p1, Point3d p2) { + assert (pcp.isInstanceOf(ProcessResource.plant3Dresource.InlineControlPoint)); + + Point3d pos = G3DTools.getPoint(pcp.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition)); + Vector3d dir = ControlPointTools.getPathLegDirection(pcp, Direction.NEXT); + dir.normalize(); + double length = pcp.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength); + dir.scale(length * 0.5); + p1.set(pos); + p2.set(pos); + p1.add(dir); + p2.sub(dir); + } + + /** + * Return positions (world) of an InlineComponents ends + * @param pcp + * @param p1 + * @param p2 + */ + public static void getInlineControlPointEnds(IEntity pcp, Point3d p1, Point3d p2, Vector3d dir) { + assert (pcp.isInstanceOf(ProcessResource.plant3Dresource.InlineControlPoint)); + + Point3d pos = G3DTools.getPoint(pcp.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition)); + dir.set(ControlPointTools.getPathLegDirection(pcp, Direction.NEXT)); + double length = pcp.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength); + Vector3d d = new Vector3d(dir); + d.scale(length * 0.5); + p1.set(pos); + p2.set(pos); + p1.add(d); + p2.sub(d); + } + + /** + * Return positions (world) of an InlineComponents ends + * @param pcp + * @param p1 + * @param p2 + */ + public static void getInlineControlPointEnds(IEntity pcp, Point3d center, Point3d p1, Point3d p2, Vector3d dir) { + assert (pcp.isInstanceOf(ProcessResource.plant3Dresource.InlineControlPoint)); + + Point3d pos = G3DTools.getPoint(pcp.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition)); + center.set(pos); + dir.set(ControlPointTools.getPathLegDirection(pcp, Direction.NEXT)); + double length = pcp.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength); + Vector3d d = new Vector3d(dir); + d.scale(length * 0.5); + p1.set(pos); + p2.set(pos); + p1.add(d); + p2.sub(d); + } + + public static double getInlineLength(IEntity pcp) { + double l2 = 0.0; + if (pcp.isInstanceOf(ProcessResource.plant3Dresource.TurnControlPoint)) { + l2 += pcp.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength); + } else if (pcp.isInstanceOf(ProcessResource.plant3Dresource.InlineControlPoint)) { + l2 += pcp.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength) * 0.5; + } + return l2; + } + + /** + * Returns position (world) of a single port + * @param pcp + * @param type + * @return + */ + public static Point3d getRealPosition(IEntity pcp, PositionType type) { + PipeControlPoint p= new PipeControlPoint(pcp); + Point3d pos = G3DTools.getPoint(p.getWorldPosition()); + switch (type) { + case NEXT: { + Vector3d dir = ControlPointTools.getPathLegDirection(pcp,Direction.NEXT); + double length = getInlineLength(pcp); + dir.normalize(); + dir.scale(length); + pos.add(dir); + break; + } + case PREVIOUS: { + Vector3d dir = ControlPointTools.getPathLegDirection(pcp,Direction.PREVIOUS); + double length = getInlineLength(pcp); + dir.normalize(); + dir.scale(length); + pos.add(dir); + break; + } + case PORT: + // IEntity portDir = pcp.getSingleRelatedObject(ProcessResource.plant3Dresource.HasDirection); + // TODO : how we calculated needed space for a port; does it has an offset from control point's position or not? + break; + case SPLIT: + // do nothing + break; + + } + return pos; + } + + public static void getInlineMovement(PipeControlPoint pcp, Point3d start, Point3d end) { + // FIXME : check type of neighbor components and allow movement on top of variable length components, + // ffind proper range for movement (pcp's position is not) + PipeControlPoint prev = pcp.getPrevious().getPrevious(); + PipeControlPoint next = pcp.getNext().getNext(); + start.set(G3DTools.getPoint(prev.getWorldPosition())); + end.set(G3DTools.getPoint(next.getWorldPosition())); + } + + public static AxisAngle4d getControlPointLocalRotation(IEntity pcp, double angle) { + Quat4d q1 = getControlPointLocalOrientationQuat(pcp, angle); + AxisAngle4d aa= new AxisAngle4d(); + aa.set(q1); + return aa; + } + + public static AxisAngle4d getControlPointWorldRotation(IEntity pcp, double angle) { + Quat4d q1 = getControlPointWorldOrientationQuat(pcp, angle); + AxisAngle4d aa= new AxisAngle4d(); + aa.set(q1); + return aa; + } + + + public static Quat4d getControlPointLocalOrientationQuat(IEntity pcp, double angle) { + return getControlPointLocalOrientationQuat(pcp, angle, false); + } + + public static Quat4d getControlPointWorldOrientationQuat(IEntity pcp, double angle) { + return getControlPointWorldOrientationQuat(pcp, angle, false); + } + + public static Quat4d getControlPointLocalOrientationQuat(IEntity cp, double angle, boolean offset) { + PipeControlPoint pcp = new PipeControlPoint(cp); + PipeControlPoint next; + // if pcp is size change control point with offset, next control point is not in line with previous and pcp control point (it's offsetted) + // else it's more numerically stable to use next control point + if (offset) + next = pcp; + else + next = pcp.getNext(); + + PipeControlPoint prev = pcp.getPrevious(); + assert (next != null || prev != null); + if (prev == null) + prev = pcp; + else if (next == null) + next = pcp; + // TODO : check correct type + if (pcp.isInstanceOf(ProcessResource.plant3Dresource.PathLegEndControlPoint) && pcp.getPrevious() == null) { + PipeControlPoint temp = next; + next = prev; + prev = temp; + } + Vector3d current = new Vector3d(G3DTools.getPoint(next.getLocalPosition())); + current.sub(G3DTools.getPoint(prev.getLocalPosition())); + current.normalize(); + return getControlPointOrientationQuat(current, angle); + } + + public static Quat4d getControlPointWorldOrientationQuat(IEntity cp, double angle, boolean offset) { + PipeControlPoint pcp = new PipeControlPoint(cp); + PipeControlPoint next; + // if pcp is size change control point with offset, next control point is not in line with previous and pcp control point (it's offsetted) + // else it's more numerically stable to use next control point + if (offset) + next = pcp; + else + next = pcp.getNext(); + + PipeControlPoint prev = pcp.getPrevious(); + assert (next != null || prev != null); + if (prev == null) + prev = pcp; + else if (next == null) + next = pcp; + // TODO : check correct type + if (pcp.isInstanceOf(ProcessResource.plant3Dresource.PathLegEndControlPoint) && pcp.getPrevious() == null) { + PipeControlPoint temp = next; + next = prev; + prev = temp; + } + Vector3d current = new Vector3d(G3DTools.getPoint(next.getWorldPosition())); + current.sub(G3DTools.getPoint(prev.getWorldPosition())); + current.normalize(); + return getControlPointOrientationQuat(current, angle); + } + + public static Quat4d getControlPointOrientationQuat(Vector3d dir, double angle) { + + + final Vector3d front = new Vector3d(1.0,0.0,0.0); + + Quat4d q1 = new Quat4d(); + + Vector3d up = new Vector3d(0.0, 1.0, 0.0); + double a = up.angle(dir); + if (a < 0.1 || (Math.PI - a) < 0.1) { + up.set(1.0, 0.0, 0.0); + } + + Vector3d right = new Vector3d(); + + right.cross(dir, up); + up.cross(right, dir); + right.normalize(); + up.normalize(); + + Matrix3d m = new Matrix3d(); + m.m00 = dir.x; + m.m10 = dir.y; + m.m20 = dir.z; + m.m01 = up.x; + m.m11 = up.y; + m.m21 = up.z; + m.m02 = right.x; + m.m12 = right.y; + m.m22 = right.z; + + //q1.set(m); MathTools contains more stable conversion + MathTools.getQuat(m, q1); + + if (DEBUG) System.out.println("PipingTools.getPipeComponentOrientationQuat() " + dir+ " " + up + " " + right); + + Quat4d q2 = new Quat4d(); + q2.set(new AxisAngle4d(front, angle)); + q1.mul(q2); + return q1; + } + + public static PipeControlPoint findPreviousEnd(PipeControlPoint tcp) { + // TODO : optimize (we do not need the list here) + ArrayList t = new ArrayList(); + return findPreviousEnd(tcp, t); + } + + public static PipeControlPoint findNextEnd(PipeControlPoint tcp) { + // TODO : optimize (we do not need the list here) + ArrayList t = new ArrayList(); + return findNextEnd(tcp, t); + } + + /** + * Returns pipe leg's end using "nextControlPoint" relation and collects control point in the given list. + * @param tcp + * @param nextList + * @return + */ + public static PipeControlPoint findNextEnd(PipeControlPoint tcp, ArrayList nextList) { + if (DEBUG) System.out.print("PipingTools.findNextEnd " + tcp.getResource()); + while (true) { + PipeControlPoint pcp = null; + PipeControlPoint p = null; + if (nextList.size() == 0) + p = tcp; + + else + p = nextList.get(nextList.size() - 1); + + pcp = p.getNext(); + if (pcp == null) { + pcp = p; + if (nextList.size() > 0) + nextList.remove(nextList.size() - 1); + if (DEBUG) System.out.println(" " + pcp.getResource() + " not full"); + return pcp; + //break; + } + if (pcp.isInstanceOf(ProcessResource.plant3Dresource.PathLegEndControlPoint)) { + if (DEBUG) System.out.println(" " + pcp.getResource()); + return pcp; + } else { + nextList.add(pcp); + if (DEBUG) System.out.print(" " + pcp.getResource()); + } + } + } + + + + /** + * Returns pipe leg's end using "previousControlPoint" relation and collects control point in the given list. + * @param tcp + * @param prevList + * @return + */ + public static PipeControlPoint findPreviousEnd(PipeControlPoint tcp, ArrayList prevList) { + if (DEBUG) System.out.print("PipingTools.findPreviousEnd " + tcp.getResource()); + while (true) { + PipeControlPoint pcp = null; + PipeControlPoint p = null; + if (prevList.size() == 0) + p = tcp; + + else + p = prevList.get(prevList.size() - 1); + + pcp = p.getPrevious(); + if (pcp == null) { + pcp = p; + if (prevList.size() > 0) + prevList.remove(prevList.size() - 1); + if (DEBUG) System.out.println(" " + pcp.getResource() + " not full"); + return pcp; + } + if (pcp.isInstanceOf(ProcessResource.plant3Dresource.PathLegEndControlPoint)) { + if (DEBUG) System.out.println(" " + pcp.getResource()); + return pcp; + } else { + prevList.add(pcp); + if (DEBUG) System.out.print(" " + pcp.getResource()); + } + } + } + + public static PipeRun getPipeRun(PipeControlPoint pcp) { + return pcp.getControlPointOfPipeRun(); + } + + @Deprecated + public static Vector3d getSizeChangeOffsetVector(PipeControlPoint sccp) { + Quat4d q = getControlPointWorldOrientationQuat(sccp, sccp.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasRotationAngle),true); + return getSizeChangeOffsetVector(sccp,q); + } + + public static Vector3d getSizeChangeOffsetVector(PipeControlPoint sccp, Vector3d dir) { + Quat4d q = getControlPointOrientationQuat(dir, sccp.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasRotationAngle)); + return getSizeChangeOffsetVector(sccp,q); + } + + public static Vector3d getSizeChangeOffsetVector(PipeControlPoint sccp, Quat4d q) { + Vector3d v = new Vector3d(0.0,0.0,sccp.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasOffset)); + Vector3d offset = new Vector3d(); + MathTools.rotate(q, v, offset); + return offset; + } + + public static Vector3d getDirectedControlPointDirection(IEntity dcp) { + assert(dcp.isInstanceOf(ProcessResource.plant3Dresource.DirectedControlPoint)); + AxisAngle4d worldR = G3DTools.getOrientation(dcp.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldOrientation)); + Quat4d q = new Quat4d(); + q.set(worldR); + Vector3d dir = new Vector3d(); + MathTools.rotate(q, new Vector3d(1.0, 0.0, 0.0), dir); + dir.normalize(); + return dir; + } + + public static Vector3d getNozzleDirection(IEntity rotation) { + AxisAngle4d worldR = G3DTools.getOrientation(rotation); + Quat4d q = new Quat4d(); + q.set(worldR); + Vector3d dir = new Vector3d(); + MathTools.rotate(q, new Vector3d(1.0, 0.0, 0.0), dir); + return dir; + } + + public static Vector3d getNozzleDirection(PipeControlPoint dcp) { + return getNozzleDirection(dcp.getWorldOrientation()); + } + + public static void removeControlPoint(PipeControlPoint removed) { + if (DEBUG) System.out.println("PipingTools.removeControlPoint() controlpoint " + removed.getResource());//FIXME : offset + size change control points ! + + // this code is not valid anymore. + + // different removing cases: + // + // 1. Point is SizeChangeControlPoint (this is currently ok) + // * remove offset point and component + // * do NOT link components together + // + // 2. Point is VariableLength + // * check if its a branch (TODO : ontology support?) + // * if so, also branch point in the other piperun may have to be removed + // (we cannot move other components next to branch) + // * if not, components next to removed one are moved next to each other + // 3. Other + // * check if there is VariableLength on both sides, + // * if so, those must be unified to a single Variable Length component. + // * if not, components must be moved next to each other + // + // a) If removed Control Point is next to Nozzle and after the point is removed nozzle is not connected to anything + // * nozzle's link to piperun's specs must be removed + // + + + if (removed.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)|| + removed.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)) { + // sccp & ocp connect two pipeRuns to each other; when thoes are remove, pipeRuns are not connected to each other anymore. + removeDualPoint(removed); + return; + } else { + PipeControlPoint prev = removed.getPrevious(); + PipeControlPoint next = removed.getNext(); + PipeRun pipeRun = getPipeRun(removed); + if (pipeRun == null) + return; + if (next == null && prev == null) { + if (removed.isInstanceOf(ProcessResource.plant3Dresource.NozzleControlPoint)) { + // Nozzle's control point does not need to be removed, only unlinked + // TODO : what about component ports? + PipingTools2.unlinkNozzleAndPiperun(removed.getSingleRelatedObject(ProcessResource.plant3Dresource.ControlPointOf), ControlPointTools.getPipeRun(removed)); + return; + } + } else { + + if (next != null && prev != null) { + boolean link = true; + if (next.isInstanceOf(ProcessResource.plant3Dresource.BranchEndControlPoint)){ + link = false; + next.removeRelatedStatements(ProcessResource.plant3Dresource.HasPrevious); + removed.removeRelatedStatements(ProcessResource.plant3Dresource.HasNext); + removeControlPoint(next); + } + if (prev.isInstanceOf(ProcessResource.plant3Dresource.BranchEndControlPoint)) { + link = false; + prev.removeRelatedStatements(ProcessResource.plant3Dresource.HasNext); + removed.removeRelatedStatements(ProcessResource.plant3Dresource.HasPrevious); + removeControlPoint(prev); + } + if (link && prev.isInstanceOf(ProcessResource.plant3Dresource.DirectedControlPoint)&& + next.isInstanceOf(ProcessResource.plant3Dresource.DirectedControlPoint)) { + link = false; + } + if (next.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)) { + PipeControlPoint sccp = next; + PipeControlPoint ocp = sccp.getSubPoint().iterator().next(); + if (ocp == null) { + ErrorLogger.defaultLogError("Removing PipeControlPoint " + removed.getResource()+ " structure damaged, no offset control point",null); + return; + } + if (link) { + sccp.setPrevious(prev); + ocp.setPrevious(prev); + } else { + sccp.removeRelatedStatements(ProcessResource.plant3Dresource.HasPrevious); + ocp.removeRelatedStatements(ProcessResource.plant3Dresource.HasPrevious); + + } + removed.removeRelatedStatements(ProcessResource.plant3Dresource.HasNext); + } else if (next.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)) { + ErrorLogger.defaultLogError("Removing PipeControlPoint " + removed.getResource()+ " structure damaged, next control point is offset control point",null); + return; + } else if (next.getPrevious().getResource().equals(removed.getResource())) { + if (link) { + next.setPrevious(prev); + } else { + next.removeRelatedStatements(ProcessResource.plant3Dresource.HasPrevious); + } + removed.removeRelatedStatements(ProcessResource.plant3Dresource.HasNext); + } else { + ErrorLogger.defaultLogError("Removing PipeControlPoint "+ removed.getResource()+ " structure damaged", null); + return; + } + if (prev.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)) { + ErrorLogger.defaultLogError("Removing PipeControlPoint " + removed.getResource() + " structure damaged, previous control point is size change control point", null); + return; + } else if (prev.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)) { + PipeControlPoint ocp = prev; + PipeControlPoint sccp = ocp.getSubPointOf(); + if (sccp == null) { + ErrorLogger.defaultLogError("Removing PipeControlPoint " + removed.getResource() + " structure damaged, no size change control point",null); + return; + } + if (link) { + ocp.setNext(next); + sccp.setNext(next); + } else { + ocp.removeRelatedStatements(ProcessResource.plant3Dresource.HasNext); + sccp.removeRelatedStatements(ProcessResource.plant3Dresource.HasNext); + } + removed.removeRelatedStatements(ProcessResource.plant3Dresource.HasPrevious); + } else if (prev.getNext().getResource().equals(removed.getResource())) { + if (link) + prev.setNext(next); + else + prev.removeRelatedStatements(ProcessResource.plant3Dresource.HasNext); + removed.removeRelatedStatements(ProcessResource.plant3Dresource.HasPrevious); + } else { + ErrorLogger.defaultLogError("Removing PipeControlPoint " + removed.getResource() + " structure damaged", null); + return; + } + if (link) { + if (next.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthControlPoint) && + prev.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthControlPoint)) { + // we have to join them into single variable length component. + removeControlPoint(prev); + } + } + + + } else if (next != null) { + if (next.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)) { + PipeControlPoint sccp = next; + PipeControlPoint ocp = sccp.getSubPoint().iterator().next(); + if (ocp == null) { + ErrorLogger.defaultLogError("Removing PipeControlPoint "+ removed.getResource()+ " structure damaged, no offset control point",null); + return; + } + next.removeRelatedStatements(ProcessResource.plant3Dresource.HasPrevious); + ocp.removeRelatedStatements(ProcessResource.plant3Dresource.HasPrevious); + } else if (next.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)) { + ErrorLogger.defaultLogError("Removing PipeControlPoint " + removed.getResource() + " structure damaged, next control point is offset control point", null); + return; + } else if (next.getPrevious().getResource().equals(removed.getResource())) { + next.removeRelatedStatements(ProcessResource.plant3Dresource.HasPrevious); + } else { + ErrorLogger.defaultLogError("Removing PipeControlPoint " + removed.getResource() + " structure damaged", null); + return; + } + removed.removeRelatedStatements(ProcessResource.plant3Dresource.HasNext); + } else { //(prev != null) + if (prev.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)) { + ErrorLogger.defaultLogError("Removing PipeControlPoint " + removed.getResource() + " structure damaged, previous control point is size change control point", null); + return; + } else if (prev.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)) { + PipeControlPoint ocp = prev; + PipeControlPoint sccp = ocp.getSubPointOf(); + if (sccp == null) { + ErrorLogger.defaultLogError("Removing PipeControlPoint " + removed.getResource() + " structure damaged, no size change control point", null); + return; + } + prev.removeRelatedStatements(ProcessResource.plant3Dresource.HasNext); + sccp.removeRelatedStatements(ProcessResource.plant3Dresource.HasNext); + } else if (prev.getNext().getResource().equals(removed.getResource())) { + prev.removeRelatedStatements(ProcessResource.plant3Dresource.HasNext); + } else { + ErrorLogger.defaultLogError("Removing PipeControlPoint "+ removed.getResource() + " structure damaged", null); + return; + } + removed.removeRelatedStatements(ProcessResource.plant3Dresource.HasPrevious); + } + + } + if (removed.getSubPoint().size() > 0 ) { + removeSubPoints(removed); + } else if (removed.getSubPointOf() != null) { + removeParentPoint(removed); + } + + removeComponents(removed); + + pipeRun.removeStatement(ProcessResource.plant3Dresource.HasControlPoints, removed); + if (pipeRun.getChild().size() == 0) { + PipingTools2.removePipeRun(pipeRun); + } + else if (pipeRun.getControlPoints().size() == 1) { + removeControlPoint(pipeRun.getControlPoints().iterator().next()); + } + } + + } + + private static void removeDualPoint(PipeControlPoint removed) { + PipeControlPoint prev = removed.getPrevious(); + PipeControlPoint next = removed.getNext(); + if (prev != null) { + prev.removeRelatedStatements(ProcessResource.plant3Dresource.HasNext); + } + if (next != null) + next.removeRelatedStatements(ProcessResource.plant3Dresource.HasPrevious); + PipeControlPoint ocp; + PipeControlPoint sccp; + // get sccp / ocp pair + if (removed.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)) { + sccp = removed; + ocp = sccp.getSubPoint().iterator().next(); + + } else { + ocp = removed; + sccp = ocp.getSubPointOf(); + } + PipeRun p1 = getPipeRun(ocp); + PipeRun p2 = getPipeRun(sccp); + + // removes all components connected to control point + + removeComponents(ocp); + + removeComponents(sccp); + + // remove control points from pipeRuns + p1.removeStatement(ProcessResource.plant3Dresource.HasControlPoints, ocp); + p2.removeStatement(ProcessResource.plant3Dresource.HasControlPoints, sccp); + + // remove links to other control points + ocp.removeRelatedStatements(ProcessResource.plant3Dresource.HasNext); + sccp.removeRelatedStatements(ProcessResource.plant3Dresource.HasNext); + ocp.removeRelatedStatements(ProcessResource.plant3Dresource.HasPrevious); + sccp.removeRelatedStatements(ProcessResource.plant3Dresource.HasPrevious); + + // if pipeRuns contains no other components(control points), they can be removed too. + if (p1.getControlPoints().size() == 0) { + PipingTools2.removePipeRun(p1); + } else if (p1.getControlPoints().size() == 1) { + removeControlPoint(p1.getControlPoints().iterator().next()); + } + if (p2.getControlPoints().size() == 0) { + PipingTools2.removePipeRun(p2); + } else if (p2.getControlPoints().size() == 1) { + removeControlPoint(p2.getControlPoints().iterator().next()); + } + } + + /** + * Removes sub points of a point + * @param removed + * @throws TransactionException + */ + private static void removeSubPoints(PipeControlPoint removed) { + // if control point is branch control point, all branch of points must be removed too + Collection points = removed.getSubPoint(); + + for (PipeControlPoint p : points) { + removed.removeStatement(ProcessResource.plant3Dresource.HasSubPoint, p); + removeControlPoint(p); + } + } + + /** + * Removed point is a subpoint of something, + * @param removed + */ + private static void removeParentPoint(PipeControlPoint removed) { + throw new RuntimeException("Subpoints cannot be removed"); + + // if control point is branch it has to be removed from branch control point +// BranchEndControlPoint ecp = BranchEndControlPointFactory.create(removed); +// BranchControlPoint bcp = null; +// if (ecp.getBranchOfPointSet().size() == 1) { +// bcp = ecp.getBranchOfPointSet().iterator().next(); +// } +// if (bcp != null) { +// bcp.getBranchPointSet().remove(ecp); +// if (bcp.getBranchPointSet().size() == 0) { +// // branch control point is not used and can be removed +// removeControlPoint(bcp); +// } +// } + } + + + private static void removeComponents(PipeControlPoint pcp) { + IEntity component = pcp.getControlPointOf(); + if (component != null) { + PipeRun p1 = getPipeRun(pcp); + p1.removeStatement(ProcessResource.g3dResource.HasChild, component); + component.removeRelatedStatements(ProcessResource.plant3Dresource.HasControlPoint); + } + } + + private static void setStatement(IEntity subject, Resource relation, IEntity object) { + subject.removeRelatedStatements(relation); + subject.addStatement(relation, object); + } + + + public static void setWorldPosition(IEntity pcp, Tuple3d position) { + IEntity wp = pcp.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition); + G3DTools.setTuple3(wp, position); + tt.propagateWorldTransformChange(tt.getParent(pcp), pcp); + + } + + public static void setLocalPosition(IEntity pcp, Tuple3d position) { + G3DTools.setTuple3(pcp.getSingleRelatedObject(ProcessResource.g3dResource.HasLocalPosition), position); + tt.propagateLocalTransformChange(tt.getParent(pcp), pcp); + } + + public static void setWorldOrientation(IEntity node, AxisAngle4d orientation) { + G3DTools.setOrientation(node.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldOrientation), orientation); + tt.propagateWorldTransformChange(tt.getParent(node), node); + + } + + public static void setLocalOrientation(IEntity node, AxisAngle4d orientation) { + G3DTools.setOrientation(node.getSingleRelatedObject(ProcessResource.g3dResource.HasLocalOrientation), orientation); + tt.propagateLocalTransformChange(tt.getParent(node), node); + } + + private static boolean updatePosition(IEntity pcp) { + return tt.transformationUpdate(pcp); + + + // TODO : orientation is also needed, current code handles only position + // TODO : reuse the code in G3DTools! + /* + IEntity worldPosition = pcp.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition); + IEntity localPosition = pcp.getSingleRelatedObject(ProcessResource.g3dResource.HasLocalPosition); + + + Tuple3d worldP = G3DTools.getPoint(worldPosition); + Tuple3d localP = G3DTools.getPoint(localPosition); + + if (localP == null || worldP == null) + return false; + if (!isValid(worldP) && !isValid(localP)) + return false; + + Tuple3d cachedWorldP = (Tuple3d) getProperty(worldPosition.getResource()); + Tuple3d cachedLocalP = (Tuple3d) getProperty(localPosition.getResource()); + + if (DEBUG) System.out.println("PipeControlPoint changed " + worldP + " " + cachedWorldP + " " + localP + " " + cachedLocalP); + boolean changed = false; + + IEntity parent = pcp.getSingleRelatedObject(ProcessResource.plant3Dresource.ControlPointOf); + + if (parent == null) { + if (DEBUG) System.out.println("PipeControlPoint changed, no parent node"); + return false; + } + + if (cachedLocalP == null) { + storeProperty(localPosition.getResource(), localP); + Tuple3d p = G3DTools.getWorldFromLocal(parent, new Point3d(localP)); + storeProperty(worldPosition.getResource(), p); + G3DTools.setTuple3(worldPosition, p); + if (DEBUG) System.out.println("PipeControlPoint changed local " + worldP + " " + p); + changed = true; + } else { + if (TransformationTools.changed(cachedLocalP, localP)) { + storeProperty(localPosition.getResource(), localP); + Tuple3d p = G3DTools.getWorldFromLocal(parent, new Point3d(localP)); + storeProperty(worldPosition.getResource(), p); + G3DTools.setTuple3(worldPosition, p); + if (DEBUG) System.out.println("PipeControlPoint changed local " + worldP + " " + localP); + changed = true; + } + if (cachedWorldP == null) { + storeProperty(worldPosition.getResource(), worldP); + Tuple3d p = G3DTools.getLocalFromWorld(parent, new Point3d(worldP)); + G3DTools.setTuple3(localPosition, p); + storeProperty(localPosition.getResource(), p); + if (DEBUG) System.out.println("PipeControlPoint changed world " + worldP + " " + p); + changed = true; + } else { + if (TransformationTools.changed(cachedWorldP, worldP)) { + storeProperty(worldPosition.getResource(), worldP); + Tuple3d p = G3DTools.getLocalFromWorld(parent, new Point3d(worldP)); + G3DTools.setTuple3(localPosition, p); + storeProperty(localPosition.getResource(), p); + if (DEBUG) System.out.println("PipeControlPoint changed world " + worldP + " " + p); + changed = true; + } + } + } + return changed; + //*/ + } + + static boolean isControlPointChanged(PipeControlPoint node) { + long id = node.getResource().getResourceId(); + boolean changed = updatePosition(node); + //if (!changed) { + if (node.isInstanceOf(ProcessResource.plant3Dresource.PathLegEndControlPoint)) { + if (node.isInstanceOf(ProcessResource.plant3Dresource.TurnControlPoint)) { + Pair connected = (Pair)getProperty(node.getResource().getResourceId()); + PipeControlPoint next = node.getNext(); + PipeControlPoint prev = node.getPrevious(); + if ((next != null && prev != null) && ( + connected == null || + (connected.first == null && prev != null) || + (connected.second == null && next != null) || + !connected.first.equals(prev.getResource().getResourceId()) || + !connected.second.equals(next.getResource().getResourceId()))) { + storeProperty(id, new Pair(prev.getResource().getResourceId(),next.getResource().getResourceId())); + changed = true; + } + if (node.isInstanceOf(ProcessResource.plant3Dresource.VariableAngleTurnControlPoint)) { + double r = node.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasTurnRadius); + Double d = (Double)getProperty(id + ":turnradius"); + if (d == null || TransformationTools.changed(r, d)) { + storeProperty(id + ":turnradius", r); + changed = true; + } + } + } + else if (node.isInstanceOf(ProcessResource.plant3Dresource.DirectedControlPoint)) { + Vector3d dir = ControlPointTools.getDirectedControlPointDirection(node); + Vector3d old = (Vector3d)getProperty(id + ":direction"); + if (old == null || TransformationTools.changed(dir, old)) { + storeProperty(id + ":direction", dir); + changed = true; + } + } + } else { // InlineControlPoint + if (node.isInstanceOf(ProcessResource.plant3Dresource.FixedLengthControlPoint)) { + double length = node.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength); + Double d = (Double)getProperty(id + ":length"); + if (d == null) + changed = true; + else + changed = changed || TransformationTools.changed(length, d); + + if (changed) { + storeProperty(id + ":length", length); + return true; + } + } else + if (node.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)) { + + double angle = node.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasRotationAngle); + Double d = (Double)getProperty(id + ":rotationangle"); + if (d == null) + changed = true; + else + changed = changed || TransformationTools.changed(angle, d); + if (changed) { + storeProperty(id + ":rotationangle", angle); + return true; + } + Collection subpoints = node.getSubPoint(); + if (subpoints.size() != 1) + throw new RuntimeException("Current implementation assumes that size change components are dual conmnected"); + PipeControlPoint ocp = subpoints.iterator().next(); + if (node.isInstanceOf(ProcessResource.plant3Dresource.OffsettingPoint)) { + double offset = ocp.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasOffset); + d = (Double)getProperty(id +":offset"); + if (d == null) + changed = true; + else + changed = TransformationTools.changed(offset, d); + if (changed) { + storeProperty(id+":offset", offset); + return true; + } + } +// } else if (node instanceof OffsetControlPoint) { +// OffsetControlPoint ocp = (OffsetControlPoint)node; +// //ocp. +// } else if (node instanceof BranchControlPoint) { +// BranchControlPoint bcp = (BranchControlPoint)node; +// int size = bcp.getBranchPointSet().size(); +// Integer i = (Integer)getProperty(bcp.getResource().getId()); +// if (i == null) +// changed =true; +// else +// changed = changed || i != size; +// if (changed) { +// storeProperty(bcp.getResource().getId(), size); +// return true; +// } + } + } + //} + + return changed; + } + + private static boolean isValid(Tuple3d v) { + if (Double.isInfinite(v.x) || + Double.isNaN(v.x) || + Double.isInfinite(v.y) || + Double.isNaN(v.y) || + Double.isInfinite(v.z) || + Double.isNaN(v.z)) + return false; + return true; + } + + private static HashMap properties = new HashMap(); + + public static Object getProperty(Object key) { + return properties.get(key); + } + + public static void storeProperty(Object key, Object value) { + properties.put(key, value); + } + + /** + * Loads positions of controlpoint to rule cache + * + * TODO : this caches only transformation information : other info must be cached too + * + * @param root resource of the modeled plant + */ + public static void reloadCache(Graph graph, Resource root) { + + Stack stack = new Stack(); + stack.add(EntityFactory.create(graph,root)); + while (!stack.isEmpty()) { + IEntity current = stack.pop(); + IEntity pcp = current.getAtMostOneRelatedObject(ProcessResource.plant3Dresource.HasControlPoint); + if (pcp == null) { + stack.addAll(current.getRelatedObjects(ProcessResource.g3dResource.HasChild)); + } else { + if (DEBUG) System.out.println("Cached pcp " + pcp.getResource()); + IEntity localPos = pcp.getSingleRelatedObject(ProcessResource.g3dResource.HasLocalPosition); + IEntity worldPos = pcp.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition); + + tt.storeProperty(localPos.getResource(),G3DTools.getPoint(localPos)); + tt.storeProperty(worldPos.getResource(),G3DTools.getPoint(worldPos)); + + IEntity localOr = pcp.getAtMostOneRelatedObject(ProcessResource.g3dResource.HasLocalOrientation); + IEntity worldOr = pcp.getAtMostOneRelatedObject(ProcessResource.g3dResource.HasWorldOrientation); + + if (worldOr != null) { + tt.storeProperty(localOr.getResource(),G3DTools.getOrientation(localOr)); + tt.storeProperty(worldOr.getResource(),G3DTools.getOrientation(worldOr)); + } + + stack.addAll(pcp.getRelatedObjects(ProcessResource.plant3Dresource.HasSubPoint)); + } + } + + } +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/PathUtils.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/PathUtils.java new file mode 100644 index 00000000..9ddaf040 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/PathUtils.java @@ -0,0 +1,145 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.common; + +import java.util.ArrayList; +import java.util.Collection; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.layer0.utils.viewpoints.TraversalPath; +import org.simantics.proconf.browsing.GraphExplorer; +import org.simantics.utils.datastructures.Pair; + + + + + +public class PathUtils { + + public static void createPath(java.util.List samplePath, TraversalPath path, Resource sampleInstance, Resource sampleSource, GraphExplorer oe) { +// while (tNode != null) { +// long[] path = tNode.getPath(); +// for (int i = 0; i < path.length; i++) { +// samplePath.add(i, path[i]); +// } +// samplePath.add(path.length,tNode.getCoreId()); +// tNode = oe.getTreeParent(tNode); +// } + while (path != null) { + Resource predicate = path.getPredicate(); + Resource obj = path.getResource(); + if (predicate != null) { + samplePath.add(0,predicate); + path = path.getTail(); + } else { + // there is no relation and so this has to be root + path = null; + } + samplePath.add(1,obj); + + } + + if (!sampleInstance.equals(samplePath.get(0)) || !sampleSource.equals(samplePath.get(samplePath.size()-1))) { + String s = ""; + for (int i = 0; i < samplePath.size(); i++) { + s += samplePath.get(i) + " "; + } + throw new RuntimeException("Path from " + sampleInstance + " to " + + sampleSource + " is broken: " + s); + } + +// String s = ""; +// for (int i = 0; i < samplePath.size(); i++) { +// s += samplePath.get(i) + " "; +// } +// System.out.println("Path from " + sampleInstance + " to " + sampleSource + " is: " + s); + samplePath.remove(0); + } + + + + /** + * Finds similar path in cloned resource + * TODO : this isn't correct way to do this; + * Rigth way would be finding mapping between two clones + * and then find the similar resource + * (Viewpoint used to create clone is required) + * + * @param path + * @param begin + * @return + */ + public static IEntity findSimilar(java.util.List path, IEntity begin) { + if (path.size() == 0) + return begin; + if (path.size() == 1) + return null; + Graph g = begin.getGraph(); + java.util.List tPath = new ArrayList(); + tPath.addAll(path); + + Resource p = tPath.get(0); // predicate (relation) + Resource o = tPath.get(1); // object + tPath.remove(0); + tPath.remove(0); + + IEntity predicate = EntityFactory.create(g, p); + + + Collection possibleObjects = begin.getRelatedObjects(predicate); + if (possibleObjects.size() == 0) + return null; + if (possibleObjects.size() == 1) + return findSimilar(tPath, possibleObjects.iterator().next()); + else { + IEntity object = EntityFactory.create(g, o); + Collection objectTypes = object.getTypes(); + java.util.List> list = new ArrayList>(); + for (IEntity possible : possibleObjects) { + boolean matchTypes = true; + for (IEntity type : objectTypes) { + if(!possible.isInstanceOf(type)) { + matchTypes = false; + break; + } + + } + if (matchTypes) { + IEntity r = findSimilar(tPath,possible); + if (r != null) + list.add(new Pair(possible,r)); + //return r; + } + } + if (list.size() == 0) + return null; + if (list.size() == 1) + return list.get(0).second; + else { + // uses names of objects to detect similarities + String name = object.getName(); + if (name != null) { + for (Pair possible : list) { + String otherName = possible.first.getName(); + //System.out.println(name + " : " + otherName); + if (otherName != null && name.compareTo(otherName) == 0) + return possible.second; + } + } + } + } + + return null; + } +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/PipeComponentProvider.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/PipeComponentProvider.java new file mode 100644 index 00000000..a59e0f81 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/PipeComponentProvider.java @@ -0,0 +1,531 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.common; + +import java.nio.FloatBuffer; +import java.nio.IntBuffer; + +import javax.vecmath.AxisAngle4d; +import javax.vecmath.Point3d; +import javax.vecmath.Quat4d; +import javax.vecmath.Vector3d; + +import org.simantics.layer0.utils.IEntity; +import org.simantics.proconf.g3d.base.G3DTools; +import org.simantics.proconf.g3d.base.GeometryProvider; +import org.simantics.proconf.g3d.base.MathTools; +import org.simantics.utils.ErrorLogger; + +import com.jme.scene.Geometry; +import com.jme.scene.Line; +import com.jme.scene.TriMesh; +import com.jme.util.geom.BufferUtils; + +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.stubs.PipeControlPoint; +import fi.vtt.simantics.processeditor.stubs.PipelineComponent; +import fi.vtt.simantics.processeditor.stubs.TurnControlPoint; + + +/** + * Geometry provider for pipe components. + * TODO : split into three providers (one for each type) to faster access (ShapeNodes can cache geometry provider) + * + * @author Marko Luukkainen + * + */ +public class PipeComponentProvider implements GeometryProvider { + + + //private static double ELBOW_RING_ANGLE = 12.0/ Math.PI; + //private static int RING_SEGMENTS = 8; + + private static double ELBOW_RING_ANGLE = 24.0/ Math.PI; + private static int RING_SEGMENTS = 16; + + public boolean canHandle(IEntity instance) { + if (instance.isInstanceOf(ProcessResource.plant3Dresource.Elbow)) + return true; + if (instance.isInstanceOf(ProcessResource.plant3Dresource.Straight)) + return true; + if (instance.isInstanceOf(ProcessResource.plant3Dresource.Reducer)) + return true; + return false; + } + + + public Geometry[] getGeometryFromResource(IEntity instance, boolean transform) { + if (instance.isInstanceOf(ProcessResource.plant3Dresource.Elbow)) { + Geometry[] g = new Geometry[]{new TriMesh(),new Line()}; + if( getElbowGeometry(instance,g)) { + return g; + } + return null; + } + + if (instance.isInstanceOf(ProcessResource.plant3Dresource.Straight)) { + Geometry[] g = new Geometry[]{new TriMesh(),new Line()}; + if( getStraightGeometry(instance,g)) { + return g; + } + return null; + } + if (instance.isInstanceOf(ProcessResource.plant3Dresource.Reducer)) { + Geometry[] g = new Geometry[]{new TriMesh(),new Line()}; + if (getReducerGeometry(instance,g)) { + return g; + } + return null; + } + return null; + } + + public boolean reconstructGeometry(IEntity instance, boolean transform, Geometry[] geometry) { + if (instance.isInstanceOf(ProcessResource.plant3Dresource.Elbow)) + return getElbowGeometry(instance,geometry); + if (instance.isInstanceOf(ProcessResource.plant3Dresource.Straight)) + return getStraightGeometry(instance,geometry); + if (instance.isInstanceOf(ProcessResource.plant3Dresource.Reducer)) + return getReducerGeometry(instance,geometry); + + return false; + } + + public boolean getElbowGeometry(IEntity instance, Geometry[] geometry) { + PipelineComponent elbow = new PipelineComponent(instance); + PipeControlPoint pcp = elbow.getControlPoint(); + if (pcp == null) { + ErrorLogger.defaultLogError("Elbow " + instance + " has no control point", null); + return false; + } + TurnControlPoint tcp = new TurnControlPoint(pcp); + // double turnAngleValue = tcp.getTurnAngleValue(); + + double pipeRadius = elbow.getPipeDiameter()[0]*0.5; + double elbowRadius = elbow.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasTurnRadius); + double R = tcp.getLength()[0]; //getComponentOffset(); + double turnAngle = tcp.getTurnAngle()[0]; + + PipeControlPoint startControlPoint = tcp.getPrevious(); + PipeControlPoint endControlPoint = tcp.getNext(); + if (startControlPoint == null || endControlPoint == null) + return false; + + //Point3d start = getLocalPoint(pipeline,startControlPoint); + //Point3d middle = getLocalPoint(pipeline,tcp); + //Point3d end = getLocalPoint(pipeline,endControlPoint); + + Point3d start = G3DTools.getPoint(startControlPoint.getWorldPosition()); + Point3d middle = G3DTools.getPoint(tcp.getWorldPosition()); + Point3d end = G3DTools.getPoint(endControlPoint.getWorldPosition()); + + Vector3d dir1 = new Vector3d(middle); + dir1.sub(start); + Vector3d dir2 = new Vector3d(end); + dir2.sub(middle); + + Vector3d n = new Vector3d(dir1); + n.normalize(); + Vector3d offset = new Vector3d(n); + + offset.scale(R); + Vector3d startPipe = new Vector3d(middle); + startPipe.sub(offset); + // normal of the plane + Vector3d normal = new Vector3d(); + normal.cross(dir1, dir2); + Vector3d elbowCenter = new Vector3d(); + elbowCenter.cross(normal, dir1); + elbowCenter.normalize(); + elbowCenter.scale(elbowRadius); + elbowCenter.add(startPipe); + + elbowCenter.sub(middle); + + // creates sweep shape by rotating a circle + // several values must be checked if they are infinite (OCC crashes if they are) + if (turnAngle > 0.001 && normal.lengthSquared() > 0.0 && !(Double.isInfinite(turnAngle)) && isValid(n) && isValid(startPipe)) { +// System.out.println(startPipe + " " + middle + " " + n + " " + elbowCenter + " " + normal + " " + turnAngle); +// gp_Circ circ = new gp_Circ(new double[] { startPipe.x - middle.x, startPipe.y - middle.y, +// startPipe.z - middle.z, n.x, n.y, n.z }, pipeRadius); +// TopoDS_Edge ed = (TopoDS_Edge) new BRepBuilderAPI_MakeEdge(circ).shape(); +// TopoDS_Wire w = (TopoDS_Wire) new BRepBuilderAPI_MakeWire(ed).shape(); +// TopoDS_Face F = (TopoDS_Face) new BRepBuilderAPI_MakeFace(w).shape(); +// TopoDS_Shape S4 = new BRepPrimAPI_MakeRevol(F, new double[] { elbowCenter.x, elbowCenter.y, elbowCenter.z, +// normal.x, normal.y, normal.z }, turnAngle).shape(); +// +// try { +// return OccTriangulator.getGeometry(S4, true); +// +// } catch (Exception e) { +// e.printStackTrace(); +// return null; +// } + elbow(pipeRadius,elbowRadius,n,normal,turnAngle,elbowCenter,geometry); + return true; + } + return false; + + } + + public void elbow(double radius, double turnRadius, Vector3d sn, Vector3d rn, double angle, Vector3d p, Geometry[] geometry) { + Vector3d t = new Vector3d(); + t.cross(sn,rn); + t.normalize(); + t.scale(turnRadius); + Vector3d vs[][] = calcCirc(RING_SEGMENTS, 0.0, 0.0, 0.0, sn.x, sn.y, sn.z, radius); + int rings = (int)Math.ceil(angle * ELBOW_RING_ANGLE * Math.sqrt(turnRadius)); + if (rings < 2) + rings = 2; + FloatBuffer v = BufferUtils.createFloatBuffer(vs[0].length * rings * 3); + FloatBuffer n = BufferUtils.createFloatBuffer(vs[0].length * rings * 3); + Quat4d q = new Quat4d(); + AxisAngle4d aa = new AxisAngle4d(); + Vector3d pos = new Vector3d(); + Vector3d t2 = new Vector3d(); + + aa.x = rn.x; + aa.y = rn.y; + aa.z = rn.z; + for (int i = 0; i < rings; i++) { + double a = (double)i/(double)(rings-1) * angle; + aa.angle = a; + q.set(aa); + MathTools.rotate(q, t, pos); + for (int j = 0; j < vs[0].length; j++) { + MathTools.rotate(q, vs[0][j], t2); + t2.add(pos); + t2.add(p); + v.put((float)t2.x); + v.put((float)t2.y); + v.put((float)t2.z); + MathTools.rotate(q, vs[1][j], t2); + n.put((float)t2.x); + n.put((float)t2.y); + n.put((float)t2.z); + } + } + int indexCount = indexCount(RING_SEGMENTS, rings); + int edgeIndexCount = edgeIndexCount(RING_SEGMENTS, rings); + IntBuffer i = BufferUtils.createIntBuffer(indexCount); + IntBuffer ei = BufferUtils.createIntBuffer(edgeIndexCount); + createIndices(i, RING_SEGMENTS, rings); + createEdgeIndices(ei, RING_SEGMENTS, rings); + TriMesh m = (TriMesh)geometry[0];//new TriMesh(); + Line l = (Line)geometry[1];//new Line(); + m.reconstruct(v, n, null, null,i); + l.reconstruct(v, null, null, null,ei); + //return new Geometry[]{m,l}; + } + + public boolean getStraightGeometry(IEntity instance, Geometry[] geometry) { + //Straight straight = new Straight(instance); + PipelineComponent straight = new PipelineComponent(instance); + double pipeRadius = straight.getPipeDiameter()[0] * 0.5; + //PipeRun pipeline = (PipeRun)PipingTools2.getPipeRun(straight.toPipelineComponent());//parent.getGraphicsNode(); + //double pipeRadius = pipeline.getPipeDiameter()[0] * 0.5; + + +// PipeControlPoint startControlPoint = (PipeControlPoint)StubFactory.getStubForResource(this.getClass().getClassLoader(),straight.getHasPreviousControlPoint().getResource()); +// PipeControlPoint endControlPoint = (PipeControlPoint)StubFactory.getStubForResource(this.getClass().getClassLoader(),straight.getHasNextControlPoint().getResource()); + + // start and end position of the pipe + // positions may be linked to other components, like nozzles + // and then their coordinates are in component's local coordinates + // which must be transformed into pipeline's local coordinates + + Point3d startPipe = new Point3d();//getLocalPoint(pipeline,startControlPoint); + + + Point3d endPipe = new Point3d(); //getLocalPoint(pipeline, endControlPoint); + + + + + PipingTools2.getInlineComponentEnds(straight, startPipe, endPipe); + boolean b = createStraightGeometry(startPipe, endPipe, pipeRadius, geometry); + if (!b) + ErrorLogger.getDefault().logWarning("Straight pipe " + instance + " is too short", null); + return b; + } + + public static boolean createStraightGeometry(Point3d startPipe, Point3d endPipe, double pipeRadius, Geometry geometry[]) { + Vector3d dir = new Vector3d(endPipe); + dir.sub(startPipe); + + double h = dir.length(); +// several values must be checked if they are infinite (OCC crashes if they are) + if (h > 0.001 && h < 10000.0 && pipeRadius > 0.01) { + + dir.normalize(); + + Vector3d[][] v1 = calcCirc(RING_SEGMENTS, startPipe.x, startPipe.y, startPipe.z, dir.x, dir.y, dir.z, pipeRadius); + Vector3d[][] v2 = calcCirc(RING_SEGMENTS, endPipe.x, endPipe.y, endPipe.z, dir.x, dir.y, dir.z, pipeRadius); + TriMesh m = (TriMesh)geometry[0];//new TriMesh(); + Line l = null; + if (geometry.length>1) + l = (Line)geometry[1];//new Line(); + FloatBuffer v = BufferUtils.createFloatBuffer(v1[0].length * 2 * 3); + FloatBuffer n = BufferUtils.createFloatBuffer(v1[0].length * 2 * 3 ); + for (int i = 0; i < v1[0].length; i++) { + v.put((float)v1[0][i].x); + v.put((float)v1[0][i].y); + v.put((float)v1[0][i].z); + n.put((float)v1[1][i].x); + n.put((float)v1[1][i].y); + n.put((float)v1[1][i].z); + } + for (int i = 0; i < v2[0].length; i++) { + v.put((float)v2[0][i].x); + v.put((float)v2[0][i].y); + v.put((float)v2[0][i].z); + n.put((float)v2[1][i].x); + n.put((float)v2[1][i].y); + n.put((float)v2[1][i].z); + } + + IntBuffer i = BufferUtils.createIntBuffer(indexCount(RING_SEGMENTS, 2)); + createIndices(i, RING_SEGMENTS, 2); + m.reconstruct(v, n, null, null,i); + if (l != null) { + IntBuffer ei = BufferUtils.createIntBuffer(edgeIndexCount(RING_SEGMENTS, 2)); + createEdgeIndices(ei, RING_SEGMENTS, 2); + l.reconstruct(v, null, null, null,ei); + } + return true; + } + return false; + } + + public static void createStraightEdges(Line l, Point3d startPipe, Point3d endPipe, double pipeRadius) { + Vector3d dir = new Vector3d(endPipe); + dir.sub(startPipe); + dir.normalize(); + Vector3d[][] v1 = calcCirc(8, startPipe.x, startPipe.y, startPipe.z, dir.x, dir.y, dir.z, pipeRadius); + Vector3d[][] v2 = calcCirc(8, endPipe.x, endPipe.y, endPipe.z, dir.x, dir.y, dir.z, pipeRadius); + FloatBuffer v = BufferUtils.createFloatBuffer(v1[0].length * 2 * 3); + FloatBuffer n = BufferUtils.createFloatBuffer(v1[0].length * 2 * 3 ); + for (int i = 0; i < v1[0].length; i++) { + v.put((float)v1[0][i].x); + v.put((float)v1[0][i].y); + v.put((float)v1[0][i].z); + n.put((float)v1[1][i].x); + n.put((float)v1[1][i].y); + n.put((float)v1[1][i].z); + } + for (int i = 0; i < v2[0].length; i++) { + v.put((float)v2[0][i].x); + v.put((float)v2[0][i].y); + v.put((float)v2[0][i].z); + n.put((float)v2[1][i].x); + n.put((float)v2[1][i].y); + n.put((float)v2[1][i].z); + } + + + IntBuffer ei = BufferUtils.createIntBuffer(edgeIndexCount(8, 2)); + createEdgeIndices(ei, 8, 2); + l.reconstruct(v, null, null, null,ei); + } + + public boolean getReducerGeometry(IEntity instance,Geometry[] geometry) { + //Reducer reducer = new Reducer(instance); + PipelineComponent reducer = new PipelineComponent(instance); + PipeControlPoint pcp = reducer.getControlPoint(); + PipeControlPoint pcp2 = pcp.getSubPoint().iterator().next(); + //PipeControlPoint pcp = reducer.getHasControlPoint(); + //PipeControlPoint prev = pcp.getPreviousPoint(); + //assert (prev != null); + //Point3d prevPoint = GraphicsNodeTools.getPoint(prev.getLocalPosition()); + //Point3d point = GraphicsNodeTools.getPoint(pcp.getLocalPosition()); + //Vector3d dir = new Vector3d(point); + //dir.sub(prevPoint); + //dir.normalize(); + double h = reducer.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength); + double r1 = pcp.getPipeDiameter()[0] * 0.5;//reducer.getBottomRadius(); + double r2 = pcp2.getPipeDiameter()[0] * 0.5;//reducer.getTopRadiusValue(); + + if (h > 0.001 && r1 > 0.001 && r2 > 0.001 ) { +// TopoDS_Shape S4 = getShape(h,r1,r2, instance.isInstanceOf(GlobalIdMap.get(PSK3DModelingOntologyMapping.ECCENTRIC_REDUCER))); +// +// +// try { +// return OccTriangulator.getGeometry(S4, true); +// +// } catch (Exception e) { +// e.printStackTrace(); +// return null; +// } + Vector3d[][] v1 = calcCirc(RING_SEGMENTS, -h * 0.5, 0.0, 0.0, 1.0, 0.0, 0.0, r1); + Vector3d[][] v2 = calcCirc(RING_SEGMENTS, h * 0.5, 0.0, instance.isInstanceOf(ProcessResource.plant3Dresource.EccentricReducer) ? (r1 - r2) : 0.0, 1.0, 0.0, 0.0, r2); + TriMesh m = (TriMesh)geometry[0];//new TriMesh(); + Line l = (Line)geometry[1];//new Line(); + FloatBuffer v = BufferUtils.createFloatBuffer(v1[0].length * 2 * 3); + FloatBuffer n = BufferUtils.createFloatBuffer(v1[0].length * 2 * 3 ); + for (int i = 0; i < v1[0].length; i++) { + v.put((float)v1[0][i].x); + v.put((float)v1[0][i].y); + v.put((float)v1[0][i].z); + n.put((float)v1[1][i].x); + n.put((float)v1[1][i].y); + n.put((float)v1[1][i].z); + } + for (int i = 0; i < v2[0].length; i++) { + v.put((float)v2[0][i].x); + v.put((float)v2[0][i].y); + v.put((float)v2[0][i].z); + n.put((float)v2[1][i].x); + n.put((float)v2[1][i].y); + n.put((float)v2[1][i].z); + } + + IntBuffer i = BufferUtils.createIntBuffer(indexCount(RING_SEGMENTS, 2)); + IntBuffer ei = BufferUtils.createIntBuffer(edgeIndexCount(RING_SEGMENTS, 2)); + createIndices(i, RING_SEGMENTS, 2); + createEdgeIndices(ei, RING_SEGMENTS, 2); + m.reconstruct(v, n, null, null,i); + l.reconstruct(v, null, null, null,ei); + //return new Geometry[]{m,l}; + return true; + + } + return false; + + } + +// protected TopoDS_Shape getShape(double h, double r1, double r2, boolean eccentric) { +// TopoDS_Shape S4 = null; +// +// gp_Circ circ1 = new gp_Circ(new double[] { -h * 0.5, 0.0, 0.0, 1.0, 0.0, 0.0 }, r1); +// TopoDS_Edge ed1 = (TopoDS_Edge) new BRepBuilderAPI_MakeEdge(circ1) +// .shape(); +// TopoDS_Wire w1 = (TopoDS_Wire) new BRepBuilderAPI_MakeWire(ed1).shape(); +// gp_Circ circ2 = new gp_Circ(new double[] { h * 0.5, 0.0, eccentric ? r1 - r2 : 0.0, 1.0, 0.0, 0.0 }, r2); +// TopoDS_Edge ed2 = (TopoDS_Edge) new BRepBuilderAPI_MakeEdge(circ2) +// .shape(); +// TopoDS_Wire w2 = (TopoDS_Wire) new BRepBuilderAPI_MakeWire(ed2).shape(); +//// BRepOffsetAPI_ThruSections generatorb = new BRepOffsetAPI_ThruSections( +//// true, false); +// BRepOffsetAPI_ThruSections generatorb = new BRepOffsetAPI_ThruSections(true, true); +// generatorb.addWire(w1); +// generatorb.addWire(w2); +// generatorb.build(); +// S4 = generatorb.shape(); +// return S4; +// } + + private boolean isValid(Vector3d v) { + if (Double.isInfinite(v.x) || + Double.isNaN(v.x) || + Double.isInfinite(v.y) || + Double.isNaN(v.y) || + Double.isInfinite(v.z) || + Double.isNaN(v.z)) + return false; + return true; + } + + private static Vector3d[][] calcCirc(int segmentCount,double x, double y, double z, double dx, double dy, double dz, double r) { + Vector3d res[][] = new Vector3d[2][segmentCount + 1]; + Vector3d t = new Vector3d(); + if (Math.abs(dy) + Math.abs(dz) < 0.001) { + t.y = 1.0; + } else { + t.x = 1.0; + } + Vector3d d = new Vector3d(dx,dy,dz); + Vector3d a = new Vector3d(); + a.cross(t, d); + a.normalize(); + a.scale(r); + Quat4d q = new Quat4d(); + AxisAngle4d aa = new AxisAngle4d(); + aa.x = dx; + aa.y = dy; + aa.z = dz; + for (int i = 0; i <= segmentCount; i++) { + aa.angle = (double)i / (double) segmentCount * Math.PI * 2.0; + q.set(aa); + res[0][i] = new Vector3d(); + res[1][i] = new Vector3d(); + MathTools.rotate(q, a, res[0][i]); + res[1][i].normalize(res[0][i]); + //res[1][i].negate(); + res[0][i].x += x; + res[0][i].y += y; + res[0][i].z += z; + } + return res; + + } + + private static int indexCount(int segmentCount, int ringCount) { + return 6 * segmentCount * (ringCount - 1); + } + + private static void createIndices(IntBuffer buf, int segmentCount, int ringCount) { + int s = segmentCount + 1; + for (int ring = 0; ring < ringCount - 1; ring++) { + for (int segment = 0; segment < segmentCount; segment++) { + int index = ring * s + segment; + buf.put(index); + buf.put(index + 1); + buf.put(index + s); + buf.put(index + s + 1); + buf.put(index + s); + buf.put(index + 1); + } + } + } + + private static int edgeIndexCount(int segmentCount, int ringCount) { + if (ringCount > 1) { + return segmentCount * 4 + ringCount * 4 * (segmentCount / 4); + } else { + return ringCount * segmentCount * 2; + } + } + + private static void createEdgeIndices(IntBuffer buf, int segmentCount, int ringCount) { + int s = segmentCount + 1; + if (ringCount > 1) { + int ring = 0; + for (int segment = 0; segment < segmentCount; segment++) { + int index = ring * s + segment; + buf.put(index); + buf.put(index + 1); + } + ring = ringCount - 1; + for (int segment = 0; segment < segmentCount; segment++) { + int index = ring * s + segment; + buf.put(index); + buf.put(index + 1); + } + int space = segmentCount / 4; + for (ring = 0; ring < ringCount - 1; ring++) { + for (int segment = 0; segment < segmentCount; segment+=space) { + int index = ring * s + segment; + buf.put(index); + buf.put(index + s); + } + } + } else { + int ring = 0; + for (int segment = 0; segment < segmentCount; segment++) { + int index = ring * s + segment; + buf.put(index); + buf.put(index + 1); + } + } + buf.limit(buf.position()); + + } +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/PipingRules.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/PipingRules.java new file mode 100644 index 00000000..d7e1619e --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/PipingRules.java @@ -0,0 +1,1134 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.common; + +import java.util.ArrayList; +import java.util.Collection; + +import javax.vecmath.AxisAngle4d; +import javax.vecmath.Point3d; +import javax.vecmath.Vector3d; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.proconf.g3d.base.G3DTools; +import org.simantics.proconf.g3d.base.MathTools; +import org.simantics.utils.ErrorLogger; + +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.stubs.PipeControlPoint; +import fi.vtt.simantics.processeditor.stubs.PipeRun; +import fi.vtt.simantics.processeditor.stubs.PipelineComponent; + +/** + * Rules that update pipeline. + * TODO : optimize, remove stubs + * + * FIXME : transformations + * + * TODO : FixedAngleTurnComponents are handled like VariableAngleTurnComponents + * + * + * @author Marko Luukkainen + * + */ +public class PipingRules { + + private static final boolean DEBUG = false; + private static final boolean DUMMY = false; + + private static final double MIN_TURN_ANGLE = 0.01; + + private static final int REMOVE_NONE = 0; + private static final int REMOVE_START = 1; + private static final int REMOVE_END = 2; + private static final int REMOVE_BOTH = 3; + + private enum PathLegUpdateType {NONE,PREV,NEXT,PREV_S,NEXT_S}; + + /** + * Rule + * + * @param resources + * @param pp + * @throws TransactionException + */ + public static void pipeControlPointPositionUpdate(Graph g, Resource pp) { + + PipeControlPoint pcp = new PipeControlPoint(g,pp); + if (DEBUG) System.out.println("PipeControlPoint changed " + pp); + + boolean changed = ControlPointTools.isControlPointChanged(pcp); + + + if (changed) { + if (pcp.isInstanceOf(ProcessResource.plant3Dresource.PathLegEndControlPoint)) { + updatePathLegEndControlPoint(pcp); + } else { + updateInlineControlPoint(pcp); + } + } + + } + + + + public static class ExpandIterInfo { + // these two are turn control points + private PipeControlPoint start; + private PipeControlPoint end; + private int type; + + public ExpandIterInfo() { + + } + + public ExpandIterInfo(PipeControlPoint tcp, int type) { + if (type == REMOVE_START) + start = tcp; + else + end = tcp; + this.type = type; + } + + public ExpandIterInfo(PipeControlPoint start, PipeControlPoint end) { + this.start = start; + this.end = end; + this.type = REMOVE_BOTH; + } + + public PipeControlPoint getEnd() { + return end; + } + public void setEnd(PipeControlPoint end) { + this.end = end; + } + public PipeControlPoint getStart() { + return start; + } + public void setStart(PipeControlPoint start) { + this.start = start; + } + public int getType() { + return type; + } + public void setType(int type) { + this.type = type; + } + + + } + + private static void updatePathLegEndControlPoint(PipeControlPoint pcp) { + if (DEBUG) System.out.println("PipingTools.updateRunEndControlPoint() " + pcp.getResource()); + if (pcp.getNext() != null) { + updatePathLegNext(pcp,pcp,PathLegUpdateType.NEXT_S); + } + if (pcp.getPrevious() != null) { + updatePathLegPrev(pcp,pcp,PathLegUpdateType.PREV_S); + } + + } + + private static void updateInlineControlPoint(PipeControlPoint pcp) { + if (DEBUG) System.out.println("PipingTools.updateInlineControlPoint() " + pcp.getResource()); + PipeControlPoint start = ControlPointTools.findPreviousEnd(pcp); + updatePathLegNext(start,pcp,PathLegUpdateType.NONE); + } + + private static PipeControlPoint insertElbow(PipeControlPoint pcp1 , PipeControlPoint pcp2, Point3d pos) { + if (DEBUG) System.out.println("PipingRules.insertElbow() " + pcp1.getResource() + " " + pcp2.getResource()+ " " + pos); + PipelineComponent elbow = PipingTools2.instantiatePipelineComponent(pcp1.getGraph(), ControlPointTools.getPipeRun(pcp1).getResource(), ProcessResource.plant3Dresource.Elbow); + PipeControlPoint pcp = elbow.getControlPoint(); + + ControlPointTools.insertControlPoint(pcp, pcp1,pcp2); + + ControlPointTools.setWorldPosition(pcp, pos); + + return pcp; + } + + private static void updatePathLegNext(PipeControlPoint start, PipeControlPoint updated, PathLegUpdateType lengthChange){ + ArrayList list = new ArrayList(); + PipeControlPoint end = ControlPointTools.findNextEnd(start,list); + // this is for inline cp that is also path leg end + if (start.equals(updated)) + lengthChange = PathLegUpdateType.NEXT; + else if (end.equals(updated)) + lengthChange = PathLegUpdateType.PREV; + updatePathLegNext(start, list, end, updated, lengthChange); + } + + private static void updatePathLegNext(PipeControlPoint start, ArrayList list, PipeControlPoint end, PipeControlPoint updated, PathLegUpdateType lengthChange) { + updatePathLeg(start,list,end,false,0,new ArrayList(),updated, lengthChange); + } + + private static class UpdateStruct2 { + public PipeControlPoint start; + public Point3d startPoint; + public ArrayList list; + public PipeControlPoint end; + public Point3d endPoint; + public Vector3d dir; + public Vector3d offset; + public boolean hasOffsets; + public int iter; + public boolean reversed; + public ArrayList toRemove; + public PipeControlPoint updated; + public UpdateStruct2(PipeControlPoint start, Point3d startPoint, ArrayList list, PipeControlPoint end, Point3d endPoint, Vector3d dir, Vector3d offset, boolean hasOffsets, int iter, boolean reversed, ArrayList toRemove, PipeControlPoint updated) { + super(); + this.start = start; + this.startPoint = startPoint; + this.list = list; + this.end = end; + this.endPoint = endPoint; + this.dir = dir; + this.offset = offset; + this.hasOffsets = hasOffsets; + this.iter = iter; + this.reversed = reversed; + this.toRemove = toRemove; + this.updated = updated; + } + + public String toString() { + return start.getResource() + " " + end.getResource() + " " + dir + " " + hasOffsets + " " + offset + " " + iter + " " + toRemove.size(); + } + + } + + private static boolean calculateOffset(Point3d startPoint, Point3d endPoint, ArrayList list, Vector3d dir, Vector3d offset) { + boolean hasOffsets = false; + dir.set(startPoint); + dir.sub(endPoint); + dir.normalize(); + offset.set(0.0,0.0,0.0); + for (PipeControlPoint icp : list) { + if (icp.isInstanceOf(ProcessResource.plant3Dresource.OffsettingPoint)) { + hasOffsets = true; + offset.add(ControlPointTools.getSizeChangeOffsetVector(icp,dir)); + } + else if (icp.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)) + ErrorLogger.defaultLogError("Updating pipe run, found offset controlpoint " + icp.getResource(), new Exception("ASSERT!")); + } + return hasOffsets; + } + + /** + * @param start starting point of the pipe run + * @param list list of inline control points in the pipe run + * @param end ending point of the pipe run + * @param reversed boolean flag indicating wether start or end control point was modified (if true then end point was modified) + * @throws TransactionException + */ + private static void updatePathLeg(PipeControlPoint start, ArrayList list, PipeControlPoint end, boolean reversed, int iter, ArrayList toRemove, PipeControlPoint updated, PathLegUpdateType lengthChange) { + // FIXME: direction is calculated wrong way! + boolean hasOffsets = false; + Vector3d offset = new Vector3d(); + Point3d startPoint = G3DTools.getPoint(start.getWorldPosition()); + Point3d endPoint = G3DTools.getPoint(end.getWorldPosition()); + Vector3d dir = new Vector3d (); + hasOffsets = calculateOffset(startPoint, endPoint, list, dir, offset); + updatePathLeg(new UpdateStruct2(start, startPoint, list, end, endPoint, dir, offset, hasOffsets, iter, reversed, toRemove, updated), lengthChange); + + } + + private static void updatePathLeg(UpdateStruct2 u, PathLegUpdateType lengthChange){ + int directed = 0; + if (u.start.isInstanceOf(ProcessResource.plant3Dresource.DirectedControlPoint)) + directed ++; + if (u.end.isInstanceOf(ProcessResource.plant3Dresource.DirectedControlPoint)) + directed++; + switch (directed) { + case 0: + updateFreePathLeg(u,lengthChange); + break; + case 1: + updateDirectedPathLeg(u,lengthChange); + break; + case 2: + updateDualDirectedPathLeg(u,lengthChange); + break; + } + + } + + private static void updateFreePathLeg(UpdateStruct2 u, PathLegUpdateType lengthChange) { + if (DEBUG) System.out.println("PipingRules.updateFreePipeRun " + u + " " + lengthChange); + checkExpandPathLeg(u, lengthChange); + } + + private static void updateInlineControlPoints(UpdateStruct2 u, boolean checkSizes) { + if (DEBUG) System.out.println("PipingTools.updateInlineControlPoints() " + u); + + if (!u.hasOffsets) { + // FIXME : cache positions + if (!checkSizes) { + for (PipeControlPoint icp : u.list) { + updateInlineControlPoint(icp, u.startPoint, u.endPoint,u.dir); + } + return; + } + + ArrayList pathLegPoints = new ArrayList(); + pathLegPoints.add(u.start); + for (PipeControlPoint icp : u.list) { + //updateInlineControlPoint(icp, u.startPoint, u.endPoint,u.dir); + updateBranchControlPointBranches(icp); + pathLegPoints.add(icp); + } + pathLegPoints.add(u.end); + + // TODO : values can be cached in the loop + for (int i = 1; i < pathLegPoints.size(); i++) { + PipeControlPoint icp = pathLegPoints.get(i); + + PipeControlPoint prev; + Point3d prevPos; + prev = pathLegPoints.get(i-1); + prevPos = G3DTools.getPoint(prev.getWorldPosition()); + Point3d currentPos = G3DTools.getPoint(icp.getWorldPosition()); + + if (icp.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthControlPoint)) { + if (i != pathLegPoints.size() - 1) { + PipeControlPoint next; + Point3d nextPos; + next = pathLegPoints.get(i + 1); + nextPos = G3DTools.getPoint(next.getWorldPosition()); + Vector3d dir = new Vector3d(nextPos); + dir.sub(prevPos); + double l = dir.lengthSquared(); // distance between control points (square) + double l2prev = ControlPointTools.getInlineLength(prev); // distance taken by components + double l2next = ControlPointTools.getInlineLength(next); + double l2 = l2prev + l2next; + double l2s = MathTools.square(l2); + if (l2s < l) { // check if there is enough space for variable length component. + // components fit + dir.normalize(); + double length = Math.sqrt(l) - l2; // true length of the variable length component + dir.scale(length*0.5 + l2prev); // calculate center position of the component + dir.add(prevPos); + ControlPointTools.setWorldPosition(icp,dir); + icp.setRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength, length); + } else { + //components leave no space to the component and it must be removed + ControlPointTools.removeControlPoint(icp); + } + + } else { + // this is variable length component at the end of the piperun. + // the problem is that we want to keep unconnected end of the component in the same + // place, but center of the component must be moved. + double currentLength = icp.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength); + Vector3d dir = new Vector3d(); + dir.sub(currentPos,prevPos); + dir.normalize(); + Point3d endPos = new Point3d(dir); + endPos.scale(currentLength * 0.5); + endPos.add(currentPos); //this is the free end of the component + + double offset = ControlPointTools.getInlineLength(prev); + Point3d beginPos = new Point3d(dir); + beginPos.scale(offset); + beginPos.add(prevPos); //this is the connected end of the component + + double l = beginPos.distance(endPos); + + dir.scale(l*0.5); + beginPos.add(dir); //center position + + if (DEBUG) System.out.println("PipingRules.updateInlineControlPoints() setting variable length to " + l); + icp.setRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength, l); + + ControlPointTools.setWorldPosition(icp, beginPos); + } + i++; + + } else if (!prev.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthControlPoint)){ + // If this and previous control point are not variable length pcps, we'll have to check if there is no empty space between them. + // I there is, we'll have to create new variable length component between them. + Vector3d dir = new Vector3d(currentPos); + dir.sub(prevPos); + double l = dir.lengthSquared(); + double l2prev = ControlPointTools.getInlineLength(prev); + double l2next = ControlPointTools.getInlineLength(icp); + double l2 = l2prev + l2next; + double l2s = l2 * l2; + if (l > l2s) { + PipelineComponent component = PipingTools2.instantiatePipelineComponent(prev.getGraph(), ControlPointTools.getPipeRun(prev).getResource(), ProcessResource.plant3Dresource.Straight); + PipeControlPoint scp = component.getControlPoint(); + ControlPointTools.insertControlPoint(scp, prev, icp); + + dir.normalize(); + double length = Math.sqrt(l) - l2; // true length of the variable length component + dir.scale(length*0.5 + l2prev); // calculate center position of the component + dir.add(prevPos); + ControlPointTools.setWorldPosition(scp, dir); + scp.setRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength, length); + } + } + } + } else { + u.endPoint.sub(u.offset); + // FIXME : straights + for (PipeControlPoint icp : u.list) { + updateInlineControlPoint(icp, u.startPoint, u.endPoint,u.dir); + updateBranchControlPointBranches(icp); + if (icp.isInstanceOf(ProcessResource.plant3Dresource.OffsettingPoint)) { + // TODO : offset vector is already calculated and should be + // cached + u.offset = ControlPointTools.getSizeChangeOffsetVector(icp, u.dir); + updateOffsetPoint( icp, u.offset); + u.startPoint.add(u.offset); + u.endPoint.add(u.offset); + } + } + } + } + + + + private static void ppNoOffset(UpdateStruct2 u) { + if (DEBUG)System.out.println("PipingRules.ppNoOffset() " + u); + Vector3d offset = new Vector3d(); + if (u.hasOffsets) { + u.dir.normalize(); + for (PipeControlPoint icp : u.list) { + if (icp.isInstanceOf(ProcessResource.plant3Dresource.OffsettingPoint)) { + offset.add(ControlPointTools.getSizeChangeOffsetVector(icp,u.dir)); + } + else if (icp.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)) + ErrorLogger.defaultLogError("Updating pipe run, found offset controlpoint " + icp.getResource(), new Exception("ASSERT!")); + } + } + u.offset = offset; + checkExpandPathLeg(u,PathLegUpdateType.NONE); + } + + private static void ppNoDir(PipeControlPoint start, Point3d startPoint,ArrayList list, PipeControlPoint end,Point3d endPoint, boolean hasOffsets,int iter,boolean reversed, ArrayList toRemove, PipeControlPoint updated) { + if (DEBUG)System.out.println("PipingRules.ppNoDir() " + start.getResource() + " " + end.getResource() + " " + iter + " " + toRemove.size()); + // FIXME : extra loop (dir should be calculated here) + Vector3d dir = new Vector3d(); + Vector3d offset = new Vector3d(); + hasOffsets = calculateOffset(startPoint, endPoint, list, dir, offset); + ppNoOffset(new UpdateStruct2(start, startPoint, list, end, endPoint, dir, null, hasOffsets, iter, reversed, toRemove,updated)); + } + + private static void checkExpandPathLeg(UpdateStruct2 u, PathLegUpdateType lengthChange) { + if (DEBUG)System.out.println("PipingRules.checkExpandPathLeg() " + u + " " + lengthChange); + if (lengthChange != PathLegUpdateType.NONE) { + // FIXME : turns cannot be checked before inline cps are updated, since their position affects calculation of turns + processPathLeg(u,false,false); + int type = checkTurns(u,lengthChange); + if (type == REMOVE_NONE) { + processPathLeg(u,false,true); + } else { + expandPathLeg(u, type); + } + } else { + processPathLeg(u,false,true); + } + } + + private static void updateDirectedPathLeg(UpdateStruct2 u, PathLegUpdateType lengthChange) { + if (DEBUG)System.out.println("PipingRules.updateDirectedPipeRun() " + u + " " + lengthChange); + PipeControlPoint dcp; + PipeControlPoint other; + boolean canMoveOther = false; + boolean dcpStart = false; + Point3d position; + if (u.start.isInstanceOf(ProcessResource.plant3Dresource.DirectedControlPoint)) { + dcp = u.start; + other = u.end; + position = u.startPoint; + dcpStart = true; + if (!u.reversed) + canMoveOther = true; + } else { + dcp = u.end; + other = u.start; + position = u.endPoint; + if (u.reversed) + canMoveOther = true; + } + + Vector3d directedDirection = ControlPointTools.getDirectedControlPointDirection(dcp); + Point3d directedEndPoint = new Point3d(u.endPoint); + if (u.hasOffsets) + directedEndPoint.add(u.offset); + + double mu[] = new double[2]; + + Vector3d closest; + Vector3d t = new Vector3d(); + + if (dcpStart) { + closest = MathTools.closestPointOnStraight(directedEndPoint, u.startPoint, directedDirection, mu); + t.sub(closest, directedEndPoint); + } else { + closest = MathTools.closestPointOnStraight(u.startPoint, directedEndPoint, directedDirection, mu); + t.sub(closest, u.startPoint); + } + + + double distance = t.lengthSquared(); + boolean aligned = (distance < 0.001); + if (aligned) { + checkExpandPathLeg(u,lengthChange); + } else { + if (u.iter > 0) { + backIter(u); + } else { + PipeControlPoint nextToMoved; + + if (u.list.size() > 0) + if (dcpStart) + nextToMoved = u.list.get(0); + else + nextToMoved = u.list.get(u.list.size() - 1); + else if (dcpStart) + nextToMoved = u.end; + else + nextToMoved = u.start; + if (other.isInstanceOf(ProcessResource.plant3Dresource.VariableAngleTurnControlPoint)) { + + // TODO calculate needed space from next run end. + if (mu[0] < 1.0) { + if (dcpStart) { + closest.set(u.startPoint); + } else { + closest.set(u.endPoint); + } + closest.add(directedDirection); + } + + if (canMoveOther) { + if (DEBUG)System.out.println("PipingRules.updateDirectedPipeRun() moved end " + other.getResource() + " to " + closest); + ControlPointTools.setWorldPosition(other, closest); + if (dcpStart) { + ppNoOffset(new UpdateStruct2(u.start, u.startPoint, u.list, u.end, new Point3d(closest), directedDirection,null, u.hasOffsets, u.iter, u.reversed, u.toRemove,u.updated)); + if (u.end.getNext() != null) + updatePathLegNext(u.end,u.updated,PathLegUpdateType.NEXT); + } else { + ppNoOffset(new UpdateStruct2(u.start, new Point3d(closest), u.list, u.end, u.endPoint, directedDirection,null, u.hasOffsets, u.iter, u.reversed, u.toRemove,u.updated)); + if (u.start.getPrevious() != null) + updatePathLegPrev(u.start,u.updated,PathLegUpdateType.PREV); + } + } else { + // TODO : calculate needed space from next run end. + insertElbowUpdate(u, dcp, nextToMoved, dcpStart, position, directedDirection); + } + } else if (other.isInstanceOf(ProcessResource.plant3Dresource.UndirectedControlPoint) && + other.getSubPointOf() != null) { + // FIXME : this code was for updating branches + Vector3d bintersect = new Vector3d(); + PipeControlPoint bcp = other.getSubPointOf(); + if (bcp != null && canMoveOther) { + Point3d bstart = new Point3d(); + Point3d bend = new Point3d(); + Vector3d bdir = new Vector3d(); + ControlPointTools.getInlineControlPointEnds(bcp, bstart, bend, bdir); + Vector3d nintersect = new Vector3d(); + + MathTools.intersectStraightStraight(position, directedDirection, bstart, + bdir, nintersect, bintersect, mu); + Vector3d dist = new Vector3d(nintersect); + dist.sub(bintersect); + canMoveOther = mu[1] > 0.0 && mu[1] < 1.0 && dist.lengthSquared() < 0.01; + } else { + // TODO : endControlPoints are undirected: calculcate correct position for it + throw new UnsupportedOperationException("not implemented"); + } + if (canMoveOther) { + if (DEBUG) System.out.println("PipingRules.updateDirectedPipeRun() moved end " + other.getResource() + " to " + bintersect); + // is required branch position is in possible range + ControlPointTools.setWorldPosition(bcp, bintersect); + if (dcpStart) { + checkExpandPathLeg(new UpdateStruct2(u.start, u.startPoint, u.list, u.end, new Point3d(bintersect),directedDirection, u.offset, u.hasOffsets, u.iter, u.reversed, u.toRemove,u.updated),lengthChange); + } else { + checkExpandPathLeg(new UpdateStruct2(u.start, new Point3d(bintersect), u.list, u.end, u.endPoint,directedDirection, u.offset, u.hasOffsets, u.iter, u.reversed, u.toRemove,u.updated),lengthChange); + } + } else { + // branch cannot be moved into right position, new turn + // / elbow must be inserted + insertElbowUpdate(u , dcp, nextToMoved, dcpStart, position, directedDirection); + } + + } else { // assume that control point cannot be moved, but can be rotated + insertElbowUpdate(u, dcp, nextToMoved, dcpStart, position, directedDirection); + } + } + } + } + + + + private static void updateDualDirectedPathLeg(UpdateStruct2 u, PathLegUpdateType lengthChange) { + if (DEBUG) System.out.println("PipingRules.updateDualDirectedPipeRun() " + u + " " + lengthChange); + + PipeControlPoint dcp1 = u.start; + PipeControlPoint dcp2 = u.end; + Point3d position1 = u.startPoint; + Point3d position2 = u.endPoint; + Point3d position1offset = new Point3d(position1); + position1offset.sub(u.offset); + Point3d position2offset = new Point3d(position2); + position2offset.add(u.offset); + Vector3d dir1 = ControlPointTools.getDirectedControlPointDirection(dcp1); + Vector3d dir2 = ControlPointTools.getDirectedControlPointDirection(dcp2); + Vector3d p1 = MathTools.closestPointOnStraight(position1offset, position2, dir2); + Vector3d p2 = MathTools.closestPointOnStraight(position2offset, position1, dir1); + double d1 = position1.distance(new Point3d(p1)); + double d2 = position2.distance(new Point3d(p2)); + + boolean aligned = (d1 < 0.01 && d2 < 0.01); + if (aligned) { + processPathLeg(u); + } else { + if (u.iter > 0) { + backIter(u); + } else { + PipeControlPoint dcp; + PipeControlPoint next; + if (!u.reversed) { + dcp = dcp1; + if (u.list.size() > 0) + next = u.list.get(0); + else + next = dcp2; + } else { + dcp = dcp2; + if (u.list.size() > 0) + next = u.list.get(u.list.size() - 1); + else + next = dcp1; + } + + PipeRun pipeline = ControlPointTools.getPipeRun(dcp1); + PipelineComponent elbow1 = PipingTools2.instantiatePipelineComponent(u.start.getGraph(), pipeline.getResource(), ProcessResource.plant3Dresource.Elbow); + PipelineComponent elbow2 = PipingTools2.instantiatePipelineComponent(u.start.getGraph(), pipeline.getResource(), ProcessResource.plant3Dresource.Elbow); + + PipeControlPoint tcp1 = elbow1.getControlPoint(); + PipeControlPoint tcp2 = elbow2.getControlPoint(); + + // Straight s1 = getStraight(dcp, next); + ControlPointTools.insertControlPoint(tcp1, dcp, next); + // s1 = getStraight(tcp1, next); + ControlPointTools.insertControlPoint(tcp2, tcp1, next); + p1 = G3DTools.getVector(dcp.getLocalPosition()); + if (!u.reversed) + p1.add(dir1); + else + p1.add(dir2); + + if (!u.reversed) + p2 = MathTools.closestPointOnStraight(new Point3d(p1), position2, dir2); + else + p2 = MathTools.closestPointOnStraight(new Point3d(p1), position1, dir1); + + ControlPointTools.setWorldPosition(tcp1, p1); + ControlPointTools.setWorldPosition(tcp2, p2); + + if (DEBUG) System.out.println("PipingRules.updateDualDirectedPipeRun() created two turns " + tcp1.getResource() + " " + tcp2.getResource()); + + if (!u.reversed) { + Vector3d dd = new Vector3d(p2); + dd.sub(p1); + dir2.negate(); + processPathLeg(new UpdateStruct2(u.start, u.startPoint,new ArrayList(), tcp1, new Point3d(p1),dir1, new Vector3d(), false, 0, false,new ArrayList(), u.updated)); + processPathLeg(new UpdateStruct2(tcp1,new Point3d(p1), new ArrayList(),tcp2, new Point3d(p2), dd,new Vector3d(), false, 0, false,new ArrayList(), u.updated)); + // offset is recalculated + processPathLegNoOffset(new UpdateStruct2(tcp2, new Point3d(p2), u.list,u.end, u.endPoint, dir2, null, u.hasOffsets,u.iter, u.reversed, u.toRemove, u.updated)); + } else { + Vector3d dd = new Vector3d(p1); + dd.sub(p2); + dir2.negate(); + processPathLeg(new UpdateStruct2(tcp1,new Point3d(p1), new ArrayList(),u.end, u.endPoint, dir2, new Vector3d(), false, 0,false, new ArrayList(), u.updated)); + processPathLeg(new UpdateStruct2(tcp2,new Point3d(p2), new ArrayList(),tcp1, new Point3d(p1), dd,new Vector3d(), false, 0, false,new ArrayList(), u.updated)); + // offset is recalculated + processPathLegNoOffset(new UpdateStruct2(u.start, u.startPoint,u.list, tcp2, new Point3d(p2),dir1, null, u.hasOffsets, u.iter, u.reversed,u.toRemove, u.updated)); + } + } + } + } + + private static void insertElbowUpdate(UpdateStruct2 u, PipeControlPoint dcp, PipeControlPoint next, boolean dcpStart, Point3d position, Vector3d directedDirection) { + + Vector3d closest = new Vector3d(position); + closest.add(directedDirection); + PipeControlPoint tcp = insertElbow(dcp, next, new Point3d(closest)); + + if (DEBUG) System.out.println("PipingRules.updateDirectedPipeRun() inserted " + tcp.getResource()); + + if (dcpStart) { + // update pipe run from new turn to other end + ppNoDir(tcp, new Point3d(closest), u.list, u.end, u.endPoint, u.hasOffsets, u.iter, u.reversed, u.toRemove, u.updated); + // update pipe run from directed to new turn + processPathLeg(new UpdateStruct2(u.start, u.startPoint, new ArrayList(), tcp, new Point3d(closest), directedDirection, new Vector3d(), false, 0, false, new ArrayList(),u.updated)); + } else { + // update pipe run from other end to new turn + ppNoDir(u.start, u.startPoint, u.list, tcp, new Point3d(closest), u.hasOffsets, u.iter, u.reversed, u.toRemove,u.updated); + // update pipe run from new turn to directed + processPathLeg(new UpdateStruct2(tcp, new Point3d(closest), new ArrayList(), u.end, u.endPoint, directedDirection, new Vector3d(), false, 0, false, new ArrayList(),u.updated)); + } + } + + /** + * Checks if turns can be removed (turn angle near zero) + */ + private static int checkTurns(UpdateStruct2 u, PathLegUpdateType lengthChange) { + if (DEBUG) + System.out.println("PipingRules.checkTurns() " + u.start.getResource() + + " " + u.end.getResource()); + boolean startRemoved = false; + boolean endRemoved = false; + if (u.start.isInstanceOf(ProcessResource.plant3Dresource.VariableAngleTurnControlPoint)) { + // this won't work properly if inline control points are not updated + PipeControlPoint startPrev = u.start.getPrevious(); + if (startPrev != null) { + double a; + if (!u.hasOffsets) { + a = updateTurnControlPointTurn( u.start, startPrev, u.end); + } else { + Point3d ep = new Point3d(u.endPoint); + ep.add(u.offset); + a = updateTurnControlPointTurn( u.start,u.startPoint, G3DTools.getPoint(startPrev.getLocalPosition()), ep); + + } + if (a < MIN_TURN_ANGLE) + startRemoved = true; + else if (lengthChange == PathLegUpdateType.PREV || lengthChange == PathLegUpdateType.PREV_S){ + PathLegUpdateType type; + if (lengthChange == PathLegUpdateType.PREV_S) + type = PathLegUpdateType.PREV; + else + type = PathLegUpdateType.NONE; + updatePathLegPrev(u.start, u.start, type); + } + } + } + if (u.end.isInstanceOf(ProcessResource.plant3Dresource.VariableAngleTurnControlPoint)) { + + PipeControlPoint endNext = u.end.getNext(); + if (endNext != null) { + double a; + if (!u.hasOffsets) { + a = updateTurnControlPointTurn(u.end,u.start, endNext); + } else { + Point3d sp = new Point3d(u.startPoint); + sp.sub(u.offset); + a = updateTurnControlPointTurn(u.end, u.endPoint, sp, G3DTools.getPoint(endNext.getLocalPosition())); + } + if (a < MIN_TURN_ANGLE) + endRemoved = true; + else if (lengthChange == PathLegUpdateType.NEXT || lengthChange == PathLegUpdateType.NEXT_S){ + PathLegUpdateType type; + if (lengthChange == PathLegUpdateType.NEXT_S) + type = PathLegUpdateType.NEXT; + else + type = PathLegUpdateType.NONE; + updatePathLegNext(u.end, u.end,type); + } + } + } + if (DEBUG) + System.out.println("PipingRules.checkTurns() res " + startRemoved + " " + endRemoved); + if (!startRemoved && !endRemoved) + return REMOVE_NONE; + if (startRemoved && endRemoved) + return REMOVE_BOTH; + if (startRemoved) + return REMOVE_START; + return REMOVE_END; + } + + /** + * Expands piperun search over turns that are going to be removed + * + */ + private static void expandPathLeg(UpdateStruct2 u, int type) { + if (DEBUG) System.out.println("PipingRules.expandPipeline " + u.start.getResource() + " " + u.end.getResource()); + ArrayList newList = new ArrayList (); + switch (type) { + case REMOVE_NONE : + throw new RuntimeException("Error in piping rules"); + case REMOVE_START : + u.toRemove.add(new ExpandIterInfo(u.start,REMOVE_START)); + u.start = ControlPointTools.findPreviousEnd(u.start); + u.startPoint = G3DTools.getPoint(u.start.getLocalPosition()); + ControlPointTools.findNextEnd(u.start,newList); + newList.addAll(u.list); + u.list = newList; + break; + case REMOVE_END : + u.toRemove.add(new ExpandIterInfo(u.end,REMOVE_END)); + u.end = ControlPointTools.findNextEnd(u.end,newList); + u.endPoint = G3DTools.getPoint(u.end.getLocalPosition()); + u.list.addAll(newList); + break; + case REMOVE_BOTH : + u.toRemove.add(new ExpandIterInfo(u.start,u.end)); + u.start = ControlPointTools.findPreviousEnd(u.start); + u.startPoint = G3DTools.getPoint(u.start.getLocalPosition()); + ControlPointTools.findNextEnd(u.start,newList); + newList.addAll(u.list); + u.list = newList; + newList = new ArrayList (); + u.end = ControlPointTools.findNextEnd(u.end,newList); + u.endPoint = G3DTools.getPoint(u.end.getLocalPosition()); + u.list.addAll(newList); + break; + default: + throw new RuntimeException("Error in piping rules"); + + } + u.offset = new Vector3d(); + if (u.hasOffsets) { + u.dir.normalize(); + for (PipeControlPoint icp : u.list) { + if (icp.isInstanceOf(ProcessResource.plant3Dresource.OffsettingPoint)) { + u.offset.add(ControlPointTools.getSizeChangeOffsetVector(icp,u.dir)); + } + else if (icp.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)) + ErrorLogger.defaultLogError("Updating pipe run, found offset controlpoint " + icp.getResource(), new Exception("ASSERT!")); + } + } + if (DEBUG) System.out.println("PipingRules.expandPipeline expanded " + u.start.getResource() + " " + u.end.getResource()); + u.iter++; + updatePathLeg(u,PathLegUpdateType.NONE); + } + + /** + * reverts one iteration of turn removing back) + */ + private static void backIter(UpdateStruct2 u) { + + if (DEBUG) System.out.println("PipingRules.backIter" + u.start.getResource() + " " + u.end.getResource()); + if (u.iter == 0) + throw new RuntimeException("Error in piping rules"); + ExpandIterInfo info = u.toRemove.get(u.toRemove.size()-1); + u.toRemove.remove(u.toRemove.size()-1); + if (info.getType() == REMOVE_START || info.getType() == REMOVE_BOTH) { + while (u.list.size() > 0) { + PipeControlPoint icp = u.list.get(0); + if (icp.getPrevious().getResource().equals(info.getStart().getResource())) + break; + u.list.remove(icp); + } + u.start = info.getStart(); + } + if (info.getType() == REMOVE_END || info.getType() == REMOVE_BOTH) { + while (u.list.size() > 0) { + PipeControlPoint icp = u.list.get(u.list.size() - 1); + if (icp.getNext().getResource().equals(info.getEnd().getResource())) + break; + u.list.remove(icp); + } + u.end = info.getEnd(); + } + u.offset = new Vector3d(); + if (u.hasOffsets) { + u.dir.normalize(); + for (PipeControlPoint icp : u.list) { + if (icp.isInstanceOf(ProcessResource.plant3Dresource.OffsettingPoint)) { + u.offset.add(ControlPointTools.getSizeChangeOffsetVector(icp,u.dir)); + } + else if (icp.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)) + ErrorLogger.defaultLogError("Updating pipe run, found offset controlpoint " + icp.getResource(), new Exception("ASSERT!")); + } + } + processPathLeg(u); + + } + + /** + * Processes pipe run (removes necessary turns and updates run ends) + */ + // private static void processPathLeg(PipeControlPoint start, Point3d startPoint,ArrayList list, PipeControlPoint end,Point3d endPoint, Vector3d dir,Vector3d offset, boolean hasOffsets,int iter, boolean reversed, ArrayList toRemove) throws TransactionException { + + private static void processPathLeg(UpdateStruct2 u) { + if (DEBUG) System.out.println("PipingRules.processPathLeg " + u.start.getResource() + " " + u.end.getResource()); + processPathLeg(u, true, true); + } + + + private static void processPathLeg(UpdateStruct2 u, boolean updateEnds, boolean updateInline) { + if (DEBUG) System.out.println("PipingRules.processPathLeg " + u.start.getResource() + " " + u.end.getResource()); + if (u.toRemove.size() > 0) { + for (ExpandIterInfo info : u.toRemove) { + if (info.getStart() != null) { + ControlPointTools.removeControlPoint(info.getStart()); + } + if (info.getEnd() != null) { + ControlPointTools.removeControlPoint(info.getEnd()); + } + } + // ControlPointTools.removeControlPoint may remove mo0re than one CP; + // we must populate inline CP list again. + u.list.clear(); + ControlPointTools.findNextEnd(u.start, u.list); + } + // FIXME : inline CPs are update twice because their positions must be updated before and after ends. + updateInlineControlPoints(u,false); + if (updateEnds) { + if (u.start.isInstanceOf(ProcessResource.plant3Dresource.TurnControlPoint)) { + updateTurnControlPointTurn(u.start, u.start.getPrevious(), u.start.getNext()); + updatePathLegPrev(u.start, u.start, PathLegUpdateType.NONE); + } else if (u.start.isInstanceOf(ProcessResource.plant3Dresource.EndComponentControlPoint)) { + updateEndComponentControlPoint(u.start, u.startPoint, u.endPoint); + } + if (u.end.isInstanceOf(ProcessResource.plant3Dresource.TurnControlPoint)) { + updateTurnControlPointTurn( u.end, u.end.getPrevious(), u.end.getNext()); + updatePathLegNext(u.end, u.end, PathLegUpdateType.NONE); + } else if (u.end.isInstanceOf(ProcessResource.plant3Dresource.EndComponentControlPoint)) { + updateEndComponentControlPoint(u.end, u.startPoint, u.endPoint); + } + + } else { + if (u.start.isInstanceOf(ProcessResource.plant3Dresource.EndComponentControlPoint)) { + updateEndComponentControlPoint(u.start, u.startPoint, u.endPoint); + } + if (u.end.isInstanceOf(ProcessResource.plant3Dresource.EndComponentControlPoint)) { + updateEndComponentControlPoint( u.end, u.startPoint, u.endPoint); + } + } + if(updateInline) + updateInlineControlPoints(u,true); + + } + + /** + * Processes pipe run and recalculates offset + */ + //private static void processPathLeg(PipeControlPoint start, Point3d startPoint,ArrayList list, PipeControlPoint end,Point3d endPoint, Vector3d dir, boolean hasOffsets,int iter, boolean reversed, ArrayList toRemove) throws TransactionException { + private static void processPathLegNoOffset(UpdateStruct2 u) { + if (DEBUG) System.out.println("PipingRules.processPathLeg " + u.start.getResource() + " " + u.end.getResource()); + Vector3d offset = new Vector3d(); + if (u.hasOffsets) { + u.dir.normalize(); + for (PipeControlPoint icp : u.list) { + if (icp.isInstanceOf(ProcessResource.plant3Dresource.OffsetComponent)) { + offset.add(ControlPointTools.getSizeChangeOffsetVector(icp,u.dir)); + } else if (icp.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)) { + ErrorLogger.defaultLogError("Updating pipe run, found offset controlpoint " + icp.getResource(), new Exception("ASSERT!")); + } + } + } + processPathLeg(u); + } + + private static void updateOffsetPoint(PipeControlPoint sccp, Vector3d offset) { + Point3d world = G3DTools.getPoint(sccp.getWorldPosition()); + world.add(offset); + PipeControlPoint ocp = sccp.getSubPoint().iterator().next(); + ControlPointTools.setWorldPosition(ocp, world); + } + + private static void updatePathLegPrev(PipeControlPoint start, PipeControlPoint updated, PathLegUpdateType lengthChange) { + ArrayList list = new ArrayList(); + PipeControlPoint end = ControlPointTools.findPreviousEnd(start,list); + updatePathLegPrev(start, list, end,updated,lengthChange); + } + + private static void updatePathLegPrev(PipeControlPoint start, ArrayList list, PipeControlPoint end, PipeControlPoint updated, PathLegUpdateType lengthChange) { + // reverses the list + ArrayList nextList = new ArrayList(); + for (PipeControlPoint icp : list) { + if (icp.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)) { + nextList.add(0, icp.getSubPointOf()); + } else { + nextList.add(0,icp); + } + + } + updatePathLeg(end, nextList, start, true,0,new ArrayList(),updated,lengthChange); + + } + + + /** + * Updates InlineControlPoints position when straight pipe's end(s) have + * been changed) + * + * @param pipeline + * @param icp + * @param nextPoint + * @param prevPoint + */ + private static void updateInlineControlPoint( PipeControlPoint icp, Point3d nextPoint, Point3d prevPoint, Vector3d dir) { + if (DEBUG) System.out.println("PipingRules.updateInlineControlPoint() " + icp.getResource()); + + Point3d inlinePoint = G3DTools.getPoint(icp.getLocalPosition()); + if (DEBUG) System.out.print("InlineControlPoint update "+icp.getResource() + " " + inlinePoint + " " + prevPoint + " " + nextPoint); + Vector3d newInlinePoint = null; + boolean branchUpdate = false; + PipeControlPoint becp = null; + for (PipeControlPoint pcp : icp.getSubPoint()) + if (pcp.isInstanceOf(ProcessResource.plant3Dresource.UndirectedControlPoint)) { + branchUpdate = true; + becp = pcp; + break; + } + + if (DUMMY || !branchUpdate) { + newInlinePoint = MathTools.closestPointOnEdge(new Vector3d(inlinePoint), new Vector3d(nextPoint), new Vector3d(prevPoint)); + } else { + + // FIXME : can only handle one branch + PipeControlPoint p = null; + if (becp.getNext() != null) { + p = ControlPointTools.findNextEnd(becp); + } else if (becp.getPrevious() != null) { + p = ControlPointTools.findPreviousEnd(becp); + } + if (p == null) { + newInlinePoint = MathTools.closestPointOnEdge(new Vector3d(inlinePoint), new Vector3d(nextPoint), new Vector3d(prevPoint)); + } else { + Point3d branchLegEnd = G3DTools.getPoint(p.getLocalPosition()); + Vector3d dir2 = new Vector3d(inlinePoint); + dir2.sub(branchLegEnd); + Vector3d dir1 = new Vector3d(nextPoint); + dir1.sub(prevPoint); + newInlinePoint = new Vector3d(); + double mu[] = new double[2]; + MathTools.intersectStraightStraight(new Vector3d(prevPoint), dir1, new Vector3d(branchLegEnd), dir2, newInlinePoint, new Vector3d(),mu); + if (DEBUG) System.out.println(mu[0]); + // FIXME : reserve space + if (mu[0] < 0.0) { + newInlinePoint = new Vector3d(prevPoint); + } else if (mu[0] > 1.0) { + newInlinePoint = new Vector3d(nextPoint); + } + } + } + if (DEBUG) System.out.println(" " + newInlinePoint); + + ControlPointTools.setWorldPosition(icp, newInlinePoint); + updateControlPointOrientation(icp); + } + + /** + * Updates InlineControlPoints position when straight pipe's end(s) have + * been changed) + * + * @param pipeline + * @param icp + * @param nextPoint + * @param prevPoint + */ + private static void updateEndComponentControlPoint( PipeControlPoint ecp, Point3d start, Point3d end) { + if (DEBUG) System.out.println("PipingRules.updateEndComponentControlPoint() " + ecp.getResource()); +// PipeControlPoint next = ecp.getNext(); +// PipeControlPoint prev = ecp.getPrevious(); +// if (next != null) { +// end = G3DTools.getPoint(next.getLocalPosition()); +// start = G3DTools.getPoint(ecp.getLocalPosition()); +// } else if (prev != null) { +// end = G3DTools.getPoint(ecp.getLocalPosition()); +// start = G3DTools.getPoint(prev.getLocalPosition()); +// } else { +// // TODO : warning? +// return; +// } + //Vector3d dir = new Vector3d (end); + //dir.sub(start); + //dir.normalize(); + //G3DTools.setTuple(ecp.getDirection(), dir); + + updateControlPointOrientation(ecp); + + for (PipeControlPoint pcp : ecp.getSubPoint()) { + // TODO update position + updatePathLegEndControlPoint(pcp); + } + } + + private static void updateControlPointOrientation(PipeControlPoint pcp) { + // FIXME : hack to bypass variable length components orientation + if (pcp.getAtMostOneRelatedObject(ProcessResource.g3dResource.HasWorldOrientation) == null) + return; + Double angleO = pcp.getAtMostOneRelatedScalarDouble(ProcessResource.plant3Dresource.HasRotationAngle); + double angle = 0.0; + if (angleO != null) + angle = angleO; + + AxisAngle4d aa = ControlPointTools.getControlPointWorldRotation(pcp, angle); + ControlPointTools.setWorldOrientation(pcp,aa); + + } + + /** + * Updates all branches when branch's position has been changed + * @param bcp + */ + private static void updateBranchControlPointBranches(PipeControlPoint bcp) { + if (DEBUG) System.out.println("PipingRules.updateBranchControlPointBranches() " + bcp.getResource()); + Collection branches = bcp.getSubPoint(); + if (branches.size() == 0) { + if (DEBUG) System.out.println("No Branches found"); + return; + } + for (PipeControlPoint pcp : branches) { + updatePathLegEndControlPoint(pcp); + } + } + + /** + * Recalculates turn control point's internal data (turn angle and offset) + * @param tcp + * @param prev + * @param next + */ + private static double updateTurnControlPointTurn( PipeControlPoint tcp, PipeControlPoint prev, PipeControlPoint next) { + if (DEBUG) System.out.println("PipingTools.updateTurnControlPointTurn()" + tcp.getResource()); + if (next == null || prev == null) + return Math.PI; // FIXME : argh + Point3d middlePoint = G3DTools.getPoint(tcp.getWorldPosition()); + Point3d nextPoint = G3DTools.getPoint(next.getWorldPosition()); + Point3d prevPoint = G3DTools.getPoint(prev.getWorldPosition()); + return updateTurnControlPointTurn(tcp, middlePoint, prevPoint, nextPoint); + } + + /** + * Recalculates turn control point's internal data (turn angle and offset) + * @param tcp + * @param middlePoint + * @param nextPoint + * @param prevPoint + */ + private static double updateTurnControlPointTurn( PipeControlPoint tcp, Point3d middlePoint, Point3d prevPoint, Point3d nextPoint) { + + Vector3d dir1 = new Vector3d(middlePoint); + dir1.sub(prevPoint); + Vector3d dir2 = new Vector3d(nextPoint); + dir2.sub(middlePoint); + if (DEBUG) System.out.println("PipingTools.updateTurnControlPointTurn " + tcp.getResource() + " " + prevPoint + " " + middlePoint + " " + nextPoint); + return updateTurnControlPointTurn(tcp, dir1, dir2); + } + + private static double updateTurnControlPointTurn(PipeControlPoint tcp, Vector3d dir1, Vector3d dir2) { + double turnAngle = dir1.angle(dir2); + double angle = Math.PI - turnAngle; + + double elbowRadius = tcp.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasTurnRadius); + double R = elbowRadius / Math.tan(angle * 0.5); + Vector3d turnAxis = new Vector3d(); + turnAxis.cross(dir1, dir2); + turnAxis.normalize(); + tcp.setRelatedScalarDouble(ProcessResource.plant3Dresource.HasTurnAngle,turnAngle); + tcp.setRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength, R);//setComponentOffsetValue(R); + G3DTools.setTuple3(tcp.getSingleRelatedObject(ProcessResource.plant3Dresource.HasTurnAxis), turnAxis); + if (DEBUG) System.out.println("PipingTools.updateTurnControlPointTurn " + dir1 + " " + dir2 + " " + turnAngle + " " + turnAxis); + return turnAngle; + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/PipingTools.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/PipingTools.java new file mode 100644 index 00000000..7ae038d2 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/PipingTools.java @@ -0,0 +1,225 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.common; + + +public class PipingTools { +// private static final boolean DEBUG = true; +// +// +// +// /** +// * Splits straigth by inserting new controlpoint between straight ends. +// * @param straight +// * @param newPcp +// * @throws TransactionException +// */ +//// public static void insertControlPoint(Straight straight, PipeControlPoint newPcp) throws TransactionException { +//// if (straight == null || newPcp == null) { +//// ErrorLogger.defaultLogError("Routing pipe, cannot make branch: straight or control point is null", null); +//// return; +//// } +//// PipeControlPoint scp = straight.getHasControlPoint(); +//// PipeControlPoint straightStart = (PipeControlPoint)StubFactory.getStubForResource(straight.getClass().getClassLoader(),scp.getPreviousPoint().getResource()); +//// PipeControlPoint straightEnd = (PipeControlPoint)StubFactory.getStubForResource(straight.getClass().getClassLoader(),scp.getNext().getResource()); +//// if (DEBUG) System.out.println("PipingTools inserting control point between " + straightStart.getResource() + " " + straightEnd.getResource() + " straight " + straight.getResource()); +//// +//// // remove the straight pipe +//// PipeControlPoint temp = PipeControlPointFactory.instantiate(newPcp.getGraph()); +//// //straight.setHasNextControlPoint(temp); +//// //straight.setHasPreviousControlPoint(temp); +//// straight.setHasControlPoint(temp); +//// +//// PipeRun pipeRun = getPipeRun(straight); +//// if (pipeRun != null) { +//// pipeRun.getHasSubnodesSet().remove(straight.getResource()); +//// } +//// insertControlPoint(pipeRun, newPcp, straightStart, straightEnd); +//// +//// } +// +// +// +// +// +// +// +// +// public static void getStraightPipeEnds(Straight straight, Point3d end1, Point3d end2) { +// getStraightPipeEnds(getPipeRun(straight), straight, end1, end2); +// } +// +// public static void getStraightPipeEnds(PipeRun pipeRun,Straight straight, Point3d end1, Point3d end2) { +// if (DEBUG) System.out.println("PipingTools.getStraightPipeEnds() " + straight.getResource()); +// PipeControlPoint scp = straight.getHasControlPoint(); +// PipeControlPoint startControlPoint = (PipeControlPoint)StubFactory.getStubForResource(straight.getClass().getClassLoader(),scp.getPrevious().getResource()); +// PipeControlPoint endControlPoint = (PipeControlPoint)StubFactory.getStubForResource(straight.getClass().getClassLoader(),scp.getNext().getResource()); +// if (startControlPoint == null || endControlPoint == null) { +// ErrorLogger.defaultLogError("Pipe ends null", new NullPointerException()); +// } +// // start and end position of the pipe +// // positions may be linked to other components, like nozzles +// // and then their coordinates are in component's local coordinates +// // which must be transformed into pipeRun's local coordinates +// +// //Point3d startPipe = getLocalPoint(pipeRun,startControlPoint); +// +// +// //Point3d endPipe = getLocalPoint(pipeRun, endControlPoint); +// Point3d startPipe = G3DTools.getPoint(startControlPoint.getLocalPosition()); +// Point3d endPipe = G3DTools.getPoint(endControlPoint.getLocalPosition()); +// if (startPipe == null || endPipe == null) { +// end1.x = Double.NaN; +// end1.y = Double.NaN; +// end1.z = Double.NaN; +// end2.x = Double.NaN; +// end2.y = Double.NaN; +// end2.z = Double.NaN; +// if (DEBUG) System.out.println("no positions"); +// return; +// } +// +// Vector3d dir = new Vector3d(endPipe); +// dir.sub(startPipe); +// +// +// if (startControlPoint instanceof TurnControlPoint) { +// TurnControlPoint t = (TurnControlPoint)startControlPoint; +// double R = t.getComponentOffsetValue(); +// Vector3d n = new Vector3d(dir); +// n.normalize(); +// n.scale(R); +// startPipe.add(n); +// } else if (startControlPoint instanceof InlineControlPoint && !(startControlPoint instanceof BranchControlPoint)) { +// InlineControlPoint t = (InlineControlPoint)startControlPoint; +// double R = t.getNextComponentOffsetValue(); +// Vector3d n = new Vector3d(dir); +// n.normalize(); +// n.scale(R); +// startPipe.add(n); +// } +// +// if (endControlPoint instanceof TurnControlPoint) { +// TurnControlPoint t = (TurnControlPoint)endControlPoint; +// double R = t.getComponentOffsetValue(); +// Vector3d n = new Vector3d(dir); +// n.normalize(); +// n.scale(R); +// endPipe.sub(n); +// } else if (endControlPoint instanceof InlineControlPoint && !(endControlPoint instanceof BranchControlPoint)) { +// InlineControlPoint t = (InlineControlPoint)endControlPoint; +// double R = t.getPreviousComponentOffsetValue(); +// Vector3d n = new Vector3d(dir); +// n.normalize(); +// n.scale(R); +// endPipe.sub(n); +// } +// +// end1.x = startPipe.x; +// end1.y = startPipe.y; +// end1.z = startPipe.z; +// +// end2.x = endPipe.x; +// end2.y = endPipe.y; +// end2.z = endPipe.z; +// +// } +// +// /** +// * Finds direction and ends where inline component, reducer or branch can be moved. +// * @param icp +// * @param s +// * @param e +// * @param d +// */ +// public static void getInlineEnds(InlineControlPoint icp, Vector3d s, Vector3d e, Vector3d d) { +// +// PipeControlPoint next = (PipeControlPoint)StubFactory.getStubForResource(icp.getClass().getClassLoader(), icp.getNext().getResource()); +// PipeControlPoint prev = (PipeControlPoint)StubFactory.getStubForResource(icp.getClass().getClassLoader(), icp.getPrevious().getResource()); +// Vector3d start = G3DTools.getVector(prev.getLocalPosition()); +// Vector3d end = G3DTools.getVector(next.getLocalPosition()); +// if (icp.getResource().isInstanceOf(GlobalIdMap.get(PSK3DModelingOntologyMapping.SIZE_CHANGE_CONTROL_POINT))) { +// SizeChangeControlPoint sccp = SizeChangeControlPointFactory.create(icp.getResource()); +// Vector3d tDir = new Vector3d(G3DTools.getVector(sccp.getLocalPosition())); +// Vector3d offset = getSizeChangeOffsetVector(sccp, tDir); +// end.sub(offset); +// } +// Vector3d dir = new Vector3d(end); +// dir.sub(start); +// Vector3d n = new Vector3d(dir); +// n.normalize(); +// +// double offset = icp.getNextComponentOffsetValue(); +// if (next instanceof InlineControlPoint) { +// InlineControlPoint ip = (InlineControlPoint) next; +// offset += ip.getPreviousComponentOffsetValue(); +// } +// else if (next instanceof TurnControlPoint) { +// TurnControlPoint tcp = (TurnControlPoint)next; +// offset += tcp.getComponentOffsetValue(); +// } +// Vector3d t = new Vector3d(n); +// t.scale(offset); +// end.sub(t); +// +// offset = icp.getPreviousComponentOffsetValue(); +// if (prev instanceof InlineControlPoint) { +// InlineControlPoint ip = (InlineControlPoint) prev; +// offset += ip.getPreviousComponentOffsetValue(); +// } +// else if (prev instanceof TurnControlPoint) { +// TurnControlPoint tcp = (TurnControlPoint)prev; +// offset += tcp.getComponentOffsetValue(); +// } +// t = new Vector3d(n); +// t.scale(offset); +// start.add(t); +// +// dir= new Vector3d(end); +// dir.sub(start); +// +// s.x = start.x; +// s.y = start.y; +// s.z = start.z; +// +// e.x = end.x; +// e.y = end.y; +// e.z = end.z; +// +// d.x = dir.x; +// d.y = dir.y; +// d.z = dir.z; +// +// System.out.println("PipingTools.getInlineEnds() " + s + " " + e + " " + d); +// } +// +// +// public static void setSame(fi.vtt.simantics.layer0.stubs.Double d1, fi.vtt.simantics.layer0.stubs.Double d2) { +// d1.getResource().createRelation(d2.getResource(), GlobalIdMap.get(PSK3DModelingOntologyMapping.IS_SAME_VALUE)); +// } +// +// public static void setHalf(fi.vtt.simantics.layer0.stubs.Double d1, fi.vtt.simantics.layer0.stubs.Double d2) { +// d1.getResource().createRelation(d2.getResource(), GlobalIdMap.get(PSK3DModelingOntologyMapping.IS_HALF_OF_THE_VALUE)); +// } +// +// +// + +// +// +// +// +// +// +// +// + +} \ No newline at end of file diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/PipingTools2.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/PipingTools2.java new file mode 100644 index 00000000..4baf3089 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/PipingTools2.java @@ -0,0 +1,668 @@ +package fi.vtt.simantics.processeditor.common; + +import java.util.Collection; + +import javax.vecmath.Point3d; +import javax.vecmath.Vector3d; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.layer0.utils.Statement; +import org.simantics.layer0.utils.instantiation.Instance; +import org.simantics.layer0.utils.instantiation.InstanceFactory; +import org.simantics.proconf.g3d.base.G3DTools; +import org.simantics.proconf.g3d.stubs.G3DNode; + +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.actions.PositionType; +import fi.vtt.simantics.processeditor.stubs.Equipment; +import fi.vtt.simantics.processeditor.stubs.InlineComponent; +import fi.vtt.simantics.processeditor.stubs.Nozzle; +import fi.vtt.simantics.processeditor.stubs.PipeControlPoint; +import fi.vtt.simantics.processeditor.stubs.PipeRun; +import fi.vtt.simantics.processeditor.stubs.PipelineComponent; + +public class PipingTools2 { + private static final boolean DEBUG = false; + public enum Direction{NEXT,PREVIOUS}; + + + + /** + * Reverses a piperun by swapping all previous/next connections + * @param pipeRun + */ + public static void reversePipeRun(IEntity pipeRun) { +// //FIXME : reducers / size-change / offset-control points +// RelationTypeSet cps = pipeRun.getHasControlPointSet(); +// if (cps.size() == 0) +// return; +// List list = new ArrayList(); +// PipeControlPoint pcp = cps.iterator().next(); +// list.add(pcp); +// PipeControlPoint temp = pcp.getPrevious(); +// while (temp != null) { +// list.add(0,temp); +// temp = temp.getPrevious(); +// } +// temp = pcp.getNext(); +// while (temp != null) { +// list.add(temp); +// temp = temp.getNext(); +// } +// // now list contains control points in sorted order. +// // switch order +// for (int i = 0; i < list.size() - 1; i++) { +// PipeControlPoint pcp1 = list.get(i); +// PipeControlPoint pcp2 = list.get(i+1); +// pcp1.setPrevious(pcp2); +// pcp2.setNext(pcp1); +// +// } +// // fix ends +// list.get(0).setNext(null); +// list.get(list.size() - 1).setPrevious(null); + + } + + public static IEntity getPipeRun(IEntity component) { + assert(component.isInstanceOf(ProcessResource.plant3Dresource.PipelineComponent)); + return component.getSingleRelatedObject(ProcessResource.g3dResource.HasParent); + } + + /** + * Returns Nozzle of a directed control point + * @param dcp + * @return + */ + public static Nozzle getNozzle(PipeControlPoint dcp) { + assert (dcp.isInstanceOf(ProcessResource.plant3Dresource.DirectedControlPoint)); + IEntity e = dcp.getControlPointOf(); + if (e == null) + return null; + assert (e.isInstanceOf(ProcessResource.plant3Dresource.Nozzle)); + return new Nozzle(e); + } + + /** + * Instantiates new pipeline component and all necessary control points for it. + * @param graph + * @param typeResource + * @return + */ + public static PipelineComponent instantiatePipelineComponent(Graph graph, Resource pipeRunResource, Resource typeResource) { + IEntity pipeRun = EntityFactory.create(graph,pipeRunResource); + Instance ins = InstanceFactory.getInstanceOfType(graph, typeResource); + Resource instance = ins.instantiate(graph); + PipelineComponent component = new PipelineComponent(graph,instance); + G3DTools.resetTransformation(component); + // copy control point + Collection pcps = graph.getObjects(typeResource, ProcessResource.plant3Dresource.HasControlPoint); + assert(pcps.size() == 1); + Collection types = graph.getObjects(pcps.iterator().next(), ProcessResource.builtins.InstanceOf); + PipeControlPoint componentPCP = new PipeControlPoint(graph,InstanceFactory.instantiate(graph, types)); + component.addStatement(ProcessResource.plant3Dresource.HasControlPoint, componentPCP); + pipeRun.addStatement(ProcessResource.g3dResource.HasChild, component); + pipeRun.addStatement(ProcessResource.plant3Dresource.HasControlPoints, componentPCP); + component.setPipeDiameter(pipeRun.getSingleRelatedObject(ProcessResource.plant3Dresource.HasPipeDiameter)); + if (component.isInstanceOf(ProcessResource.plant3Dresource.VariableAngleTurnComponent)) { + setStatement(component, ProcessResource.plant3Dresource.HasTurnRadius, pipeRun.getSingleRelatedObject(ProcessResource.plant3Dresource.HasTurnRadius)); + setStatement(componentPCP, ProcessResource.plant3Dresource.HasTurnRadius, pipeRun.getSingleRelatedObject(ProcessResource.plant3Dresource.HasTurnRadius)); + setStatement(component, ProcessResource.plant3Dresource.HasTurnAngle, componentPCP.getSingleRelatedObject(ProcessResource.plant3Dresource.HasTurnAngle)); + setStatement(component, ProcessResource.plant3Dresource.HasTurnAxis, componentPCP.getSingleRelatedObject(ProcessResource.plant3Dresource.HasTurnAxis)); + } + if (component.getAtMostOneRelatedObject(ProcessResource.plant3Dresource.HasLength) != null) { + setStatement(componentPCP, ProcessResource.plant3Dresource.HasLength, component.getSingleRelatedObject(ProcessResource.plant3Dresource.HasLength)); + } + componentPCP.setLocalOrientation(component.getLocalOrientation()); + componentPCP.setWorldOrientation(component.getWorldOrientation()); + + componentPCP.setLocalPosition(component.getLocalPosition()); + componentPCP.setWorldPosition(component.getWorldPosition()); + + setStatement(componentPCP, ProcessResource.plant3Dresource.HasPipeDiameter, pipeRun.getSingleRelatedObject(ProcessResource.plant3Dresource.HasPipeDiameter)); + setStatement(component, ProcessResource.plant3Dresource.HasPipeDiameter, pipeRun.getSingleRelatedObject(ProcessResource.plant3Dresource.HasPipeDiameter)); + + // TODO : instantiate subpoints + + + return component; + } + + public static Nozzle instantiateNozzle(Graph graph, Resource typeResource) { + Instance ins = InstanceFactory.getInstanceOfType(graph, typeResource); + Resource instance = ins.instantiate(graph); + Nozzle n = new Nozzle(graph,instance); + G3DTools.resetTransformation(n); + + // copy control point + Collection pcps = graph.getObjects(typeResource, ProcessResource.plant3Dresource.HasControlPoint); + assert(pcps.size() == 1); + Collection types = graph.getObjects(pcps.iterator().next(), ProcessResource.builtins.InstanceOf); + PipeControlPoint nozzlePCP = new PipeControlPoint(graph,InstanceFactory.instantiate(graph, types)); + n.addStatement(ProcessResource.plant3Dresource.HasControlPoint, nozzlePCP); + nozzlePCP.setLocalOrientation(n.getLocalOrientation()); + nozzlePCP.setWorldOrientation(n.getWorldOrientation()); + nozzlePCP.setLocalPosition(n.getLocalPosition()); + nozzlePCP.setWorldPosition(n.getWorldPosition()); + setStatement(nozzlePCP, ProcessResource.plant3Dresource.HasPipeDiameter, n.getSingleRelatedObject(ProcessResource.plant3Dresource.HasPipeDiameter)); + nozzlePCP.setPipeDiameter(0.2); + return n; + } + + public static Equipment instantiateEquipment(Graph graph, Resource typeResource) { + Instance ins = InstanceFactory.getInstanceOfType(graph, typeResource); + Resource instance = ins.instantiate(graph); + Equipment equipment = new Equipment(graph, instance); + G3DTools.resetTransformation(equipment); + + IEntity type = EntityFactory.create(graph, typeResource); + IEntity geometricModel = type.getSingleRelatedObject(ProcessResource.plant3Dresource.HasGraphics); + + Collection sizingProperties = geometricModel.getRelatedObjects(ProcessResource.g3dResource.HasSizingParameter); + Collection equipmentProperties = equipment.getRelatedStatements(ProcessResource.builtins.HasProperty); + + for (IEntity e : sizingProperties) { + String name = e.getName(); + String pName = "Has " + name; + boolean found = false; + for (Statement s : equipmentProperties) { + IEntity predicate = s.getPredicate(); + String predicateName = predicate.getName(); + if (predicateName.equals(pName)) { + found = true; + break; + } + } + if(!found) { + IEntity rel = getOrCreateRel(graph,name); + equipment.setRelatedScalarDouble(rel, 1.0); + } + } + + // TODO : create nozzles if needed + + return equipment; + } + + private static IEntity getOrCreateRel(Graph graph, String name) { + IEntity rel = null; + try { + Resource relr = graph.getResourceByURI("http://www.vtt.fi/Simantics/Plant3D/1.0/Relations#Has" + name); + rel = EntityFactory.create(graph,relr); + } catch (Exception e) { + Resource relLib = null; + try { + relLib = graph.getResourceByURI("http://www.vtt.fi/Simantics/Plant3D/1.0#Relations"); + } catch (Exception e2) { + + } + Resource relr = graph.newResource(); + rel = EntityFactory.create(graph, relr); + rel.addStatement(ProcessResource.builtins.SubrelationOf, ProcessResource.g3dResource.HasNonTransformation); + rel.setName("Has " + name); + Resource irelr = graph.newResource(); + graph.addStatement(relr,ProcessResource.builtins.InverseOf,irelr); + graph.addStatement(relLib, ProcessResource.builtins.ConsistsOf, relr); + } + return rel; + } + + public static IEntity getLibraryComponentType(IEntity component) { + assert(component.isInstanceOf(ProcessResource.plant3Dresource.LibraryComponent)); + // IEntity.getTypes() returns all types, but we want the closest type. + Collection types = component.getRelatedObjects(ProcessResource.builtins.InstanceOf);//component.getTypes(); + IEntity type = null; + for (IEntity t : types) { + if (t.isInheritedFrom(ProcessResource.plant3Dresource.LibraryComponent)) { + if (type == null) + type = t; + else + throw new RuntimeException("Cannot find proper type for library component " + component.getResource() ); + } + } + return type; + } + + /** + * Splits existing VariableLengthComponent with another component. + * Result is two VariableLengthComponents and inserted component between them. + * + * Note : world position of newComponent must be set before this method may be called. + * + * @param newComponent + * @param splittingComponent + */ + public static void splitVariableLengthComponent(IEntity newComponent, IEntity splittingComponent) { + assert(splittingComponent.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent)); + assert(newComponent.isInstanceOf(ProcessResource.plant3Dresource.PipelineComponent)); + assert(!newComponent.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent)); + IEntity newCP = newComponent.getSingleRelatedObject(ProcessResource.plant3Dresource.HasControlPoint); + IEntity splittingCP = splittingComponent.getSingleRelatedObject(ProcessResource.plant3Dresource.HasControlPoint); + IEntity nextCP = splittingCP.getAtMostOneRelatedObject(ProcessResource.plant3Dresource.HasNext); + IEntity prevCP = splittingCP.getAtMostOneRelatedObject(ProcessResource.plant3Dresource.HasPrevious); + + /* there are many different cases to insert new component when + it splits existing VariableLengthinlineComponent. + + 1. VariableLengthComponet is connected from both sides: + - insert new component between VariableLength component and component connected to it + - insert new VariableLengthComponent between inserted component and component selected in previous step + + 2. VariableLengthComponent is connected from one side + - Use previous case or: + - Insert new component to empty end + - Insert new VariableLength component to inserted components empty end + + 3. VariableLength is not connected to any component. + - Should not be possible, at least in current implementation. + - Could be done using second case + + */ + + if (nextCP == null && prevCP == null) { + // this should not be possible + throw new RuntimeException("VariableLengthComponent " + splittingComponent.getResource() + " is not connected to anything."); + } + + Point3d next = ControlPointTools.getRealPosition(splittingCP, PositionType.NEXT); + Point3d prev = ControlPointTools.getRealPosition(splittingCP, PositionType.PREVIOUS); + Point3d comp = G3DTools.getPoint(newComponent.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldPosition)); + double length = newComponent.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength); + Vector3d dir = new Vector3d(next); + dir.sub(prev); + dir.normalize(); + dir.scale(length * 0.5); + Point3d vn = new Point3d(comp); + Point3d vp = new Point3d(comp); + vn.add(dir); + vp.sub(dir); + double ln = vn.distance(next); + double lp = vp.distance(prev); + vp.interpolate(prev, 0.5); + vn.interpolate(next, 0.5); + + IEntity type = getLibraryComponentType(splittingComponent); + + IEntity newVariableLengthComponent = instantiatePipelineComponent(splittingComponent.getGraph(), getPipeRun(splittingComponent).getResource(), type.getResource()); + IEntity newVariableLengthCP = newVariableLengthComponent.getSingleRelatedObject(ProcessResource.plant3Dresource.HasControlPoint); + if (nextCP == null) { + ControlPointTools.insertControlPoint(newCP, splittingCP,Direction.NEXT); + ControlPointTools.insertControlPoint(newVariableLengthCP, newCP,Direction.NEXT); + ControlPointTools.setWorldPosition(splittingCP, vp); + splittingCP.setRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength, lp); + ControlPointTools.setWorldPosition(newVariableLengthCP, vn); + newVariableLengthComponent.setRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength, ln); + } else if (prevCP == null) { + ControlPointTools.insertControlPoint(newCP, splittingCP,Direction.PREVIOUS); + ControlPointTools.insertControlPoint(newVariableLengthCP, newCP,Direction.PREVIOUS); + ControlPointTools.setWorldPosition(splittingCP, vn); + splittingCP.setRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength, ln); + ControlPointTools.setWorldPosition(newVariableLengthCP, vp); + newVariableLengthComponent.setRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength, lp); + } else { + ControlPointTools.insertControlPoint(newCP,splittingCP,nextCP); + ControlPointTools.insertControlPoint(newVariableLengthCP, newCP,nextCP); + ControlPointTools.setWorldPosition(splittingCP, vp); + splittingCP.setRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength, lp); + ControlPointTools.setWorldPosition(newVariableLengthCP, vn); + newVariableLengthComponent.setRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength, ln); + } + + } + + /** + * Attaches newComponent into connectedComponent's connectedControlPoint + * @param newComponent + * @param connectedComponent + * @param connectedControlPoint + */ + public static void insertComponent(IEntity newComponent, IEntity connectedComponent, IEntity connectedControlPoint, Direction direction) { + assert (newComponent.isInstanceOf(ProcessResource.plant3Dresource.PipelineComponent)); + assert (connectedComponent.isInstanceOf(ProcessResource.plant3Dresource.PipelineComponent)); + // TODO : piperun check is more complicated, since newComponent and connectedComponent may be SizeChangeComponents + //assert (getPipeRun(connectedComponent).equals(getPipeRun(newComponent))); + + // new control point and its subpoint + IEntity newControlPoint = newComponent.getSingleRelatedObject(ProcessResource.plant3Dresource.HasControlPoint); + ControlPointTools.insertControlPoint(newControlPoint, connectedControlPoint, direction); +// IEntity newSubPoint = null; +// if (newControlPoint.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)) +// newSubPoint = newControlPoint.getSingleRelatedObject(ProcessResource.plant3Dresource.HasSubPoint); +// +// // connected components parent or subpoint +// IEntity connectedSubPoint = null; +// IEntity connectedParentPoint = null; +// if (connectedControlPoint.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)) +// connectedSubPoint = connectedControlPoint.getSingleRelatedObject(ProcessResource.plant3Dresource.HasSubPoint); +// else if (connectedControlPoint.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)) +// connectedParentPoint = connectedControlPoint.getSingleRelatedObject(ProcessResource.plant3Dresource.SubPointOf); +// +// if (direction == Direction.NEXT) { +// assert (connectedSubPoint == null); // if direction is next, connection done to subpoint +// setStatement(connectedControlPoint, ProcessResource.plant3Dresource.HasNext, newControlPoint); +// if (connectedParentPoint != null) +// setStatement(connectedParentPoint, ProcessResource.plant3Dresource.HasNext, newControlPoint); +// setStatement(newControlPoint, ProcessResource.plant3Dresource.HasPrevious, connectedControlPoint); +// if (newSubPoint != null) +// setStatement(newSubPoint, ProcessResource.plant3Dresource.HasPrevious, connectedControlPoint); +// +// } else { +// assert (connectedParentPoint == null); // if direction is prev, connection done to parentpoint +// if (newSubPoint != null) { +// +// } +// } + + /* + private void insertEndComponent() { + activated = false; + Graph coreTC = parent.getGraph(); + + if (replace == null) + checkForEndInsertion(); + if (replace == null) { + ErrorLogger.defaultLogError("Cannot insert end component",null); + end(); + return; + } + G3DNode p = straight.getHasParent(); + if (p == null) { + ErrorLogger.defaultLogError("Straight pipe has no parent", new Exception("ASSERT!")); + + } else { + Pipeline pipeline = PipelineFactory.create(p); + coreTC.startTransaction(this); + try { + Vector3d startPoint = GraphicsNodeTools.getVector(replace.getLocalPosition()); + EndComponentControlPoint ecp = EndComponentControlPointFactory.instantiate(coreTC); + coreTC.commitChanges(CommitMessage.CHANGE_MESSAGE); + pipeline.getHasControlPointSet().remove(replace); + // create dummy node + //PipeControlPoint pcp = PipeControlPointFactory.instantiate(coreTC); + replace.setNextPoint(null); + replace.setPreviousPoint(null); + pipeline.getHasControlPointSet().add(ecp); + if (next) { + straight.getHasControlPoint().getPreviousPoint().setNextPoint(ecp); + straight.getHasControlPoint().setNextPoint(ecp); + ecp.setPreviousPoint(straight.getHasControlPoint().getPreviousPoint()); + //ecp.setNextPoint(null); + } else { + straight.getHasControlPoint().getNextPoint().setPreviousPoint(ecp); + straight.getHasControlPoint().setPreviousPoint(ecp); + ecp.setNextPoint(straight.getHasControlPoint().getNextPoint()); + //ecp.setPreviousPoint(null); + } + G3DTools.setTranslation(ecp.getLocalPosition(), startPoint); + // FIXME : component should specify how much space it needs + createAndLink(coreTC, pipeline, ecp); + coreTC.commitChanges(CommitMessage.CHANGE_MESSAGE); + coreTC.commitTransaction(CommitMessage.TRANSACTION_MESSAGE); + } catch (TransactionException e) { + ErrorLogger.defaultLogError("Cannot insert component", e); + coreTC.cancelTransaction(); + } + } + + end(); + } + + private void insertComponent(Point3d startPoint) { + activated = false; + Graph coreTC = parent.getGraph(); + G3DNode p = straight.getHasParent(); + if (p == null) { + ErrorLogger.defaultLogError("Straight pipe has no parent", new Exception("ASSERT!")); + + } else { + Pipeline pipeline = PipelineFactory.create(p); + coreTC.startTransaction(this); + try { + InlineComponentControlPoint icp = InlineComponentControlPointFactory.instantiate(coreTC); + coreTC.commitChanges(CommitMessage.CHANGE_MESSAGE); + PipeControlPoint scp = straight.getHasControlPoint(); + // it shouldn't matter whitch control point to use, next or previous. + PipingTools.insertControlPoint(pipeline, icp, scp, scp.getNextPoint()); + //PipingTools.insertControlPoint(straight, icp); + pipeline.getHasControlPointSet().add(icp); + G3DTools.setTranslation(icp.getLocalPosition(), startPoint); + // FIXME : component should specify how much space it needs + icp.setNextComponentOffsetValue(pipeline.getPipeRadiusValue()); + icp.setPreviousComponentOffsetValue(pipeline.getPipeRadiusValue()); + PipingTools.setSame(pipeline.getPipeRadius(), icp.getNextComponentOffset()); + PipingTools.setSame(pipeline.getPipeRadius(), icp.getPreviousComponentOffset()); + createAndLink(coreTC, pipeline, icp); + coreTC.commitChanges(CommitMessage.CHANGE_MESSAGE); + coreTC.commitTransaction(CommitMessage.TRANSACTION_MESSAGE); + } catch (TransactionException e) { + ErrorLogger.defaultLogError("Cannot insert component", e); + coreTC.cancelTransaction(); + } + } + + line.removeFromParent(); + + end(); + + } + + + private void createAndLink(Graph coreTC, Pipeline pipeline, PipeControlPoint icp) throws TransactionException { + PipelineComponent component = PipelineComponentFactory.create(OntologyUtils.instantiate(typeResource)); + coreTC.commitChanges(CommitMessage.CHANGE_MESSAGE); + component.setHasControlPoint(icp); + component.setLocalPosition(icp.getLocalPosition()); + pipeline.getHasSubnodesSet().add(component); + component.setPipeRadius(pipeline.getPipeRadius()); + component.setHasGraphics(GraphicsModelFactory.create(modelResource)); + + } + */ + + /* + old insert reducer code + + Pipeline pipeline = PipingTools.getPipeline(straight); + // pcp is Turn Control Point and we'll have to change it's type to Size Change Control Point + // First we'll remove its unnecessary properties and elbow connected to it, + RelationTypeSet pipeComponents = pcp.getControlPointOfSet(); + Resource elbowResource = null; + for (Entity e : pipeComponents) { + if (e.getResource().isInstanceOf(GlobalIdMap.get(PSK3DModelingOntologyMapping.ELBOW))) { + elbowResource = e.getResource(); + } + } + if (elbowResource != null) { + pipeComponents.remove(elbowResource); + pipeline.getHasSubnodesSet().remove(elbowResource); + } + RelationSet rs = pcp.getResource().getRelatedResourcesWithRelationIds(GlobalIdMap.get(PSK3DModelingOntologyMapping.HAS_TURN_ANGLE)); + RelationReference rr = rs.getRelations()[0]; + pcp.getResource().removeRelationById(rr.getObjectId(),rr.getRelationId()); + rs = pcp.getResource().getRelatedResourcesWithRelationIds(GlobalIdMap.get(PSK3DModelingOntologyMapping.HAS_COMPONENT_OFFSET)); + rr = rs.getRelations()[0]; + pcp.getResource().removeRelationById(rr.getObjectId(),rr.getRelationId()); + rs = pcp.getResource().getRelatedResourcesWithRelationIds(GlobalIdMap.get(Builtins.InstanceOf)); + rr = rs.getRelations()[0]; + //pcp.getResource().removeRelationById(type[0], GlobalIdMap.get(Builtins.InstanceOf)); + pcp.getResource().removeRelationById(rr.getObjectId(),rr.getRelationId()); + Resource sccpType = graph.getResource(PSK3DModelingOntologyMapping.SIZE_CHANGE_CONTROL_POINT); + pcp.createRelation(sccpType, graph.getResource(Builtins.InstanceOf)); + + graph.commitChanges(CommitMessage.CHANGE_MESSAGE); + + Reducer reducer = null; + Pipeline newPipeline = PipelineFactory.instantiate(graph); + OffsetControlPoint offsetControlPoint = OffsetControlPointFactory.instantiate(graph); + if (i == 0) { + reducer = ConcentricReducerFactory.instantiate(graph); + } else { + reducer = EccentricReducerFactory.instantiate(graph); + } + graph.commitChanges(CommitMessage.CHANGE_MESSAGE); + SizeChangeControlPoint sccp = SizeChangeControlPointFactory.create(pcp.getResource()); + + + // FIXME : lenght, pipe radius and turn angle from specs + let the user choose spec for new pipeline + double reducerLength = 0.3; + reducer.setLengthValue(reducerLength); + double newPipeRadius = pipelineDialog.getPipeRadius(); + double newPipeTurnRadius = pipelineDialog.getTurnRadius(); + + reducer.setLocalPosition(sccp.getLocalPosition()); + reducer.setWorldPosition(sccp.getWorldPosition()); + + reducer.setBottomRadiusValue(pipeline.getPipeRadiusValue()); + + reducer.setPipeRadius(pipeline.getPipeRadius()); + reducer.setTopRadiusValue(newPipeRadius); + newPipeline.setPipeRadiusValue(newPipeRadius); + newPipeline.setTurnRadiusValue(newPipeTurnRadius); + + // reducer is adjuste by pipelines' radiis + PipingTools.setSame(pipeline.getPipeRadius(), reducer.getBottomRadius()); + PipingTools.setSame(newPipeline.getPipeRadius(), reducer.getTopRadius()); + + //newPipeline.getHasControlPointSet().add(pcp); + sccp.setHasOffsetPoint(offsetControlPoint); + offsetControlPoint.setOffsetPointOf(sccp); + + reducer.setHasControlPoint(sccp); + graph.commitChanges(CommitMessage.CHANGE_MESSAGE); + + sccp.setNextComponentOffsetValue(reducerLength*0.5); + sccp.setPreviousComponentOffsetValue(reducerLength*0.5); + + // offsets are calculated from reducers length + PipingTools.setHalf(reducer.getLength(), sccp.getNextComponentOffset()); + PipingTools.setHalf(reducer.getLength(), sccp.getPreviousComponentOffset()); + + // linking sccp and ocp offsets + offsetControlPoint.setNextComponentOffset(sccp.getNextComponentOffset()); + offsetControlPoint.setPreviousComponentOffset(sccp.getPreviousComponentOffset()); + + + offsetControlPoint.setPreviousPoint(sccp.getPreviousPoint()); + offsetControlPoint.setNextPoint(sccp.getNextPoint()); + if (i == 1) { + // FIXME : link offset value + sccp.setOffsetValue(reducer.getBottomRadiusValue() - reducer.getTopRadiusValue()); + sccp.setAngle(((EccentricReducer)reducer).getAngle()); + Vector3d v = PipingTools.getSizeChangeOffsetVector(sccp); + Point3d local = GraphicsNodeTools.getTranslation(sccp.getLocalPosition()); + local.add(v); + //Point3d World = GraphicsNodeTools.getTranslation(sccp.getLocalPosition()); + GraphicsNodeTools.setTranslation(offsetControlPoint.getLocalPosition(), local); + } else { + // FIXME : is it possible that pipelines are in different coordinate systems + offsetControlPoint.setLocalPosition(sccp.getLocalPosition()); + offsetControlPoint.setWorldPosition(sccp.getWorldPosition()); + } + ((TestProcessEditor)parent).getPlant().getHasSubnodesSet().add(newPipeline); + pipeline.getHasSubnodesSet().add(reducer); + newPipeline.getHasControlPointSet().add(offsetControlPoint); + graph.commitChanges(CommitMessage.CHANGE_MESSAGE); + + graph.commitTransaction(CommitMessage.TRANSACTION_MESSAGE); + + */ + + + + } + + /** + * Returns direction of a nozzle + * @param nozzle + * @return + */ + public static Vector3d getNozzleDirection(IEntity nozzle) { + return ControlPointTools.getNozzleDirection(nozzle.getSingleRelatedObject(ProcessResource.g3dResource.HasWorldOrientation)); + } + + /** + * Returns true if a nozzle is not connected to a pipe + * @param nozzle + * @return + */ + public static boolean isFreeNozzle(IEntity nozzle) { + assert (nozzle.isInstanceOf(ProcessResource.plant3Dresource.Nozzle)); + IEntity pcp = nozzle.getSingleRelatedObject(ProcessResource.plant3Dresource.HasControlPoint); + IEntity next = pcp.getAtMostOneRelatedObject(ProcessResource.plant3Dresource.HasNext); + IEntity previous = pcp.getAtMostOneRelatedObject(ProcessResource.plant3Dresource.HasPrevious); + if (next == null && previous == null) { + assert (pcp.getAtMostOneRelatedObject(ProcessResource.plant3Dresource.ControlPointOfPipeRun) == null); + return true; + } + assert (pcp.getAtMostOneRelatedObject(ProcessResource.plant3Dresource.ControlPointOfPipeRun) != null); + return false; + } + + public static void getInlineComponentEnds(IEntity inlineComponent, Point3d p1, Point3d p2) { + assert(inlineComponent.isInstanceOf(ProcessResource.plant3Dresource.InlineComponent)); + ControlPointTools.getInlineControlPointEnds(inlineComponent.getSingleRelatedObject(ProcessResource.plant3Dresource.HasControlPoint), p1, p2); + } + + public static void getInlineComponentEnds(IEntity inlineComponent, Point3d p1, Point3d p2, Vector3d dir) { + assert(inlineComponent.isInstanceOf(ProcessResource.plant3Dresource.InlineComponent)); + ControlPointTools.getInlineControlPointEnds(inlineComponent.getSingleRelatedObject(ProcessResource.plant3Dresource.HasControlPoint), p1, p2,dir); + } + + public static void getInlineComponentEnds(IEntity inlineComponent, Point3d center, Point3d p1, Point3d p2, Vector3d dir) { + assert(inlineComponent.isInstanceOf(ProcessResource.plant3Dresource.InlineComponent)); + ControlPointTools.getInlineControlPointEnds(inlineComponent.getSingleRelatedObject(ProcessResource.plant3Dresource.HasControlPoint), center, p1, p2,dir); + } + + public static void removePipeRun(PipeRun pipeRun) { + if (DEBUG) System.out.println("PipingTools.removePipeRun() " + pipeRun.getResource()); + G3DNode parent = pipeRun.getParent(); + if (parent != null) + parent.getChild().remove(pipeRun); + + } + /** + * Liks piperun's specs to nozzle's specs + * @param nozzle + * @param piperun + */ + public static void linkNozzleAndPipeRun(IEntity nozzle, IEntity piperun) { + assert(nozzle.isInstanceOf(ProcessResource.plant3Dresource.Nozzle)); + assert(piperun.isInstanceOf(ProcessResource.plant3Dresource.PipeRun)); + IEntity diam = piperun.getSingleRelatedObject(ProcessResource.plant3Dresource.HasPipeDiameter); + + piperun.addStatement(ProcessResource.plant3Dresource.HasControlPoints, nozzle.getSingleRelatedObject(ProcessResource.plant3Dresource.HasControlPoint)); + setStatement(nozzle, ProcessResource.plant3Dresource.HasPipeDiameter, diam); + } + + /** + * Unlinks piperun's specs from nozzle's specs. + * @param nozzle + * @param piperun + */ + public static void unlinkNozzleAndPiperun(IEntity nozzle, IEntity piperun) { + assert(nozzle.isInstanceOf(ProcessResource.plant3Dresource.Nozzle)); + assert(piperun.isInstanceOf(ProcessResource.plant3Dresource.PipeRun)); + + piperun.removeStatement(ProcessResource.plant3Dresource.HasControlPoints, nozzle.getSingleRelatedObject(ProcessResource.plant3Dresource.HasControlPoint)); + // get current diameter + double diam = nozzle.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasPipeDiameter); + // remove link to shared diameter resource + nozzle.removeRelatedStatements(ProcessResource.plant3Dresource.HasPipeDiameter); + // create new reource for diameter + nozzle.setRelatedScalarDouble(ProcessResource.plant3Dresource.HasPipeDiameter, diam); + } + + private static void setStatement(IEntity subject, Resource relation, IEntity object) { + subject.removeRelatedStatements(relation); + subject.addStatement(relation, object); + } + + public static void getInlineMovement(InlineComponent ic, Point3d start, Point3d end) { + PipeControlPoint pcp = ic.getControlPoint(); + ControlPointTools.getInlineMovement(pcp, start, end); + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/ConfigureAnimationDialog.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/ConfigureAnimationDialog.java new file mode 100644 index 00000000..de5e5aa2 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/ConfigureAnimationDialog.java @@ -0,0 +1,478 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.dialogs; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.Map.Entry; + +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.List; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Resource; +import org.simantics.db.Session; +import org.simantics.g2d.stubs.anim.Animation; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.layer0.utils.viewpoints.TraversalPath; +import org.simantics.proconf.browsing.GraphExplorer; +import org.simantics.proconf.g3d.animation.Animatable; +import org.simantics.proconf.g3d.animation.AnimationSystem; +import org.simantics.proconf.g3d.animation.ResourceAnimationController; +import org.simantics.proconf.g3d.animation.ScaledResourceAnimationController; +import org.simantics.proconf.g3d.base.ScenegraphAdapter; +import org.simantics.proconf.g3d.scenegraph.IGraphicsNode; +import org.simantics.proconf.g3d.stubs.G3DModel; +import org.simantics.proconf.g3d.tools.OEPathSelectionListener; +import org.simantics.utils.ErrorLogger; + +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.common.PathUtils; + +public class ConfigureAnimationDialog extends Dialog { + Session session; + List typeList; + List animationList; + java.util.List nodes; + Set models; + + private Composite oeLabelComposite; + //private Control viewpointControl; + private Composite oeComposite; + private GraphExplorer oe; + private Map instanceModelMap = new HashMap(); + private ScenegraphAdapter adapter; + + private Button applyAnimationButton; + + Resource selectedType; + Resource sampleInstance; + Resource sampleSource; + java.util.List samplePath; + AnimationSystem animationSystem; + + Button scaleButton; + Text minText; + Text maxText; + + public ConfigureAnimationDialog(Shell parentShell, Session session, java.util.List nodes, ScenegraphAdapter adapter, AnimationSystem animationSystem) { + super(parentShell); + this.session = session; + this.nodes = nodes; + models = new HashSet(); + session.syncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + for (Resource n : ConfigureAnimationDialog.this.nodes) { + IEntity t = EntityFactory.create(g,n); + Collection r = t.getRelatedObjects(ProcessResource.plant3Dresource.HasGraphics); + if (r.size() == 1) { + IEntity model = r.iterator().next(); + if (model.isInstanceOf(ProcessResource.g3dResource.G3DModel)) { + models.add(model.getResource()); + instanceModelMap.put(n, model.getResource()); + } else { + throw new RuntimeException("Expected G3DModel, got something else " + model); + } + } else { + ErrorLogger.getDefault().logWarning("Got node without a model", null); + } + } + return GraphRequestStatus.transactionComplete(); + } + }); + + this.adapter = adapter; + this.animationSystem = animationSystem; + int shellStyle = getShellStyle(); + setShellStyle(shellStyle | SWT.MAX | SWT.RESIZE); + } + + @Override + protected void configureShell(Shell newShell) { + super.configureShell(newShell); + newShell.setText("Configure animations"); + + } + + protected Control createDialogArea(Composite parent) { + Composite composite = (Composite) super.createDialogArea(parent); + GridLayout layout = new GridLayout(4,true); + layout.marginHeight = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN); + layout.marginWidth = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN); + layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING); + layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING); + composite.setLayout(layout); + + Label label = new Label(composite, SWT.WRAP); + label.setText("Types"); +// GridData data = new GridData(GridData.GRAB_HORIZONTAL +// | GridData.GRAB_VERTICAL | GridData.HORIZONTAL_ALIGN_FILL +// | GridData.VERTICAL_ALIGN_BEGINNING); + GridData data = new GridData(GridData.CENTER,GridData.FILL,true,false,1,1); + data.widthHint = convertHorizontalDLUsToPixels(IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH); + label.setLayoutData(data); + label.setFont(parent.getFont()); + + label = new Label(composite, SWT.WRAP); + label.setText("Models"); + label.setLayoutData(data); + label.setFont(parent.getFont()); + + label = new Label(composite, SWT.WRAP); + label.setText("Animations"); + label.setLayoutData(data); + label.setFont(parent.getFont()); + + oeLabelComposite = new Composite(composite,SWT.NONE); + data = new GridData(GridData.CENTER,GridData.FILL,true,false,1,1); + data.widthHint = convertHorizontalDLUsToPixels(IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH); + + oeLabelComposite.setLayoutData(data); + oeLabelComposite.setLayout(new FillLayout(SWT.HORIZONTAL)); + //label = new Label(composite, SWT.WRAP); + label = new Label(oeLabelComposite, SWT.WRAP); + label.setText("Animation source"); +// label.setLayoutData(data); + label.setFont(parent.getFont()); + + typeList = new List(composite, SWT.BORDER | SWT.SINGLE | SWT.READ_ONLY | SWT.V_SCROLL); + typeList.setLayoutData(new GridData(GridData.GRAB_VERTICAL | GridData.VERTICAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL)); +// modelList = new List(composite, SWT.BORDER | SWT.SINGLE | SWT.READ_ONLY | SWT.V_SCROLL); +// modelList.setLayoutData(new GridData(GridData.GRAB_VERTICAL | GridData.VERTICAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL)); + animationList = new List(composite, SWT.BORDER | SWT.SINGLE | SWT.READ_ONLY | SWT.V_SCROLL); + animationList.setLayoutData(new GridData(GridData.GRAB_VERTICAL | GridData.VERTICAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL)); + oeComposite = new Composite(composite,SWT.BORDER); + oeComposite.setLayoutData(new GridData(GridData.GRAB_VERTICAL | GridData.VERTICAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL)); + layout = new GridLayout(); + layout.marginWidth = 0; + layout.marginHeight = 0; + oeComposite.setLayout(layout); + + session.asyncRead(new GraphRequestAdapter() { + TreeMap sorter; + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + Collection types = getTypes(g,nodes); + + sorter = new TreeMap(); + for (Resource type : types) { + IEntity t = EntityFactory.create(g,type); + if (t.getRelatedObjects(ProcessResource.plant3Dresource.HasGraphics).size() > 0) { + String key = t.getName(); + if (key.equals("")) key = "ERROR (" + type.getResourceId() + ")"; + sorter.put(key, type); + } + } + + + + return GraphRequestStatus.transactionComplete(); + } + + @Override + public void requestCompleted(GraphRequestStatus status) { + getShell().getDisplay().asyncExec(new Runnable(){ + @Override + public void run() { + for (Entry e : sorter.entrySet()) { + typeList.add(e.getKey()); + typeList.setData(e.getKey(), e.getValue()); + } + } + }); + } + }); + + typeList.addSelectionListener(new SelectionListener() { + public void widgetSelected(SelectionEvent e) { + session.asyncRead(new GraphRequestAdapter(){ + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + String key = typeList.getItem(typeList.getSelectionIndex()); + selectType(EntityFactory.create(g,(Resource) typeList.getData(key))); + return GraphRequestStatus.transactionComplete(); + } + }); + + } + public void widgetDefaultSelected(SelectionEvent e) { + } + }); + +// modelList.addSelectionListener(new SelectionListener() { +// public void widgetSelected(SelectionEvent e) { +// if (modelList.getSelectionIndex() < 0 || modelList.getSelectionIndex() >= modelList.getItemCount()) +// return; +// String key = modelList.getItem(modelList.getSelectionIndex()); +// selectModel((GraphicsModel) modelList.getData(key)); +// } +// public void widgetDefaultSelected(SelectionEvent e) { +// } +// }); + + Composite buttonComposite = new Composite(composite,SWT.NONE); + buttonComposite.setLayoutData(new GridData(GridData.END,GridData.FILL,true,false,4,1)); + buttonComposite.setLayout(new FillLayout(SWT.HORIZONTAL)); + scaleButton = new Button(buttonComposite,SWT.CHECK); + scaleButton.setText("Scaling"); + scaleButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + if (scaleButton.getSelection()) { + minText.setEnabled(true); + maxText.setEnabled(true); + } else { + minText.setEnabled(false); + maxText.setEnabled(false); + } + } + }); + minText = new Text(buttonComposite,SWT.SINGLE|SWT.BORDER); + minText.setText("0.0"); + + maxText = new Text(buttonComposite,SWT.SINGLE|SWT.BORDER); + maxText.setText("1.0"); + + minText.setEnabled(false); + maxText.setEnabled(false); + + applyAnimationButton = new Button(buttonComposite,SWT.PUSH); + applyAnimationButton.setText("Apply animation"); + applyAnimationButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + session.asyncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + applyAnimation(g); + return GraphRequestStatus.transactionComplete(); + } + }); + + } + }); + return composite; + } + + /** + * Updates type selection: + * Finds all GraphicsModels that are connected to instances of selected type with HasGraphics-relation + * and lists them in modelList. + * + * @param resource + */ + private void selectType(IEntity resource) { + Graph g = resource.getGraph(); + selectedType = resource.getResource(); + //modelList.removeAll(); + animationList.removeAll(); + + Collection model = resource.getRelatedObjects(ProcessResource.plant3Dresource.HasGraphics); + if (model.size() != 1) + throw new RuntimeException("Type " + resource + " does not have a model"); + + if (oe != null) { + oe.dispose(); + } + sampleInstance = null; + sampleSource = null; + for (Resource n : nodes) { + IEntity t = EntityFactory.create(g,n); + if (t.isInstanceOf(resource.getResource())) { + sampleInstance = n; + break; + } + } + if (sampleInstance != null) { +// oe = new OntologyExplorer("Animation Source",this.getShell(), new OntologyEditorInput(sampleInstance.getId())); +// if(viewpointControl != null && !viewpointControl.isDisposed()) { +// viewpointControl.dispose(); +// } +// viewpointControl = oe.getControl(oeLabelComposite, 1, OntologyExplorer.ViewpointSelector, SWT.NONE); +// Control c = oe.getControl(oeComposite, 1, OntologyExplorer.OntologyTree, SWT.SINGLE); +// c.setLayoutData(new GridData(GridData.FILL_BOTH)); +// oe.init(null, ViewpointUtils.getModelledHandler(oe.getGraph(), Builtins.DefaultViewpointId), null, ViewLabelProviderDecorationSettings.DEFAULT, new MenuAboutToShowAction(), new NullAdditionAction(), false); +// //oeComposite.layout(true, true); +// oe.setSelectionScheme(new SourceSelectionScheme(oe)); +// //oeLabelComposite.layout(true, true); +// oeComposite.getParent().getParent().layout(true,true); + + oe = new GraphExplorer(oeComposite,SWT.SINGLE); + oe.getTree().setLayoutData(new GridData(GridData.FILL_BOTH)); + oe.getViewer().addPostSelectionChangedListener(new OEPathSelectionListener(){ + @Override + protected void pathSelectionUpdated(java.util.List paths) { + if (paths.size() == 0) { + //selectSource(null); + } else { + final TraversalPath path = paths.iterator().next(); + session.asyncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + selectSource(g,path); + return GraphRequestStatus.transactionComplete(); + } + }); + + } + } + }); + } + +// modelList.redraw(); +// animationList.redraw(); + selectModel(new G3DModel(model.iterator().next())); + } + + /** + * Selects model and shows model's animations in animationList + * @param model + */ + private void selectModel(G3DModel model) { + animationList.removeAll(); + + TreeMap sorter = new TreeMap(); + + Collection animations = model.getAnimation(); + for (Animation a : animations) { + String key = a.getName(); + if (key.equals("")) key = "ERROR (" + a.getResource().getResourceId() + ")"; + sorter.put(key, a); + } + + final TreeMap fa = sorter; + + getShell().getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + for (Entry e : fa.entrySet()) { + animationList.add(e.getKey()); + animationList.setData(e.getKey(), e.getValue()); + } + animationList.redraw(); + + } + }); + + } + + private void selectSource(Graph graph,TraversalPath path) { + //System.out.println(sampleInstance + " " + resource); + + if (path == null) { + sampleSource = null; + return; + } + IEntity t = EntityFactory.create(graph,path.getResource()); + if (!t.isInstanceOf(ProcessResource.builtins.Double)) { + sampleSource = null; + } else { + sampleSource = path.getResource(); + samplePath = new ArrayList(); + PathUtils.createPath(samplePath, path ,sampleInstance,sampleSource,oe); + } + } + + + + private void applyAnimation(Graph graph) { + int animationIndex = animationList.getSelectionIndex(); + if (sampleInstance == null || sampleSource == null || samplePath == null || animationIndex == -1) { + throw new RuntimeException("Missing required selections"); + //return; + } + + java.util.List instances = new ArrayList(); + java.util.List sources = new ArrayList(); + browseOthers(graph,instances, sources); + instances.add(sampleInstance); + sources.add(sampleSource); + + for (int i = 0; i < instances.size(); i++) { + IGraphicsNode n = adapter.getNode(instances.get(i)); + if (!(n instanceof Animatable)) { + //throw new RuntimeException("Node is not animatable"); + continue; + } + + Animatable animatable = (Animatable) n; + Animation a = (Animation) animationList.getData(animationList.getItem(animationIndex)); + if (!animatable.setAnimation(graph,a.getResource())) { + //throw new RuntimeException("Cannot set animation"); + continue; + } + ResourceAnimationController c; + if (scaleButton.getSelection()) { + c = new ScaledResourceAnimationController(sources.get(i),Double.parseDouble(minText.getText()),Double.parseDouble(maxText.getText())); + } else { + c = new ResourceAnimationController(sources.get(i)); + } + c.addAnimatable(animatable); + animationSystem.add(c); + } + + } + + private void browseOthers(Graph g, java.util.List instances,java.util.List sources) { + java.util.List possibleInstances = new ArrayList(); + for (Resource n : nodes) { + IEntity t = EntityFactory.create(g,n); + if (t.isInstanceOf(selectedType) && !n.equals(sampleInstance)) { + possibleInstances.add(n.getResource()); + } + } + + for (Resource instance : possibleInstances) { + IEntity source = PathUtils.findSimilar(samplePath,EntityFactory.create(g,instance)); + if (source != null) { + instances.add(instance); + sources.add(source.getResource()); + } else { + ErrorLogger.getDefault().logWarning("Cannot find animation source for " + instance, null); + } + } + } + + + private Collection getTypes(Graph g, java.util.List instances) { + Set types = new HashSet(); + for (Resource r : instances) { + IEntity t = EntityFactory.create(g,r); + Collection tTypes = t.getTypes(); + for (IEntity type : tTypes) + types.add(type.getResource()); + } + return types; + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/ConfigureMonitorDialog.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/ConfigureMonitorDialog.java new file mode 100644 index 00000000..a771976c --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/ConfigureMonitorDialog.java @@ -0,0 +1,309 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.dialogs; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; +import java.util.TreeMap; +import java.util.Map.Entry; + +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.List; +import org.eclipse.swt.widgets.Shell; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Resource; +import org.simantics.db.Session; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.layer0.utils.viewpoints.TraversalPath; +import org.simantics.proconf.browsing.GraphExplorer; +import org.simantics.proconf.g3d.stubs.G3DModel; +import org.simantics.proconf.g3d.tools.OEPathSelectionListener; + +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.common.PathUtils; +import fi.vtt.simantics.processeditor.monitors.PathContainer; + +public class ConfigureMonitorDialog extends Dialog { + Session session; + List typeList; + java.util.List nodes; + + + private Composite oeLabelComposite; + //private Control viewpointControl; + private Composite oeComposite; + private GraphExplorer oe; + + private Button applyAnimationButton; + + Resource selectedType; + Resource sampleInstance; + java.util.List sampleSource; + java.util.List> samplePath; + + + public ConfigureMonitorDialog(Shell parentShell, Session session, java.util.List nodes) { + super(parentShell); + this.nodes = nodes; + this.session = session; + int shellStyle = getShellStyle(); + setShellStyle(shellStyle | SWT.MAX | SWT.RESIZE); + } + + @Override + protected void configureShell(Shell newShell) { + super.configureShell(newShell); + newShell.setText("Configure monitors"); + + } + + protected Control createDialogArea(Composite parent) { + Composite composite = (Composite) super.createDialogArea(parent); + GridLayout layout = new GridLayout(2,true); + layout.marginHeight = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN); + layout.marginWidth = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN); + layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING); + layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING); + composite.setLayout(layout); + + Label label = new Label(composite, SWT.WRAP); + label.setText("Types"); + GridData data = new GridData(GridData.CENTER,GridData.FILL,true,false,1,1); + data.widthHint = convertHorizontalDLUsToPixels(IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH); + label.setLayoutData(data); + label.setFont(parent.getFont()); + + oeLabelComposite = new Composite(composite,SWT.NONE); + oeLabelComposite.setLayoutData(data); + oeLabelComposite.setLayout(new FillLayout(SWT.HORIZONTAL)); + //label = new Label(composite, SWT.WRAP); + label = new Label(oeLabelComposite, SWT.WRAP); + label.setText("Monitor source"); +// label.setLayoutData(data); + label.setFont(parent.getFont()); + + typeList = new List(composite, SWT.BORDER | SWT.SINGLE | SWT.READ_ONLY | SWT.V_SCROLL); + typeList.setLayoutData(new GridData(GridData.GRAB_VERTICAL | GridData.VERTICAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL)); + + oeComposite = new Composite(composite,SWT.BORDER); + oeComposite.setLayoutData(new GridData(GridData.GRAB_VERTICAL | GridData.VERTICAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL)); + layout = new GridLayout(); + layout.marginWidth = 0; + layout.marginHeight = 0; + oeComposite.setLayout(layout); + session.asyncRead(new GraphRequestAdapter() { + TreeMap sorter; + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + Collection types = getTypes(g,nodes); + + sorter = new TreeMap(); + for (Resource type : types) { + IEntity t = EntityFactory.create(g, type); + String key = t.getName(); + if (key.equals("")) key = "ERROR (" + type.getResourceId() + ")"; + sorter.put(key, type); + } + + + return GraphRequestStatus.transactionComplete(); + } + + @Override + public void requestCompleted(GraphRequestStatus status) { + getShell().getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + for (Entry e : sorter.entrySet()) { + typeList.add(e.getKey()); + typeList.setData(e.getKey(), e.getValue()); + } + } + }); + } + }); + + typeList.addSelectionListener(new SelectionListener() { + public void widgetSelected(SelectionEvent e) { + session.asyncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + String key = typeList.getItem(typeList.getSelectionIndex()); + selectType(EntityFactory.create(g,(Resource) typeList.getData(key))); + return GraphRequestStatus.transactionComplete(); + } + }); + + } + public void widgetDefaultSelected(SelectionEvent e) { + } + }); + + + + Composite buttonComposite = new Composite(composite,SWT.NONE); + buttonComposite.setLayoutData(new GridData(GridData.END,GridData.FILL,true,false,4,1)); + buttonComposite.setLayout(new FillLayout(SWT.HORIZONTAL)); + + + applyAnimationButton = new Button(buttonComposite,SWT.PUSH); + applyAnimationButton.setText("Apply monitor configuration"); + applyAnimationButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + applyAnimation(); + } + }); + return composite; + } + + /** + * Updates type selection: + * Finds all GraphicsModels that are connected to instances of selected type with HasGraphics-relation + * and lists them in modelList. + * + * @param resource + */ + private void selectType(IEntity resource) { + selectedType = resource.getResource(); + + TreeMap sorter = new TreeMap(); + + Collection models = resource.getRelatedObjects(ProcessResource.plant3Dresource.HasGraphics); + for (IEntity model : models) { + + String key = model.getName(); + if (key.equals("")) key = "ERROR (" + model.getResource().getResourceId() + ")"; + sorter.put(key, new G3DModel(model)); + } + + if (oe != null) { + oe.dispose(); + } + sampleInstance = null; + sampleSource = null; + for (Resource n : nodes) { + IEntity t = EntityFactory.create(resource.getGraph(),n); + if (t.isInstanceOf(resource.getResource())) { + sampleInstance = n; + break; + } + } + if (sampleInstance != null) { +// oe = new OntologyExplorer("Animation Source",this.getShell(), new OntologyEditorInput(sampleInstance.getId())); +// if(viewpointControl != null && !viewpointControl.isDisposed()) { +// viewpointControl.dispose(); +// } +// viewpointControl = oe.getControl(oeLabelComposite, 1, OntologyExplorer.ViewpointSelector, SWT.NONE); +// Control c = oe.getControl(oeComposite, 1, OntologyExplorer.OntologyTree, SWT.MULTI); +// c.setLayoutData(new GridData(GridData.FILL_BOTH)); +// oe.init(null, ViewpointUtils.getModelledHandler(oe.getGraph(), Builtins.DefaultViewpointId), null, ViewLabelProviderDecorationSettings.DEFAULT, new MenuAboutToShowAction(), new NullAdditionAction(), false); +// oe.setSelectionScheme(new SourceSelectionScheme(oe)); +// oeComposite.getParent().layout(true,true); + oe = new GraphExplorer(oeComposite,SWT.MULTI); + oe.getTree().setLayoutData(new GridData(GridData.FILL_BOTH)); + oe.getViewer().addPostSelectionChangedListener(new OEPathSelectionListener(){ + @Override + protected void pathSelectionUpdated(java.util.List paths) { + if (paths.size() == 0) { + //selectSource(null); + } else { + final java.util.List ps = paths; + session.asyncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + selectSource(g,ps); + return GraphRequestStatus.transactionComplete(); + } + }); + + } + + } + }); + } + + } + + + + private void selectSource(Graph graph, java.util.List resources) { + if (resources == null) { + sampleSource = null; + } + for (TraversalPath p : resources) { + IEntity t = EntityFactory.create(graph, p.getResource()); + if (!t.isInstanceOf(ProcessResource.builtins.Double)) { + sampleSource = null; + return; + } + } + sampleSource = new ArrayList(); + for (TraversalPath p : resources) + sampleSource.add(p.getResource()); + + samplePath = new ArrayList>(); + for (int i = 0; i < sampleSource.size(); i++) { + TraversalPath tpath = resources.get(i); + java.util.List path = new ArrayList(); + PathUtils.createPath(path, tpath,sampleInstance,sampleSource.get(i),oe); + samplePath.add(path); + } + + } + + private void applyAnimation() { + + if (sampleInstance == null || sampleSource == null || samplePath == null ) { + throw new RuntimeException("Missing required selections"); + //return; + } + + PathContainer.getInstance().clearPaths(selectedType); + for (java.util.List s : samplePath) { + PathContainer.getInstance().addPath(selectedType, s); + } + } + + + + + + private Collection getTypes(Graph g, java.util.List instances) { + Set types = new HashSet(); + for (Resource r : instances) { + IEntity t = EntityFactory.create(g,r); + Collection tTypes = t.getTypes(); + for (IEntity type : tTypes) + types.add(type.getResource()); + } + return types; + } + + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/ConfigurePipelineAnimationDialog.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/ConfigurePipelineAnimationDialog.java new file mode 100644 index 00000000..2735a69c --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/ConfigurePipelineAnimationDialog.java @@ -0,0 +1,315 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.dialogs; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Resource; +import org.simantics.db.Session; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.layer0.utils.viewpoints.TraversalPath; +import org.simantics.proconf.browsing.GraphExplorer; +import org.simantics.proconf.g3d.animation.AnimationSystem; +import org.simantics.proconf.g3d.base.JmeRenderingComponent; +import org.simantics.proconf.g3d.tools.OEPathSelectionListener; +import org.simantics.utils.ErrorLogger; + +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.animations.ResourcePipeAnimationController; +import fi.vtt.simantics.processeditor.common.PathUtils; +import fi.vtt.simantics.processeditor.stubs.PipeRun; + + +public class ConfigurePipelineAnimationDialog extends Dialog { + Session session; + java.util.List nodes; + + //private Control viewpointControl1; + private GraphExplorer oe1; + + + //private Control viewpointControl2; + private GraphExplorer oe2; + + JmeRenderingComponent component; + + private Button applyAnimationButton; + + Resource sampleInstance; + Resource sampleSource1; + Resource sampleSource2; + java.util.List samplePath1; + java.util.List samplePath2; + AnimationSystem animationSystem; + + Button scaleButton1; + Text minText1; + Text maxText1; + + Button scaleButton2; + Text minText2; + Text maxText2; + + public ConfigurePipelineAnimationDialog(Shell parentShell, Session session,java.util.List nodes, JmeRenderingComponent component, AnimationSystem animationSystem) { + super(parentShell); + this.session = session; + this.nodes = nodes; + this.component = component; + this.animationSystem = animationSystem; + int shellStyle = getShellStyle(); + setShellStyle(shellStyle | SWT.MAX | SWT.RESIZE); + } + + @Override + protected void configureShell(Shell newShell) { + super.configureShell(newShell); + newShell.setText("Configure pipeline animations"); + + } + + protected Control createDialogArea(Composite parent) { + Composite composite = (Composite) super.createDialogArea(parent); + GridLayout layout = new GridLayout(2,true); + layout.marginHeight = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN); + layout.marginWidth = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN); + layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING); + layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING); + composite.setLayout(layout); + + Label label = new Label(composite, SWT.WRAP); + label.setText("Color Change"); + GridData data = new GridData(GridData.CENTER,GridData.FILL,true,false,1,1); + data.widthHint = convertHorizontalDLUsToPixels(IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH); + label.setLayoutData(data); + label.setFont(parent.getFont()); + + label = new Label(composite, SWT.WRAP); + label.setText("Particle velocity"); + label.setLayoutData(data); + label.setFont(parent.getFont()); + + sampleInstance = nodes.get(0).getResource(); + +// oe1 = new OntologyExplorer("Animation Source",this.getShell(), new OntologyEditorInput(sampleInstance.getId())); +// viewpointControl1 = oe1.getControl(composite, 1, OntologyExplorer.ViewpointSelector, SWT.NONE); +// +// oe2 = new OntologyExplorer("Animation Source",this.getShell(), new OntologyEditorInput(sampleInstance.getId())); +// viewpointControl2 = oe2.getControl(composite, 1, OntologyExplorer.ViewpointSelector, SWT.NONE); +// +// Control c = oe1.getControl(composite, 1, OntologyExplorer.OntologyTree, SWT.SINGLE|SWT.BORDER); +// c.setLayoutData(new GridData(GridData.FILL_BOTH)); +// +// c = oe2.getControl(composite, 1, OntologyExplorer.OntologyTree, SWT.SINGLE|SWT.BORDER); +// c.setLayoutData(new GridData(GridData.FILL_BOTH)); +// +// oe1.init(null, ViewpointUtils.getModelledHandler(oe1.getGraph(), Builtins.DefaultViewpointId), null, ViewLabelProviderDecorationSettings.DEFAULT, new MenuAboutToShowAction(), new NullAdditionAction(), false); +// oe1.setSelectionScheme(new SourceSelectionScheme(oe1)); +// +// oe2.init(null, ViewpointUtils.getModelledHandler(oe1.getGraph(), Builtins.DefaultViewpointId), null, ViewLabelProviderDecorationSettings.DEFAULT, new MenuAboutToShowAction(), new NullAdditionAction(), false); +// oe2.setSelectionScheme(new SourceSelectionScheme(oe2)); + + oe1 = new GraphExplorer(composite,SWT.SINGLE); + oe1.getTree().setLayoutData(new GridData(GridData.FILL_BOTH)); + + oe2 = new GraphExplorer(composite,SWT.SINGLE); + oe2.getTree().setLayoutData(new GridData(GridData.FILL_BOTH)); + + oe1.getViewer().addPostSelectionChangedListener(new OEPathListener(oe1)); + oe2.getViewer().addPostSelectionChangedListener(new OEPathListener(oe2)); + + + Composite buttonComposite = new Composite(composite,SWT.NONE); + buttonComposite.setLayoutData(new GridData(GridData.END,GridData.FILL,true,false,1,1)); + buttonComposite.setLayout(new FillLayout(SWT.HORIZONTAL)); + + scaleButton1 = new Button(buttonComposite,SWT.CHECK); + scaleButton1.setText("Scaling"); + scaleButton1.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + if (scaleButton1.getSelection()) { + minText1.setEnabled(true); + maxText1.setEnabled(true); + } else { + minText1.setEnabled(false); + maxText1.setEnabled(false); + } + } + }); + minText1 = new Text(buttonComposite,SWT.SINGLE|SWT.BORDER); + minText1.setText("0.0"); + + maxText1 = new Text(buttonComposite,SWT.SINGLE|SWT.BORDER); + maxText1.setText("1.0"); + + minText1.setEnabled(false); + maxText1.setEnabled(false); + + buttonComposite = new Composite(composite,SWT.NONE); + buttonComposite.setLayoutData(new GridData(GridData.END,GridData.FILL,true,false,1,1)); + buttonComposite.setLayout(new FillLayout(SWT.HORIZONTAL)); + + scaleButton2 = new Button(buttonComposite,SWT.CHECK); + scaleButton2.setText("Scaling"); + scaleButton2.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + if (scaleButton2.getSelection()) { + minText2.setEnabled(true); + maxText2.setEnabled(true); + } else { + minText2.setEnabled(false); + maxText2.setEnabled(false); + } + } + }); + minText2 = new Text(buttonComposite,SWT.SINGLE|SWT.BORDER); + minText2.setText("0.0"); + + maxText2 = new Text(buttonComposite,SWT.SINGLE|SWT.BORDER); + maxText2.setText("1.0"); + + minText2.setEnabled(false); + maxText2.setEnabled(false); + + + applyAnimationButton = new Button(composite,SWT.PUSH); + applyAnimationButton.setText("Apply animation"); + applyAnimationButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + session.syncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + applyAnimation(g); + return GraphRequestStatus.transactionComplete(); + } + }); + + } + }); + applyAnimationButton.setLayoutData(new GridData(GridData.END,GridData.FILL,true,false,2,1)); + return composite; + } + + private class OEPathListener extends OEPathSelectionListener { + GraphExplorer oe; + + public OEPathListener(GraphExplorer oe) { + this.oe = oe; + } + + protected void pathSelectionUpdated(List paths) { + if (paths.size() == 0) { + //selectSource(null); + } else { + selectSource(oe,paths.get(0)); + } + } + } + + private void selectSource(GraphExplorer oe,TraversalPath path) { + Graph graph = null; + IEntity t = EntityFactory.create(graph,path.getResource()); + if (!t.isInstanceOf(ProcessResource.builtins.Double)) + return; + if (oe == oe1) { + sampleSource1 = path.getResource(); + samplePath1 = new ArrayList(); + PathUtils.createPath(samplePath1, path,sampleInstance,sampleSource1,oe); + } else if (oe == oe2) { + sampleSource2 = path.getResource(); + samplePath2 = new ArrayList(); + PathUtils.createPath(samplePath2, path,sampleInstance,sampleSource2,oe); + } + } + + + + + private void applyAnimation(Graph graph) { + if (sampleInstance == null || sampleSource1 == null || sampleSource2 == null || samplePath1 == null|| samplePath2 == null) { + throw new RuntimeException("Missing required selections"); + //return; + } + java.util.List instances1 = new ArrayList(); + java.util.List instances2 = new ArrayList(); + java.util.List sources1 = new ArrayList(); + java.util.List sources2 = new ArrayList(); + browseOthers(instances1, sources1,samplePath1); + browseOthers(instances2, sources2,samplePath2); + instances1.add(sampleInstance); + instances2.add(sampleInstance); // instances1 == instances2 + sources1.add(sampleSource1); + sources2.add(sampleSource2); + + for (int i = 0; i < instances1.size(); i++) { + + double cMin = 0.0; + double cMax = 1.0; + double vMin = 0.0; + double vMax = 0.0; + + if (scaleButton1.getSelection()) { + cMin = Double.parseDouble(minText1.getText()); + cMax = Double.parseDouble(maxText1.getText()); + } + if (scaleButton2.getSelection()) { + vMin = Double.parseDouble(minText2.getText()); + vMax = Double.parseDouble(maxText2.getText()); + } + ResourcePipeAnimationController c = new ResourcePipeAnimationController(component, new PipeRun(graph,instances1.get(i)),sources1.get(i),cMin,cMax,sources2.get(i),vMin,vMax); + + animationSystem.add(c); + } + + } + + private void browseOthers(java.util.List instances,java.util.List sources,java.util.List samplePath) { + Graph graph = null; + java.util.List possibleInstances = new ArrayList(); + for (Resource n : nodes) { + possibleInstances.add(n); + } + + for (Resource instance : possibleInstances) { + IEntity source = PathUtils.findSimilar(samplePath,EntityFactory.create(graph,instance)); + if (source != null) { + instances.add(instance); + sources.add(source.getResource()); + } else { + ErrorLogger.getDefault().logWarning("Cannot find animation source for " + instance, null); + } + } + } + + + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/EquipmentDialog.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/EquipmentDialog.java new file mode 100644 index 00000000..cf194301 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/EquipmentDialog.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.dialogs; + +import org.eclipse.swt.widgets.Shell; +import org.simantics.db.Session; + + +import fi.vtt.simantics.processeditor.ProcessResource; + +public class EquipmentDialog extends LibraryComponentDialog { + + + public EquipmentDialog(Shell parentShell, String dialogTitle, Session session) { + super(parentShell,session,ProcessResource.plant3Dresource.Equipment,dialogTitle); + + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/LibraryComponentDialog.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/LibraryComponentDialog.java new file mode 100644 index 00000000..6909fb63 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/LibraryComponentDialog.java @@ -0,0 +1,195 @@ +package fi.vtt.simantics.processeditor.dialogs; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Stack; + +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.List; +import org.eclipse.swt.widgets.Shell; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Resource; +import org.simantics.db.Session; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.proconf.ui.ProConfUI; +import org.simantics.utils.ErrorLogger; + +import fi.vtt.simantics.processeditor.ProcessResource; + +public class LibraryComponentDialog extends Dialog{ + + private List typeList; + private Resource selectedType = null; + private Session session; + private String title; + + private Resource primaryType; + private Collection requiredTypes = new ArrayList(); + private Collection filteredTypes = new ArrayList(); + + public LibraryComponentDialog(Shell shell, Session session, Resource primaryType, String title) { + super(shell); + assert(title != null); + this.session = session; + this.title = title; + this.primaryType = primaryType; + } + + + protected void setFilter(Collection filter) { + this.filteredTypes = filter; + } + + protected void setRequired(Collection required) { + this.requiredTypes = required; + } + + + @Override + protected void configureShell(Shell newShell) { + + super.configureShell(newShell); + newShell.setText(title); + } + + public Resource getComboValue() { + return selectedType; + } + + protected Control createDialogArea(Composite parent) { + Composite composite = (Composite) super.createDialogArea(parent); + + Label label = new Label(composite, SWT.WRAP); + label.setText("Select Component"); + GridData data = new GridData(GridData.GRAB_HORIZONTAL + | GridData.GRAB_VERTICAL | GridData.HORIZONTAL_ALIGN_FILL + | GridData.VERTICAL_ALIGN_CENTER); + data.widthHint = convertHorizontalDLUsToPixels(IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH); + label.setLayoutData(data); + label.setFont(parent.getFont()); + // TODO : list populating is done in random order; change to alphabetic + typeList = new List(composite, SWT.BORDER | SWT.SINGLE | SWT.READ_ONLY | SWT.V_SCROLL); + typeList.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL)); + + typeList.addSelectionListener(new SelectionListener() { + public void widgetSelected(SelectionEvent e) { + String key = typeList.getItem(typeList.getSelectionIndex()); + selectedType = (Resource) typeList.getData(key); + } + public void widgetDefaultSelected(SelectionEvent e) { + } + }); + getShell().setText(title + " loading..."); + session.asyncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + loadComponents(g); + return GraphRequestStatus.transactionComplete(); + } + + @Override + public void requestCompleted(GraphRequestStatus status) { + getDialogArea().getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + getShell().setText(title); + if (selectedType == null) { + typeList.select(0); + selectedType = (Resource)typeList.getData(typeList.getItem(0)); + } + } + + }); + } + }); + + GridData data2 = new GridData(GridData.GRAB_HORIZONTAL + | GridData.GRAB_VERTICAL | GridData.HORIZONTAL_ALIGN_FILL + | GridData.VERTICAL_ALIGN_FILL); + data2.widthHint = convertHorizontalDLUsToPixels(IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH); + data2.heightHint = 200; + typeList.setLayoutData(data2); + typeList.setFont(parent.getFont()); + + typeList.showSelection(); + + applyDialogFont(composite); + return composite; + } + + private void loadComponents(Graph g) { + Resource projectResource = ProConfUI.getProject().getResource(); + Stack handling = new Stack(); + handling.push(projectResource); + while (!handling.isEmpty()) { + final Resource node = handling.pop(); + if (g.isInstanceOf(node,primaryType)) { + IEntity equipment = EntityFactory.create(g, node); + Collection graphics = equipment + .getRelatedObjects(ProcessResource.plant3Dresource.HasGraphics); + if (graphics.size() != 1) { + ErrorLogger.defaultLogError("Equipment " + + equipment.getName() + " has " + graphics.size() + + " + graphical representation!", null); + } else { + boolean add = true; + for (Resource r : requiredTypes) { + if (!equipment.isInstanceOf(r)) { + add = false; + break; + } + } + if (add) { + for (Resource r : filteredTypes) { + if (equipment.isInstanceOf(r)) { + add = false; + break; + } + } + } + if (add) { + final String name = equipment.getName(); + getDialogArea().getDisplay().asyncExec(new Runnable() { + public void run() { + // List won't work with two ore more same names. + if (typeList.getData(name)!= null) { + String n = new String(name); + int i = 1; + while (true) { + n = name +"("+i+")"; + if (typeList.getData(n)== null) { + typeList.add(n); + typeList.setData(n, node); + break; + } + } + } else { + typeList.add(name); + typeList.setData(name, node); + } + } + }); + } + } + } else { + handling.addAll(g.getObjects(node, + ProcessResource.builtins.ConsistsOf)); + } + + } + + } + + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/NozzleDialog.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/NozzleDialog.java new file mode 100644 index 00000000..282c9ce6 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/NozzleDialog.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.dialogs; + +import org.eclipse.swt.widgets.Shell; +import org.simantics.db.Session; + + +import fi.vtt.simantics.processeditor.ProcessResource; + +public class NozzleDialog extends LibraryComponentDialog { + + + public NozzleDialog(Shell parentShell, String dialogTitle, Session session) { + super(parentShell,session,ProcessResource.plant3Dresource.Nozzle,dialogTitle); + + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/PipelineComponentDialog.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/PipelineComponentDialog.java new file mode 100644 index 00000000..a7510b4d --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/PipelineComponentDialog.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.dialogs; + +import java.util.Collection; + +import org.eclipse.swt.widgets.Shell; +import org.simantics.db.Resource; +import org.simantics.db.Session; + + + +import fi.vtt.simantics.processeditor.ProcessResource; + +public class PipelineComponentDialog extends LibraryComponentDialog{ + + + public PipelineComponentDialog(Shell parentShell, Collection requiredTypes, Collection filteredTypes, Session session) { + super(parentShell,session,ProcessResource.plant3Dresource.PipelineComponent,"Select Component"); + if (requiredTypes != null) + setRequired(requiredTypes); + if (filteredTypes != null) + setFilter(filteredTypes); + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/PipelineDialog.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/PipelineDialog.java new file mode 100644 index 00000000..5cf1ea40 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/PipelineDialog.java @@ -0,0 +1,132 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.dialogs; + +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.KeyEvent; +import org.eclipse.swt.events.KeyListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; + +public class PipelineDialog extends Dialog implements KeyListener{ + Text pipeRadiusText; + Text turnRadiusText; + + double pipeDiameter = 0.0; + double turnRadius = 0.0; + + public PipelineDialog(Shell parentShell) { + super(parentShell); + } + + public PipelineDialog(Shell parentShell, double pipeRadius, double turnRadius) { + super(parentShell); + this.pipeDiameter = pipeRadius; + this.turnRadius = turnRadius; + } + + + @Override + protected void configureShell(Shell newShell) { + super.configureShell(newShell); + newShell.setText("Configure new pipeline"); + } + + @Override + protected Control createDialogArea(Composite parent) { + Composite composite = (Composite) super.createDialogArea(parent); + Label label = new Label(composite, SWT.WRAP); + label.setText("Input pipeline specifications"); + GridData data = new GridData(GridData.GRAB_HORIZONTAL + | GridData.GRAB_VERTICAL | GridData.HORIZONTAL_ALIGN_FILL + | GridData.VERTICAL_ALIGN_CENTER); + + data.widthHint = convertHorizontalDLUsToPixels(IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH); + label.setLayoutData(data); + label.setFont(parent.getFont()); + label = new Label(composite, SWT.WRAP); + label.setText("Pipe diameter"); + label.setLayoutData(data); + label.setFont(parent.getFont()); + pipeRadiusText = new Text(composite,SWT.BORDER); + pipeRadiusText.setLayoutData(data); + label = new Label(composite, SWT.WRAP); + label.setText("Pipe elbow/turn radius"); + label.setLayoutData(data); + label.setFont(parent.getFont()); + turnRadiusText = new Text(composite,SWT.BORDER); + turnRadiusText.setLayoutData(data); + + pipeRadiusText.addKeyListener(this); + turnRadiusText.addKeyListener(this); + if (pipeDiameter > 0.0 && turnRadius > 0.0) { + pipeRadiusText.setText(Double.toString(pipeDiameter)); + turnRadiusText.setText(Double.toString(turnRadius)); + } + + + return composite; + } + + @Override + public int open() { + return super.open(); + } + + + + + public void keyPressed(KeyEvent e) { + + + } + + public void keyReleased(KeyEvent e) { + boolean ok = true; + try { + pipeDiameter = Double.parseDouble(pipeRadiusText.getText()); + turnRadius = Double.parseDouble(turnRadiusText.getText()); + if (pipeDiameter <= 0.0) + ok = false; + if (turnRadius <= 0.0) + ok = false; + + } catch (NumberFormatException err) { + ok = false; + } + if (ok) { + this.getButton(IDialogConstants.OK_ID).setEnabled(true); + } else { + this.getButton(IDialogConstants.OK_ID).setEnabled(false); + } + } + + + public double getPipeDiameter() { + return pipeDiameter; + } + + + public double getTurnRadius() { + return turnRadius; + } + + + + + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/gizmo/PositionSelectionGizmo.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/gizmo/PositionSelectionGizmo.java new file mode 100644 index 00000000..62d36858 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/gizmo/PositionSelectionGizmo.java @@ -0,0 +1,177 @@ +package fi.vtt.simantics.processeditor.gizmo; + +import java.net.URL; +import java.util.ArrayList; +import java.util.List; + +import javax.vecmath.Point3d; + +import org.eclipse.core.runtime.FileLocator; +import org.eclipse.core.runtime.Path; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.base.VecmathJmeTools; +import org.simantics.proconf.g3d.gizmo.Gizmo; +import org.simantics.utils.datastructures.Pair; + +import com.jme.bounding.BoundingSphere; +import com.jme.image.Image; +import com.jme.image.Texture; +import com.jme.math.Vector3f; +import com.jme.renderer.Renderer; +import com.jme.scene.BillboardNode; +import com.jme.scene.Node; +import com.jme.scene.shape.Quad; +import com.jme.scene.state.AlphaState; +import com.jme.scene.state.LightState; +import com.jme.scene.state.TextureState; +import com.jme.scene.state.ZBufferState; +import com.jme.util.TextureManager; + +import fi.vtt.simantics.processeditor.Activator; +import fi.vtt.simantics.processeditor.actions.PositionType; + +/** + * Gizmo that allows user to selected insertion point of a component + * TODO : for splits we want use line between component ends to + * position the button, instead of its center point. + * + * @author Marko Luukkainen + * + */ +public class PositionSelectionGizmo implements Gizmo { + + private static String PICK_PREFIX = "insert"; + private static String SPLIT_TEXTURE = "icons/middle.png"; + private static String END_TEXTURE = "icons/plus.png"; + private static String PORT_TEXTURE = END_TEXTURE; + + private ThreeDimensionalEditorBase parent; + + private boolean changed = false; + private int selected = -1; + private boolean useDistanceResize = true; + + private List nodes; + private List alphaStates; + private Node rootNode; + + public PositionSelectionGizmo(ThreeDimensionalEditorBase parent, List> positions) { + this.parent = parent; + rootNode = new Node(); + rootNode.setCullMode(Node.CULL_NEVER); + rootNode.setRenderQueueMode(Renderer.QUEUE_TRANSPARENT); + rootNode.setLightCombineMode(LightState.OFF); + int i = 0; + nodes = new ArrayList(); + alphaStates = new ArrayList(); + // create a button (billboard) for each insertion position + + ZBufferState zs = parent.getRenderingComponent().getDisplaySystem().getRenderer().createZBufferState(); + zs.setFunction(ZBufferState.CF_ALWAYS); + + for (Pair p : positions) { + BillboardNode node = new BillboardNode(""); + nodes.add(node); + Quad quad = new Quad(PICK_PREFIX + i,1.f,1.f); + + TextureState ts = parent.getRenderingComponent().getDisplaySystem().getRenderer().createTextureState(); + String filename = ""; + switch (p.second) { + case NEXT: + case PREVIOUS: + filename = END_TEXTURE; + break; + case SPLIT: + filename = SPLIT_TEXTURE; + break; + case PORT: + filename = PORT_TEXTURE; + } + URL url = FileLocator.find(Activator.getDefault().getBundle(), new Path(filename),null); + Image image = TextureManager.loadImage(url, true); + Texture texture = new Texture(); + texture.setImage(image); + texture.setFilter(Texture.FM_LINEAR); + ts.setTexture(texture); + quad.setRenderState(ts); + + AlphaState as = parent.getRenderingComponent().getDisplaySystem().getRenderer().createAlphaState(); + as.setSrcFunction(AlphaState.SB_SRC_ALPHA); + as.setDstFunction(AlphaState.DB_ONE_MINUS_SRC_ALPHA); + as.setBlendEnabled(true); + alphaStates.add(as); + quad.setRenderState(as); + quad.setRenderState(zs); + + node.attachChild(quad); + node.setLocalTranslation(VecmathJmeTools.get(p.first)); + quad.setModelBound(new BoundingSphere(0.5f,new Vector3f())); + quad.updateModelBound(); + rootNode.attachChild(node); + + i++; + } + } + + + @Override + public Node getNode() { + return rootNode; + } + + @Override + public String getPickPrefix() { + return PICK_PREFIX; + } + + @Override + public boolean isChanged() { + return changed; + } + + @Override + public void setChanged(boolean b) { + changed = b; + } + + @Override + public void setSelected(String name) { + if (name == null) { + setSelected(-1); + return; + } + assert(name.startsWith(PICK_PREFIX)); + setSelected(Integer.parseInt(name.substring(PICK_PREFIX.length()))); + } + + private void setSelected(int i) { + if (selected == i) + return; + if (selected != -1) { + alphaStates.get(selected).setDstFunction(AlphaState.DB_ONE_MINUS_SRC_ALPHA); + nodes.get(selected).getChild(0).setRenderState(alphaStates.get(selected)); + } + selected = i; + if (selected != -1) { + alphaStates.get(selected).setDstFunction(AlphaState.DB_ONE); + nodes.get(selected).getChild(0).setRenderState(alphaStates.get(selected)); + } + parent.setViewChanged(true); + } + + public int getSelected() { + return selected; + } + + public void update() { + if (useDistanceResize) { + Vector3f v = VecmathJmeTools.get(parent.getCamera().getCameraPos()); + for (BillboardNode n : nodes) { + float length = v.subtract(n.getWorldTranslation()).length(); + n.setLocalScale(length * 0.06f); + } + } + } + + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/EquipmentEditorAdapter.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/EquipmentEditorAdapter.java new file mode 100644 index 00000000..6339ca45 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/EquipmentEditorAdapter.java @@ -0,0 +1,40 @@ +package fi.vtt.simantics.processeditor.handlers; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.proconf.ui.workbench.ResourceEditorInput; +import org.simantics.proconf.ui.workbench.editor.SimpleEditorAdapter; +import org.simantics.utils.ui.BundleUtils; +import org.simantics.utils.ui.workbench.WorkbenchUtils; + +import fi.vtt.simantics.processeditor.Activator; +import fi.vtt.simantics.processeditor.ProcessResource; + +/** + * EditorAdapter for EquipmentEditor + * + * @author Marko Luukkainen + * + */ +public class EquipmentEditorAdapter extends SimpleEditorAdapter { + public EquipmentEditorAdapter() { + super("Equipment Editor", + BundleUtils.getImageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/tank.png"), + null,null,null); + } + + @Override + public boolean canHandle(Graph g, Resource r) { + if(ProcessResource.plant3Dresource == null) return false; + if(ProcessResource.plant3Dresource.Plant == null) return false; + if(!g.isInstanceOf(r, ProcessResource.plant3Dresource.Equipment)) return false; + return true; + } + + + @Override + public void openEditor(Resource r) throws Exception { + WorkbenchUtils.openEditor("org.simantics.proconf.processeditor.equipmenteditor", new ResourceEditorInput("org.simantics.proconf.processeditor.equipmenteditor",r)); + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/NewComponentHandler.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/NewComponentHandler.java new file mode 100644 index 00000000..7cb2be98 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/NewComponentHandler.java @@ -0,0 +1,290 @@ +package fi.vtt.simantics.processeditor.handlers; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.handlers.HandlerUtil; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Resource; +import org.simantics.layer0.stubs.Library; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.layer0.utils.instantiation.InstanceFactory; +import org.simantics.proconf.ui.ProConfUI; +import org.simantics.proconf.ui.utils.ResourceAdaptionUtils; + +import fi.vtt.simantics.processeditor.ProcessResource; + + +/** + * Handler that creates new pipeline components. + * + * @author Marko Luukkainen + * + */ +public class NewComponentHandler extends AbstractHandler { + + private Map nameMap; + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + ISelection s = HandlerUtil.getCurrentSelectionChecked(event); + IStructuredSelection ss = (IStructuredSelection) s; + if (ss.size() != 1) + return null; + final Resource lib = ResourceAdaptionUtils.toSingleResource(ss); + + + + if (nameMap == null) { + ProConfUI.getSession().syncRead(new GraphRequestAdapter(){ + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + nameMap = new HashMap(); + for (Resource r : getComponentTypes()) { + IEntity e = EntityFactory.create(g,r); + nameMap.put(r, e.getName()); + for (Resource r2 : getComponentOptions(r)) { + IEntity e2 = EntityFactory.create(g,r2); + nameMap.put(r2, e2.getName()); + } + } + return GraphRequestStatus.transactionComplete(); + } + }); + } + + ComponentTypeDialog dialog = new ComponentTypeDialog(Display.getDefault().getActiveShell()); + if (dialog.open() == ComponentTypeDialog.CANCEL) + return null; + final List types = dialog.getSelection(); + final String name = dialog.getName(); + + if (types.size() == 0 || name == null || name.length() == 0) + return null; + + ProConfUI.getSession().asyncWrite(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + // instantiate component + IEntity instance = EntityFactory.create(g, InstanceFactory.instantiate(g, types)); + Library l = new Library(g, lib); + l.addStatement(g.getBuiltins().ConsistsOf, instance); + instance.setName(name); + + // TODO : is this correct (instance & inherits) + for (Resource type : types) { + instance.addStatement(ProcessResource.builtins.Inherits, type); + } + + // instantiate control point(s) + List cpTypes = getControlPointTypes(types); + boolean isDual = (cpTypes.contains(ProcessResource.plant3Dresource.SizeChangeControlPoint) || + cpTypes.contains(ProcessResource.plant3Dresource.OffsettingPoint)); + IEntity cp = EntityFactory.create(g, InstanceFactory.instantiate(g, cpTypes)); + instance.addStatement(ProcessResource.plant3Dresource.HasControlPoint, cp); + if (isDual) { + IEntity subCP = EntityFactory.create(g, InstanceFactory.instantiate(g, ProcessResource.plant3Dresource.DualSubControlPoint)); + cp.addStatement(ProcessResource.plant3Dresource.HasSubPoint, subCP); + } + // instantiate model + Resource modelType = g.getResourceByURI("http://www.vtt.fi/Simantics/CSG/1.0/Types#CSGModel"); + IEntity model = EntityFactory.create(g, InstanceFactory.instantiate(g, modelType)); + instance.addStatement(ProcessResource.plant3Dresource.HasGraphics, model); + + return GraphRequestStatus.transactionComplete(); + } + }); + + + return null; + } + + /** + * Returns all possible types for a pipeline component + * @return + */ + private List getComponentTypes() { + List list = new ArrayList(); + list.add(ProcessResource.plant3Dresource.FixedLengthInlineComponent); + list.add(ProcessResource.plant3Dresource.VariableLengthInlineComponent); + list.add(ProcessResource.plant3Dresource.VariableAngleTurnComponent); + list.add(ProcessResource.plant3Dresource.FixedAngleTurnComponent); + list.add(ProcessResource.plant3Dresource.EndComponent); + list.add(ProcessResource.plant3Dresource.Nozzle); + + return list; + } + + /** + * Returns optional types for a component type + * @param type + * @return + */ + private List getComponentOptions(Resource type) { + List list = new ArrayList(); + if (type.equals(ProcessResource.plant3Dresource.FixedLengthInlineComponent)) { + list.add(ProcessResource.plant3Dresource.SizeChangeComponent); + list.add(ProcessResource.plant3Dresource.OffsetComponent); + } + return list; + } + + /** + * Returns control point type(s) for given control point type. + * + * @param types + * @return + */ + private List getControlPointTypes(List types) { + Resource primaryType = types.get(0); + List cpTypes = new ArrayList(); + if (primaryType == ProcessResource.plant3Dresource.FixedLengthInlineComponent) { + if (types.size() == 1) { + cpTypes.add(ProcessResource.plant3Dresource.FixedLengthControlPoint); + } else { + if (types.contains(ProcessResource.plant3Dresource.SizeChangeComponent)) { + cpTypes.add(ProcessResource.plant3Dresource.SizeChangeControlPoint); + } + if (types.contains(ProcessResource.plant3Dresource.OffsetComponent)) { + cpTypes.add(ProcessResource.plant3Dresource.OffsettingPoint); + } + if (cpTypes.size() == 0) { + throw new RuntimeException("Cannot find control point type for " + primaryType); + } + } + + } else if (primaryType == ProcessResource.plant3Dresource.VariableLengthInlineComponent) { + cpTypes.add(ProcessResource.plant3Dresource.VariableLengthControlPoint); + } else if (primaryType == ProcessResource.plant3Dresource.FixedAngleTurnComponent) { + cpTypes.add(ProcessResource.plant3Dresource.FixedAngleTurnControlPoint); + } else if (primaryType == ProcessResource.plant3Dresource.VariableAngleTurnComponent) { + cpTypes.add(ProcessResource.plant3Dresource.VariableAngleTurnControlPoint); + } else if (primaryType == ProcessResource.plant3Dresource.EndComponent) { + cpTypes.add(ProcessResource.plant3Dresource.EndComponentControlPoint); + } else if (primaryType == ProcessResource.plant3Dresource.Nozzle) { + cpTypes.add(ProcessResource.plant3Dresource.NozzleControlPoint); + } else { + throw new RuntimeException("Cannot find control point type for " + primaryType); + } + + return cpTypes; + } + + + private class ComponentTypeDialog extends Dialog { + + List selected = new ArrayList(); + String name; + + public ComponentTypeDialog(Shell shell) { + super(shell); + } + + @Override + protected Control createDialogArea(Composite parent) { + Composite composite = (Composite) super.createDialogArea(parent); + Label label = new Label(composite,SWT.NONE); + label.setText("Name:"); + Text text = new Text(composite,SWT.SINGLE|SWT.BORDER); + text.addModifyListener(new ModifyListener() { + @Override + public void modifyText(ModifyEvent e) { + name = ((Text)e.widget).getText(); + } + }); + GridData data = new GridData(); + data.grabExcessHorizontalSpace = true; + data.horizontalAlignment = SWT.FILL; + text.setLayoutData(data); + label = new Label(composite,SWT.NONE); + label.setText("Type:"); + for (Resource r : getComponentTypes()) { + final Button b = new Button(composite,SWT.RADIO); + b.setText(nameMap.get(r)); + b.setData(r); + b.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + Button button = (Button)e.widget; + Resource res = (Resource)button.getData(); + if (button.getSelection()) { + selected.add(0,res); + } else { + selected.remove(res); + } + } + }); + data = new GridData(); + b.setLayoutData(data); + for (Resource r2 : getComponentOptions(r)) { + final Button b2 = new Button(composite,SWT.CHECK); + b2.setText(nameMap.get(r2)); + b2.setData(r2); + b.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + b2.setEnabled(b.getSelection()); + Resource res = (Resource)b2.getData(); + if (!b.getSelection()) { + selected.remove(res); + } else if (b2.getSelection()) { + selected.add(res); + } + } + }); + b2.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + Button button = (Button)e.widget; + Resource res = (Resource)button.getData(); + if (button.getSelection()) { + selected.add(res); + } else { + selected.remove(res); + } + } + }); + b2.setEnabled(false); + data = new GridData(); + data.horizontalIndent = convertWidthInCharsToPixels(2); + b2.setLayoutData(data); + } + } + + return composite; + } + + List getSelection() { + return selected; + } + + public String getName() { + return name; + } + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/NewEquipmentHandler.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/NewEquipmentHandler.java new file mode 100644 index 00000000..49eb77ef --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/NewEquipmentHandler.java @@ -0,0 +1,110 @@ +package fi.vtt.simantics.processeditor.handlers; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.handlers.HandlerUtil; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Resource; +import org.simantics.layer0.stubs.Library; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.layer0.utils.instantiation.InstanceFactory; +import org.simantics.proconf.ui.ProConfUI; +import org.simantics.proconf.ui.utils.ResourceAdaptionUtils; + +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.stubs.Equipment; + +/** + * Creates new equipment + * + * @author Marko Luukkainen + * + */ +public class NewEquipmentHandler extends AbstractHandler { + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + ISelection s = HandlerUtil.getCurrentSelectionChecked(event); + IStructuredSelection ss = (IStructuredSelection) s; + if (ss.size() != 1) + return null; + final Resource lib = ResourceAdaptionUtils.toSingleResource(ss); + + EquipmentDialog dialog = new EquipmentDialog(Display.getDefault().getActiveShell()); + if (dialog.open() == EquipmentDialog.CANCEL) + return null; + final String name = dialog.getName(); + if (name == null || name.length() == 0) + return null; + ProConfUI.getSession().asyncWrite(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + Equipment equipment = Equipment.createDefault(g); + Library l = new Library(g, lib); + l.addStatement(g.getBuiltins().ConsistsOf, equipment); + + // TODO : is this correct (instance & inherits) + equipment.addStatement(ProcessResource.builtins.Inherits, ProcessResource.plant3Dresource.Equipment); + + Resource modelType = g.getResourceByURI("http://www.vtt.fi/Simantics/CSG/1.0/Types#CSGModel"); + IEntity model = EntityFactory.create(g, InstanceFactory.instantiate(g, modelType)); + equipment.addStatement(ProcessResource.plant3Dresource.HasGraphics, model); + equipment.setName(name); + return GraphRequestStatus.transactionComplete(); + } + }); + + + return null; + } + + private class EquipmentDialog extends Dialog { + + private String name; + + public EquipmentDialog(Shell shell) { + super(shell); + } + + @Override + protected Control createDialogArea(Composite parent) { + Composite composite = (Composite) super.createDialogArea(parent); + Label label = new Label(composite,SWT.NONE); + label.setText("Name:"); + Text text = new Text(composite,SWT.SINGLE|SWT.BORDER); + text.addModifyListener(new ModifyListener() { + @Override + public void modifyText(ModifyEvent e) { + name = ((Text)e.widget).getText(); + } + }); + GridData data = new GridData(); + data.grabExcessHorizontalSpace = true; + data.horizontalAlignment = SWT.FILL; + text.setLayoutData(data); + return composite; + } + + public String getName() { + return name; + } + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/NewPlantHandler.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/NewPlantHandler.java new file mode 100644 index 00000000..45f54cf5 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/NewPlantHandler.java @@ -0,0 +1,95 @@ +package fi.vtt.simantics.processeditor.handlers; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.handlers.HandlerUtil; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Resource; +import org.simantics.layer0.stubs.Library; +import org.simantics.proconf.ui.ProConfUI; +import org.simantics.proconf.ui.utils.ResourceAdaptionUtils; + +import fi.vtt.simantics.processeditor.stubs.Plant; + +public class NewPlantHandler extends AbstractHandler { + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + ISelection s = HandlerUtil.getCurrentSelectionChecked(event); + IStructuredSelection ss = (IStructuredSelection) s; + if (ss.size() != 1) + return null; + final Resource lib = ResourceAdaptionUtils.toSingleResource(ss); + + PlantDialog dialog = new PlantDialog(Display.getDefault().getActiveShell()); + if (dialog.open() == PlantDialog.CANCEL) + return null; + final String name = dialog.getName(); + if (name == null || name.length() == 0) + return null; + + ProConfUI.getSession().asyncWrite(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + Plant model = Plant.createDefault(g); + model.setName(name); + Library l = new Library(g, lib); + l.addStatement(g.getBuiltins().ConsistsOf, model); + + return GraphRequestStatus.transactionComplete(); + } + }); + + + return null; + } + + private class PlantDialog extends Dialog { + + private String name; + + public PlantDialog(Shell shell) { + super(shell); + } + + @Override + protected Control createDialogArea(Composite parent) { + Composite composite = (Composite) super.createDialogArea(parent); + Label label = new Label(composite,SWT.NONE); + label.setText("Name:"); + Text text = new Text(composite,SWT.SINGLE|SWT.BORDER); + text.addModifyListener(new ModifyListener() { + @Override + public void modifyText(ModifyEvent e) { + name = ((Text)e.widget).getText(); + } + }); + GridData data = new GridData(); + data.grabExcessHorizontalSpace = true; + data.horizontalAlignment = SWT.FILL; + text.setLayoutData(data); + return composite; + } + + public String getName() { + return name; + } + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/PipelineComponentEditorAdapter.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/PipelineComponentEditorAdapter.java new file mode 100644 index 00000000..2523fa1e --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/PipelineComponentEditorAdapter.java @@ -0,0 +1,45 @@ +package fi.vtt.simantics.processeditor.handlers; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.proconf.ui.workbench.ResourceEditorInput; +import org.simantics.proconf.ui.workbench.editor.SimpleEditorAdapter; +import org.simantics.utils.ui.BundleUtils; +import org.simantics.utils.ui.workbench.WorkbenchUtils; + +import fi.vtt.simantics.processeditor.Activator; +import fi.vtt.simantics.processeditor.ProcessResource; + +/** + * EditorAdapter for PipeLineComponentEditor + * + * @author Marko Luukkainen + * + */ +public class PipelineComponentEditorAdapter extends SimpleEditorAdapter { + public PipelineComponentEditorAdapter() { + super("Component Editor", + BundleUtils.getImageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/Component.png"), + null,null,null); + } + + @Override + public boolean canHandle(Graph g, Resource r) { + if(ProcessResource.plant3Dresource == null) return false; + if(ProcessResource.plant3Dresource.Plant == null) return false; + if(!g.isInstanceOf(r, ProcessResource.plant3Dresource.PipelineComponent)) { + if (g.isInstanceOf(r, ProcessResource.plant3Dresource.Nozzle)) + return true; + return false; + } + if(g.isInstanceOf(r, ProcessResource.plant3Dresource.CodedComponent)) return false; + return true; + } + + + @Override + public void openEditor(Resource r) throws Exception { + WorkbenchUtils.openEditor("org.simantics.proconf.processeditor.componenteditor", new ResourceEditorInput("org.simantics.proconf.processeditor.componenteditor",r)); + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/Plant3DEditorAdapter.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/Plant3DEditorAdapter.java new file mode 100644 index 00000000..93edd948 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/Plant3DEditorAdapter.java @@ -0,0 +1,34 @@ +package fi.vtt.simantics.processeditor.handlers; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.proconf.ui.workbench.ResourceEditorInput; +import org.simantics.proconf.ui.workbench.editor.SimpleEditorAdapter; +import org.simantics.utils.ui.BundleUtils; +import org.simantics.utils.ui.workbench.WorkbenchUtils; + +import fi.vtt.simantics.processeditor.Activator; +import fi.vtt.simantics.processeditor.ProcessResource; + +public class Plant3DEditorAdapter extends SimpleEditorAdapter { + public Plant3DEditorAdapter() { + super("PlantEditor", + BundleUtils.getImageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/factory.png"), + null,null,null); + } + + @Override + public boolean canHandle(Graph g, Resource r) { + if(ProcessResource.plant3Dresource == null) return false; + if(ProcessResource.plant3Dresource.Plant == null) return false; + return g.isInstanceOf(r, ProcessResource.plant3Dresource.Plant); + } + + + @Override + public void openEditor(Resource r) throws Exception { + WorkbenchUtils.openEditor("org.simantics.proconf.processeditor.planteditor", new ResourceEditorInput("org.simantics.proconf.processeditor.planteditor",r)); + + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/Plant3DProjectAdapter.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/Plant3DProjectAdapter.java new file mode 100644 index 00000000..305b6362 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/Plant3DProjectAdapter.java @@ -0,0 +1,14 @@ +package fi.vtt.simantics.processeditor.handlers; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.db.adaption.AdaptionException; +import org.simantics.db.adaption.ResourceAdapter; + +public class Plant3DProjectAdapter implements ResourceAdapter { + @SuppressWarnings("unchecked") + @Override + public T adapt(Graph graph, Resource resource, Resource mia) throws AdaptionException { + return (T) new Plant3DProjectType(graph,resource); + } +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/Plant3DProjectType.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/Plant3DProjectType.java new file mode 100644 index 00000000..f1121176 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/handlers/Plant3DProjectType.java @@ -0,0 +1,53 @@ +package fi.vtt.simantics.processeditor.handlers; + +import java.util.ArrayList; +import java.util.Collection; + +import org.simantics.db.Builtins; +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.layer0.utils.direct.GraphUtils; +import org.simantics.proconf.ui.projects.IProject; +import org.simantics.proconf.ui.projects.ProjectType; + +public class Plant3DProjectType extends ProjectType{ + + public Plant3DProjectType(Graph graph, Resource projectTypeResource) { + super(graph, projectTypeResource); + } + + @Override + public Resource createProject(Graph g, String name) throws Exception { + Resource project = super.createProject(g, name); + Builtins b = g.getBuiltins(); + { // Plants + Resource modelLibrary = g.newResource(); + g.addStatement(modelLibrary, b.InstanceOf, b.ModelLibrary); + GraphUtils.addRelatedScalarString(g, modelLibrary, b.HasName, "Plants"); + g.addStatement(project, b.ConsistsOf, modelLibrary); + } + { // Equipment + Resource modelLibrary = g.newResource(); + g.addStatement(modelLibrary, b.InstanceOf, b.ModelLibrary); + GraphUtils.addRelatedScalarString(g, modelLibrary, b.HasName, "Equipment"); + g.addStatement(project, b.ConsistsOf, modelLibrary); + } + return project; + + } + + @Override + public IProject loadProject(Graph g, Resource r) { + + IProject project = super.loadProject(g, r); + project.set(DefaultPerspective, "org.simantics.proconf.processeditor.plantmodelling"); + Collection perspectives = new ArrayList(); + perspectives.add("org.simantics.proconf.processeditor.plantmodelling"); + project.set(Perspectives, perspectives); + + return project; + } + + + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/BillboardMonitor.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/BillboardMonitor.java new file mode 100644 index 00000000..d35d62c1 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/BillboardMonitor.java @@ -0,0 +1,216 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.monitors; + +import java.awt.Color; +import java.util.ArrayList; + +import javax.vecmath.Point3d; +import javax.vecmath.Vector3d; + +import org.simantics.db.Graph; +import org.simantics.proconf.g3d.base.G3DTools; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.base.VecmathJmeTools; +import org.simantics.proconf.g3d.scenegraph.IGraphicsNode; +import org.simantics.proconf.g3d.stubs.G3DNode; + +import com.jme.image.Texture; +import com.jme.math.Vector3f; +import com.jme.renderer.ColorRGBA; +import com.jme.renderer.Renderer; +import com.jme.scene.BillboardNode; +import com.jme.scene.Node; +import com.jme.scene.shape.Quad; +import com.jme.scene.state.AlphaState; +import com.jme.scene.state.MaterialState; +import com.jme.scene.state.RenderState; +import com.jme.scene.state.TextureState; +import com.jme.scene.state.ZBufferState; +import com.jmex.awt.swingui.ImageGraphics; + + +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.stubs.InlineComponent; + + + +/** + * A monitor that uses billboard to show it's information. + * + * @author Marko Luukkainen + * + */ +//TODO : should it be variable length / fixed length inline component instead of Straight + +public class BillboardMonitor implements Monitor{ + private enum Type{POSITION,PIPE}; + private Type type; + private ThreeDimensionalEditorBase editor; + private BillboardNode monitorNode = null; + private int monitorSize = 128; + private ImageGraphics graphics = ImageGraphics.createInstance(monitorSize, monitorSize, 0); + private Node currentParent = null; + private IGraphicsNode node = null; + private boolean useDistanceResize = true; + + Point3d start; + Point3d end; + Point3d middle; + + private MonitorTextProvider provider = new ObjectPropertyProvider(); + + + public BillboardMonitor(ThreeDimensionalEditorBase editor) { + this.editor = editor; + monitorNode = new BillboardNode(""); + monitorNode.setRenderQueueMode(Renderer.QUEUE_TRANSPARENT); + ZBufferState zs = editor.getRenderingComponent() + .getDisplaySystem().getRenderer().createZBufferState(); + zs.setEnabled(true); + zs.setFunction(ZBufferState.CF_ALWAYS); + monitorNode.setRenderState(zs); + Quad quad = new Quad(""); + quad.initialize(3.f, 3.f); + monitorNode.attachChild(quad); + // SWTImageGraphics graphics = + // SWTImageGraphics.createInstance(64,64, 0); + + graphics.clearRect(0, 0, monitorSize, monitorSize); + + // graphics.setFont(new Font("Arial",Font.PLAIN,30)); + // graphics.setColor(Display.getDefault().getSystemColor(SWT.COLOR_GREEN)); + graphics.setColor(new Color(0, 255, 0, 255)); + graphics.drawString("Monitor", 0, 32); + + TextureState ts = editor.getRenderingComponent().getDisplaySystem().getRenderer().createTextureState(); + Texture texture = new Texture(); + texture.setApply(Texture.AM_MODULATE); + // texture.setBlendColor(new ColorRGBA(1, 1, 1, 1)); + texture.setFilter(Texture.MM_LINEAR); + texture.setMipmapState(Texture.FM_LINEAR); + texture.setImage(graphics.getImage()); + graphics.update(); + AlphaState as = editor.getRenderingComponent().getDisplaySystem() + .getRenderer().createAlphaState(); + as.setBlendEnabled(true); + as.setSrcFunction(AlphaState.SB_SRC_ALPHA); + as.setDstFunction(AlphaState.DB_ONE_MINUS_SRC_ALPHA); + as.setTestEnabled(true); + as.setTestFunction(AlphaState.TF_GREATER); + ts.setTexture(texture); + MaterialState ms = editor.getRenderingComponent().getDisplaySystem().getRenderer().createMaterialState(); + ms.setEmissive(new ColorRGBA(1.f, 1.f, 1.f, 0.f)); + monitorNode.setRenderState(ts); + monitorNode.setRenderState(as); + monitorNode.setRenderState(ms); + graphics.drawLine(0, 33, monitorSize-1, 33); + graphics.update(); + } + + public boolean acceptNode(Graph graph, IGraphicsNode node) { + Node selectedParent = node.getGroup(); + if (currentParent == null || !selectedParent.equals(currentParent)) { + if (node.getG3DNode(graph).getLocalPosition() != null) { + return true; + } else if (node.getG3DNode(graph).isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent)) { + + return true; + } + } + + return false; + } + + public void setNode(Graph graph, IGraphicsNode node) { + G3DNode n = node.getG3DNode(graph); + if (n.getLocalPosition() != null) { + type = Type.POSITION; + monitorNode.setLocalTranslation(new Vector3f(0.f,0.f,0.f)); + } else if (n.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent)) { + type = Type.PIPE; + InlineComponent ic = new InlineComponent(n); + start = G3DTools.getPoint(ic.getControlPoint().getPrevious().getLocalPosition()); + end = G3DTools.getPoint(ic.getControlPoint().getNext().getLocalPosition()); + Vector3d dir = new Vector3d(end); + dir.sub(start); + dir.scale(0.5); + middle = new Point3d(start); + middle.add(dir); + monitorNode.setLocalTranslation(VecmathJmeTools.get(middle)); + } else { + return; + } + Node selectedParent = node.getGroup(); + this.node = node; + currentParent = selectedParent; + monitorNode.removeFromParent(); + currentParent.attachChild(monitorNode); + + provider.setSource(n); + update(graph); + } + + public IGraphicsNode getNode() { + return node; + } + + public void update() { + if (useDistanceResize) { + Vector3f v = VecmathJmeTools.get(editor.getCamera().getCameraPos()); + v.subtractLocal(monitorNode.getWorldTranslation()); + float length = v.length(); + monitorNode.setLocalScale(length * 0.06f); + } + } + + + public void update(Graph graph) { + ArrayList titles = provider.getTexts(graph); + graphics.clearRect(0, 0, monitorSize, monitorSize); + int y = 16; + for (String s : titles) { + graphics.drawString(s, 0, y); + y += 16; + } + + TextureState ts = (TextureState) monitorNode + .getRenderState(RenderState.RS_TEXTURE); + ts.deleteAll(); // FIXME : texture won't be updated without this + graphics.update(); + update(); + } + + public void remove() { + monitorNode.removeFromParent(); + node = null; + } + + /** + * if true, monitors size is independent of distance to camera. Else monitor's size changes when camera is moved. + * @return + */ + public boolean isUseDistanceResize() { + return useDistanceResize; + } + + public void setUseDistanceResize(boolean useDistanceResize) { + this.useDistanceResize = useDistanceResize; + if (!useDistanceResize) { + monitorNode.setLocalScale(1.f); + } + } + + public void setTextProvider(MonitorTextProvider provider) { + this.provider = provider; + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/Monitor.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/Monitor.java new file mode 100644 index 00000000..d748b175 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/Monitor.java @@ -0,0 +1,62 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.monitors; + +import org.simantics.db.Graph; +import org.simantics.proconf.g3d.scenegraph.IGraphicsNode; + + + + +/** + * Interface for monitors (Textual display of objects properties) + * + * @author Marko Luukkainen + * + */ +public interface Monitor { + + /** + * Returns true if monitor can be attached to node + * @param node + * @return + */ + public boolean acceptNode(Graph graph,IGraphicsNode node); + + /** + * Returns the scene-graph node where monitor is attached + * @return + */ + public IGraphicsNode getNode(); + + /** + * Sets monitored node + * @param node + */ + public void setNode(Graph graph,IGraphicsNode node); + + /** + * Updates monitor's texts + * + */ + public void update(); + + public void update(Graph graph); + + /** + * Removes the monitor. + */ + public void remove(); + + + public void setTextProvider(MonitorTextProvider provider); + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/MonitorTextProvider.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/MonitorTextProvider.java new file mode 100644 index 00000000..08b3b02b --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/MonitorTextProvider.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.monitors; + +import java.util.ArrayList; + +import org.simantics.db.Graph; +import org.simantics.layer0.utils.IEntity; + + + +public interface MonitorTextProvider { + public void setSource(IEntity instance); + public ArrayList getTexts(Graph graph); +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/ObjectPropertyProvider.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/ObjectPropertyProvider.java new file mode 100644 index 00000000..f0945609 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/ObjectPropertyProvider.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.monitors; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.layer0.utils.ResourceDebugUtils; + + +import fi.vtt.simantics.processeditor.ProcessResource; + + +public class ObjectPropertyProvider implements MonitorTextProvider { + + private Resource instance; + private Resource properties[]; + String name; + + public void setSource(IEntity instance) { + this.instance = instance.getResource(); + Collection props = instance.getRelatedObjects(ProcessResource.builtins.HasProperty); + List res = new ArrayList(); + for (IEntity t : props) + res.add(t.getResource()); + properties = new Resource[res.size()]; + properties = res.toArray(properties); + name = ResourceDebugUtils.getReadableNameForEntity(instance); + } + + public ArrayList getTexts(Graph graph) { + ArrayList titles = new ArrayList(); + if (instance == null) + return titles; + IEntity thing = EntityFactory.create(graph,instance); + name = ResourceDebugUtils.getReadableNameForEntity(thing); + titles.add(name); + + for (Resource p : properties) { + thing = EntityFactory.create(graph,p); + //if (p.isInstanceOf(Builtins.Double)) { + //typeResources = p.getRelatedResources(Builtins.InstanceOf); + //name = PropertyUtils.getScalarStringProperty(typeResources[0],Builtins.HasName); + name = ResourceDebugUtils.getReadableNameForEntity(thing); + titles.add(name); + //} + } + return titles; + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/PathContainer.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/PathContainer.java new file mode 100644 index 00000000..4c2aab7e --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/PathContainer.java @@ -0,0 +1,61 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.monitors; + +import java.util.Collection; +import java.util.List; + +import org.simantics.db.Resource; +import org.simantics.layer0.utils.IEntity; +import org.simantics.utils.datastructures.MapList; + + +/** + * Container for Paths + * FIXME : singleton + * TODO : removing paths + * TODO : prevent adding same path multiple times + * + * + * @author Marko Luukkainen + * + */ +public class PathContainer { + + private static PathContainer instance = new PathContainer(); + + MapList> paths; + + private PathContainer() { + paths = new MapList>(); + } + + public List> getPaths(IEntity instance) { + Collection types = instance.getTypes(); + if (types.size() != 1) + throw new UnsupportedOperationException("Multi-instances not supported!"); + Resource type = types.iterator().next().getResource(); + return paths.getValues(type); + } + + public void addPath(Resource type, List path) { + paths.add(type, path); + } + + public void clearPaths(Resource type) { + paths.remove(type); + } + + public static PathContainer getInstance() { + return instance; + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/ResourcePathPropertyProvider.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/ResourcePathPropertyProvider.java new file mode 100644 index 00000000..75812333 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/ResourcePathPropertyProvider.java @@ -0,0 +1,87 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.monitors; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.layer0.utils.ResourceDebugUtils; + +import fi.vtt.simantics.processeditor.common.PathUtils; + + +public class ResourcePathPropertyProvider implements MonitorTextProvider { + + private Resource instance; + private List properties = new ArrayList(); + private List names = new ArrayList(); + private List units = new ArrayList(); + String name; + + private MonitorTextProvider provider = new ObjectPropertyProvider(); + + public void setSource(IEntity instance) { + this.instance = instance.getResource(); + properties.clear(); + names.clear(); + //units.clear(); + List> paths = PathContainer.getInstance().getPaths(instance); + if (paths != null) { + for (List path : paths) { + IEntity source = PathUtils.findSimilar(path, instance); + if (source != null) + properties.add(source.getResource()); + } + } + Collection types = instance.getTypes(); + name = ResourceDebugUtils.getReadableNameForEntity(types.iterator().next()); + for (Resource p : properties) { + names.add(ResourceDebugUtils.getReadableNameForEntity(EntityFactory.create(instance.getGraph(),p))); +// if (p.isInstanceOf(Builtins.Double)) { +// typeResources = p.getRelatedResources(Builtins.InstanceOf); +// String name = PropertyUtils.getScalarStringProperty(typeResources[0],Builtins.HasName); +// Property property = new Property(p); +// String abbr = property.getUnitAbbreviation(); +// names.add(name); +// if (abbr != null) +// units.add(abbr); +// else +// units.add(""); +// //titles.add(name + " " + PropertyUtils.getDoubleValue(p)[0] + " " + abbr); +// } + } + provider.setSource(instance); + } + + public ArrayList getTexts(Graph graph) { + if (properties.size() == 0) + return provider.getTexts(graph); + ArrayList titles = new ArrayList(); + if (instance == null) + return titles; + + titles.add(name); + for (int i = 0; i < properties.size(); i++) { + //titles.add(names.get(i) + " " + Double.toString(PropertyUtils.getDoubleValue(properties.get(i))[0]) + " " + units.get(i)); + // FIXME : check value + titles.add(names.get(i) + " " + EntityFactory.create(graph,properties.get(i)).toProperty().getValue()); + } + + return titles; + } + + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/TextMonitor.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/TextMonitor.java new file mode 100644 index 00000000..41c60a6b --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/monitors/TextMonitor.java @@ -0,0 +1,272 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.monitors; + +import java.net.URL; +import java.util.ArrayList; + +import javax.vecmath.Point3d; +import javax.vecmath.Vector3d; + +import org.eclipse.core.runtime.FileLocator; +import org.eclipse.core.runtime.Path; +import org.eclipse.swt.graphics.Rectangle; +import org.simantics.db.Graph; +import org.simantics.proconf.g3d.base.G3DTools; +import org.simantics.proconf.g3d.base.MathTools; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.base.VecmathJmeTools; +import org.simantics.proconf.g3d.scenegraph.IGraphicsNode; +import org.simantics.proconf.g3d.stubs.G3DNode; + +import com.jme.image.Texture; +import com.jme.math.Vector2f; +import com.jme.math.Vector3f; +import com.jme.renderer.ColorRGBA; +import com.jme.renderer.Renderer; +import com.jme.scene.Node; +import com.jme.scene.Text; +import com.jme.scene.shape.Quad; +import com.jme.scene.state.AlphaState; +import com.jme.scene.state.MaterialState; +import com.jme.scene.state.RenderState; +import com.jme.scene.state.TextureState; +import com.jme.util.TextureManager; + +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.stubs.InlineComponent; + +/** + * A monitor implemetation that uses JME's text component to show it's information. + * + * @author Marko Luukkainen + * + */ +public class TextMonitor implements Monitor { + private enum Type{POSITION,PIPE}; + private Type type; + + public static String fontLocation = "data/textures/tahoma512.png"; + + + private ThreeDimensionalEditorBase editor; + private ArrayList texts = new ArrayList(); + private Node monitorNode = new Node(""); + Node textNode; + private IGraphicsNode node = null; + + Point3d start; + Point3d end; + Point3d middle; + + float width = 0.f; + float height = 0.f; + float textHeight = 0.f; + + Quad background; + + private MonitorTextProvider provider = new ObjectPropertyProvider(); + + public TextMonitor(ThreeDimensionalEditorBase editor) { + this.editor = editor; + textNode = new Node(""); + + + + AlphaState as1 = editor.getRenderingComponent().getDisplaySystem().getRenderer().createAlphaState(); + as1.setBlendEnabled(true); + as1.setSrcFunction(AlphaState.SB_SRC_ALPHA); + as1.setDstFunction(AlphaState.DB_ONE_MINUS_SRC_ALPHA); + as1.setTestEnabled(true); + as1.setTestFunction(AlphaState.TF_GREATER); + as1.setEnabled(true); + + MaterialState ms = editor.getRenderingComponent().getDisplaySystem().getRenderer().createMaterialState(); + ms.setEmissive(new ColorRGBA(0.f,1.f,0.f,0.f)); + + TextureState font = editor.getRenderingComponent().getDisplaySystem().getRenderer().createTextureState(); + /** The texture is loaded from fontLocation */ + font.setTexture(loadFontTexture()); + font.setEnabled(true); + textNode.setRenderState(font); + textNode.setRenderState(as1); + textNode.setRenderState(ms); + background = new Quad("",100.f,100.f); + + MaterialState ms2 = editor.getRenderingComponent().getDisplaySystem().getRenderer().createMaterialState(); + ms2.setEmissive(new ColorRGBA(0.f,0.f,0.f,0.8f)); + ms2.setDiffuse(new ColorRGBA(0.f,0.f,0.f,0.8f)); + + AlphaState as2 = editor.getRenderingComponent().getDisplaySystem().getRenderer().createAlphaState(); + as2.setBlendEnabled(true); + as2.setSrcFunction(AlphaState.SB_SRC_ALPHA); + as2.setDstFunction(AlphaState.DB_ONE_MINUS_SRC_ALPHA); + as2.setTestEnabled(true); + as2.setTestFunction(AlphaState.TF_GREATER); + as2.setEnabled(true); + monitorNode.setRenderState(ms2); + monitorNode.setRenderState(as2); + + background.setRenderQueueMode(Renderer.QUEUE_ORTHO); + textNode.setRenderQueueMode(Renderer.QUEUE_ORTHO); + + monitorNode.attachChild(background); + monitorNode.attachChild(textNode); + // editor.getRenderingComponent().getOrthoNode().attachChild(monitorNode); + + + } + + public boolean acceptNode(Graph graph,IGraphicsNode node) { + G3DNode n = node.getG3DNode(graph); + if (this.node == null || !node.equals(this.node)) { + if (n.getLocalPosition() != null) { + return true; + } else if (n.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent)) { + return true; + } + } + + return false; + + } + + public void setNode(Graph graph, IGraphicsNode node) { + G3DNode n = node.getG3DNode(graph); + if (n.getLocalPosition() != null) { + type = Type.POSITION; + } else if (n.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent)) { + type = Type.PIPE; + InlineComponent ic = new InlineComponent(n); + start = G3DTools.getPoint(ic.getControlPoint().getPrevious().getWorldPosition()); + end = G3DTools.getPoint(ic.getControlPoint().getNext().getWorldPosition()); + Vector3d dir = new Vector3d(end); + dir.sub(start); + dir.scale(0.5); + middle = new Point3d(start); + middle.add(dir); + } else { + return; + } + + this.node = node; + provider.setSource(n); + ArrayList titles = provider.getTexts(graph); + + for (int i = titles.size() - 1; i < texts.size(); i++) { + texts.get(i).removeFromParent(); + } + while (texts.size() < titles.size()) { + Text text = new Text("", ""); + texts.add(text); + textNode.attachChild(text); + } + width = 0.f; + height = 0.f; + for (int i = 0; i < titles.size(); i++) { + Text text = texts.get(i); + text.print(titles.get(i)); + width = Math.max(width,text.getWidth()); + textHeight = text.getHeight(); + height += textHeight; + textNode.attachChild(text); + } + background.resize(width+20.f, height+10.f); + if (monitorNode.getParent() == null) + editor.getScenegraphAdapter().getRoot().attachChild(monitorNode); + + } + + private void updateText(Graph graph) { + ArrayList titles = provider.getTexts(graph); + float newWidth = 0.f; + for (int i = 0; i < titles.size(); i++) { + Text text = texts.get(i); + text.print(titles.get(i)); + newWidth = Math.max(newWidth,text.getWidth()); + } + if (newWidth != width) { + width = newWidth; + background.resize(width+20.f, height+10.f); + } + + } + + public void update() { + if (node == null) + return; + Vector2f v; + + if (type == Type.POSITION) { + v = editor.getScreenCoord(VecmathJmeTools.getD(node.getGroup().getWorldTranslation())); + } else { + float mx = editor.getRenderingComponent().getDisplaySystem().getWidth(); + float my = editor.getRenderingComponent().getDisplaySystem().getHeight(); + Vector2f s = editor.getScreenCoord(start); + Vector2f e = editor.getScreenCoord(end); + Vector2f rs = new Vector2f(); + Vector2f re = new Vector2f(); + boolean in = MathTools.clipLineRectangle(s, e, new Vector2f(0.f,0.f), new Vector2f(mx,my), rs, re); + if (in) { + re.subtractLocal(rs); + re.multLocal(0.5f); + rs.addLocal(re); + v = rs; + } else { + // just a hack to move monitor out of the view + v = new Vector2f (mx+width,my+height); + } + + + } + background.setLocalTranslation(new Vector3f(v.x,v.y,0.f)); + float y = v.y + (height * 0.5f) - textHeight; + v.x -= width * 0.5f; + + for (Text text : texts) { + text.setLocalTranslation(new Vector3f(v.x,y,0.f)); + y -= textHeight; + } + + + + } + + @Override + public void update(Graph graph) { + updateText(graph); + update(); + } + + public IGraphicsNode getNode() { + return node; + } + + public void remove() { + monitorNode.removeFromParent(); + node = null; + } + + protected Texture loadFontTexture() { + URL url = FileLocator.find(com.jme.eclipse.Activator.getDefault().getBundle(),new Path(fontLocation),null); + return TextureManager.loadTexture(url, Texture.MM_LINEAR, + Texture.FM_LINEAR); + } + + public void setTextProvider(MonitorTextProvider provider) { + this.provider = provider; + } + + + + + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/perspectives/Plant3DModellingPerspective.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/perspectives/Plant3DModellingPerspective.java new file mode 100644 index 00000000..f7cceaa6 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/perspectives/Plant3DModellingPerspective.java @@ -0,0 +1,13 @@ +package fi.vtt.simantics.processeditor.perspectives; + +import org.eclipse.ui.IPageLayout; +import org.eclipse.ui.IPerspectiveFactory; + +public class Plant3DModellingPerspective implements IPerspectiveFactory{ + + @Override + public void createInitialLayout(IPageLayout layout) { + + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/perspectives/ViewpointGenerator.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/perspectives/ViewpointGenerator.java new file mode 100644 index 00000000..03c7a5c2 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/perspectives/ViewpointGenerator.java @@ -0,0 +1,108 @@ +package fi.vtt.simantics.processeditor.perspectives; + +import java.util.Collection; + +import org.simantics.db.Builtins; +import org.simantics.layer0.utils.IEntity; +import org.simantics.layer0.utils.Statement; +import org.simantics.layer0.utils.viewpoints.AcceptDecision; +import org.simantics.layer0.utils.viewpoints.AcceptRule; +import org.simantics.layer0.utils.viewpoints.PlainStateFactory; +import org.simantics.layer0.utils.viewpoints.ResourceViewpoint; +import org.simantics.layer0.utils.viewpoints.State; +import org.simantics.layer0.utils.viewpoints.StateFactory; +import org.simantics.layer0.utils.viewpoints.TraversalDecision; +import org.simantics.layer0.utils.viewpoints.TraversalRule; +import org.simantics.layer0.utils.viewpoints.rules.AcceptAllResourceAcceptRule; + +import fi.vtt.simantics.processeditor.ProcessResource; + +public class ViewpointGenerator { + public static ResourceViewpoint createViewpoint() { + StateFactory f = new PlainStateFactory(); + final State rootState = f.newState(); + final State projectState = f.newState(); + final State libraryState = f.newState(); + + return new ResourceViewpoint(new TraversalRule() { + @Override + public TraversalDecision makeTraversalDecision(State state, Statement statement) { + Builtins b = statement.getGraph().getBuiltins(); + if (state.equals(rootState)) { + if (statement.getObject().isInstanceOf(b.Ontology)) + return TraversalDecision.stopTraversal; + if(!statement.getPredicate().equals(b.ConsistsOf)) + return TraversalDecision.stopTraversal; + return TraversalDecision.continueTraversal(projectState); + } else if (state.equals(projectState)) { + if(!statement.getPredicate().equals(b.ConsistsOf)) + return TraversalDecision.stopTraversal; + return TraversalDecision.continueTraversal(libraryState); + } else if (state.equals(libraryState)) { + if(!statement.getPredicate().equals(b.ConsistsOf)) + return TraversalDecision.stopTraversal; + return TraversalDecision.continueTraversal(libraryState); + } + return TraversalDecision.stopTraversal; + } + + @Override + public boolean areAllStatesRelevant() { + return true; + } + + @Override + public Collection relevantStates() { + return null; + } + }, new AcceptRule() { + @Override + public AcceptDecision makeAcceptDecision(State state, IEntity obj) { + Builtins b = obj.getGraph().getBuiltins(); + //NOSEResource nr = NOSEResource.getInstance(obj.getGraph()); + if(obj.isInstanceOf(b.Project)) return AcceptDecision.REJECT; + else if (obj.isInstanceOf(b.Ontology)) return AcceptDecision.REJECT; + else return AcceptDecision.ACCEPT; + } + + @Override + public boolean areAllStatesRelevant() { + return true; + } + + @Override + public Collection relevantStates() { + return null; + } + }, rootState); + } + + public static ResourceViewpoint createObjectStructureViewpoint() { + StateFactory f = new PlainStateFactory(); + final State rootState = f.newState(); + + return new ResourceViewpoint(new TraversalRule() { + @Override + public TraversalDecision makeTraversalDecision(State state, + Statement statement) { + if (state.equals(rootState)) { + if (!statement.getPredicate().isSubrelationOf( + ProcessResource.g3dResource.HasChild)) + return TraversalDecision.stopTraversal; + return TraversalDecision.continueTraversal(rootState); + } + return TraversalDecision.stopTraversal; + } + + @Override + public boolean areAllStatesRelevant() { + return true; + } + + @Override + public Collection relevantStates() { + return null; + } + }, new AcceptAllResourceAcceptRule(), rootState); + } +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/scenegraph/NonVisibleNode.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/scenegraph/NonVisibleNode.java new file mode 100644 index 00000000..240dd866 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/scenegraph/NonVisibleNode.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.scenegraph; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.proconf.g3d.scenegraph.IGraphicsNode; +import org.simantics.proconf.g3d.scenegraph.NonTransformableNode; + +import fi.vtt.simantics.processeditor.ProcessResource; + +public class NonVisibleNode extends NonTransformableNode { + + public NonVisibleNode(IGraphicsNode parent, Graph graph, Resource resource) { + super(parent,resource); + if (!getG3DNode(graph).isInstanceOf(ProcessResource.plant3Dresource.NonVisibleComponent)) + throw new RuntimeException("Resource must be instance of NonVisibleComponent"); + + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/scenegraph/PipeComponentNode.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/scenegraph/PipeComponentNode.java new file mode 100644 index 00000000..2c204a27 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/scenegraph/PipeComponentNode.java @@ -0,0 +1,107 @@ +package fi.vtt.simantics.processeditor.scenegraph; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import javax.vecmath.AxisAngle4d; +import javax.vecmath.Quat4d; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.scenegraph.IGraphicsNode; +import org.simantics.proconf.g3d.scenegraph.ShapeNode; + +import com.jme.math.Quaternion; +import com.jme.renderer.ColorRGBA; +import com.jme.scene.Geometry; +import com.jme.scene.state.MaterialState; +import com.jme.scene.state.RenderState; + +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.common.ControlPointTools; +import fi.vtt.simantics.processeditor.common.PipingTools; +import fi.vtt.simantics.processeditor.stubs.CodedComponent; +import fi.vtt.simantics.processeditor.stubs.PipeControlPoint; +import fi.vtt.simantics.processeditor.stubs.Plant3DResource; +import fi.vtt.simantics.processeditor.stubs.SizeChangeControlPoint; + + +/** + * This is for hard-coded geometries + * TODO : we need an extension point for geometries, + * so that other code-based geometries can be supported + * + * + * @author Marko Luukkainen + * + */ +public class PipeComponentNode extends ShapeNode { + + enum Type{ELBOW,STRAIGHT,REDUCER}; + + Type type; + Resource controlPoint; + + + public PipeComponentNode(ThreeDimensionalEditorBase editor, IGraphicsNode parent, Graph graph, Resource resource) { + super(editor, parent, graph, resource); + CodedComponent component = new CodedComponent(graph,resource); + PipeControlPoint cp = component.getControlPoint(); + Plant3DResource p3r = ProcessResource.plant3Dresource; + controlPoint = cp.getResource(); + + if (component.isInstanceOf(p3r.Elbow)) { + type = Type.ELBOW; + } else if (component.isInstanceOf(p3r.Straight)) { + type = Type.STRAIGHT; + } else if (component.isInstanceOf(p3r.Elbow)) { + type = Type.REDUCER; + } + + + } + + @Override + public Collection getMaterial() { + MaterialState ms = null; + ms = editor.getRenderingComponent().getDisplaySystem().getRenderer().createMaterialState(); + ms.setEmissive(new ColorRGBA(0.f,0.f,0.f,0.f)); + ms.setSpecular(new ColorRGBA(1.f,1.f,1.f,1.f)); + ms.setEnabled(true); + ms.setShininess(128.f); + if (type == Type.ELBOW) { + ms.setDiffuse(new ColorRGBA(0.5f,0.5f,0.5f,0.f)); + ms.setAmbient(new ColorRGBA(0.5f,0.5f,0.5f,0.f)); + } else if (type == Type.STRAIGHT) { + ms.setDiffuse(new ColorRGBA(0.75f,0.75f,0.75f,0.f)); + ms.setAmbient(new ColorRGBA(0.75f,0.75f,0.75f,0.f)); + } else { + ms.setDiffuse(new ColorRGBA(0.6f,0.6f,0.6f,0.f)); + ms.setAmbient(new ColorRGBA(0.6f,0.6f,0.6f,0.f)); + } + List states = new ArrayList(); + states.add(ms); + return states; + } + + + @Override + public void updateTransform(Graph graph) { + if (type == Type.REDUCER) { + SizeChangeControlPoint sccp = new SizeChangeControlPoint(graph, controlPoint); + Quat4d q = ControlPointTools.getControlPointLocalOrientationQuat(sccp, sccp.getRotationAngle()[0], true); + update(q); + } + if (type != Type.STRAIGHT) { + super.updateTransform(graph); + } else { + transform.setLocalTranslation(0.f,0.f,0.f); + transform.setLocalRotation(new Quaternion()); + } + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/scenegraph/PipeRunNode.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/scenegraph/PipeRunNode.java new file mode 100644 index 00000000..b03a36fb --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/scenegraph/PipeRunNode.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.scenegraph; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.proconf.g3d.scenegraph.IGraphicsNode; +import org.simantics.proconf.g3d.scenegraph.NonTransformableNode; + +import fi.vtt.simantics.processeditor.ProcessResource; + +public class PipeRunNode extends NonTransformableNode { + + public PipeRunNode(IGraphicsNode parent, Graph graph, Resource resource) { + super(parent,resource); + if (!getG3DNode(graph).isInstanceOf(ProcessResource.plant3Dresource.PipeRun)) + throw new RuntimeException("Resource must be instance of Pipeline"); + + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/scenegraph/PipelineComponentNode.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/scenegraph/PipelineComponentNode.java new file mode 100644 index 00000000..07f20eb1 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/scenegraph/PipelineComponentNode.java @@ -0,0 +1,87 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.scenegraph; + +import javax.vecmath.AxisAngle4d; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.scenegraph.IGraphicsNode; +import org.simantics.proconf.g3d.scenegraph.ParameterizedModelNode; + +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.common.ControlPointTools; +import fi.vtt.simantics.processeditor.stubs.PipeControlPoint; +import fi.vtt.simantics.processeditor.stubs.PipelineComponent; + + + +public class PipelineComponentNode extends ParameterizedModelNode { + + boolean updating = false; + + public PipelineComponentNode(ThreeDimensionalEditorBase editor, IGraphicsNode parent, Graph graph, Resource resource) { + super(editor,parent,graph, resource, ProcessResource.plant3Dresource.HasGraphics); + PipelineComponent component = new PipelineComponent(graph, resource); + if(!component.isInstanceOf(ProcessResource.plant3Dresource.PipelineComponent)) + throw new RuntimeException("Resource must be instance of Inline Component " + resource); + if (!(parent instanceof PipeRunNode)) + throw new RuntimeException("Parent must be instance of PipelineNode " + parent.getResource() + " " + resource); + + //PipeControlPoint pcp = component.getControlPoint(); +// monitor = new StructuralChangeMonitor( +// new StructuralChangeListener[] { this }, pcp.getResource(), GlobalIdMap +// .get(Layer0Mapping.HAS_PROPERTY)); + updateTransform(graph); + } + +// public void handleUpdate(StructuralChangeMonitor monitor, GraphChangeEvent event) { +// if (updating) +// return; +// if (event.getParameter() instanceof InlineComponentNode) +// return; +// if (event.getTransactionId() == null) +// return; +// if (event.getParameter() instanceof AbstractGraphicsNode) +// return; +// +// updating = true; +// updateTransform(); +// updating = false; +// } + + public void updateTransform(Graph graph) { + super.updateTransform(graph); + /* + PipelineComponent component = new PipelineComponent(graph,shapeResource); + + PipeControlPoint pcp = component.getControlPoint(); + Double angle = component.getAtMostOneRelatedScalarDouble(ProcessResource.plant3Dresource.HasRotationAngle); + double componentAngle = 0.0; + if (angle != null) + componentAngle = angle; + + AxisAngle4d aa = ControlPointTools.getControlPointRotation(pcp, componentAngle); + update(aa); + */ + } + + + public void dispose() { + //monitor.dispose(); + super.dispose(); + } + + + + +} \ No newline at end of file diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/tools/ControlPointContribution.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/tools/ControlPointContribution.java new file mode 100644 index 00000000..2f3dba8a --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/tools/ControlPointContribution.java @@ -0,0 +1,431 @@ +package fi.vtt.simantics.processeditor.tools; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import javax.vecmath.AxisAngle4d; +import javax.vecmath.Point3d; +import javax.vecmath.Quat4d; +import javax.vecmath.Vector3d; + +import org.eclipse.core.runtime.FileLocator; +import org.eclipse.core.runtime.Path; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.IToolBarManager; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.layout.FormAttachment; +import org.eclipse.swt.layout.FormData; +import org.eclipse.swt.layout.FormLayout; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Resource; +import org.simantics.proconf.g3d.actions.ContextAction; +import org.simantics.proconf.g3d.base.EditorContribution; +import org.simantics.proconf.g3d.base.G3DTools; +import org.simantics.proconf.g3d.base.MathTools; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.base.VecmathJmeTools; +import org.simantics.proconf.g3d.common.StructuredResourceSelection; +import org.simantics.utils.ErrorLogger; + +import com.jme.renderer.ColorRGBA; +import com.jme.scene.Geometry; +import com.jme.scene.Node; +import com.jme.scene.Spatial; +import com.jme.scene.TriMesh; +import com.jme.scene.shape.Sphere; +import com.jme.scene.state.MaterialState; +import com.jme.util.export.Savable; +import com.jme.util.export.binary.BinaryImporter; +import com.jmex.model.converters.ObjToJme; + +import fi.vtt.simantics.processeditor.Activator; +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.common.PipeComponentProvider; +import fi.vtt.simantics.processeditor.stubs.DirectedControlPoint; +import fi.vtt.simantics.processeditor.stubs.PipeControlPoint; + +public class ControlPointContribution implements EditorContribution { + private List actions = new ArrayList(); + private ThreeDimensionalEditorBase parent; + private Resource componentResource; + private Resource controlPointResource; + + private Composite sideComposite; + + private double radius = 0.2; + private double radius2 = 0.1; + private double angle = Math.PI / 4.0; + + public ControlPointContribution(ThreeDimensionalEditorBase parent) { + this.parent = parent; + } + + @Override + public void createControl(Composite parent) { + FormLayout flayout = new FormLayout(); + parent.setLayout(flayout); + sideComposite = new Composite(parent,SWT.BORDER); + FormData data = new FormData(); + data.top = new FormAttachment(0, 0); + data.left = new FormAttachment(0, 0); + data.right = new FormAttachment(sideComposite, 0, SWT.LEFT); + data.bottom = new FormAttachment(100,0); + this.parent.getRenderingComposite().setLayoutData(data); + GridLayout layout = new GridLayout(1,false); + layout.marginHeight = 1; + layout.marginWidth = 1; + sideComposite.setLayout(layout); + data = new FormData(); + data.top = new FormAttachment(0, 0); + data.bottom = new FormAttachment(100,0); + data.right = new FormAttachment(100,0); + sideComposite.setLayoutData(data); + + Button showCPButton = new Button(sideComposite,SWT.TOGGLE); + showCPButton.setText("Show CtrlPts"); + showCPButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + Button b = (Button)e.widget; + showControlPoints(b.getSelection()); + } + }); + + Button addCPButton = new Button(sideComposite,SWT.PUSH); + addCPButton.setText("Add CtrlPt"); + addCPButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + addControlPoint(); + } + }); + + Button removeCPButton = new Button(sideComposite,SWT.PUSH); + removeCPButton.setText("Remove CtrlPt"); + removeCPButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + + } + }); + + Button showPipesButton = new Button(sideComposite,SWT.TOGGLE); + showPipesButton.setText("Pipes"); + showPipesButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + Button b = (Button)e.widget; + showPipes(b.getSelection()); + } + }); + + + } + + @Override + public void disposeControl() { + sideComposite.dispose(); + } + + @Override + public void fillContextMenu(Graph graph, IMenuManager manager, + StructuredResourceSelection selection) { + + } + + @Override + public void fillLocalPullDown(IMenuManager manager) { + + } + + @Override + public void fillLocalToolBar(IToolBarManager manager) { + + } + + @Override + public Collection getActions() { + return actions; + } + + @Override + public String getName() { + return "Control Points"; + } + + List pipes = new ArrayList(); + List controlPoints = new ArrayList(); + + private void showPipes(boolean show) { + if (show) { + if (!pipes.isEmpty()) { + for (Node n : pipes) { + n.removeFromParent(); + n.dispose(); + } + pipes.clear(); + } + parent.getSession().asyncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + PipeControlPoint pcp = new PipeControlPoint(g,controlPointResource); + if (pcp.isInstanceOf(ProcessResource.plant3Dresource.EndComponentControlPoint)) { + Node n = new Node(); + TriMesh mesh = new TriMesh(); + Point3d p1 = new Point3d(-10.0,0.0,0.0); + Point3d p2 = new Point3d( 0.0,0.0,0.0); + PipeComponentProvider.createStraightGeometry(p1, p2, radius, new Geometry[]{mesh}); + n.attachChild(mesh); + parent.getRenderingComponent().getShadowRoot().attachChild(n); + pipes.add(n); + + } else if (pcp.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)) { + + double length = 0.5; + Double d = pcp.getAtMostOneRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength); + if (d != null) + length = d; + + double offset = 0.0; + d = pcp.getAtMostOneRelatedScalarDouble(ProcessResource.plant3Dresource.HasOffset); + if (d != null) + offset = d; + + double r = radius; + if (pcp.isInstanceOf(ProcessResource.plant3Dresource.SizeChangeControlPoint)) { + r = radius2; + } + + Node n = new Node(); + TriMesh mesh = new TriMesh(); + Point3d p1 = new Point3d(-10.0,0.0,0.0); + Point3d p2 = new Point3d( -length*0.5,0.0,0.0); + + PipeComponentProvider.createStraightGeometry(p1, p2, radius, new Geometry[]{mesh}); + n.attachChild(mesh); + parent.getRenderingComponent().getShadowRoot().attachChild(n); + pipes.add(n); + + n = new Node(); + mesh = new TriMesh(); + p1 = new Point3d(10.0,offset,0.0); + p2 = new Point3d(length*0.5,offset,0.0); + + PipeComponentProvider.createStraightGeometry(p1, p2, r, new Geometry[]{mesh}); + n.attachChild(mesh); + parent.getRenderingComponent().getShadowRoot().attachChild(n); + pipes.add(n); + + } else if (pcp.isInstanceOf(ProcessResource.plant3Dresource.InlineControlPoint)) { + double length = 0.5; + Double d = pcp.getAtMostOneRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength); + if (d != null) + length = d; + + Node n = new Node(); + TriMesh mesh = new TriMesh(); + Point3d p1 = new Point3d(-10.0,0.0,0.0); + Point3d p2 = new Point3d( -length*0.5,0.0,0.0); + + PipeComponentProvider.createStraightGeometry(p1, p2, radius, new Geometry[]{mesh}); + n.attachChild(mesh); + parent.getRenderingComponent().getShadowRoot().attachChild(n); + pipes.add(n); + + n = new Node(); + mesh = new TriMesh(); + p1 = new Point3d(10.0,0.0,0.0); + p2 = new Point3d(length*0.5,0.0,0.0); + + PipeComponentProvider.createStraightGeometry(p1, p2, radius, new Geometry[]{mesh}); + n.attachChild(mesh); + parent.getRenderingComponent().getShadowRoot().attachChild(n); + pipes.add(n); + } else if (pcp.isInstanceOf(ProcessResource.plant3Dresource.TurnControlPoint)) { + double length = 0.5; + Double d = pcp.getAtMostOneRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength); + if (d != null) + length = d; + + Node n = new Node(); + TriMesh mesh = new TriMesh(); + Point3d p1 = new Point3d(-10.0,0.0,0.0); + Point3d p2 = new Point3d( -length*0.5,0.0,0.0); + + PipeComponentProvider.createStraightGeometry(p1, p2, radius, new Geometry[]{mesh}); + n.attachChild(mesh); + parent.getRenderingComponent().getShadowRoot().attachChild(n); + pipes.add(n); + + n = new Node(); + mesh = new TriMesh(); + p1 = new Point3d(10.0,0.0,0.0); + p2 = new Point3d(length*0.5,0.0,0.0); + Quat4d q = new Quat4d(); + q.set(new AxisAngle4d(0.0,1.0,0.0,angle)); + MathTools.rotate(q, p1, p1); + MathTools.rotate(q, p2, p2); + + PipeComponentProvider.createStraightGeometry(p1, p2, radius, new Geometry[]{mesh}); + n.attachChild(mesh); + parent.getRenderingComponent().getShadowRoot().attachChild(n); + pipes.add(n); + } else if (pcp.isInstanceOf(ProcessResource.plant3Dresource.DirectedControlPoint)) { + Node n = new Node(); + TriMesh mesh = new TriMesh(); + Point3d p1 = new Point3d(10.0,0.0,0.0); + Point3d p2 = new Point3d( 0.0,0.0,0.0); + PipeComponentProvider.createStraightGeometry(p1, p2, radius, new Geometry[]{mesh}); + n.attachChild(mesh); + parent.getRenderingComponent().getShadowRoot().attachChild(n); + pipes.add(n); + } + + if(!pcp.isInstanceOf(ProcessResource.plant3Dresource.DualInlineControlPoint)) { + Collection subPoints = pcp.getSubPoint(); + + } + + parent.setViewChanged(true); + return GraphRequestStatus.transactionComplete(); + } + }); + } else { + if (!pipes.isEmpty()) { + for (Node n : pipes) { + n.removeFromParent(); + n.dispose(); + } + pipes.clear(); + parent.setViewChanged(true); + } + } + } + + private void showControlPoints(boolean show) { + if (show) { + if (!controlPoints.isEmpty()) { + for (Node n : controlPoints) { + n.removeFromParent(); + n.dispose(); + } + + } + parent.getSession().asyncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + + PipeControlPoint pcp = new PipeControlPoint(g,controlPointResource); + Vector3d p = G3DTools.getVector(pcp.getWorldPosition()); + Node n = new Node(); + Spatial sphere = new Sphere("",5,8,0.1f); + n.attachChild(sphere); + n.setLocalTranslation(VecmathJmeTools.get(p)); + MaterialState ms = parent.getRenderingComponent().getDisplaySystem().getRenderer().createMaterialState(); + ms.setDiffuse(new ColorRGBA(1.f,0.f,0.f,0.f)); + sphere.setRenderState(ms); + sphere.setName(Long.toString(pcp.getResource().getResourceId())); + parent.getRenderingComponent().getNoShadowRoot().attachChild(n); + controlPoints.add(n); + Collection subPoints = pcp.getSubPoint(); + ms = parent.getRenderingComponent().getDisplaySystem().getRenderer().createMaterialState(); + ms.setDiffuse(new ColorRGBA(0.f,1.f,0.f,0.f)); + for (PipeControlPoint cp : subPoints) { + p = G3DTools.getVector(cp.getWorldPosition()); + n = new Node(); + if (cp.isInstanceOf(ProcessResource.plant3Dresource.DirectedControlPoint)) { + sphere = getDCPMesh(); + if (sphere == null) + sphere = new Sphere("",5,8,0.1f); + } else { + sphere = new Sphere("",5,8,0.1f); + } + sphere.setName(Long.toString(cp.getResource().getResourceId())); + n.attachChild(sphere); + n.setLocalTranslation(VecmathJmeTools.get(p)); + sphere.setRenderState(ms); + parent.getRenderingComponent().getNoShadowRoot().attachChild(n); + controlPoints.add(n); + } + parent.setViewChanged(true); + return GraphRequestStatus.transactionComplete(); + } + }); + } else { + if (!controlPoints.isEmpty()) { + for (Node n : controlPoints) { + n.removeFromParent(); + n.dispose(); + } + parent.setViewChanged(true); + } + } + } + + @Override + public void initialize(Graph graph) { + Resource modelResource = parent.getInputResource(); + Resource inverse = graph.getInverse(ProcessResource.plant3Dresource.HasGraphics); + Collection equipment = graph.getObjects(modelResource, inverse); + if (equipment.size() != 1) + throw new RuntimeException("Cannot find component for model " + modelResource); + componentResource = equipment.iterator().next(); + Collection pcp = graph.getObjects(componentResource, ProcessResource.plant3Dresource.HasControlPoint); + if (pcp.size() != 1) + throw new RuntimeException("Cannot find control point for component " + componentResource); + controlPointResource = pcp.iterator().next(); + } + + @Override + public void dispose() { + + } + + @Override + public void run() { + + } + + private void addControlPoint() { + parent.getSession().asyncWrite(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + DirectedControlPoint dcp = DirectedControlPoint.createDefault(g); + PipeControlPoint pcp = new PipeControlPoint(g,controlPointResource); + pcp.addStatement(ProcessResource.plant3Dresource.HasSubPoint, dcp); + return GraphRequestStatus.transactionComplete(); + } + }); + } + + private Spatial getDCPMesh() { + try { + ObjToJme converter=new ObjToJme(); + String file = "data/dcp.obj"; + URL objFile=FileLocator.find(Activator.getDefault().getBundle(),new Path(file),null); + converter.setProperty("mtllib",objFile); + ByteArrayOutputStream BO=new ByteArrayOutputStream(); + //System.out.println("Starting to convert .obj to .jme"); + converter.convert(objFile.openStream(),BO); + + Savable s = BinaryImporter.getInstance().load(new ByteArrayInputStream(BO.toByteArray())); + return (Spatial)s; + } catch (Exception e) { + ErrorLogger.defaultLogError(e); + return null; + } + } + + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/tools/NozzleContribution.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/tools/NozzleContribution.java new file mode 100644 index 00000000..91f65baa --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/tools/NozzleContribution.java @@ -0,0 +1,129 @@ +package fi.vtt.simantics.processeditor.tools; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IContributionItem; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.IToolBarManager; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.layout.FormAttachment; +import org.eclipse.swt.layout.FormData; +import org.eclipse.swt.layout.FormLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Text; +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.proconf.g3d.actions.ContextAction; +import org.simantics.proconf.g3d.base.EditorContribution; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.common.StructuredResourceSelection; + +import fi.vtt.simantics.processeditor.ProcessResource; + +public class NozzleContribution implements EditorContribution { + private List actions = new ArrayList(); + private ThreeDimensionalEditorBase parent; + private Resource equipmentResource; + private Composite sideComposite; + + public NozzleContribution(ThreeDimensionalEditorBase parent) { + this.parent = parent; + } + + @Override + public void createControl(Composite parent) { + FormLayout flayout = new FormLayout(); + parent.setLayout(flayout); + sideComposite = new Composite(parent,SWT.BORDER); + FormData data = new FormData(); + data.top = new FormAttachment(0, 0); + data.left = new FormAttachment(0, 0); + data.right = new FormAttachment(sideComposite, 0, SWT.LEFT); + data.bottom = new FormAttachment(100,0); + this.parent.getRenderingComposite().setLayoutData(data); + sideComposite.setLayout(new FillLayout(SWT.VERTICAL)); + data = new FormData(); + data.top = new FormAttachment(0, 0); + data.bottom = new FormAttachment(100,0); + data.right = new FormAttachment(100,0); + sideComposite.setLayoutData(data); + showNozzles(true); + + Button addButton = new Button(sideComposite,SWT.PUSH); + addButton.setText("Add Nozzle"); + Label label = new Label(sideComposite,SWT.NONE); + label.setText("Restrictions:"); + Button minButton = new Button(sideComposite,SWT.CHECK); + minButton.setText("Min"); + Text minText = new Text(sideComposite,SWT.SINGLE | SWT.BORDER); + Button maxButton = new Button(sideComposite,SWT.CHECK); + maxButton.setText("Max"); + Text maxText = new Text(sideComposite,SWT.SINGLE | SWT.BORDER); + minText.setToolTipText("Enter minimum number of nozzles"); + maxText.setToolTipText("Enter maximum number of nozzles"); + + } + + @Override + public void disposeControl() { + sideComposite.dispose(); + + } + @Override + public void fillContextMenu(Graph graph, IMenuManager manager, + StructuredResourceSelection selection) { + + } + + @Override + public void fillLocalPullDown(IMenuManager manager) { + + } + + @Override + public void fillLocalToolBar(IToolBarManager manager) { + + } + + @Override + public Collection getActions() { + return actions; + } + + @Override + public String getName() { + return "Nozzles"; + } + + private void showNozzles(boolean show) { + + } + + @Override + public void initialize(Graph graph) { + Resource modelResource = parent.getInputResource(); + Resource inverse = graph.getInverse(ProcessResource.plant3Dresource.HasGraphics); + Collection equipment = graph.getObjects(modelResource, inverse); + if (equipment.size() != 1) + throw new RuntimeException("Cannot find equipment"); + equipmentResource = equipment.iterator().next(); + } + + @Override + public void dispose() { + showNozzles(false); + } + + @Override + public void run() { + + } + + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/tools/PlantEditContribution.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/tools/PlantEditContribution.java new file mode 100644 index 00000000..e411131b --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/tools/PlantEditContribution.java @@ -0,0 +1,330 @@ +package fi.vtt.simantics.processeditor.tools; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.IToolBarManager; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.FormAttachment; +import org.eclipse.swt.layout.FormData; +import org.eclipse.swt.layout.FormLayout; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Text; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Resource; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.proconf.g3d.actions.ContextAction; +import org.simantics.proconf.g3d.actions.FocusAction; +import org.simantics.proconf.g3d.actions.RemoveAction; +import org.simantics.proconf.g3d.actions.RotateAction; +import org.simantics.proconf.g3d.actions.TranslateAction; +import org.simantics.proconf.g3d.base.EditorContribution; +import org.simantics.proconf.g3d.common.StructuredResourceSelection; +import org.simantics.utils.ui.jface.MenuTools; + +import com.jme.intersection.CollisionData; +import com.jme.intersection.CollisionResults; +import com.jme.intersection.TriangleCollisionResults; +import com.jme.scene.Geometry; +import com.jme.scene.Node; +import com.jme.scene.Spatial; + +import fi.vtt.simantics.processeditor.Activator; +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.actions.InsertComponentAction; +import fi.vtt.simantics.processeditor.actions.InsertEquipmentAction; +import fi.vtt.simantics.processeditor.actions.InsertNozzleAction; +import fi.vtt.simantics.processeditor.actions.ReversePipelineAction; +import fi.vtt.simantics.processeditor.actions.RoutePipeAction; +import fi.vtt.simantics.processeditor.actions.TranslateElbowAction; +import fi.vtt.simantics.processeditor.actions.TranslateInlineComponentAction; +import fi.vtt.simantics.processeditor.actions.TranslateStraightAction; +import fi.vtt.simantics.processeditor.common.ControlPointTools; +import fi.vtt.simantics.processeditor.stubs.InlineComponent; +import fi.vtt.simantics.processeditor.stubs.PipeControlPoint; +import fi.vtt.simantics.processeditor.views.ProcessEditor; + +public class PlantEditContribution implements EditorContribution { + private List actions = new ArrayList(); + private ProcessEditor parent; + private Composite infoComposite; + private Text infoText; + + private Action checkInterferencesAction = null; + + public PlantEditContribution(ProcessEditor parent) { + this.parent = parent; + } + + @Override + public void createControl(Composite parent) { + FormLayout flayout = new FormLayout(); + parent.setLayout(flayout); + infoComposite = new Composite(parent, SWT.BORDER); + FormData data = new FormData(); + data.top = new FormAttachment(0, 0); + data.left = new FormAttachment(0, 0); + data.right = new FormAttachment(100, 0); + data.bottom = new FormAttachment(infoComposite, 0, SWT.TOP); + this.parent.getRenderingComposite().setLayoutData(data); + data = new FormData(); + data.left = new FormAttachment(0, 0); + data.right = new FormAttachment(100, 0); + data.bottom = new FormAttachment(100, 0); + data.height = 18; + infoComposite.setLayoutData(data); + GridLayout layout = new GridLayout(1,false); + layout.marginWidth = 1; + layout.marginHeight = 1; + infoComposite.setLayout(layout); + infoText = new Text(infoComposite, SWT.NONE); + GridData gdata = new GridData(); + gdata.grabExcessHorizontalSpace = true; + gdata.horizontalAlignment = SWT.FILL; + infoText.setLayoutData(gdata); + + } + + @Override + public void disposeControl() { + infoComposite.dispose(); + + } + + @Override + public void dispose() { + + } + + + + @Override + public void fillContextMenu(Graph graph, IMenuManager manager, + StructuredResourceSelection selection) { + + } + + @Override + public void fillLocalPullDown(IMenuManager manager) { + MenuTools.getOrCreate(parent.getMenuID(),"Advanced", manager).add(checkInterferencesAction); + + } + + @Override + public void fillLocalToolBar(IToolBarManager manager) { + + } + + @Override + public Collection getActions() { + return actions; + } + + @Override + public String getName() { + return "Plant Editing"; + } + + @Override + public void initialize(Graph graph) { + actions.add(new TranslateAction(parent){ + @Override + public boolean usable(Graph graph,List resources) { + if (super.usable(graph, resources)) { + for (Resource r : resources) { + // FIXME : use new ontology : + // 1. lose ends works like end components (just what this code does, but type checks are not correct) + // 2. connected components are moved inline. (TranslateInlineAction) + IEntity t = EntityFactory.create(graph, r); + if (t.isInstanceOf(ProcessResource.plant3Dresource.InlineComponent)) { + InlineComponent component = new InlineComponent(t); + PipeControlPoint pcp = component.getControlPoint(); + if (pcp.getNext() != null && pcp.getPrevious() != null) + return false; + } + } + return true; + } + return false; + } + + @Override + public void setInfoText(String text) { + infoText.setText(text); + } + }); + actions.add(new TranslateInlineComponentAction(parent) { + @Override + public void setInfoText(String text) { + infoText.setText(text); + } + }); + actions.add(new TranslateStraightAction(parent) { + @Override + public void setInfoText(String text) { + infoText.setText(text); + } + }); + actions.add(new TranslateElbowAction(parent) { + @Override + public void setInfoText(String text) { + infoText.setText(text); + } + }); + actions.add(new RotateAction(parent){ + @Override + public boolean usable(Graph graph,List resources) { + if (super.usable(graph,resources)) { + for (Resource r : resources) { + IEntity t = EntityFactory.create(graph,r); + // FIXME : use new ontology + // TODO : create rotate action that can rotate inline components + // TODO : ontology change: pipes and similar components cannot be rotated, since there is no point to do that. + if (t.isInstanceOf(ProcessResource.plant3Dresource.InlineComponent)) { + return false; + } + } + return true; + } + + return false; + } + + @Override + public void setInfoText(String text) { + infoText.setText(text); + } + }); + actions.add(new RemoveAction(parent) { + @Override + public GraphRequestStatus doChanges(Graph graph) { + Iterator i = parent.getSelectionAdapter().getCurrentSelection().iterator(); + while (i.hasNext()) { + Resource s = i.next(); + IEntity r = EntityFactory.create(graph, s); + if (r.isInstanceOf(ProcessResource.g3dResource.G3DNode)) { + Collection parentNode= r.getRelatedObjects(ProcessResource.g3dResource.HasParent); + if (parentNode.size() == 1) { + Collection rs = r.getRelatedObjects(ProcessResource.plant3Dresource.HasControlPoint); + for (IEntity cp : rs) { + ControlPointTools.removeControlPoint(new PipeControlPoint(cp)); + } + r.removeRelatedStatements(ProcessResource.g3dResource.HasParent); + } else { + if (parentNode.size() == 0) { + parent.showMessage("Object has no parent, don't know what to do!"); + } else { + parent.showMessage("Object has more than one parent, don't know what to do!"); + } + } + } + + } + //parent.getSelectionAdapter().setSelection(new StructuredResourceSelection()); + return GraphRequestStatus.transactionComplete(); + } + }); + actions.add(new FocusAction(parent)); + actions.add(new RoutePipeAction(parent){ + @Override + public void setInfoText(String text) { + infoText.setText(text); + } + }); + actions.add(new InsertComponentAction(parent)); + actions.add(new InsertEquipmentAction(parent)); + actions.add(new InsertNozzleAction(parent)); + actions.add(new ReversePipelineAction(parent)); + + checkInterferencesAction = new Action() { + public void run() { + CollisionResults results = new TriangleCollisionResults(); + //getRenderingComponent().getNormalRoot().calculateCollisions(getRenderingComponent().getNormalRoot(), results); + collide(parent.getRenderingComponent().getShadowRoot(),parent.getRenderingComponent().getShadowRoot(),results); + results = filterResults(results); + for (int i = 0; i < results.getNumber(); i++) { + CollisionData data = results.getCollisionData(i); + Geometry s = data.getSourceMesh(); + Geometry t = data.getTargetMesh(); + MessageDialog dialog = new MessageDialog(parent.getRenderingComposite().getShell(),"Interference " + i + " / " + results.getNumber(), null, "Interference between " + s + " and " + t,MessageDialog.WARNING,new String[]{"Next","Cancel"},0); + try { + Resource sid = parent.getScenegraphAdapter().getNodeResource(s.getName()); + Resource tid = parent.getScenegraphAdapter().getNodeResource(t.getName()); + + StructuredResourceSelection sel = new StructuredResourceSelection(); + if (sid == tid) { + sel.add(sid); + } else { + sel.add(sid); + sel.add(tid); + } + parent.getSelectionAdapter().setSelection(sel); + } catch(NumberFormatException e) { + + } + if (dialog.open() == 1) + break; + } + } + + private void collide(Spatial s, Spatial p, CollisionResults r) { + s.calculateCollisions(p, r); + if (s instanceof Node) { + Node n = (Node)s; + for (Spatial t : n.getChildren()) + collide(t,p,r); + } + } + + private CollisionResults filterResults(CollisionResults results) { + CollisionResults r = new TriangleCollisionResults(); + for (int i = 0; i < results.getNumber(); i++) { + CollisionData d = results.getCollisionData(i); + if (d.getSourceMesh() == d.getTargetMesh()) + continue; + boolean found = false; + for (int j = 0; j < r.getNumber(); j++) { + CollisionData d2 = r.getCollisionData(j); + if (d2.getSourceMesh() == d.getSourceMesh() && + d2.getTargetMesh() == d.getTargetMesh()) { + found = true; + break; + } + if (d2.getSourceMesh() == d.getTargetMesh() && + d2.getTargetMesh() == d.getSourceMesh()) { + found = true; + break; + } + } + if (!found) { + if (d.getSourceTris().size() == 0) + continue; + if (d.getTargetTris().size() == 0) + continue; + r.addCollisionData(d); + } + } + return r; + } + + }; + checkInterferencesAction.setText("Interferences"); + checkInterferencesAction.setImageDescriptor(Activator.imageDescriptorFromPlugin("fi.vtt.proconf.ode", "icons/silk/delete.png")); + + } + + @Override + public void run() { + + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/tools/PlantVisualizationContribution.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/tools/PlantVisualizationContribution.java new file mode 100644 index 00000000..42b93f0a --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/tools/PlantVisualizationContribution.java @@ -0,0 +1,376 @@ +package fi.vtt.simantics.processeditor.tools; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Stack; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.IToolBarManager; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.widgets.Composite; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Resource; +import org.simantics.proconf.g3d.actions.ContextAction; +import org.simantics.proconf.g3d.actions.FocusAction; +import org.simantics.proconf.g3d.animation.Animatable; +import org.simantics.proconf.g3d.animation.AnimationController; +import org.simantics.proconf.g3d.animation.AnimationSystem; +import org.simantics.proconf.g3d.animation.TestAnimationController; +import org.simantics.proconf.g3d.animation.ui.AnimationControlCreator; +import org.simantics.proconf.g3d.base.EditorContribution; +import org.simantics.proconf.g3d.common.StructuredResourceSelection; +import org.simantics.proconf.g3d.scenegraph.IGraphicsNode; +import org.simantics.proconf.g3d.stubs.G3DNode; +import org.simantics.utils.ui.jface.MenuTools; + +import fi.vtt.simantics.processeditor.Activator; +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.animations.PipeAnimationController; +import fi.vtt.simantics.processeditor.dialogs.ConfigureAnimationDialog; +import fi.vtt.simantics.processeditor.dialogs.ConfigureMonitorDialog; +import fi.vtt.simantics.processeditor.dialogs.ConfigurePipelineAnimationDialog; +import fi.vtt.simantics.processeditor.monitors.Monitor; +import fi.vtt.simantics.processeditor.monitors.ResourcePathPropertyProvider; +import fi.vtt.simantics.processeditor.monitors.TextMonitor; +import fi.vtt.simantics.processeditor.stubs.PipeRun; +import fi.vtt.simantics.processeditor.views.ProcessEditor; + +public class PlantVisualizationContribution implements EditorContribution { + private List actions = new ArrayList(); + private ProcessEditor parent; + + private AnimationSystem animationSystem = null; + private Action animatePipesAction = null; + private Action animateAction = null; + private Action showMonitorsAction = null; + private Action configureAnimationAction = null; + private Action configurePipelineAnimationAction = null; + private Action configureMonitorAction = null; + + private Monitor monitor; + + public PlantVisualizationContribution(ProcessEditor parent) { + this.parent = parent; + } + + @Override + public void createControl(Composite parent) { + parent.setLayout(new FillLayout()); + this.parent.getRenderingComposite().setLayoutData(null); + } + + @Override + public void disposeControl() { + + } + + @Override + public void dispose() { + + } + + @Override + public void fillContextMenu(Graph graph, IMenuManager manager, + StructuredResourceSelection selection) { + + } + + @Override + public void fillLocalPullDown(IMenuManager menuManager) { + MenuTools.getOrCreate(parent.getMenuID(),"Monitors", menuManager).add(showMonitorsAction); + MenuTools.getOrCreate(parent.getMenuID(),"Monitors", menuManager).add(configureMonitorAction); + IMenuManager animationMenu = MenuTools.getOrCreate(parent.getMenuID(),"Animations",menuManager); + animationMenu.add(configureAnimationAction); + animationMenu.add(configurePipelineAnimationAction); + MenuTools.getOrCreate(parent.getMenuID(),"Test", animationMenu).add(animateAction); + MenuTools.getOrCreate(parent.getMenuID(),"Test", animationMenu).add(animatePipesAction); + + } + +// @Override +// public void fillMainMenu(List list) { +// MenuTools.getOrCreate("Monitors", list).add(showMonitorsAction); +// MenuTools.getOrCreate("Monitors", list).add(configureMonitorAction); +// IMenuManager animationMenu = MenuTools.getOrCreate("Animations",list); +// animationMenu.add(configureAnimationAction); +// animationMenu.add(configurePipelineAnimationAction); +// MenuTools.getOrCreate("Test", animationMenu).add(animateAction); +// MenuTools.getOrCreate("Test", animationMenu).add(animatePipesAction); +// +// } + + @Override + public void fillLocalToolBar(IToolBarManager manager) { + AnimationControlCreator c = new AnimationControlCreator(getAnimationSystem()); + manager.add(c.createStopAction()); + manager.add(c.createPauseAction()); + manager.add(c.createPlayAction()); + manager.add(showMonitorsAction); + } + + @Override + public Collection getActions() { + return actions; + } + + @Override + public String getName() { + return "Plant Visualization"; + } + + @Override + public void run() { + parent.getSession().syncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + getAnimationSystem().run(g,0.01); + updateMonitor(g); + return GraphRequestStatus.transactionComplete(); + } + }); + + + } + + @Override + public void initialize(Graph graph) { + animateAction = new Action("", Action.AS_CHECK_BOX) { + public void run() { + if (this.isChecked()) { + parent.getSession().asyncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) + throws Exception { + AnimationController c = new TestAnimationController(); + Collection nodes = parent.getScenegraphAdapter().getNodes(); + for (IGraphicsNode node : nodes) { + if (node instanceof Animatable) { + Animatable a = (Animatable) node; + if (a.setRandomAnimation(g)) + c.addAnimatable(a); + } + } + animationSystem.add(c); + return GraphRequestStatus.transactionComplete(); + } + }); + +// showMessage("Activated " + animatables.size() +// + " animations"); + } else { + animationSystem.stop(); + } + } + }; + + animateAction.setText("Random animations"); + + animatePipesAction = new AnimatePipesAction("Pipe animations"); + + showMonitorsAction = new Action("Interactive Monitor", Action.AS_CHECK_BOX) { + public void run() { + showMonitors(this.isChecked()); + } + }; + showMonitorsAction.setImageDescriptor(Activator.imageDescriptorFromPlugin("fi.vtt.proconf.ode", "icons/silk/monitor.png")); + + + + configureAnimationAction = new Action() { + + public void run() { + parent.getSession().syncRead(new GraphRequestAdapter(){ + List list = new ArrayList(); + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + Stack stack = new Stack(); + stack.add(parent.getPlant(g).toG3DNode()); + while (!stack.isEmpty()) { + G3DNode n = stack.pop(); + list.add(n.getResource()); + for (G3DNode no : n.getChild()) + stack.push(no); + } + + if (list.size() == 0) + return GraphRequestStatus.transactionComplete(); + + ConfigureAnimationDialog dialog = new ConfigureAnimationDialog(parent.getRenderingComposite().getShell(),parent.getSession(),list,parent.getScenegraphAdapter(),getAnimationSystem()); + dialog.open(); + return GraphRequestStatus.transactionComplete(); + } + + }); + + } + + + }; + configureAnimationAction.setText("Configure animations"); + configureAnimationAction.setImageDescriptor(Activator.imageDescriptorFromPlugin("fi.vtt.proconf.ode", "icons/silk/film_edit.png")); + + configurePipelineAnimationAction = new Action() { + + public void run() { + parent.getSession().syncRead(new GraphRequestAdapter(){ + List list = new ArrayList(); + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + Stack stack = new Stack(); + stack.add(parent.getPlant(g).toG3DNode()); + while (!stack.isEmpty()) { + G3DNode n = stack.pop(); + if (n.isInstanceOf(ProcessResource.plant3Dresource.PipeRun)) + list.add(n.getResource()); + else //piperun will not contain other piperuns + for (G3DNode no : n.getChild()) + stack.push(no); + } + + if (list.size() == 0) + return GraphRequestStatus.transactionComplete(); + + ConfigurePipelineAnimationDialog dialog = new ConfigurePipelineAnimationDialog(parent.getRenderingComposite().getShell(),parent.getSession(),list,parent.getRenderingComponent(),getAnimationSystem()); + dialog.open(); + return GraphRequestStatus.transactionComplete(); + } + + }); + + } + + + }; + configurePipelineAnimationAction.setText("Configure pipeline animations"); + configurePipelineAnimationAction.setImageDescriptor(Activator.imageDescriptorFromPlugin("fi.vtt.proconf.ode", "icons/silk/film_edit.png")); + configureMonitorAction = new Action() { + + public void run() { + parent.getSession().syncRead(new GraphRequestAdapter(){ + List list = new ArrayList(); + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + Stack stack = new Stack(); + stack.add(parent.getPlant(g).toG3DNode()); + while (!stack.isEmpty()) { + G3DNode n = stack.pop(); + list.add(n.getResource()); + for (G3DNode no : n.getChild()) + stack.push(no); + } + + if (list.size() == 0) + return GraphRequestStatus.transactionComplete(); + + ConfigureMonitorDialog dialog = new ConfigureMonitorDialog(parent.getRenderingComposite().getShell(),parent.getSession(),list); + dialog.open(); + return GraphRequestStatus.transactionComplete(); + } + + }); + + } + }; + configureMonitorAction.setText("Configure monitor"); + configureMonitorAction.setImageDescriptor(Activator.imageDescriptorFromPlugin("fi.vtt.proconf.ode", "icons/silk/monitor_edit.png")); + + actions.add(new FocusAction(parent)); + } + + private AnimationSystem getAnimationSystem() { + if (animationSystem == null) { + animationSystem = new AnimationSystem(parent.getScenegraphAdapter()); + } + return animationSystem; + } + + protected void updateMonitor(Graph graph) { + if (showMonitorsAction.isChecked()) { + + List nodes = parent.getSelectionAdapter().getInteractiveSelectedObjects(); + if (nodes.size() > 0) { + IGraphicsNode selected = nodes.get(0); + if (monitor.acceptNode(graph,selected)) + monitor.setNode(graph,selected); + } + monitor.update(); + } + } + + protected Monitor createMonitor() { + Monitor m = new TextMonitor(parent); + m.setTextProvider(new ResourcePathPropertyProvider()); + return m; + } + + private void showMonitors(boolean show) { + if (show) { + if (monitor == null) { + monitor = createMonitor(); + } + final List nodes = parent.getSelectionAdapter().getInteractiveSelectedObjects(); + if (nodes.size() > 0) { + parent.getSession().asyncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + monitor.setNode(g,nodes.get(0)); + return GraphRequestStatus.transactionComplete(); + } + }); + + } + + } else if (!show && monitor != null) { + monitor.remove(); + parent.setViewChanged(true); + } + } + + private class AnimatePipesAction extends Action { + + public AnimatePipesAction(String text) { + super(text, Action.AS_CHECK_BOX); + + } + + public void run() { + if (this.isChecked()) { + parent.getSession().syncRead(new GraphRequestAdapter() { + List list = new ArrayList(); + + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + Stack stack = new Stack(); + stack.add(parent.getPlant(g).toG3DNode()); + while (!stack.isEmpty()) { + G3DNode n = stack.pop(); + if (n.isInstanceOf(ProcessResource.plant3Dresource.PipeRun)) + list.add(new PipeRun(n)); + else + //piperun will not contain other piperuns + for (G3DNode no : n.getChild()) + stack.push(no); + } + + for (PipeRun n : list) { + PipeAnimationController c = new PipeAnimationController(parent.getRenderingComponent(), n); + //animationSystem.add(c); + getAnimationSystem().add(c); + } + return GraphRequestStatus.transactionComplete(); + } + + }); + + } else { + //stopAnimations(); + getAnimationSystem().stop(); + } + } + + } +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/EquipmentEditorPart.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/EquipmentEditorPart.java new file mode 100644 index 00000000..07283dac --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/EquipmentEditorPart.java @@ -0,0 +1,46 @@ +package fi.vtt.simantics.processeditor.views; + +import java.util.Collection; + +import org.eclipse.swt.widgets.Display; +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.db.management.ISessionContext; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorPart; +import org.simantics.proconf.g3d.shapeeditor.views.ShapeEditorBase; + +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.tools.NozzleContribution; + +public class EquipmentEditorPart extends ThreeDimensionalEditorPart { + + @Override + protected ThreeDimensionalEditorBase createEditor(ISessionContext session) { + ShapeEditorBase base = new ShapeEditorBase(session); + base.addEditorContribution(new NozzleContribution(base)); + return base; + } + + @Override + public void reload(Graph g) { + Resource inputResource = getInputResource(); + Collection model = g.getObjects(inputResource, ProcessResource.plant3Dresource.HasGraphics); + if (model.size() != 1) + throw new RuntimeException("Cannot find model for equipment " + inputResource); + Resource modelResource = model.iterator().next(); + if (modelResource != null) { + editor.reload(g,modelResource); + } else { + + Display d = getSite().getShell().getDisplay(); + d.asyncExec(new Runnable() { + public void run() { + editor.showMessage("Failed to load model."); + getSite().getPage().closeEditor(EquipmentEditorPart.this,false); + } + }); + } + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/PipelineComponentEditorPart.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/PipelineComponentEditorPart.java new file mode 100644 index 00000000..e94d7d57 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/PipelineComponentEditorPart.java @@ -0,0 +1,46 @@ +package fi.vtt.simantics.processeditor.views; + +import java.util.Collection; + +import org.eclipse.swt.widgets.Display; +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.db.management.ISessionContext; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorPart; +import org.simantics.proconf.g3d.shapeeditor.views.ShapeEditorBase; + +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.tools.ControlPointContribution; + +public class PipelineComponentEditorPart extends ThreeDimensionalEditorPart { + + @Override + protected ThreeDimensionalEditorBase createEditor(ISessionContext session) { + ShapeEditorBase base = new ShapeEditorBase(session); + base.addEditorContribution(new ControlPointContribution(base)); + return base; + } + + @Override + public void reload(Graph g) { + Resource inputResource = getInputResource(); + Collection model = g.getObjects(inputResource, ProcessResource.plant3Dresource.HasGraphics); + if (model.size() != 1) + throw new RuntimeException("Cannot find model for pipeline component " + inputResource); + Resource modelResource = model.iterator().next(); + if (modelResource != null) { + editor.reload(g,modelResource); + } else { + + Display d = getSite().getShell().getDisplay(); + d.asyncExec(new Runnable() { + public void run() { + editor.showMessage("Failed to load model."); + getSite().getPage().closeEditor(PipelineComponentEditorPart.this,false); + } + }); + } + } + +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/PlantStructureOutlinePage.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/PlantStructureOutlinePage.java new file mode 100644 index 00000000..0c7a356f --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/PlantStructureOutlinePage.java @@ -0,0 +1,27 @@ +package fi.vtt.simantics.processeditor.views; + +import org.eclipse.swt.widgets.Composite; +import org.simantics.db.Resource; +import org.simantics.db.management.ISessionContext; +import org.simantics.layer0.utils.viewpoints.ResourceViewpoint; +import org.simantics.proconf.browsing.views.GraphExplorerOutlinePage; + +import fi.vtt.simantics.processeditor.perspectives.ViewpointGenerator; + +public class PlantStructureOutlinePage extends GraphExplorerOutlinePage { + + + public PlantStructureOutlinePage(ISessionContext sessionContext, Resource inputResource) { + super(sessionContext, inputResource); + } + + @Override + public void createControl(Composite parent) { + super.createControl(parent); + } + + @Override + public ResourceViewpoint getViewPoint(ISessionContext sessionContext) { + return ViewpointGenerator.createObjectStructureViewpoint(); + } +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/PlantStructureView.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/PlantStructureView.java new file mode 100644 index 00000000..6685e36c --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/PlantStructureView.java @@ -0,0 +1,22 @@ +package fi.vtt.simantics.processeditor.views; + +import org.eclipse.swt.widgets.Composite; +import org.simantics.db.management.ISessionContext; +import org.simantics.layer0.utils.viewpoints.ResourceViewpoint; +import org.simantics.proconf.browsing.GraphExplorer; +import org.simantics.proconf.browsing.views.GraphExplorerView; + +import fi.vtt.simantics.processeditor.perspectives.ViewpointGenerator; + +public class PlantStructureView extends GraphExplorerView { + + @Override + protected GraphExplorer createExplorer(Composite parent) { + return super.createExplorer(parent); + } + + @Override + protected ResourceViewpoint getViewpoint(ISessionContext context) { + return ViewpointGenerator.createViewpoint(); + } +} diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/ProcessEditor.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/ProcessEditor.java new file mode 100644 index 00000000..5aae5881 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/ProcessEditor.java @@ -0,0 +1,704 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.views; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.KeyEvent; +import org.eclipse.swt.events.KeyListener; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.views.contentoutline.IContentOutlinePage; +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.db.Session; +import org.simantics.db.management.ISessionContext; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.layer0.utils.Property; +import org.simantics.proconf.g3d.base.JmeRenderingComponent; +import org.simantics.proconf.g3d.base.ScenegraphAdapter; +import org.simantics.proconf.g3d.base.ScenegraphAdapterImpl; +import org.simantics.proconf.g3d.base.SelectionAdapter; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.common.StructuredResourceSelection; +import org.simantics.proconf.g3d.scenegraph.IGeometryNode; +import org.simantics.proconf.g3d.scenegraph.IGraphicsNode; +import org.simantics.proconf.g3d.scenegraph.ISelectableNode; +import org.simantics.proconf.g3d.scenegraph.ParameterizedModelNode; +import org.simantics.proconf.g3d.shapes.FloorShape; +import org.simantics.proconf.g3d.stubs.G3DNode; +import org.simantics.utils.ErrorLogger; +import org.simantics.utils.ui.jface.MenuTools; + +import com.jme.math.Vector3f; +import com.jme.scene.Geometry; + +import fi.vtt.simantics.processeditor.Activator; +import fi.vtt.simantics.processeditor.ProcessResource; +import fi.vtt.simantics.processeditor.actions.InsertComponentAction; +import fi.vtt.simantics.processeditor.actions.InsertEquipmentAction; +import fi.vtt.simantics.processeditor.actions.InsertNozzleAction; +import fi.vtt.simantics.processeditor.actions.RoutePipeAction; +import fi.vtt.simantics.processeditor.common.ControlPointTools; +import fi.vtt.simantics.processeditor.common.PipingRules; +import fi.vtt.simantics.processeditor.scenegraph.NonVisibleNode; +import fi.vtt.simantics.processeditor.scenegraph.PipelineComponentNode; +import fi.vtt.simantics.processeditor.scenegraph.PipeComponentNode; +import fi.vtt.simantics.processeditor.scenegraph.PipeRunNode; +import fi.vtt.simantics.processeditor.stubs.PipeControlPoint; +import fi.vtt.simantics.processeditor.stubs.PipeRun; +import fi.vtt.simantics.processeditor.stubs.Plant; +import fi.vtt.simantics.processeditor.stubs.Plant3DResource; +import fi.vtt.simantics.processeditor.tools.PlantEditContribution; +import fi.vtt.simantics.processeditor.tools.PlantVisualizationContribution; + +public class ProcessEditor extends ThreeDimensionalEditorBase { + + private Resource plantResource = null; + + //private List animationControllers = new ArrayList(); + + private Action configureFloorAction = null; + + private Geometry floorShape = null; + + public ProcessEditor(ISessionContext session) { + super(session); + addEditorContribution(new PlantEditContribution(this)); + addEditorContribution(new PlantVisualizationContribution(this)); + } + + public ProcessEditor(ISessionContext session,JmeRenderingComponent component) { + super(session,component); + addEditorContribution(new PlantEditContribution(this)); + addEditorContribution(new PlantVisualizationContribution(this)); + } + + @Override + protected ScenegraphAdapter createScenegraphAdapter() { + return new ProcessEditorAdapter(session,getRenderingComponent()); + } + + @Override + public void createControl(Graph graph,Composite parent) { + super.createControl(graph,parent); + + floorShape = FloorShape.getShape(getRenderingComponent().getDisplaySystem().getRenderer(), 100.f,0.2f); + getRenderingComponent().getNoCastRoot().attachChild(floorShape); + floorShape.setLocalTranslation(new Vector3f(0.f,-0.01f,0.f)); + } + + @Override + protected void makeActions(Graph graph) { + super.makeActions(graph); + + //actions.add(new ShowTrendsAction(this)); + + configureFloorAction = new Action() { + public void run() { + FloorConfigureDialog dialog = new FloorConfigureDialog(ProcessEditor.this.parent.getShell()); + if (dialog.open() == FloorConfigureDialog.CANCEL) + return; + if (dialog.isFloorEnabled()) { + if (floorShape.getParent() == null) + getRenderingComponent().getNoCastRoot().attachChild(floorShape); + } else { + floorShape.removeFromParent(); + } + floorShape.setLocalTranslation(new Vector3f(0.f,(float)dialog.getFloorHeight(),0.f)); + + } + }; + configureFloorAction.setText("Configure floor"); + configureFloorAction.setImageDescriptor(Activator.imageDescriptorFromPlugin("fi.vtt.proconf.ode", "icons/silk/shape_align_bottom.png")); + +// ContextActionFactory extended[] = ContextActionRegistry.getActions("fi.vtt.proconf.shapeeditor.processeditorview"); +// for (ContextActionFactory c : extended) { +// actions.add(c.createAction(this)); +// } + } + +// protected void stopAnimations() { +// animationSystem.stop(); +// } + + protected void fillLocalPullDown() { + super.fillLocalPullDown(); + MenuTools.getOrCreate(getMenuID(),"Advanced", menuManager).add(configureFloorAction); + } + + protected class ProcessEditorAdapter extends ScenegraphAdapterImpl { + + public ProcessEditorAdapter(Session session, JmeRenderingComponent component) { + super(session, component); + } + + private class NormalScengraphQuery extends ScenegraphQuery { + + public NormalScengraphQuery(Resource node) { + super(node); + } + + + @Override + public void shapeAdded(Graph graph, IGraphicsNode node) { + // FIXME : this won't work like in previous ProConf + } + } + + private Map pipeRunQueries = new HashMap(); + + protected ScenegraphQuery newSubnodeListener(G3DNode node) { + if (node.isInstanceOf(ProcessResource.plant3Dresource.PipeRun)) { + PipeRunControlPointQuery query = new PipeRunControlPointQuery(node.getResource()); + pipeRunQueries.put(node.getResource(), query); + node.getGraph().performQuery(query); +// return new SubnodeListener(node) { +// @Override +// public void shapeAdded(IGraphicsNode node) { +// if (node instanceof IGeometryNode) { +// updateGeometry((IGeometryNode)node); +// +// } +// node.setVisible(true); +// } +// }; + } + return new NormalScengraphQuery(node.getResource()); + + } + + @Override + protected NodePropertyQuery newRootPropertyListener(G3DNode root) { + // currently Plant does not have any properties. + return null; + } + + private class TransformationQuery extends NodeTransformationQuery { + + public TransformationQuery(Resource res) { + super(res); + } + + @Override + public void shapeUpdated(Graph graph, IGraphicsNode shape) { + //if (shape instanceof IGeometryNode) { + // updateGeometry((IGeometryNode)shape); + //} else { + shape.updateTransform(graph); + //} + } + } + + @Override + protected NodeTransformationQuery newTransformationListener(G3DNode root) { + return new TransformationQuery(root.getResource()); + } + + private class NormalNodePropertyQuery extends org.simantics.proconf.g3d.base.ScenegraphAdapterImpl.NodePropertyQuery { + + public NormalNodePropertyQuery(Resource resource) { + super(resource); + } + + @Override + public void shapeUpdated(Graph graph,IGraphicsNode shape) { + if (shape instanceof IGeometryNode) { + updateGeometry((IGeometryNode)shape); + } else { + shape.updateTransform(graph); + } + } + } + @Override + protected NodePropertyQuery newPropertyListener(G3DNode node) { + return new NormalNodePropertyQuery(node.getResource()); + } + + @Override + protected IGraphicsNode instantiateNode(IGraphicsNode parent, + G3DNode node) { + Plant3DResource p3r = ProcessResource.plant3Dresource; + IGraphicsNode newNode = null; + try { + if (node.isInstanceOf(p3r.Equipment)) { + newNode = new ParameterizedModelNode( + ProcessEditor.this, parent, node.getGraph(), + node.getResource(), p3r.HasGraphics); + } else if (node.isInstanceOf(p3r.PipeRun)) { + newNode = new PipeRunNode(parent, node.getGraph(), node.getResource()); + } else if (node.isInstanceOf(p3r.Nozzle)) { + newNode = new ParameterizedModelNode( + ProcessEditor.this, parent, node.getGraph(), + node.getResource(), p3r.HasGraphics); + // CodedComponent must be handled first since it uses + // hard-coded geometries + // TODO : is this really necessary, or could we unify + // PipeComponentNode, InlineComponentNode,... + } else if (node.isInstanceOf(p3r.CodedComponent)) { + newNode = new PipeComponentNode(ProcessEditor.this, + parent, node.getGraph(), node.getResource()); + } else if (node.isInstanceOf(p3r.NonVisibleComponent)) { + newNode = new NonVisibleNode(parent, node.getGraph(), node.getResource()); + } else if (node.isInstanceOf(p3r.PipelineComponent)) { + newNode = new PipelineComponentNode(ProcessEditor.this, + parent, node.getGraph(), node.getResource()); + } + + // } else if (node instanceof Shape) // Markers (ar/mobile) + // needed this + // newNode = new ShapeNode(TestProcessEditor.this,parent,node); + if (newNode != null) { + if (newNode instanceof ISelectableNode) + ((ISelectableNode) newNode).setVisible(true); + if (newNode instanceof IGeometryNode) { + updateGeometry((IGeometryNode) newNode); + } + return newNode; + } + } catch (Exception e) { + ErrorLogger.defaultLogError("Cannot handle node " + node.getResource(), e); + return null; + } + ErrorLogger.defaultLogError("Cannot handle node " + node.getResource(), null); + return null; + + } + + /** + * This is used to create elbows and straight pipes to pipeline TODO : + * this should be done with rule-engine! + * + * + * @author Marko Luukkainen + * + */ + protected class PipeRunControlPointQuery extends NodeQuery { + private List removed = new ArrayList(); + private List added = new ArrayList(); + + public PipeRunControlPointQuery(Resource r) { + super(r); + if (DEBUG) System.out.println("Created PipeRunControlPointQuery for " + r); + + } + + @Override + protected Object compute2(Graph graph) { + PipeRun run = new PipeRun(graph, nodeResource); + Collection cps = run + .getRelatedObjects(ProcessResource.plant3Dresource.HasControlPoints); + List res = new ArrayList(); + for (IEntity t : cps) + res.add(t.getResource()); + return res; + } + + @Override + public boolean updated(Graph graph, Object oldResult, + Object newResult) { + + removed.clear(); + added.clear(); + + List oldCps = (List) oldResult; + List newCps = (List) newResult; + if (oldCps == null) + oldCps = new ArrayList(); + + for (Resource r : oldCps) { + if (!newCps.contains(r)) + removed.add(r); + } + + for (Resource r : newCps) { + if (!oldCps.contains(r)) + added.add(r); + } + for (Resource r : removed) + removeControlPoint(graph, r); + for (Resource r : added) { + addControlPoint(graph, r); + // ControlPointTools.addControlPoint(new + // PipeRun(graph,pipeRun), new PipeControlPoint(graph, r)); + } + + return (added.size() > 0 || removed.size() > 0); + } + + @Override + public void dispose() { + super.dispose(); + for (ControlPointPropertyQuery q : controlPointPropertyQueries.values()) + q.dispose(); + controlPointPropertyQueries.clear(); + } + + private Map controlPointPropertyQueries = new HashMap(); + + private void addControlPoint(Graph graph, Resource resource) { + ControlPointPropertyQuery query = new ControlPointPropertyQuery(resource); + graph.performQuery(query); + controlPointPropertyQueries.put(resource,query); + } + + private void removeControlPoint(Graph graph, Resource resource) { + ControlPointPropertyQuery query = controlPointPropertyQueries.remove(resource); + query.dispose(); + ControlPointTools.removeControlPoint(new PipeControlPoint( + graph, resource)); + } + + } + + protected class ControlPointPropertyQuery extends NodeQuery { + boolean initialized = false; + + public ControlPointPropertyQuery(Resource r) { + super(r); + if (DEBUG) System.out.println("Created ControlPointPropertyQuery for " + r); + } + + @Override + public List compute2(Graph g) { + IEntity t = EntityFactory.create(g,nodeResource); + + Collection properties = t.getRelatedProperties(ProcessResource.builtins.HasProperty); + List propertyValues = new ArrayList(); + p(properties,propertyValues); + + return propertyValues; + } + + private void p(Collection properties, List propertyValues) { + for (Property p : properties) { + Collection subProperties = p.getRelatedProperties(p.getGraph().getBuiltins().HasProperty); + if (subProperties.size() != 0) { + p(subProperties,propertyValues); + } + if (p.hasValue()){ + propertyValues.add(p.getValue()); + } + } + } + + @Override + public boolean updated(Graph graph, Object oldResult, Object newResult) { + PipingRules.pipeControlPointPositionUpdate(graph, this.nodeResource); + if (initialized) { + //PipingRules.pipeControlPointPositionUpdate(graph, this.nodeResource); + } else { + initialized = true; + } + return true; + } + } + + @Override + protected void removeNode(Resource parent, Resource r) { + super.removeNode(parent, r); + PipeRunControlPointQuery q = pipeRunQueries.get(r); + if (q != null) + q.dispose(); + } + + @Override + public void dispose() { + super.dispose(); + } + } + + @Override + protected void pageSelectionChanged(IWorkbenchPart part, ISelection selection) { + if (!(selection instanceof StructuredResourceSelection)) { + return; + } + + StructuredResourceSelection s = (StructuredResourceSelection) selection; + selectionAdapter.setCurrentSelection(s); + viewChanged = true; + + //if (s.getRootSelection() == null) { + if (!(part instanceof ProcessEditor)) { + //System.out.println("ShapeEditorView.pageSelectionChanged() no root selection"); + ((ProcessEditorSelectionAdapter)selectionAdapter).setEditorSelection(true); + return; + } + //if (!s.getRootSelection().getResource().getId().equals(plant.getResource().getId())) { + ProcessEditor sender = (ProcessEditor)part; + if (!sender.getPlantResource().equals(plantResource)) { +// System.out.println("ShapeEditorView.pageSelectionChanged() not right group " +// + s.getRootSelection().getResource().getId() + " != " + model.getResource().getId()); + selectionAdapter.setCurrentSelection(new StructuredResourceSelection()); + ((ProcessEditorSelectionAdapter)selectionAdapter).setEditorSelection(false); + return; + } + selectionAdapter.setEditorSelection(); + + } + + @Override + protected void reloadFrom(IEntity thing) { + if (plantResource != null) { + throw new UnsupportedOperationException("Reloading instantiated viewer not supported"); + } + if (thing.isInstanceOf(ProcessResource.plant3Dresource.Plant)) { + plantResource = thing.getResource(); + G3DNode plant = new G3DNode(thing); + adapter.setRootNode(plant); + //adapter.addOutbound(plant); + ControlPointTools.reloadCache(thing.getGraph(),plant.getResource()); + } else { + throw new IllegalArgumentException("Resource is not a plant"); + } + } + + public Resource getPlantResource() { + return plantResource; + } + + public Plant getPlant(Graph g) { + return new Plant(g, plantResource); + } + + @Override + protected SelectionAdapter createSelectionAdapter() { + return new ProcessEditorSelectionAdapter(adapter); + } + + protected class ProcessEditorSelectionAdapter extends SelectionAdapter { + + + public ProcessEditorSelectionAdapter(ScenegraphAdapter adapter) { + super(adapter); + // TODO Auto-generated constructor stub + } + + @Override + protected StructuredResourceSelection filterSelection(ISelection s) { + if (!(s instanceof StructuredResourceSelection)) + return new StructuredResourceSelection(); + return (StructuredResourceSelection)s; + } + + @Override + public void setEditorSelection() { + List sel = getSelectedObjects(); + for (IGraphicsNode o : adapter.getNodes()) + if (o instanceof ISelectableNode) { + if (sel.contains(o)) { + ((ISelectableNode)o).setSelected(true); + } else { + ((ISelectableNode)o).setSelected(false); + } + } + List selected = getSelectedResources(); + // TODO : don't know why this code is here, but it seems unnecessary +// for (Resource r : selected) { +// if (!adapter.hasNode(r)) { +// // instantiating a new resource : usin this editor's tc +// Resource resource = graph.getResource(r.getId()); +// adapter.addInbound(resource).setSelected(true); +// +// } +// } + + } + + public void setEditorSelection(boolean addShapes) { + + List sel = getSelectedObjects(); + for (IGraphicsNode o : adapter.getNodes()) + if (o instanceof ISelectableNode) { + if (sel.contains(o)) { + ((ISelectableNode)o).setSelected(true); + } else { + ((ISelectableNode)o).setSelected(false); + } + } + if (addShapes) { + // TODO : don't know why this code is here, but it seems unnecessary +// List selected = getSelectedResources(); +// for (Resource r : selected) { +// if (!adapter.hasNode(r)) { +// if (r.isInstanceOf(GlobalIdMap.get(PSK3DModelingOntologyMapping.EQUIPMENT))) { +// Resource group = GraphicsNodeTools.getModelFromResource(r); +// if (group != null && group.getId() == plant.getResource().getId()) { +//// instantiating a new resource : usin this editor's tc +// Resource resource = graph.getResource(r.getId()); +// adapter.addInbound(resource).setSelected(true); +// } +// +// } +// } +// } + } + } + + @Override + protected void setEditorHighlightSelection() { + List sel = getInteractiveSelectedObjects(); + for (IGraphicsNode o : adapter.getNodes()) + if (o instanceof ISelectableNode) { + if (sel.contains(o)) { + ((ISelectableNode)o).setHighlighted(true); + } else { + ((ISelectableNode)o).setHighlighted(false); + } + } + } + } + + private class FloorConfigureDialog extends Dialog implements KeyListener,SelectionListener { + + private boolean floorEnabled = true; + private double floorHeight = 0.0; + + private Text floorHeightText = null; + private Button floorEnabledButton = null; + + public FloorConfigureDialog(Shell shell) { + super(shell); + } + + @Override + protected Control createDialogArea(Composite parent) { + Composite composite = (Composite) super.createDialogArea(parent); + Label label = new Label(composite, SWT.WRAP); + label.setText("Configure floor"); + GridData data = new GridData(GridData.GRAB_HORIZONTAL + | GridData.GRAB_VERTICAL | GridData.HORIZONTAL_ALIGN_FILL + | GridData.VERTICAL_ALIGN_CENTER); + + data.widthHint = convertHorizontalDLUsToPixels(IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH); + label.setLayoutData(data); + label.setFont(parent.getFont()); + floorEnabledButton = new Button(composite,SWT.CHECK); + floorEnabledButton.setText("Enabled"); + label = new Label(composite, SWT.WRAP); + label.setText("Height"); + label.setLayoutData(data); + label.setFont(parent.getFont()); + floorHeightText = new Text(composite,SWT.NONE); + + + floorHeightText.addKeyListener(this); + floorEnabledButton.addSelectionListener(this); + floorEnabledButton.setSelection(floorEnabled); + floorHeightText.setText(Double.toString(floorHeight)); + + return composite; + } + + @Override + protected void configureShell(Shell newShell) { + super.configureShell(newShell); + newShell.setText("Configure floor"); + } + + public void keyPressed(KeyEvent e) { + + } + + public void keyReleased(KeyEvent e) { + boolean ok = true; + try { + floorHeight = Double.parseDouble(floorHeightText.getText()); + } catch (NumberFormatException err) { + ok = false; + } + if (ok) { + this.getButton(IDialogConstants.OK_ID).setEnabled(true); + } else { + this.getButton(IDialogConstants.OK_ID).setEnabled(false); + } + } + + public void widgetDefaultSelected(SelectionEvent e) { + + } + + public void widgetSelected(SelectionEvent e) { + floorEnabled = floorEnabledButton.getSelection(); + } + + public boolean isFloorEnabled() { + return floorEnabled; + } + + public double getFloorHeight() { + return floorHeight; + } + + } + + @Override + protected void hookDragAndDrop() { + super.hookDragAndDrop(); + dropTarget.addDropListener(new InsertEquipmentAction(this)); + dropTarget.addDropListener(new InsertNozzleAction(this)); + dropTarget.addDropListener(new InsertComponentAction(this)); + dropTarget.addDropListener(new RoutePipeAction(this)); + } + + @Override + public Object getAdapter(Class adapter) { + if (adapter == IContentOutlinePage.class) { + if (getPlantResource() == null) + return null; + final PlantStructureOutlinePage page = new PlantStructureOutlinePage(sessionContext,getPlantResource()); + + getSelectionAdapter().addSelectionChangedListener(new ISelectionChangedListener() { + @Override + public void selectionChanged(SelectionChangedEvent event) { + page.setSelection(event.getSelection()); + + } + }); + parent.getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + page.addSelectionChangedListener(new ISelectionChangedListener() { + @Override + public void selectionChanged(SelectionChangedEvent event) { + selectionAdapter.setSelection(SelectionAdapter.transformSelection(event.getSelection())); + } + }); + } + }); + + + + return page; + } + return null; + } +} \ No newline at end of file diff --git a/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/ProcessEditorPart.java b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/ProcessEditorPart.java new file mode 100644 index 00000000..a83f40b5 --- /dev/null +++ b/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/views/ProcessEditorPart.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package fi.vtt.simantics.processeditor.views; + +import org.simantics.db.management.ISessionContext; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorPart; + + +public class ProcessEditorPart extends ThreeDimensionalEditorPart { + + @Override + protected ThreeDimensionalEditorBase createEditor(ISessionContext session) { + return new ProcessEditor(session); + } + +} -- 2.45.2