forked from kscience/visionforge
Lines implemented
This commit is contained in:
parent
0fbad16be6
commit
ce80ffe91b
@ -4,6 +4,7 @@ import hep.dataforge.meta.*
|
||||
import hep.dataforge.names.Name
|
||||
import hep.dataforge.names.NameToken
|
||||
import hep.dataforge.names.asName
|
||||
import hep.dataforge.names.toName
|
||||
import hep.dataforge.values.Value
|
||||
import kotlin.jvm.JvmName
|
||||
import kotlin.properties.ReadOnlyProperty
|
||||
@ -35,81 +36,79 @@ class VisualObjectDelegate(
|
||||
}
|
||||
|
||||
class VisualObjectDelegateWrapper<T>(
|
||||
val obj: VisualObject,
|
||||
val key: Name?,
|
||||
val default: T,
|
||||
val inherited: Boolean,
|
||||
val write: Config.(name: Name, value: T) -> Unit = { name, value -> set(name, value) },
|
||||
val read: (MetaItem<*>?) -> T?
|
||||
) : ReadWriteProperty<VisualObject, T> {
|
||||
) : ReadWriteProperty<Any?, T> {
|
||||
|
||||
//private var cachedName: Name? = null
|
||||
|
||||
override fun getValue(thisRef: VisualObject, property: KProperty<*>): T {
|
||||
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
|
||||
val name = key ?: property.name.asName()
|
||||
return if (inherited) {
|
||||
read(thisRef.getProperty(name))
|
||||
} else {
|
||||
read(thisRef.config[name])
|
||||
} ?: default
|
||||
return read(obj.getProperty(name,inherited))?:default
|
||||
}
|
||||
|
||||
override fun setValue(thisRef: VisualObject, property: KProperty<*>, value: T) {
|
||||
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
|
||||
val name = key ?: property.name.asName()
|
||||
thisRef.config[name] = value
|
||||
obj.config[name] = value
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun VisualObject.value(default: Value? = null, key: String? = null, inherited: Boolean = false) =
|
||||
VisualObjectDelegateWrapper(key?.asName(), default, inherited) { it.value }
|
||||
VisualObjectDelegateWrapper(this, key?.toName(), default, inherited) { it.value }
|
||||
|
||||
fun VisualObject.string(default: String? = null, key: String? = null, inherited: Boolean = false) =
|
||||
VisualObjectDelegateWrapper(key?.asName(), default, inherited) { it.string }
|
||||
VisualObjectDelegateWrapper(this, key?.toName(), default, inherited) { it.string }
|
||||
|
||||
fun VisualObject.boolean(default: Boolean? = null, key: String? = null, inherited: Boolean = false) =
|
||||
VisualObjectDelegateWrapper(key?.asName(), default, inherited) { it.boolean }
|
||||
VisualObjectDelegateWrapper(this, key?.toName(), default, inherited) { it.boolean }
|
||||
|
||||
fun VisualObject.number(default: Number? = null, key: String? = null, inherited: Boolean = false) =
|
||||
VisualObjectDelegateWrapper(key?.asName(), default, inherited) { it.number }
|
||||
VisualObjectDelegateWrapper(this, key?.toName(), default, inherited) { it.number }
|
||||
|
||||
fun VisualObject.double(default: Double? = null, key: String? = null, inherited: Boolean = false) =
|
||||
VisualObjectDelegateWrapper(key?.asName(), default, inherited) { it.double }
|
||||
VisualObjectDelegateWrapper(this, key?.toName(), default, inherited) { it.double }
|
||||
|
||||
fun VisualObject.int(default: Int? = null, key: String? = null, inherited: Boolean = false) =
|
||||
VisualObjectDelegateWrapper(key?.asName(), default, inherited) { it.int }
|
||||
VisualObjectDelegateWrapper(this, key?.toName(), default, inherited) { it.int }
|
||||
|
||||
|
||||
fun VisualObject.node(key: String? = null, inherited: Boolean = true) =
|
||||
VisualObjectDelegateWrapper(key?.asName(), null, inherited) { it.node }
|
||||
VisualObjectDelegateWrapper(this, key?.toName(), null, inherited) { it.node }
|
||||
|
||||
fun VisualObject.item(key: String? = null, inherited: Boolean = true) =
|
||||
VisualObjectDelegateWrapper(key?.asName(), null, inherited) { it }
|
||||
VisualObjectDelegateWrapper(this, key?.toName(), null, inherited) { it }
|
||||
|
||||
//fun <T : Configurable> Configurable.spec(spec: Specification<T>, key: String? = null) = ChildConfigDelegate<T>(key) { spec.wrap(this) }
|
||||
|
||||
@JvmName("safeString")
|
||||
fun VisualObject.string(default: String, key: String? = null, inherited: Boolean = false) =
|
||||
VisualObjectDelegateWrapper(key?.asName(), default, inherited) { it.string }
|
||||
VisualObjectDelegateWrapper(this, key?.toName(), default, inherited) { it.string }
|
||||
|
||||
@JvmName("safeBoolean")
|
||||
fun VisualObject.boolean(default: Boolean, key: String? = null, inherited: Boolean = false) =
|
||||
VisualObjectDelegateWrapper(key?.asName(), default, inherited) { it.boolean }
|
||||
VisualObjectDelegateWrapper(this, key?.toName(), default, inherited) { it.boolean }
|
||||
|
||||
@JvmName("safeNumber")
|
||||
fun VisualObject.number(default: Number, key: String? = null, inherited: Boolean = false) =
|
||||
VisualObjectDelegateWrapper(key?.asName(), default, inherited) { it.number }
|
||||
VisualObjectDelegateWrapper(this, key?.toName(), default, inherited) { it.number }
|
||||
|
||||
@JvmName("safeDouble")
|
||||
fun VisualObject.double(default: Double, key: String? = null, inherited: Boolean = false) =
|
||||
VisualObjectDelegateWrapper(key?.asName(), default, inherited) { it.double }
|
||||
VisualObjectDelegateWrapper(this, key?.toName(), default, inherited) { it.double }
|
||||
|
||||
@JvmName("safeInt")
|
||||
fun VisualObject.int(default: Int, key: String? = null, inherited: Boolean = false) =
|
||||
VisualObjectDelegateWrapper(key?.asName(), default, inherited) { it.int }
|
||||
VisualObjectDelegateWrapper(this, key?.toName(), default, inherited) { it.int }
|
||||
|
||||
|
||||
inline fun <reified E : Enum<E>> VisualObject.enum(default: E, key: String? = null, inherited: Boolean = false) =
|
||||
VisualObjectDelegateWrapper(
|
||||
this,
|
||||
key?.let { NameToken(it).asName() },
|
||||
default,
|
||||
inherited
|
||||
@ -121,11 +120,11 @@ fun <T> VisualObject.merge(
|
||||
key: String? = null,
|
||||
transformer: (Sequence<MetaItem<*>>) -> T
|
||||
): ReadOnlyProperty<VisualObject, T> {
|
||||
return object : ReadOnlyProperty<VisualObject, T> {
|
||||
override fun getValue(thisRef: VisualObject, property: KProperty<*>): T {
|
||||
val name = key?.asName() ?: property.name.asName()
|
||||
return object : ReadOnlyProperty<Any?, T> {
|
||||
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
|
||||
val name = key?.toName() ?: property.name.asName()
|
||||
val sequence = sequence<MetaItem<*>> {
|
||||
var thisObj: VisualObject? = thisRef
|
||||
var thisObj: VisualObject? = this@merge
|
||||
while (thisObj != null) {
|
||||
thisObj.config[name]?.let { yield(it) }
|
||||
thisObj = thisObj.parent
|
||||
|
@ -0,0 +1,26 @@
|
||||
@file:UseSerializers(Point3DSerializer::class)
|
||||
|
||||
package hep.dataforge.vis.spatial
|
||||
|
||||
import hep.dataforge.io.ConfigSerializer
|
||||
import hep.dataforge.meta.Config
|
||||
import hep.dataforge.vis.common.AbstractVisualObject
|
||||
import hep.dataforge.vis.common.number
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.UseSerializers
|
||||
|
||||
@Serializable
|
||||
class PolyLine(var points: List<Point3D>) : AbstractVisualObject(), VisualObject3D {
|
||||
@Serializable(ConfigSerializer::class)
|
||||
override var properties: Config? = null
|
||||
|
||||
override var position: Point3D? = null
|
||||
override var rotation: Point3D? = null
|
||||
override var scale: Point3D? = null
|
||||
|
||||
//var lineType by string()
|
||||
var thickness by number(1.0, key = "material.thickness")
|
||||
}
|
||||
|
||||
fun VisualGroup3D.polyline(vararg points: Point3D, name: String = "", action: PolyLine.() -> Unit = {}) =
|
||||
PolyLine(points.toList()).apply(action).also { set(name, it) }
|
@ -4,6 +4,7 @@ import hep.dataforge.meta.*
|
||||
import hep.dataforge.values.ValueType
|
||||
import hep.dataforge.vis.common.Colors
|
||||
import hep.dataforge.vis.spatial.Material3D
|
||||
import info.laht.threekt.materials.LineBasicMaterial
|
||||
import info.laht.threekt.materials.Material
|
||||
import info.laht.threekt.materials.MeshBasicMaterial
|
||||
import info.laht.threekt.materials.MeshPhongMaterial
|
||||
@ -13,8 +14,37 @@ import info.laht.threekt.math.Color
|
||||
object Materials {
|
||||
val DEFAULT_COLOR = Color(Colors.darkgreen)
|
||||
val DEFAULT = MeshPhongMaterial().apply {
|
||||
this.color.set(DEFAULT_COLOR)
|
||||
color.set(DEFAULT_COLOR)
|
||||
}
|
||||
val DEFAULT_LINE_COLOR = Color(Colors.black)
|
||||
val DEFAULT_LINE = LineBasicMaterial().apply {
|
||||
color.set(DEFAULT_LINE_COLOR)
|
||||
}
|
||||
|
||||
|
||||
private val materialCache = HashMap<Meta, Material>()
|
||||
private val lineMaterialCache = HashMap<Meta, Material>()
|
||||
|
||||
fun getMaterial(meta: Meta): Material = materialCache.getOrPut(meta) {
|
||||
MeshBasicMaterial().apply {
|
||||
color = meta["color"]?.color() ?: DEFAULT_COLOR
|
||||
opacity = meta["opacity"]?.double ?: 1.0
|
||||
transparent = meta["transparent"].boolean ?: (opacity < 1.0)
|
||||
//node["specularColor"]?.let { specular = it.color() }
|
||||
//side = 2
|
||||
}
|
||||
}
|
||||
|
||||
fun getLineMaterial(meta: Meta): Material = lineMaterialCache.getOrPut(meta) {
|
||||
LineBasicMaterial().apply {
|
||||
color = meta["color"]?.color() ?: DEFAULT_LINE_COLOR
|
||||
opacity = meta["opacity"].double ?: 1.0
|
||||
transparent = meta["transparent"].boolean ?: (opacity < 1.0)
|
||||
linewidth = meta["thickness"].double ?: 1.0
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -41,26 +71,26 @@ fun MetaItem<*>.color(): Color {
|
||||
}
|
||||
}
|
||||
|
||||
private val materialCache = HashMap<Meta, Material>()
|
||||
|
||||
/**
|
||||
* Infer Three material based on meta item
|
||||
*/
|
||||
fun Meta?.jsMaterial(): Material {
|
||||
return if (this == null) {
|
||||
Materials.DEFAULT
|
||||
} else
|
||||
//TODO add more options for material
|
||||
return materialCache.getOrPut(this) {
|
||||
MeshBasicMaterial().apply {
|
||||
color = get("color")?.color() ?: Materials.DEFAULT_COLOR
|
||||
opacity = get("opacity")?.double ?: 1.0
|
||||
transparent = get("transparent").boolean ?: (opacity < 1.0)
|
||||
//node["specularColor"]?.let { specular = it.color() }
|
||||
//side = 2
|
||||
}
|
||||
} else {
|
||||
Materials.getMaterial(this)
|
||||
}
|
||||
}
|
||||
|
||||
fun Material3D?.jsMaterial(): Material = this?.config.jsMaterial()
|
||||
fun Meta?.jsLineMaterial(): Material {
|
||||
return if (this == null) {
|
||||
Materials.DEFAULT_LINE
|
||||
} else{
|
||||
Materials.getLineMaterial(this)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun Material3D?.jsMaterial(): Material = this?.config.jsMaterial()
|
||||
fun Material3D?.jsLineMaterial(): Material = this?.config.jsLineMaterial()
|
||||
|
||||
|
@ -0,0 +1,99 @@
|
||||
package hep.dataforge.vis.spatial.three
|
||||
|
||||
import hep.dataforge.meta.boolean
|
||||
import hep.dataforge.meta.node
|
||||
import hep.dataforge.names.asName
|
||||
import hep.dataforge.names.plus
|
||||
import hep.dataforge.names.startsWith
|
||||
import hep.dataforge.vis.spatial.Material3D
|
||||
import hep.dataforge.vis.spatial.VisualObject3D
|
||||
import hep.dataforge.vis.spatial.layer
|
||||
import hep.dataforge.vis.spatial.material
|
||||
import info.laht.threekt.core.BufferGeometry
|
||||
import info.laht.threekt.geometries.EdgesGeometry
|
||||
import info.laht.threekt.geometries.WireframeGeometry
|
||||
import info.laht.threekt.objects.LineSegments
|
||||
import info.laht.threekt.objects.Mesh
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
/**
|
||||
* Basic geometry-based factory
|
||||
*/
|
||||
abstract class MeshThreeFactory<T : VisualObject3D>(
|
||||
override val type: KClass<out T>
|
||||
) : ThreeFactory<T> {
|
||||
/**
|
||||
* Build a geometry for an object
|
||||
*/
|
||||
abstract fun buildGeometry(obj: T): BufferGeometry
|
||||
|
||||
private fun Mesh.applyEdges(obj: T) {
|
||||
children.find { it.name == "edges" }?.let { remove(it) }
|
||||
//inherited edges definition, enabled by default
|
||||
if (obj.getProperty(EDGES_ENABLED_KEY).boolean != false) {
|
||||
val material = obj.getProperty(EDGES_MATERIAL_KEY).node.jsLineMaterial()
|
||||
add(
|
||||
LineSegments(
|
||||
EdgesGeometry(geometry as BufferGeometry),
|
||||
material
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun Mesh.applyWireFrame(obj: T) {
|
||||
children.find { it.name == "wireframe" }?.let { remove(it) }
|
||||
//inherited wireframe definition, disabled by default
|
||||
if (obj.getProperty(WIREFRAME_ENABLED_KEY).boolean == true) {
|
||||
val material = obj.getProperty(WIREFRAME_MATERIAL_KEY).node.jsLineMaterial()
|
||||
add(
|
||||
LineSegments(
|
||||
WireframeGeometry(geometry as BufferGeometry),
|
||||
material
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun invoke(obj: T): Mesh {
|
||||
//TODO add caching for geometries using templates
|
||||
val geometry = buildGeometry(obj)
|
||||
|
||||
//JS sometimes tries to pass Geometry as BufferGeometry
|
||||
@Suppress("USELESS_IS_CHECK") if (geometry !is BufferGeometry) error("BufferGeometry expected")
|
||||
|
||||
val mesh = Mesh(geometry, obj.material.jsMaterial()).apply {
|
||||
matrixAutoUpdate = false
|
||||
applyEdges(obj)
|
||||
applyWireFrame(obj)
|
||||
//set position for mesh
|
||||
updatePosition(obj)
|
||||
|
||||
layers.enable(obj.layer)
|
||||
children.forEach {
|
||||
it.layers.enable(obj.layer)
|
||||
}
|
||||
}
|
||||
|
||||
//add listener to object properties
|
||||
obj.onPropertyChange(this) { name, _, _ ->
|
||||
when {
|
||||
name.startsWith(VisualObject3D.GEOMETRY_KEY) -> mesh.geometry = buildGeometry(obj)
|
||||
name.startsWith(WIREFRAME_KEY) -> mesh.applyWireFrame(obj)
|
||||
name.startsWith(EDGES_KEY) -> mesh.applyEdges(obj)
|
||||
else -> mesh.updateProperty(obj, name)
|
||||
}
|
||||
}
|
||||
return mesh
|
||||
}
|
||||
|
||||
companion object {
|
||||
val EDGES_KEY = "edges".asName()
|
||||
val WIREFRAME_KEY = "wireframe".asName()
|
||||
val ENABLED_KEY = "enabled".asName()
|
||||
val EDGES_ENABLED_KEY = EDGES_KEY + ENABLED_KEY
|
||||
val EDGES_MATERIAL_KEY = EDGES_KEY + Material3D.MATERIAL_KEY
|
||||
val WIREFRAME_ENABLED_KEY = WIREFRAME_KEY + ENABLED_KEY
|
||||
val WIREFRAME_MATERIAL_KEY = WIREFRAME_KEY + Material3D.MATERIAL_KEY
|
||||
}
|
||||
}
|
@ -1,22 +1,14 @@
|
||||
package hep.dataforge.vis.spatial.three
|
||||
|
||||
import hep.dataforge.meta.boolean
|
||||
import hep.dataforge.meta.node
|
||||
import hep.dataforge.names.Name
|
||||
import hep.dataforge.names.asName
|
||||
import hep.dataforge.names.plus
|
||||
import hep.dataforge.names.startsWith
|
||||
import hep.dataforge.provider.Type
|
||||
import hep.dataforge.vis.common.VisualObject
|
||||
import hep.dataforge.vis.spatial.*
|
||||
import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_KEY
|
||||
import hep.dataforge.vis.spatial.VisualObject3D.Companion.GEOMETRY_KEY
|
||||
import hep.dataforge.vis.spatial.three.ThreeFactory.Companion.TYPE
|
||||
import info.laht.threekt.core.BufferGeometry
|
||||
import info.laht.threekt.core.Object3D
|
||||
import info.laht.threekt.geometries.EdgesGeometry
|
||||
import info.laht.threekt.geometries.WireframeGeometry
|
||||
import info.laht.threekt.objects.LineSegments
|
||||
import info.laht.threekt.objects.Mesh
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
@ -46,30 +38,6 @@ internal fun Object3D.updatePosition(obj: VisualObject3D) {
|
||||
updateMatrix()
|
||||
}
|
||||
|
||||
internal fun <T : VisualObject3D> Mesh.updateFrom(obj: T) {
|
||||
matrixAutoUpdate = false
|
||||
|
||||
//inherited edges definition, enabled by default
|
||||
if (obj.getProperty(MeshThreeFactory.EDGES_ENABLED_KEY).boolean != false) {
|
||||
val material = obj.getProperty(MeshThreeFactory.EDGES_MATERIAL_KEY).node?.jsMaterial() ?: Materials.DEFAULT
|
||||
add(LineSegments(EdgesGeometry(geometry as BufferGeometry), material))
|
||||
}
|
||||
|
||||
//inherited wireframe definition, disabled by default
|
||||
if (obj.getProperty(MeshThreeFactory.WIREFRAME_ENABLED_KEY).boolean == true) {
|
||||
val material = obj.getProperty(MeshThreeFactory.WIREFRAME_MATERIAL_KEY).node?.jsMaterial() ?: Materials.DEFAULT
|
||||
add(LineSegments(WireframeGeometry(geometry as BufferGeometry), material))
|
||||
}
|
||||
|
||||
//set position for mesh
|
||||
updatePosition(obj)
|
||||
|
||||
layers.enable(obj.layer)
|
||||
children.forEach {
|
||||
it.layers.enable(obj.layer)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsafe invocation of a factory
|
||||
*/
|
||||
@ -82,53 +50,6 @@ operator fun <T : VisualObject3D> ThreeFactory<T>.invoke(obj: Any): Object3D {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic geometry-based factory
|
||||
*/
|
||||
abstract class MeshThreeFactory<T : VisualObject3D>(override val type: KClass<out T>) : ThreeFactory<T> {
|
||||
/**
|
||||
* Build a geometry for an object
|
||||
*/
|
||||
abstract fun buildGeometry(obj: T): BufferGeometry
|
||||
|
||||
|
||||
override fun invoke(obj: T): Mesh {
|
||||
//create mesh from geometry
|
||||
return buildMesh(obj) { buildGeometry(it) }
|
||||
}
|
||||
|
||||
companion object {
|
||||
val EDGES_KEY = "edges".asName()
|
||||
val WIREFRAME_KEY = "wireframe".asName()
|
||||
val ENABLED_KEY = "enabled".asName()
|
||||
val EDGES_ENABLED_KEY = EDGES_KEY + ENABLED_KEY
|
||||
val EDGES_MATERIAL_KEY = EDGES_KEY + MATERIAL_KEY
|
||||
val WIREFRAME_ENABLED_KEY = WIREFRAME_KEY + ENABLED_KEY
|
||||
val WIREFRAME_MATERIAL_KEY = WIREFRAME_KEY + MATERIAL_KEY
|
||||
|
||||
fun <T : VisualObject3D> buildMesh(obj: T, geometryBuilder: (T) -> BufferGeometry): Mesh {
|
||||
//TODO add caching for geometries using templates
|
||||
val geometry = geometryBuilder(obj)
|
||||
|
||||
//JS sometimes tries to pass Geometry as BufferGeometry
|
||||
@Suppress("USELESS_IS_CHECK") if (geometry !is BufferGeometry) error("BufferGeometry expected")
|
||||
|
||||
val mesh = Mesh(geometry, obj.material.jsMaterial())
|
||||
|
||||
mesh.updateFrom(obj)
|
||||
|
||||
//add listener to object properties
|
||||
obj.onPropertyChange(this) { name, _, _ ->
|
||||
mesh.updateProperty(obj, name)
|
||||
if (name.startsWith(GEOMETRY_KEY)) {
|
||||
mesh.geometry = geometryBuilder(obj)
|
||||
}
|
||||
}
|
||||
return mesh
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun Object3D.updateProperty(source: VisualObject, propertyName: Name) {
|
||||
if (this is Mesh && propertyName.startsWith(MATERIAL_KEY)) {
|
||||
//updated material
|
||||
|
@ -0,0 +1,32 @@
|
||||
package hep.dataforge.vis.spatial.three
|
||||
|
||||
import hep.dataforge.vis.spatial.PolyLine
|
||||
import hep.dataforge.vis.spatial.layer
|
||||
import hep.dataforge.vis.spatial.material
|
||||
import info.laht.threekt.core.Geometry
|
||||
import info.laht.threekt.core.Object3D
|
||||
import info.laht.threekt.objects.LineSegments
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
object ThreeLineFactory : ThreeFactory<PolyLine> {
|
||||
override val type: KClass<out PolyLine> get() = PolyLine::class
|
||||
|
||||
override fun invoke(obj: PolyLine): Object3D {
|
||||
val geometry = Geometry().apply {
|
||||
vertices = obj.points.toTypedArray()
|
||||
}
|
||||
|
||||
val material = obj.material.jsLineMaterial()
|
||||
return LineSegments(geometry, material).apply {
|
||||
|
||||
updatePosition(obj)
|
||||
layers.enable(obj.layer)
|
||||
|
||||
//add listener to object properties
|
||||
obj.onPropertyChange(this) { propertyName, _, _ ->
|
||||
updateProperty(obj, propertyName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -33,6 +33,7 @@ class ThreePlugin : AbstractPlugin() {
|
||||
objectFactories[Convex::class] = ThreeConvexFactory
|
||||
objectFactories[Sphere::class] = ThreeSphereFactory
|
||||
objectFactories[ConeSegment::class] = ThreeCylinderFactory
|
||||
objectFactories[PolyLine::class] = ThreeLineFactory
|
||||
}
|
||||
|
||||
private fun findObjectFactory(type: KClass<out VisualObject3D>): ThreeFactory<*>? {
|
||||
|
@ -28,7 +28,10 @@
|
||||
package info.laht.threekt.objects
|
||||
|
||||
import info.laht.threekt.core.BufferGeometry
|
||||
import info.laht.threekt.core.Geometry
|
||||
import info.laht.threekt.core.Object3D
|
||||
import info.laht.threekt.materials.Material
|
||||
|
||||
open external class LineSegments(geometry: BufferGeometry, material: Material) : Object3D
|
||||
open external class LineSegments(geometry: BufferGeometry, material: Material) : Object3D {
|
||||
constructor(geometry: Geometry, material: Material)
|
||||
}
|
@ -130,6 +130,21 @@ private class ThreeDemoApp : ApplicationBase() {
|
||||
}
|
||||
}
|
||||
}
|
||||
demo("lines", "Track / line segments") {
|
||||
sphere(100) {
|
||||
color(Colors.blue)
|
||||
detail = 50
|
||||
opacity = 0.4
|
||||
}
|
||||
repeat(20) {
|
||||
polyline(Point3D(100, 100, 100), Point3D(-100, -100, -100)) {
|
||||
thickness = 208.0
|
||||
rotationX = it * PI2 / 20
|
||||
color(Colors.green)
|
||||
//rotationY = it * PI2 / 20
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user