forked from kscience/visionforge
OrbitControls for FX finally working
This commit is contained in:
parent
fb358dbc8e
commit
493c527743
@ -22,7 +22,7 @@ dependencies {
|
||||
exclude(group = "org.openjfx")
|
||||
}
|
||||
|
||||
api("org.fxyz3d:fxyz3d:0.5.2") {
|
||||
api("org.fxyz3d:fxyz3d:0.5.4") {
|
||||
exclude(module = "slf4j-simple")
|
||||
}
|
||||
api("org.jetbrains.kotlinx:kotlinx-coroutines-javafx:${ru.mipt.npm.gradle.KScienceVersions.coroutinesVersion}")
|
||||
|
@ -1,55 +1,73 @@
|
||||
package space.kscience.visionforge.solid
|
||||
|
||||
import javafx.beans.InvalidationListener
|
||||
import javafx.beans.property.SimpleBooleanProperty
|
||||
import javafx.beans.property.SimpleDoubleProperty
|
||||
import javafx.event.EventHandler
|
||||
import javafx.geometry.Point3D
|
||||
import javafx.scene.Camera
|
||||
import javafx.scene.Node
|
||||
import javafx.scene.SubScene
|
||||
import javafx.scene.input.MouseEvent
|
||||
import javafx.scene.input.ScrollEvent
|
||||
import javafx.scene.shape.Sphere
|
||||
import javafx.scene.transform.Rotate
|
||||
import javafx.scene.transform.Rotate.X_AXIS
|
||||
import javafx.scene.transform.Rotate.Y_AXIS
|
||||
import javafx.scene.transform.Translate
|
||||
import space.kscience.dataforge.meta.useProperty
|
||||
import tornadofx.*
|
||||
import kotlin.math.*
|
||||
import kotlin.math.PI
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.max
|
||||
import kotlin.math.sin
|
||||
import space.kscience.visionforge.solid.specifications.Camera as CameraSpec
|
||||
|
||||
|
||||
public class OrbitControls internal constructor(camera: Camera, canvas: SubScene, spec: CameraSpec) {
|
||||
|
||||
public val distanceProperty: SimpleDoubleProperty = SimpleDoubleProperty(spec.distance)
|
||||
public var distance: Double by distanceProperty
|
||||
|
||||
public val azimuthProperty: SimpleDoubleProperty = SimpleDoubleProperty(spec.azimuth)
|
||||
public var azimuth: Double by azimuthProperty
|
||||
|
||||
public val zenithProperty: SimpleDoubleProperty = SimpleDoubleProperty(PI / 2 - spec.latitude)
|
||||
public var zenith: Double by zenithProperty
|
||||
//
|
||||
// public val latitudeProperty: DoubleBinding = zenithProperty.unaryMinus().plus(PI / 2)
|
||||
// public val latitude by latitudeProperty
|
||||
|
||||
public val baseXProperty: SimpleDoubleProperty = SimpleDoubleProperty(0.0)
|
||||
public var x: Double by baseXProperty
|
||||
public val baseYProperty: SimpleDoubleProperty = SimpleDoubleProperty(0.0)
|
||||
public var y: Double by baseYProperty
|
||||
public val baseZProperty: SimpleDoubleProperty = SimpleDoubleProperty(0.0)
|
||||
public var z: Double by baseZProperty
|
||||
|
||||
private val baseTranslate = Translate(0.0, 0.0, 0.0)
|
||||
|
||||
// val basePositionProperty: ObjectBinding<Point3D> =
|
||||
// nonNullObjectBinding(baseXProperty, baseYProperty, baseZProperty) {
|
||||
// Point3D(x, y, z)
|
||||
// }
|
||||
//
|
||||
// val basePosition by basePositionProperty
|
||||
public var x: Double by baseTranslate.xProperty()
|
||||
public var y: Double by baseTranslate.yProperty()
|
||||
public var z: Double by baseTranslate.zProperty()
|
||||
|
||||
private val distanceProperty = SimpleDoubleProperty().apply {
|
||||
spec.useProperty(CameraSpec::distance) {
|
||||
set(it)
|
||||
}
|
||||
}
|
||||
|
||||
private val distanceTranslation = Translate().apply {
|
||||
zProperty().bind(-distanceProperty)
|
||||
}
|
||||
|
||||
public var distance: Double by distanceProperty
|
||||
|
||||
private val centering = Translate().apply {
|
||||
xProperty().bind(-canvas.widthProperty() / 2)
|
||||
yProperty().bind(-canvas.heightProperty() / 2)
|
||||
}
|
||||
|
||||
private val yUpRotation = Rotate(180.0, X_AXIS)
|
||||
|
||||
private val azimuthRotation = Rotate().apply {
|
||||
axis = Y_AXIS
|
||||
angleProperty().bind(azimuthProperty * (180.0 / PI))
|
||||
}
|
||||
|
||||
private val zenithRotation = Rotate().apply {
|
||||
axisProperty().bind(objectBinding(azimuthProperty) {
|
||||
azimuthRotation.inverseTransform(X_AXIS)
|
||||
})
|
||||
angleProperty().bind(-zenithProperty * (180.0 / PI))
|
||||
}
|
||||
|
||||
private val inProgressProperty = SimpleBooleanProperty(false)
|
||||
|
||||
|
||||
public val centerMarker: Node by lazy {
|
||||
Sphere(10.0).also {
|
||||
it.transforms.setAll(baseTranslate)
|
||||
@ -57,75 +75,21 @@ public class OrbitControls internal constructor(camera: Camera, canvas: SubScene
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private val rx = Rotate(0.0, Rotate.X_AXIS)
|
||||
|
||||
private val ry = Rotate(0.0, Rotate.Y_AXIS)
|
||||
|
||||
private val translate = Translate(0.0, 0.0, 0.0)
|
||||
|
||||
//private val rz = Rotate(0.0, Rotate.Z_AXIS)
|
||||
|
||||
|
||||
init {
|
||||
camera.transforms.setAll(baseTranslate, ry, rx, translate)
|
||||
|
||||
update()
|
||||
val listener = InvalidationListener {
|
||||
update()
|
||||
}
|
||||
distanceProperty.addListener(listener)
|
||||
azimuthProperty.addListener(listener)
|
||||
zenithProperty.addListener(listener)
|
||||
baseXProperty.addListener(listener)
|
||||
baseYProperty.addListener(listener)
|
||||
baseZProperty.addListener(listener)
|
||||
camera.transforms.setAll(
|
||||
baseTranslate,
|
||||
yUpRotation,
|
||||
azimuthRotation,
|
||||
zenithRotation,
|
||||
distanceTranslation,
|
||||
centering,
|
||||
)
|
||||
|
||||
canvas.apply {
|
||||
//center.xProperty().bind(widthProperty().divide(2))
|
||||
//center.zProperty().bind(heightProperty().divide(2))
|
||||
handleMouse()
|
||||
}
|
||||
// coordinateContainer?.vbox {
|
||||
// label(distanceProperty.asString())
|
||||
// label(azimuthProperty.asString())
|
||||
// label(zenithProperty.asString())
|
||||
// }
|
||||
}
|
||||
|
||||
private fun update() {
|
||||
val spherePosition = Point3D(
|
||||
sin(zenith) * sin(azimuth),
|
||||
cos(zenith),
|
||||
sin(zenith) * cos(azimuth),
|
||||
).times(distance)
|
||||
val basePosition = Point3D(x, y, z)
|
||||
baseTranslate.x = x
|
||||
baseTranslate.y = y
|
||||
baseTranslate.z = z
|
||||
//Create direction vector
|
||||
val camPosition = basePosition+spherePosition
|
||||
val camDirection: Point3D = (-spherePosition).normalize()
|
||||
|
||||
val xRotation = Math.toDegrees(asin(-camDirection.y))
|
||||
val yRotation = Math.toDegrees(atan2(camDirection.x, camDirection.z))
|
||||
|
||||
rx.pivotX = camPosition.x
|
||||
rx.pivotY = camPosition.y
|
||||
rx.pivotZ = camPosition.z
|
||||
rx.angle = xRotation
|
||||
|
||||
ry.pivotX = camPosition.x
|
||||
ry.pivotY = camPosition.y
|
||||
ry.pivotZ = camPosition.z
|
||||
ry.angle = yRotation
|
||||
|
||||
translate.x = camPosition.x
|
||||
translate.y = camPosition.y
|
||||
translate.z = camPosition.z
|
||||
}
|
||||
|
||||
|
||||
private fun Node.handleMouse() {
|
||||
|
||||
var mousePosX = 0.0
|
||||
@ -135,7 +99,7 @@ public class OrbitControls internal constructor(camera: Camera, canvas: SubScene
|
||||
var mouseDeltaX: Double
|
||||
var mouseDeltaY: Double
|
||||
|
||||
onMousePressed = EventHandler<MouseEvent> { me ->
|
||||
onMousePressed = EventHandler { me ->
|
||||
mousePosX = me.sceneX
|
||||
mousePosY = me.sceneY
|
||||
mouseOldX = me.sceneX
|
||||
@ -143,7 +107,7 @@ public class OrbitControls internal constructor(camera: Camera, canvas: SubScene
|
||||
inProgressProperty.set(true)
|
||||
}
|
||||
|
||||
onMouseDragged = EventHandler<MouseEvent> { me ->
|
||||
onMouseDragged = EventHandler { me ->
|
||||
mouseOldX = mousePosX
|
||||
mouseOldY = mousePosY
|
||||
mousePosX = me.sceneX
|
||||
@ -158,11 +122,11 @@ public class OrbitControls internal constructor(camera: Camera, canvas: SubScene
|
||||
}
|
||||
|
||||
if (me.isPrimaryButtonDown) {
|
||||
azimuth = (azimuth - mouseDeltaX * MOUSE_SPEED * modifier * ROTATION_SPEED).coerceIn(0.0, 2 * PI)
|
||||
zenith = (zenith - mouseDeltaY * MOUSE_SPEED * modifier * ROTATION_SPEED).coerceIn(0.0, PI)
|
||||
azimuth = (azimuth - mouseDeltaX * MOUSE_SPEED * modifier * ROTATION_SPEED)
|
||||
zenith = (zenith - mouseDeltaY * MOUSE_SPEED * modifier * ROTATION_SPEED).coerceIn(-PI, PI)
|
||||
} else if (me.isSecondaryButtonDown) {
|
||||
x += MOUSE_SPEED * modifier * TRACK_SPEED * (mouseDeltaX * cos(azimuth) + mouseDeltaY * sin(azimuth))
|
||||
z += MOUSE_SPEED * modifier * TRACK_SPEED * (-mouseDeltaX * sin(azimuth) + mouseDeltaY * cos(azimuth))
|
||||
x += MOUSE_SPEED * modifier * TRACK_SPEED * (mouseDeltaX * cos(azimuth) - mouseDeltaY * sin(azimuth))
|
||||
z += MOUSE_SPEED * modifier * TRACK_SPEED * ( mouseDeltaX * sin(azimuth) + mouseDeltaY * cos(azimuth))
|
||||
}
|
||||
}
|
||||
|
||||
@ -170,7 +134,7 @@ public class OrbitControls internal constructor(camera: Camera, canvas: SubScene
|
||||
inProgressProperty.set(false)
|
||||
}
|
||||
|
||||
onScroll = EventHandler<ScrollEvent> { event ->
|
||||
onScroll = EventHandler { event ->
|
||||
distance = max(1.0, distance - MOUSE_SPEED * event.deltaY * RESIZE_SPEED)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user