Merge branch 'dev' into doc
This commit is contained in:
commit
83b72475ae
17
.github/workflows/gradle.yml
vendored
Normal file
17
.github/workflows/gradle.yml
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
name: Gradle build
|
||||
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Set up JDK 11
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 11
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew build
|
@ -113,3 +113,11 @@ tailrec fun VisualObject.findStyle(name: String): Meta? =
|
||||
|
||||
fun VisualObject.findAllStyles(): Laminate = Laminate(styles.mapNotNull(::findStyle))
|
||||
|
||||
//operator fun VisualObject.get(name: Name): VisualObject?{
|
||||
// return when {
|
||||
// name.isEmpty() -> this
|
||||
// this is VisualGroup -> this[name]
|
||||
// else -> null
|
||||
// }
|
||||
//}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
package hep.dataforge.vis.js.editor
|
||||
|
||||
import hep.dataforge.names.NameToken
|
||||
import hep.dataforge.names.Name
|
||||
import hep.dataforge.names.plus
|
||||
import hep.dataforge.vis.common.VisualGroup
|
||||
import hep.dataforge.vis.common.VisualObject
|
||||
import hep.dataforge.vis.common.isEmpty
|
||||
@ -12,61 +13,64 @@ import org.w3c.dom.HTMLElement
|
||||
import org.w3c.dom.HTMLSpanElement
|
||||
import kotlin.dom.clear
|
||||
|
||||
fun Element.objectTree(
|
||||
token: NameToken,
|
||||
fun Element.displayObjectTree(
|
||||
obj: VisualObject,
|
||||
clickCallback: (VisualObject) -> Unit = {}
|
||||
clickCallback: (Name) -> Unit = {}
|
||||
) {
|
||||
clear()
|
||||
append {
|
||||
card("Object tree") {
|
||||
subTree(token, obj, clickCallback)
|
||||
subTree(Name.EMPTY, obj, clickCallback)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun TagConsumer<HTMLElement>.subTree(
|
||||
token: NameToken,
|
||||
fullName: Name,
|
||||
obj: VisualObject,
|
||||
clickCallback: (VisualObject) -> Unit
|
||||
clickCallback: (Name) -> Unit
|
||||
) {
|
||||
// val fullName = parentName + token
|
||||
val token = fullName.last()?.toString()?:"World"
|
||||
|
||||
if (obj is VisualGroup && !obj.isEmpty) {
|
||||
//display as node if any child is visible
|
||||
if (obj is VisualGroup && obj.children.keys.any { !it.body.startsWith("@") }) {
|
||||
lateinit var toggle: HTMLSpanElement
|
||||
div("d-inline-block text-truncate") {
|
||||
toggle = span("objTree-caret")
|
||||
label("objTree-label") {
|
||||
+token.toString()
|
||||
onClickFunction = { clickCallback(obj) }
|
||||
+token
|
||||
onClickFunction = { clickCallback(fullName) }
|
||||
}
|
||||
}
|
||||
val subtree = ul("objTree-subtree")
|
||||
toggle.onclick = {
|
||||
toggle.classList.toggle("objTree-caret-down")
|
||||
subtree.apply {
|
||||
//If expanded, add children dynamically
|
||||
if (toggle.classList.contains("objTree-caret-down")) {
|
||||
obj.children.entries
|
||||
.filter { !it.key.toString().startsWith("@") }
|
||||
.filter { !it.key.toString().startsWith("@") } // ignore statics and other hidden children
|
||||
.sortedBy { (it.value as? VisualGroup)?.isEmpty ?: true }
|
||||
.forEach { (token, child) ->
|
||||
.forEach { (childToken, child) ->
|
||||
append {
|
||||
li().apply {
|
||||
subTree(token, child, clickCallback)
|
||||
subTree(fullName + childToken, child, clickCallback)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// if not, clear them to conserve memory on very long lists
|
||||
this.clear()
|
||||
}
|
||||
}
|
||||
//jQuery(subtree).asDynamic().collapse("toggle")
|
||||
}
|
||||
} else {
|
||||
div("d-inline-block text-truncate") {
|
||||
span("objTree-leaf")
|
||||
label("objTree-label") {
|
||||
+token.toString()
|
||||
onClickFunction = { clickCallback(obj) }
|
||||
+token
|
||||
onClickFunction = { clickCallback(fullName) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,52 +5,71 @@ import hep.dataforge.js.jsObject
|
||||
import hep.dataforge.meta.DynamicMeta
|
||||
import hep.dataforge.meta.Meta
|
||||
import hep.dataforge.meta.update
|
||||
import hep.dataforge.names.Name
|
||||
import hep.dataforge.names.isEmpty
|
||||
import hep.dataforge.vis.common.VisualObject
|
||||
import hep.dataforge.vis.common.findStyle
|
||||
import kotlinx.html.dom.append
|
||||
import kotlinx.html.js.div
|
||||
import kotlinx.html.js.h4
|
||||
import kotlinx.html.js.*
|
||||
import org.w3c.dom.Element
|
||||
import kotlin.collections.forEach
|
||||
import kotlin.collections.isNotEmpty
|
||||
import kotlin.collections.set
|
||||
import kotlin.dom.clear
|
||||
|
||||
//FIXME something rotten in JS-Meta converter
|
||||
fun Meta.toDynamic() = JSON.parse<dynamic>(toJson().toString())
|
||||
|
||||
//TODO add node descriptor instead of configuring property selector
|
||||
fun Element.propertyEditor(item: VisualObject?, propertySelector: (VisualObject) -> Meta = { it.config }) {
|
||||
fun Element.displayPropertyEditor(
|
||||
name: Name,
|
||||
item: VisualObject,
|
||||
propertySelector: (VisualObject) -> Meta = { it.config }
|
||||
) {
|
||||
clear()
|
||||
if (item != null) {
|
||||
append {
|
||||
card("Properties") {
|
||||
val dMeta: dynamic = propertySelector(item).toDynamic()
|
||||
val options: JSONEditorOptions = jsObject {
|
||||
mode = "form"
|
||||
onChangeJSON = { item.config.update(DynamicMeta(it.asDynamic())) }
|
||||
}
|
||||
JSONEditor(div(), options, dMeta)
|
||||
}
|
||||
|
||||
val styles = item.styles
|
||||
if (styles.isNotEmpty()) {
|
||||
card("Styles") {
|
||||
item.styles.forEach { style ->
|
||||
val styleMeta = item.findStyle(style)
|
||||
h4("container") { +style }
|
||||
if (styleMeta != null) {
|
||||
div("container").apply {
|
||||
val options: JSONEditorOptions = jsObject {
|
||||
mode = "view"
|
||||
}
|
||||
JSONEditor(
|
||||
this,
|
||||
options,
|
||||
styleMeta.toDynamic()
|
||||
)
|
||||
append {
|
||||
card("Properties") {
|
||||
if (!name.isEmpty()) {
|
||||
nav {
|
||||
attributes["aria-label"] = "breadcrumb"
|
||||
ol("breadcrumb") {
|
||||
name.tokens.forEach { token ->
|
||||
li("breadcrumb-item") {
|
||||
+token.toString()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
val dMeta: dynamic = propertySelector(item).toDynamic()
|
||||
val options: JSONEditorOptions = jsObject {
|
||||
mode = "form"
|
||||
onChangeJSON = { item.config.update(DynamicMeta(it.asDynamic())) }
|
||||
}
|
||||
JSONEditor(div(), options, dMeta)
|
||||
}
|
||||
|
||||
val styles = item.styles
|
||||
if (styles.isNotEmpty()) {
|
||||
card("Styles") {
|
||||
item.styles.forEach { style ->
|
||||
val styleMeta = item.findStyle(style)
|
||||
h4("container") { +style }
|
||||
if (styleMeta != null) {
|
||||
div("container").apply {
|
||||
val options: JSONEditorOptions = jsObject {
|
||||
mode = "view"
|
||||
}
|
||||
JSONEditor(
|
||||
this,
|
||||
options,
|
||||
styleMeta.toDynamic()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -49,6 +49,7 @@ class Visual3DPlugin(meta: Meta) : AbstractPlugin(meta) {
|
||||
Box::class with Box.serializer()
|
||||
Convex::class with Convex.serializer()
|
||||
Extruded::class with Extruded.serializer()
|
||||
addSubclass(PolyLine.serializer())
|
||||
addSubclass(Label3D.serializer())
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,6 @@ import hep.dataforge.vis.common.VisualObject
|
||||
import hep.dataforge.vis.spatial.VisualObject3D.Companion.DETAIL_KEY
|
||||
import hep.dataforge.vis.spatial.VisualObject3D.Companion.IGNORE_KEY
|
||||
import hep.dataforge.vis.spatial.VisualObject3D.Companion.LAYER_KEY
|
||||
import hep.dataforge.vis.spatial.VisualObject3D.Companion.SELECTED_KEY
|
||||
import hep.dataforge.vis.spatial.VisualObject3D.Companion.VISIBLE_KEY
|
||||
import kotlinx.serialization.UseSerializers
|
||||
|
||||
@ -121,9 +120,9 @@ var VisualObject.ignore: Boolean?
|
||||
get() = getProperty(IGNORE_KEY,false).boolean
|
||||
set(value) = setProperty(IGNORE_KEY, value)
|
||||
|
||||
var VisualObject.selected: Boolean?
|
||||
get() = getProperty(SELECTED_KEY).boolean
|
||||
set(value) = setProperty(SELECTED_KEY, value)
|
||||
//var VisualObject.selected: Boolean?
|
||||
// get() = getProperty(SELECTED_KEY).boolean
|
||||
// set(value) = setProperty(SELECTED_KEY, value)
|
||||
|
||||
private fun VisualObject3D.position(): Point3D =
|
||||
position ?: Point3D(0.0, 0.0, 0.0).also { position = it }
|
||||
|
@ -1,8 +1,6 @@
|
||||
package hep.dataforge.vis.spatial.three
|
||||
|
||||
import hep.dataforge.meta.Meta
|
||||
import hep.dataforge.meta.boolean
|
||||
import hep.dataforge.meta.get
|
||||
import hep.dataforge.meta.node
|
||||
import hep.dataforge.names.asName
|
||||
import hep.dataforge.names.plus
|
||||
@ -10,10 +8,10 @@ import hep.dataforge.names.startsWith
|
||||
import hep.dataforge.vis.spatial.Material3D
|
||||
import hep.dataforge.vis.spatial.VisualObject3D
|
||||
import hep.dataforge.vis.spatial.layer
|
||||
import hep.dataforge.vis.spatial.three.ThreeMaterials.getMaterial
|
||||
import info.laht.threekt.core.BufferGeometry
|
||||
import info.laht.threekt.geometries.EdgesGeometry
|
||||
import info.laht.threekt.geometries.WireframeGeometry
|
||||
import info.laht.threekt.materials.MeshBasicMaterial
|
||||
import info.laht.threekt.objects.LineSegments
|
||||
import info.laht.threekt.objects.Mesh
|
||||
import kotlin.reflect.KClass
|
||||
@ -37,7 +35,7 @@ abstract class MeshThreeFactory<in T : VisualObject3D>(
|
||||
|
||||
//val meshMeta: Meta = obj.properties[Material3D.MATERIAL_KEY]?.node ?: Meta.empty
|
||||
|
||||
val mesh = Mesh(geometry, MeshBasicMaterial()).apply {
|
||||
val mesh = Mesh(geometry, getMaterial(obj)).apply {
|
||||
matrixAutoUpdate = false
|
||||
applyEdges(obj)
|
||||
applyWireFrame(obj)
|
||||
@ -45,9 +43,6 @@ abstract class MeshThreeFactory<in T : VisualObject3D>(
|
||||
//set position for mesh
|
||||
updatePosition(obj)
|
||||
|
||||
//set color for mesh
|
||||
updateMaterial(obj)
|
||||
|
||||
layers.enable(obj.layer)
|
||||
children.forEach {
|
||||
it.layers.enable(obj.layer)
|
||||
|
@ -4,33 +4,55 @@ import hep.dataforge.context.Context
|
||||
import hep.dataforge.meta.Meta
|
||||
import hep.dataforge.meta.get
|
||||
import hep.dataforge.meta.string
|
||||
import hep.dataforge.names.Name
|
||||
import hep.dataforge.names.plus
|
||||
import hep.dataforge.names.toName
|
||||
import hep.dataforge.output.Renderer
|
||||
import hep.dataforge.vis.common.Colors
|
||||
import hep.dataforge.vis.spatial.VisualObject3D
|
||||
import hep.dataforge.vis.spatial.specifications.CameraSpec
|
||||
import hep.dataforge.vis.spatial.specifications.CanvasSpec
|
||||
import hep.dataforge.vis.spatial.specifications.ControlsSpec
|
||||
import hep.dataforge.vis.spatial.three.ThreeMaterials.HIGHLIGHT_MATERIAL
|
||||
import info.laht.threekt.WebGLRenderer
|
||||
import info.laht.threekt.cameras.PerspectiveCamera
|
||||
import info.laht.threekt.core.BufferGeometry
|
||||
import info.laht.threekt.core.Object3D
|
||||
import info.laht.threekt.core.Raycaster
|
||||
import info.laht.threekt.external.controls.OrbitControls
|
||||
import info.laht.threekt.external.controls.TrackballControls
|
||||
import info.laht.threekt.geometries.EdgesGeometry
|
||||
import info.laht.threekt.helpers.AxesHelper
|
||||
import info.laht.threekt.math.Vector2
|
||||
import info.laht.threekt.objects.LineSegments
|
||||
import info.laht.threekt.objects.Mesh
|
||||
import info.laht.threekt.scenes.Scene
|
||||
import org.w3c.dom.HTMLElement
|
||||
import org.w3c.dom.Node
|
||||
import org.w3c.dom.events.MouseEvent
|
||||
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 spec: CanvasSpec) : Renderer<VisualObject3D> {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class ThreeCanvas(element: HTMLElement, val three: ThreePlugin, val spec: CanvasSpec) : Renderer<VisualObject3D> {
|
||||
|
||||
override val context: Context get() = three.context
|
||||
|
||||
var content: VisualObject3D? = null
|
||||
private set
|
||||
|
||||
private var root: Object3D? = null
|
||||
|
||||
private val raycaster = Raycaster()
|
||||
private val mousePosition: Vector2 = Vector2()
|
||||
|
||||
var clickListener: ((Name) -> Unit)? = null
|
||||
|
||||
val axes = AxesHelper(spec.axes.size.toInt()).apply {
|
||||
visible = spec.axes.visible
|
||||
}
|
||||
@ -41,27 +63,26 @@ class ThreeCanvas(val three: ThreePlugin, val spec: CanvasSpec) : Renderer<Visua
|
||||
|
||||
val camera = buildCamera(spec.camera)
|
||||
|
||||
private fun buildCamera(spec: CameraSpec) = PerspectiveCamera(
|
||||
spec.fov,
|
||||
1.0,
|
||||
spec.nearClip,
|
||||
spec.farClip
|
||||
).apply {
|
||||
translateX(spec.distance* sin(spec.zenith) * sin(spec.azimuth))
|
||||
translateY(spec.distance* cos(spec.zenith))
|
||||
translateZ(spec.distance * sin(spec.zenith) * cos(spec.azimuth))
|
||||
}
|
||||
|
||||
private fun addControls(element: Node, controlsSpec: ControlsSpec) {
|
||||
when (controlsSpec["type"].string) {
|
||||
"trackball" -> TrackballControls(camera, element)
|
||||
else -> OrbitControls(camera, element)
|
||||
}
|
||||
}
|
||||
|
||||
fun attach(element: HTMLElement) {
|
||||
init {
|
||||
element.clear()
|
||||
|
||||
//Attach listener to track mouse changes
|
||||
element.addEventListener("mousemove", { event ->
|
||||
(event as? MouseEvent)?.run {
|
||||
val rect = element.getBoundingClientRect()
|
||||
mousePosition.x = ((event.clientX - rect.left) / element.clientWidth) * 2 - 1
|
||||
mousePosition.y = -((event.clientY - rect.top) / element.clientHeight) * 2 + 1
|
||||
}
|
||||
}, false)
|
||||
|
||||
element.addEventListener("mousedown", { event ->
|
||||
val mesh = pick()
|
||||
if (mesh != null) {
|
||||
val name = mesh.fullName()
|
||||
clickListener?.invoke(name)
|
||||
}
|
||||
}, false)
|
||||
|
||||
camera.aspect = 1.0
|
||||
|
||||
val renderer = WebGLRenderer { antialias = true }.apply {
|
||||
@ -72,6 +93,13 @@ class ThreeCanvas(val three: ThreePlugin, val spec: CanvasSpec) : Renderer<Visua
|
||||
addControls(renderer.domElement, spec.controls)
|
||||
|
||||
fun animate() {
|
||||
val mesh = pick()
|
||||
|
||||
if (mesh != null && highlighted != mesh) {
|
||||
highlighted?.toggleHighlight(false)
|
||||
mesh.toggleHighlight(true)
|
||||
}
|
||||
|
||||
window.requestAnimationFrame {
|
||||
animate()
|
||||
}
|
||||
@ -90,16 +118,98 @@ class ThreeCanvas(val three: ThreePlugin, val spec: CanvasSpec) : Renderer<Visua
|
||||
animate()
|
||||
}
|
||||
|
||||
private fun pick(): Mesh? {
|
||||
// update the picking ray with the camera and mouse position
|
||||
raycaster.setFromCamera(mousePosition, camera)
|
||||
|
||||
// calculate objects intersecting the picking ray
|
||||
return root?.let { root ->
|
||||
val intersects = raycaster.intersectObject(root, true)
|
||||
val intersect = intersects.firstOrNull()
|
||||
intersect?.`object` as? Mesh
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve full name of the object relative to the global root
|
||||
*/
|
||||
private fun Object3D.fullName(): Name {
|
||||
if (root == null) error("Can't resolve element name without the root")
|
||||
return if (parent == root) {
|
||||
name.toName()
|
||||
} else {
|
||||
(parent?.fullName() ?: Name.EMPTY) + name.toName()
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildCamera(spec: CameraSpec) = PerspectiveCamera(
|
||||
spec.fov,
|
||||
1.0,
|
||||
spec.nearClip,
|
||||
spec.farClip
|
||||
).apply {
|
||||
translateX(spec.distance * sin(spec.zenith) * sin(spec.azimuth))
|
||||
translateY(spec.distance * cos(spec.zenith))
|
||||
translateZ(spec.distance * sin(spec.zenith) * cos(spec.azimuth))
|
||||
}
|
||||
|
||||
private fun addControls(element: Node, controlsSpec: ControlsSpec) {
|
||||
when (controlsSpec["type"].string) {
|
||||
"trackball" -> TrackballControls(camera, element)
|
||||
else -> OrbitControls(camera, element)
|
||||
}
|
||||
}
|
||||
|
||||
override fun render(obj: VisualObject3D, meta: Meta) {
|
||||
content = obj
|
||||
//clear old root
|
||||
scene.children.find { it.name == "@root" }?.let {
|
||||
scene.remove(it)
|
||||
}
|
||||
|
||||
val object3D = three.buildObject3D(obj)
|
||||
object3D.name = "@root"
|
||||
scene.add(object3D)
|
||||
content = obj
|
||||
root = object3D
|
||||
}
|
||||
|
||||
private var highlighted: Mesh? = null
|
||||
|
||||
/**
|
||||
* Toggle highlight for the given [Mesh] object
|
||||
*/
|
||||
private fun Mesh.toggleHighlight(highlight: Boolean) {
|
||||
if (highlight) {
|
||||
val edges = LineSegments(
|
||||
EdgesGeometry(geometry as BufferGeometry),
|
||||
HIGHLIGHT_MATERIAL
|
||||
).apply {
|
||||
name = "@highlight"
|
||||
}
|
||||
add(edges)
|
||||
highlighted = this
|
||||
} else {
|
||||
val highlightEdges = children.find { it.name == "@highlight" }
|
||||
highlightEdges?.let { remove(it) }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle highlight for element with given name
|
||||
*/
|
||||
fun highlight(name: Name?) {
|
||||
if (name == null) {
|
||||
highlighted?.toggleHighlight(false)
|
||||
highlighted = null
|
||||
return
|
||||
}
|
||||
val mesh = root?.findChild(name) as? Mesh
|
||||
if (mesh != null && highlighted != mesh) {
|
||||
highlighted?.toggleHighlight(false)
|
||||
mesh.toggleHighlight(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun ThreePlugin.output(element: HTMLElement? = null, spec: CanvasSpec = CanvasSpec.empty()): ThreeCanvas =
|
||||
ThreeCanvas(this, spec).apply {
|
||||
if (element != null) {
|
||||
attach(element)
|
||||
}
|
||||
}
|
||||
fun ThreePlugin.output(element: HTMLElement, spec: CanvasSpec = CanvasSpec.empty()): ThreeCanvas =
|
||||
ThreeCanvas(element, this, spec)
|
@ -0,0 +1,56 @@
|
||||
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.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.CanvasTextBaseline
|
||||
import org.w3c.dom.HTMLCanvasElement
|
||||
import org.w3c.dom.MIDDLE
|
||||
import kotlin.browser.document
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
/**
|
||||
* Using example from http://stemkoski.github.io/Three.js/Texture-From-Canvas.html
|
||||
*/
|
||||
object ThreeCanvasLabelFactory: 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 = "Bold ${obj.fontSize}pt ${obj.fontFamily}"
|
||||
context.fillStyle = obj.color ?: "black"
|
||||
context.textBaseline = CanvasTextBaseline.MIDDLE
|
||||
val metrics = context.measureText(obj.text)
|
||||
//canvas.width = metrics.width.toInt()
|
||||
|
||||
|
||||
context.fillText(obj.text, (canvas.width - metrics.width)/2, 0.5*canvas.height)
|
||||
|
||||
|
||||
// canvas contents will be used for a texture
|
||||
val texture = Texture(canvas)
|
||||
texture.needsUpdate = true
|
||||
|
||||
val material = MeshBasicMaterial().apply {
|
||||
map = texture
|
||||
side = DoubleSide
|
||||
transparent = true
|
||||
}
|
||||
|
||||
val mesh = Mesh(
|
||||
PlaneBufferGeometry(canvas.width, canvas.height),
|
||||
material
|
||||
)
|
||||
|
||||
mesh.updatePosition(obj)
|
||||
|
||||
return mesh
|
||||
}
|
||||
}
|
@ -7,6 +7,7 @@ import hep.dataforge.vis.common.VisualObject
|
||||
import hep.dataforge.vis.spatial.*
|
||||
import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_KEY
|
||||
import hep.dataforge.vis.spatial.three.ThreeFactory.Companion.TYPE
|
||||
import hep.dataforge.vis.spatial.three.ThreeMaterials.getMaterial
|
||||
import info.laht.threekt.core.BufferGeometry
|
||||
import info.laht.threekt.core.Object3D
|
||||
import info.laht.threekt.objects.Mesh
|
||||
@ -53,14 +54,13 @@ fun Object3D.updatePosition(obj: VisualObject3D) {
|
||||
/**
|
||||
* Update non-position non-geometry property
|
||||
*/
|
||||
fun Object3D.updateProperty(source: VisualObject, propertyName: Name) {
|
||||
fun Object3D.updateProperty(source: VisualObject3D, propertyName: Name) {
|
||||
if (this is Mesh && propertyName.startsWith(MATERIAL_KEY)) {
|
||||
updateMaterial(source)
|
||||
this.material = getMaterial(source)
|
||||
} else if (
|
||||
source is VisualObject3D &&
|
||||
(propertyName.startsWith(VisualObject3D.position)
|
||||
|| propertyName.startsWith(VisualObject3D.rotation)
|
||||
|| propertyName.startsWith(VisualObject3D.scale))
|
||||
propertyName.startsWith(VisualObject3D.position)
|
||||
|| propertyName.startsWith(VisualObject3D.rotation)
|
||||
|| propertyName.startsWith(VisualObject3D.scale)
|
||||
) {
|
||||
//update position of mesh using this object
|
||||
updatePosition(source)
|
||||
|
@ -34,7 +34,7 @@ class ThreeGeometryBuilder : GeometryBuilder<BufferGeometry> {
|
||||
override fun face(vertex1: Point3D, vertex2: Point3D, vertex3: Point3D, normal: Point3D?, meta: Meta) {
|
||||
val face = Face3(append(vertex1), append(vertex2), append(vertex3), normal ?: Vector3(0, 0, 0))
|
||||
meta["materialIndex"].int?.let { face.materialIndex = it }
|
||||
meta["color"]?.color()?.let { face.color = it }
|
||||
meta["color"]?.getColor()?.let { face.color = it }
|
||||
faces.add(face)
|
||||
}
|
||||
|
||||
|
@ -1,56 +1,33 @@
|
||||
package hep.dataforge.vis.spatial.three
|
||||
|
||||
import hep.dataforge.js.jsObject
|
||||
import hep.dataforge.meta.MetaItem
|
||||
import hep.dataforge.names.Name
|
||||
import hep.dataforge.vis.spatial.Label3D
|
||||
import hep.dataforge.vis.spatial.color
|
||||
import info.laht.threekt.DoubleSide
|
||||
import hep.dataforge.vis.spatial.three.ThreeMaterials.getMaterial
|
||||
import info.laht.threekt.core.Object3D
|
||||
import info.laht.threekt.geometries.PlaneBufferGeometry
|
||||
import info.laht.threekt.materials.MeshBasicMaterial
|
||||
import info.laht.threekt.geometries.TextBufferGeometry
|
||||
import info.laht.threekt.objects.Mesh
|
||||
import info.laht.threekt.textures.Texture
|
||||
import org.w3c.dom.CanvasRenderingContext2D
|
||||
import org.w3c.dom.CanvasTextBaseline
|
||||
import org.w3c.dom.HTMLCanvasElement
|
||||
import org.w3c.dom.MIDDLE
|
||||
import kotlin.browser.document
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
/**
|
||||
* Using example from http://stemkoski.github.io/Three.js/Texture-From-Canvas.html
|
||||
*
|
||||
*/
|
||||
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 = "Bold ${obj.fontSize}pt ${obj.fontFamily}"
|
||||
context.fillStyle = obj.color ?: "black"
|
||||
context.textBaseline = CanvasTextBaseline.MIDDLE
|
||||
val metrics = context.measureText(obj.text)
|
||||
//canvas.width = metrics.width.toInt()
|
||||
|
||||
|
||||
context.fillText(obj.text, (canvas.width - metrics.width)/2, 0.5*canvas.height)
|
||||
|
||||
|
||||
// canvas contents will be used for a texture
|
||||
val texture = Texture(canvas)
|
||||
texture.needsUpdate = true
|
||||
|
||||
val material = MeshBasicMaterial().apply {
|
||||
map = texture
|
||||
side = DoubleSide
|
||||
transparent = true
|
||||
val textGeo = TextBufferGeometry( obj.text, jsObject {
|
||||
font = obj.fontFamily
|
||||
size = 20
|
||||
height = 1
|
||||
curveSegments = 1
|
||||
} )
|
||||
return Mesh(textGeo, getMaterial(obj)).apply {
|
||||
updatePosition(obj)
|
||||
obj.onPropertyChange(this@ThreeLabelFactory){name: Name, before: MetaItem<*>?, after: MetaItem<*>? ->
|
||||
//TODO
|
||||
}
|
||||
}
|
||||
|
||||
val mesh = Mesh(
|
||||
PlaneBufferGeometry(canvas.width, canvas.height),
|
||||
material
|
||||
)
|
||||
|
||||
mesh.updatePosition(obj)
|
||||
|
||||
return mesh
|
||||
}
|
||||
}
|
@ -3,18 +3,18 @@ package hep.dataforge.vis.spatial.three
|
||||
import hep.dataforge.meta.*
|
||||
import hep.dataforge.values.ValueType
|
||||
import hep.dataforge.vis.common.Colors
|
||||
import hep.dataforge.vis.common.VisualObject
|
||||
import hep.dataforge.vis.spatial.Material3D
|
||||
import hep.dataforge.vis.spatial.VisualObject3D
|
||||
import info.laht.threekt.materials.LineBasicMaterial
|
||||
import info.laht.threekt.materials.Material
|
||||
import info.laht.threekt.materials.MeshBasicMaterial
|
||||
import info.laht.threekt.materials.MeshPhongMaterial
|
||||
import info.laht.threekt.math.Color
|
||||
import info.laht.threekt.objects.Mesh
|
||||
|
||||
|
||||
object ThreeMaterials {
|
||||
val DEFAULT_COLOR = Color(Colors.darkgreen)
|
||||
val DEFAULT = MeshPhongMaterial().apply {
|
||||
val DEFAULT = MeshBasicMaterial().apply {
|
||||
color.set(DEFAULT_COLOR)
|
||||
}
|
||||
val DEFAULT_LINE_COLOR = Color(Colors.black)
|
||||
@ -22,34 +22,49 @@ object ThreeMaterials {
|
||||
color.set(DEFAULT_LINE_COLOR)
|
||||
}
|
||||
|
||||
val HIGHLIGHT_MATERIAL = LineBasicMaterial().apply {
|
||||
color.set(Colors.ivory)
|
||||
linewidth = 8.0
|
||||
}
|
||||
|
||||
// private val materialCache = HashMap<Meta, Material>()
|
||||
private val lineMaterialCache = HashMap<Meta?, LineBasicMaterial>()
|
||||
|
||||
|
||||
// fun buildMaterial(meta: Meta): Material =
|
||||
// MeshBasicMaterial().apply {
|
||||
// color = meta["color"]?.color() ?: DEFAULT_COLOR
|
||||
// opacity = meta["opacity"]?.double ?: 1.0
|
||||
// transparent = meta["transparent"].boolean ?: (opacity < 1.0)
|
||||
// //node["specularColor"]?.let { specular = it.color() }
|
||||
// //side = 2
|
||||
// }
|
||||
|
||||
fun getLineMaterial(meta: Meta?): LineBasicMaterial = lineMaterialCache.getOrPut(meta) {
|
||||
LineBasicMaterial().apply {
|
||||
color = meta[Material3D.COLOR_KEY]?.color() ?: DEFAULT_LINE_COLOR
|
||||
fun getLineMaterial(meta: Meta?): LineBasicMaterial {
|
||||
if (meta == null) return DEFAULT_LINE
|
||||
return LineBasicMaterial().apply {
|
||||
color = meta[Material3D.COLOR_KEY]?.getColor() ?: DEFAULT_LINE_COLOR
|
||||
opacity = meta[Material3D.OPACITY_KEY].double ?: 1.0
|
||||
transparent = opacity < 1.0
|
||||
linewidth = meta["thickness"].double ?: 1.0
|
||||
}
|
||||
}
|
||||
|
||||
fun getMaterial(visualObject3D: VisualObject3D): Material {
|
||||
val meta = visualObject3D.getProperty(Material3D.MATERIAL_KEY).node ?: return ThreeMaterials.DEFAULT
|
||||
return if (meta[Material3D.SPECULAR_COLOR] != null) {
|
||||
MeshPhongMaterial().apply {
|
||||
color = meta[Material3D.COLOR_KEY]?.getColor() ?: DEFAULT_COLOR
|
||||
specular = meta[Material3D.SPECULAR_COLOR]!!.getColor()
|
||||
opacity = meta[Material3D.OPACITY_KEY]?.double ?: 1.0
|
||||
transparent = opacity < 1.0
|
||||
wireframe = meta[Material3D.WIREFRAME_KEY].boolean ?: false
|
||||
needsUpdate = true
|
||||
}
|
||||
} else {
|
||||
MeshBasicMaterial().apply {
|
||||
color = meta[Material3D.COLOR_KEY]?.getColor() ?: DEFAULT_COLOR
|
||||
opacity = meta[Material3D.OPACITY_KEY]?.double ?: 1.0
|
||||
transparent = opacity < 1.0
|
||||
wireframe = meta[Material3D.WIREFRAME_KEY].boolean ?: false
|
||||
needsUpdate = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Infer color based on meta item
|
||||
*/
|
||||
fun MetaItem<*>.color(): Color {
|
||||
fun MetaItem<*>.getColor(): Color {
|
||||
return when (this) {
|
||||
is MetaItem.ValueItem -> if (this.value.type == ValueType.NUMBER) {
|
||||
val int = value.number.toInt()
|
||||
@ -67,47 +82,3 @@ fun MetaItem<*>.color(): Color {
|
||||
}
|
||||
}
|
||||
|
||||
///**
|
||||
// * Infer Three material based on meta item
|
||||
// */
|
||||
//fun Meta?.jsMaterial(): Material {
|
||||
// return if (this == null) {
|
||||
// ThreeMaterials.DEFAULT
|
||||
// } else {
|
||||
// ThreeMaterials.buildMaterial(this)
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//fun Meta?.jsLineMaterial(): Material {
|
||||
// return if (this == null) {
|
||||
// ThreeMaterials.DEFAULT_LINE
|
||||
// } else {
|
||||
// ThreeMaterials.buildLineMaterial(this)
|
||||
// }
|
||||
//}
|
||||
|
||||
|
||||
//fun Material3D?.jsMaterial(): Material = this?.config.jsMaterial()
|
||||
//fun Material3D?.jsLineMaterial(): Material = this?.config.jsLineMaterial()
|
||||
|
||||
fun Mesh.updateMaterial(obj: VisualObject) {
|
||||
val meta = obj.getProperty(Material3D.MATERIAL_KEY).node ?: EmptyMeta
|
||||
material = if(meta[Material3D.SPECULAR_COLOR]!= null){
|
||||
MeshPhongMaterial().apply {
|
||||
color = meta[Material3D.COLOR_KEY]?.color() ?: ThreeMaterials.DEFAULT_COLOR
|
||||
specular = meta[Material3D.SPECULAR_COLOR]!!.color()
|
||||
opacity = meta[Material3D.OPACITY_KEY]?.double ?: 1.0
|
||||
transparent = opacity < 1.0
|
||||
wireframe = meta[Material3D.WIREFRAME_KEY].boolean ?: false
|
||||
needsUpdate = true
|
||||
}
|
||||
}else {
|
||||
MeshBasicMaterial().apply {
|
||||
color = meta[Material3D.COLOR_KEY]?.color() ?: ThreeMaterials.DEFAULT_COLOR
|
||||
opacity = meta[Material3D.OPACITY_KEY]?.double ?: 1.0
|
||||
transparent = opacity < 1.0
|
||||
wireframe = meta[Material3D.WIREFRAME_KEY].boolean ?: false
|
||||
needsUpdate = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ class ThreePlugin : AbstractPlugin() {
|
||||
objectFactories[Sphere::class] = ThreeSphereFactory
|
||||
objectFactories[ConeSegment::class] = ThreeCylinderFactory
|
||||
objectFactories[PolyLine::class] = ThreeLineFactory
|
||||
objectFactories[Label3D::class] = ThreeLabelFactory
|
||||
objectFactories[Label3D::class] = ThreeCanvasLabelFactory
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
|
@ -25,7 +25,7 @@ class ThreeProxyFactory(val three: ThreePlugin) : ThreeFactory<Proxy> {
|
||||
if (name.first()?.body == PROXY_CHILD_PROPERTY_PREFIX) {
|
||||
val childName = name.first()?.index?.toName() ?: error("Wrong syntax for proxy child property: '$name'")
|
||||
val propertyName = name.cutFirst()
|
||||
val proxyChild = obj[childName] ?: error("Proxy child with name '$childName' not found")
|
||||
val proxyChild = obj[childName] as? VisualObject3D ?: error("Proxy child with name '$childName' not found or not a 3D object")
|
||||
val child = object3D.findChild(childName)?: error("Object child with name '$childName' not found")
|
||||
child.updateProperty(proxyChild, propertyName)
|
||||
} else {
|
||||
|
@ -25,7 +25,7 @@ private fun saveData(event: Event, fileName: String, mimeType: String = "text/pl
|
||||
fileSaver.saveAs(blob, fileName)
|
||||
}
|
||||
|
||||
fun Element.threeSettings(canvas: ThreeCanvas, block: TagConsumer<HTMLElement>.() -> Unit = {}) {
|
||||
fun Element.displayCanvasControls(canvas: ThreeCanvas, block: TagConsumer<HTMLElement>.() -> Unit = {}) {
|
||||
clear()
|
||||
append {
|
||||
card("Settings") {
|
||||
|
@ -50,7 +50,7 @@ external interface Intersect {
|
||||
var `object`: Object3D
|
||||
}
|
||||
|
||||
external class Raycaster {
|
||||
external class Raycaster() {
|
||||
|
||||
constructor(origin: Vector3, direction: Vector3, near: Number, far: Number)
|
||||
|
||||
@ -62,8 +62,8 @@ external class Raycaster {
|
||||
|
||||
fun setFromCamera(coord: Vector2, camera: Camera)
|
||||
|
||||
fun intersectObject(object3D: Object3D, recursive: Boolean): List<Intersect>
|
||||
fun intersectObject(object3D: Object3D, recursive: Boolean): Array<Intersect>
|
||||
|
||||
fun intersectObjects(objects: List<Object3D>, recursive: Boolean): List<Intersect>
|
||||
fun intersectObjects(objects: List<Object3D>, recursive: Boolean): Array<Intersect>
|
||||
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
@file:Suppress(
|
||||
"INTERFACE_WITH_SUPERCLASS",
|
||||
"OVERRIDING_FINAL_MEMBER",
|
||||
"RETURN_TYPE_MISMATCH_ON_OVERRIDE",
|
||||
"CONFLICTING_OVERLOADS",
|
||||
"EXTERNAL_DELEGATION"
|
||||
)
|
||||
@file:JsModule("three")
|
||||
@file:JsNonModule
|
||||
|
||||
package info.laht.threekt.geometries
|
||||
|
||||
import info.laht.threekt.core.BufferGeometry
|
||||
import info.laht.threekt.core.Geometry
|
||||
import info.laht.threekt.extras.core.Shape
|
||||
import info.laht.threekt.math.Vector2
|
||||
|
||||
external interface ExtrudeGeometryOptions {
|
||||
var curveSegments: Number?
|
||||
get() = definedExternally
|
||||
set(value) = definedExternally
|
||||
var steps: Number?
|
||||
get() = definedExternally
|
||||
set(value) = definedExternally
|
||||
var depth: Number?
|
||||
get() = definedExternally
|
||||
set(value) = definedExternally
|
||||
var bevelEnabled: Boolean?
|
||||
get() = definedExternally
|
||||
set(value) = definedExternally
|
||||
var bevelThickness: Number?
|
||||
get() = definedExternally
|
||||
set(value) = definedExternally
|
||||
var bevelSize: Number?
|
||||
get() = definedExternally
|
||||
set(value) = definedExternally
|
||||
var bevelOffset: Number?
|
||||
get() = definedExternally
|
||||
set(value) = definedExternally
|
||||
var bevelSegments: Number?
|
||||
get() = definedExternally
|
||||
set(value) = definedExternally
|
||||
var extrudePath: Any?
|
||||
get() = definedExternally
|
||||
set(value) = definedExternally
|
||||
var UVGenerator: UVGenerator?
|
||||
get() = definedExternally
|
||||
set(value) = definedExternally
|
||||
}
|
||||
|
||||
external interface UVGenerator {
|
||||
fun generateTopUV(
|
||||
geometry: ExtrudeBufferGeometry,
|
||||
vertices: Array<Number>,
|
||||
indexA: Number,
|
||||
indexB: Number,
|
||||
indexC: Number
|
||||
): Array<Vector2>
|
||||
|
||||
fun generateSideWallUV(
|
||||
geometry: ExtrudeBufferGeometry,
|
||||
vertices: Array<Number>,
|
||||
indexA: Number,
|
||||
indexB: Number,
|
||||
indexC: Number,
|
||||
indexD: Number
|
||||
): Array<Vector2>
|
||||
}
|
||||
|
||||
external open class ExtrudeBufferGeometry : BufferGeometry {
|
||||
constructor(shapes: Shape, options: ExtrudeGeometryOptions?)
|
||||
constructor(shapes: Array<Shape>, options: ExtrudeGeometryOptions?)
|
||||
|
||||
open fun addShapeList(shapes: Array<Shape>, options: Any? = definedExternally)
|
||||
open fun addShape(shape: Shape, options: Any? = definedExternally)
|
||||
|
||||
companion object {
|
||||
var WorldUVGenerator: UVGenerator
|
||||
}
|
||||
}
|
||||
|
||||
external open class ExtrudeGeometry : Geometry {
|
||||
constructor(shapes: Shape, options: ExtrudeGeometryOptions?)
|
||||
constructor(shapes: Array<Shape>, options: ExtrudeGeometryOptions?)
|
||||
|
||||
open fun addShapeList(shapes: Array<Shape>, options: Any? = definedExternally)
|
||||
open fun addShape(shape: Shape, options: Any? = definedExternally)
|
||||
|
||||
companion object {
|
||||
var WorldUVGenerator: UVGenerator
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
@file:JsModule("three")
|
||||
@file:JsNonModule
|
||||
|
||||
package info.laht.threekt.geometries
|
||||
|
||||
|
||||
external interface TextGeometryParameters {
|
||||
var font: Any?
|
||||
get() = definedExternally
|
||||
set(value) = definedExternally
|
||||
var size: Number?
|
||||
get() = definedExternally
|
||||
set(value) = definedExternally
|
||||
var height: Number?
|
||||
get() = definedExternally
|
||||
set(value) = definedExternally
|
||||
var curveSegments: Number?
|
||||
get() = definedExternally
|
||||
set(value) = definedExternally
|
||||
var bevelEnabled: Boolean?
|
||||
get() = definedExternally
|
||||
set(value) = definedExternally
|
||||
var bevelThickness: Number?
|
||||
get() = definedExternally
|
||||
set(value) = definedExternally
|
||||
var bevelSize: Number?
|
||||
get() = definedExternally
|
||||
set(value) = definedExternally
|
||||
var bevelOffset: Number?
|
||||
get() = definedExternally
|
||||
set(value) = definedExternally
|
||||
var bevelSegments: Number?
|
||||
get() = definedExternally
|
||||
set(value) = definedExternally
|
||||
}
|
||||
|
||||
external class TextBufferGeometry(text: String, parameters: TextGeometryParameters? = definedExternally) : ExtrudeBufferGeometry {
|
||||
val parameters: TextGeometryParameters
|
||||
}
|
||||
|
||||
external class TextGeometry(text: String, parameters: TextGeometryParameters? = definedExternally) : ExtrudeGeometry {
|
||||
val parameters: TextGeometryParameters
|
||||
}
|
@ -2,12 +2,15 @@ package hep.dataforge.vis.spatial.gdml.demo
|
||||
|
||||
import hep.dataforge.context.Global
|
||||
import hep.dataforge.js.Application
|
||||
import hep.dataforge.vis.js.editor.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.propertyEditor
|
||||
import hep.dataforge.names.Name
|
||||
import hep.dataforge.names.isEmpty
|
||||
import hep.dataforge.vis.common.VisualGroup
|
||||
import hep.dataforge.vis.common.VisualObject
|
||||
import hep.dataforge.vis.js.editor.displayObjectTree
|
||||
import hep.dataforge.vis.js.editor.displayPropertyEditor
|
||||
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_WIREFRAME_KEY
|
||||
@ -19,8 +22,8 @@ import hep.dataforge.vis.spatial.gdml.GDMLTransformer
|
||||
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.displayCanvasControls
|
||||
import hep.dataforge.vis.spatial.three.output
|
||||
import hep.dataforge.vis.spatial.three.threeSettings
|
||||
import hep.dataforge.vis.spatial.visible
|
||||
import kotlinx.html.dom.append
|
||||
import kotlinx.html.js.p
|
||||
@ -154,13 +157,18 @@ private class GDMLDemoApp : Application {
|
||||
message("Rendering")
|
||||
|
||||
//output.camera.layers.enable(1)
|
||||
val output = three.output(canvasElement as HTMLElement)
|
||||
val canvas = three.output(canvasElement as HTMLElement)
|
||||
|
||||
output.camera.layers.set(0)
|
||||
configElement.threeSettings(output)
|
||||
canvas.camera.layers.set(0)
|
||||
configElement.displayCanvasControls(canvas)
|
||||
//tree.visualObjectTree(visual, editor::propertyEditor)
|
||||
treeElement.objectTree(NameToken("World"), visual) {
|
||||
editorElement.propertyEditor(it) { item ->
|
||||
fun selectElement(name: Name) {
|
||||
val child: VisualObject = when {
|
||||
name.isEmpty() -> visual
|
||||
visual is VisualGroup -> visual[name] ?: return
|
||||
else -> return
|
||||
}
|
||||
editorElement.displayPropertyEditor(name, child) { item ->
|
||||
//val descriptorMeta = Material3D.descriptor
|
||||
|
||||
val properties = item.allProperties()
|
||||
@ -176,8 +184,18 @@ private class GDMLDemoApp : Application {
|
||||
}
|
||||
}
|
||||
|
||||
// canvas.clickListener = ::selectElement
|
||||
|
||||
output.render(visual)
|
||||
//tree.visualObjectTree(visual, editor::propertyEditor)
|
||||
treeElement.displayObjectTree(visual) { name ->
|
||||
selectElement(name)
|
||||
canvas.highlight(name)
|
||||
}
|
||||
canvas.render(visual)
|
||||
|
||||
|
||||
|
||||
canvas.render(visual)
|
||||
message(null)
|
||||
spinner(false)
|
||||
}
|
||||
|
@ -5,10 +5,13 @@ import hep.dataforge.js.Application
|
||||
import hep.dataforge.js.startApplication
|
||||
import hep.dataforge.meta.buildMeta
|
||||
import hep.dataforge.meta.withBottom
|
||||
import hep.dataforge.names.NameToken
|
||||
import hep.dataforge.names.Name
|
||||
import hep.dataforge.names.isEmpty
|
||||
import hep.dataforge.vis.common.VisualGroup
|
||||
import hep.dataforge.vis.common.VisualObject
|
||||
import hep.dataforge.vis.js.editor.card
|
||||
import hep.dataforge.vis.js.editor.objectTree
|
||||
import hep.dataforge.vis.js.editor.propertyEditor
|
||||
import hep.dataforge.vis.js.editor.displayObjectTree
|
||||
import hep.dataforge.vis.js.editor.displayPropertyEditor
|
||||
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_WIREFRAME_KEY
|
||||
@ -16,8 +19,8 @@ import hep.dataforge.vis.spatial.Visual3DPlugin
|
||||
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.displayCanvasControls
|
||||
import hep.dataforge.vis.spatial.three.output
|
||||
import hep.dataforge.vis.spatial.three.threeSettings
|
||||
import hep.dataforge.vis.spatial.visible
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.features.json.JsonFeature
|
||||
@ -35,7 +38,7 @@ private class GDMLDemoApp : Application {
|
||||
|
||||
private val model = Model()
|
||||
|
||||
private val connection = HttpClient{
|
||||
private val connection = HttpClient {
|
||||
install(JsonFeature) {
|
||||
serializer = KotlinxSerializer(Visual3DPlugin.json)
|
||||
}
|
||||
@ -48,22 +51,21 @@ 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 settingsElement =
|
||||
document.getElementById("settings") ?: error("Element with id 'settings' 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()
|
||||
|
||||
canvasElement.clear()
|
||||
val visual: VisualObject3D = model.root
|
||||
|
||||
//output.camera.layers.enable(1)
|
||||
val output = three.output(canvasElement as HTMLElement)
|
||||
val canvas = three.output(canvasElement as HTMLElement)
|
||||
|
||||
output.camera.layers.set(0)
|
||||
output.camera.position.z = -2000.0
|
||||
output.camera.position.y = 500.0
|
||||
settingsElement.threeSettings(output){
|
||||
canvas.camera.layers.set(0)
|
||||
canvas.camera.position.z = -2000.0
|
||||
canvas.camera.position.y = 500.0
|
||||
settingsElement.displayCanvasControls(canvas) {
|
||||
card("Events") {
|
||||
button {
|
||||
+"Next"
|
||||
@ -82,9 +84,15 @@ private class GDMLDemoApp : Application {
|
||||
}
|
||||
}
|
||||
}
|
||||
//tree.visualObjectTree(visual, editor::propertyEditor)
|
||||
treeElement.objectTree(NameToken("World"), visual) {
|
||||
editorElement.propertyEditor(it) { item ->
|
||||
|
||||
|
||||
fun selectElement(name: Name) {
|
||||
val child: VisualObject = when {
|
||||
name.isEmpty() -> visual
|
||||
visual is VisualGroup -> visual[name] ?: return
|
||||
else -> return
|
||||
}
|
||||
editorElement.displayPropertyEditor(name, child) { item ->
|
||||
//val descriptorMeta = Material3D.descriptor
|
||||
|
||||
val properties = item.allProperties()
|
||||
@ -100,9 +108,14 @@ private class GDMLDemoApp : Application {
|
||||
}
|
||||
}
|
||||
|
||||
// canvas.clickListener = ::selectElement
|
||||
|
||||
output.render(visual)
|
||||
|
||||
//tree.visualObjectTree(visual, editor::propertyEditor)
|
||||
treeElement.displayObjectTree(visual) { name ->
|
||||
selectElement(name)
|
||||
canvas.highlight(name)
|
||||
}
|
||||
canvas.render(visual)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,13 +19,15 @@
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-lg-3">
|
||||
<div class="row" id ="settings"></div>
|
||||
<div class="row" id ="tree"></div>
|
||||
<div class="row" id="tree"></div>
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<div class="container" id = "canvas"></div>
|
||||
<div id="canvas"></div>
|
||||
</div>
|
||||
<div class="col-lg-3">
|
||||
<div class="row" id="settings"></div>
|
||||
<div class="row" id="editor"></div>
|
||||
</div>
|
||||
<div class="col-lg-3" id="editor"></div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
@ -12,10 +12,10 @@ import hep.dataforge.vis.spatial.*
|
||||
import hep.dataforge.vis.spatial.VisualObject3D.Companion.GEOMETRY_KEY
|
||||
import hep.dataforge.vis.spatial.demo.VariableBoxThreeFactory.Z_SIZE_KEY
|
||||
import hep.dataforge.vis.spatial.three.*
|
||||
import hep.dataforge.vis.spatial.three.ThreeMaterials.getMaterial
|
||||
import info.laht.threekt.core.BufferGeometry
|
||||
import info.laht.threekt.core.Object3D
|
||||
import info.laht.threekt.geometries.BoxBufferGeometry
|
||||
import info.laht.threekt.materials.MeshBasicMaterial
|
||||
import info.laht.threekt.objects.Mesh
|
||||
import kotlinx.serialization.UseSerializers
|
||||
import kotlin.math.max
|
||||
@ -69,16 +69,13 @@ private object VariableBoxThreeFactory : ThreeFactory<VisualObject3D> {
|
||||
//JS sometimes tries to pass Geometry as BufferGeometry
|
||||
@Suppress("USELESS_IS_CHECK") if (geometry !is BufferGeometry) error("BufferGeometry expected")
|
||||
|
||||
val mesh = Mesh(geometry, MeshBasicMaterial()).apply {
|
||||
val mesh = Mesh(geometry, getMaterial(obj)).apply {
|
||||
applyEdges(obj)
|
||||
applyWireFrame(obj)
|
||||
|
||||
//set position for mesh
|
||||
updatePosition(obj)
|
||||
|
||||
//set color for mesh
|
||||
updateMaterial(obj)
|
||||
|
||||
layers.enable(obj.layer)
|
||||
children.forEach {
|
||||
it.layers.enable(obj.layer)
|
||||
|
Loading…
Reference in New Issue
Block a user