Refactored SolidMaterial to use color wrapper

This commit is contained in:
Alexander Nozik 2020-12-14 13:47:46 +03:00
parent f4970955cb
commit 1ccd45d6c5
20 changed files with 105 additions and 63 deletions

View File

@ -58,7 +58,7 @@ class Model {
} }
private fun highlight(pixel: String) { private fun highlight(pixel: String) {
map[pixel]?.color("blue") map[pixel]?.color?.invoke("blue")
} }
fun reset() { fun reset() {

View File

@ -4,6 +4,7 @@ package ru.mipt.npm.sat
import hep.dataforge.names.toName import hep.dataforge.names.toName
import hep.dataforge.vision.solid.Solid import hep.dataforge.vision.solid.Solid
import hep.dataforge.vision.solid.color import hep.dataforge.vision.solid.color
import hep.dataforge.vision.solid.invoke
import hep.dataforge.vision.three.server.* import hep.dataforge.vision.three.server.*
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
@ -40,7 +41,7 @@ fun main() {
val target = "layer[$randomLayer].segment[$randomI,$randomJ]".toName() val target = "layer[$randomLayer].segment[$randomI,$randomJ]".toName()
(sat[target] as? Solid)?.color("red") (sat[target] as? Solid)?.color("red")
delay(300) delay(300)
(sat[target] as? Solid)?.color = "green" (sat[target] as? Solid)?.color("green")
delay(10) delay(10)
} }
} }

View File

