Almost working OrbitControls for FX

This commit is contained in:
Alexander Nozik 2019-12-28 22:11:43 +03:00
parent 26948a88d7
commit 459d256ebd
31 changed files with 451 additions and 319 deletions

View File

@ -1,6 +1,6 @@
import scientifik.useSerialization import scientifik.useSerialization
val dataforgeVersion by extra("0.1.5-dev-5") val dataforgeVersion by extra("0.1.5-dev-6")
plugins { plugins {
val kotlinVersion = "1.3.61" val kotlinVersion = "1.3.61"

View File

@ -35,6 +35,7 @@ kotlin {
api("hep.dataforge:dataforge-output-html:$dataforgeVersion") api("hep.dataforge:dataforge-output-html:$dataforgeVersion")
api(npm("bootstrap","4.4.1")) api(npm("bootstrap","4.4.1"))
implementation(npm("jsoneditor")) implementation(npm("jsoneditor"))
implementation(npm("file-saver"))
} }
} }
} }

View File

@ -1,10 +1,9 @@
package hep.dataforge.js package hep.dataforge.vis.js.editor
import hep.dataforge.names.NameToken import hep.dataforge.names.NameToken
import hep.dataforge.vis.common.VisualGroup import hep.dataforge.vis.common.VisualGroup
import hep.dataforge.vis.common.VisualObject import hep.dataforge.vis.common.VisualObject
import hep.dataforge.vis.common.isEmpty import hep.dataforge.vis.common.isEmpty
import hep.dataforge.vis.js.editor.card
import kotlinx.html.TagConsumer import kotlinx.html.TagConsumer
import kotlinx.html.dom.append import kotlinx.html.dom.append
import kotlinx.html.js.* import kotlinx.html.js.*

View File

