forked from kscience/visionforge
Strict mode for Three canvas. Styles builders
This commit is contained in:
parent
216be4a6a1
commit
3c0df98f50
@ -1,6 +1,9 @@
|
|||||||
package ru.mipt.npm.sat
|
package ru.mipt.npm.sat
|
||||||
|
|
||||||
|
import hep.dataforge.meta.set
|
||||||
import hep.dataforge.vision.solid.*
|
import hep.dataforge.vision.solid.*
|
||||||
|
import hep.dataforge.vision.style
|
||||||
|
import hep.dataforge.vision.useStyle
|
||||||
import kotlin.math.PI
|
import kotlin.math.PI
|
||||||
|
|
||||||
internal fun visionOfSatellite(
|
internal fun visionOfSatellite(
|
||||||
@ -12,7 +15,18 @@ internal fun visionOfSatellite(
|
|||||||
ySegmentSize: Number = xSegmentSize,
|
ySegmentSize: Number = xSegmentSize,
|
||||||
fiberDiameter: Number = 1.0,
|
fiberDiameter: Number = 1.0,
|
||||||
): SolidGroup = SolidGroup {
|
): SolidGroup = SolidGroup {
|
||||||
opacity = 0.3
|
val transparent by style {
|
||||||
|
this[SolidMaterial.MATERIAL_OPACITY_KEY] = 0.3
|
||||||
|
}
|
||||||
|
|
||||||
|
val red by style {
|
||||||
|
this[SolidMaterial.MATERIAL_COLOR_KEY] = "red"
|
||||||
|
}
|
||||||
|
|
||||||
|
val blue by style {
|
||||||
|
this[SolidMaterial.MATERIAL_COLOR_KEY] = "blue"
|
||||||
|
}
|
||||||
|
|
||||||
val totalXSize = xSegments * xSegmentSize.toDouble()
|
val totalXSize = xSegments * xSegmentSize.toDouble()
|
||||||
val totalYSize = ySegments * ySegmentSize.toDouble()
|
val totalYSize = ySegments * ySegmentSize.toDouble()
|
||||||
for (layer in 1..layers) {
|
for (layer in 1..layers) {
|
||||||
@ -20,6 +34,7 @@ internal fun visionOfSatellite(
|
|||||||
for (i in 1..xSegments) {
|
for (i in 1..xSegments) {
|
||||||
for (j in 1..ySegments) {
|
for (j in 1..ySegments) {
|
||||||
box(xSegmentSize, ySegmentSize, layerHeight, name = "segment[$i,$j]") {
|
box(xSegmentSize, ySegmentSize, layerHeight, name = "segment[$i,$j]") {
|
||||||
|
useStyle(transparent)
|
||||||
z = (layer - 0.5) * layerHeight.toDouble()
|
z = (layer - 0.5) * layerHeight.toDouble()
|
||||||
x = (i - 0.5) * xSegmentSize.toDouble()
|
x = (i - 0.5) * xSegmentSize.toDouble()
|
||||||
y = (j - 0.5) * ySegmentSize.toDouble()
|
y = (j - 0.5) * ySegmentSize.toDouble()
|
||||||
@ -29,23 +44,21 @@ internal fun visionOfSatellite(
|
|||||||
group("fibers") {
|
group("fibers") {
|
||||||
for (i in 1..xSegments) {
|
for (i in 1..xSegments) {
|
||||||
cylinder(fiberDiameter, totalYSize) {
|
cylinder(fiberDiameter, totalYSize) {
|
||||||
|
useStyle(red)
|
||||||
rotationX = PI / 2
|
rotationX = PI / 2
|
||||||
z = (layer - 1.0) * layerHeight.toDouble() + fiberDiameter.toDouble()
|
z = (layer - 1.0) * layerHeight.toDouble() + fiberDiameter.toDouble()
|
||||||
x = (i - 0.5) * xSegmentSize.toDouble()
|
x = (i - 0.5) * xSegmentSize.toDouble()
|
||||||
y = totalYSize/2
|
y = totalYSize / 2
|
||||||
|
|
||||||
color("red")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (j in 1..ySegments) {
|
for (j in 1..ySegments) {
|
||||||
cylinder(fiberDiameter, totalXSize) {
|
cylinder(fiberDiameter, totalXSize) {
|
||||||
|
useStyle(blue)
|
||||||
rotationY = PI / 2
|
rotationY = PI / 2
|
||||||
z = (layer) * layerHeight.toDouble() - fiberDiameter.toDouble()
|
z = (layer) * layerHeight.toDouble() - fiberDiameter.toDouble()
|
||||||
y = (j - 0.5) * xSegmentSize.toDouble()
|
y = (j - 0.5) * xSegmentSize.toDouble()
|
||||||
x = totalXSize/2
|
x = totalXSize / 2
|
||||||
|
|
||||||
color("blue")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,9 +42,9 @@ fun main() {
|
|||||||
val target = "layer[$randomLayer].segment[$randomI,$randomJ]".toName()
|
val target = "layer[$randomLayer].segment[$randomI,$randomJ]".toName()
|
||||||
val targetVision = sat[target] as Solid
|
val targetVision = sat[target] as Solid
|
||||||
targetVision.color("red")
|
targetVision.color("red")
|
||||||
delay(300)
|
delay(1000)
|
||||||
targetVision.color.clear()
|
targetVision.color.clear()
|
||||||
delay(10)
|
delay(500)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,8 +37,7 @@ public val ThreeCanvasComponent: FunctionalComponent<ThreeCanvasProps> = functio
|
|||||||
if (canvas == null) {
|
if (canvas == null) {
|
||||||
val element = elementRef.current as? HTMLElement ?: error("Canvas element not found")
|
val element = elementRef.current as? HTMLElement ?: error("Canvas element not found")
|
||||||
val three: ThreePlugin = props.context.plugins.fetch(ThreePlugin)
|
val three: ThreePlugin = props.context.plugins.fetch(ThreePlugin)
|
||||||
val newCanvas: ThreeCanvas =
|
val newCanvas: ThreeCanvas = three.createCanvas(element, props.options ?: Canvas3DOptions.empty())
|
||||||
three.createCanvas(element, props.options ?: Canvas3DOptions.empty())
|
|
||||||
props.canvasCallback?.invoke(newCanvas)
|
props.canvasCallback?.invoke(newCanvas)
|
||||||
canvas = newCanvas
|
canvas = newCanvas
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,33 @@
|
|||||||
|
package hep.dataforge.vision
|
||||||
|
|
||||||
|
import hep.dataforge.meta.DFExperimental
|
||||||
|
import hep.dataforge.meta.Meta
|
||||||
|
import hep.dataforge.meta.MetaBuilder
|
||||||
|
import kotlin.properties.ReadOnlyProperty
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A reference to a style defined in a specific container
|
||||||
|
*/
|
||||||
|
public class StyleReference(public val owner: VisionGroup, public val name: String)
|
||||||
|
|
||||||
|
private tailrec fun styleIsDefined(vision: Vision, reference: StyleReference): Boolean = when {
|
||||||
|
reference.owner === vision -> true
|
||||||
|
vision.parent == null -> false
|
||||||
|
else -> styleIsDefined(vision.parent!!, reference)
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisionBuilder
|
||||||
|
public fun Vision.useStyle(reference: StyleReference) {
|
||||||
|
//check that style is defined in a parent
|
||||||
|
//check(styleIsDefined(this, reference)) { "Style reference does not belong to a Vision parent" }
|
||||||
|
useStyle(reference.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
@DFExperimental
|
||||||
|
@VisionBuilder
|
||||||
|
public fun VisionGroup.style(builder: MetaBuilder.() -> Unit): ReadOnlyProperty<Any?, StyleReference> =
|
||||||
|
ReadOnlyProperty { _, property ->
|
||||||
|
val styleName = property.name
|
||||||
|
styleSheet.define(styleName, Meta(builder))
|
||||||
|
StyleReference(this, styleName)
|
||||||
|
}
|
@ -110,4 +110,6 @@ public fun Vision.getStyleItems(name: Name): Sequence<MetaItem<*>> {
|
|||||||
/**
|
/**
|
||||||
* Collect all styles for this object in a single laminate
|
* Collect all styles for this object in a single laminate
|
||||||
*/
|
*/
|
||||||
public val Vision.allStyles: Laminate get() = Laminate(styles.mapNotNull(::getStyle))
|
public val Vision.allStyles: Laminate get() = Laminate(styles.mapNotNull(::getStyle))
|
||||||
|
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ private fun Vision.isolate(manager: VisionManager): Vision {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
public class VisionChange(
|
public data class VisionChange(
|
||||||
public val reset: Boolean = false,
|
public val reset: Boolean = false,
|
||||||
public val vision: Vision? = null,
|
public val vision: Vision? = null,
|
||||||
@Serializable(MetaSerializer::class) public val properties: Meta? = null,
|
@Serializable(MetaSerializer::class) public val properties: Meta? = null,
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
package hep.dataforge.vision
|
||||||
|
|
||||||
|
import hep.dataforge.meta.MetaItem
|
||||||
|
import hep.dataforge.names.Name
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Property containers are used to create a symmetric behaviors for vision properties and style builders
|
||||||
|
*/
|
||||||
|
public interface VisionPropertyContainer<out T> {
|
||||||
|
public fun getProperty(
|
||||||
|
name: Name,
|
||||||
|
inherit: Boolean = false,
|
||||||
|
includeStyles: Boolean = true,
|
||||||
|
includeDefaults: Boolean = true,
|
||||||
|
): MetaItem<*>?
|
||||||
|
|
||||||
|
public fun setProperty(name: Name, item: MetaItem<*>?, notify: Boolean = true)
|
||||||
|
}
|
@ -138,7 +138,7 @@ public class VisionClient : AbstractPlugin() {
|
|||||||
renderVision(element, change.vision, outputMeta)
|
renderVision(element, change.vision, outputMeta)
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.debug { "Got update $change for output with name $name" }
|
logger.info { "Got update ${change.toString()} for output with name $name" }
|
||||||
visionMap[element]?.update(change)
|
visionMap[element]?.update(change)
|
||||||
?: console.info("Target vision for element $element with name $name not found")
|
?: console.info("Target vision for element $element with name $name not found")
|
||||||
} else {
|
} else {
|
||||||
|
@ -88,6 +88,7 @@ public fun VisionContainerBuilder<Vision>.group(
|
|||||||
/**
|
/**
|
||||||
* Define a group with given [name], attach it to this parent and return it.
|
* Define a group with given [name], attach it to this parent and return it.
|
||||||
*/
|
*/
|
||||||
|
@VisionBuilder
|
||||||
public fun VisionContainerBuilder<Vision>.group(name: String, action: SolidGroup.() -> Unit = {}): SolidGroup =
|
public fun VisionContainerBuilder<Vision>.group(name: String, action: SolidGroup.() -> Unit = {}): SolidGroup =
|
||||||
SolidGroup().apply(action).also { set(name, it) }
|
SolidGroup().apply(action).also { set(name, it) }
|
||||||
|
|
||||||
|
@ -130,7 +130,8 @@ public class ThreeCanvas(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun attach(element: Element) {
|
internal fun attach(element: Element) {
|
||||||
|
check(element.children.length == 0){"The element for Three canvas is not empty"}
|
||||||
element.appendChild(canvas)
|
element.appendChild(canvas)
|
||||||
updateSize()
|
updateSize()
|
||||||
}
|
}
|
||||||
@ -189,8 +190,10 @@ public class ThreeCanvas(
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override fun render(vision: Solid) {
|
public override fun render(vision: Solid) {
|
||||||
//clear old root
|
scene.children.find { it.name == "@root" }?.let {
|
||||||
clear()
|
//Throw error is something is already rendered here
|
||||||
|
error("Root object already is present in the canvas")
|
||||||
|
}
|
||||||
|
|
||||||
val object3D = three.buildObject3D(vision)
|
val object3D = three.buildObject3D(vision)
|
||||||
object3D.name = "@root"
|
object3D.name = "@root"
|
||||||
|
@ -136,9 +136,19 @@ public class ThreePlugin : AbstractPlugin(), ElementVisionRenderer {
|
|||||||
return if (vision is Solid) ElementVisionRenderer.DEFAULT_RATING else ElementVisionRenderer.ZERO_RATING
|
return if (vision is Solid) ElementVisionRenderer.DEFAULT_RATING else ElementVisionRenderer.ZERO_RATING
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public fun renderSolid(
|
||||||
|
element: Element,
|
||||||
|
vision: Solid,
|
||||||
|
options: Canvas3DOptions,
|
||||||
|
): ThreeCanvas = createCanvas(element, options).apply {
|
||||||
|
render(vision)
|
||||||
|
}
|
||||||
|
|
||||||
override fun render(element: Element, vision: Vision, meta: Meta) {
|
override fun render(element: Element, vision: Vision, meta: Meta) {
|
||||||
createCanvas(element, Canvas3DOptions.read(meta)).render(
|
renderSolid(
|
||||||
vision as? Solid ?: error("Solid expected but ${vision::class} is found")
|
element,
|
||||||
|
vision as? Solid ?: error("Solid expected but ${vision::class} is found"),
|
||||||
|
Canvas3DOptions.read(meta)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,7 +163,7 @@ public fun ThreePlugin.render(
|
|||||||
element: HTMLElement,
|
element: HTMLElement,
|
||||||
obj: Solid,
|
obj: Solid,
|
||||||
options: Canvas3DOptions.() -> Unit = {},
|
options: Canvas3DOptions.() -> Unit = {},
|
||||||
): ThreeCanvas = createCanvas(element, Canvas3DOptions(options)).apply { render(obj) }
|
): ThreeCanvas = renderSolid(element, obj, Canvas3DOptions(options))
|
||||||
|
|
||||||
internal operator fun Object3D.set(token: NameToken, object3D: Object3D) {
|
internal operator fun Object3D.set(token: NameToken, object3D: Object3D) {
|
||||||
object3D.name = token.toString()
|
object3D.name = token.toString()
|
||||||
|
Loading…
Reference in New Issue
Block a user