@ -134,31 +134,39 @@ fun Page<Solid>.showcase() {
fun Page<Solid>.showcaseCSG() { fun Page<Solid>.showcaseCSG() {
demo("CSG.simple", "CSG operations") { demo("CSG.simple", "CSG operations") {
composite(CompositeType.UNION) {
box(100, 100, 100) {
z = 50
}
sphere(50)
material {
color(Colors.lightgreen)
opacity = 0.3f
}
}
composite(CompositeType.INTERSECT) { composite(CompositeType.INTERSECT) {
y = 300 y = 300
box(100, 100, 100) { box(100, 100, 100) {
z = 50 z = 50
} }
sphere(50) sphere(50){
detail = 32
}
material {
color(Colors.red) color(Colors.red)
wireframe = false
}
}
composite(CompositeType.UNION) {
box(100, 100, 100) {
z = 50
}
sphere(50){
detail = 32
}
color(Colors.lightgreen)
opacity = 0.3
} }
composite(CompositeType.SUBTRACT) { composite(CompositeType.SUBTRACT) {
y = -300 y = -300
box(100, 100, 100) { box(100, 100, 100) {
z = 50 z = 50
} }
sphere(50) sphere(50){
color(Colors.blue) detail = 32
}
color(Colors.teal)
opacity = 0.7
} }
} }

View File

@ -1,12 +1,10 @@
import hep.dataforge.Application import hep.dataforge.Application
import hep.dataforge.context.Global
import hep.dataforge.startApplication import hep.dataforge.startApplication
import hep.dataforge.vision.bootstrap.visionPropertyEditor import hep.dataforge.vision.bootstrap.visionPropertyEditor
import hep.dataforge.vision.react.ThreeCanvasComponent import hep.dataforge.vision.react.ThreeCanvasComponent
import hep.dataforge.vision.react.objectTree import hep.dataforge.vision.react.objectTree
import hep.dataforge.vision.solid.* import hep.dataforge.vision.solid.*
import hep.dataforge.vision.solid.specifications.Canvas3DOptions import hep.dataforge.vision.solid.specifications.Canvas3DOptions
import hep.dataforge.vision.solid.three.ThreePlugin
import kotlinx.browser.document import kotlinx.browser.document
import org.w3c.dom.HTMLElement import org.w3c.dom.HTMLElement
import react.RBuilder import react.RBuilder
@ -14,7 +12,7 @@ import react.child
import react.dom.div import react.dom.div
import react.dom.render import react.dom.render
public fun RBuilder.threeCanvas(object3D: Solid, options: Canvas3DOptions.() -> Unit = {}) { fun RBuilder.threeCanvas(object3D: Solid, options: Canvas3DOptions.() -> Unit = {}) {
child(ThreeCanvasComponent) { child(ThreeCanvasComponent) {
attrs { attrs {
this.obj = object3D this.obj = object3D
@ -25,8 +23,6 @@ public fun RBuilder.threeCanvas(object3D: Solid, options: Canvas3DOptions.() ->
private class PlayGroundApp : Application { private class PlayGroundApp : Application {
private val three = Global.plugins.fetch(ThreePlugin)
override fun start(state: Map<String, Any>) { override fun start(state: Map<String, Any>) {
val element = val element =

View File

@ -8,6 +8,10 @@ import hep.dataforge.names.Name
import hep.dataforge.values.ValueType import hep.dataforge.values.ValueType
import hep.dataforge.values.asValue import hep.dataforge.values.asValue
@DslMarker
public annotation class VisionBuilder
public fun Sequence<MetaItem<*>?>.merge(): MetaItem<*>? { public fun Sequence<MetaItem<*>?>.merge(): MetaItem<*>? {
return when (val first = firstOrNull { it != null }) { return when (val first = firstOrNull { it != null }) {
null -> null null -> null

View File

@ -1,5 +1,6 @@
package hep.dataforge.vision.solid package hep.dataforge.vision.solid
import hep.dataforge.vision.VisionBuilder
import hep.dataforge.vision.VisionContainerBuilder import hep.dataforge.vision.VisionContainerBuilder
import hep.dataforge.vision.set import hep.dataforge.vision.set
import hep.dataforge.vision.solid.Solid.Companion.solidEquals import hep.dataforge.vision.solid.Solid.Companion.solidEquals
@ -61,6 +62,7 @@ public class Box(
} }
} }
@VisionBuilder
public inline fun VisionContainerBuilder<Solid>.box( public inline fun VisionContainerBuilder<Solid>.box(
xSize: Number, xSize: Number,
ySize: Number, ySize: Number,

View File

@ -3,10 +3,7 @@ package hep.dataforge.vision.solid
import hep.dataforge.meta.update import hep.dataforge.meta.update
import hep.dataforge.names.NameToken import hep.dataforge.names.NameToken
import hep.dataforge.vision.Vision import hep.dataforge.vision.*
import hep.dataforge.vision.VisionContainerBuilder
import hep.dataforge.vision.VisionGroup
import hep.dataforge.vision.set
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@ -33,6 +30,7 @@ public class Composite(
get() = mapOf(NameToken("first") to first, NameToken("second") to second) get() = mapOf(NameToken("first") to first, NameToken("second") to second)
} }
@VisionBuilder
public inline fun VisionContainerBuilder<Solid>.composite( public inline fun VisionContainerBuilder<Solid>.composite(
type: CompositeType, type: CompositeType,
name: String = "", name: String = "",
@ -58,11 +56,14 @@ public inline fun VisionContainerBuilder<Solid>.composite(
} }
} }
@VisionBuilder
public inline fun VisionContainerBuilder<Solid>.union(name: String = "", builder: SolidGroup.() -> Unit): Composite = public inline fun VisionContainerBuilder<Solid>.union(name: String = "", builder: SolidGroup.() -> Unit): Composite =
composite(CompositeType.UNION, name, builder = builder) composite(CompositeType.UNION, name, builder = builder)
@VisionBuilder
public inline fun VisionContainerBuilder<Solid>.subtract(name: String = "", builder: SolidGroup.() -> Unit): Composite = public inline fun VisionContainerBuilder<Solid>.subtract(name: String = "", builder: SolidGroup.() -> Unit): Composite =
composite(CompositeType.SUBTRACT, name, builder = builder) composite(CompositeType.SUBTRACT, name, builder = builder)
@VisionBuilder
public inline fun VisionContainerBuilder<Solid>.intersect(name: String = "", builder: SolidGroup.() -> Unit): Composite = public inline fun VisionContainerBuilder<Solid>.intersect(name: String = "", builder: SolidGroup.() -> Unit): Composite =
composite(CompositeType.INTERSECT, name, builder = builder) composite(CompositeType.INTERSECT, name, builder = builder)

View File

@ -1,5 +1,6 @@
package hep.dataforge.vision.solid package hep.dataforge.vision.solid
import hep.dataforge.vision.VisionBuilder
import hep.dataforge.vision.VisionContainerBuilder import hep.dataforge.vision.VisionContainerBuilder
import hep.dataforge.vision.set import hep.dataforge.vision.set
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
@ -102,5 +103,6 @@ public class Extruded(
} }
} }
@VisionBuilder
public fun VisionContainerBuilder<Solid>.extrude(name: String = "", action: Extruded.() -> Unit = {}): Extruded = public fun VisionContainerBuilder<Solid>.extrude(name: String = "", action: Extruded.() -> Unit = {}): Extruded =
Extruded().apply(action).also { set(name, it) } Extruded().apply(action).also { set(name, it) }

View File

@ -4,6 +4,7 @@ import hep.dataforge.meta.number
import hep.dataforge.names.Name import hep.dataforge.names.Name
import hep.dataforge.names.asName import hep.dataforge.names.asName
import hep.dataforge.names.plus import hep.dataforge.names.plus
import hep.dataforge.vision.VisionBuilder
import hep.dataforge.vision.VisionContainerBuilder import hep.dataforge.vision.VisionContainerBuilder
import hep.dataforge.vision.props import hep.dataforge.vision.props
import hep.dataforge.vision.set import hep.dataforge.vision.set
@ -23,6 +24,7 @@ public class PolyLine(public var points: List<Point3D>) : SolidBase(), Solid {
} }
@VisionBuilder
public fun VisionContainerBuilder<Solid>.polyline( public fun VisionContainerBuilder<Solid>.polyline(
vararg points: Point3D, vararg points: Point3D,
name: String = "", name: String = "",

View File

@ -9,6 +9,7 @@ import hep.dataforge.values.ValueType
import hep.dataforge.values.asValue import hep.dataforge.values.asValue
import hep.dataforge.vision.Vision import hep.dataforge.vision.Vision
import hep.dataforge.vision.Vision.Companion.VISIBLE_KEY import hep.dataforge.vision.Vision.Companion.VISIBLE_KEY
import hep.dataforge.vision.VisionBuilder
import hep.dataforge.vision.enum import hep.dataforge.vision.enum
import hep.dataforge.vision.layout.Output import hep.dataforge.vision.layout.Output
import hep.dataforge.vision.setProperty import hep.dataforge.vision.setProperty
@ -104,6 +105,7 @@ public var Solid.layer: Int
config[LAYER_KEY] = value.asValue() config[LAYER_KEY] = value.asValue()
} }
@VisionBuilder
public fun Output<Solid>.solidGroup(builder: SolidGroup.() -> Unit): Unit = render(SolidGroup().apply(builder)) public fun Output<Solid>.solidGroup(builder: SolidGroup.() -> Unit): Unit = render(SolidGroup().apply(builder))
// Common properties // Common properties

View File

@ -86,6 +86,7 @@ public fun SolidGroup(block: SolidGroup.() -> Unit): SolidGroup {
public tailrec fun PrototypeHolder.getPrototype(name: Name): Solid? = public tailrec fun PrototypeHolder.getPrototype(name: Name): Solid? =
prototypes?.get(name) as? Solid ?: (parent as? PrototypeHolder)?.getPrototype(name) prototypes?.get(name) as? Solid ?: (parent as? PrototypeHolder)?.getPrototype(name)
@VisionBuilder
public fun VisionContainerBuilder<Vision>.group(name: Name = Name.EMPTY, action: SolidGroup.() -> Unit = {}): SolidGroup = public fun VisionContainerBuilder<Vision>.group(name: Name = Name.EMPTY, action: SolidGroup.() -> Unit = {}): SolidGroup =
SolidGroup().apply(action).also { set(name, it) } SolidGroup().apply(action).also { set(name, it) }

View File

@ -1,5 +1,6 @@
package hep.dataforge.vision.solid package hep.dataforge.vision.solid
import hep.dataforge.vision.VisionBuilder
import hep.dataforge.vision.VisionContainerBuilder import hep.dataforge.vision.VisionContainerBuilder
import hep.dataforge.vision.set import hep.dataforge.vision.set
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
@ -13,6 +14,7 @@ public class SolidLabel(
public var fontFamily: String, public var fontFamily: String,
) : SolidBase(), Solid ) : SolidBase(), Solid
@VisionBuilder
public fun VisionContainerBuilder<Solid>.label( public fun VisionContainerBuilder<Solid>.label(
text: String, text: String,
fontSize: Number = 20, fontSize: Number = 20,

View File

@ -6,26 +6,66 @@ import hep.dataforge.meta.descriptors.attributes
import hep.dataforge.names.Name import hep.dataforge.names.Name
import hep.dataforge.names.asName import hep.dataforge.names.asName
import hep.dataforge.names.plus import hep.dataforge.names.plus
import hep.dataforge.values.Value
import hep.dataforge.values.ValueType import hep.dataforge.values.ValueType
import hep.dataforge.values.asValue import hep.dataforge.values.asValue
import hep.dataforge.values.string
import hep.dataforge.vision.Colors import hep.dataforge.vision.Colors
import hep.dataforge.vision.VisionBuilder
import hep.dataforge.vision.setProperty import hep.dataforge.vision.setProperty
import hep.dataforge.vision.solid.SolidMaterial.Companion.MATERIAL_COLOR_KEY import hep.dataforge.vision.solid.SolidMaterial.Companion.MATERIAL_COLOR_KEY
import hep.dataforge.vision.solid.SolidMaterial.Companion.MATERIAL_KEY import hep.dataforge.vision.solid.SolidMaterial.Companion.MATERIAL_KEY
import hep.dataforge.vision.solid.SolidMaterial.Companion.MATERIAL_OPACITY_KEY import hep.dataforge.vision.solid.SolidMaterial.Companion.MATERIAL_OPACITY_KEY
import hep.dataforge.vision.widgetType import hep.dataforge.vision.widgetType
@VisionBuilder
public class ColorAccessor(private val parent: MutableItemProvider, private val colorKey: Name) {
public var value: Value?
get() = parent.getItem(colorKey).value
set(value) {
parent[colorKey] = value
}
}
public var ColorAccessor?.string: String?
get() = this?.value?.string
set(value) {
this?.value = value?.asValue()
}
/**
* Set [webcolor](https://en.wikipedia.org/wiki/Web_colors) as string
*/
public operator fun ColorAccessor?.invoke(webColor: String) {
this?.value = webColor.asValue()
}
/**
* Set color as RGB integer
*/
public operator fun ColorAccessor?.invoke(rgb: Int) {
this?.value = rgb.asValue()
}
/**
* Set color as RGB
*/
public operator fun ColorAccessor?.invoke(r: UByte, g: UByte, b: UByte) {
this?.value = Colors.rgbToString(r, g, b).asValue()
}
@VisionBuilder
public class SolidMaterial : Scheme() { public class SolidMaterial : Scheme() {
/** /**
* Primary web-color for the material * Primary web-color for the material
*/ */
public var color: String? by string(key = COLOR_KEY) public var color: ColorAccessor = ColorAccessor(config, COLOR_KEY)
/** /**
* Specular color for phong material * Specular color for phong material
*/ */
public var specularColor: String? by string(key = SPECULAR_COLOR_KEY) public var specularColor: ColorAccessor = ColorAccessor(config, SPECULAR_COLOR_KEY)
/** /**
* Opacity * Opacity
@ -75,37 +115,13 @@ public class SolidMaterial : Scheme() {
} }
} }
/** public val Solid.color: ColorAccessor get() = ColorAccessor(config, MATERIAL_COLOR_KEY)
* Set color as web-color
*/
public fun Solid.color(webColor: String) {
setProperty(MATERIAL_COLOR_KEY, webColor.asValue())
}
/** public var Solid.material: SolidMaterial?
* Set color as integer
*/
public fun Solid.color(rgb: Int) {
setProperty(MATERIAL_COLOR_KEY, rgb.asValue())
}
public fun Solid.color(r: UByte, g: UByte, b: UByte): Unit = setProperty(
MATERIAL_COLOR_KEY,
Colors.rgbToString(r, g, b).asValue()
)
/**
* Web colors representation of the color in `#rrggbb` format or HTML name
*/
public var Solid.color: String?
get() = getProperty(MATERIAL_COLOR_KEY)?.let { Colors.fromMeta(it) }
set(value) {
setProperty(MATERIAL_COLOR_KEY, value?.asValue())
}
public val Solid.material: SolidMaterial?
get() = getProperty(MATERIAL_KEY).node?.let { SolidMaterial.read(it) } get() = getProperty(MATERIAL_KEY).node?.let { SolidMaterial.read(it) }
set(value) = setProperty(MATERIAL_KEY, value?.config)
@VisionBuilder
public fun Solid.material(builder: SolidMaterial.() -> Unit) { public fun Solid.material(builder: SolidMaterial.() -> Unit) {
val node = config[MATERIAL_KEY].node val node = config[MATERIAL_KEY].node
if (node != null) { if (node != null) {
@ -115,8 +131,8 @@ public fun Solid.material(builder: SolidMaterial.() -> Unit) {
} }
} }
public var Solid.opacity: Double? public var Solid.opacity: Number?
get() = getProperty(MATERIAL_OPACITY_KEY).double get() = getProperty(MATERIAL_OPACITY_KEY).number
set(value) { set(value) {
setProperty(MATERIAL_OPACITY_KEY, value?.asValue()) setProperty(MATERIAL_OPACITY_KEY, value?.asValue())
} }

View File

@ -1,5 +1,6 @@
package hep.dataforge.vision.solid package hep.dataforge.vision.solid
import hep.dataforge.vision.VisionBuilder
import hep.dataforge.vision.VisionContainerBuilder import hep.dataforge.vision.VisionContainerBuilder
import hep.dataforge.vision.set import hep.dataforge.vision.set
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
@ -50,6 +51,7 @@ public class Sphere(
} }
} }
@VisionBuilder
public inline fun VisionContainerBuilder<Solid>.sphere( public inline fun VisionContainerBuilder<Solid>.sphere(
radius: Number, radius: Number,
phi: Number = 2 * PI, phi: Number = 2 * PI,

View File

@ -1,5 +1,6 @@
package hep.dataforge.vision.solid package hep.dataforge.vision.solid
import hep.dataforge.vision.VisionBuilder
import hep.dataforge.vision.VisionContainerBuilder import hep.dataforge.vision.VisionContainerBuilder
import hep.dataforge.vision.set import hep.dataforge.vision.set
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
@ -118,6 +119,7 @@ public class Tube(
} }
@VisionBuilder
public inline fun VisionContainerBuilder<Solid>.tube( public inline fun VisionContainerBuilder<Solid>.tube(
r: Number, r: Number,
height: Number, height: Number,

View File

@ -55,7 +55,7 @@ class PropertyTest {
} }
} }
} }
assertEquals("#555555", box?.color) assertEquals("#555555", box?.color.string)
} }
@Test @Test
@ -76,6 +76,6 @@ class PropertyTest {
box = ref("box".asName()) box = ref("box".asName())
} }
} }
assertEquals("#555555", box?.color) assertEquals("#555555", box?.color.string)
} }
} }

View File

@ -28,8 +28,8 @@ class VisionUpdateTest {
} }
targetVision.update(dif) targetVision.update(dif)
assertTrue { targetVision["top"] is SolidGroup } assertTrue { targetVision["top"] is SolidGroup }
assertEquals("red", (targetVision["origin"] as Solid).color) // Should work assertEquals("red", (targetVision["origin"] as Solid).color.string) // Should work
assertEquals("#00007b", (targetVision["top"] as SolidGroup).color) // new item always takes precedence assertEquals("#00007b", (targetVision["top"] as SolidGroup).color.string) // new item always takes precedence
} }
@Test @Test

