Visualization refactoring
This commit is contained in:
parent
0d15bc1d0b
commit
8c77d3800b
@ -0,0 +1,23 @@
|
|||||||
|
package hep.dataforge.vis
|
||||||
|
|
||||||
|
import javafx.scene.paint.Color
|
||||||
|
import javafx.scene.paint.PhongMaterial
|
||||||
|
|
||||||
|
object Materials{
|
||||||
|
val RED = PhongMaterial().apply {
|
||||||
|
diffuseColor = Color.DARKRED
|
||||||
|
specularColor = Color.RED
|
||||||
|
}
|
||||||
|
|
||||||
|
val WHITE = PhongMaterial().apply {
|
||||||
|
diffuseColor = Color.WHITE
|
||||||
|
specularColor = Color.LIGHTBLUE
|
||||||
|
}
|
||||||
|
|
||||||
|
val GREY = PhongMaterial().apply {
|
||||||
|
diffuseColor = Color.DARKGREY
|
||||||
|
specularColor = Color.GREY
|
||||||
|
}
|
||||||
|
|
||||||
|
val BLUE = PhongMaterial(Color.BLUE)
|
||||||
|
}
|
@ -0,0 +1,157 @@
|
|||||||
|
package hep.dataforge.vis.spatial
|
||||||
|
|
||||||
|
import javafx.event.EventHandler
|
||||||
|
import javafx.scene.*
|
||||||
|
import javafx.scene.input.KeyCode
|
||||||
|
import javafx.scene.input.KeyEvent
|
||||||
|
import javafx.scene.input.MouseEvent
|
||||||
|
import javafx.scene.input.ScrollEvent
|
||||||
|
import javafx.scene.paint.Color
|
||||||
|
import org.fxyz3d.utils.CameraTransformer
|
||||||
|
import tornadofx.*
|
||||||
|
|
||||||
|
class Canvas3D : Fragment() {
|
||||||
|
val world: Group = Group()
|
||||||
|
|
||||||
|
private val camera = PerspectiveCamera().apply {
|
||||||
|
nearClip = CAMERA_NEAR_CLIP
|
||||||
|
farClip = CAMERA_FAR_CLIP
|
||||||
|
translateZ = CAMERA_INITIAL_DISTANCE
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO move up
|
||||||
|
val cameraShift = CameraTransformer().apply {
|
||||||
|
val cameraFlip = CameraTransformer()
|
||||||
|
cameraFlip.children.add(camera)
|
||||||
|
cameraFlip.setRotateZ(180.0)
|
||||||
|
children.add(cameraFlip)
|
||||||
|
}
|
||||||
|
|
||||||
|
val cameraRotation = CameraTransformer().apply {
|
||||||
|
children.add(cameraShift)
|
||||||
|
ry.angle = CAMERA_INITIAL_Y_ANGLE
|
||||||
|
rx.angle = CAMERA_INITIAL_X_ANGLE
|
||||||
|
rz.angle = CAMERA_INITIAL_Z_ANGLE
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override val root =borderpane {
|
||||||
|
center = SubScene(
|
||||||
|
Group(world, cameraRotation).apply { DepthTest.ENABLE },
|
||||||
|
1024.0,
|
||||||
|
768.0,
|
||||||
|
true,
|
||||||
|
SceneAntialiasing.BALANCED
|
||||||
|
).apply {
|
||||||
|
fill = Color.GREY
|
||||||
|
this.camera = this@Canvas3D.camera
|
||||||
|
id = "canvas"
|
||||||
|
handleKeyboard(this)
|
||||||
|
handleMouse(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun handleKeyboard(scene: SubScene) {
|
||||||
|
scene.onKeyPressed = EventHandler<KeyEvent> { event ->
|
||||||
|
if (event.isControlDown) {
|
||||||
|
when (event.code) {
|
||||||
|
KeyCode.Z -> {
|
||||||
|
cameraShift.t.x = 0.0
|
||||||
|
cameraShift.t.y = 0.0
|
||||||
|
camera.translateZ = CAMERA_INITIAL_DISTANCE
|
||||||
|
cameraRotation.ry.angle = CAMERA_INITIAL_Y_ANGLE
|
||||||
|
cameraRotation.rx.angle = CAMERA_INITIAL_X_ANGLE
|
||||||
|
}
|
||||||
|
// KeyCode.X -> axisGroup.isVisible = !axisGroup.isVisible
|
||||||
|
// KeyCode.S -> snapshot()
|
||||||
|
// KeyCode.DIGIT1 -> pixelMap.filterKeys { it.getLayerNumber() == 1 }.values.forEach {
|
||||||
|
// toggleTransparency(
|
||||||
|
// it
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
// KeyCode.DIGIT2 -> pixelMap.filterKeys { it.getLayerNumber() == 2 }.values.forEach {
|
||||||
|
// toggleTransparency(
|
||||||
|
// it
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
// KeyCode.DIGIT3 -> pixelMap.filterKeys { it.getLayerNumber() == 3 }.values.forEach {
|
||||||
|
// toggleTransparency(
|
||||||
|
// it
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
else -> {
|
||||||
|
}//do nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleMouse(scene: SubScene) {
|
||||||
|
|
||||||
|
var mousePosX: Double = 0.0
|
||||||
|
var mousePosY: Double = 0.0
|
||||||
|
var mouseOldX: Double = 0.0
|
||||||
|
var mouseOldY: Double = 0.0
|
||||||
|
var mouseDeltaX: Double = 0.0
|
||||||
|
var mouseDeltaY: Double = 0.0
|
||||||
|
|
||||||
|
scene.onMousePressed = EventHandler<MouseEvent> { me ->
|
||||||
|
mousePosX = me.sceneX
|
||||||
|
mousePosY = me.sceneY
|
||||||
|
mouseOldX = me.sceneX
|
||||||
|
mouseOldY = me.sceneY
|
||||||
|
}
|
||||||
|
|
||||||
|
scene.onMouseDragged = EventHandler<MouseEvent> { me ->
|
||||||
|
mouseOldX = mousePosX
|
||||||
|
mouseOldY = mousePosY
|
||||||
|
mousePosX = me.sceneX
|
||||||
|
mousePosY = me.sceneY
|
||||||
|
mouseDeltaX = mousePosX - mouseOldX
|
||||||
|
mouseDeltaY = mousePosY - mouseOldY
|
||||||
|
|
||||||
|
val modifier = when {
|
||||||
|
me.isControlDown -> CONTROL_MULTIPLIER
|
||||||
|
me.isShiftDown -> SHIFT_MULTIPLIER
|
||||||
|
else -> 1.0
|
||||||
|
}
|
||||||
|
|
||||||
|
if (me.isPrimaryButtonDown) {
|
||||||
|
cameraRotation.rz.angle =
|
||||||
|
cameraRotation.rz.angle + mouseDeltaX * MOUSE_SPEED * modifier * ROTATION_SPEED
|
||||||
|
cameraRotation.rx.angle =
|
||||||
|
cameraRotation.rx.angle + mouseDeltaY * MOUSE_SPEED * modifier * ROTATION_SPEED
|
||||||
|
// } else if (me.isSecondaryButtonDown()) {
|
||||||
|
// double z = camera.getTranslateZ();
|
||||||
|
// double newZ = z + mouseDeltaX * MOUSE_SPEED * modifier*100;
|
||||||
|
// camera.setTranslateZ(newZ);
|
||||||
|
} else if (me.isSecondaryButtonDown) {
|
||||||
|
cameraShift.t.x = cameraShift.t.x + mouseDeltaX * MOUSE_SPEED * modifier * TRACK_SPEED
|
||||||
|
cameraShift.t.y = cameraShift.t.y + mouseDeltaY * MOUSE_SPEED * modifier * TRACK_SPEED
|
||||||
|
}
|
||||||
|
}
|
||||||
|
scene.onScroll = EventHandler<ScrollEvent> { event ->
|
||||||
|
val z = camera.translateZ
|
||||||
|
val newZ = z + MOUSE_SPEED * event.deltaY * RESIZE_SPEED
|
||||||
|
camera.translateZ = newZ
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val CAMERA_INITIAL_DISTANCE = -4500.0
|
||||||
|
private const val CAMERA_INITIAL_X_ANGLE = -50.0
|
||||||
|
private const val CAMERA_INITIAL_Y_ANGLE = 0.0
|
||||||
|
private const val CAMERA_INITIAL_Z_ANGLE = -210.0
|
||||||
|
private const val CAMERA_NEAR_CLIP = 0.1
|
||||||
|
private const val CAMERA_FAR_CLIP = 10000.0
|
||||||
|
private const val AXIS_LENGTH = 2000.0
|
||||||
|
private const val CONTROL_MULTIPLIER = 0.1
|
||||||
|
private const val SHIFT_MULTIPLIER = 10.0
|
||||||
|
private const val MOUSE_SPEED = 0.1
|
||||||
|
private const val ROTATION_SPEED = 2.0
|
||||||
|
private const val TRACK_SPEED = 6.0
|
||||||
|
private const val RESIZE_SPEED = 50.0
|
||||||
|
private const val LINE_WIDTH = 3.0
|
||||||
|
}
|
||||||
|
}
|
@ -8,62 +8,20 @@ import hep.dataforge.vis.DisplayGroup
|
|||||||
import hep.dataforge.vis.DisplayObject
|
import hep.dataforge.vis.DisplayObject
|
||||||
import hep.dataforge.vis.DisplayObjectPropertyListener
|
import hep.dataforge.vis.DisplayObjectPropertyListener
|
||||||
import hep.dataforge.vis.transform
|
import hep.dataforge.vis.transform
|
||||||
import javafx.event.EventHandler
|
import javafx.scene.Group
|
||||||
import javafx.scene.*
|
import javafx.scene.Node
|
||||||
import javafx.scene.input.KeyCode
|
|
||||||
import javafx.scene.input.KeyEvent
|
|
||||||
import javafx.scene.input.MouseEvent
|
|
||||||
import javafx.scene.input.ScrollEvent
|
|
||||||
import javafx.scene.paint.Color
|
import javafx.scene.paint.Color
|
||||||
import javafx.scene.paint.PhongMaterial
|
|
||||||
import org.fxyz3d.geometry.Point3D
|
import org.fxyz3d.geometry.Point3D
|
||||||
import org.fxyz3d.shapes.primitives.CuboidMesh
|
import org.fxyz3d.shapes.primitives.CuboidMesh
|
||||||
import org.fxyz3d.utils.CameraTransformer
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* https://github.com/miho/JCSG for operations
|
* https://github.com/miho/JCSG for operations
|
||||||
*
|
*
|
||||||
* TODO move world and camera boilerplate to another class
|
|
||||||
*/
|
*/
|
||||||
class FXSpatialRenderer(override val context: Context) : Output<DisplayObject> {
|
class FXSpatialRenderer(override val context: Context) : Output<DisplayObject> {
|
||||||
|
|
||||||
private val world: Group = Group()
|
val canvas by lazy { Canvas3D() }
|
||||||
|
|
||||||
private val camera = PerspectiveCamera().apply {
|
|
||||||
nearClip = CAMERA_NEAR_CLIP
|
|
||||||
farClip = CAMERA_FAR_CLIP
|
|
||||||
translateZ = CAMERA_INITIAL_DISTANCE
|
|
||||||
}
|
|
||||||
|
|
||||||
val cameraShift = CameraTransformer().apply {
|
|
||||||
val cameraFlip = CameraTransformer()
|
|
||||||
cameraFlip.children.add(camera)
|
|
||||||
cameraFlip.setRotateZ(180.0)
|
|
||||||
children.add(cameraFlip)
|
|
||||||
}
|
|
||||||
|
|
||||||
val cameraRotation = CameraTransformer().apply {
|
|
||||||
children.add(cameraShift)
|
|
||||||
ry.angle = CAMERA_INITIAL_Y_ANGLE
|
|
||||||
rx.angle = CAMERA_INITIAL_X_ANGLE
|
|
||||||
rz.angle = CAMERA_INITIAL_Z_ANGLE
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
val canvas: SubScene = SubScene(
|
|
||||||
Group(world, cameraRotation).apply { DepthTest.ENABLE },
|
|
||||||
1024.0,
|
|
||||||
768.0,
|
|
||||||
true,
|
|
||||||
SceneAntialiasing.BALANCED
|
|
||||||
).apply {
|
|
||||||
fill = Color.GREY
|
|
||||||
this.camera = this@FXSpatialRenderer.camera
|
|
||||||
id = "canvas"
|
|
||||||
handleKeyboard(this)
|
|
||||||
handleMouse(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun buildObject(obj: DisplayObject): Node {
|
private fun buildObject(obj: DisplayObject): Node {
|
||||||
return when (obj) {
|
return when (obj) {
|
||||||
@ -72,6 +30,7 @@ class FXSpatialRenderer(override val context: Context) : Output<DisplayObject> {
|
|||||||
val listener = DisplayObjectPropertyListener(obj)
|
val listener = DisplayObjectPropertyListener(obj)
|
||||||
this.center = Point3D(obj.x.toFloat(), obj.y.toFloat(), obj.z.toFloat())
|
this.center = Point3D(obj.x.toFloat(), obj.y.toFloat(), obj.z.toFloat())
|
||||||
this.diffuseColorProperty().bind(listener["color"].transform {
|
this.diffuseColorProperty().bind(listener["color"].transform {
|
||||||
|
//TODO Move to extension
|
||||||
val int = it.int ?: 0
|
val int = it.int ?: 0
|
||||||
val red = int and 0x00ff0000 shr 16
|
val red = int and 0x00ff0000 shr 16
|
||||||
val green = int and 0x0000ff00 shr 8
|
val green = int and 0x0000ff00 shr 8
|
||||||
@ -84,127 +43,6 @@ class FXSpatialRenderer(override val context: Context) : Output<DisplayObject> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun render(obj: DisplayObject, meta: Meta) {
|
override fun render(obj: DisplayObject, meta: Meta) {
|
||||||
world.children.add(buildObject(obj))
|
canvas.world.children.add(buildObject(obj))
|
||||||
}
|
|
||||||
|
|
||||||
private fun handleKeyboard(scene: SubScene) {
|
|
||||||
scene.onKeyPressed = EventHandler<KeyEvent> { event ->
|
|
||||||
if (event.isControlDown) {
|
|
||||||
when (event.code) {
|
|
||||||
KeyCode.Z -> {
|
|
||||||
cameraShift.t.x = 0.0
|
|
||||||
cameraShift.t.y = 0.0
|
|
||||||
camera.translateZ = CAMERA_INITIAL_DISTANCE
|
|
||||||
cameraRotation.ry.angle = CAMERA_INITIAL_Y_ANGLE
|
|
||||||
cameraRotation.rx.angle = CAMERA_INITIAL_X_ANGLE
|
|
||||||
}
|
|
||||||
// KeyCode.X -> axisGroup.isVisible = !axisGroup.isVisible
|
|
||||||
// KeyCode.S -> snapshot()
|
|
||||||
// KeyCode.DIGIT1 -> pixelMap.filterKeys { it.getLayerNumber() == 1 }.values.forEach {
|
|
||||||
// toggleTransparency(
|
|
||||||
// it
|
|
||||||
// )
|
|
||||||
// }
|
|
||||||
// KeyCode.DIGIT2 -> pixelMap.filterKeys { it.getLayerNumber() == 2 }.values.forEach {
|
|
||||||
// toggleTransparency(
|
|
||||||
// it
|
|
||||||
// )
|
|
||||||
// }
|
|
||||||
// KeyCode.DIGIT3 -> pixelMap.filterKeys { it.getLayerNumber() == 3 }.values.forEach {
|
|
||||||
// toggleTransparency(
|
|
||||||
// it
|
|
||||||
// )
|
|
||||||
// }
|
|
||||||
else -> {
|
|
||||||
}//do nothing
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun handleMouse(scene: SubScene) {
|
|
||||||
|
|
||||||
var mousePosX: Double = 0.0
|
|
||||||
var mousePosY: Double = 0.0
|
|
||||||
var mouseOldX: Double = 0.0
|
|
||||||
var mouseOldY: Double = 0.0
|
|
||||||
var mouseDeltaX: Double = 0.0
|
|
||||||
var mouseDeltaY: Double = 0.0
|
|
||||||
|
|
||||||
scene.onMousePressed = EventHandler<MouseEvent> { me ->
|
|
||||||
mousePosX = me.sceneX
|
|
||||||
mousePosY = me.sceneY
|
|
||||||
mouseOldX = me.sceneX
|
|
||||||
mouseOldY = me.sceneY
|
|
||||||
}
|
|
||||||
|
|
||||||
scene.onMouseDragged = EventHandler<MouseEvent> { me ->
|
|
||||||
mouseOldX = mousePosX
|
|
||||||
mouseOldY = mousePosY
|
|
||||||
mousePosX = me.sceneX
|
|
||||||
mousePosY = me.sceneY
|
|
||||||
mouseDeltaX = mousePosX - mouseOldX
|
|
||||||
mouseDeltaY = mousePosY - mouseOldY
|
|
||||||
|
|
||||||
val modifier = when {
|
|
||||||
me.isControlDown -> CONTROL_MULTIPLIER
|
|
||||||
me.isShiftDown -> SHIFT_MULTIPLIER
|
|
||||||
else -> 1.0
|
|
||||||
}
|
|
||||||
|
|
||||||
if (me.isPrimaryButtonDown) {
|
|
||||||
cameraRotation.rz.angle =
|
|
||||||
cameraRotation.rz.angle + mouseDeltaX * MOUSE_SPEED * modifier * ROTATION_SPEED
|
|
||||||
cameraRotation.rx.angle =
|
|
||||||
cameraRotation.rx.angle + mouseDeltaY * MOUSE_SPEED * modifier * ROTATION_SPEED
|
|
||||||
// } else if (me.isSecondaryButtonDown()) {
|
|
||||||
// double z = camera.getTranslateZ();
|
|
||||||
// double newZ = z + mouseDeltaX * MOUSE_SPEED * modifier*100;
|
|
||||||
// camera.setTranslateZ(newZ);
|
|
||||||
} else if (me.isSecondaryButtonDown) {
|
|
||||||
cameraShift.t.x = cameraShift.t.x + mouseDeltaX * MOUSE_SPEED * modifier * TRACK_SPEED
|
|
||||||
cameraShift.t.y = cameraShift.t.y + mouseDeltaY * MOUSE_SPEED * modifier * TRACK_SPEED
|
|
||||||
}
|
|
||||||
}
|
|
||||||
scene.onScroll = EventHandler<ScrollEvent> { event ->
|
|
||||||
val z = camera.translateZ
|
|
||||||
val newZ = z + MOUSE_SPEED * event.deltaY * RESIZE_SPEED
|
|
||||||
camera.translateZ = newZ
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private const val CAMERA_INITIAL_DISTANCE = -4500.0
|
|
||||||
private const val CAMERA_INITIAL_X_ANGLE = -50.0
|
|
||||||
private const val CAMERA_INITIAL_Y_ANGLE = 0.0
|
|
||||||
private const val CAMERA_INITIAL_Z_ANGLE = -210.0
|
|
||||||
private const val CAMERA_NEAR_CLIP = 0.1
|
|
||||||
private const val CAMERA_FAR_CLIP = 10000.0
|
|
||||||
private const val AXIS_LENGTH = 2000.0
|
|
||||||
private const val CONTROL_MULTIPLIER = 0.1
|
|
||||||
private const val SHIFT_MULTIPLIER = 10.0
|
|
||||||
private const val MOUSE_SPEED = 0.1
|
|
||||||
private const val ROTATION_SPEED = 2.0
|
|
||||||
private const val TRACK_SPEED = 6.0
|
|
||||||
private const val RESIZE_SPEED = 50.0
|
|
||||||
private const val LINE_WIDTH = 3.0
|
|
||||||
|
|
||||||
private val redMaterial = PhongMaterial().apply {
|
|
||||||
diffuseColor = Color.DARKRED
|
|
||||||
specularColor = Color.RED
|
|
||||||
}
|
|
||||||
|
|
||||||
private val whiteMaterial = PhongMaterial().apply {
|
|
||||||
diffuseColor = Color.WHITE
|
|
||||||
specularColor = Color.LIGHTBLUE
|
|
||||||
}
|
|
||||||
|
|
||||||
private val greyMaterial = PhongMaterial().apply {
|
|
||||||
diffuseColor = Color.DARKGREY
|
|
||||||
specularColor = Color.GREY
|
|
||||||
}
|
|
||||||
|
|
||||||
private val blueMaterial = PhongMaterial(Color.BLUE)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -18,7 +18,7 @@ class RendererDemoApp : App(RendererDemoView::class)
|
|||||||
class RendererDemoView : View() {
|
class RendererDemoView : View() {
|
||||||
val renderer = FXSpatialRenderer(Global)
|
val renderer = FXSpatialRenderer(Global)
|
||||||
override val root: Parent = borderpane {
|
override val root: Parent = borderpane {
|
||||||
center = renderer.canvas
|
center = renderer.canvas.root
|
||||||
}
|
}
|
||||||
|
|
||||||
lateinit var group: DisplayGroup
|
lateinit var group: DisplayGroup
|
||||||
@ -51,7 +51,7 @@ class RendererDemoView : View() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
renderer.cameraRotation.apply {
|
renderer.canvas.cameraRotation.apply {
|
||||||
ry.angle = -30.0
|
ry.angle = -30.0
|
||||||
rx.angle = -15.0
|
rx.angle = -15.0
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user