Almost working OrbitControls for FX
This commit is contained in:
parent
26948a88d7
commit
459d256ebd
@ -1,6 +1,6 @@
|
||||
import scientifik.useSerialization
|
||||
|
||||
val dataforgeVersion by extra("0.1.5-dev-5")
|
||||
val dataforgeVersion by extra("0.1.5-dev-6")
|
||||
|
||||
plugins {
|
||||
val kotlinVersion = "1.3.61"
|
||||
|
@ -35,6 +35,7 @@ kotlin {
|
||||
api("hep.dataforge:dataforge-output-html:$dataforgeVersion")
|
||||
api(npm("bootstrap","4.4.1"))
|
||||
implementation(npm("jsoneditor"))
|
||||
implementation(npm("file-saver"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,9 @@
|
||||
package hep.dataforge.js
|
||||
package hep.dataforge.vis.js.editor
|
||||
|
||||
import hep.dataforge.names.NameToken
|
||||
import hep.dataforge.vis.common.VisualGroup
|
||||
import hep.dataforge.vis.common.VisualObject
|
||||
import hep.dataforge.vis.common.isEmpty
|
||||
import hep.dataforge.vis.js.editor.card
|
||||
import kotlinx.html.TagConsumer
|
||||
import kotlinx.html.dom.append
|
||||
import kotlinx.html.js.*
|
||||
|
@ -5,13 +5,9 @@ import hep.dataforge.meta.MetaBuilder
|
||||
import hep.dataforge.meta.buildMeta
|
||||
import hep.dataforge.names.Name
|
||||
import hep.dataforge.names.toName
|
||||
import hep.dataforge.vis.common.VisualObject
|
||||
import hep.dataforge.vis.common.useStyle
|
||||
import hep.dataforge.vis.spatial.*
|
||||
import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_COLOR_KEY
|
||||
import hep.dataforge.vis.spatial.RotationOrder
|
||||
import hep.dataforge.vis.spatial.VisualGroup3D
|
||||
import hep.dataforge.vis.spatial.VisualObject3D
|
||||
import hep.dataforge.vis.spatial.rotationOrder
|
||||
import scientifik.gdml.*
|
||||
import kotlin.random.Random
|
||||
|
||||
@ -37,7 +33,14 @@ class GDMLTransformer(val root: GDML) {
|
||||
var volumeAction: (GDMLGroup) -> Action = { Action.CACHE }
|
||||
|
||||
|
||||
var solidConfiguration: VisualObject3D.(parent: GDMLVolume, solid: GDMLSolid) -> Unit = { _, _ -> }
|
||||
var solidConfiguration: VisualObject3D.(parent: GDMLVolume, solid: GDMLSolid) -> Unit = { parent, solid ->
|
||||
lUnit = LUnit.CM
|
||||
if (parent.physVolumes.isNotEmpty()) {
|
||||
useStyle("opaque") {
|
||||
Material3D.MATERIAL_OPACITY_KEY put 0.3
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun VisualObject3D.useStyle(name: String, builder: MetaBuilder.() -> Unit) {
|
||||
styleCache.getOrPut(name.toName()) {
|
||||
|
@ -6,8 +6,8 @@ import hep.dataforge.names.asName
|
||||
import hep.dataforge.names.plus
|
||||
import hep.dataforge.vis.common.get
|
||||
import hep.dataforge.vis.spatial.*
|
||||
import hep.dataforge.vis.spatial.GeometryConstants.one
|
||||
import hep.dataforge.vis.spatial.GeometryConstants.zero
|
||||
import hep.dataforge.vis.spatial.World.ONE
|
||||
import hep.dataforge.vis.spatial.World.ZERO
|
||||
import scientifik.gdml.*
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.sin
|
||||
@ -21,20 +21,20 @@ private fun VisualObject3D.withPosition(
|
||||
): VisualObject3D = apply {
|
||||
newPos?.let {
|
||||
val point = Point3D(it.x(lUnit), it.y(lUnit), it.z(lUnit))
|
||||
if (position != null || point != zero) {
|
||||
if (position != null || point != ZERO) {
|
||||
position = point
|
||||
}
|
||||
}
|
||||
newRotation?.let {
|
||||
val point = Point3D(it.x(), it.y(), it.z())
|
||||
if (rotation != null || point != zero) {
|
||||
if (rotation != null || point != ZERO) {
|
||||
rotation = point
|
||||
}
|
||||
//this@withPosition.rotationOrder = RotationOrder.ZXY
|
||||
}
|
||||
newScale?.let {
|
||||
val point = Point3D(it.x, it.y, it.z)
|
||||
if (scale != null || point != one) {
|
||||
if (scale != null || point != ONE) {
|
||||
scale = point
|
||||
}
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ class Visual3DPlugin(meta: Meta) : AbstractPlugin(meta) {
|
||||
contextual(Point2DSerializer)
|
||||
contextual(NameSerializer)
|
||||
contextual(NameTokenSerializer)
|
||||
contextual(Meta::class, MetaSerializer)
|
||||
contextual(MetaSerializer)
|
||||
contextual(ConfigSerializer)
|
||||
|
||||
polymorphic(VisualObject::class, VisualObject3D::class) {
|
||||
@ -48,7 +48,8 @@ class Visual3DPlugin(meta: Meta) : AbstractPlugin(meta) {
|
||||
Tube::class with Tube.serializer()
|
||||
Box::class with Box.serializer()
|
||||
Convex::class with Convex.serializer()
|
||||
addSubclass(Extruded.serializer())
|
||||
Extruded::class with Extruded.serializer()
|
||||
addSubclass(Label3D.serializer())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,12 +3,8 @@ package hep.dataforge.vis.spatial
|
||||
import kotlin.math.PI
|
||||
|
||||
object World {
|
||||
const val CAMERA_INITIAL_DISTANCE = -500.0
|
||||
const val CAMERA_INITIAL_X_ANGLE = -50.0
|
||||
const val CAMERA_INITIAL_Y_ANGLE = 0.0
|
||||
const val CAMERA_INITIAL_Z_ANGLE = -210.0
|
||||
const val CAMERA_NEAR_CLIP = 0.1
|
||||
const val CAMERA_FAR_CLIP = 10000.0
|
||||
val ZERO = Point3D(0.0, 0.0, 0.0)
|
||||
val ONE = Point3D(1.0, 1.0, 1.0)
|
||||
}
|
||||
|
||||
const val PI2: Float = 2 * PI.toFloat()
|
@ -39,8 +39,3 @@ fun Point3D.toMeta() = buildMeta {
|
||||
VisualObject3D.y put y
|
||||
VisualObject3D.z put z
|
||||
}
|
||||
|
||||
object GeometryConstants {
|
||||
val zero = Point3D(0.0, 0.0, 0.0)
|
||||
val one = Point3D(1.0, 1.0, 1.0)
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package hep.dataforge.vis.spatial.specifications
|
||||
|
||||
import hep.dataforge.meta.*
|
||||
|
||||
class AxesSpec(override val config: Config) : Specific {
|
||||
var visible by boolean(!config.isEmpty())
|
||||
var size by double(AXIS_SIZE)
|
||||
var width by double(AXIS_WIDTH)
|
||||
|
||||
companion object : Specification<AxesSpec> {
|
||||
override fun wrap(config: Config): AxesSpec = AxesSpec(config)
|
||||
|
||||
const val AXIS_SIZE = 1000.0
|
||||
const val AXIS_WIDTH = 3.0
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package hep.dataforge.vis.spatial.specifications
|
||||
|
||||
import hep.dataforge.meta.*
|
||||
import kotlin.math.PI
|
||||
|
||||
class CameraSpec(override val config: Config) : Specific {
|
||||
var fov by int(FIELD_OF_VIEW)
|
||||
//var aspect by double(1.0)
|
||||
var nearClip by double(NEAR_CLIP)
|
||||
var farClip by double(FAR_CLIP)
|
||||
|
||||
var distance by double(INITIAL_DISTANCE)
|
||||
var azimuth by double(INITIAL_AZIMUTH)
|
||||
var latitude by double(INITIAL_LATITUDE)
|
||||
val zenith: Double get() = PI / 2 - latitude
|
||||
|
||||
companion object : Specification<CameraSpec> {
|
||||
override fun wrap(config: Config): CameraSpec = CameraSpec(config)
|
||||
const val INITIAL_DISTANCE = 300.0
|
||||
const val INITIAL_AZIMUTH = 0.0
|
||||
const val INITIAL_LATITUDE = PI/6
|
||||
const val NEAR_CLIP = 0.1
|
||||
const val FAR_CLIP = 10000.0
|
||||
const val FIELD_OF_VIEW = 75
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package hep.dataforge.vis.spatial.specifications
|
||||
|
||||
import hep.dataforge.meta.*
|
||||
|
||||
class CanvasSpec(override val config: Config) : Specific {
|
||||
var axes by spec(AxesSpec)
|
||||
var camera by spec(CameraSpec)
|
||||
var controls by spec(ControlsSpec)
|
||||
var minSize by int(300)
|
||||
|
||||
companion object: Specification<CanvasSpec>{
|
||||
override fun wrap(config: Config): CanvasSpec = CanvasSpec(config)
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package hep.dataforge.vis.spatial.specifications
|
||||
|
||||
import hep.dataforge.meta.Config
|
||||
import hep.dataforge.meta.Specific
|
||||
import hep.dataforge.meta.Specification
|
||||
|
||||
class ControlsSpec(override val config: Config) : Specific {
|
||||
companion object : Specification<ControlsSpec> {
|
||||
override fun wrap(config: Config): ControlsSpec = ControlsSpec(config)
|
||||
}
|
||||
}
|
@ -15,8 +15,8 @@ internal fun mergeChild(parent: VisualGroup, child: VisualObject): VisualObject
|
||||
//parent.properties?.let { config.update(it) }
|
||||
|
||||
if (this is VisualObject3D && parent is VisualObject3D) {
|
||||
position = (position ?: GeometryConstants.zero) + (parent.position ?: GeometryConstants.zero)
|
||||
rotation = (parent.rotation ?: GeometryConstants.zero) + (parent.rotation ?: GeometryConstants.zero)
|
||||
position = (position ?: World.ZERO) + (parent.position ?: World.ZERO)
|
||||
rotation = (parent.rotation ?: World.ZERO) + (parent.rotation ?: World.ZERO)
|
||||
scale = when {
|
||||
scale == null && parent.scale == null -> null
|
||||
scale == null -> parent.scale
|
||||
|
@ -1,59 +1,61 @@
|
||||
package hep.dataforge.vis.spatial.three
|
||||
|
||||
import hep.dataforge.context.Context
|
||||
import hep.dataforge.meta.*
|
||||
import hep.dataforge.meta.Meta
|
||||
import hep.dataforge.meta.get
|
||||
import hep.dataforge.meta.string
|
||||
import hep.dataforge.output.Renderer
|
||||
import hep.dataforge.vis.common.Colors
|
||||
import hep.dataforge.vis.spatial.Point3D
|
||||
import hep.dataforge.vis.spatial.VisualObject3D
|
||||
import hep.dataforge.vis.spatial.World
|
||||
import hep.dataforge.vis.spatial.specifications.AxesSpec
|
||||
import hep.dataforge.vis.spatial.specifications.CameraSpec
|
||||
import hep.dataforge.vis.spatial.specifications.CanvasSpec
|
||||
import hep.dataforge.vis.spatial.specifications.ControlsSpec
|
||||
import info.laht.threekt.WebGLRenderer
|
||||
import info.laht.threekt.cameras.PerspectiveCamera
|
||||
import info.laht.threekt.external.controls.OrbitControls
|
||||
import info.laht.threekt.external.controls.TrackballControls
|
||||
import info.laht.threekt.helpers.AxesHelper
|
||||
import info.laht.threekt.lights.AmbientLight
|
||||
import info.laht.threekt.scenes.Scene
|
||||
import org.w3c.dom.HTMLElement
|
||||
import org.w3c.dom.Node
|
||||
import kotlin.browser.window
|
||||
import kotlin.dom.clear
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.max
|
||||
import kotlin.math.sin
|
||||
|
||||
class ThreeCanvas(val three: ThreePlugin, val meta: Meta = EmptyMeta) : Renderer<VisualObject3D> {
|
||||
class ThreeCanvas(val three: ThreePlugin, val spec: CanvasSpec) : Renderer<VisualObject3D> {
|
||||
|
||||
override val context: Context get() = three.context
|
||||
|
||||
var data: VisualObject3D? = null
|
||||
var content: VisualObject3D? = null
|
||||
private set
|
||||
|
||||
val axes = AxesHelper(meta["axes.size"].int ?: 50).apply { visible = false }
|
||||
val axes = AxesHelper(spec.axes.size.toInt()).apply {
|
||||
visible = spec.axes.visible
|
||||
}
|
||||
|
||||
val scene: Scene = Scene().apply {
|
||||
add(AmbientLight())
|
||||
if (meta["axes.visible"].boolean == true) {
|
||||
axes.visible = true
|
||||
}
|
||||
add(axes)
|
||||
}
|
||||
|
||||
private fun buildCamera(meta: Meta) = PerspectiveCamera(
|
||||
meta["fov"].int ?: 75,
|
||||
meta["aspect"].double ?: 1.0,
|
||||
meta["nearClip"].double ?: World.CAMERA_NEAR_CLIP,
|
||||
meta["farClip"].double ?: World.CAMERA_FAR_CLIP
|
||||
val camera = buildCamera(spec.camera)
|
||||
|
||||
private fun buildCamera(spec: CameraSpec) = PerspectiveCamera(
|
||||
spec.fov,
|
||||
1.0,
|
||||
spec.nearClip,
|
||||
spec.farClip
|
||||
).apply {
|
||||
position.setZ(World.CAMERA_INITIAL_DISTANCE)
|
||||
rotation.set(
|
||||
World.CAMERA_INITIAL_X_ANGLE,
|
||||
World.CAMERA_INITIAL_Y_ANGLE,
|
||||
World.CAMERA_INITIAL_Z_ANGLE
|
||||
)
|
||||
translateX(spec.distance* sin(spec.zenith) * sin(spec.azimuth))
|
||||
translateY(spec.distance* cos(spec.zenith))
|
||||
translateZ(spec.distance * sin(spec.zenith) * cos(spec.azimuth))
|
||||
}
|
||||
|
||||
val camera = buildCamera(meta["camera"].node ?: EmptyMeta)
|
||||
|
||||
private fun addControls(element: Node, meta: Meta) {
|
||||
when (meta["type"].string) {
|
||||
private fun addControls(element: Node, controlsSpec: ControlsSpec) {
|
||||
when (controlsSpec["type"].string) {
|
||||
"trackball" -> TrackballControls(camera, element)
|
||||
else -> OrbitControls(camera, element)
|
||||
}
|
||||
@ -69,7 +71,7 @@ class ThreeCanvas(val three: ThreePlugin, val meta: Meta = EmptyMeta) : Renderer
|
||||
|
||||
}
|
||||
|
||||
addControls(renderer.domElement, meta["controls"].node ?: EmptyMeta)
|
||||
addControls(renderer.domElement, spec.controls ?: ControlsSpec.empty())
|
||||
|
||||
fun animate() {
|
||||
window.requestAnimationFrame {
|
||||
@ -80,9 +82,7 @@ class ThreeCanvas(val three: ThreePlugin, val meta: Meta = EmptyMeta) : Renderer
|
||||
|
||||
element.appendChild(renderer.domElement)
|
||||
|
||||
val minSize by meta.number(0).int
|
||||
|
||||
renderer.setSize(max(minSize, element.offsetWidth), max(minSize, element.offsetWidth))
|
||||
renderer.setSize(max(spec.minSize, element.offsetWidth), max(spec.minSize, element.offsetWidth))
|
||||
|
||||
element.onresize = {
|
||||
renderer.setSize(element.offsetWidth, element.offsetWidth)
|
||||
@ -93,13 +93,13 @@ class ThreeCanvas(val three: ThreePlugin, val meta: Meta = EmptyMeta) : Renderer
|
||||
}
|
||||
|
||||
override fun render(obj: VisualObject3D, meta: Meta) {
|
||||
data = obj
|
||||
content = obj
|
||||
scene.add(three.buildObject3D(obj))
|
||||
}
|
||||
}
|
||||
|
||||
fun ThreePlugin.output(element: HTMLElement? = null, meta: Meta = EmptyMeta, override: MetaBuilder.() -> Unit = {}) =
|
||||
ThreeCanvas(this, buildMeta(meta, override)).apply {
|
||||
fun ThreePlugin.output(element: HTMLElement? = null, spec: CanvasSpec = CanvasSpec.empty()): ThreeCanvas =
|
||||
ThreeCanvas(this, spec).apply {
|
||||
if (element != null) {
|
||||
attach(element)
|
||||
}
|
||||
|
@ -1,29 +1,35 @@
|
||||
package hep.dataforge.vis.spatial.three
|
||||
|
||||
import hep.dataforge.vis.spatial.Label3D
|
||||
import hep.dataforge.vis.spatial.color
|
||||
import info.laht.threekt.DoubleSide
|
||||
import info.laht.threekt.core.Object3D
|
||||
import info.laht.threekt.geometries.PlaneGeometry
|
||||
import info.laht.threekt.geometries.PlaneBufferGeometry
|
||||
import info.laht.threekt.materials.MeshBasicMaterial
|
||||
import info.laht.threekt.objects.Mesh
|
||||
import info.laht.threekt.textures.Texture
|
||||
import org.w3c.dom.CanvasRenderingContext2D
|
||||
import org.w3c.dom.HTMLCanvasElement
|
||||
import org.w3c.dom.*
|
||||
import kotlin.browser.document
|
||||
import kotlin.math.PI
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
/**
|
||||
* Using example from http://stemkoski.github.io/Three.js/Texture-From-Canvas.html
|
||||
*/
|
||||
object ThreeTextFactory : ThreeFactory<Label3D> {
|
||||
object ThreeLabelFactory : ThreeFactory<Label3D> {
|
||||
override val type: KClass<in Label3D> get() = Label3D::class
|
||||
|
||||
override fun invoke(obj: Label3D): Object3D {
|
||||
val canvas = document.createElement("canvas") as HTMLCanvasElement
|
||||
val context = canvas.getContext("2d") as CanvasRenderingContext2D
|
||||
context.font = "${obj.fontSize}pt ${obj.fontFamily}"
|
||||
context.fillStyle = "rgba(255,0,0,0.95)"//obj.material?.color ?: "black"
|
||||
context.fillText(obj.text, 0.0, 0.0)
|
||||
context.font = "Bold ${obj.fontSize}pt ${obj.fontFamily}"
|
||||
context.fillStyle = obj.color ?: "black"
|
||||
context.textAlign = CanvasTextAlign.CENTER
|
||||
//context.textBaseline = CanvasTextBaseline.MIDDLE
|
||||
val metrics = context.measureText(obj.text)
|
||||
|
||||
context.fillText(obj.text, 0.5*metrics.width, 0.5*metrics.width)
|
||||
|
||||
|
||||
// canvas contents will be used for a texture
|
||||
val texture = Texture(canvas)
|
||||
@ -32,14 +38,16 @@ object ThreeTextFactory : ThreeFactory<Label3D> {
|
||||
val material = MeshBasicMaterial().apply {
|
||||
map = texture
|
||||
side = DoubleSide
|
||||
transparent = true
|
||||
}
|
||||
material.transparent = true;
|
||||
|
||||
val mesh = Mesh(
|
||||
PlaneGeometry(canvas.clientWidth, canvas.clientHeight),
|
||||
PlaneBufferGeometry(canvas.width, canvas.height),
|
||||
material
|
||||
)
|
||||
|
||||
//mesh.rotateX(PI)
|
||||
|
||||
mesh.updatePosition(obj)
|
||||
|
||||
return mesh
|
@ -27,7 +27,7 @@ class ThreePlugin : AbstractPlugin() {
|
||||
objectFactories[Sphere::class] = ThreeSphereFactory
|
||||
objectFactories[ConeSegment::class] = ThreeCylinderFactory
|
||||
objectFactories[PolyLine::class] = ThreeLineFactory
|
||||
objectFactories[Label3D::class] = ThreeTextFactory
|
||||
objectFactories[Label3D::class] = ThreeLabelFactory
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
|
@ -1,45 +1,61 @@
|
||||
package hep.dataforge.vis.spatial.three
|
||||
|
||||
import hep.dataforge.js.requireJS
|
||||
import hep.dataforge.vis.js.editor.card
|
||||
import hep.dataforge.vis.spatial.Visual3DPlugin
|
||||
import hep.dataforge.vis.spatial.VisualGroup3D
|
||||
import kotlinx.html.InputType
|
||||
import kotlinx.html.TagConsumer
|
||||
import kotlinx.html.button
|
||||
import kotlinx.html.dom.append
|
||||
import kotlinx.html.js.*
|
||||
import org.w3c.dom.Element
|
||||
import org.w3c.dom.HTMLElement
|
||||
import org.w3c.dom.events.Event
|
||||
import org.w3c.files.Blob
|
||||
import org.w3c.files.BlobPropertyBag
|
||||
import kotlin.dom.clear
|
||||
|
||||
//private fun download(filename: String, text: String) {
|
||||
// var element = document.createElement("a");
|
||||
// element.setAttribute("href", "data:text/json;charset=utf-8," + encodeURIComponent(text));
|
||||
// element.setAttribute("download", filename);
|
||||
//
|
||||
// element.style.display = 'none';
|
||||
// document.body.appendChild(element);
|
||||
//
|
||||
// element.click();
|
||||
//
|
||||
// document.body.removeChild(element);
|
||||
//}
|
||||
private fun saveData(event: Event, fileName: String, mimeType: String = "text/plain", dataBuilder: () -> String) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
|
||||
fun Element.threeOutputConfig(canvas: ThreeCanvas) {
|
||||
val fileSaver = requireJS("file-saver")
|
||||
val blob = Blob(arrayOf(dataBuilder()), BlobPropertyBag("$mimeType;charset=utf-8"))
|
||||
fileSaver.saveAs(blob, fileName)
|
||||
}
|
||||
|
||||
fun Element.threeSettings(canvas: ThreeCanvas, block: TagConsumer<HTMLElement>.() -> Unit = {}) {
|
||||
clear()
|
||||
append {
|
||||
card("Settings") {
|
||||
div("row") {
|
||||
div("col-1") {
|
||||
label { +"Axes" }
|
||||
div("col-2") {
|
||||
label("checkbox-inline") {
|
||||
input(type = InputType.checkBox).apply {
|
||||
checked = canvas.axes.visible
|
||||
onChangeFunction = {
|
||||
canvas.axes.visible = checked
|
||||
}
|
||||
}
|
||||
+"Axes"
|
||||
}
|
||||
}
|
||||
div("col-1") {
|
||||
button {
|
||||
+"Export"
|
||||
onClickFunction = {
|
||||
|
||||
val json = (canvas.content as? VisualGroup3D)?.let { group ->
|
||||
Visual3DPlugin.json.stringify(
|
||||
VisualGroup3D.serializer(),
|
||||
group
|
||||
)
|
||||
}
|
||||
if (json != null) {
|
||||
saveData(it, "object.json", "text/json"){
|
||||
json
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -66,5 +82,6 @@ fun Element.threeOutputConfig(canvas: ThreeCanvas) {
|
||||
}
|
||||
}
|
||||
}
|
||||
block()
|
||||
}
|
||||
}
|
@ -5,7 +5,6 @@ import hep.dataforge.meta.float
|
||||
import hep.dataforge.meta.get
|
||||
import hep.dataforge.meta.node
|
||||
import hep.dataforge.vis.spatial.*
|
||||
import hep.dataforge.vis.spatial.GeometryConstants.zero
|
||||
import info.laht.threekt.core.*
|
||||
import info.laht.threekt.external.controls.OrbitControls
|
||||
import info.laht.threekt.materials.Material
|
||||
@ -13,6 +12,7 @@ import info.laht.threekt.math.Euler
|
||||
import info.laht.threekt.math.Vector3
|
||||
import info.laht.threekt.objects.Mesh
|
||||
import info.laht.threekt.textures.Texture
|
||||
import kotlin.math.PI
|
||||
|
||||
/**
|
||||
* Utility methods for three.kt.
|
||||
@ -30,6 +30,8 @@ val MetaItem<*>.vector get() = Vector3(node["x"].float ?: 0f, node["y"].float ?:
|
||||
|
||||
fun Geometry.toBufferGeometry(): BufferGeometry = BufferGeometry().apply { fromGeometry(this@toBufferGeometry) }
|
||||
|
||||
internal fun Double.toRadians() = this * PI / 180
|
||||
|
||||
fun CSG.toGeometry(): Geometry {
|
||||
val geom = Geometry()
|
||||
|
||||
@ -45,7 +47,7 @@ fun CSG.toGeometry(): Geometry {
|
||||
}
|
||||
|
||||
for (j in 3..polygon.vertices.size) {
|
||||
val fc = Face3(v0, v0 + j - 2, v0 + j - 1, zero)
|
||||
val fc = Face3(v0, v0 + j - 2, v0 + j - 1, World.ZERO)
|
||||
fc.vertexNormals = arrayOf(
|
||||
Vector3().copy(pvs[0].normal),
|
||||
Vector3().copy(pvs[j - 2].normal),
|
||||
|
@ -2,29 +2,20 @@ package hep.dataforge.vis.spatial.fx
|
||||
|
||||
import hep.dataforge.context.Context
|
||||
import hep.dataforge.context.ContextAware
|
||||
import hep.dataforge.meta.*
|
||||
import hep.dataforge.meta.Meta
|
||||
import hep.dataforge.output.Renderer
|
||||
import hep.dataforge.vis.spatial.VisualObject3D
|
||||
import hep.dataforge.vis.spatial.World.CAMERA_FAR_CLIP
|
||||
import hep.dataforge.vis.spatial.World.CAMERA_INITIAL_DISTANCE
|
||||
import hep.dataforge.vis.spatial.World.CAMERA_INITIAL_X_ANGLE
|
||||
import hep.dataforge.vis.spatial.World.CAMERA_INITIAL_Y_ANGLE
|
||||
import hep.dataforge.vis.spatial.World.CAMERA_NEAR_CLIP
|
||||
import hep.dataforge.vis.spatial.specifications.CanvasSpec
|
||||
import javafx.application.Platform
|
||||
import javafx.beans.property.ObjectProperty
|
||||
import javafx.beans.property.SimpleObjectProperty
|
||||
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.layout.BorderPane
|
||||
import javafx.scene.paint.Color
|
||||
import org.fxyz3d.scene.Axes
|
||||
import org.fxyz3d.utils.CameraTransformer
|
||||
import tornadofx.*
|
||||
|
||||
class FXCanvas3D(val plugin: FX3DPlugin, meta: Meta = EmptyMeta) :
|
||||
class FXCanvas3D(val plugin: FX3DPlugin, val spec: CanvasSpec) :
|
||||
Fragment(), Renderer<VisualObject3D>, ContextAware {
|
||||
|
||||
override val context: Context get() = plugin.context
|
||||
@ -32,41 +23,23 @@ class FXCanvas3D(val plugin: FX3DPlugin, meta: Meta = EmptyMeta) :
|
||||
val world = Group()
|
||||
|
||||
val axes = Axes().also {
|
||||
it.setHeight(meta["axis.size"].double ?: AXIS_LENGTH)
|
||||
it.setRadius(meta["axis.width"].double ?: LINE_WIDTH)
|
||||
it.isVisible = meta["axis.visible"].boolean ?: (meta["axis"] != null)
|
||||
it.setHeight(spec.axes.size)
|
||||
it.setRadius(spec.axes.width)
|
||||
it.isVisible = spec.axes.visible
|
||||
world.add(it)
|
||||
}
|
||||
|
||||
val light = AmbientLight()
|
||||
|
||||
private val camera = PerspectiveCamera().apply {
|
||||
nearClip = CAMERA_NEAR_CLIP
|
||||
farClip = CAMERA_FAR_CLIP
|
||||
translateZ = CAMERA_INITIAL_DISTANCE
|
||||
nearClip = spec.camera.nearClip
|
||||
farClip = spec.camera.farClip
|
||||
fieldOfView = spec.camera.fov.toDouble()
|
||||
this.add(light)
|
||||
}
|
||||
|
||||
val cameraTransform = CameraTransformer().also {
|
||||
it.add(camera)
|
||||
}
|
||||
|
||||
val translationXProperty get() = cameraTransform.t.xProperty()
|
||||
var translateX by translationXProperty
|
||||
val translationYProperty get() = cameraTransform.t.yProperty()
|
||||
var translateY by translationYProperty
|
||||
val translationZProperty get() = cameraTransform.t.zProperty()
|
||||
var translateZ by translationZProperty
|
||||
|
||||
val rotationXProperty get() = cameraTransform.rx.angleProperty()
|
||||
var angleX by rotationXProperty
|
||||
val rotationYProperty get() = cameraTransform.ry.angleProperty()
|
||||
var angleY by rotationYProperty
|
||||
val rotationZProperty get() = cameraTransform.rz.angleProperty()
|
||||
var angleZ by rotationZProperty
|
||||
|
||||
private val canvas = SubScene(
|
||||
Group(world, cameraTransform).apply { DepthTest.ENABLE },
|
||||
Group(world, camera).apply { DepthTest.ENABLE },
|
||||
400.0,
|
||||
400.0,
|
||||
true,
|
||||
@ -74,15 +47,16 @@ class FXCanvas3D(val plugin: FX3DPlugin, meta: Meta = EmptyMeta) :
|
||||
).also { scene ->
|
||||
scene.fill = Color.GREY
|
||||
scene.camera = camera
|
||||
//id = "canvas"
|
||||
handleKeyboard(scene)
|
||||
handleMouse(scene)
|
||||
}
|
||||
|
||||
override val root = borderpane {
|
||||
center = canvas
|
||||
}
|
||||
|
||||
val controls = camera.orbitControls(canvas, spec.camera).also {
|
||||
world.add(it.centerMarker)
|
||||
}
|
||||
|
||||
val rootObjectProperty: ObjectProperty<VisualObject3D> = SimpleObjectProperty()
|
||||
var rootObject: VisualObject3D? by rootObjectProperty
|
||||
|
||||
@ -105,99 +79,7 @@ class FXCanvas3D(val plugin: FX3DPlugin, meta: Meta = EmptyMeta) :
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun handleKeyboard(scene: SubScene) {
|
||||
scene.onKeyPressed = EventHandler<KeyEvent> { event ->
|
||||
if (event.isControlDown) {
|
||||
when (event.code) {
|
||||
KeyCode.Z -> {
|
||||
translateX = 0.0
|
||||
translateY = 0.0
|
||||
camera.translateZ = CAMERA_INITIAL_DISTANCE
|
||||
angleY = CAMERA_INITIAL_Y_ANGLE
|
||||
angleX = CAMERA_INITIAL_X_ANGLE
|
||||
}
|
||||
KeyCode.X -> axes.isVisible = !axes.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) {
|
||||
angleY += mouseDeltaX * MOUSE_SPEED * modifier * ROTATION_SPEED
|
||||
angleX += mouseDeltaY * MOUSE_SPEED * modifier * ROTATION_SPEED
|
||||
} else if (me.isSecondaryButtonDown) {
|
||||
translateX -= mouseDeltaX * MOUSE_SPEED * modifier * TRACK_SPEED
|
||||
translateY -= 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
|
||||
}
|
||||
}
|
||||
|
||||
override fun render(obj: VisualObject3D, meta: Meta) {
|
||||
rootObject = obj
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val AXIS_LENGTH = 400.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 = 1.0
|
||||
}
|
||||
}
|
@ -0,0 +1,174 @@
|
||||
package hep.dataforge.vis.spatial.fx
|
||||
|
||||
import hep.dataforge.vis.spatial.specifications.CameraSpec
|
||||
import javafx.beans.InvalidationListener
|
||||
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.Translate
|
||||
import tornadofx.*
|
||||
import kotlin.math.*
|
||||
|
||||
|
||||
class OrbitControls internal constructor(camera: Camera, canvas: SubScene, spec: CameraSpec) {
|
||||
|
||||
val distanceProperty = SimpleDoubleProperty(spec.distance)
|
||||
var distance by distanceProperty
|
||||
|
||||
val azimuthProperty = SimpleDoubleProperty(spec.azimuth)
|
||||
var azimuth by azimuthProperty
|
||||
|
||||
val zenithProperty = SimpleDoubleProperty(PI/2 - spec.latitude)
|
||||
var zenith by zenithProperty
|
||||
|
||||
val latitudeProperty = zenithProperty.unaryMinus().plus(PI/2)
|
||||
val latitude by latitudeProperty
|
||||
|
||||
val baseXProperty = SimpleDoubleProperty(0.0)
|
||||
var x by baseXProperty
|
||||
val baseYProperty = SimpleDoubleProperty(0.0)
|
||||
var y by baseYProperty
|
||||
val baseZProperty = SimpleDoubleProperty(0.0)
|
||||
var z by baseZProperty
|
||||
|
||||
// val basePositionProperty: ObjectBinding<Point3D> =
|
||||
// nonNullObjectBinding(baseXProperty, baseYProperty, baseZProperty) {
|
||||
// Point3D(x, y, z)
|
||||
// }
|
||||
//
|
||||
// val basePosition by basePositionProperty
|
||||
|
||||
val centerMarker by lazy {
|
||||
Sphere(10.0).also {
|
||||
it.translateXProperty().bind(baseXProperty)
|
||||
it.translateYProperty().bind(baseYProperty)
|
||||
it.translateZProperty().bind(baseZProperty)
|
||||
}
|
||||
}
|
||||
|
||||
private val rx = Rotate(0.0, Rotate.X_AXIS)
|
||||
|
||||
private val ry = Rotate(0.0, Rotate.Y_AXIS)
|
||||
|
||||
private val translate = Translate()
|
||||
|
||||
private val rz = Rotate(180.0, Rotate.Z_AXIS)
|
||||
|
||||
|
||||
init {
|
||||
camera.transforms.setAll(ry, rx, translate,rz)
|
||||
update()
|
||||
val listener = InvalidationListener {
|
||||
update()
|
||||
}
|
||||
distanceProperty.addListener(listener)
|
||||
azimuthProperty.addListener(listener)
|
||||
zenithProperty.addListener(listener)
|
||||
baseXProperty.addListener(listener)
|
||||
baseYProperty.addListener(listener)
|
||||
baseZProperty.addListener(listener)
|
||||
|
||||
canvas.apply {
|
||||
camera.translateXProperty().bind(widthProperty().divide(2))
|
||||
camera.translateZProperty().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)
|
||||
//Create direction vector
|
||||
val cameraPosition = 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 = cameraPosition.x
|
||||
rx.pivotY = cameraPosition.y
|
||||
rx.pivotZ = cameraPosition.z
|
||||
rx.angle = xRotation
|
||||
|
||||
ry.pivotX = cameraPosition.x
|
||||
ry.pivotY = cameraPosition.y
|
||||
ry.pivotZ = cameraPosition.z
|
||||
ry.angle = yRotation
|
||||
|
||||
translate.x = cameraPosition.x
|
||||
translate.y = cameraPosition.y
|
||||
translate.z = cameraPosition.z
|
||||
}
|
||||
|
||||
|
||||
private fun Node.handleMouse() {
|
||||
|
||||
var mousePosX = 0.0
|
||||
var mousePosY = 0.0
|
||||
var mouseOldX: Double
|
||||
var mouseOldY: Double
|
||||
var mouseDeltaX: Double
|
||||
var mouseDeltaY: Double
|
||||
|
||||
onMousePressed = EventHandler<MouseEvent> { me ->
|
||||
mousePosX = me.sceneX
|
||||
mousePosY = me.sceneY
|
||||
mouseOldX = me.sceneX
|
||||
mouseOldY = me.sceneY
|
||||
}
|
||||
|
||||
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) {
|
||||
azimuth -= mouseDeltaX * MOUSE_SPEED * modifier * ROTATION_SPEED
|
||||
zenith -= mouseDeltaY * MOUSE_SPEED * modifier * ROTATION_SPEED
|
||||
} else if (me.isSecondaryButtonDown) {
|
||||
x += mouseDeltaX * MOUSE_SPEED * modifier * TRACK_SPEED
|
||||
z -= mouseDeltaY * MOUSE_SPEED * modifier * TRACK_SPEED
|
||||
}
|
||||
}
|
||||
onScroll = EventHandler<ScrollEvent> { event ->
|
||||
distance = max(1.0, distance - MOUSE_SPEED * event.deltaY * RESIZE_SPEED)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
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 = 0.02
|
||||
private const val TRACK_SPEED = 6.0
|
||||
private const val RESIZE_SPEED = 10.0
|
||||
}
|
||||
}
|
||||
|
||||
fun Camera.orbitControls(canvas: SubScene, spec: CameraSpec) =
|
||||
OrbitControls(this, canvas, spec)
|
@ -2,7 +2,7 @@ package hep.dataforge.vis.spatial.gdml.demo
|
||||
|
||||
import hep.dataforge.context.Global
|
||||
import hep.dataforge.js.Application
|
||||
import hep.dataforge.js.objectTree
|
||||
import hep.dataforge.vis.js.editor.objectTree
|
||||
import hep.dataforge.js.startApplication
|
||||
import hep.dataforge.meta.buildMeta
|
||||
import hep.dataforge.meta.withBottom
|
||||
@ -20,7 +20,7 @@ import hep.dataforge.vis.spatial.gdml.LUnit
|
||||
import hep.dataforge.vis.spatial.gdml.toVisual
|
||||
import hep.dataforge.vis.spatial.three.ThreePlugin
|
||||
import hep.dataforge.vis.spatial.three.output
|
||||
import hep.dataforge.vis.spatial.three.threeOutputConfig
|
||||
import hep.dataforge.vis.spatial.three.threeSettings
|
||||
import hep.dataforge.vis.spatial.visible
|
||||
import kotlinx.html.dom.append
|
||||
import kotlinx.html.js.p
|
||||
@ -157,7 +157,7 @@ private class GDMLDemoApp : Application {
|
||||
val output = three.output(canvasElement as HTMLElement)
|
||||
|
||||
output.camera.layers.set(0)
|
||||
configElement.threeOutputConfig(output)
|
||||
configElement.threeSettings(output)
|
||||
//tree.visualObjectTree(visual, editor::propertyEditor)
|
||||
treeElement.objectTree(NameToken("World"), visual) {
|
||||
editorElement.propertyEditor(it) { item ->
|
||||
|
@ -6,9 +6,9 @@
|
||||
<title>Three js demo for particle physics</title>
|
||||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
|
||||
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="css/ru.mipt.npm.muon.monitor.main.css">
|
||||
<link rel="stylesheet" href="css/main.css">
|
||||
<link rel="stylesheet" href="css/jsoneditor.min.css">
|
||||
<script type="text/javascript" src="ru.mipt.npm.muon.monitor.main.bundle.js"></script>
|
||||
<script type="text/javascript" src="main.bundle.js"></script>
|
||||
</head>
|
||||
<body class="testApp">
|
||||
<div class="container" id="drop_zone" data-toggle="tooltip" data-placement="right"
|
||||
|
@ -20,7 +20,7 @@ kotlin {
|
||||
js {
|
||||
browser {
|
||||
webpackTask {
|
||||
sourceMaps = false
|
||||
sourceMaps = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,11 +2,11 @@ package ru.mipt.npm.muon.monitor
|
||||
|
||||
import hep.dataforge.context.Global
|
||||
import hep.dataforge.js.Application
|
||||
import hep.dataforge.js.objectTree
|
||||
import hep.dataforge.js.startApplication
|
||||
import hep.dataforge.meta.buildMeta
|
||||
import hep.dataforge.meta.withBottom
|
||||
import hep.dataforge.names.NameToken
|
||||
import hep.dataforge.vis.js.editor.objectTree
|
||||
import hep.dataforge.vis.js.editor.propertyEditor
|
||||
import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_COLOR_KEY
|
||||
import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_OPACITY_KEY
|
||||
@ -15,11 +15,12 @@ import hep.dataforge.vis.spatial.VisualObject3D
|
||||
import hep.dataforge.vis.spatial.VisualObject3D.Companion.VISIBLE_KEY
|
||||
import hep.dataforge.vis.spatial.three.ThreePlugin
|
||||
import hep.dataforge.vis.spatial.three.output
|
||||
import hep.dataforge.vis.spatial.three.threeOutputConfig
|
||||
import hep.dataforge.vis.spatial.three.threeSettings
|
||||
import hep.dataforge.vis.spatial.visible
|
||||
import org.w3c.dom.HTMLElement
|
||||
import kotlin.browser.document
|
||||
import kotlin.dom.clear
|
||||
import kotlin.math.PI
|
||||
|
||||
private class GDMLDemoApp : Application {
|
||||
// /**
|
||||
@ -59,7 +60,8 @@ private class GDMLDemoApp : Application {
|
||||
//val url = URL("https://drive.google.com/open?id=1w5e7fILMN83JGgB8WANJUYm8OW2s0WVO")
|
||||
|
||||
val canvasElement = document.getElementById("canvas") ?: error("Element with id 'canvas' not found on page")
|
||||
val configElement = document.getElementById("layers") ?: error("Element with id 'layers' not found on page")
|
||||
val settingsElement =
|
||||
document.getElementById("settings") ?: error("Element with id 'settings' not found on page")
|
||||
val treeElement = document.getElementById("tree") ?: error("Element with id 'tree' not found on page")
|
||||
val editorElement = document.getElementById("editor") ?: error("Element with id 'editor' not found on page")
|
||||
canvasElement.clear()
|
||||
@ -71,7 +73,9 @@ private class GDMLDemoApp : Application {
|
||||
val output = three.output(canvasElement as HTMLElement)
|
||||
|
||||
output.camera.layers.set(0)
|
||||
configElement.threeOutputConfig(output)
|
||||
output.camera.position.z = -2000.0
|
||||
output.camera.position.y = 500.0
|
||||
settingsElement.threeSettings(output)
|
||||
//tree.visualObjectTree(visual, editor::propertyEditor)
|
||||
treeElement.objectTree(NameToken("World"), visual) {
|
||||
editorElement.propertyEditor(it) { item ->
|
||||
|
@ -27,8 +27,8 @@
|
||||
<div class="row">
|
||||
<div class="col-lg-3" id="tree"></div>
|
||||
<div class="col-lg-6">
|
||||
<div class="row" id="layers"></div>
|
||||
<div class="row container" id="canvas"></div>
|
||||
<div class="row" id="settings"></div>
|
||||
<div class="row" id="canvas"></div>
|
||||
</div>
|
||||
<div class="col-lg-3" id="editor"></div>
|
||||
</div>
|
||||
|
@ -1,11 +1,13 @@
|
||||
package hep.dataforge.vis.spatial.demo
|
||||
|
||||
import hep.dataforge.meta.buildMeta
|
||||
import hep.dataforge.meta.invoke
|
||||
import hep.dataforge.names.toName
|
||||
import hep.dataforge.output.OutputManager
|
||||
import hep.dataforge.vis.common.Colors
|
||||
import hep.dataforge.vis.common.VisualObject
|
||||
import hep.dataforge.vis.spatial.*
|
||||
import hep.dataforge.vis.spatial.specifications.CanvasSpec
|
||||
import kotlinx.coroutines.*
|
||||
import kotlin.math.PI
|
||||
import kotlin.math.cos
|
||||
@ -21,10 +23,22 @@ fun OutputManager.demo(name: String, title: String = name, block: VisualGroup3D.
|
||||
output.render(action = block)
|
||||
}
|
||||
|
||||
val canvasOptions = CanvasSpec {
|
||||
minSize = 500
|
||||
axes {
|
||||
size = 500.0
|
||||
visible = true
|
||||
}
|
||||
camera {
|
||||
distance = 600.0
|
||||
latitude = PI/6
|
||||
}
|
||||
}
|
||||
|
||||
fun OutputManager.showcase() {
|
||||
demo("shapes", "Basic shapes") {
|
||||
box(100.0, 100.0, 100.0) {
|
||||
z = 110.0
|
||||
z = -110.0
|
||||
}
|
||||
sphere(50.0) {
|
||||
x = 110
|
||||
@ -88,6 +102,7 @@ fun OutputManager.showcase() {
|
||||
layer(i * 5, 20 * sin(2 * PI / 100 * i), 20 * cos(2 * PI / 100 * i))
|
||||
}
|
||||
color(Colors.teal)
|
||||
rotationX = -PI / 2
|
||||
}
|
||||
}
|
||||
|
||||
@ -111,8 +126,8 @@ fun OutputManager.showcase() {
|
||||
box(100, 100, 50) {
|
||||
opacity = 0.3
|
||||
}
|
||||
label("Hello, world!",fontSize = 15) {
|
||||
z = -26
|
||||
label("Hello, world!", fontSize = 12) {
|
||||
z = 26
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,27 +22,27 @@ private class ThreeDemoApp : Application {
|
||||
ThreeDemoGrid(element).run {
|
||||
showcase()
|
||||
showcaseCSG()
|
||||
demo("dynamicBox", "Dancing boxes") {
|
||||
val boxes = (-10..10).flatMap { i ->
|
||||
(-10..10).map { j ->
|
||||
varBox(10, 10, 0, name = "cell_${i}_${j}") {
|
||||
x = i * 10
|
||||
y = j * 10
|
||||
value = 128
|
||||
setProperty(EDGES_ENABLED_KEY, false)
|
||||
setProperty(WIREFRAME_ENABLED_KEY, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
GlobalScope.launch {
|
||||
while (isActive) {
|
||||
delay(500)
|
||||
boxes.forEach { box ->
|
||||
box.value = (box.value + Random.nextInt(-15, 15)).coerceIn(0..255)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// demo("dynamicBox", "Dancing boxes") {
|
||||
// val boxes = (-10..10).flatMap { i ->
|
||||
// (-10..10).map { j ->
|
||||
// varBox(10, 10, 0, name = "cell_${i}_${j}") {
|
||||
// x = i * 10
|
||||
// y = j * 10
|
||||
// value = 128
|
||||
// setProperty(EDGES_ENABLED_KEY, false)
|
||||
// setProperty(WIREFRAME_ENABLED_KEY, false)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// GlobalScope.launch {
|
||||
// while (isActive) {
|
||||
// delay(500)
|
||||
// boxes.forEach { box ->
|
||||
// box.value = (box.value + Random.nextInt(-15, 15)).coerceIn(0..255)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
|
@ -3,11 +3,15 @@ package hep.dataforge.vis.spatial.demo
|
||||
import hep.dataforge.context.Global
|
||||
import hep.dataforge.meta.Meta
|
||||
import hep.dataforge.meta.get
|
||||
import hep.dataforge.meta.invoke
|
||||
import hep.dataforge.meta.string
|
||||
import hep.dataforge.names.Name
|
||||
import hep.dataforge.output.OutputManager
|
||||
import hep.dataforge.output.Renderer
|
||||
import hep.dataforge.vis.common.VisualObject
|
||||
import hep.dataforge.vis.spatial.specifications.AxesSpec
|
||||
import hep.dataforge.vis.spatial.specifications.CameraSpec
|
||||
import hep.dataforge.vis.spatial.specifications.CanvasSpec
|
||||
import hep.dataforge.vis.spatial.three.ThreeCanvas
|
||||
import hep.dataforge.vis.spatial.three.ThreePlugin
|
||||
import hep.dataforge.vis.spatial.three.output
|
||||
@ -40,18 +44,14 @@ class ThreeDemoGrid(element: Element, meta: Meta = Meta.EMPTY) : OutputManager {
|
||||
|
||||
return outputs.getOrPut(name) {
|
||||
if (type != VisualObject::class) error("Supports only DisplayObject")
|
||||
val output = three.output(meta = meta) {
|
||||
"minSize" put 500
|
||||
"axis" put {
|
||||
"size" put 500
|
||||
}
|
||||
}
|
||||
lateinit var output: ThreeCanvas
|
||||
//TODO calculate cell width here using jquery
|
||||
gridRoot.append {
|
||||
span("border") {
|
||||
div("col-6") {
|
||||
div { id = "output-$name" }.also {
|
||||
output.attach(it)
|
||||
output = three.output(it, canvasOptions)
|
||||
//output.attach(it)
|
||||
}
|
||||
hr()
|
||||
h2 { +(meta["title"].string ?: name.toString()) }
|
||||
|
@ -4,32 +4,14 @@
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<title>Three js demo for particle physics</title>
|
||||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
|
||||
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
|
||||
<script type="text/javascript" src="ru.mipt.npm.muon.monitor.main.bundle.js"></script>
|
||||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
|
||||
integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
|
||||
<script type="text/javascript" src="main.bundle.js"></script>
|
||||
</head>
|
||||
<body class="testApp">
|
||||
<!--
|
||||
<div class="container" id="drop_zone" data-toggle="tooltip" data-placement="right"
|
||||
title="Для загрузки данных в текстовом формате, надо перетащить файл сюда">
|
||||
Загрузить данные
|
||||
<br/>
|
||||
(перетащить файл сюда)
|
||||
</div>
|
||||
-->
|
||||
<div class="container">
|
||||
<h1>Demo grid</h1>
|
||||
</div>
|
||||
<div class="container" id="canvas"></div>
|
||||
|
||||
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"
|
||||
integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo"
|
||||
crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"
|
||||
integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1"
|
||||
crossorigin="anonymous"></script>
|
||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"
|
||||
integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM"
|
||||
crossorigin="anonymous"></script>
|
||||
</body>
|
||||
</html>
|
@ -1,7 +1,5 @@
|
||||
package hep.dataforge.vis.spatial.demo
|
||||
|
||||
import hep.dataforge.vis.spatial.Material3D
|
||||
import hep.dataforge.vis.spatial.gdml.LUnit
|
||||
import hep.dataforge.vis.spatial.gdml.gdml
|
||||
import javafx.stage.Stage
|
||||
import tornadofx.*
|
||||
@ -14,22 +12,12 @@ class FXDemoApp : App(FXDemoGrid::class) {
|
||||
override fun start(stage: Stage) {
|
||||
super.start(stage)
|
||||
|
||||
stage.width = 400.0
|
||||
stage.height = 400.0
|
||||
stage.width = 600.0
|
||||
stage.height = 600.0
|
||||
|
||||
//view.showcase()
|
||||
view.demo("gdml", "gdml") {
|
||||
gdml(Paths.get("D:\\Work\\Projects\\gdml.kt\\gdml-source\\cubes.gdml")) {
|
||||
lUnit = LUnit.CM
|
||||
|
||||
solidConfiguration = { parent, solid ->
|
||||
if (parent.physVolumes.isNotEmpty()) {
|
||||
useStyle("opaque") {
|
||||
Material3D.MATERIAL_OPACITY_KEY put 0.3
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
view.showcase()
|
||||
view.demo("gdml", "gdml-cubes") {
|
||||
gdml(Paths.get("D:\\Work\\Projects\\gdml.kt\\gdml-source\\cubes.gdml"))
|
||||
//setProperty(Material3D.MATERIAL_WIREFRAME_KEY, true)
|
||||
}
|
||||
}
|
||||
|
@ -9,13 +9,15 @@ import hep.dataforge.output.Renderer
|
||||
import hep.dataforge.vis.common.VisualObject
|
||||
import hep.dataforge.vis.spatial.fx.FX3DPlugin
|
||||
import hep.dataforge.vis.spatial.fx.FXCanvas3D
|
||||
import hep.dataforge.vis.spatial.specifications.AxesSpec
|
||||
import hep.dataforge.vis.spatial.specifications.CanvasSpec
|
||||
import javafx.collections.FXCollections
|
||||
import javafx.scene.Parent
|
||||
import javafx.scene.control.Tab
|
||||
import tornadofx.*
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
class FXDemoGrid : View(), OutputManager {
|
||||
class FXDemoGrid : View(title = "DataForge-vis FX demo"), OutputManager {
|
||||
private val outputs = FXCollections.observableHashMap<Name, FXCanvas3D>()
|
||||
|
||||
override val root: Parent = borderpane {
|
||||
@ -32,13 +34,7 @@ class FXDemoGrid : View(), OutputManager {
|
||||
override fun <T : Any> get(type: KClass<out T>, name: Name, stage: Name, meta: Meta): Renderer<T> {
|
||||
return outputs.getOrPut(name) {
|
||||
if (type != VisualObject::class) kotlin.error("Supports only DisplayObject")
|
||||
val customMeta = buildMeta(meta) {
|
||||
"minSize" put 500
|
||||
"axis" put {
|
||||
"size" put 500
|
||||
}
|
||||
}
|
||||
val output = FXCanvas3D(fx3d, customMeta)
|
||||
val output = FXCanvas3D(fx3d, canvasOptions)
|
||||
|
||||
output
|
||||
} as Renderer<T>
|
||||
|
Loading…
Reference in New Issue
Block a user