View File

@ -9,5 +9,5 @@ kscience {
dependencies { dependencies {
api(project(":visionforge-solid")) api(project(":visionforge-solid"))
implementation(npm("three", "0.122.0")) implementation(npm("three", "0.122.0"))
implementation(npm("three-csg-ts", "1.0.6")) implementation(npm("three-csg-ts", "2.0.0"))
} }

View File

@ -3,6 +3,7 @@ package hep.dataforge.vision.solid.three
import hep.dataforge.meta.node import hep.dataforge.meta.node
import hep.dataforge.vision.solid.PolyLine import hep.dataforge.vision.solid.PolyLine
import hep.dataforge.vision.solid.color import hep.dataforge.vision.solid.color
import hep.dataforge.vision.solid.string
import hep.dataforge.vision.solid.three.ThreeMaterials.DEFAULT_LINE_COLOR import hep.dataforge.vision.solid.three.ThreeMaterials.DEFAULT_LINE_COLOR
import info.laht.threekt.core.Geometry import info.laht.threekt.core.Geometry
import info.laht.threekt.core.Object3D import info.laht.threekt.core.Object3D
@ -21,7 +22,7 @@ public object ThreeLineFactory : ThreeFactory<PolyLine> {
val material = ThreeMaterials.getLineMaterial(obj.getProperty(MeshThreeFactory.EDGES_MATERIAL_KEY).node, true) val material = ThreeMaterials.getLineMaterial(obj.getProperty(MeshThreeFactory.EDGES_MATERIAL_KEY).node, true)
material.linewidth = obj.thickness.toDouble() material.linewidth = obj.thickness.toDouble()
material.color = obj.color?.let { Color(it) } ?: DEFAULT_LINE_COLOR material.color = obj.color.string?.let { Color(it) } ?: DEFAULT_LINE_COLOR
return LineSegments(geometry, material).apply { return LineSegments(geometry, material).apply {
updatePosition(obj) updatePosition(obj)