@ -5,13 +5,9 @@ import hep.dataforge.meta.MetaBuilder
import hep.dataforge.meta.buildMeta import hep.dataforge.meta.buildMeta
import hep.dataforge.names.Name import hep.dataforge.names.Name
import hep.dataforge.names.toName import hep.dataforge.names.toName
import hep.dataforge.vis.common.VisualObject
import hep.dataforge.vis.common.useStyle 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.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 scientifik.gdml.*
import kotlin.random.Random import kotlin.random.Random
@ -37,7 +33,14 @@ class GDMLTransformer(val root: GDML) {
var volumeAction: (GDMLGroup) -> Action = { Action.CACHE } 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) { fun VisualObject3D.useStyle(name: String, builder: MetaBuilder.() -> Unit) {
styleCache.getOrPut(name.toName()) { styleCache.getOrPut(name.toName()) {

View File

@ -6,8 +6,8 @@ import hep.dataforge.names.asName
import hep.dataforge.names.plus import hep.dataforge.names.plus
import hep.dataforge.vis.common.get import hep.dataforge.vis.common.get
import hep.dataforge.vis.spatial.* import hep.dataforge.vis.spatial.*
import hep.dataforge.vis.spatial.GeometryConstants.one import hep.dataforge.vis.spatial.World.ONE
import hep.dataforge.vis.spatial.GeometryConstants.zero import hep.dataforge.vis.spatial.World.ZERO
import scientifik.gdml.* import scientifik.gdml.*
import kotlin.math.cos import kotlin.math.cos
import kotlin.math.sin import kotlin.math.sin
@ -21,20 +21,20 @@ private fun VisualObject3D.withPosition(
): VisualObject3D = apply { ): VisualObject3D = apply {
newPos?.let { newPos?.let {
val point = Point3D(it.x(lUnit), it.y(lUnit), it.z(lUnit)) val point = Point3D(it.x(lUnit), it.y(lUnit), it.z(lUnit))
if (position != null || point != zero) { if (position != null || point != ZERO) {
position = point position = point
} }
} }
newRotation?.let { newRotation?.let {
val point = Point3D(it.x(), it.y(), it.z()) val point = Point3D(it.x(), it.y(), it.z())
if (rotation != null || point != zero) { if (rotation != null || point != ZERO) {
rotation = point rotation = point
} }
//this@withPosition.rotationOrder = RotationOrder.ZXY //this@withPosition.rotationOrder = RotationOrder.ZXY
} }
newScale?.let { newScale?.let {
val point = Point3D(it.x, it.y, it.z) val point = Point3D(it.x, it.y, it.z)
if (scale != null || point != one) { if (scale != null || point != ONE) {
scale = point scale = point
} }
} }

View File

@ -38,7 +38,7 @@ class Visual3DPlugin(meta: Meta) : AbstractPlugin(meta) {
contextual(Point2DSerializer) contextual(Point2DSerializer)
contextual(NameSerializer) contextual(NameSerializer)
contextual(NameTokenSerializer) contextual(NameTokenSerializer)
contextual(Meta::class, MetaSerializer) contextual(MetaSerializer)
contextual(ConfigSerializer) contextual(ConfigSerializer)
polymorphic(VisualObject::class, VisualObject3D::class) { polymorphic(VisualObject::class, VisualObject3D::class) {
@ -48,7 +48,8 @@ class Visual3DPlugin(meta: Meta) : AbstractPlugin(meta) {
Tube::class with Tube.serializer() Tube::class with Tube.serializer()
Box::class with Box.serializer() Box::class with Box.serializer()
Convex::class with Convex.serializer() Convex::class with Convex.serializer()
addSubclass(Extruded.serializer()) Extruded::class with Extruded.serializer()
addSubclass(Label3D.serializer())
} }
} }

View File

@ -3,12 +3,8 @@ package hep.dataforge.vis.spatial
import kotlin.math.PI import kotlin.math.PI
object World { object World {
const val CAMERA_INITIAL_DISTANCE = -500.0 val ZERO = Point3D(0.0, 0.0, 0.0)
const val CAMERA_INITIAL_X_ANGLE = -50.0 val ONE = Point3D(1.0, 1.0, 1.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
} }
const val PI2: Float = 2 * PI.toFloat() const val PI2: Float = 2 * PI.toFloat()

View File

@ -39,8 +39,3 @@ fun Point3D.toMeta() = buildMeta {
VisualObject3D.y put y VisualObject3D.y put y
VisualObject3D.z put z VisualObject3D.z put z
} }
object GeometryConstants {
val zero = Point3D(0.0, 0.0, 0.0)
val one = Point3D(1.0, 1.0, 1.0)
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -15,8 +15,8 @@ internal fun mergeChild(parent: VisualGroup, child: VisualObject): VisualObject
//parent.properties?.let { config.update(it) } //parent.properties?.let { config.update(it) }
if (this is VisualObject3D && parent is VisualObject3D) { if (this is VisualObject3D && parent is VisualObject3D) {
position = (position ?: GeometryConstants.zero) + (parent.position ?: GeometryConstants.zero) position = (position ?: World.ZERO) + (parent.position ?: World.ZERO)
rotation = (parent.rotation ?: GeometryConstants.zero) + (parent.rotation ?: GeometryConstants.zero) rotation = (parent.rotation ?: World.ZERO) + (parent.rotation ?: World.ZERO)
scale = when { scale = when {
scale == null && parent.scale == null -> null scale == null && parent.scale == null -> null
scale == null -> parent.scale scale == null -> parent.scale

View File

@ -1,59 +1,61 @@
package hep.dataforge.vis.spatial.three package hep.dataforge.vis.spatial.three
import hep.dataforge.context.Context 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.output.Renderer
import hep.dataforge.vis.common.Colors import hep.dataforge.vis.common.Colors
import hep.dataforge.vis.spatial.Point3D
import hep.dataforge.vis.spatial.VisualObject3D 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.WebGLRenderer
import info.laht.threekt.cameras.PerspectiveCamera import info.laht.threekt.cameras.PerspectiveCamera
import info.laht.threekt.external.controls.OrbitControls import info.laht.threekt.external.controls.OrbitControls
import info.laht.threekt.external.controls.TrackballControls import info.laht.threekt.external.controls.TrackballControls
import info.laht.threekt.helpers.AxesHelper import info.laht.threekt.helpers.AxesHelper
import info.laht.threekt.lights.AmbientLight
import info.laht.threekt.scenes.Scene import info.laht.threekt.scenes.Scene
import org.w3c.dom.HTMLElement import org.w3c.dom.HTMLElement
import org.w3c.dom.Node import org.w3c.dom.Node
import kotlin.browser.window import kotlin.browser.window
import kotlin.dom.clear import kotlin.dom.clear
import kotlin.math.cos
import kotlin.math.max 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 override val context: Context get() = three.context
var data: VisualObject3D? = null var content: VisualObject3D? = null
private set 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 { val scene: Scene = Scene().apply {
add(AmbientLight())
if (meta["axes.visible"].boolean == true) {
axes.visible = true
}
add(axes) add(axes)
} }
private fun buildCamera(meta: Meta) = PerspectiveCamera( val camera = buildCamera(spec.camera)
meta["fov"].int ?: 75,
meta["aspect"].double ?: 1.0, private fun buildCamera(spec: CameraSpec) = PerspectiveCamera(
meta["nearClip"].double ?: World.CAMERA_NEAR_CLIP, spec.fov,
meta["farClip"].double ?: World.CAMERA_FAR_CLIP 1.0,
spec.nearClip,
spec.farClip
).apply { ).apply {
position.setZ(World.CAMERA_INITIAL_DISTANCE) translateX(spec.distance* sin(spec.zenith) * sin(spec.azimuth))
rotation.set( translateY(spec.distance* cos(spec.zenith))
World.CAMERA_INITIAL_X_ANGLE, translateZ(spec.distance * sin(spec.zenith) * cos(spec.azimuth))
World.CAMERA_INITIAL_Y_ANGLE,
World.CAMERA_INITIAL_Z_ANGLE
)
} }
val camera = buildCamera(meta["camera"].node ?: EmptyMeta) private fun addControls(element: Node, controlsSpec: ControlsSpec) {
when (controlsSpec["type"].string) {
private fun addControls(element: Node, meta: Meta) {
when (meta["type"].string) {
"trackball" -> TrackballControls(camera, element) "trackball" -> TrackballControls(camera, element)
else -> OrbitControls(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() { fun animate() {
window.requestAnimationFrame { window.requestAnimationFrame {
@ -80,9 +82,7 @@ class ThreeCanvas(val three: ThreePlugin, val meta: Meta = EmptyMeta) : Renderer
element.appendChild(renderer.domElement) element.appendChild(renderer.domElement)
val minSize by meta.number(0).int renderer.setSize(max(spec.minSize, element.offsetWidth), max(spec.minSize, element.offsetWidth))
renderer.setSize(max(minSize, element.offsetWidth), max(minSize, element.offsetWidth))
element.onresize = { element.onresize = {
renderer.setSize(element.offsetWidth, element.offsetWidth) 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) { override fun render(obj: VisualObject3D, meta: Meta) {
data = obj content = obj
scene.add(three.buildObject3D(obj)) scene.add(three.buildObject3D(obj))
} }
} }
fun ThreePlugin.output(element: HTMLElement? = null, meta: Meta = EmptyMeta, override: MetaBuilder.() -> Unit = {}) = fun ThreePlugin.output(element: HTMLElement? = null, spec: CanvasSpec = CanvasSpec.empty()): ThreeCanvas =
ThreeCanvas(this, buildMeta(meta, override)).apply { ThreeCanvas(this, spec).apply {
if (element != null) { if (element != null) {
attach(element) attach(element)
} }

View File

@ -1,29 +1,35 @@
package hep.dataforge.vis.spatial.three package hep.dataforge.vis.spatial.three
import hep.dataforge.vis.spatial.Label3D import hep.dataforge.vis.spatial.Label3D
import hep.dataforge.vis.spatial.color
import info.laht.threekt.DoubleSide import info.laht.threekt.DoubleSide
import info.laht.threekt.core.Object3D 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.materials.MeshBasicMaterial
import info.laht.threekt.objects.Mesh import info.laht.threekt.objects.Mesh
import info.laht.threekt.textures.Texture import info.laht.threekt.textures.Texture
import org.w3c.dom.CanvasRenderingContext2D import org.w3c.dom.*
import org.w3c.dom.HTMLCanvasElement
import kotlin.browser.document import kotlin.browser.document
import kotlin.math.PI
import kotlin.reflect.KClass import kotlin.reflect.KClass
/** /**
* Using example from http://stemkoski.github.io/Three.js/Texture-From-Canvas.html * 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 val type: KClass<in Label3D> get() = Label3D::class
override fun invoke(obj: Label3D): Object3D { override fun invoke(obj: Label3D): Object3D {
val canvas = document.createElement("canvas") as HTMLCanvasElement val canvas = document.createElement("canvas") as HTMLCanvasElement
val context = canvas.getContext("2d") as CanvasRenderingContext2D val context = canvas.getContext("2d") as CanvasRenderingContext2D
context.font = "${obj.fontSize}pt ${obj.fontFamily}" context.font = "Bold ${obj.fontSize}pt ${obj.fontFamily}"
context.fillStyle = "rgba(255,0,0,0.95)"//obj.material?.color ?: "black" context.fillStyle = obj.color ?: "black"
context.fillText(obj.text, 0.0, 0.0) 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 // canvas contents will be used for a texture
val texture = Texture(canvas) val texture = Texture(canvas)
@ -32,14 +38,16 @@ object ThreeTextFactory : ThreeFactory<Label3D> {
val material = MeshBasicMaterial().apply { val material = MeshBasicMaterial().apply {
map = texture map = texture
side = DoubleSide side = DoubleSide
transparent = true
} }
material.transparent = true;
val mesh = Mesh( val mesh = Mesh(
PlaneGeometry(canvas.clientWidth, canvas.clientHeight), PlaneBufferGeometry(canvas.width, canvas.height),
material material
) )
//mesh.rotateX(PI)
mesh.updatePosition(obj) mesh.updatePosition(obj)
return mesh return mesh

View File

@ -27,7 +27,7 @@ class ThreePlugin : AbstractPlugin() {
objectFactories[Sphere::class] = ThreeSphereFactory objectFactories[Sphere::class] = ThreeSphereFactory
objectFactories[ConeSegment::class] = ThreeCylinderFactory objectFactories[ConeSegment::class] = ThreeCylinderFactory
objectFactories[PolyLine::class] = ThreeLineFactory objectFactories[PolyLine::class] = ThreeLineFactory
objectFactories[Label3D::class] = ThreeTextFactory objectFactories[Label3D::class] = ThreeLabelFactory
} }
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")

View File

@ -1,51 +1,67 @@
package hep.dataforge.vis.spatial.three package hep.dataforge.vis.spatial.three
import hep.dataforge.js.requireJS
import hep.dataforge.vis.js.editor.card 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.InputType
import kotlinx.html.TagConsumer
import kotlinx.html.button import kotlinx.html.button
import kotlinx.html.dom.append import kotlinx.html.dom.append
import kotlinx.html.js.* import kotlinx.html.js.*
import org.w3c.dom.Element 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 import kotlin.dom.clear
//private fun download(filename: String, text: String) { private fun saveData(event: Event, fileName: String, mimeType: String = "text/plain", dataBuilder: () -> String) {
// var element = document.createElement("a"); event.stopPropagation();
// element.setAttribute("href", "data:text/json;charset=utf-8," + encodeURIComponent(text)); event.preventDefault();
// element.setAttribute("download", filename);
//
// element.style.display = 'none';
// document.body.appendChild(element);
//
// element.click();
//
// document.body.removeChild(element);
//}
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() clear()
append { append {
card("Settings"){ card("Settings") {
div("row"){ div("row") {
div("col-1") { div("col-2") {
label { +"Axes" } label("checkbox-inline") {
input(type = InputType.checkBox).apply { input(type = InputType.checkBox).apply {
checked = canvas.axes.visible checked = canvas.axes.visible
onChangeFunction = { onChangeFunction = {
canvas.axes.visible = checked canvas.axes.visible = checked
}
} }
+"Axes"
} }
} }
div("col-1") { div("col-1") {
button { button {
+"Export" +"Export"
onClickFunction = { 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
}
}
} }
} }
} }
} }
} }
card("Layers"){ card("Layers") {
div("row") { div("row") {
(0..11).forEach { layer -> (0..11).forEach { layer ->
div("col-1") { div("col-1") {
@ -66,5 +82,6 @@ fun Element.threeOutputConfig(canvas: ThreeCanvas) {
} }
} }
} }
block()
} }
} }

View File

@ -5,7 +5,6 @@ import hep.dataforge.meta.float
import hep.dataforge.meta.get import hep.dataforge.meta.get
import hep.dataforge.meta.node import hep.dataforge.meta.node
import hep.dataforge.vis.spatial.* import hep.dataforge.vis.spatial.*
import hep.dataforge.vis.spatial.GeometryConstants.zero
import info.laht.threekt.core.* import info.laht.threekt.core.*
import info.laht.threekt.external.controls.OrbitControls import info.laht.threekt.external.controls.OrbitControls
import info.laht.threekt.materials.Material 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.math.Vector3
import info.laht.threekt.objects.Mesh import info.laht.threekt.objects.Mesh
import info.laht.threekt.textures.Texture import info.laht.threekt.textures.Texture
import kotlin.math.PI
/** /**
* Utility methods for three.kt. * 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) } fun Geometry.toBufferGeometry(): BufferGeometry = BufferGeometry().apply { fromGeometry(this@toBufferGeometry) }
internal fun Double.toRadians() = this * PI / 180
fun CSG.toGeometry(): Geometry { fun CSG.toGeometry(): Geometry {
val geom = Geometry() val geom = Geometry()
@ -45,7 +47,7 @@ fun CSG.toGeometry(): Geometry {
} }
for (j in 3..polygon.vertices.size) { 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( fc.vertexNormals = arrayOf(
Vector3().copy(pvs[0].normal), Vector3().copy(pvs[0].normal),
Vector3().copy(pvs[j - 2].normal), Vector3().copy(pvs[j - 2].normal),

View File

@ -2,29 +2,20 @@ package hep.dataforge.vis.spatial.fx
import hep.dataforge.context.Context import hep.dataforge.context.Context
import hep.dataforge.context.ContextAware import hep.dataforge.context.ContextAware
import hep.dataforge.meta.* import hep.dataforge.meta.Meta
import hep.dataforge.output.Renderer import hep.dataforge.output.Renderer
import hep.dataforge.vis.spatial.VisualObject3D import hep.dataforge.vis.spatial.VisualObject3D
import hep.dataforge.vis.spatial.World.CAMERA_FAR_CLIP import hep.dataforge.vis.spatial.specifications.CanvasSpec
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 javafx.application.Platform import javafx.application.Platform
import javafx.beans.property.ObjectProperty import javafx.beans.property.ObjectProperty
import javafx.beans.property.SimpleObjectProperty import javafx.beans.property.SimpleObjectProperty
import javafx.event.EventHandler
import javafx.scene.* import javafx.scene.*
import javafx.scene.input.KeyCode import javafx.scene.layout.BorderPane
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 org.fxyz3d.scene.Axes import org.fxyz3d.scene.Axes
import org.fxyz3d.utils.CameraTransformer
import tornadofx.* import tornadofx.*
class FXCanvas3D(val plugin: FX3DPlugin, meta: Meta = EmptyMeta) : class FXCanvas3D(val plugin: FX3DPlugin, val spec: CanvasSpec) :
Fragment(), Renderer<VisualObject3D>, ContextAware { Fragment(), Renderer<VisualObject3D>, ContextAware {
override val context: Context get() = plugin.context override val context: Context get() = plugin.context
@ -32,41 +23,23 @@ class FXCanvas3D(val plugin: FX3DPlugin, meta: Meta = EmptyMeta) :
val world = Group() val world = Group()
val axes = Axes().also { val axes = Axes().also {
it.setHeight(meta["axis.size"].double ?: AXIS_LENGTH) it.setHeight(spec.axes.size)
it.setRadius(meta["axis.width"].double ?: LINE_WIDTH) it.setRadius(spec.axes.width)
it.isVisible = meta["axis.visible"].boolean ?: (meta["axis"] != null) it.isVisible = spec.axes.visible
world.add(it) world.add(it)
} }
val light = AmbientLight() val light = AmbientLight()
private val camera = PerspectiveCamera().apply { private val camera = PerspectiveCamera().apply {
nearClip = CAMERA_NEAR_CLIP nearClip = spec.camera.nearClip
farClip = CAMERA_FAR_CLIP farClip = spec.camera.farClip
translateZ = CAMERA_INITIAL_DISTANCE fieldOfView = spec.camera.fov.toDouble()
this.add(light) 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( private val canvas = SubScene(
Group(world, cameraTransform).apply { DepthTest.ENABLE }, Group(world, camera).apply { DepthTest.ENABLE },
400.0, 400.0,
400.0, 400.0,
true, true,
@ -74,15 +47,16 @@ class FXCanvas3D(val plugin: FX3DPlugin, meta: Meta = EmptyMeta) :
).also { scene -> ).also { scene ->
scene.fill = Color.GREY scene.fill = Color.GREY
scene.camera = camera scene.camera = camera
//id = "canvas"
handleKeyboard(scene)
handleMouse(scene)
} }
override val root = borderpane { override val root = borderpane {
center = canvas center = canvas
} }
val controls = camera.orbitControls(canvas, spec.camera).also {
world.add(it.centerMarker)
}
val rootObjectProperty: ObjectProperty<VisualObject3D> = SimpleObjectProperty() val rootObjectProperty: ObjectProperty<VisualObject3D> = SimpleObjectProperty()
var rootObject: VisualObject3D? by rootObjectProperty 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) { override fun render(obj: VisualObject3D, meta: Meta) {
rootObject = obj 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
}
} }

View File

@ -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)

View File

@ -2,7 +2,7 @@ package hep.dataforge.vis.spatial.gdml.demo
import hep.dataforge.context.Global import hep.dataforge.context.Global
import hep.dataforge.js.Application 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.js.startApplication
import hep.dataforge.meta.buildMeta import hep.dataforge.meta.buildMeta
import hep.dataforge.meta.withBottom 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.gdml.toVisual
import hep.dataforge.vis.spatial.three.ThreePlugin import hep.dataforge.vis.spatial.three.ThreePlugin
import hep.dataforge.vis.spatial.three.output 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 hep.dataforge.vis.spatial.visible
import kotlinx.html.dom.append import kotlinx.html.dom.append
import kotlinx.html.js.p import kotlinx.html.js.p
@ -157,7 +157,7 @@ private class GDMLDemoApp : Application {
val output = three.output(canvasElement as HTMLElement) val output = three.output(canvasElement as HTMLElement)
output.camera.layers.set(0) output.camera.layers.set(0)
configElement.threeOutputConfig(output) configElement.threeSettings(output)
//tree.visualObjectTree(visual, editor::propertyEditor) //tree.visualObjectTree(visual, editor::propertyEditor)
treeElement.objectTree(NameToken("World"), visual) { treeElement.objectTree(NameToken("World"), visual) {
editorElement.propertyEditor(it) { item -> editorElement.propertyEditor(it) { item ->

View File

@ -6,9 +6,9 @@
<title>Three js demo for particle physics</title> <title>Three js demo for particle physics</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" <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"> 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"> <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> </head>
<body class="testApp"> <body class="testApp">
<div class="container" id="drop_zone" data-toggle="tooltip" data-placement="right" <div class="container" id="drop_zone" data-toggle="tooltip" data-placement="right"

View File

@ -20,7 +20,7 @@ kotlin {
js { js {
browser { browser {
webpackTask { webpackTask {
sourceMaps = false sourceMaps = true
} }
} }
} }

View File

@ -2,11 +2,11 @@ package ru.mipt.npm.muon.monitor
import hep.dataforge.context.Global import hep.dataforge.context.Global
import hep.dataforge.js.Application import hep.dataforge.js.Application
import hep.dataforge.js.objectTree
import hep.dataforge.js.startApplication import hep.dataforge.js.startApplication
import hep.dataforge.meta.buildMeta import hep.dataforge.meta.buildMeta
import hep.dataforge.meta.withBottom import hep.dataforge.meta.withBottom
import hep.dataforge.names.NameToken import hep.dataforge.names.NameToken
import hep.dataforge.vis.js.editor.objectTree
import hep.dataforge.vis.js.editor.propertyEditor 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_COLOR_KEY
import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_OPACITY_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.VisualObject3D.Companion.VISIBLE_KEY
import hep.dataforge.vis.spatial.three.ThreePlugin import hep.dataforge.vis.spatial.three.ThreePlugin
import hep.dataforge.vis.spatial.three.output 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 hep.dataforge.vis.spatial.visible
import org.w3c.dom.HTMLElement import org.w3c.dom.HTMLElement
import kotlin.browser.document import kotlin.browser.document
import kotlin.dom.clear import kotlin.dom.clear
import kotlin.math.PI
private class GDMLDemoApp : Application { private class GDMLDemoApp : Application {
// /** // /**
@ -59,7 +60,8 @@ private class GDMLDemoApp : Application {
//val url = URL("https://drive.google.com/open?id=1w5e7fILMN83JGgB8WANJUYm8OW2s0WVO") //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 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 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") val editorElement = document.getElementById("editor") ?: error("Element with id 'editor' not found on page")
canvasElement.clear() canvasElement.clear()
@ -71,7 +73,9 @@ private class GDMLDemoApp : Application {
val output = three.output(canvasElement as HTMLElement) val output = three.output(canvasElement as HTMLElement)
output.camera.layers.set(0) 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) //tree.visualObjectTree(visual, editor::propertyEditor)
treeElement.objectTree(NameToken("World"), visual) { treeElement.objectTree(NameToken("World"), visual) {
editorElement.propertyEditor(it) { item -> editorElement.propertyEditor(it) { item ->

View File

@ -27,8 +27,8 @@
<div class="row"> <div class="row">
<div class="col-lg-3" id="tree"></div> <div class="col-lg-3" id="tree"></div>
<div class="col-lg-6"> <div class="col-lg-6">
<div class="row" id="layers"></div> <div class="row" id="settings"></div>
<div class="row container" id="canvas"></div> <div class="row" id="canvas"></div>
</div> </div>
<div class="col-lg-3" id="editor"></div> <div class="col-lg-3" id="editor"></div>
</div> </div>

View File

@ -1,11 +1,13 @@
package hep.dataforge.vis.spatial.demo package hep.dataforge.vis.spatial.demo
import hep.dataforge.meta.buildMeta import hep.dataforge.meta.buildMeta
import hep.dataforge.meta.invoke
import hep.dataforge.names.toName import hep.dataforge.names.toName
import hep.dataforge.output.OutputManager import hep.dataforge.output.OutputManager
import hep.dataforge.vis.common.Colors import hep.dataforge.vis.common.Colors
import hep.dataforge.vis.common.VisualObject import hep.dataforge.vis.common.VisualObject
import hep.dataforge.vis.spatial.* import hep.dataforge.vis.spatial.*
import hep.dataforge.vis.spatial.specifications.CanvasSpec
import kotlinx.coroutines.* import kotlinx.coroutines.*
import kotlin.math.PI import kotlin.math.PI
import kotlin.math.cos import kotlin.math.cos
@ -21,10 +23,22 @@ fun OutputManager.demo(name: String, title: String = name, block: VisualGroup3D.
output.render(action = block) 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() { fun OutputManager.showcase() {
demo("shapes", "Basic shapes") { demo("shapes", "Basic shapes") {
box(100.0, 100.0, 100.0) { box(100.0, 100.0, 100.0) {
z = 110.0 z = -110.0
} }
sphere(50.0) { sphere(50.0) {
x = 110 x = 110
@ -88,6 +102,7 @@ fun OutputManager.showcase() {
layer(i * 5, 20 * sin(2 * PI / 100 * i), 20 * cos(2 * PI / 100 * i)) layer(i * 5, 20 * sin(2 * PI / 100 * i), 20 * cos(2 * PI / 100 * i))
} }
color(Colors.teal) color(Colors.teal)
rotationX = -PI / 2
} }
} }
@ -111,13 +126,13 @@ fun OutputManager.showcase() {
box(100, 100, 50) { box(100, 100, 50) {
opacity = 0.3 opacity = 0.3
} }
label("Hello, world!",fontSize = 15) { label("Hello, world!", fontSize = 12) {
z = -26 z = 26
} }
} }
} }
fun OutputManager.showcaseCSG(){ fun OutputManager.showcaseCSG() {
demo("CSG.simple", "CSG operations") { demo("CSG.simple", "CSG operations") {
composite(CompositeType.UNION) { composite(CompositeType.UNION) {
box(100, 100, 100) { box(100, 100, 100) {

View File

@ -22,27 +22,27 @@ private class ThreeDemoApp : Application {
ThreeDemoGrid(element).run { ThreeDemoGrid(element).run {
showcase() showcase()
showcaseCSG() showcaseCSG()
demo("dynamicBox", "Dancing boxes") { // demo("dynamicBox", "Dancing boxes") {
val boxes = (-10..10).flatMap { i -> // val boxes = (-10..10).flatMap { i ->
(-10..10).map { j -> // (-10..10).map { j ->
varBox(10, 10, 0, name = "cell_${i}_${j}") { // varBox(10, 10, 0, name = "cell_${i}_${j}") {
x = i * 10 // x = i * 10
y = j * 10 // y = j * 10
value = 128 // value = 128
setProperty(EDGES_ENABLED_KEY, false) // setProperty(EDGES_ENABLED_KEY, false)
setProperty(WIREFRAME_ENABLED_KEY, false) // setProperty(WIREFRAME_ENABLED_KEY, false)
} // }
} // }
} // }
GlobalScope.launch { // GlobalScope.launch {
while (isActive) { // while (isActive) {
delay(500) // delay(500)
boxes.forEach { box -> // boxes.forEach { box ->
box.value = (box.value + Random.nextInt(-15, 15)).coerceIn(0..255) // box.value = (box.value + Random.nextInt(-15, 15)).coerceIn(0..255)
} // }
} // }
} // }
} // }
} }

View File

@ -3,11 +3,15 @@ package hep.dataforge.vis.spatial.demo
import hep.dataforge.context.Global import hep.dataforge.context.Global
import hep.dataforge.meta.Meta import hep.dataforge.meta.Meta
import hep.dataforge.meta.get import hep.dataforge.meta.get
import hep.dataforge.meta.invoke
import hep.dataforge.meta.string import hep.dataforge.meta.string
import hep.dataforge.names.Name import hep.dataforge.names.Name
import hep.dataforge.output.OutputManager import hep.dataforge.output.OutputManager
import hep.dataforge.output.Renderer import hep.dataforge.output.Renderer
import hep.dataforge.vis.common.VisualObject 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.ThreeCanvas
import hep.dataforge.vis.spatial.three.ThreePlugin import hep.dataforge.vis.spatial.three.ThreePlugin
import hep.dataforge.vis.spatial.three.output import hep.dataforge.vis.spatial.three.output
@ -40,18 +44,14 @@ class ThreeDemoGrid(element: Element, meta: Meta = Meta.EMPTY) : OutputManager {
return outputs.getOrPut(name) { return outputs.getOrPut(name) {
if (type != VisualObject::class) error("Supports only DisplayObject") if (type != VisualObject::class) error("Supports only DisplayObject")
val output = three.output(meta = meta) { lateinit var output: ThreeCanvas
"minSize" put 500
"axis" put {
"size" put 500
}
}
//TODO calculate cell width here using jquery //TODO calculate cell width here using jquery
gridRoot.append { gridRoot.append {
span("border") { span("border") {
div("col-6") { div("col-6") {
div { id = "output-$name" }.also { div { id = "output-$name" }.also {
output.attach(it) output = three.output(it, canvasOptions)
//output.attach(it)
} }
hr() hr()
h2 { +(meta["title"].string ?: name.toString()) } h2 { +(meta["title"].string ?: name.toString()) }

View File

@ -4,32 +4,14 @@
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Three js demo for particle physics</title> <title>Three js demo for particle physics</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous"> integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
<script type="text/javascript" src="ru.mipt.npm.muon.monitor.main.bundle.js"></script> <script type="text/javascript" src="main.bundle.js"></script>
</head> </head>
<body class="testApp"> <body class="testApp">
<!--
<div class="container" id="drop_zone" data-toggle="tooltip" data-placement="right"
title="Для загрузки данных в текстовом формате, надо перетащить файл сюда">
Загрузить данные
<br/>
(перетащить файл сюда)
</div>
-->
<div class="container"> <div class="container">
<h1>Demo grid</h1> <h1>Demo grid</h1>
</div> </div>
<div class="container" id="canvas"></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> </body>
</html> </html>

View File

@ -1,7 +1,5 @@
package hep.dataforge.vis.spatial.demo 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 hep.dataforge.vis.spatial.gdml.gdml
import javafx.stage.Stage import javafx.stage.Stage
import tornadofx.* import tornadofx.*
@ -14,22 +12,12 @@ class FXDemoApp : App(FXDemoGrid::class) {
override fun start(stage: Stage) { override fun start(stage: Stage) {
super.start(stage) super.start(stage)
stage.width = 400.0 stage.width = 600.0
stage.height = 400.0 stage.height = 600.0
//view.showcase() view.showcase()
view.demo("gdml", "gdml") { view.demo("gdml", "gdml-cubes") {
gdml(Paths.get("D:\\Work\\Projects\\gdml.kt\\gdml-source\\cubes.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
}
}
}
}
//setProperty(Material3D.MATERIAL_WIREFRAME_KEY, true) //setProperty(Material3D.MATERIAL_WIREFRAME_KEY, true)
} }
} }

View File

@ -9,13 +9,15 @@ import hep.dataforge.output.Renderer
import hep.dataforge.vis.common.VisualObject import hep.dataforge.vis.common.VisualObject
import hep.dataforge.vis.spatial.fx.FX3DPlugin import hep.dataforge.vis.spatial.fx.FX3DPlugin
import hep.dataforge.vis.spatial.fx.FXCanvas3D 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.collections.FXCollections
import javafx.scene.Parent import javafx.scene.Parent
import javafx.scene.control.Tab import javafx.scene.control.Tab
import tornadofx.* import tornadofx.*
import kotlin.reflect.KClass import kotlin.reflect.KClass
class FXDemoGrid : View(), OutputManager { class FXDemoGrid : View(title = "DataForge-vis FX demo"), OutputManager {
private val outputs = FXCollections.observableHashMap<Name, FXCanvas3D>() private val outputs = FXCollections.observableHashMap<Name, FXCanvas3D>()
override val root: Parent = borderpane { 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> { override fun <T : Any> get(type: KClass<out T>, name: Name, stage: Name, meta: Meta): Renderer<T> {
return outputs.getOrPut(name) { return outputs.getOrPut(name) {
if (type != VisualObject::class) kotlin.error("Supports only DisplayObject") if (type != VisualObject::class) kotlin.error("Supports only DisplayObject")
val customMeta = buildMeta(meta) { val output = FXCanvas3D(fx3d, canvasOptions)
"minSize" put 500
"axis" put {
"size" put 500
}
}
val output = FXCanvas3D(fx3d, customMeta)
output output
} as Renderer<T> } as Renderer<T>