forked from kscience/visionforge
Clipping implemented
This commit is contained in:
parent
8652b03fa5
commit
bdbff04d78
@ -8,6 +8,7 @@
|
|||||||
- SphereLayer solid
|
- SphereLayer solid
|
||||||
- Hexagon interface and GenericHexagon implementation (Box inherits Hexagon)
|
- Hexagon interface and GenericHexagon implementation (Box inherits Hexagon)
|
||||||
- Increased the default detail level for spheres and cones to 32
|
- Increased the default detail level for spheres and cones to 32
|
||||||
|
- Simple clipping for Solids in ThreeJs
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- Vision does not implement ItemProvider anymore. Property changes are done via `getProperty`/`setProperty` and `property` delegate.
|
- 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)
|
rawInput -> child(StringValueChooser, props)
|
||||||
descriptor?.widgetType == "color" -> child(ColorValueChooser, props)
|
descriptor?.widgetType == "color" -> child(ColorValueChooser, props)
|
||||||
descriptor?.widgetType == "multiSelect" -> child(MultiSelectChooser, props)
|
descriptor?.widgetType == "multiSelect" -> child(MultiSelectChooser, props)
|
||||||
|
descriptor?.widgetType == "range" -> child(RangeValueChooser, props)
|
||||||
type == ValueType.BOOLEAN -> child(BooleanValueChooser, props)
|
type == ValueType.BOOLEAN -> child(BooleanValueChooser, props)
|
||||||
type == ValueType.NUMBER -> child(NumberValueChooser, props)
|
type == ValueType.NUMBER -> child(NumberValueChooser, props)
|
||||||
descriptor?.allowedValues?.isNotEmpty() ?: false -> child(ComboValueChooser, props)
|
descriptor?.allowedValues?.isNotEmpty() ?: false -> child(ComboValueChooser, props)
|
||||||
|
@ -23,6 +23,11 @@ public inline fun <S : Scheme, reified T> NodeDescriptorBuilder.value(
|
|||||||
type(ValueType.NUMBER)
|
type(ValueType.NUMBER)
|
||||||
block()
|
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) {
|
typeOf<Boolean>() -> value(property.name) {
|
||||||
type(ValueType.BOOLEAN)
|
type(ValueType.BOOLEAN)
|
||||||
block()
|
block()
|
||||||
|
@ -17,16 +17,7 @@ public class Composite(
|
|||||||
public val compositeType: CompositeType,
|
public val compositeType: CompositeType,
|
||||||
public val first: Solid,
|
public val first: Solid,
|
||||||
public val second: Solid,
|
public val second: Solid,
|
||||||
) : SolidBase(), 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)
|
|
||||||
}
|
|
||||||
|
|
||||||
@VisionBuilder
|
@VisionBuilder
|
||||||
public inline fun VisionContainerBuilder<Solid>.composite(
|
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.*
|
||||||
import space.kscience.dataforge.meta.descriptors.NodeDescriptor
|
import space.kscience.dataforge.meta.descriptors.NodeDescriptor
|
||||||
|
import space.kscience.dataforge.meta.descriptors.attributes
|
||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.dataforge.values.ValueType
|
import space.kscience.dataforge.values.ValueType
|
||||||
import space.kscience.visionforge.hide
|
import space.kscience.visionforge.hide
|
||||||
@ -9,14 +10,40 @@ import space.kscience.visionforge.scheme
|
|||||||
import space.kscience.visionforge.value
|
import space.kscience.visionforge.value
|
||||||
import space.kscience.visionforge.widgetType
|
import space.kscience.visionforge.widgetType
|
||||||
|
|
||||||
public class ClippingPlane: Scheme(){
|
public class Clipping : Scheme() {
|
||||||
public var x: Double by double(0.0)
|
public var x: Double? by double()
|
||||||
public var y: Double by double(0.0)
|
public var y: Double? by double()
|
||||||
public var z: Double by double(0.0)
|
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 class Canvas3DOptions : Scheme() {
|
||||||
public var axes: Axes by spec(Axes)
|
public var axes: Axes by spec(Axes)
|
||||||
@ -34,7 +61,7 @@ public class Canvas3DOptions : Scheme() {
|
|||||||
|
|
||||||
public var layers: List<Number> by numberList(0)
|
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
|
public var onSelect: ((Name?) -> Unit)? = null
|
||||||
|
|
||||||
@ -75,6 +102,7 @@ public class Canvas3DOptions : Scheme() {
|
|||||||
widgetType = "multiSelect"
|
widgetType = "multiSelect"
|
||||||
allow(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
|
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
|
package info.laht.threekt.math
|
||||||
|
|
||||||
external class Plane {
|
external class Plane() {
|
||||||
|
|
||||||
constructor()
|
|
||||||
constructor(normal: Vector3, constant: Double)
|
constructor(normal: Vector3, constant: Double)
|
||||||
|
|
||||||
var normal: Vector3
|
var normal: Vector3
|
||||||
|
@ -12,7 +12,9 @@ import info.laht.threekt.helpers.AxesHelper
|
|||||||
import info.laht.threekt.lights.AmbientLight
|
import info.laht.threekt.lights.AmbientLight
|
||||||
import info.laht.threekt.materials.LineBasicMaterial
|
import info.laht.threekt.materials.LineBasicMaterial
|
||||||
import info.laht.threekt.math.Box3
|
import info.laht.threekt.math.Box3
|
||||||
|
import info.laht.threekt.math.Plane
|
||||||
import info.laht.threekt.math.Vector2
|
import info.laht.threekt.math.Vector2
|
||||||
|
import info.laht.threekt.math.Vector3
|
||||||
import info.laht.threekt.objects.LineSegments
|
import info.laht.threekt.objects.LineSegments
|
||||||
import info.laht.threekt.objects.Mesh
|
import info.laht.threekt.objects.Mesh
|
||||||
import info.laht.threekt.scenes.Scene
|
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.get
|
||||||
import space.kscience.dataforge.meta.string
|
import space.kscience.dataforge.meta.string
|
||||||
import space.kscience.dataforge.meta.useProperty
|
import space.kscience.dataforge.meta.useProperty
|
||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.*
|
||||||
import space.kscience.dataforge.names.asName
|
|
||||||
import space.kscience.dataforge.names.plus
|
|
||||||
import space.kscience.dataforge.names.toName
|
|
||||||
import space.kscience.visionforge.Colors
|
import space.kscience.visionforge.Colors
|
||||||
import space.kscience.visionforge.solid.Solid
|
import space.kscience.visionforge.solid.Solid
|
||||||
import space.kscience.visionforge.solid.specifications.*
|
import space.kscience.visionforge.solid.specifications.*
|
||||||
@ -59,7 +58,7 @@ public class ThreeCanvas(
|
|||||||
private set
|
private set
|
||||||
|
|
||||||
private val scene: Scene = Scene().apply {
|
private val scene: Scene = Scene().apply {
|
||||||
options.useProperty(Canvas3DOptions::axes) { axesConfig ->
|
options.useProperty(Canvas3DOptions::axes, this) { axesConfig ->
|
||||||
getObjectByName(AXES_NAME)?.let { remove(it) }
|
getObjectByName(AXES_NAME)?.let { remove(it) }
|
||||||
val axesObject = AxesHelper(axes.size.toInt()).apply { visible = axes.visible }
|
val axesObject = AxesHelper(axes.size.toInt()).apply { visible = axes.visible }
|
||||||
axesObject.name = AXES_NAME
|
axesObject.name = AXES_NAME
|
||||||
@ -67,7 +66,7 @@ public class ThreeCanvas(
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Set up light
|
//Set up light
|
||||||
options.useProperty(Canvas3DOptions::light) { lightConfig ->
|
options.useProperty(Canvas3DOptions::light, this) { lightConfig ->
|
||||||
//remove old light if present
|
//remove old light if present
|
||||||
getObjectByName(LIGHT_NAME)?.let { remove(it) }
|
getObjectByName(LIGHT_NAME)?.let { remove(it) }
|
||||||
//add new light
|
//add new light
|
||||||
@ -87,7 +86,7 @@ public class ThreeCanvas(
|
|||||||
translateX(spec.distance * sin(spec.zenith) * sin(spec.azimuth))
|
translateX(spec.distance * sin(spec.zenith) * sin(spec.azimuth))
|
||||||
translateY(spec.distance * cos(spec.zenith))
|
translateY(spec.distance * cos(spec.zenith))
|
||||||
translateZ(spec.distance * sin(spec.zenith) * cos(spec.azimuth))
|
translateZ(spec.distance * sin(spec.zenith) * cos(spec.azimuth))
|
||||||
options.useProperty(Canvas3DOptions::layers) { selectedLayers ->
|
options.useProperty(Canvas3DOptions::layers, this) { selectedLayers ->
|
||||||
(0..31).forEach {
|
(0..31).forEach {
|
||||||
if (it in selectedLayers) {
|
if (it in selectedLayers) {
|
||||||
this@apply.layers.enable(it)
|
this@apply.layers.enable(it)
|
||||||
@ -98,7 +97,6 @@ public class ThreeCanvas(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public val camera: PerspectiveCamera = buildCamera(options.camera)
|
public val camera: PerspectiveCamera = buildCamera(options.camera)
|
||||||
|
|
||||||
private var picked: Object3D? = null
|
private var picked: Object3D? = null
|
||||||
@ -107,6 +105,30 @@ public class ThreeCanvas(
|
|||||||
antialias = true
|
antialias = true
|
||||||
}.apply {
|
}.apply {
|
||||||
setClearColor(Colors.skyblue, 1)
|
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 {
|
private val canvas = (renderer.domElement as HTMLCanvasElement).apply {
|
||||||
@ -291,5 +313,6 @@ public class ThreeCanvas(
|
|||||||
private const val SELECT_NAME = "@select"
|
private const val SELECT_NAME = "@select"
|
||||||
private const val LIGHT_NAME = "@light"
|
private const val LIGHT_NAME = "@light"
|
||||||
private const val AXES_NAME = "@axes"
|
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 canvas = document.createElement("canvas") as HTMLCanvasElement
|
||||||
val context = canvas.getContext("2d") as CanvasRenderingContext2D
|
val context = canvas.getContext("2d") as CanvasRenderingContext2D
|
||||||
context.font = "Bold ${obj.fontSize}pt ${obj.fontFamily}"
|
context.font = "Bold ${obj.fontSize}pt ${obj.fontFamily}"
|
||||||
context.fillStyle = obj.color ?: "black"
|
context.fillStyle = obj.color.value ?: "black"
|
||||||
context.textBaseline = CanvasTextBaseline.MIDDLE
|
context.textBaseline = CanvasTextBaseline.MIDDLE
|
||||||
val metrics = context.measureText(obj.text)
|
val metrics = context.measureText(obj.text)
|
||||||
//canvas.width = metrics.width.toInt()
|
//canvas.width = metrics.width.toInt()
|
||||||
|
Loading…
Reference in New Issue
Block a user