Make solid arguments immutable

This commit is contained in:
Alexander Nozik 2021-07-12 15:22:02 +03:00
parent 5af8fe3e99
commit 0d53b6f77d
17 changed files with 128 additions and 86 deletions

View File

@ -19,6 +19,8 @@
- VisionGroup builder accepts `null` as name for statics instead of `""` - VisionGroup builder accepts `null` as name for statics instead of `""`
- gdml sphere is rendered as a SphereLayer instead of Sphere (#35) - gdml sphere is rendered as a SphereLayer instead of Sphere (#35)
- Tube is replaced by more general ConeSurface - Tube is replaced by more general ConeSurface
- position, rotation and size moved to properties
- prototypes moved to children
### Deprecated ### Deprecated

View File

@ -27,7 +27,7 @@ fun VisionLayout<Solid>.demo(name: String, title: String = name, block: SolidGro
} }
val canvasOptions = Canvas3DOptions { val canvasOptions = Canvas3DOptions {
size{ size {
minSize = 400 minSize = 400
} }
axes { axes {
@ -57,9 +57,8 @@ fun VisionLayout<Solid>.showcase() {
rotationX = PI / 4 rotationX = PI / 4
color("blue") color("blue")
} }
sphereLayer(50,40){ sphereLayer(50, 40, theta = PI / 2) {
theta = (PI/2).toFloat() rotationX = -PI * 3 / 4
rotationX = - PI * 3 / 4
z = 110 z = 110
color(Colors.pink) color(Colors.pink)
} }

View File

@ -23,7 +23,7 @@ internal fun SolidGroup.varBox(
action: VariableBox.() -> Unit = {}, action: VariableBox.() -> Unit = {},
): VariableBox = VariableBox(xSize, ySize).apply(action).also { set(name, it) } ): VariableBox = VariableBox(xSize, ySize).apply(action).also { set(name, it) }
internal class VariableBox(val xSize: Number, val ySize: Number) : ThreeVision() { internal class VariableBox(val xSize: Number, val ySize: Number) : ThreeJsVision() {
override fun render(three: ThreePlugin): Object3D { override fun render(three: ThreePlugin): Object3D {
val geometry = BoxGeometry(xSize, ySize, 1) val geometry = BoxGeometry(xSize, ySize, 1)

View File

@ -1,12 +1,15 @@
package space.kscience.visionforge package space.kscience.visionforge
import space.kscience.dataforge.meta.Config
import space.kscience.dataforge.meta.MetaItem import space.kscience.dataforge.meta.MetaItem
import space.kscience.dataforge.meta.get
import space.kscience.dataforge.meta.set
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
/** /**
* Property containers are used to create a symmetric behaviors for vision properties and style builders * Property containers are used to create a symmetric behaviors for vision properties and style builders
*/ */
public interface VisionPropertyContainer<out T> { public interface VisionPropertyContainer<out V: Vision> {
public fun getProperty( public fun getProperty(
name: Name, name: Name,
inherit: Boolean = false, inherit: Boolean = false,
@ -15,4 +18,18 @@ public interface VisionPropertyContainer<out T> {
): MetaItem? ): MetaItem?
public fun setProperty(name: Name, item: MetaItem?, notify: Boolean = true) public fun setProperty(name: Name, item: MetaItem?, notify: Boolean = true)
}
public open class SimpleVisionPropertyContainer<out V: Vision>(protected val config: Config): VisionPropertyContainer<V>{
override fun getProperty(
name: Name,
inherit: Boolean,
includeStyles: Boolean,
includeDefaults: Boolean
): MetaItem? = config[name]
override fun setProperty(name: Name, item: MetaItem?, notify: Boolean) {
config[name] = item
}
} }

View File

@ -232,11 +232,10 @@ private class GdmlTransformerEnv(val settings: GdmlTransformer) {
bottomRadius = solid.rmax1 * lScale, bottomRadius = solid.rmax1 * lScale,
height = solid.z * lScale, height = solid.z * lScale,
upperRadius = solid.rmax2 * lScale, upperRadius = solid.rmax2 * lScale,
startAngle = solid.startphi * aScale,
angle = solid.deltaphi * aScale,
name = name name = name
) { )
startAngle = solid.startphi * aScale
angle = solid.deltaphi * aScale
}
} else { } else {
coneSurface( coneSurface(
bottomOuterRadius = solid.rmax1 * lScale, bottomOuterRadius = solid.rmax1 * lScale,
@ -244,11 +243,10 @@ private class GdmlTransformerEnv(val settings: GdmlTransformer) {
height = solid.z * lScale, height = solid.z * lScale,
topOuterRadius = solid.rmax2 * lScale, topOuterRadius = solid.rmax2 * lScale,
topInnerRadius = solid.rmin2 * lScale, topInnerRadius = solid.rmin2 * lScale,
startAngle = solid.startphi * aScale,
angle = solid.deltaphi * aScale,
name = name name = name
) { )
startAngle = solid.startphi * aScale
angle = solid.deltaphi * aScale
}
} }
is GdmlXtru -> extrude(name) { is GdmlXtru -> extrude(name) {
shape { shape {
@ -276,12 +274,15 @@ private class GdmlTransformerEnv(val settings: GdmlTransformer) {
scaleZ = solid.scale.z.toFloat() scaleZ = solid.scale.z.toFloat()
} }
} }
is GdmlSphere -> sphereLayer(solid.rmax * lScale, solid.rmin * lScale, name) { is GdmlSphere -> sphereLayer(
phi = solid.deltaphi * aScale outerRadius = solid.rmax * lScale,
theta = solid.deltatheta * aScale innerRadius = solid.rmin * lScale,
phiStart = solid.startphi * aScale phi = solid.deltaphi * aScale,
thetaStart = solid.starttheta * aScale theta = solid.deltatheta * aScale,
} phiStart = solid.startphi * aScale,
thetaStart = solid.starttheta * aScale,
name = name,
)
is GdmlOrb -> sphere(solid.r * lScale, name = name) is GdmlOrb -> sphere(solid.r * lScale, name = name)
is GdmlPolyhedra -> extrude(name) { is GdmlPolyhedra -> extrude(name) {
//getting the radius of first //getting the radius of first

View File

@ -15,11 +15,11 @@ import kotlin.math.sin
@Serializable @Serializable
@SerialName("solid.cone") @SerialName("solid.cone")
public class ConeSegment( public class ConeSegment(
public var bottomRadius: Float, public val bottomRadius: Float,
public var height: Float, public val height: Float,
public var topRadius: Float, public val topRadius: Float,
public var startAngle: Float = 0f, public val startAngle: Float = 0f,
public var angle: Float = PI2 public val angle: Float = PI2
) : SolidBase(), GeometrySolid { ) : SolidBase(), GeometrySolid {
override fun <T : Any> toGeometry(geometryBuilder: GeometryBuilder<T>) { override fun <T : Any> toGeometry(geometryBuilder: GeometryBuilder<T>) {
@ -83,10 +83,14 @@ public inline fun VisionContainerBuilder<Solid>.cone(
bottomRadius: Number, bottomRadius: Number,
height: Number, height: Number,
upperRadius: Number = 0.0, upperRadius: Number = 0.0,
startAngle: Number = 0f,
angle: Number = PI2,
name: String? = null, name: String? = null,
block: ConeSegment.() -> Unit = {} block: ConeSegment.() -> Unit = {}
): ConeSegment = ConeSegment( ): ConeSegment = ConeSegment(
bottomRadius.toFloat(), bottomRadius.toFloat(),
height.toFloat(), height.toFloat(),
topRadius = upperRadius.toFloat() topRadius = upperRadius.toFloat(),
startAngle = startAngle.toFloat(),
angle = angle.toFloat()
).apply(block).also { set(name, it) } ).apply(block).also { set(name, it) }

View File

@ -16,13 +16,13 @@ import kotlin.math.sin
@Serializable @Serializable
@SerialName("solid.coneSurface") @SerialName("solid.coneSurface")
public class ConeSurface( public class ConeSurface(
public var bottomRadius: Float, public val bottomRadius: Float,
public var bottomInnerRadius: Float, public val bottomInnerRadius: Float,
public var height: Float, public val height: Float,
public var topRadius: Float, public val topRadius: Float,
public var topInnerRadius: Float, public val topInnerRadius: Float,
public var startAngle: Float = 0f, public val startAngle: Float = 0f,
public var angle: Float = PI2, public val angle: Float = PI2,
) : SolidBase(), GeometrySolid { ) : SolidBase(), GeometrySolid {
init { init {
@ -148,6 +148,8 @@ public inline fun VisionContainerBuilder<Solid>.coneSurface(
height: Number, height: Number,
topOuterRadius: Number, topOuterRadius: Number,
topInnerRadius: Number, topInnerRadius: Number,
startAngle: Number = 0f,
angle: Number = PI2,
name: String? = null, name: String? = null,
block: ConeSurface.() -> Unit = {}, block: ConeSurface.() -> Unit = {},
): ConeSurface = ConeSurface( ): ConeSurface = ConeSurface(
@ -156,4 +158,6 @@ public inline fun VisionContainerBuilder<Solid>.coneSurface(
height = height.toFloat(), height = height.toFloat(),
topRadius = topOuterRadius.toFloat(), topRadius = topOuterRadius.toFloat(),
topInnerRadius = topInnerRadius.toFloat(), topInnerRadius = topInnerRadius.toFloat(),
startAngle = startAngle.toFloat(),
angle = angle.toFloat()
).apply(block).also { set(name, it) } ).apply(block).also { set(name, it) }

View File

@ -2,9 +2,8 @@ package space.kscience.visionforge.solid
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import space.kscience.visionforge.VisionBuilder import space.kscience.dataforge.meta.Config
import space.kscience.visionforge.VisionContainerBuilder import space.kscience.visionforge.*
import space.kscience.visionforge.set
import kotlin.math.PI import kotlin.math.PI
import kotlin.math.cos import kotlin.math.cos
import kotlin.math.sin import kotlin.math.sin
@ -13,7 +12,7 @@ import kotlin.math.sin
public typealias Shape2D = List<Point2D> public typealias Shape2D = List<Point2D>
@Serializable @Serializable
public class Shape2DBuilder(private val points: MutableList<Point2D> = ArrayList()) { public class Shape2DBuilder(private val points: ArrayList<Point2D> = ArrayList()) {
public fun point(x: Number, y: Number) { public fun point(x: Number, y: Number) {
points.add(Point2D(x, y)) points.add(Point2D(x, y))
@ -38,19 +37,9 @@ public data class Layer(var x: Float, var y: Float, var z: Float, var scale: Flo
@Serializable @Serializable
@SerialName("solid.extrude") @SerialName("solid.extrude")
public class Extruded( public class Extruded(
public var shape: List<Point2D> = ArrayList(), public val shape: List<Point2D>,
public var layers: MutableList<Layer> = ArrayList() public val layers: List<Layer>
) : SolidBase(), GeometrySolid { ) : SolidBase(), GeometrySolid, VisionPropertyContainer<Extruded> {
public fun shape(block: Shape2DBuilder.() -> Unit) {
this.shape = Shape2DBuilder().apply(block).build()
//TODO send invalidation signal
}
public fun layer(z: Number, x: Number = 0.0, y: Number = 0.0, scale: Number = 1.0) {
layers.add(Layer(x.toFloat(), y.toFloat(), z.toFloat(), scale.toFloat()))
//TODO send invalidation signal
}
override fun <T : Any> toGeometry(geometryBuilder: GeometryBuilder<T>) { override fun <T : Any> toGeometry(geometryBuilder: GeometryBuilder<T>) {
val shape: Shape2D = shape val shape: Shape2D = shape
@ -103,6 +92,24 @@ public class Extruded(
} }
} }
public class ExtrudeBuilder(
public var shape: List<Point2D> = emptyList(),
public var layers: ArrayList<Layer> = ArrayList(),
config: Config = Config()
) : SimpleVisionPropertyContainer<Extruded>(config) {
public fun shape(block: Shape2DBuilder.() -> Unit) {
this.shape = Shape2DBuilder().apply(block).build()
}
public fun layer(z: Number, x: Number = 0.0, y: Number = 0.0, scale: Number = 1.0) {
layers.add(Layer(x.toFloat(), y.toFloat(), z.toFloat(), scale.toFloat()))
}
internal fun build(): Extruded = Extruded(shape, layers).apply { configure(config) }
}
@VisionBuilder @VisionBuilder
public fun VisionContainerBuilder<Solid>.extrude(name: String? = null, action: Extruded.() -> Unit = {}): Extruded = public fun VisionContainerBuilder<Solid>.extrude(
Extruded().apply(action).also { set(name, it) } name: String? = null,
action: ExtrudeBuilder.() -> Unit = {}
): Extruded = ExtrudeBuilder().apply(action).build().also { set(name, it) }

View File

@ -13,7 +13,7 @@ import space.kscience.visionforge.set
@Serializable @Serializable
@SerialName("solid.line") @SerialName("solid.line")
public class PolyLine(public var points: List<Point3D>) : SolidBase(), Solid { public class PolyLine(public val points: List<Point3D>) : SolidBase(), Solid {
//var lineType by string() //var lineType by string()
public var thickness: Number by allProperties(inherit = false).number(1.0, public var thickness: Number by allProperties(inherit = false).number(1.0,

View File

@ -37,6 +37,8 @@ public interface Solid : Vision {
override val descriptor: NodeDescriptor get() = Companion.descriptor override val descriptor: NodeDescriptor get() = Companion.descriptor
public companion object { public companion object {
// val SELECTED_KEY = "selected".asName() // val SELECTED_KEY = "selected".asName()
public val DETAIL_KEY: Name = "detail".asName() public val DETAIL_KEY: Name = "detail".asName()

View File

@ -2,11 +2,7 @@ package space.kscience.visionforge.solid
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.descriptors.NodeDescriptor import space.kscience.dataforge.meta.descriptors.NodeDescriptor
import space.kscience.dataforge.meta.float
import space.kscience.dataforge.meta.get
import space.kscience.dataforge.meta.node
import space.kscience.visionforge.VisionBase import space.kscience.visionforge.VisionBase
import space.kscience.visionforge.VisionChange import space.kscience.visionforge.VisionChange
@ -20,15 +16,3 @@ public open class SolidBase : VisionBase(), Solid {
super.update(change) super.update(change)
} }
} }
internal fun Meta.toVector(default: Float = 0f) = Point3D(
this[Solid.X_KEY].float ?: default,
this[Solid.Y_KEY].float ?: default,
this[Solid.Z_KEY].float ?: default
)
internal fun Solid.updatePosition(meta: Meta?) {
meta[Solid.POSITION_KEY].node?.toVector()?.let { position = it }
meta[Solid.ROTATION_KEY].node?.toVector()?.let { rotation = it }
meta[Solid.SCALE_KEY].node?.toVector(1f)?.let { scale = it }
}

View File

@ -9,9 +9,9 @@ import space.kscience.visionforge.set
@Serializable @Serializable
@SerialName("solid.label") @SerialName("solid.label")
public class SolidLabel( public class SolidLabel(
public var text: String, public val text: String,
public var fontSize: Double, public val fontSize: Double,
public var fontFamily: String, public val fontFamily: String,
) : SolidBase(), Solid ) : SolidBase(), Solid
@VisionBuilder @VisionBuilder

View File

@ -4,6 +4,7 @@ import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import space.kscience.visionforge.VisionBuilder import space.kscience.visionforge.VisionBuilder
import space.kscience.visionforge.VisionContainerBuilder import space.kscience.visionforge.VisionContainerBuilder
import space.kscience.visionforge.VisionPropertyContainer
import space.kscience.visionforge.set import space.kscience.visionforge.set
import kotlin.math.PI import kotlin.math.PI
import kotlin.math.cos import kotlin.math.cos
@ -12,12 +13,12 @@ import kotlin.math.sin
@Serializable @Serializable
@SerialName("solid.sphere") @SerialName("solid.sphere")
public class Sphere( public class Sphere(
public var radius: Float, public val radius: Float,
public var phiStart: Float = 0f, public val phiStart: Float = 0f,
public var phi: Float = PI2, public val phi: Float = PI2,
public var thetaStart: Float = 0f, public val thetaStart: Float = 0f,
public var theta: Float = PI.toFloat(), public val theta: Float = PI.toFloat(),
) : SolidBase(), GeometrySolid { ) : SolidBase(), GeometrySolid, VisionPropertyContainer<Sphere> {
override fun <T : Any> toGeometry(geometryBuilder: GeometryBuilder<T>) { override fun <T : Any> toGeometry(geometryBuilder: GeometryBuilder<T>) {
fun point3DfromSphCoord(r: Float, theta: Float, phi: Float): Point3D { fun point3DfromSphCoord(r: Float, theta: Float, phi: Float): Point3D {

View File

@ -15,12 +15,12 @@ import kotlin.math.sin
@Serializable @Serializable
@SerialName("solid.sphereLayer") @SerialName("solid.sphereLayer")
public class SphereLayer( public class SphereLayer(
public var outerRadius: Float, public val outerRadius: Float,
public var innerRadius: Float, public val innerRadius: Float,
public var phiStart: Float = 0f, public val phiStart: Float = 0f,
public var phi: Float = PI2, public val phi: Float = PI2,
public var thetaStart: Float = 0f, public val thetaStart: Float = 0f,
public var theta: Float = PI.toFloat(), public val theta: Float = PI.toFloat(),
) : SolidBase(), GeometrySolid { ) : SolidBase(), GeometrySolid {
override fun <T : Any> toGeometry(geometryBuilder: GeometryBuilder<T>): Unit = geometryBuilder.run { override fun <T : Any> toGeometry(geometryBuilder: GeometryBuilder<T>): Unit = geometryBuilder.run {
@ -72,9 +72,17 @@ public class SphereLayer(
public inline fun VisionContainerBuilder<Solid>.sphereLayer( public inline fun VisionContainerBuilder<Solid>.sphereLayer(
outerRadius: Number, outerRadius: Number,
innerRadius: Number, innerRadius: Number,
phiStart: Number = 0f,
phi: Number = PI2,
thetaStart: Number = 0f,
theta: Number = PI.toFloat(),
name: String? = null, name: String? = null,
action: SphereLayer.() -> Unit = {}, action: SphereLayer.() -> Unit = {},
): SphereLayer = SphereLayer( ): SphereLayer = SphereLayer(
outerRadius.toFloat(), outerRadius.toFloat(),
innerRadius.toFloat(), innerRadius.toFloat(),
phiStart.toFloat(),
phi.toFloat(),
thetaStart.toFloat(),
theta.toFloat()
).apply(action).also { set(name, it) } ).apply(action).also { set(name, it) }

View File

@ -105,4 +105,17 @@ public fun Point3D.toMeta(): MetaBuilder = Meta {
X_KEY put x X_KEY put x
Y_KEY put y Y_KEY put y
Z_KEY put z Z_KEY put z
}
internal fun Meta.toVector(default: Float = 0f) = Point3D(
this[Solid.X_KEY].float ?: default,
this[Solid.Y_KEY].float ?: default,
this[Solid.Z_KEY].float ?: default
)
internal fun Solid.updatePosition(meta: Meta?) {
meta[Solid.POSITION_KEY].node?.toVector()?.let { position = it }
meta[Solid.ROTATION_KEY].node?.toVector()?.let { rotation = it }
meta[Solid.SCALE_KEY].node?.toVector(1f)?.let { scale = it }
} }

View File

@ -6,6 +6,6 @@ import space.kscience.visionforge.solid.SolidBase
/** /**
* A custom visual object that has its own Three.js renderer * A custom visual object that has its own Three.js renderer
*/ */
public abstract class ThreeVision : SolidBase() { public abstract class ThreeJsVision : SolidBase() {
public abstract fun render(three: ThreePlugin): Object3D public abstract fun render(three: ThreePlugin): Object3D
} }

View File

@ -49,7 +49,7 @@ public class ThreePlugin : AbstractPlugin(), ElementVisionRenderer {
} }
public fun buildObject3D(obj: Solid): Object3D = when (obj) { public fun buildObject3D(obj: Solid): Object3D = when (obj) {
is ThreeVision -> obj.render(this) is ThreeJsVision -> obj.render(this)
is SolidReferenceGroup -> ThreeReferenceFactory(this, obj) is SolidReferenceGroup -> ThreeReferenceFactory(this, obj)
is SolidGroup -> { is SolidGroup -> {
val group = ThreeGroup() val group = ThreeGroup()