Clipping implemented
This commit is contained in:
parent
8652b03fa5
commit
bdbff04d78
@ -8,6 +8,7 @@
|
||||
- SphereLayer solid
|
||||
- Hexagon interface and GenericHexagon implementation (Box inherits Hexagon)
|
||||
- Increased the default detail level for spheres and cones to 32
|
||||
- Simple clipping for Solids in ThreeJs
|
||||
|
||||
### Changed
|
||||
- Vision does not implement ItemProvider anymore. Property changes are done via `getProperty`/`setProperty` and `property` delegate.
|
||||
|
@ -0,0 +1,43 @@
|
||||
package space.kscience.visionforge.react
|
||||
|
||||
import kotlinx.html.InputType
|
||||
import kotlinx.html.js.onChangeFunction
|
||||
import org.w3c.dom.HTMLInputElement
|
||||
import org.w3c.dom.events.Event
|
||||
import react.FunctionalComponent
|
||||
import react.functionalComponent
|
||||
import react.useState
|
||||
import space.kscience.dataforge.meta.get
|
||||
import space.kscience.dataforge.meta.string
|
||||
import space.kscience.dataforge.values.asValue
|
||||
import styled.styledInput
|
||||
|
||||
@JsExport
|
||||
public val RangeValueChooser: FunctionalComponent<ValueChooserProps> =
|
||||
functionalComponent("RangeValueChooser") { props ->
|
||||
var innerValue by useState(props.item.string)
|
||||
|
||||
val handleChange: (Event) -> Unit = {
|
||||
val newValue = (it.target as HTMLInputElement).value
|
||||
props.valueChanged?.invoke(newValue.toDoubleOrNull()?.asValue())
|
||||
innerValue = newValue
|
||||
}
|
||||
|
||||
styledInput(type = InputType.range) {
|
||||
attrs {
|
||||
value = innerValue ?: ""
|
||||
onChangeFunction = handleChange
|
||||
val minValue = props.descriptor?.attributes?.get("min").string
|
||||
minValue?.let {
|
||||
min = it
|
||||
}
|
||||
val maxValue = props.descriptor?.attributes?.get("max").string
|
||||
maxValue?.let {
|
||||
max = it
|
||||
}
|
||||
props.descriptor?.attributes?.get("step").string?.let {
|
||||
step = it
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -153,6 +153,7 @@ public val ValueChooser: FunctionalComponent<ValueChooserProps> = functionalComp
|
||||
rawInput -> child(StringValueChooser, props)
|
||||
descriptor?.widgetType == "color" -> child(ColorValueChooser, props)
|
||||
descriptor?.widgetType == "multiSelect" -> child(MultiSelectChooser, props)
|
||||
descriptor?.widgetType == "range" -> child(RangeValueChooser, props)
|
||||
type == ValueType.BOOLEAN -> child(BooleanValueChooser, props)
|
||||
type == ValueType.NUMBER -> child(NumberValueChooser, props)
|
||||
descriptor?.allowedValues?.isNotEmpty() ?: false -> child(ComboValueChooser, props)
|
||||
|
@ -23,6 +23,11 @@ public inline fun <S : Scheme, reified T> NodeDescriptorBuilder.value(
|
||||
type(ValueType.NUMBER)
|
||||
block()
|
||||
}
|
||||
typeOf<Number?>(), typeOf<Int?>(), typeOf<Double?>(), typeOf<Short?>(), typeOf<Long?>(), typeOf<Float?>() ->
|
||||
value(property.name) {
|
||||
type(ValueType.NUMBER)
|
||||
block()
|
||||
}
|
||||
typeOf<Boolean>() -> value(property.name) {
|
||||
type(ValueType.BOOLEAN)
|
||||
block()
|
||||
|
@ -17,16 +17,7 @@ public class Composite(
|
||||
public val compositeType: CompositeType,
|
||||
public val first: Solid,
|
||||
public val second: Solid,
|
||||
) : SolidBase(), Solid {
|
||||
//
|
||||
// init {
|
||||
// first.parent = this
|
||||
// second.parent = this
|
||||
// }
|
||||
//
|
||||
// override val children: Map<NameToken, Vision>
|
||||
// get() = mapOf(NameToken("first") to first, NameToken("second") to second)
|
||||
}
|
||||
) : SolidBase(), Solid
|
||||
|
||||
@VisionBuilder
|
||||
public inline fun VisionContainerBuilder<Solid>.composite(
|
||||
|
@ -2,6 +2,7 @@ package space.kscience.visionforge.solid.specifications
|
||||
|
||||
import space.kscience.dataforge.meta.*
|
||||
import space.kscience.dataforge.meta.descriptors.NodeDescriptor
|
||||
import space.kscience.dataforge.meta.descriptors.attributes
|
||||
import space.kscience.dataforge.names.Name
|
||||
import space.kscience.dataforge.values.ValueType
|
||||
import space.kscience.visionforge.hide
|
||||
@ -9,15 +10,41 @@ import space.kscience.visionforge.scheme
|
||||
import space.kscience.visionforge.value
|
||||
import space.kscience.visionforge.widgetType
|
||||
|
||||
public class ClippingPlane: Scheme(){
|
||||
public var x: Double by double(0.0)
|
||||
public var y: Double by double(0.0)
|
||||
public var z: Double by double(0.0)
|
||||
public class Clipping : Scheme() {
|
||||
public var x: Double? by double()
|
||||
public var y: Double? by double()
|
||||
public var z: Double? by double()
|
||||
|
||||
public companion object: SchemeSpec<ClippingPlane>(::ClippingPlane)
|
||||
public companion object : SchemeSpec<Clipping>(::Clipping) {
|
||||
override val descriptor: NodeDescriptor = NodeDescriptor {
|
||||
value(Clipping::x) {
|
||||
widgetType = "range"
|
||||
attributes {
|
||||
set("min", 0.0)
|
||||
set("max", 1.0)
|
||||
set("step", 0.01)
|
||||
}
|
||||
}
|
||||
value(Clipping::y) {
|
||||
widgetType = "range"
|
||||
attributes {
|
||||
set("min", 0.0)
|
||||
set("max", 1.0)
|
||||
set("step", 0.01)
|
||||
}
|
||||
}
|
||||
value(Clipping::z) {
|
||||
widgetType = "range"
|
||||
attributes {
|
||||
set("min", 0.0)
|
||||
set("max", 1.0)
|
||||
set("step", 0.01)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class Canvas3DOptions : Scheme() {
|
||||
public var axes: Axes by spec(Axes)
|
||||
public var light: Light by spec(Light)
|
||||
@ -34,7 +61,7 @@ public class Canvas3DOptions : Scheme() {
|
||||
|
||||
public var layers: List<Number> by numberList(0)
|
||||
|
||||
//public var clippingPlanes: List<ClippingPlane> by list
|
||||
public var clipping: Clipping by spec(Clipping)
|
||||
|
||||
public var onSelect: ((Name?) -> Unit)? = null
|
||||
|
||||
@ -75,6 +102,7 @@ public class Canvas3DOptions : Scheme() {
|
||||
widgetType = "multiSelect"
|
||||
allow(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
|
||||
}
|
||||
scheme(Canvas3DOptions::clipping, Clipping)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,15 @@
|
||||
@file:JsModule("three")
|
||||
@file:JsNonModule
|
||||
package info.laht.threekt.helpers
|
||||
|
||||
import info.laht.threekt.math.Color
|
||||
import info.laht.threekt.math.Plane
|
||||
import info.laht.threekt.objects.LineSegments
|
||||
|
||||
/**
|
||||
* Helper object to visualize a [Plane].
|
||||
*/
|
||||
external class PlaneHelper(plane : Plane, size : Float, hex : Color): LineSegments{
|
||||
var plane: Plane
|
||||
var size: Float
|
||||
}
|
@ -27,9 +27,7 @@
|
||||
|
||||
package info.laht.threekt.math
|
||||
|
||||
external class Plane {
|
||||
|
||||
constructor()
|
||||
external class Plane() {
|
||||
constructor(normal: Vector3, constant: Double)
|
||||
|
||||
var normal: Vector3
|
||||
|
@ -12,7 +12,9 @@ import info.laht.threekt.helpers.AxesHelper
|
||||
import info.laht.threekt.lights.AmbientLight
|
||||
import info.laht.threekt.materials.LineBasicMaterial
|
||||
import info.laht.threekt.math.Box3
|
||||
import info.laht.threekt.math.Plane
|
||||
import info.laht.threekt.math.Vector2
|
||||
import info.laht.threekt.math.Vector3
|
||||
import info.laht.threekt.objects.LineSegments
|
||||
import info.laht.threekt.objects.Mesh
|
||||
import info.laht.threekt.scenes.Scene
|
||||
@ -25,10 +27,7 @@ import space.kscience.dataforge.context.logger
|
||||
import space.kscience.dataforge.meta.get
|
||||
import space.kscience.dataforge.meta.string
|
||||
import space.kscience.dataforge.meta.useProperty
|
||||
import space.kscience.dataforge.names.Name
|
||||
import space.kscience.dataforge.names.asName
|
||||
import space.kscience.dataforge.names.plus
|
||||
import space.kscience.dataforge.names.toName
|
||||
import space.kscience.dataforge.names.*
|
||||
import space.kscience.visionforge.Colors
|
||||
import space.kscience.visionforge.solid.Solid
|
||||
import space.kscience.visionforge.solid.specifications.*
|
||||
@ -59,7 +58,7 @@ public class ThreeCanvas(
|
||||
private set
|
||||
|
||||
private val scene: Scene = Scene().apply {
|
||||
options.useProperty(Canvas3DOptions::axes) { axesConfig ->
|
||||
options.useProperty(Canvas3DOptions::axes, this) { axesConfig ->
|
||||
getObjectByName(AXES_NAME)?.let { remove(it) }
|
||||
val axesObject = AxesHelper(axes.size.toInt()).apply { visible = axes.visible }
|
||||
axesObject.name = AXES_NAME
|
||||
@ -67,7 +66,7 @@ public class ThreeCanvas(
|
||||
}
|
||||
|
||||
//Set up light
|
||||
options.useProperty(Canvas3DOptions::light) { lightConfig ->
|
||||
options.useProperty(Canvas3DOptions::light, this) { lightConfig ->
|
||||
//remove old light if present
|
||||
getObjectByName(LIGHT_NAME)?.let { remove(it) }
|
||||
//add new light
|
||||
@ -87,7 +86,7 @@ public class ThreeCanvas(
|
||||
translateX(spec.distance * sin(spec.zenith) * sin(spec.azimuth))
|
||||
translateY(spec.distance * cos(spec.zenith))
|
||||
translateZ(spec.distance * sin(spec.zenith) * cos(spec.azimuth))
|
||||
options.useProperty(Canvas3DOptions::layers) { selectedLayers ->
|
||||
options.useProperty(Canvas3DOptions::layers, this) { selectedLayers ->
|
||||
(0..31).forEach {
|
||||
if (it in selectedLayers) {
|
||||
this@apply.layers.enable(it)
|
||||
@ -98,7 +97,6 @@ public class ThreeCanvas(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public val camera: PerspectiveCamera = buildCamera(options.camera)
|
||||
|
||||
private var picked: Object3D? = null
|
||||
@ -107,6 +105,30 @@ public class ThreeCanvas(
|
||||
antialias = true
|
||||
}.apply {
|
||||
setClearColor(Colors.skyblue, 1)
|
||||
//Clipping planes
|
||||
localClippingEnabled = true
|
||||
options.onChange(this@ThreeCanvas) { name, _, _ ->
|
||||
if (name.startsWith(Canvas3DOptions::clipping.name.asName())) {
|
||||
val clipping = options.clipping
|
||||
boundingBox?.let { boundingBox ->
|
||||
val xClippingPlane = clipping.x?.let {
|
||||
val absoluteValue = boundingBox.min.x + (boundingBox.max.x - boundingBox.min.x) * it
|
||||
Plane(Vector3(-1.0, 0.0, 0.0), absoluteValue)
|
||||
|
||||
}
|
||||
val yClippingPlane = clipping.y?.let {
|
||||
val absoluteValue = boundingBox.min.y + (boundingBox.max.y - boundingBox.min.y) * it
|
||||
Plane(Vector3(0.0, -1.0, 0.0), absoluteValue)
|
||||
}
|
||||
|
||||
val zClippingPlane = clipping.z?.let {
|
||||
val absoluteValue = boundingBox.min.z + (boundingBox.max.z - boundingBox.min.z) * it
|
||||
Plane(Vector3(0.0, 0.0, -1.0), absoluteValue)
|
||||
}
|
||||
clippingPlanes = listOfNotNull(xClippingPlane, yClippingPlane, zClippingPlane).toTypedArray()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val canvas = (renderer.domElement as HTMLCanvasElement).apply {
|
||||
@ -291,5 +313,6 @@ public class ThreeCanvas(
|
||||
private const val SELECT_NAME = "@select"
|
||||
private const val LIGHT_NAME = "@light"
|
||||
private const val AXES_NAME = "@axes"
|
||||
private const val CLIP_HELPER_NAME = "@clipping"
|
||||
}
|
||||
}
|
@ -26,7 +26,7 @@ public object ThreeCanvasLabelFactory : ThreeFactory<SolidLabel> {
|
||||
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.fillStyle = obj.color.value ?: "black"
|
||||
context.textBaseline = CanvasTextBaseline.MIDDLE
|
||||
val metrics = context.measureText(obj.text)
|
||||
//canvas.width = metrics.width.toInt()
|
||||
|
Loading…
Reference in New Issue
Block a user