From a7841edb3c9d09e13bb26324d3e30395d6858aaf Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Wed, 30 Jun 2021 18:39:56 +0300 Subject: [PATCH 01/29] Hide detail property for solids --- .../kotlin/space/kscience/visionforge/solid/Solid.kt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solid.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solid.kt index d7d03c90..fda8531e 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solid.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solid.kt @@ -72,6 +72,11 @@ public interface Solid : Vision { hide() } + value(DETAIL_KEY){ + type(ValueType.NUMBER) + hide() + } + item(SolidMaterial.MATERIAL_KEY.toString(), SolidMaterial.descriptor) enum(ROTATION_ORDER_KEY, default = RotationOrder.XYZ) { From 3fdd0d62d4b2d66a8e534842bb4408cb159e50fc Mon Sep 17 00:00:00 2001 From: kiruma524 <71787194+kiruma524@users.noreply.github.com> Date: Fri, 9 Jul 2021 18:23:56 +0300 Subject: [PATCH 02/29] Update OrbitControls.kt --- .../kscience/visionforge/solid/OrbitControls.kt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/OrbitControls.kt b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/OrbitControls.kt index 47c3c8e8..a32e44f5 100644 --- a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/OrbitControls.kt +++ b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/OrbitControls.kt @@ -59,13 +59,13 @@ class OrbitControls internal constructor(camera: Camera, canvas: SubScene, spec: private val ry = Rotate(0.0, Rotate.Y_AXIS) - private val translate = Translate() + private val rz = Rotate(0.0, Rotate.Z_AXIS) - //private val rz = Rotate(180.0, Rotate.Z_AXIS) + private val translate = Translate() init { - camera.transforms.setAll(ry, rx, translate) + camera.transforms.setAll(rx, ry, rz, translate) update() val listener = InvalidationListener { update() @@ -143,8 +143,8 @@ class OrbitControls internal constructor(camera: Camera, canvas: SubScene, spec: mouseOldY = mousePosY mousePosX = me.sceneX mousePosY = me.sceneY - mouseDeltaX = mousePosX - mouseOldX - mouseDeltaY = mousePosY - mouseOldY + mouseDeltaX = mouseOldX - mousePosX + mouseDeltaY = mouseOldY - mousePosY val modifier = when { me.isControlDown -> CONTROL_MULTIPLIER @@ -176,4 +176,4 @@ class OrbitControls internal constructor(camera: Camera, canvas: SubScene, spec: } fun Camera.orbitControls(canvas: SubScene, spec: CameraSpec) = - OrbitControls(this, canvas, spec) \ No newline at end of file + OrbitControls(this, canvas, spec) From 199cad1dc162b087d4867806b8c62f6368f09f27 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sat, 10 Jul 2021 16:51:57 +0300 Subject: [PATCH 03/29] Refactor to ThreeJS v 130 --- .../ru/mipt/npm/muon/monitor/Monitor.kt | 14 +-- .../ru/mipt/npm/muon/monitor/sim/Pixel.kt | 20 ++-- .../ru/mipt/npm/muon/monitor/sim/line.kt | 2 +- .../ru/mipt/npm/muon/monitor/sim/monitor.kt | 8 +- .../mipt/npm/muon/monitor/sim/simulation.kt | 12 +- .../playground/src/jvmMain/kotlin/gdmlIaxo.kt | 3 +- .../visionforge/solid/demo/VariableBox.kt | 4 +- .../visionforge-gdml-jupyter/build.gradle.kts | 16 ++- settings.gradle.kts | 2 - .../space/kscience/visionforge/VisionGroup.kt | 1 + .../kscience/visionforge/solid/FXCanvas3D.kt | 42 +++---- .../visionforge/solid/FXConvexFactory.kt | 5 +- .../visionforge/solid/OrbitControls.kt | 53 +++++---- .../visionforge/gdml/GdmlTransformerEnv.kt | 12 +- .../space/kscience/visionforge/solid/Solid.kt | 18 +-- .../kscience/visionforge/solid/geometry.kt | 45 ++++++-- visionforge-threejs/build.gradle.kts | 4 +- .../info/laht/threekt/core/BufferAttribute.kt | 34 ++++++ .../info/laht/threekt/core/BufferGeometry.kt | 6 +- .../info/laht/threekt/core/DirectGeometry.kt | 48 -------- .../kotlin/info/laht/threekt/core/Geometry.kt | 109 ------------------ .../laht/threekt/geometries/BoxGeometry.kt | 11 -- .../laht/threekt/geometries/ConeGeometry.kt | 12 +- .../threekt/geometries/CylinderGeometry.kt | 12 -- .../laht/threekt/geometries/EdgesGeometry.kt | 5 +- ...ExtrudedGeometry.kt => ExtrudeGeometry.kt} | 13 --- .../laht/threekt/geometries/PlaneGeometry.kt | 10 -- .../laht/threekt/geometries/SphereGeometry.kt | 11 -- ...{TextBufferGeometry.kt => TextGeometry.kt} | 7 +- .../laht/threekt/geometries/TorusGeometry.kt | 10 +- .../laht/threekt/geometries/TubeGeometry.kt | 21 +--- .../threekt/geometries/WireframeGeometry.kt | 8 +- .../info/laht/threekt/objects/LineSegments.kt | 2 - .../kotlin/info/laht/threekt/objects/Mesh.kt | 10 +- .../solid/three/MeshThreeFactory.kt | 3 - .../solid/three/ThreeBoxFactory.kt | 8 +- .../solid/three/ThreeCanvasLabelFactory.kt | 4 +- .../solid/three/ThreeCompositeFactory.kt | 3 +- .../solid/three/ThreeConeFactory.kt | 6 +- .../visionforge/solid/three/ThreeFactory.kt | 8 +- .../solid/three/ThreeGeometryBuilder.kt | 63 +++++----- .../solid/three/ThreeLineFactory.kt | 6 +- .../solid/three/ThreeSphereFactory.kt | 6 +- .../kscience/visionforge/solid/three/csg.kt | 84 +++++++------- .../kscience/visionforge/solid/three/three.kt | 44 +------ 45 files changed, 304 insertions(+), 521 deletions(-) delete mode 100644 visionforge-threejs/src/main/kotlin/info/laht/threekt/core/DirectGeometry.kt delete mode 100644 visionforge-threejs/src/main/kotlin/info/laht/threekt/core/Geometry.kt rename visionforge-threejs/src/main/kotlin/info/laht/threekt/geometries/{ExtrudedGeometry.kt => ExtrudeGeometry.kt} (83%) rename visionforge-threejs/src/main/kotlin/info/laht/threekt/geometries/{TextBufferGeometry.kt => TextGeometry.kt} (83%) diff --git a/demo/muon-monitor/src/commonMain/kotlin/ru/mipt/npm/muon/monitor/Monitor.kt b/demo/muon-monitor/src/commonMain/kotlin/ru/mipt/npm/muon/monitor/Monitor.kt index e87a2abc..17d5ac86 100644 --- a/demo/muon-monitor/src/commonMain/kotlin/ru/mipt/npm/muon/monitor/Monitor.kt +++ b/demo/muon-monitor/src/commonMain/kotlin/ru/mipt/npm/muon/monitor/Monitor.kt @@ -11,7 +11,7 @@ import space.kscience.visionforge.solid.plus class SC1( val name: String, val center: Point3D, - val xSize: Double = PIXEL_XY_SIZE, val ySize: Double = PIXEL_XY_SIZE, val zSize: Double = PIXEL_Z_SIZE + val xSize: Float = PIXEL_XY_SIZE, val ySize: Float = PIXEL_XY_SIZE, val zSize: Float = PIXEL_Z_SIZE ) class SC16( @@ -121,12 +121,12 @@ internal expect fun readMonitorConfig(): String object Monitor { const val GEOMETRY_TOLERANCE = 0.01 - const val PIXEL_XY_SIZE = 122.0 - const val PIXEL_XY_SPACING = 123.2 - const val PIXEL_Z_SIZE = 30.0 - const val CENTRAL_LAYER_Z = 0.0 - const val UPPER_LAYER_Z = -166.0 - const val LOWER_LAYER_Z = 180.0 + const val PIXEL_XY_SIZE = 122.0f + const val PIXEL_XY_SPACING = 123.2f + const val PIXEL_Z_SIZE = 30.0f + const val CENTRAL_LAYER_Z = 0.0f + const val UPPER_LAYER_Z = -166.0f + const val LOWER_LAYER_Z = 180.0f /** * Build map for the whole monitor diff --git a/demo/muon-monitor/src/jvmMain/kotlin/ru/mipt/npm/muon/monitor/sim/Pixel.kt b/demo/muon-monitor/src/jvmMain/kotlin/ru/mipt/npm/muon/monitor/sim/Pixel.kt index 71a96647..579bca15 100644 --- a/demo/muon-monitor/src/jvmMain/kotlin/ru/mipt/npm/muon/monitor/sim/Pixel.kt +++ b/demo/muon-monitor/src/jvmMain/kotlin/ru/mipt/npm/muon/monitor/sim/Pixel.kt @@ -17,19 +17,19 @@ import kotlin.random.Random internal class SC1Aux(val sc: SC1, var efficiency: Double = 1.0) { // val layer: Layer = findLayer(center.z); private val upLayer = - findLayer(sc.center.z + sc.zSize / 2.0)//Layer("${name}_up", center.z + zSize / 2.0); + findLayer(sc.center.z + sc.zSize / 2f)//Layer("${name}_up", center.z + zSize / 2.0); private val bottomLayer = - findLayer(sc.center.z - sc.zSize / 2.0)//Layer("${name}_bottom", center.z - zSize / 2.0); + findLayer(sc.center.z - sc.zSize / 2f)//Layer("${name}_bottom", center.z - zSize / 2.0); private val centralLayer = findLayer(sc.center.z) - private val center = Vector3D(sc.center.x, sc.center.y, sc.center.z) + private val center = Vector3D(sc.center.x.toDouble(), sc.center.y.toDouble(), sc.center.z.toDouble()) private val sideLayers: Array = arrayOf( - Plane(center.add(Vector3D(PIXEL_XY_SIZE / 2, 0.0, 0.0)), Vector3D(1.0, 0.0, 0.0), GEOMETRY_TOLERANCE), - Plane(center.add(Vector3D(-PIXEL_XY_SIZE / 2, 0.0, 0.0)), Vector3D(-1.0, 0.0, 0.0), GEOMETRY_TOLERANCE), - Plane(center.add(Vector3D(0.0, PIXEL_XY_SIZE / 2, 0.0)), Vector3D(0.0, 1.0, 0.0), GEOMETRY_TOLERANCE), - Plane(center.add(Vector3D(0.0, -PIXEL_XY_SIZE / 2, 0.0)), Vector3D(0.0, -1.0, 0.0), GEOMETRY_TOLERANCE) - ); + Plane(center.add(Vector3D(PIXEL_XY_SIZE / 2.0, 0.0, 0.0)), Vector3D(1.0, 0.0, 0.0), GEOMETRY_TOLERANCE), + Plane(center.add(Vector3D(-PIXEL_XY_SIZE / 2.0, 0.0, 0.0)), Vector3D(-1.0, 0.0, 0.0), GEOMETRY_TOLERANCE), + Plane(center.add(Vector3D(0.0, PIXEL_XY_SIZE / 2.0, 0.0)), Vector3D(0.0, 1.0, 0.0), GEOMETRY_TOLERANCE), + Plane(center.add(Vector3D(0.0, -PIXEL_XY_SIZE / 2.0, 0.0)), Vector3D(0.0, -1.0, 0.0), GEOMETRY_TOLERANCE) + ) //TODO add efficiency private fun containsPoint(x: Double, y: Double, z: Double, tolerance: Double = GEOMETRY_TOLERANCE): Boolean { @@ -63,8 +63,8 @@ internal class SC1Aux(val sc: SC1, var efficiency: Double = 1.0) { * The layer number from up to bottom */ fun getLayerNumber(): Int { - return when (this.center.z) { - UPPER_LAYER_Z -> 1; + return when (this.center.z.toFloat()) { + UPPER_LAYER_Z -> 1 CENTRAL_LAYER_Z -> 2; LOWER_LAYER_Z -> 3; else -> throw RuntimeException("Unknown layer"); diff --git a/demo/muon-monitor/src/jvmMain/kotlin/ru/mipt/npm/muon/monitor/sim/line.kt b/demo/muon-monitor/src/jvmMain/kotlin/ru/mipt/npm/muon/monitor/sim/line.kt index de704441..c2578783 100644 --- a/demo/muon-monitor/src/jvmMain/kotlin/ru/mipt/npm/muon/monitor/sim/line.kt +++ b/demo/muon-monitor/src/jvmMain/kotlin/ru/mipt/npm/muon/monitor/sim/line.kt @@ -45,7 +45,7 @@ fun makeTrack(start: Vector3D, direction: Vector3D): Line { fun makeTrack(x: Double, y: Double, theta: Double, phi: Double): Line { //TODO check angle definitions return makeTrack( - Vector3D(x, y, CENTRAL_LAYER_Z), + Vector3D(x, y, CENTRAL_LAYER_Z.toDouble()), Vector3D(phi, theta) ) } diff --git a/demo/muon-monitor/src/jvmMain/kotlin/ru/mipt/npm/muon/monitor/sim/monitor.kt b/demo/muon-monitor/src/jvmMain/kotlin/ru/mipt/npm/muon/monitor/sim/monitor.kt index a4e83c8b..d2ec7235 100644 --- a/demo/muon-monitor/src/jvmMain/kotlin/ru/mipt/npm/muon/monitor/sim/monitor.kt +++ b/demo/muon-monitor/src/jvmMain/kotlin/ru/mipt/npm/muon/monitor/sim/monitor.kt @@ -13,12 +13,12 @@ import ru.mipt.npm.muon.monitor.readResource internal const val MINIMAL_TRACK_LENGTH = 10.0 -private val layerCache = HashMap() +private val layerCache = HashMap() -fun findLayer(z: Double): Plane = layerCache.getOrPut(z) { +fun findLayer(z: Float): Plane = layerCache.getOrPut(z) { Plane( - Vector3D(0.0, 0.0, z), Vector3D(0.0, 0.0, 1.0), - Monitor.GEOMETRY_TOLERANCE + Vector3D(0.0, 0.0, z.toDouble()), Vector3D(0.0, 0.0, 1.0), + Monitor.GEOMETRY_TOLERANCE.toDouble() ) } diff --git a/demo/muon-monitor/src/jvmMain/kotlin/ru/mipt/npm/muon/monitor/sim/simulation.kt b/demo/muon-monitor/src/jvmMain/kotlin/ru/mipt/npm/muon/monitor/sim/simulation.kt index 6019a94a..f8d45fd4 100644 --- a/demo/muon-monitor/src/jvmMain/kotlin/ru/mipt/npm/muon/monitor/sim/simulation.kt +++ b/demo/muon-monitor/src/jvmMain/kotlin/ru/mipt/npm/muon/monitor/sim/simulation.kt @@ -28,8 +28,8 @@ interface TrackGenerator { */ class UniformTrackGenerator( override val rnd: RandomGenerator, - val maxX: Double = 4 * PIXEL_XY_SIZE, - val maxY: Double = 4 * PIXEL_XY_SIZE + val maxX: Float = 4 * PIXEL_XY_SIZE, + val maxY: Float = 4 * PIXEL_XY_SIZE ) : TrackGenerator { override fun generate(): Line { @@ -44,8 +44,8 @@ class UniformTrackGenerator( class FixedAngleGenerator( override val rnd: RandomGenerator, val phi: Double, val theta: Double, - val maxX: Double = 4 * PIXEL_XY_SIZE, - val maxY: Double = 4 * PIXEL_XY_SIZE + val maxX: Float = 4 * PIXEL_XY_SIZE, + val maxY: Float = 4 * PIXEL_XY_SIZE ) : TrackGenerator { override fun generate(): Line { val x = (1 - rnd.nextDouble() * 2.0) * maxX @@ -60,8 +60,8 @@ class FixedAngleGenerator( class Cos2TrackGenerator( override val rnd: RandomGenerator, val power: Double = 2.0, - val maxX: Double = 4 * PIXEL_XY_SIZE, - val maxY: Double = 4 * PIXEL_XY_SIZE + val maxX: Float = 4 * PIXEL_XY_SIZE, + val maxY: Float = 4 * PIXEL_XY_SIZE ) : TrackGenerator { override fun generate(): Line { diff --git a/demo/playground/src/jvmMain/kotlin/gdmlIaxo.kt b/demo/playground/src/jvmMain/kotlin/gdmlIaxo.kt index a9070af7..fc2ebce3 100644 --- a/demo/playground/src/jvmMain/kotlin/gdmlIaxo.kt +++ b/demo/playground/src/jvmMain/kotlin/gdmlIaxo.kt @@ -3,6 +3,7 @@ package space.kscience.visionforge.examples import space.kscience.dataforge.context.Context import space.kscience.gdml.GdmlShowCase import space.kscience.visionforge.gdml.toVision +import space.kscience.visionforge.html.ResourceLocation import space.kscience.visionforge.solid.Solids fun main() { @@ -10,7 +11,7 @@ fun main() { plugin(Solids) } - context.makeVisionFile { + context.makeVisionFile(resourceLocation = ResourceLocation.EMBED) { vision("canvas") { GdmlShowCase.babyIaxo().toVision() } } } \ No newline at end of file diff --git a/demo/solid-showcase/src/jsMain/kotlin/space/kscience/visionforge/solid/demo/VariableBox.kt b/demo/solid-showcase/src/jsMain/kotlin/space/kscience/visionforge/solid/demo/VariableBox.kt index e3961775..f372fa38 100644 --- a/demo/solid-showcase/src/jsMain/kotlin/space/kscience/visionforge/solid/demo/VariableBox.kt +++ b/demo/solid-showcase/src/jsMain/kotlin/space/kscience/visionforge/solid/demo/VariableBox.kt @@ -1,7 +1,7 @@ package space.kscience.visionforge.solid.demo import info.laht.threekt.core.Object3D -import info.laht.threekt.geometries.BoxBufferGeometry +import info.laht.threekt.geometries.BoxGeometry import info.laht.threekt.objects.Mesh import space.kscience.dataforge.meta.int import space.kscience.dataforge.meta.number @@ -26,7 +26,7 @@ internal fun SolidGroup.varBox( internal class VariableBox(val xSize: Number, val ySize: Number) : ThreeVision() { override fun render(three: ThreePlugin): Object3D { - val geometry = BoxBufferGeometry(xSize, ySize, 1) + val geometry = BoxGeometry(xSize, ySize, 1) val material = ThreeMaterials.DEFAULT.clone() diff --git a/jupyter/visionforge-gdml-jupyter/build.gradle.kts b/jupyter/visionforge-gdml-jupyter/build.gradle.kts index e2d1db03..896b44a4 100644 --- a/jupyter/visionforge-gdml-jupyter/build.gradle.kts +++ b/jupyter/visionforge-gdml-jupyter/build.gradle.kts @@ -4,9 +4,9 @@ plugins { description = "Jupyter api artifact for GDML rendering" -kotlin{ +kotlin { explicitApi = null - js{ + js { useCommonJs() browser { webpackTask { @@ -25,19 +25,17 @@ kotlin{ tasks.getByName("jvmProcessResources") { dependsOn(jsBrowserDistribution) - afterEvaluate { - from(jsBrowserDistribution) - } + from(jsBrowserDistribution) } } - sourceSets{ + sourceSets { commonMain { dependencies { api(project(":visionforge-solid")) } } - jvmMain{ + jvmMain { dependencies { implementation(project(":visionforge-gdml")) } @@ -52,10 +50,10 @@ kotlin{ } } -kscience{ +kscience { useJupyter() } -readme{ +readme { maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL } \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index bc62b31e..6311841e 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -16,8 +16,6 @@ pluginManagement { } } -//enableFeaturePreview("GRADLE_METADATA") - rootProject.name = "visionforge" diff --git a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionGroup.kt b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionGroup.kt index 4f16982b..6b35d971 100644 --- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionGroup.kt +++ b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionGroup.kt @@ -58,6 +58,7 @@ public operator fun VisionGroup.iterator(): Iterator = children.values.i public val VisionGroup.isEmpty: Boolean get() = this.children.isEmpty() public interface VisionContainerBuilder { + //TODO add documentation public operator fun set(name: Name?, child: V?) } diff --git a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/FXCanvas3D.kt b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/FXCanvas3D.kt index 171bc5a3..a05c844a 100644 --- a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/FXCanvas3D.kt +++ b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/FXCanvas3D.kt @@ -4,6 +4,7 @@ import javafx.application.Platform import javafx.beans.property.ObjectProperty import javafx.beans.property.SimpleObjectProperty import javafx.scene.* +import javafx.scene.layout.BorderPane import javafx.scene.paint.Color import org.fxyz3d.scene.Axes import space.kscience.dataforge.context.Context @@ -11,31 +12,32 @@ import space.kscience.dataforge.context.ContextAware import space.kscience.visionforge.solid.specifications.Canvas3DOptions import tornadofx.* -class FXCanvas3D( - val plugin: FX3DPlugin, - val spec: Canvas3DOptions = Canvas3DOptions.empty(), +public class FXCanvas3D( + public val fx3d: FX3DPlugin, + public val options: Canvas3DOptions = Canvas3DOptions.empty(), ) : Fragment(), ContextAware { - override val context: Context get() = plugin.context + override val context: Context get() = fx3d.context - val world = Group().apply { + public val world: Group = Group().apply { //transforms.add(Rotate(180.0, Rotate.Z_AXIS)) } - val axes = Axes().also { - it.setHeight(spec.axes.size) - it.setRadius(spec.axes.width) - it.isVisible = spec.axes.visible + public val axes: Axes = Axes().also { + it.setHeight(options.axes.size) + it.setRadius(options.axes.width) + it.isVisible = options.axes.visible world.add(it) } - val light = AmbientLight() + public val light: AmbientLight = AmbientLight() private val camera = PerspectiveCamera().apply { - nearClip = spec.camera.nearClip - farClip = spec.camera.farClip - fieldOfView = spec.camera.fov.toDouble() - this.add(light) + nearClip = options.camera.nearClip + farClip = options.camera.farClip + fieldOfView = options.camera.fov.toDouble() + + add(light) } private val canvas = SubScene( @@ -49,19 +51,19 @@ class FXCanvas3D( scene.camera = camera } - override val root = borderpane { + override val root: BorderPane = borderpane { center = canvas } - val controls = camera.orbitControls(canvas, spec.camera).also { + public val controls: OrbitControls = camera.orbitControls(canvas, options.camera).also { world.add(it.centerMarker) } - val rootObjectProperty: ObjectProperty = SimpleObjectProperty() - var rootObject: Solid? by rootObjectProperty + public val rootObjectProperty: ObjectProperty = SimpleObjectProperty() + public var rootObject: Solid? by rootObjectProperty private val rootNodeProperty = rootObjectProperty.objectBinding { - it?.let { plugin.buildNode(it) } + it?.let { fx3d.buildNode(it) } } init { @@ -79,7 +81,7 @@ class FXCanvas3D( } } - fun render(vision: Solid) { + public fun render(vision: Solid) { rootObject = vision } } \ No newline at end of file diff --git a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/FXConvexFactory.kt b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/FXConvexFactory.kt index f2bbba54..7538d6c6 100644 --- a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/FXConvexFactory.kt +++ b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/FXConvexFactory.kt @@ -11,7 +11,10 @@ object FXConvexFactory : FX3DFactory { override val type: KClass get() = Convex::class override fun invoke(obj: Convex, binding: VisualObjectFXBinding): Node { - val hull = HullUtil.hull(obj.points.map { Vector3d.xyz(it.x, it.y, it.z) }, PropertyStorage()) + val hull = HullUtil.hull( + obj.points.map { Vector3d.xyz(it.x.toDouble(), it.y.toDouble(), it.z.toDouble()) }, + PropertyStorage() + ) return hull.toNode() } diff --git a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/OrbitControls.kt b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/OrbitControls.kt index a32e44f5..38a04a16 100644 --- a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/OrbitControls.kt +++ b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/OrbitControls.kt @@ -1,6 +1,7 @@ package space.kscience.visionforge.solid import javafx.beans.InvalidationListener +import javafx.beans.property.SimpleBooleanProperty import javafx.beans.property.SimpleDoubleProperty import javafx.event.EventHandler import javafx.geometry.Point3D @@ -17,26 +18,26 @@ import kotlin.math.* import space.kscience.visionforge.solid.specifications.Camera as CameraSpec -class OrbitControls internal constructor(camera: Camera, canvas: SubScene, spec: CameraSpec) { +public class OrbitControls internal constructor(camera: Camera, canvas: SubScene, spec: CameraSpec) { - val distanceProperty = SimpleDoubleProperty(spec.distance) - var distance by distanceProperty + public val distanceProperty: SimpleDoubleProperty = SimpleDoubleProperty(spec.distance) + public var distance: Double by distanceProperty - val azimuthProperty = SimpleDoubleProperty(spec.azimuth) - var azimuth by azimuthProperty + public val azimuthProperty: SimpleDoubleProperty = SimpleDoubleProperty(spec.azimuth) + public var azimuth: Double by azimuthProperty - val zenithProperty = SimpleDoubleProperty(PI / 2 - spec.latitude) - var zenith by zenithProperty + public val zenithProperty: SimpleDoubleProperty = SimpleDoubleProperty(PI / 2 - spec.latitude) + public var zenith: Double by zenithProperty +// +// public val latitudeProperty: DoubleBinding = zenithProperty.unaryMinus().plus(PI / 2) +// public val latitude by latitudeProperty - val latitudeProperty = zenithProperty.unaryMinus().plus(PI / 2) - val latitude by latitudeProperty - - val baseXProperty = SimpleDoubleProperty(0.0) - var x by baseXProperty - val baseYProperty = SimpleDoubleProperty(0.0) - var y by baseYProperty - val baseZProperty = SimpleDoubleProperty(0.0) - var z by baseZProperty + public val baseXProperty: SimpleDoubleProperty = SimpleDoubleProperty(0.0) + public var x: Double by baseXProperty + public val baseYProperty: SimpleDoubleProperty = SimpleDoubleProperty(0.0) + public var y: Double by baseYProperty + public val baseZProperty: SimpleDoubleProperty = SimpleDoubleProperty(0.0) + public var z: Double by baseZProperty private val baseTranslate = Translate() @@ -47,13 +48,15 @@ class OrbitControls internal constructor(camera: Camera, canvas: SubScene, spec: // // val basePosition by basePositionProperty - val centerMarker by lazy { + private val inProgressProperty = SimpleBooleanProperty(false) + + public val centerMarker: Node by lazy { Sphere(10.0).also { it.transforms.setAll(baseTranslate) + it.visibleProperty().bind(inProgressProperty) } } - //private val center = Translate() private val rx = Rotate(0.0, Rotate.X_AXIS) @@ -65,7 +68,7 @@ class OrbitControls internal constructor(camera: Camera, canvas: SubScene, spec: init { - camera.transforms.setAll(rx, ry, rz, translate) + camera.transforms.setAll(rx, ry, rz, baseTranslate, translate) update() val listener = InvalidationListener { update() @@ -136,6 +139,7 @@ class OrbitControls internal constructor(camera: Camera, canvas: SubScene, spec: mousePosY = me.sceneY mouseOldX = me.sceneX mouseOldY = me.sceneY + inProgressProperty.set(true) } onMouseDragged = EventHandler { me -> @@ -154,18 +158,23 @@ class OrbitControls internal constructor(camera: Camera, canvas: SubScene, spec: if (me.isPrimaryButtonDown) { azimuth = (azimuth - mouseDeltaX * MOUSE_SPEED * modifier * ROTATION_SPEED).coerceIn(0.0, 2 * PI) - zenith = (zenith - mouseDeltaY * MOUSE_SPEED * modifier * ROTATION_SPEED).coerceIn(0.0,PI) + zenith = (zenith - mouseDeltaY * MOUSE_SPEED * modifier * ROTATION_SPEED).coerceIn(0.0, PI) } else if (me.isSecondaryButtonDown) { x += MOUSE_SPEED * modifier * TRACK_SPEED * (mouseDeltaX * cos(azimuth) + mouseDeltaY * sin(azimuth)) z += MOUSE_SPEED * modifier * TRACK_SPEED * (-mouseDeltaX * sin(azimuth) + mouseDeltaY * cos(azimuth)) } } + + onMouseReleased = EventHandler { + inProgressProperty.set(false) + } + onScroll = EventHandler { event -> distance = max(1.0, distance - MOUSE_SPEED * event.deltaY * RESIZE_SPEED) } } - companion object { + public companion object { private const val CONTROL_MULTIPLIER = 0.1 private const val SHIFT_MULTIPLIER = 10.0 private const val MOUSE_SPEED = 0.1 @@ -175,5 +184,5 @@ class OrbitControls internal constructor(camera: Camera, canvas: SubScene, spec: } } -fun Camera.orbitControls(canvas: SubScene, spec: CameraSpec) = +public fun Camera.orbitControls(canvas: SubScene, spec: CameraSpec): OrbitControls = OrbitControls(this, canvas, spec) diff --git a/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/GdmlTransformerEnv.kt b/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/GdmlTransformerEnv.kt index ef41a214..76561fe8 100644 --- a/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/GdmlTransformerEnv.kt +++ b/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/GdmlTransformerEnv.kt @@ -41,7 +41,7 @@ public class GdmlTransformer { internal val styleCache = HashMap() - public fun Solid.useStyle(name: String, builder: MetaBuilder.() -> Unit) { + public fun Solid.registerAndUseStyle(name: String, builder: MetaBuilder.() -> Unit) { styleCache.getOrPut(name.toName()) { Meta(builder) } @@ -49,7 +49,7 @@ public class GdmlTransformer { } public fun Solid.transparent() { - useStyle("transparent") { + registerAndUseStyle("transparent") { SolidMaterial.MATERIAL_OPACITY_KEY put 0.3 "edges.enabled" put true } @@ -75,7 +75,7 @@ public class GdmlTransformer { if (parent.physVolumes.isNotEmpty()) transparent() - useStyle(styleName) { + registerAndUseStyle(styleName) { val vfMaterial = SolidMaterial().apply { configurePaint(material, solid) } @@ -125,7 +125,11 @@ private class GdmlTransformerEnv(val settings: GdmlTransformer) { fun Solid.configureSolid(root: Gdml, parent: GdmlVolume, solid: GdmlSolid) { val material = parent.materialref.resolve(root) ?: GdmlElement(parent.materialref.ref) - settings.run { configureSolid(parent, solid, material) } + with(settings) { + with(this@configureSolid) { + configureSolid(parent, solid, material) + } + } } private fun proxySolid(root: Gdml, group: SolidGroup, solid: GdmlSolid, name: String): SolidReferenceGroup { diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solid.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solid.kt index fda8531e..9855c835 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solid.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solid.kt @@ -156,21 +156,21 @@ private fun Solid.position(): Point3D = public var Solid.x: Number get() = position?.x ?: 0f set(value) { - position().x = value.toDouble() + position().x = value.toFloat() invalidateProperty(Solid.X_POSITION_KEY) } public var Solid.y: Number get() = position?.y ?: 0f set(value) { - position().y = value.toDouble() + position().y = value.toFloat() invalidateProperty(Solid.Y_POSITION_KEY) } public var Solid.z: Number get() = position?.z ?: 0f set(value) { - position().z = value.toDouble() + position().z = value.toFloat() invalidateProperty(Solid.Z_POSITION_KEY) } @@ -180,21 +180,21 @@ private fun Solid.rotation(): Point3D = public var Solid.rotationX: Number get() = rotation?.x ?: 0f set(value) { - rotation().x = value.toDouble() + rotation().x = value.toFloat() invalidateProperty(Solid.X_ROTATION_KEY) } public var Solid.rotationY: Number get() = rotation?.y ?: 0f set(value) { - rotation().y = value.toDouble() + rotation().y = value.toFloat() invalidateProperty(Solid.Y_ROTATION_KEY) } public var Solid.rotationZ: Number get() = rotation?.z ?: 0f set(value) { - rotation().z = value.toDouble() + rotation().z = value.toFloat() invalidateProperty(Solid.Z_ROTATION_KEY) } @@ -204,20 +204,20 @@ private fun Solid.scale(): Point3D = public var Solid.scaleX: Number get() = scale?.x ?: 1f set(value) { - scale().x = value.toDouble() + scale().x = value.toFloat() invalidateProperty(Solid.X_SCALE_KEY) } public var Solid.scaleY: Number get() = scale?.y ?: 1f set(value) { - scale().y = value.toDouble() + scale().y = value.toFloat() invalidateProperty(Solid.Y_SCALE_KEY) } public var Solid.scaleZ: Number get() = scale?.z ?: 1f set(value) { - scale().z = value.toDouble() + scale().z = value.toFloat() invalidateProperty(Solid.Z_SCALE_KEY) } \ No newline at end of file diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/geometry.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/geometry.kt index 35fc731f..28a90398 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/geometry.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/geometry.kt @@ -3,29 +3,31 @@ package space.kscience.visionforge.solid import kotlinx.serialization.Serializable import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.MetaBuilder -import space.kscience.dataforge.meta.double +import space.kscience.dataforge.meta.float import space.kscience.dataforge.meta.get import kotlin.math.PI +import kotlin.math.pow +import kotlin.math.sqrt public const val PI2: Float = 2 * PI.toFloat() @Serializable -public data class Point2D(public var x: Double, public var y: Double) +public data class Point2D(public var x: Float, public var y: Float) -public fun Point2D(x: Number, y: Number): Point2D = Point2D(x.toDouble(), y.toDouble()) +public fun Point2D(x: Number, y: Number): Point2D = Point2D(x.toFloat(), y.toFloat()) public fun Point2D.toMeta(): Meta = Meta { Solid.X_KEY put x Solid.Y_KEY put y } -internal fun Meta.point2D(): Point2D = Point2D(this["x"].double ?: 0.0, this["y"].double ?: 0.0) +internal fun Meta.point2D(): Point2D = Point2D(this["x"].float ?: 0f, this["y"].float ?: 0f) @Serializable public data class Point3D( - public var x: Double, - public var y: Double, - public var z: Double, + public var x: Float, + public var y: Float, + public var z: Float, ) { public companion object { public val ZERO: Point3D = Point3D(0.0, 0.0, 0.0) @@ -33,7 +35,7 @@ public data class Point3D( } } -public fun Point3D(x: Number, y: Number, z: Number): Point3D = Point3D(x.toDouble(), y.toDouble(), z.toDouble()) +public fun Point3D(x: Number, y: Number, z: Number): Point3D = Point3D(x.toFloat(), y.toFloat(), z.toFloat()) public operator fun Point3D.plus(other: Point3D): Point3D = Point3D( this.x + other.x, @@ -41,7 +43,32 @@ public operator fun Point3D.plus(other: Point3D): Point3D = Point3D( this.z + other.z ) -internal fun Meta.point3D() = Point3D(this["x"].double ?: 0.0, this["y"].double ?: 0.0, this["y"].double ?: 0.0) +public operator fun Point3D.minus(other: Point3D): Point3D = Point3D( + this.x - other.x, + this.y - other.y, + this.z - other.z +) + +public operator fun Point3D.unaryMinus(): Point3D = Point3D( + -x, + -y, + -z +) + +public infix fun Point3D.cross(other: Point3D): Point3D = Point3D( + y * other.z - z * other.y, + z * other.x - x * other.z, + x * other.y - y * other.x +) + +public fun Point3D.normalizeInPlace(){ + val norm = sqrt(x.pow(2) + y.pow(2) + z.pow(2)) + x /= norm + y /= norm + z /= norm +} + +internal fun Meta.point3D() = Point3D(this["x"].float ?: 0.0, this["y"].float ?: 0.0, this["y"].float ?: 0.0) public fun Point3D.toMeta(): MetaBuilder = Meta { Solid.X_KEY put x diff --git a/visionforge-threejs/build.gradle.kts b/visionforge-threejs/build.gradle.kts index 60c00061..32803a61 100644 --- a/visionforge-threejs/build.gradle.kts +++ b/visionforge-threejs/build.gradle.kts @@ -4,6 +4,6 @@ plugins { dependencies { api(project(":visionforge-solid")) - implementation(npm("three", "0.124.0")) - implementation(npm("three-csg-ts", "2.2.2")) + implementation(npm("three", "0.130.1")) + implementation(npm("three-csg-ts", "3.1.4")) } diff --git a/visionforge-threejs/src/main/kotlin/info/laht/threekt/core/BufferAttribute.kt b/visionforge-threejs/src/main/kotlin/info/laht/threekt/core/BufferAttribute.kt index 001aa20c..938deb7e 100644 --- a/visionforge-threejs/src/main/kotlin/info/laht/threekt/core/BufferAttribute.kt +++ b/visionforge-threejs/src/main/kotlin/info/laht/threekt/core/BufferAttribute.kt @@ -44,6 +44,7 @@ abstract external class BufferAttribute protected constructor( * Default is 0. Position at whcih to start update. */ var offset: Int + /** * Default is -1, which means don't use update ranges. @@ -56,16 +57,19 @@ abstract external class BufferAttribute protected constructor( * UUID of this object instance. This gets automatically assigned and this shouldn't be edited. */ val uuid: String + /** * Optional name for this attribute instance. Default is an empty string. */ var name: String var array: dynamic + /** * The length of vectors that are being stored in the array. */ val itemSize: Int + /** * Stores the array's length divided by the itemSize. * @@ -73,6 +77,7 @@ abstract external class BufferAttribute protected constructor( * then this will count the number of such vectors stored. */ val count: Int + /** * Indicates how the underlying data in the buffer maps to the values in the GLSL shader code. See the constructor above for details. */ @@ -86,6 +91,7 @@ abstract external class BufferAttribute protected constructor( * This corresponds to the gl.DYNAMIC_DRAW flag. */ var dynamic: Boolean + /** * This can be used to only update some components of stored vectors ( * for example, just the component related to color). @@ -99,8 +105,16 @@ abstract external class BufferAttribute protected constructor( */ var needsUpdate: Boolean + /** + * A callback function that is executed after the Renderer has transferred the attribute array data to the GPU. + */ var onUploadCallback: () -> Unit + /** + * Sets the value of the [onUploadCallback] property. + */ + fun onUpload(callback: () -> Unit) + /** * A version number, incremented every time the needsUpdate property is set to true. */ @@ -119,6 +133,7 @@ abstract external class BufferAttribute protected constructor( fun getW(index: Int): Number fun copy(source: BufferAttribute): BufferAttribute + /** * Copy a vector from bufferAttribute[index2] to array[index1]. */ @@ -205,3 +220,22 @@ abstract external class BufferAttribute protected constructor( */ fun setXYZW(index: Int, x: Number, y: Number, z: Number, w: Number) } + + +external class Float32BufferAttribute( + array: FloatArray, + itemSize: Int, + normalized: Boolean = definedExternally +) : BufferAttribute + +external class Int32BufferAttribute( + array: IntArray, + itemSize: Int, + normalized: Boolean = definedExternally +) : BufferAttribute + +external class Int16BufferAttribute( + array: ShortArray, + itemSize: Int, + normalized: Boolean = definedExternally +) : BufferAttribute \ No newline at end of file diff --git a/visionforge-threejs/src/main/kotlin/info/laht/threekt/core/BufferGeometry.kt b/visionforge-threejs/src/main/kotlin/info/laht/threekt/core/BufferGeometry.kt index c3fd093b..251627a7 100644 --- a/visionforge-threejs/src/main/kotlin/info/laht/threekt/core/BufferGeometry.kt +++ b/visionforge-threejs/src/main/kotlin/info/laht/threekt/core/BufferGeometry.kt @@ -85,14 +85,14 @@ open external class BufferGeometry { fun clearGroups() fun addGroup(start: Int, count: Int, materialIndex: Int = definedExternally) - fun addAttribute(name: String, attribute: BufferAttribute) + fun setAttribute(name: String, attribute: BufferAttribute) fun getAttribute(name: String): BufferAttribute - fun removeAttribute(name: String): BufferGeometry + fun deleteAttribute(name: String): BufferGeometry fun setIndex(index: BufferAttribute) + fun setIndex(index: Array) fun setDrawRange(start: Int, count: Int) - fun fromGeometry(geometry: Geometry) fun setFromObject(`object`: Object3D): BufferGeometry fun updateFromObject(`object`: Object3D): BufferGeometry fun setFromPoints(points: Array): BufferGeometry diff --git a/visionforge-threejs/src/main/kotlin/info/laht/threekt/core/DirectGeometry.kt b/visionforge-threejs/src/main/kotlin/info/laht/threekt/core/DirectGeometry.kt deleted file mode 100644 index bae8ce28..00000000 --- a/visionforge-threejs/src/main/kotlin/info/laht/threekt/core/DirectGeometry.kt +++ /dev/null @@ -1,48 +0,0 @@ -/* - * The MIT License - * - * Copyright 2017-2018 Lars Ivar Hatledal - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -@file:JsModule("three") -@file:JsNonModule - -package info.laht.threekt.core - -import info.laht.threekt.math.Box3 -import info.laht.threekt.math.Sphere - -external class DirectGeometry { - - var verticesNeedUpdate: Boolean - var normalsNeedUpdate: Boolean - var colorsNeedUpdate: Boolean - var uvsNeedUpdate: Boolean - var groupsNeedUpdate: Boolean - - fun computeBoundingBox(): Box3 - fun computeBoundingSphere(): Sphere - - fun dispose() - - fun fromGeometry(geometry: Geometry) - -} \ No newline at end of file diff --git a/visionforge-threejs/src/main/kotlin/info/laht/threekt/core/Geometry.kt b/visionforge-threejs/src/main/kotlin/info/laht/threekt/core/Geometry.kt deleted file mode 100644 index 522ab07c..00000000 --- a/visionforge-threejs/src/main/kotlin/info/laht/threekt/core/Geometry.kt +++ /dev/null @@ -1,109 +0,0 @@ -/* - * The MIT License - * - * Copyright 2017-2018 Lars Ivar Hatledal - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -@file:JsModule("three") -@file:JsNonModule - -package info.laht.threekt.core - -import info.laht.threekt.math.* -import info.laht.threekt.objects.Mesh - -external interface MorphTarget { - val name: String - val vertices: Array -} - -external interface MorphNormal { - val name: String - val normals: Array -} - -open external class Geometry { - - val id: Int - - var vertices: Array - var colors: Array - var faces: Array - var faceVertexUvs: Array> - - var morphTargets: Array - var morphNormals: Array - - var skinWeights: Array - var skinIndices: Array - - var lineDistances: List - - var boundingBox: Box3? - var boundingSphere: Sphere? - - // update flags - - var elementsNeedUpdate: Boolean - var verticesNeedUpdate: Boolean - var uvsNeedUpdate: Boolean - var normalsNeedUpdate: Boolean - var colorsNeedUpdate: Boolean - var lineDistancesNeedUpdate: Boolean - var groupsNeedUpdate: Boolean - - fun applyMatrix4(matrix: Matrix4): Geometry - fun rotateX(angle: Number): Geometry - fun rotateY(angle: Number): Geometry - fun rotateZ(angle: Number): Geometry - fun translate(x: Number, y: Number, z: Number): Geometry - fun scale(x: Number, y: Number, z: Number): Geometry - fun lookAt(vector: Vector3): Geometry - fun fromBufferGeometry(geometry: BufferGeometry): Geometry - fun addFace(a: Int, b: Int, c: Int, materialIndexOffset: Int = definedExternally) - fun center(): Vector3 - fun normalize(): Geometry - fun computeFaceNormals() - fun computeVertexNormals(areaWeighted: Boolean = definedExternally) - fun computeFlatVertexNormals() - fun computeMorphNormals() - fun computeLineDistances() - fun computeBoundingBox() - fun computeBoundingSphere() - - fun merge(geometry: Geometry, matrix: Matrix4 = definedExternally, materialIndexOffset: Int = definedExternally) - - fun mergeMesh(mesh: Mesh) - - fun mergeVertices() - - fun setFromPoint(points: Array): Geometry - - fun sortFacesByMaterialIndex() - - fun toJSON(): Any - - open fun clone(): Geometry - fun copy(geometry: Geometry): Geometry - - fun dispose() - -} diff --git a/visionforge-threejs/src/main/kotlin/info/laht/threekt/geometries/BoxGeometry.kt b/visionforge-threejs/src/main/kotlin/info/laht/threekt/geometries/BoxGeometry.kt index 6cf5d5a7..8d0e5ec5 100644 --- a/visionforge-threejs/src/main/kotlin/info/laht/threekt/geometries/BoxGeometry.kt +++ b/visionforge-threejs/src/main/kotlin/info/laht/threekt/geometries/BoxGeometry.kt @@ -4,7 +4,6 @@ package info.laht.threekt.geometries import info.laht.threekt.core.BufferGeometry -import info.laht.threekt.core.Geometry external class BoxGeometry( @@ -14,14 +13,4 @@ external class BoxGeometry( widthSegments: Int = definedExternally, heightSegments: Int = definedExternally, depthSegments: Int = definedExternally -) : Geometry - - -external class BoxBufferGeometry( - width: Number, - height: Number, - depth: Number, - widthSegments: Int = definedExternally, - heightSegments: Int = definedExternally, - depthSegments: Int = definedExternally ) : BufferGeometry diff --git a/visionforge-threejs/src/main/kotlin/info/laht/threekt/geometries/ConeGeometry.kt b/visionforge-threejs/src/main/kotlin/info/laht/threekt/geometries/ConeGeometry.kt index ae143fa8..f98ad2dd 100644 --- a/visionforge-threejs/src/main/kotlin/info/laht/threekt/geometries/ConeGeometry.kt +++ b/visionforge-threejs/src/main/kotlin/info/laht/threekt/geometries/ConeGeometry.kt @@ -4,7 +4,7 @@ package info.laht.threekt.geometries import info.laht.threekt.core.BufferGeometry -import info.laht.threekt.core.Geometry + external class ConeGeometry( radius: Number = definedExternally, @@ -14,14 +14,4 @@ external class ConeGeometry( openEnded: Boolean = definedExternally, thetaStart: Boolean = definedExternally, thetaLength: Boolean = definedExternally -) : Geometry - -external class ConeBufferGeometry( - radius: Number = definedExternally, - height: Number = definedExternally, - radialSegments: Int = definedExternally, - heightSegments: Int = definedExternally, - openEnded: Boolean = definedExternally, - thetaStart: Boolean = definedExternally, - thetaLength: Boolean = definedExternally ) : BufferGeometry \ No newline at end of file diff --git a/visionforge-threejs/src/main/kotlin/info/laht/threekt/geometries/CylinderGeometry.kt b/visionforge-threejs/src/main/kotlin/info/laht/threekt/geometries/CylinderGeometry.kt index a4801453..b10e5c11 100644 --- a/visionforge-threejs/src/main/kotlin/info/laht/threekt/geometries/CylinderGeometry.kt +++ b/visionforge-threejs/src/main/kotlin/info/laht/threekt/geometries/CylinderGeometry.kt @@ -4,7 +4,6 @@ package info.laht.threekt.geometries import info.laht.threekt.core.BufferGeometry -import info.laht.threekt.core.Geometry external class CylinderGeometry( radiusTop: Number, @@ -15,15 +14,4 @@ external class CylinderGeometry( openEnded: Boolean = definedExternally, thetaStart: Number = definedExternally, thetaLength: Number = definedExternally -) : Geometry - -external class CylinderBufferGeometry( - radiusTop: Number, - radiusBottom: Number, - height: Number, - radialSegments: Int = definedExternally, - heightSegments: Int = definedExternally, - openEnded: Boolean = definedExternally, - thetaStart: Number = definedExternally, - thetaLength: Number = definedExternally ) : BufferGeometry \ No newline at end of file diff --git a/visionforge-threejs/src/main/kotlin/info/laht/threekt/geometries/EdgesGeometry.kt b/visionforge-threejs/src/main/kotlin/info/laht/threekt/geometries/EdgesGeometry.kt index 8e6568da..b0a5c91b 100644 --- a/visionforge-threejs/src/main/kotlin/info/laht/threekt/geometries/EdgesGeometry.kt +++ b/visionforge-threejs/src/main/kotlin/info/laht/threekt/geometries/EdgesGeometry.kt @@ -4,8 +4,5 @@ package info.laht.threekt.geometries import info.laht.threekt.core.BufferGeometry -import info.laht.threekt.core.Geometry -external class EdgesGeometry(geometry: Geometry, thresholdAngle: Int = definedExternally) : BufferGeometry { - constructor(geometry: BufferGeometry, thresholdAngle: Int = definedExternally) -} \ No newline at end of file +public external class EdgesGeometry(geometry: BufferGeometry, thresholdAngle: Int = definedExternally) : BufferGeometry \ No newline at end of file diff --git a/visionforge-threejs/src/main/kotlin/info/laht/threekt/geometries/ExtrudedGeometry.kt b/visionforge-threejs/src/main/kotlin/info/laht/threekt/geometries/ExtrudeGeometry.kt similarity index 83% rename from visionforge-threejs/src/main/kotlin/info/laht/threekt/geometries/ExtrudedGeometry.kt rename to visionforge-threejs/src/main/kotlin/info/laht/threekt/geometries/ExtrudeGeometry.kt index ab17c116..4b30e7af 100644 --- a/visionforge-threejs/src/main/kotlin/info/laht/threekt/geometries/ExtrudedGeometry.kt +++ b/visionforge-threejs/src/main/kotlin/info/laht/threekt/geometries/ExtrudeGeometry.kt @@ -11,7 +11,6 @@ package info.laht.threekt.geometries import info.laht.threekt.core.BufferGeometry -import info.laht.threekt.core.Geometry import info.laht.threekt.extras.core.Shape import info.laht.threekt.math.Vector2 @@ -78,15 +77,3 @@ external open class ExtrudeBufferGeometry : BufferGeometry { var WorldUVGenerator: UVGenerator } } - -external open class ExtrudeGeometry : Geometry { - constructor(shapes: Shape, options: ExtrudeGeometryOptions?) - constructor(shapes: Array, options: ExtrudeGeometryOptions?) - - open fun addShapeList(shapes: Array, options: Any? = definedExternally) - open fun addShape(shape: Shape, options: Any? = definedExternally) - - companion object { - var WorldUVGenerator: UVGenerator - } -} \ No newline at end of file diff --git a/visionforge-threejs/src/main/kotlin/info/laht/threekt/geometries/PlaneGeometry.kt b/visionforge-threejs/src/main/kotlin/info/laht/threekt/geometries/PlaneGeometry.kt index ad758af4..0b1072ef 100644 --- a/visionforge-threejs/src/main/kotlin/info/laht/threekt/geometries/PlaneGeometry.kt +++ b/visionforge-threejs/src/main/kotlin/info/laht/threekt/geometries/PlaneGeometry.kt @@ -4,7 +4,6 @@ package info.laht.threekt.geometries import info.laht.threekt.core.BufferGeometry -import info.laht.threekt.core.Geometry external class PlaneGeometry( @@ -13,13 +12,4 @@ external class PlaneGeometry( widthSegments: Int = definedExternally, heightSegments: Int = definedExternally -) : Geometry - -external class PlaneBufferGeometry( - - width: Number, - height: Number, - widthSegments: Int = definedExternally, - heightSegments: Int = definedExternally - ) : BufferGeometry \ No newline at end of file diff --git a/visionforge-threejs/src/main/kotlin/info/laht/threekt/geometries/SphereGeometry.kt b/visionforge-threejs/src/main/kotlin/info/laht/threekt/geometries/SphereGeometry.kt index 8117ff4c..5b0c9fc6 100644 --- a/visionforge-threejs/src/main/kotlin/info/laht/threekt/geometries/SphereGeometry.kt +++ b/visionforge-threejs/src/main/kotlin/info/laht/threekt/geometries/SphereGeometry.kt @@ -4,7 +4,6 @@ package info.laht.threekt.geometries import info.laht.threekt.core.BufferGeometry -import info.laht.threekt.core.Geometry external class SphereGeometry( radius: Number, @@ -14,14 +13,4 @@ external class SphereGeometry( phiLength: Number = definedExternally, thetaStart: Number = definedExternally, thetaLength: Number = definedExternally -) : Geometry - -external class SphereBufferGeometry( - radius: Number, - widthSegments: Int = definedExternally, - heightSegments: Int = definedExternally, - phiStart: Number = definedExternally, - phiLength: Number = definedExternally, - thetaStart: Number = definedExternally, - thetaLength: Number = definedExternally ) : BufferGeometry \ No newline at end of file diff --git a/visionforge-threejs/src/main/kotlin/info/laht/threekt/geometries/TextBufferGeometry.kt b/visionforge-threejs/src/main/kotlin/info/laht/threekt/geometries/TextGeometry.kt similarity index 83% rename from visionforge-threejs/src/main/kotlin/info/laht/threekt/geometries/TextBufferGeometry.kt rename to visionforge-threejs/src/main/kotlin/info/laht/threekt/geometries/TextGeometry.kt index ca9f93b3..b8c935f3 100644 --- a/visionforge-threejs/src/main/kotlin/info/laht/threekt/geometries/TextBufferGeometry.kt +++ b/visionforge-threejs/src/main/kotlin/info/laht/threekt/geometries/TextGeometry.kt @@ -34,10 +34,7 @@ external interface TextGeometryParameters { set(value) = definedExternally } -external class TextBufferGeometry(text: String, parameters: TextGeometryParameters? = definedExternally) : ExtrudeBufferGeometry { - val parameters: TextGeometryParameters -} - -external class TextGeometry(text: String, parameters: TextGeometryParameters? = definedExternally) : ExtrudeGeometry { +external class TextBufferGeometry(text: String, parameters: TextGeometryParameters? = definedExternally) : + ExtrudeBufferGeometry { val parameters: TextGeometryParameters } \ No newline at end of file diff --git a/visionforge-threejs/src/main/kotlin/info/laht/threekt/geometries/TorusGeometry.kt b/visionforge-threejs/src/main/kotlin/info/laht/threekt/geometries/TorusGeometry.kt index 7406afb3..0a53525f 100644 --- a/visionforge-threejs/src/main/kotlin/info/laht/threekt/geometries/TorusGeometry.kt +++ b/visionforge-threejs/src/main/kotlin/info/laht/threekt/geometries/TorusGeometry.kt @@ -4,7 +4,7 @@ package info.laht.threekt.geometries import info.laht.threekt.core.BufferGeometry -import info.laht.threekt.core.Geometry + external class TorusGeometry( radius: Number = definedExternally, @@ -12,12 +12,4 @@ external class TorusGeometry( radialSegments: Int = definedExternally, tubularSegments: Int = definedExternally, arc: Number = definedExternally -) : Geometry - -external class TorusBufferGeometry( - radius: Number = definedExternally, - tube: Number = definedExternally, - radialSegments: Int = definedExternally, - tubularSegments: Int = definedExternally, - arc: Number = definedExternally ) : BufferGeometry \ No newline at end of file diff --git a/visionforge-threejs/src/main/kotlin/info/laht/threekt/geometries/TubeGeometry.kt b/visionforge-threejs/src/main/kotlin/info/laht/threekt/geometries/TubeGeometry.kt index 38bc560a..36afa6ae 100644 --- a/visionforge-threejs/src/main/kotlin/info/laht/threekt/geometries/TubeGeometry.kt +++ b/visionforge-threejs/src/main/kotlin/info/laht/threekt/geometries/TubeGeometry.kt @@ -1,10 +1,10 @@ package info.laht.threekt.geometries import info.laht.threekt.core.BufferGeometry -import info.laht.threekt.core.Geometry import info.laht.threekt.extras.core.Curve import info.laht.threekt.math.Vector3 + /** * Creates a tube that extrudes along a 3d curve. */ @@ -16,25 +16,6 @@ external class TubeGeometry( radiusSegments: Int = definedExternally, closed: Boolean = definedExternally -) : Geometry { - - var tangents: Array - var normals: Array - var binormals: Array - -} - -/** - * Creates a tube that extrudes along a 3d curve. - */ -external class TubeBufferGeometry( - - path: Curve, - tubularSegments: Int = definedExternally, - radius: Number = definedExternally, - radiusSegments: Int = definedExternally, - closed: Boolean = definedExternally - ) : BufferGeometry { val parameters: dynamic diff --git a/visionforge-threejs/src/main/kotlin/info/laht/threekt/geometries/WireframeGeometry.kt b/visionforge-threejs/src/main/kotlin/info/laht/threekt/geometries/WireframeGeometry.kt index 4c0a72ee..f52c61cc 100644 --- a/visionforge-threejs/src/main/kotlin/info/laht/threekt/geometries/WireframeGeometry.kt +++ b/visionforge-threejs/src/main/kotlin/info/laht/threekt/geometries/WireframeGeometry.kt @@ -4,14 +4,8 @@ package info.laht.threekt.geometries import info.laht.threekt.core.BufferGeometry -import info.laht.threekt.core.Geometry /** * This can be used as a helper object to view a Geometry object as a wireframe. */ -external class WireframeGeometry : BufferGeometry { - - constructor(geometry: Geometry) - constructor(geometry: BufferGeometry) - -} \ No newline at end of file +external class WireframeGeometry(geometry: BufferGeometry) : BufferGeometry \ No newline at end of file diff --git a/visionforge-threejs/src/main/kotlin/info/laht/threekt/objects/LineSegments.kt b/visionforge-threejs/src/main/kotlin/info/laht/threekt/objects/LineSegments.kt index b5a83ff0..03bef34e 100644 --- a/visionforge-threejs/src/main/kotlin/info/laht/threekt/objects/LineSegments.kt +++ b/visionforge-threejs/src/main/kotlin/info/laht/threekt/objects/LineSegments.kt @@ -28,12 +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 { - constructor(geometry: Geometry, material: Material) var geometry: BufferGeometry var material: Material diff --git a/visionforge-threejs/src/main/kotlin/info/laht/threekt/objects/Mesh.kt b/visionforge-threejs/src/main/kotlin/info/laht/threekt/objects/Mesh.kt index 78dcb9f6..54669b1f 100644 --- a/visionforge-threejs/src/main/kotlin/info/laht/threekt/objects/Mesh.kt +++ b/visionforge-threejs/src/main/kotlin/info/laht/threekt/objects/Mesh.kt @@ -27,14 +27,14 @@ package info.laht.threekt.objects -import info.laht.threekt.core.* +import info.laht.threekt.core.BufferGeometry +import info.laht.threekt.core.Intersect +import info.laht.threekt.core.Object3D +import info.laht.threekt.core.Raycaster import info.laht.threekt.materials.Material -open external class Mesh : Object3D { - - constructor(geometry: Geometry?, material: Material?) - constructor(geometry: BufferGeometry?, material: Material?) +open external class Mesh(geometry: BufferGeometry?, material: Material?) : Object3D { var geometry: dynamic var material: Material diff --git a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/MeshThreeFactory.kt b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/MeshThreeFactory.kt index b01dbd1a..00313d3a 100644 --- a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/MeshThreeFactory.kt +++ b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/MeshThreeFactory.kt @@ -30,9 +30,6 @@ public abstract class MeshThreeFactory( override fun invoke(three: ThreePlugin, obj: T): Mesh { val geometry = buildGeometry(obj) - //JS sometimes tries to pass Geometry as BufferGeometry - @Suppress("USELESS_IS_CHECK") if (geometry !is BufferGeometry) error("BufferGeometry expected") - //val meshMeta: Meta = obj.properties[Material3D.MATERIAL_KEY]?.node ?: Meta.empty val mesh = Mesh(geometry, ThreeMaterials.DEFAULT).apply { diff --git a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeBoxFactory.kt b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeBoxFactory.kt index dad57066..a5b50688 100644 --- a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeBoxFactory.kt +++ b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeBoxFactory.kt @@ -1,12 +1,12 @@ package space.kscience.visionforge.solid.three -import info.laht.threekt.geometries.BoxBufferGeometry +import info.laht.threekt.geometries.BoxGeometry import space.kscience.visionforge.solid.Box import space.kscience.visionforge.solid.detail public object ThreeBoxFactory : MeshThreeFactory(Box::class) { - override fun buildGeometry(obj: Box): BoxBufferGeometry = + override fun buildGeometry(obj: Box): BoxGeometry = obj.detail?.let { detail -> - BoxBufferGeometry(obj.xSize, obj.ySize, obj.zSize, detail, detail, detail) - } ?: BoxBufferGeometry(obj.xSize, obj.ySize, obj.zSize) + BoxGeometry(obj.xSize, obj.ySize, obj.zSize, detail, detail, detail) + } ?: BoxGeometry(obj.xSize, obj.ySize, obj.zSize) } \ No newline at end of file diff --git a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeCanvasLabelFactory.kt b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeCanvasLabelFactory.kt index bbce8f19..4855abcd 100644 --- a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeCanvasLabelFactory.kt +++ b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeCanvasLabelFactory.kt @@ -2,7 +2,7 @@ package space.kscience.visionforge.solid.three import info.laht.threekt.DoubleSide import info.laht.threekt.core.Object3D -import info.laht.threekt.geometries.PlaneBufferGeometry +import info.laht.threekt.geometries.PlaneGeometry import info.laht.threekt.materials.MeshBasicMaterial import info.laht.threekt.objects.Mesh import info.laht.threekt.textures.Texture @@ -46,7 +46,7 @@ public object ThreeCanvasLabelFactory : ThreeFactory { } val mesh = Mesh( - PlaneBufferGeometry(canvas.width, canvas.height), + PlaneGeometry(canvas.width, canvas.height), material ) diff --git a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeCompositeFactory.kt b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeCompositeFactory.kt index 1f8c9328..270e63a6 100644 --- a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeCompositeFactory.kt +++ b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeCompositeFactory.kt @@ -2,6 +2,7 @@ package space.kscience.visionforge.solid.three import CSG import info.laht.threekt.core.BufferGeometry +import info.laht.threekt.math.Matrix4 import info.laht.threekt.objects.Mesh import space.kscience.visionforge.solid.Composite import space.kscience.visionforge.solid.CompositeType @@ -23,7 +24,7 @@ public class ThreeCompositeFactory(public val three: ThreePlugin) : MeshThreeFac CompositeType.INTERSECT -> firstCSG.intersect(secondCSG) CompositeType.SUBTRACT -> firstCSG.subtract(secondCSG) } - return resultCSG.toGeometry().toBufferGeometry() + return resultCSG.toGeometry(Matrix4()) } } \ No newline at end of file diff --git a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeConeFactory.kt b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeConeFactory.kt index c8eece9a..5789c30e 100644 --- a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeConeFactory.kt +++ b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeConeFactory.kt @@ -1,7 +1,7 @@ package space.kscience.visionforge.solid.three import info.laht.threekt.core.BufferGeometry -import info.laht.threekt.geometries.CylinderBufferGeometry +import info.laht.threekt.geometries.CylinderGeometry import space.kscience.visionforge.solid.ConeSegment import space.kscience.visionforge.solid.detail import kotlin.math.PI @@ -11,7 +11,7 @@ public object ThreeConeFactory : MeshThreeFactory(ConeSegment::clas override fun buildGeometry(obj: ConeSegment): BufferGeometry { val cylinder = obj.detail?.let { val segments = it.toDouble().pow(0.5).toInt() - CylinderBufferGeometry( + CylinderGeometry( radiusTop = obj.topRadius, radiusBottom = obj.bottomRadius, height = obj.height, @@ -21,7 +21,7 @@ public object ThreeConeFactory : MeshThreeFactory(ConeSegment::clas thetaStart = obj.startAngle, thetaLength = obj.angle ) - } ?: CylinderBufferGeometry( + } ?: CylinderGeometry( radiusTop = obj.topRadius, radiusBottom = obj.bottomRadius, height = obj.height, diff --git a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeFactory.kt b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeFactory.kt index e231c4ce..c62abd77 100644 --- a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeFactory.kt +++ b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeFactory.kt @@ -63,9 +63,7 @@ public fun Object3D.updateProperty(source: Vision, propertyName: Name) { * Generic factory for elements which provide inside geometry builder */ public object ThreeShapeFactory : MeshThreeFactory(GeometrySolid::class) { - override fun buildGeometry(obj: GeometrySolid): BufferGeometry { - return obj.run { - ThreeGeometryBuilder().apply { toGeometry(this) }.build() - } - } + override fun buildGeometry(obj: GeometrySolid): BufferGeometry = ThreeGeometryBuilder().apply { + obj.toGeometry(this) + }.build() } \ No newline at end of file diff --git a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeGeometryBuilder.kt b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeGeometryBuilder.kt index c1568ffd..4ba19cf9 100644 --- a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeGeometryBuilder.kt +++ b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeGeometryBuilder.kt @@ -1,52 +1,61 @@ package space.kscience.visionforge.solid.three import info.laht.threekt.core.BufferGeometry -import info.laht.threekt.core.Face3 -import info.laht.threekt.core.Geometry +import info.laht.threekt.core.Float32BufferAttribute import info.laht.threekt.math.Vector3 import space.kscience.dataforge.meta.Meta -import space.kscience.dataforge.meta.get -import space.kscience.dataforge.meta.int import space.kscience.visionforge.solid.GeometryBuilder import space.kscience.visionforge.solid.Point3D +import space.kscience.visionforge.solid.cross +import space.kscience.visionforge.solid.minus internal fun Point3D.toVector() = Vector3(x, y, z) +internal fun MutableList.add(f1: T, f2: T, f3: T) { + add(f1) + add(f2) + add(f3) +} + /** * An implementation of geometry builder for Three.js [BufferGeometry] */ public class ThreeGeometryBuilder : GeometryBuilder { - private val vertices = ArrayList() - private val faces = ArrayList() + private val indices = ArrayList() + private val positions = ArrayList() + private val normals = ArrayList() + private val colors = ArrayList() - private val vertexCache = HashMap() + private val vertexCache = HashMap() + private var counter: Short = -1 - private fun append(vertex: Point3D): Int { - val index = vertexCache[vertex] ?: -1//vertices.indexOf(vertex) - return if (index > 0) { - index - } else { - vertices.add(vertex.toVector()) - vertexCache[vertex] = vertices.size - 1 - vertices.size - 1 - } + private fun indexOf(vertex: Point3D, normal: Point3D): Short = vertexCache.getOrPut(vertex) { + //add vertex and update cache if needed + positions.add(vertex.x, vertex.y, vertex.z) + normals.add(normal.x, vertex.y, vertex.z) + colors.add(1f, 1f, 1f) + counter++ + counter } override fun face(vertex1: Point3D, vertex2: Point3D, vertex3: Point3D, normal: Point3D?, meta: Meta) { - val face = Face3(append(vertex1), append(vertex2), append(vertex3), normal?.toVector() ?: Vector3(0, 0, 0)) - meta["materialIndex"].int?.let { face.materialIndex = it } - meta["color"]?.getColor()?.let { face.color = it } - faces.add(face) + val actualNormal: Point3D = normal ?: (vertex3 - vertex2) cross (vertex1 - vertex2) + indices.add( + indexOf(vertex1, actualNormal), + indexOf(vertex2, actualNormal), + indexOf(vertex3, actualNormal) + ) } - override fun build(): BufferGeometry { - return Geometry().apply { - vertices = this@ThreeGeometryBuilder.vertices.toTypedArray() - faces = this@ThreeGeometryBuilder.faces.toTypedArray() - computeBoundingSphere() - computeFaceNormals() - }.toBufferGeometry() + override fun build(): BufferGeometry = BufferGeometry().apply { + //setIndex(Int16BufferAttribute(indices.toShortArray(), 1)) + setIndex(indices.toTypedArray()) + setAttribute("position", Float32BufferAttribute(positions.toFloatArray(), 3)) + setAttribute("normal", Float32BufferAttribute(normals.toFloatArray(), 3)) + //setAttribute("color", Float32BufferAttribute(colors.toFloatArray(), 3)) + + computeBoundingSphere() } } \ No newline at end of file diff --git a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeLineFactory.kt b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeLineFactory.kt index cc9c58ce..b2858fdb 100644 --- a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeLineFactory.kt +++ b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeLineFactory.kt @@ -1,6 +1,6 @@ package space.kscience.visionforge.solid.three -import info.laht.threekt.core.Geometry +import info.laht.threekt.core.BufferGeometry import info.laht.threekt.core.Object3D import info.laht.threekt.math.Color import info.laht.threekt.objects.LineSegments @@ -16,8 +16,8 @@ public object ThreeLineFactory : ThreeFactory { override val type: KClass get() = PolyLine::class override fun invoke(three: ThreePlugin, obj: PolyLine): Object3D { - val geometry = Geometry().apply { - vertices = Array(obj.points.size) { obj.points[it].toVector() } + val geometry = BufferGeometry().apply { + setFromPoints(Array(obj.points.size) { obj.points[it].toVector() }) } val material = ThreeMaterials.getLineMaterial(obj.getProperty(MeshThreeFactory.EDGES_MATERIAL_KEY).node, true) diff --git a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeSphereFactory.kt b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeSphereFactory.kt index 8f117516..8932a6c8 100644 --- a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeSphereFactory.kt +++ b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeSphereFactory.kt @@ -1,14 +1,14 @@ package space.kscience.visionforge.solid.three import info.laht.threekt.core.BufferGeometry -import info.laht.threekt.geometries.SphereBufferGeometry +import info.laht.threekt.geometries.SphereGeometry import space.kscience.visionforge.solid.Sphere import space.kscience.visionforge.solid.detail public object ThreeSphereFactory : MeshThreeFactory(Sphere::class) { override fun buildGeometry(obj: Sphere): BufferGeometry { return obj.detail?.let {detail -> - SphereBufferGeometry( + SphereGeometry( radius = obj.radius, phiStart = obj.phiStart, phiLength = obj.phi, @@ -17,7 +17,7 @@ public object ThreeSphereFactory : MeshThreeFactory(Sphere::class) { widthSegments = detail, heightSegments = detail ) - }?: SphereBufferGeometry( + }?: SphereGeometry( radius = obj.radius, phiStart = obj.phiStart, phiLength = obj.phi, diff --git a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/csg.kt b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/csg.kt index af99f66e..d7b0d46b 100644 --- a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/csg.kt +++ b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/csg.kt @@ -1,28 +1,34 @@ -@file:Suppress("INTERFACE_WITH_SUPERCLASS", +@file:Suppress( + "INTERFACE_WITH_SUPERCLASS", "OVERRIDING_FINAL_MEMBER", "RETURN_TYPE_MISMATCH_ON_OVERRIDE", "CONFLICTING_OVERLOADS", - "EXTERNAL_DELEGATION") + "EXTERNAL_DELEGATION" +) @file:JsModule("three-csg-ts") @file:JsNonModule +import info.laht.threekt.core.BufferGeometry import info.laht.threekt.math.Matrix4 import info.laht.threekt.math.Vector3 import info.laht.threekt.objects.Mesh -external open class CSG { - open fun clone(): CSG - open fun toPolygons(): Array - open fun union(csg: CSG): CSG - open fun subtract(csg: CSG): CSG - open fun intersect(csg: CSG): CSG - open fun inverse(): CSG +external class CSG { + fun clone(): CSG + fun toPolygons(): Array + fun toGeometry(toMatrix: Matrix4): BufferGeometry + fun union(csg: CSG): CSG + fun subtract(csg: CSG): CSG + fun intersect(csg: CSG): CSG + fun inverse(): CSG + companion object { fun fromPolygons(polygons: Array): CSG - fun fromGeometry(geom: Any): CSG - fun fromMesh(mesh: Mesh): CSG + fun fromGeometry(geom: BufferGeometry, objectIndex: dynamic = definedExternally): CSG + fun fromMesh(mesh: Mesh, objectIndex: dynamic = definedExternally): CSG + fun toGeometry(csg: CSG, toMatrix: Matrix4): BufferGeometry fun toMesh(csg: CSG, toMatrix: Matrix4): Mesh fun iEval(tokens: Mesh, index: Number? = definedExternally) fun eval(tokens: Mesh, doRemove: Boolean): Mesh @@ -35,15 +41,15 @@ external open class CSG { } } -external open class Vector(x: Number, y: Number, z: Number) : Vector3 { - open fun negated(): Vector - open fun plus(a: Vector): Vector - open fun minus(a: Vector): Vector - open fun times(a: Number): Vector - open fun dividedBy(a: Number): Vector - open fun lerp(a: Vector, t: Number): Any - open fun unit(): Vector - open fun cross(a: Vector): Any +external class Vector(x: Number, y: Number, z: Number) : Vector3 { + fun negated(): Vector + fun plus(a: Vector): Vector + fun minus(a: Vector): Vector + fun times(a: Number): Vector + fun dividedBy(a: Number): Vector + fun lerp(a: Vector, t: Number): Any + fun unit(): Vector + fun cross(a: Vector): Any } external interface IVector { @@ -52,21 +58,21 @@ external interface IVector { var z: Number } -external open class Vertex(pos: IVector, normal: IVector, uv: IVector? = definedExternally) { - open var pos: Vector - open var normal: Vector - open var uv: Vector - open fun clone(): Vertex - open fun flip() - open fun interpolate(other: Vertex, t: Number): Vertex +external class Vertex(pos: IVector, normal: IVector, uv: IVector? = definedExternally) { + var pos: Vector + var normal: Vector + var uv: Vector + fun clone(): Vertex + fun flip() + fun interpolate(other: Vertex, t: Number): Vertex } -external open class Plane(normal: Vector, w: Number) { - open var normal: Vector - open var w: Number - open fun clone(): Plane - open fun flip() - open fun splitPolygon( +external class Plane(normal: Vector, w: Number) { + var normal: Vector + var w: Number + fun clone(): Plane + fun flip() + fun splitPolygon( polygon: Polygon, coplanarFront: Array, coplanarBack: Array, @@ -80,10 +86,10 @@ external open class Plane(normal: Vector, w: Number) { } } -external open class Polygon(vertices: Array, shared: Any? = definedExternally) { - open var plane: Plane - open var vertices: Array - open var shared: Any - open fun clone(): Polygon - open fun flip() +external class Polygon(vertices: Array, shared: Any? = definedExternally) { + var plane: Plane + var vertices: Array + var shared: Any + fun clone(): Polygon + fun flip() } \ No newline at end of file diff --git a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/three.kt b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/three.kt index fa13e91d..9e78800b 100644 --- a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/three.kt +++ b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/three.kt @@ -1,7 +1,7 @@ package space.kscience.visionforge.solid.three -import CSG -import info.laht.threekt.core.* +import info.laht.threekt.core.BufferGeometry +import info.laht.threekt.core.Layers import info.laht.threekt.external.controls.OrbitControls import info.laht.threekt.materials.Material import info.laht.threekt.math.Euler @@ -19,53 +19,13 @@ public val Solid.euler: Euler get() = Euler(rotationX, rotationY, rotationZ, rot public val MetaItem.vector: Vector3 get() = Vector3(node["x"].float ?: 0f, node["y"].float ?: 0f, node["z"].float ?: 0f) -public fun Geometry.toBufferGeometry(): BufferGeometry = BufferGeometry().apply { fromGeometry(this@toBufferGeometry) } internal fun Double.toRadians() = this * PI / 180 -public fun CSG.toGeometry(): Geometry { - val geom = Geometry() - - val vertices = ArrayList() - val faces = ArrayList() - - for (polygon in toPolygons()) { - val v0 = vertices.size - val pvs = polygon.vertices - - for (pv in pvs) { - vertices.add(Vector3().copy(pv.pos)) - } - - for (j in 3..polygon.vertices.size) { - val fc = Face3(v0, v0 + j - 2, v0 + j - 1, Vector3()) - fc.vertexNormals = arrayOf( - Vector3().copy(pvs[0].normal), - Vector3().copy(pvs[j - 2].normal), - Vector3().copy(pvs[j - 1].normal) - ) - - fc.normal = Vector3().copy(polygon.plane.normal) - faces.add(fc) - } - } - geom.vertices = vertices.toTypedArray() - geom.faces = faces.toTypedArray() -// val inv: Matrix4 = Matrix4().apply { getInverse(toMatrix) } -// geom.applyMatrix(toMatrix) - geom.verticesNeedUpdate = true - geom.elementsNeedUpdate = true - geom.normalsNeedUpdate = true - geom.computeBoundingSphere() - geom.computeBoundingBox() - return geom -} internal fun Any.dispose() { when (this) { - is Geometry -> dispose() is BufferGeometry -> dispose() - is DirectGeometry -> dispose() is Material -> dispose() is Mesh -> { geometry.dispose() From c82c0ecea3b6f9fb17d7a86b9d4a39ee9952b7f7 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sat, 10 Jul 2021 17:37:56 +0300 Subject: [PATCH 04/29] Refactor to ThreeJS v 130 --- .../info/laht/threekt/core/BufferAttribute.kt | 2 +- .../kotlin/info/laht/threekt/objects/Mesh.kt | 2 +- .../solid/three/MeshThreeFactory.kt | 3 +- .../solid/three/ThreeCompositeFactory.kt | 58 ++++++++++++++----- .../solid/three/ThreeGeometryBuilder.kt | 4 +- .../kscience/visionforge/solid/three/csg.kt | 9 +-- 6 files changed, 53 insertions(+), 25 deletions(-) diff --git a/visionforge-threejs/src/main/kotlin/info/laht/threekt/core/BufferAttribute.kt b/visionforge-threejs/src/main/kotlin/info/laht/threekt/core/BufferAttribute.kt index 938deb7e..6a773330 100644 --- a/visionforge-threejs/src/main/kotlin/info/laht/threekt/core/BufferAttribute.kt +++ b/visionforge-threejs/src/main/kotlin/info/laht/threekt/core/BufferAttribute.kt @@ -223,7 +223,7 @@ abstract external class BufferAttribute protected constructor( external class Float32BufferAttribute( - array: FloatArray, + array: Array, itemSize: Int, normalized: Boolean = definedExternally ) : BufferAttribute diff --git a/visionforge-threejs/src/main/kotlin/info/laht/threekt/objects/Mesh.kt b/visionforge-threejs/src/main/kotlin/info/laht/threekt/objects/Mesh.kt index 54669b1f..fc91e333 100644 --- a/visionforge-threejs/src/main/kotlin/info/laht/threekt/objects/Mesh.kt +++ b/visionforge-threejs/src/main/kotlin/info/laht/threekt/objects/Mesh.kt @@ -36,7 +36,7 @@ import info.laht.threekt.materials.Material open external class Mesh(geometry: BufferGeometry?, material: Material?) : Object3D { - var geometry: dynamic + var geometry: BufferGeometry var material: Material var drawMode: Int diff --git a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/MeshThreeFactory.kt b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/MeshThreeFactory.kt index 00313d3a..14665a8b 100644 --- a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/MeshThreeFactory.kt +++ b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/MeshThreeFactory.kt @@ -36,7 +36,8 @@ public abstract class MeshThreeFactory( matrixAutoUpdate = false //set position for mesh updatePosition(obj) - }.applyProperties(obj) + applyProperties(obj) + } //add listener to object properties obj.onPropertyChange(three.updateScope) { name -> diff --git a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeCompositeFactory.kt b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeCompositeFactory.kt index 270e63a6..33304b72 100644 --- a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeCompositeFactory.kt +++ b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeCompositeFactory.kt @@ -1,30 +1,60 @@ package space.kscience.visionforge.solid.three import CSG -import info.laht.threekt.core.BufferGeometry -import info.laht.threekt.math.Matrix4 +import info.laht.threekt.core.Object3D import info.laht.threekt.objects.Mesh +import space.kscience.dataforge.names.startsWith +import space.kscience.visionforge.onPropertyChange import space.kscience.visionforge.solid.Composite import space.kscience.visionforge.solid.CompositeType +import kotlin.reflect.KClass /** * This should be inner, because it uses object builder */ -public class ThreeCompositeFactory(public val three: ThreePlugin) : MeshThreeFactory(Composite::class) { +public class ThreeCompositeFactory(public val three: ThreePlugin) : ThreeFactory { - override fun buildGeometry(obj: Composite): BufferGeometry { +// override fun buildGeometry(obj: Composite): BufferGeometry { +// val first = three.buildObject3D(obj.first) as? Mesh ?: error("First part of composite is not a mesh") +// //first.updateMatrix() +// val second = three.buildObject3D(obj.second) as? Mesh ?: error("Second part of composite is not a mesh") +// //second.updateMatrix() +// val firstCSG = CSG.fromMesh(first) +// val secondCSG = CSG.fromMesh(second) +//// val resultCSG = when (obj.compositeType) { +//// CompositeType.UNION -> firstCSG.union(secondCSG) +//// CompositeType.INTERSECT -> firstCSG.intersect(secondCSG) +//// CompositeType.SUBTRACT -> firstCSG.subtract(secondCSG) +//// } +//// return resultCSG.toGeometry(second.matrix) +// +// val resultMesh: Mesh = when (obj.compositeType) { +// CompositeType.UNION -> CSG.union(first,second) +// CompositeType.INTERSECT -> CSG.intersect(first,second) +// CompositeType.SUBTRACT -> CSG.subtract(first,second) +// } +// return resultMesh.geometry +// } + + override val type: KClass get() = Composite::class + + override fun invoke(three: ThreePlugin, obj: Composite): Object3D { val first = three.buildObject3D(obj.first) as? Mesh ?: error("First part of composite is not a mesh") - first.updateMatrix() val second = three.buildObject3D(obj.second) as? Mesh ?: error("Second part of composite is not a mesh") - second.updateMatrix() - val firstCSG = CSG.fromMesh(first) - val secondCSG = CSG.fromMesh(second) - val resultCSG = when (obj.compositeType) { - CompositeType.UNION -> firstCSG.union(secondCSG) - CompositeType.INTERSECT -> firstCSG.intersect(secondCSG) - CompositeType.SUBTRACT -> firstCSG.subtract(secondCSG) + return when (obj.compositeType) { + CompositeType.UNION -> CSG.union(first,second) + CompositeType.INTERSECT -> CSG.intersect(first,second) + CompositeType.SUBTRACT -> CSG.subtract(first,second) + }.apply { + updatePosition(obj) + applyProperties(obj) + obj.onPropertyChange(three.updateScope) { name -> + when { + //name.startsWith(WIREFRAME_KEY) -> mesh.applyWireFrame(obj) + name.startsWith(MeshThreeFactory.EDGES_KEY) -> applyEdges(obj) + else -> updateProperty(obj, name) + } + } } - return resultCSG.toGeometry(Matrix4()) } - } \ No newline at end of file diff --git a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeGeometryBuilder.kt b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeGeometryBuilder.kt index 4ba19cf9..d2a79ef5 100644 --- a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeGeometryBuilder.kt +++ b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeGeometryBuilder.kt @@ -52,8 +52,8 @@ public class ThreeGeometryBuilder : GeometryBuilder { override fun build(): BufferGeometry = BufferGeometry().apply { //setIndex(Int16BufferAttribute(indices.toShortArray(), 1)) setIndex(indices.toTypedArray()) - setAttribute("position", Float32BufferAttribute(positions.toFloatArray(), 3)) - setAttribute("normal", Float32BufferAttribute(normals.toFloatArray(), 3)) + setAttribute("position", Float32BufferAttribute(positions.toTypedArray(), 3)) + setAttribute("normal", Float32BufferAttribute(normals.toTypedArray(), 3)) //setAttribute("color", Float32BufferAttribute(colors.toFloatArray(), 3)) computeBoundingSphere() diff --git a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/csg.kt b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/csg.kt index d7b0d46b..2bee0a7a 100644 --- a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/csg.kt +++ b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/csg.kt @@ -32,12 +32,9 @@ external class CSG { fun toMesh(csg: CSG, toMatrix: Matrix4): Mesh fun iEval(tokens: Mesh, index: Number? = definedExternally) fun eval(tokens: Mesh, doRemove: Boolean): Mesh - var _tmpm3: Any - var doRemove: Any - var currentOp: Any - var currentPrim: Any - var nextPrim: Any - var sourceMesh: Any + fun union(meshA: Mesh, meshB: Mesh): Mesh + fun subtract(meshA: Mesh, meshB: Mesh): Mesh + fun intersect(meshA: Mesh, meshB: Mesh): Mesh } } From ba637413c770910060202e03a557d5a22ddccd2e Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 11 Jul 2021 09:58:01 +0300 Subject: [PATCH 05/29] Workaround for csg uv bug --- .../src/main/kotlin/JsPlaygroundApp.kt | 7 +++--- .../src/main/resources/index.html | 3 ++- .../playground/src/jvmMain/kotlin/gdmlIaxo.kt | 3 +-- .../main/kotlin/info/laht/threekt/THREE.kt | 1 + .../solid/three/ThreeGeometryBuilder.kt | 24 ++++++++++--------- 5 files changed, 20 insertions(+), 18 deletions(-) diff --git a/demo/js-playground/src/main/kotlin/JsPlaygroundApp.kt b/demo/js-playground/src/main/kotlin/JsPlaygroundApp.kt index b43ce062..edf159cd 100644 --- a/demo/js-playground/src/main/kotlin/JsPlaygroundApp.kt +++ b/demo/js-playground/src/main/kotlin/JsPlaygroundApp.kt @@ -1,7 +1,6 @@ import kotlinx.browser.document import kotlinx.css.height -import kotlinx.css.vh -import kotlinx.css.vw +import kotlinx.css.pct import kotlinx.css.width import react.child import react.dom.render @@ -32,8 +31,8 @@ private class JsPlaygroundApp : Application { render(element) { styledDiv { css{ - height = 100.vh - width = 100.vw + height = 100.pct + width = 100.pct } child(ThreeCanvasWithControls) { attrs { diff --git a/demo/js-playground/src/main/resources/index.html b/demo/js-playground/src/main/resources/index.html index 7a777ef1..83a9016e 100644 --- a/demo/js-playground/src/main/resources/index.html +++ b/demo/js-playground/src/main/resources/index.html @@ -2,10 +2,11 @@ + js-playground - +
\ No newline at end of file diff --git a/demo/playground/src/jvmMain/kotlin/gdmlIaxo.kt b/demo/playground/src/jvmMain/kotlin/gdmlIaxo.kt index fc2ebce3..a9070af7 100644 --- a/demo/playground/src/jvmMain/kotlin/gdmlIaxo.kt +++ b/demo/playground/src/jvmMain/kotlin/gdmlIaxo.kt @@ -3,7 +3,6 @@ package space.kscience.visionforge.examples import space.kscience.dataforge.context.Context import space.kscience.gdml.GdmlShowCase import space.kscience.visionforge.gdml.toVision -import space.kscience.visionforge.html.ResourceLocation import space.kscience.visionforge.solid.Solids fun main() { @@ -11,7 +10,7 @@ fun main() { plugin(Solids) } - context.makeVisionFile(resourceLocation = ResourceLocation.EMBED) { + context.makeVisionFile { vision("canvas") { GdmlShowCase.babyIaxo().toVision() } } } \ No newline at end of file diff --git a/visionforge-threejs/src/main/kotlin/info/laht/threekt/THREE.kt b/visionforge-threejs/src/main/kotlin/info/laht/threekt/THREE.kt index d3844561..3f8028cb 100644 --- a/visionforge-threejs/src/main/kotlin/info/laht/threekt/THREE.kt +++ b/visionforge-threejs/src/main/kotlin/info/laht/threekt/THREE.kt @@ -24,6 +24,7 @@ @file:JsModule("three") @file:JsNonModule +@file:Suppress("NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING", "unused") package info.laht.threekt diff --git a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeGeometryBuilder.kt b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeGeometryBuilder.kt index d2a79ef5..c1c5aa72 100644 --- a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeGeometryBuilder.kt +++ b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeGeometryBuilder.kt @@ -11,10 +11,10 @@ import space.kscience.visionforge.solid.minus internal fun Point3D.toVector() = Vector3(x, y, z) -internal fun MutableList.add(f1: T, f2: T, f3: T) { - add(f1) - add(f2) - add(f3) +internal fun MutableList.add(vararg values: T) { + values.forEach { + add(it) + } } /** @@ -25,16 +25,16 @@ public class ThreeGeometryBuilder : GeometryBuilder { private val indices = ArrayList() private val positions = ArrayList() private val normals = ArrayList() - private val colors = ArrayList() +// private val colors = ArrayList() private val vertexCache = HashMap() private var counter: Short = -1 - private fun indexOf(vertex: Point3D, normal: Point3D): Short = vertexCache.getOrPut(vertex) { + private fun vertex(vertex: Point3D, normal: Point3D): Short = vertexCache.getOrPut(vertex) { //add vertex and update cache if needed positions.add(vertex.x, vertex.y, vertex.z) normals.add(normal.x, vertex.y, vertex.z) - colors.add(1f, 1f, 1f) + //colors.add(1f, 1f, 1f) counter++ counter } @@ -42,19 +42,21 @@ public class ThreeGeometryBuilder : GeometryBuilder { override fun face(vertex1: Point3D, vertex2: Point3D, vertex3: Point3D, normal: Point3D?, meta: Meta) { val actualNormal: Point3D = normal ?: (vertex3 - vertex2) cross (vertex1 - vertex2) indices.add( - indexOf(vertex1, actualNormal), - indexOf(vertex2, actualNormal), - indexOf(vertex3, actualNormal) + vertex(vertex1, actualNormal), + vertex(vertex2, actualNormal), + vertex(vertex3, actualNormal) ) } override fun build(): BufferGeometry = BufferGeometry().apply { - //setIndex(Int16BufferAttribute(indices.toShortArray(), 1)) setIndex(indices.toTypedArray()) setAttribute("position", Float32BufferAttribute(positions.toTypedArray(), 3)) setAttribute("normal", Float32BufferAttribute(normals.toTypedArray(), 3)) //setAttribute("color", Float32BufferAttribute(colors.toFloatArray(), 3)) + //a temporary fix for CSG problem + val uvsArray = Array((counter+1)*2){0f} + setAttribute("uv", Float32BufferAttribute(uvsArray, 2)) computeBoundingSphere() } From 2b6942b827f055df13709aa280185b81dd675594 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 11 Jul 2021 12:07:04 +0300 Subject: [PATCH 06/29] Reimplemented coordinates as properties --- .../src/main/kotlin/JsPlaygroundApp.kt | 10 +- .../visionforge/gdml/GdmlOptimizer.kt | 18 +-- .../space/kscience/visionforge/solid/Solid.kt | 139 +++++++----------- .../kscience/visionforge/solid/SolidBase.kt | 6 +- .../kscience/visionforge/solid/SolidGroup.kt | 6 +- .../visionforge/solid/SolidReference.kt | 32 ++-- .../kscience/visionforge/solid/geometry.kt | 67 ++++++--- .../solid/transform/RemoveSingleChild.kt | 20 +-- .../laht/threekt/animation/AnimationAction.kt | 1 + 9 files changed, 142 insertions(+), 157 deletions(-) diff --git a/demo/js-playground/src/main/kotlin/JsPlaygroundApp.kt b/demo/js-playground/src/main/kotlin/JsPlaygroundApp.kt index edf159cd..ec28649c 100644 --- a/demo/js-playground/src/main/kotlin/JsPlaygroundApp.kt +++ b/demo/js-playground/src/main/kotlin/JsPlaygroundApp.kt @@ -1,7 +1,5 @@ import kotlinx.browser.document -import kotlinx.css.height -import kotlinx.css.pct -import kotlinx.css.width +import kotlinx.css.* import react.child import react.dom.render import space.kscience.dataforge.context.Context @@ -31,8 +29,10 @@ private class JsPlaygroundApp : Application { render(element) { styledDiv { css{ - height = 100.pct - width = 100.pct + padding(0.pt) + margin(0.pt) + height = 100.vh + width = 100.vw } child(ThreeCanvasWithControls) { attrs { diff --git a/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/GdmlOptimizer.kt b/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/GdmlOptimizer.kt index a35e845c..b2075e3a 100644 --- a/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/GdmlOptimizer.kt +++ b/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/GdmlOptimizer.kt @@ -11,22 +11,14 @@ public expect class Counter() { public fun incrementAndGet(): Int } -private fun Point3D?.safePlus(other: Point3D?): Point3D? = if (this == null && other == null) { - null -} else { - (this ?: Point3D(0, 0, 0)) + (other ?: Point3D(0, 0, 0)) -} - @DFExperimental internal fun Vision.updateFrom(other: Vision): Vision { if (this is Solid && other is Solid) { - position = position.safePlus(other.position) - rotation = rotation.safePlus(other.rotation) - if (this.scale != null || other.scale != null) { - scaleX = scaleX.toDouble() * other.scaleX.toDouble() - scaleY = scaleY.toDouble() * other.scaleY.toDouble() - scaleZ = scaleZ.toDouble() * other.scaleZ.toDouble() - } + position += other.position + rotation += other.rotation + scaleX = scaleX.toDouble() * other.scaleX.toDouble() + scaleY = scaleY.toDouble() * other.scaleY.toDouble() + scaleZ = scaleZ.toDouble() * other.scaleZ.toDouble() other.meta.itemSequence().forEach { (name, item) -> if (getProperty(name) == null) { setProperty(name, item) diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solid.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solid.kt index 9855c835..f2b14f2a 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solid.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solid.kt @@ -1,9 +1,7 @@ package space.kscience.visionforge.solid -import space.kscience.dataforge.meta.boolean +import space.kscience.dataforge.meta.* import space.kscience.dataforge.meta.descriptors.NodeDescriptor -import space.kscience.dataforge.meta.enum -import space.kscience.dataforge.meta.int import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.asName import space.kscience.dataforge.names.plus @@ -14,15 +12,28 @@ import space.kscience.visionforge.Vision.Companion.VISIBLE_KEY import space.kscience.visionforge.solid.Solid.Companion.DETAIL_KEY import space.kscience.visionforge.solid.Solid.Companion.IGNORE_KEY import space.kscience.visionforge.solid.Solid.Companion.LAYER_KEY +import space.kscience.visionforge.solid.Solid.Companion.POSITION_KEY +import space.kscience.visionforge.solid.Solid.Companion.ROTATION_KEY +import space.kscience.visionforge.solid.Solid.Companion.SCALE_KEY +import space.kscience.visionforge.solid.Solid.Companion.X_KEY +import space.kscience.visionforge.solid.Solid.Companion.X_POSITION_KEY +import space.kscience.visionforge.solid.Solid.Companion.X_ROTATION_KEY +import space.kscience.visionforge.solid.Solid.Companion.X_SCALE_KEY +import space.kscience.visionforge.solid.Solid.Companion.Y_KEY +import space.kscience.visionforge.solid.Solid.Companion.Y_POSITION_KEY +import space.kscience.visionforge.solid.Solid.Companion.Y_ROTATION_KEY +import space.kscience.visionforge.solid.Solid.Companion.Y_SCALE_KEY +import space.kscience.visionforge.solid.Solid.Companion.Z_KEY +import space.kscience.visionforge.solid.Solid.Companion.Z_POSITION_KEY +import space.kscience.visionforge.solid.Solid.Companion.Z_ROTATION_KEY +import space.kscience.visionforge.solid.Solid.Companion.Z_SCALE_KEY +import kotlin.properties.ReadWriteProperty +import kotlin.reflect.KProperty /** * Interface for 3-dimensional [Vision] */ public interface Solid : Vision { - public var position: Point3D? - public var rotation: Point3D? - public var scale: Point3D? - override val descriptor: NodeDescriptor get() = Companion.descriptor public companion object { @@ -72,7 +83,7 @@ public interface Solid : Vision { hide() } - value(DETAIL_KEY){ + value(DETAIL_KEY) { type(ValueType.NUMBER) hide() } @@ -84,22 +95,6 @@ public interface Solid : Vision { } } } - - internal fun solidEquals(first: Solid, second: Solid): Boolean { - if (first.position != second.position) return false - if (first.rotation != second.rotation) return false - if (first.scale != second.scale) return false - if (first.meta != second.meta) return false - return true - } - - internal fun solidHashCode(solid: Solid): Int { - var result = +(solid.position?.hashCode() ?: 0) - result = 31 * result + (solid.rotation?.hashCode() ?: 0) - result = 31 * result + (solid.scale?.hashCode() ?: 0) - result = 31 * result + solid.allProperties().hashCode() - return result - } } } @@ -150,74 +145,44 @@ public var Vision.ignore: Boolean? // get() = getProperty(SELECTED_KEY).boolean // set(value) = setProperty(SELECTED_KEY, value) -private fun Solid.position(): Point3D = - position ?: Point3D(0.0, 0.0, 0.0).also { position = it } +internal fun number(name: Name, default: Number): ReadWriteProperty = + object : ReadWriteProperty { + override fun getValue(thisRef: Solid, property: KProperty<*>): Number { + return thisRef.getOwnProperty(name)?.number ?: default + } -public var Solid.x: Number - get() = position?.x ?: 0f - set(value) { - position().x = value.toFloat() - invalidateProperty(Solid.X_POSITION_KEY) + override fun setValue(thisRef: Solid, property: KProperty<*>, value: Number) { + thisRef.setProperty(name, value) + } } -public var Solid.y: Number - get() = position?.y ?: 0f - set(value) { - position().y = value.toFloat() - invalidateProperty(Solid.Y_POSITION_KEY) +internal fun point(name: Name, default: Float): ReadWriteProperty = + object : ReadWriteProperty { + override fun getValue(thisRef: Solid, property: KProperty<*>): Point3D = object : Point3D { + override val x: Float get() = thisRef.getOwnProperty(name + X_KEY)?.float ?: default + override val y: Float get() = thisRef.getOwnProperty(name + Y_KEY)?.float ?: default + override val z: Float get() = thisRef.getOwnProperty(name + Z_KEY)?.float ?: default + } + + override fun setValue(thisRef: Solid, property: KProperty<*>, value: Point3D) { + thisRef.setProperty(name + X_KEY, value.x) + thisRef.setProperty(name + Y_KEY, value.y) + thisRef.setProperty(name + Z_KEY, value.z) + } } -public var Solid.z: Number - get() = position?.z ?: 0f - set(value) { - position().z = value.toFloat() - invalidateProperty(Solid.Z_POSITION_KEY) - } +public var Solid.position: Point3D by point(POSITION_KEY, 0f) +public var Solid.rotation: Point3D by point(ROTATION_KEY, 0f) +public var Solid.scale: Point3D by point(SCALE_KEY, 1f) -private fun Solid.rotation(): Point3D = - rotation ?: Point3D(0.0, 0.0, 0.0).also { rotation = it } +public var Solid.x: Number by number(X_POSITION_KEY, 0f) +public var Solid.y: Number by number(Y_POSITION_KEY, 0f) +public var Solid.z: Number by number(Z_POSITION_KEY, 0f) -public var Solid.rotationX: Number - get() = rotation?.x ?: 0f - set(value) { - rotation().x = value.toFloat() - invalidateProperty(Solid.X_ROTATION_KEY) - } +public var Solid.rotationX: Number by number(X_ROTATION_KEY, 0f) +public var Solid.rotationY: Number by number(Y_ROTATION_KEY, 0f) +public var Solid.rotationZ: Number by number(Z_ROTATION_KEY, 0f) -public var Solid.rotationY: Number - get() = rotation?.y ?: 0f - set(value) { - rotation().y = value.toFloat() - invalidateProperty(Solid.Y_ROTATION_KEY) - } - -public var Solid.rotationZ: Number - get() = rotation?.z ?: 0f - set(value) { - rotation().z = value.toFloat() - invalidateProperty(Solid.Z_ROTATION_KEY) - } - -private fun Solid.scale(): Point3D = - scale ?: Point3D(1.0, 1.0, 1.0).also { scale = it } - -public var Solid.scaleX: Number - get() = scale?.x ?: 1f - set(value) { - scale().x = value.toFloat() - invalidateProperty(Solid.X_SCALE_KEY) - } - -public var Solid.scaleY: Number - get() = scale?.y ?: 1f - set(value) { - scale().y = value.toFloat() - invalidateProperty(Solid.Y_SCALE_KEY) - } - -public var Solid.scaleZ: Number - get() = scale?.z ?: 1f - set(value) { - scale().z = value.toFloat() - invalidateProperty(Solid.Z_SCALE_KEY) - } \ No newline at end of file +public var Solid.scaleX: Number by number(X_SCALE_KEY, 1f) +public var Solid.scaleY: Number by number(Y_SCALE_KEY, 1f) +public var Solid.scaleZ: Number by number(Z_SCALE_KEY, 1f) \ No newline at end of file diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidBase.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidBase.kt index e69f729c..1f86bdb3 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidBase.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidBase.kt @@ -13,9 +13,9 @@ import space.kscience.visionforge.VisionChange @Serializable @SerialName("solid") public open class SolidBase( - override var position: Point3D? = null, - override var rotation: Point3D? = null, - override var scale: Point3D? = null, +// override var position: Point3D? = null, +// override var rotation: Point3D? = null, +// override var scale: Point3D? = null, ) : VisionBase(), Solid { override val descriptor: NodeDescriptor get() = Solid.descriptor diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidGroup.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidGroup.kt index 20ca8afc..ad2107f0 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidGroup.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidGroup.kt @@ -29,9 +29,9 @@ public interface PrototypeHolder { @SerialName("group.solid") public class SolidGroup( @Serializable(PrototypeSerializer::class) internal var prototypes: MutableVisionGroup? = null, - override var position: Point3D? = null, - override var rotation: Point3D? = null, - override var scale: Point3D? = null, +// override var position: Point3D? = null, +// override var rotation: Point3D? = null, +// override var scale: Point3D? = null, ) : VisionGroupBase(), Solid, PrototypeHolder { init { diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidReference.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidReference.kt index 17ee9141..3d067a62 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidReference.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidReference.kt @@ -96,22 +96,22 @@ public class SolidReferenceGroup( */ private inner class ReferenceChild(private val childName: Name) : SolidReference, VisionGroup { - //TODO replace by properties - override var position: Point3D? - get() = prototype.position - set(_) { - error("Can't set position of reference") - } - override var rotation: Point3D? - get() = prototype.rotation - set(_) { - error("Can't set position of reference") - } - override var scale: Point3D? - get() = prototype.scale - set(_) { - error("Can't set position of reference") - } +// //TODO replace by properties +// override var position: Point3D? +// get() = prototype.position +// set(_) { +// error("Can't set position of reference") +// } +// override var rotation: Point3D? +// get() = prototype.rotation +// set(_) { +// error("Can't set position of reference") +// } +// override var scale: Point3D? +// get() = prototype.scale +// set(_) { +// error("Can't set position of reference") +// } override val prototype: Solid get() = prototypeFor(childName) override val children: Map diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/geometry.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/geometry.kt index 28a90398..e8813779 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/geometry.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/geometry.kt @@ -1,10 +1,14 @@ package space.kscience.visionforge.solid +import kotlinx.serialization.KSerializer import kotlinx.serialization.Serializable -import space.kscience.dataforge.meta.Meta -import space.kscience.dataforge.meta.MetaBuilder -import space.kscience.dataforge.meta.float -import space.kscience.dataforge.meta.get +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder +import space.kscience.dataforge.meta.* +import space.kscience.visionforge.solid.Solid.Companion.X_KEY +import space.kscience.visionforge.solid.Solid.Companion.Y_KEY +import space.kscience.visionforge.solid.Solid.Companion.Z_KEY import kotlin.math.PI import kotlin.math.pow import kotlin.math.sqrt @@ -17,25 +21,48 @@ public data class Point2D(public var x: Float, public var y: Float) public fun Point2D(x: Number, y: Number): Point2D = Point2D(x.toFloat(), y.toFloat()) public fun Point2D.toMeta(): Meta = Meta { - Solid.X_KEY put x - Solid.Y_KEY put y + X_KEY put x + Y_KEY put y } internal fun Meta.point2D(): Point2D = Point2D(this["x"].float ?: 0f, this["y"].float ?: 0f) -@Serializable -public data class Point3D( - public var x: Float, - public var y: Float, - public var z: Float, -) { +@Serializable(Point3DSerializer::class) +public interface Point3D { + public val x: Float + public val y: Float + public val z: Float + public companion object { public val ZERO: Point3D = Point3D(0.0, 0.0, 0.0) public val ONE: Point3D = Point3D(1.0, 1.0, 1.0) } } -public fun Point3D(x: Number, y: Number, z: Number): Point3D = Point3D(x.toFloat(), y.toFloat(), z.toFloat()) +@Serializable(Point3DSerializer::class) +public interface MutablePoint3D : Point3D { + override var x: Float + override var y: Float + override var z: Float +} + +@Serializable +private class Point3DImpl(override var x: Float, override var y: Float, override var z: Float) : MutablePoint3D + +internal object Point3DSerializer : KSerializer { + + override val descriptor: SerialDescriptor = Point3DImpl.serializer().descriptor + + + override fun deserialize(decoder: Decoder): Point3D = decoder.decodeSerializableValue(Point3DImpl.serializer()) + + override fun serialize(encoder: Encoder, value: Point3D) { + val impl: Point3DImpl = (value as? Point3DImpl) ?: Point3DImpl(value.x, value.y, value.z) + encoder.encodeSerializableValue(Point3DImpl.serializer(), impl) + } +} + +public fun Point3D(x: Number, y: Number, z: Number): Point3D = Point3DImpl(x.toFloat(), y.toFloat(), z.toFloat()) public operator fun Point3D.plus(other: Point3D): Point3D = Point3D( this.x + other.x, @@ -61,17 +88,21 @@ public infix fun Point3D.cross(other: Point3D): Point3D = Point3D( x * other.y - y * other.x ) -public fun Point3D.normalizeInPlace(){ +public fun MutablePoint3D.normalizeInPlace() { val norm = sqrt(x.pow(2) + y.pow(2) + z.pow(2)) x /= norm y /= norm z /= norm } -internal fun Meta.point3D() = Point3D(this["x"].float ?: 0.0, this["y"].float ?: 0.0, this["y"].float ?: 0.0) +internal fun ItemProvider.point3D(default: Float = 0f) = object : Point3D { + override val x: Float by float(default) + override val y: Float by float(default) + override val z: Float by float(default) +} public fun Point3D.toMeta(): MetaBuilder = Meta { - Solid.X_KEY put x - Solid.Y_KEY put y - Solid.Z_KEY put z + X_KEY put x + Y_KEY put y + Z_KEY put z } \ No newline at end of file diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/transform/RemoveSingleChild.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/transform/RemoveSingleChild.kt index 5d07303e..c0c02bc7 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/transform/RemoveSingleChild.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/transform/RemoveSingleChild.kt @@ -14,18 +14,14 @@ internal fun mergeChild(parent: VisionGroup, child: Vision): Vision { //parent.properties?.let { config.update(it) } if (this is Solid && parent is Solid) { - position = (position ?: Point3D.ZERO) + (parent.position ?: Point3D.ZERO) - rotation = (parent.rotation ?: Point3D.ZERO) + (parent.rotation ?: Point3D.ZERO) - scale = when { - scale == null && parent.scale == null -> null - scale == null -> parent.scale - parent.scale == null -> scale - else -> Point3D( - scale!!.x * parent.scale!!.x, - scale!!.y * parent.scale!!.y, - scale!!.z * parent.scale!!.z - ) - } + position += parent.position + rotation += parent.rotation + scale = Point3D( + scale.x * parent.scale.x, + scale.y * parent.scale.y, + scale.z * parent.scale.z + ) + } } diff --git a/visionforge-threejs/src/main/kotlin/info/laht/threekt/animation/AnimationAction.kt b/visionforge-threejs/src/main/kotlin/info/laht/threekt/animation/AnimationAction.kt index 8abbc8ae..d0e9b073 100644 --- a/visionforge-threejs/src/main/kotlin/info/laht/threekt/animation/AnimationAction.kt +++ b/visionforge-threejs/src/main/kotlin/info/laht/threekt/animation/AnimationAction.kt @@ -1,3 +1,4 @@ +@file:Suppress("NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING", "unused") @file:JsModule("three") @file:JsNonModule From 7b30b62849c60c7a7aaec7508b9f74e23bbfaa4b Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 11 Jul 2021 13:43:56 +0300 Subject: [PATCH 07/29] Reimplemented coordinates as properties --- .../visionforge/solid/FXCompositeFactory.kt | 2 +- .../visionforge/gdml/GdmlOptimizer.kt | 75 ------------------- ...mlTransformerEnv.kt => GdmlTransformer.kt} | 31 ++++---- .../space/kscience/visionforge/gdml/gdmlJs.kt | 8 -- .../kscience/visionforge/gdml/gdmlJVM.kt | 3 - .../kscience/visionforge/solid/Composite.kt | 3 +- .../space/kscience/visionforge/solid/Solid.kt | 67 +++++++++++------ .../solid/transform/RemoveSingleChild.kt | 45 ++++++----- .../visionforge/solid/transform/UnRef.kt | 2 +- .../laht/threekt/utils/BufferGeometryUtils.kt | 15 ++++ .../solid/three/ThreeCompositeFactory.kt | 6 +- 11 files changed, 107 insertions(+), 150 deletions(-) delete mode 100644 visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/GdmlOptimizer.kt rename visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/{GdmlTransformerEnv.kt => GdmlTransformer.kt} (95%) delete mode 100644 visionforge-gdml/src/jsMain/kotlin/space/kscience/visionforge/gdml/gdmlJs.kt create mode 100644 visionforge-threejs/src/main/kotlin/info/laht/threekt/utils/BufferGeometryUtils.kt diff --git a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/FXCompositeFactory.kt b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/FXCompositeFactory.kt index 5aa7619e..663a927b 100644 --- a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/FXCompositeFactory.kt +++ b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/FXCompositeFactory.kt @@ -48,7 +48,7 @@ class FXCompositeFactory(val plugin: FX3DPlugin) : FX3DFactory { val firstCSG = first.toCSG() val secondCSG = second.toCSG() val resultCSG = when (obj.compositeType) { - CompositeType.UNION -> firstCSG.union(secondCSG) + CompositeType.SUM, CompositeType.UNION -> firstCSG.union(secondCSG) CompositeType.INTERSECT -> firstCSG.intersect(secondCSG) CompositeType.SUBTRACT -> firstCSG.difference(secondCSG) } diff --git a/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/GdmlOptimizer.kt b/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/GdmlOptimizer.kt deleted file mode 100644 index b2075e3a..00000000 --- a/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/GdmlOptimizer.kt +++ /dev/null @@ -1,75 +0,0 @@ -package space.kscience.visionforge.gdml - -import space.kscience.dataforge.meta.itemSequence -import space.kscience.dataforge.misc.DFExperimental -import space.kscience.visionforge.Vision -import space.kscience.visionforge.meta -import space.kscience.visionforge.solid.* - -public expect class Counter() { - public fun get(): Int - public fun incrementAndGet(): Int -} - -@DFExperimental -internal fun Vision.updateFrom(other: Vision): Vision { - if (this is Solid && other is Solid) { - position += other.position - rotation += other.rotation - scaleX = scaleX.toDouble() * other.scaleX.toDouble() - scaleY = scaleY.toDouble() * other.scaleY.toDouble() - scaleZ = scaleZ.toDouble() * other.scaleZ.toDouble() - other.meta.itemSequence().forEach { (name, item) -> - if (getProperty(name) == null) { - setProperty(name, item) - } - } - } - return this -} -// -//@DFExperimental -//private class GdmlOptimizer() : VisionVisitor { -// val logger = KotlinLogging.logger("SingleChildReducer") -// -// private val depthCount = HashMap() -// -// override suspend fun visit(name: Name, vision: Vision) { -// val depth = name.length -// depthCount.getOrPut(depth) { Counter() }.incrementAndGet() -// } -// -// override fun skip(name: Name, vision: Vision): Boolean = vision is Proxy.ProxyChild -// -// override suspend fun visitChildren(name: Name, group: VisionGroup) { -// if (name == "volumes".toName()) return -// if (group !is MutableVisionGroup) return -// -// val newChildren = group.children.entries.associate { (visionToken, vision) -> -// //Reduce single child groups -// if (vision is VisionGroup && vision !is Proxy && vision.children.size == 1) { -// val (token, child) = vision.children.entries.first() -// child.parent = null -// if (token != visionToken) { -// child.config["solidName"] = token.toString() -// } -// visionToken to child.updateFrom(vision) -// } else { -// visionToken to vision -// } -// } -// if (newChildren != group.children) { -// group.removeAll() -// newChildren.forEach { (token, child) -> -// group[token] = child -// } -// } -// } -//} -// -//@DFExperimental -//suspend fun SolidGroup.optimizeGdml(): Job = coroutineScope { -// prototypes?.let { -// VisionVisitor.visitTree(GdmlOptimizer(), this, it) -// } ?: CompletableDeferred(Unit) -//} \ No newline at end of file diff --git a/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/GdmlTransformerEnv.kt b/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/GdmlTransformer.kt similarity index 95% rename from visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/GdmlTransformerEnv.kt rename to visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/GdmlTransformer.kt index 76561fe8..3a7b48af 100644 --- a/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/GdmlTransformerEnv.kt +++ b/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/GdmlTransformer.kt @@ -163,25 +163,26 @@ private class GdmlTransformerEnv(val settings: GdmlTransformer) { newScale: GdmlScale? = null, ): T = apply { newPos?.let { - val point = Point3D(it.x(settings.lUnit), it.y(settings.lUnit), it.z(settings.lUnit)) - if (point != Point3D.ZERO) { - position = point - } + val gdmlX = it.x(settings.lUnit) + if (gdmlX != 0f) x = gdmlX + val gdmlY = it.y(settings.lUnit) + if (gdmlY != 0f) y = gdmlY + val gdmlZ = it.z(settings.lUnit) + if (gdmlZ != 0f) z = gdmlZ } newRotation?.let { - val point = Point3D(it.x(settings.aUnit), it.y(settings.aUnit), it.z(settings.aUnit)) - if (point != Point3D.ZERO) { - rotation = point - } - //this@withPosition.rotationOrder = RotationOrder.ZXY + val gdmlX = it.x(settings.aUnit) + if (gdmlX != 0f) rotationX = gdmlX + val gdmlY = it.y(settings.aUnit) + if (gdmlY != 0f) rotationY = gdmlY + val gdmlZ = it.z(settings.aUnit) + if (gdmlZ != 0f) rotationZ = gdmlZ } newScale?.let { - val point = Point3D(it.x, it.y, it.z) - if (point != Point3D.ONE) { - scale = point - } + if (it.x != 1f) scaleX = it.x + if (it.y != 1f) scaleY = it.y + if (it.z != 1f) scaleZ = it.z } - //TODO convert units if needed } fun T.withPosition(root: Gdml, physVolume: GdmlPhysVolume): T = withPosition( @@ -301,7 +302,7 @@ private class GdmlTransformerEnv(val settings: GdmlTransformer) { val first: GdmlSolid = solid.first.resolve(root) ?: error("") val second: GdmlSolid = solid.second.resolve(root) ?: error("") val type: CompositeType = when (solid) { - is GdmlUnion -> CompositeType.UNION + is GdmlUnion -> CompositeType.SUM // dumb sum for better performance is GdmlSubtraction -> CompositeType.SUBTRACT is GdmlIntersection -> CompositeType.INTERSECT } diff --git a/visionforge-gdml/src/jsMain/kotlin/space/kscience/visionforge/gdml/gdmlJs.kt b/visionforge-gdml/src/jsMain/kotlin/space/kscience/visionforge/gdml/gdmlJs.kt deleted file mode 100644 index f90eec29..00000000 --- a/visionforge-gdml/src/jsMain/kotlin/space/kscience/visionforge/gdml/gdmlJs.kt +++ /dev/null @@ -1,8 +0,0 @@ -package space.kscience.visionforge.gdml - -public actual class Counter { - private var count: Int = 0 - public actual fun get(): Int = count - - public actual fun incrementAndGet(): Int = count++ -} \ No newline at end of file diff --git a/visionforge-gdml/src/jvmMain/kotlin/space/kscience/visionforge/gdml/gdmlJVM.kt b/visionforge-gdml/src/jvmMain/kotlin/space/kscience/visionforge/gdml/gdmlJVM.kt index 7bd17a5c..b67e231e 100644 --- a/visionforge-gdml/src/jvmMain/kotlin/space/kscience/visionforge/gdml/gdmlJVM.kt +++ b/visionforge-gdml/src/jvmMain/kotlin/space/kscience/visionforge/gdml/gdmlJVM.kt @@ -4,9 +4,6 @@ import space.kscience.gdml.Gdml import space.kscience.gdml.decodeFromFile import space.kscience.visionforge.solid.SolidGroup import java.nio.file.Path -import java.util.concurrent.atomic.AtomicInteger - -public actual typealias Counter = AtomicInteger public fun SolidGroup.gdml( file: Path, diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Composite.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Composite.kt index 35cf7ab6..d1d41d09 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Composite.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Composite.kt @@ -6,7 +6,8 @@ import space.kscience.dataforge.meta.update import space.kscience.visionforge.* public enum class CompositeType { - UNION, + SUM, // Dumb sum of meshes + UNION, //CSG union INTERSECT, SUBTRACT } diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solid.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solid.kt index f2b14f2a..0b3dee57 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solid.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solid.kt @@ -48,7 +48,7 @@ public interface Solid : Vision { public val Y_KEY: Name = "y".asName() public val Z_KEY: Name = "z".asName() - public val POSITION_KEY: Name = "pos".asName() + public val POSITION_KEY: Name = "position".asName() public val X_POSITION_KEY: Name = POSITION_KEY + X_KEY public val Y_POSITION_KEY: Name = POSITION_KEY + Y_KEY @@ -83,6 +83,18 @@ public interface Solid : Vision { hide() } + node(POSITION_KEY){ + hide() + } + + node(ROTATION_KEY){ + hide() + } + + node(SCALE_KEY){ + hide() + } + value(DETAIL_KEY) { type(ValueType.NUMBER) hide() @@ -145,7 +157,7 @@ public var Vision.ignore: Boolean? // get() = getProperty(SELECTED_KEY).boolean // set(value) = setProperty(SELECTED_KEY, value) -internal fun number(name: Name, default: Number): ReadWriteProperty = +internal fun float(name: Name, default: Number): ReadWriteProperty = object : ReadWriteProperty { override fun getValue(thisRef: Solid, property: KProperty<*>): Number { return thisRef.getOwnProperty(name)?.number ?: default @@ -156,33 +168,40 @@ internal fun number(name: Name, default: Number): ReadWriteProperty = - object : ReadWriteProperty { - override fun getValue(thisRef: Solid, property: KProperty<*>): Point3D = object : Point3D { - override val x: Float get() = thisRef.getOwnProperty(name + X_KEY)?.float ?: default - override val y: Float get() = thisRef.getOwnProperty(name + Y_KEY)?.float ?: default - override val z: Float get() = thisRef.getOwnProperty(name + Z_KEY)?.float ?: default +internal fun point(name: Name, default: Float): ReadWriteProperty = + object : ReadWriteProperty { + override fun getValue(thisRef: Solid, property: KProperty<*>): Point3D? { + val item = thisRef.getOwnProperty(name) ?: return null + return object : Point3D { + override val x: Float get() = item[X_KEY]?.float ?: default + override val y: Float get() = item[Y_KEY]?.float ?: default + override val z: Float get() = item[Z_KEY]?.float ?: default + } } - override fun setValue(thisRef: Solid, property: KProperty<*>, value: Point3D) { - thisRef.setProperty(name + X_KEY, value.x) - thisRef.setProperty(name + Y_KEY, value.y) - thisRef.setProperty(name + Z_KEY, value.z) + override fun setValue(thisRef: Solid, property: KProperty<*>, value: Point3D?) { + if (value == null) { + thisRef.setProperty(name, null) + } else { + thisRef.setProperty(name + X_KEY, value.x) + thisRef.setProperty(name + Y_KEY, value.y) + thisRef.setProperty(name + Z_KEY, value.z) + } } } -public var Solid.position: Point3D by point(POSITION_KEY, 0f) -public var Solid.rotation: Point3D by point(ROTATION_KEY, 0f) -public var Solid.scale: Point3D by point(SCALE_KEY, 1f) +public var Solid.position: Point3D? by point(POSITION_KEY, 0f) +public var Solid.rotation: Point3D? by point(ROTATION_KEY, 0f) +public var Solid.scale: Point3D? by point(SCALE_KEY, 1f) -public var Solid.x: Number by number(X_POSITION_KEY, 0f) -public var Solid.y: Number by number(Y_POSITION_KEY, 0f) -public var Solid.z: Number by number(Z_POSITION_KEY, 0f) +public var Solid.x: Number by float(X_POSITION_KEY, 0f) +public var Solid.y: Number by float(Y_POSITION_KEY, 0f) +public var Solid.z: Number by float(Z_POSITION_KEY, 0f) -public var Solid.rotationX: Number by number(X_ROTATION_KEY, 0f) -public var Solid.rotationY: Number by number(Y_ROTATION_KEY, 0f) -public var Solid.rotationZ: Number by number(Z_ROTATION_KEY, 0f) +public var Solid.rotationX: Number by float(X_ROTATION_KEY, 0f) +public var Solid.rotationY: Number by float(Y_ROTATION_KEY, 0f) +public var Solid.rotationZ: Number by float(Z_ROTATION_KEY, 0f) -public var Solid.scaleX: Number by number(X_SCALE_KEY, 1f) -public var Solid.scaleY: Number by number(Y_SCALE_KEY, 1f) -public var Solid.scaleZ: Number by number(Z_SCALE_KEY, 1f) \ No newline at end of file +public var Solid.scaleX: Number by float(X_SCALE_KEY, 1f) +public var Solid.scaleY: Number by float(Y_SCALE_KEY, 1f) +public var Solid.scaleZ: Number by float(Z_SCALE_KEY, 1f) \ No newline at end of file diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/transform/RemoveSingleChild.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/transform/RemoveSingleChild.kt index c0c02bc7..a51aaa25 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/transform/RemoveSingleChild.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/transform/RemoveSingleChild.kt @@ -1,32 +1,39 @@ package space.kscience.visionforge.solid.transform +import space.kscience.dataforge.meta.itemSequence import space.kscience.dataforge.misc.DFExperimental import space.kscience.dataforge.names.asName -import space.kscience.visionforge.* +import space.kscience.visionforge.MutableVisionGroup +import space.kscience.visionforge.Vision +import space.kscience.visionforge.VisionGroup +import space.kscience.visionforge.meta import space.kscience.visionforge.solid.* +private operator fun Number.plus(other: Number) = toFloat() + other.toFloat() +private operator fun Number.times(other: Number) = toFloat() * other.toFloat() + @DFExperimental -internal fun mergeChild(parent: VisionGroup, child: Vision): Vision { - return child.apply { - - configure(parent.meta) - - //parent.properties?.let { config.update(it) } - - if (this is Solid && parent is Solid) { - position += parent.position - rotation += parent.rotation - scale = Point3D( - scale.x * parent.scale.x, - scale.y * parent.scale.y, - scale.z * parent.scale.z - ) - +internal fun Vision.updateFrom(other: Vision): Vision { + if (this is Solid && other is Solid) { + x += other.x + y += other.y + z += other.y + rotationX += other.rotationX + rotationY += other.rotationY + rotationZ += other.rotationZ + scaleX *= other.scaleX + scaleY *= other.scaleY + scaleZ *= other.scaleZ + other.meta.itemSequence().forEach { (name, item) -> + if (getProperty(name) == null) { + setProperty(name, item) + } } - } + return this } + @DFExperimental internal object RemoveSingleChild : VisualTreeTransform() { @@ -39,7 +46,7 @@ internal object RemoveSingleChild : VisualTreeTransform() { } if (parent is VisionGroup && parent.children.size == 1) { val child = parent.children.values.first() - val newParent = mergeChild(parent, child) + val newParent = child.updateFrom(parent) newParent.parent = null set(childName.asName(), newParent) } diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/transform/UnRef.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/transform/UnRef.kt index b6d7c2e6..890c8291 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/transform/UnRef.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/transform/UnRef.kt @@ -31,7 +31,7 @@ internal object UnRef : VisualTreeTransform() { } children.filter { (it.value as? SolidReferenceGroup)?.refName == name }.forEach { (key, value) -> val reference = value as SolidReferenceGroup - val newChild = mergeChild(reference, reference.prototype) + val newChild = reference.prototype.updateFrom(reference) newChild.parent = null set(key.asName(), newChild) // replace proxy with merged object } diff --git a/visionforge-threejs/src/main/kotlin/info/laht/threekt/utils/BufferGeometryUtils.kt b/visionforge-threejs/src/main/kotlin/info/laht/threekt/utils/BufferGeometryUtils.kt new file mode 100644 index 00000000..dd15b514 --- /dev/null +++ b/visionforge-threejs/src/main/kotlin/info/laht/threekt/utils/BufferGeometryUtils.kt @@ -0,0 +1,15 @@ +@file:JsModule("three/examples/jsm/utils/BufferGeometryUtils") +@file:JsNonModule +package info.laht.threekt.utils + +import info.laht.threekt.core.BufferGeometry + + +public external object BufferGeometryUtils { + /** + * Merges a set of geometries into a single instance. All geometries must have compatible attributes. If merge does not succeed, the method returns null. + * @param geometries -- Array of BufferGeometry instances. + * @param useGroups -- Whether groups should be generated for the merged geometry or not. + */ + public fun mergeBufferGeometries(geometries: Array, useGroups: Boolean): BufferGeometry +} \ No newline at end of file diff --git a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeCompositeFactory.kt b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeCompositeFactory.kt index 33304b72..2cdd12d3 100644 --- a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeCompositeFactory.kt +++ b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeCompositeFactory.kt @@ -42,9 +42,9 @@ public class ThreeCompositeFactory(public val three: ThreePlugin) : ThreeFactory val first = three.buildObject3D(obj.first) as? Mesh ?: error("First part of composite is not a mesh") val second = three.buildObject3D(obj.second) as? Mesh ?: error("Second part of composite is not a mesh") return when (obj.compositeType) { - CompositeType.UNION -> CSG.union(first,second) - CompositeType.INTERSECT -> CSG.intersect(first,second) - CompositeType.SUBTRACT -> CSG.subtract(first,second) + CompositeType.SUM, CompositeType.UNION -> CSG.union(first, second) + CompositeType.INTERSECT -> CSG.intersect(first, second) + CompositeType.SUBTRACT -> CSG.subtract(first, second) }.apply { updatePosition(obj) applyProperties(obj) From 42e2530f6fb3b8db94a8c55f50817a2d1a13a7ad Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 11 Jul 2021 15:16:04 +0300 Subject: [PATCH 08/29] cleanup --- .../kscience/visionforge/VisionGroupBase.kt | 2 +- .../kscience/visionforge/solid/SolidGroup.kt | 3 --- .../visionforge/solid/SolidReference.kt | 17 ----------------- 3 files changed, 1 insertion(+), 21 deletions(-) diff --git a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionGroupBase.kt b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionGroupBase.kt index 44800673..997789c1 100644 --- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionGroupBase.kt +++ b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionGroupBase.kt @@ -17,7 +17,7 @@ import space.kscience.dataforge.names.* @Serializable @SerialName("vision.group") public open class VisionGroupBase( - @SerialName("children") internal val childrenInternal: MutableMap = LinkedHashMap(), + @SerialName("children") protected val childrenInternal: MutableMap = LinkedHashMap(), ) : VisionBase(), MutableVisionGroup { /** diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidGroup.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidGroup.kt index ad2107f0..513a6fc9 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidGroup.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidGroup.kt @@ -29,9 +29,6 @@ public interface PrototypeHolder { @SerialName("group.solid") public class SolidGroup( @Serializable(PrototypeSerializer::class) internal var prototypes: MutableVisionGroup? = null, -// override var position: Point3D? = null, -// override var rotation: Point3D? = null, -// override var scale: Point3D? = null, ) : VisionGroupBase(), Solid, PrototypeHolder { init { diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidReference.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidReference.kt index 3d067a62..8778657f 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidReference.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidReference.kt @@ -95,23 +95,6 @@ public class SolidReferenceGroup( * (properties are stored in external cache) and created and destroyed on-demand). */ private inner class ReferenceChild(private val childName: Name) : SolidReference, VisionGroup { - -// //TODO replace by properties -// override var position: Point3D? -// get() = prototype.position -// set(_) { -// error("Can't set position of reference") -// } -// override var rotation: Point3D? -// get() = prototype.rotation -// set(_) { -// error("Can't set position of reference") -// } -// override var scale: Point3D? -// get() = prototype.scale -// set(_) { -// error("Can't set position of reference") -// } override val prototype: Solid get() = prototypeFor(childName) override val children: Map From 073d374a9e84255b0997ed687add95847448210c Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Mon, 12 Jul 2021 10:01:21 +0300 Subject: [PATCH 09/29] Fix tests with new prototype location --- .../{GDMLVisualTest.kt => GDMLVisionTest.kt} | 2 +- .../space/kscience/visionforge/VisionBase.kt | 7 +- .../kscience/visionforge/gdml/layerMarker.kt | 23 ++++ .../src/commonTest/kotlin/TestCubes.kt | 2 +- .../visionforge/gdml/bmanStatistics.kt | 3 +- .../space/kscience/visionforge/solid/Solid.kt | 1 + .../kscience/visionforge/solid/SolidBase.kt | 6 +- .../kscience/visionforge/solid/SolidGroup.kt | 82 +++----------- .../visionforge/solid/SolidReference.kt | 100 +++++++++--------- 9 files changed, 96 insertions(+), 130 deletions(-) rename demo/gdml/src/commonTest/kotlin/space/kscience/visionforge/gdml/{GDMLVisualTest.kt => GDMLVisionTest.kt} (97%) create mode 100644 visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/layerMarker.kt diff --git a/demo/gdml/src/commonTest/kotlin/space/kscience/visionforge/gdml/GDMLVisualTest.kt b/demo/gdml/src/commonTest/kotlin/space/kscience/visionforge/gdml/GDMLVisionTest.kt similarity index 97% rename from demo/gdml/src/commonTest/kotlin/space/kscience/visionforge/gdml/GDMLVisualTest.kt rename to demo/gdml/src/commonTest/kotlin/space/kscience/visionforge/gdml/GDMLVisionTest.kt index c12c7215..17bdc014 100644 --- a/demo/gdml/src/commonTest/kotlin/space/kscience/visionforge/gdml/GDMLVisualTest.kt +++ b/demo/gdml/src/commonTest/kotlin/space/kscience/visionforge/gdml/GDMLVisionTest.kt @@ -10,7 +10,7 @@ import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertNotNull -class GDMLVisualTest { +class GDMLVisionTest { // @Test // fun testCubesStyles(){ diff --git a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionBase.kt b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionBase.kt index c9b68219..62f90f52 100644 --- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionBase.kt +++ b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionBase.kt @@ -28,11 +28,10 @@ internal data class PropertyListener( */ @Serializable @SerialName("vision") -public open class VisionBase : Vision { +public open class VisionBase( + override @Transient var parent: VisionGroup? = null, protected var properties: Config? = null - - @Transient - override var parent: VisionGroup? = null +) : Vision { @Synchronized protected fun getOrCreateProperties(): Config { diff --git a/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/layerMarker.kt b/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/layerMarker.kt new file mode 100644 index 00000000..17b75e79 --- /dev/null +++ b/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/layerMarker.kt @@ -0,0 +1,23 @@ +package space.kscience.visionforge.gdml + +import space.kscience.dataforge.names.Name +import space.kscience.dataforge.names.plus +import space.kscience.visionforge.VisionGroup + +private fun VisionGroup.countChildren(namePrefix: Name, cache: MutableMap = hashMapOf()): Int { + var counter = 0 + children.forEach { (token, child) -> + if (child is VisionGroup) { + counter += child.countChildren(namePrefix + token, cache) + } else { + counter++ + } + } + cache[namePrefix] = counter + return counter +} + + +public fun VisionGroup.processLayers() { + +} \ No newline at end of file diff --git a/visionforge-gdml/src/commonTest/kotlin/TestCubes.kt b/visionforge-gdml/src/commonTest/kotlin/TestCubes.kt index a364996c..9fb80095 100644 --- a/visionforge-gdml/src/commonTest/kotlin/TestCubes.kt +++ b/visionforge-gdml/src/commonTest/kotlin/TestCubes.kt @@ -26,7 +26,7 @@ class TestCubes { val smallBoxPrototype = vision.getPrototype("solids.smallBox".toName()) as? Box assertNotNull(smallBoxPrototype) assertEquals(30.0, smallBoxPrototype.xSize.toDouble()) - val smallBoxVision = vision["composite-111.smallBox"]?.prototype as? Box + val smallBoxVision = vision["composite-111.smallBox"]?.unref as? Box assertNotNull(smallBoxVision) assertEquals(30.0, smallBoxVision.xSize.toDouble()) } diff --git a/visionforge-gdml/src/jvmTest/kotlin/space/kscience/visionforge/gdml/bmanStatistics.kt b/visionforge-gdml/src/jvmTest/kotlin/space/kscience/visionforge/gdml/bmanStatistics.kt index eccac343..1f1da074 100644 --- a/visionforge-gdml/src/jvmTest/kotlin/space/kscience/visionforge/gdml/bmanStatistics.kt +++ b/visionforge-gdml/src/jvmTest/kotlin/space/kscience/visionforge/gdml/bmanStatistics.kt @@ -5,7 +5,6 @@ import kotlinx.coroutines.withContext import nl.adaptivity.xmlutil.StAXReader import space.kscience.gdml.Gdml import space.kscience.gdml.decodeFromReader -import space.kscience.visionforge.solid.prototype import space.kscience.visionforge.visitor.countDistinct import space.kscience.visionforge.visitor.flowStatistics import java.io.File @@ -23,7 +22,7 @@ suspend fun main() { vision.flowStatistics>{ _, child -> - child.prototype::class + child::class }.countDistinct().forEach { (depth, size) -> println("$depth\t$size") } diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solid.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solid.kt index 0b3dee57..a4c8e69c 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solid.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solid.kt @@ -34,6 +34,7 @@ import kotlin.reflect.KProperty * Interface for 3-dimensional [Vision] */ public interface Solid : Vision { + override val descriptor: NodeDescriptor get() = Companion.descriptor public companion object { diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidBase.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidBase.kt index 1f86bdb3..c88052b2 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidBase.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidBase.kt @@ -12,11 +12,7 @@ import space.kscience.visionforge.VisionChange @Serializable @SerialName("solid") -public open class SolidBase( -// override var position: Point3D? = null, -// override var rotation: Point3D? = null, -// override var scale: Point3D? = null, -) : VisionBase(), Solid { +public open class SolidBase : VisionBase(), Solid { override val descriptor: NodeDescriptor get() = Solid.descriptor override fun update(change: VisionChange) { diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidGroup.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidGroup.kt index 513a6fc9..27f95c17 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidGroup.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidGroup.kt @@ -1,14 +1,7 @@ package space.kscience.visionforge.solid -import kotlinx.serialization.KSerializer -import kotlinx.serialization.PolymorphicSerializer import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable -import kotlinx.serialization.builtins.MapSerializer -import kotlinx.serialization.descriptors.SerialDescriptor -import kotlinx.serialization.encoding.Decoder -import kotlinx.serialization.encoding.Encoder -import space.kscience.dataforge.meta.MetaItem import space.kscience.dataforge.meta.descriptors.NodeDescriptor import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.NameToken @@ -27,37 +20,35 @@ public interface PrototypeHolder { */ @Serializable @SerialName("group.solid") -public class SolidGroup( - @Serializable(PrototypeSerializer::class) internal var prototypes: MutableVisionGroup? = null, -) : VisionGroupBase(), Solid, PrototypeHolder { +public class SolidGroup : VisionGroupBase(), Solid, PrototypeHolder { + + override val children: Map get() = super.childrenInternal.filter { it.key != PROTOTYPES_TOKEN } + + public var prototypes: MutableVisionGroup? + get() = childrenInternal[PROTOTYPES_TOKEN] as? MutableVisionGroup + set(value) { + set(PROTOTYPES_TOKEN, value) + } - init { - prototypes?.parent = this - } override val descriptor: NodeDescriptor get() = Solid.descriptor /** - * Ger a prototype redirecting the request to the parent if prototype is not found + * Get a prototype redirecting the request to the parent if prototype is not found. + * If prototype is a ref, then it is unfolded until */ override fun getPrototype(name: Name): Solid? = - (prototypes?.get(name) as? Solid) ?: (parent as? PrototypeHolder)?.getPrototype(name) + prototypes?.get(name)?.unref ?: (parent as? PrototypeHolder)?.getPrototype(name) /** * Create or edit prototype node as a group */ override fun prototypes(builder: VisionContainerBuilder.() -> Unit): Unit { - (prototypes ?: Prototypes().also { + (prototypes ?: SolidGroup().also { prototypes = it - it.parent = this }).run(builder) } -// /** -// * TODO add special static group to hold statics without propagation -// */ -// override fun addStatic(child: VisualObject) = setChild(NameToken("@static(${child.hashCode()})"), child) - override fun createGroup(): SolidGroup = SolidGroup() override fun update(change: VisionChange) { @@ -87,50 +78,3 @@ public fun VisionContainerBuilder.group( @VisionBuilder public fun VisionContainerBuilder.group(name: String, action: SolidGroup.() -> Unit = {}): SolidGroup = SolidGroup().apply(action).also { set(name, it) } - -/** - * A special class which works as a holder for prototypes - */ -internal class Prototypes( - children: MutableMap = hashMapOf(), -) : VisionGroupBase(children), PrototypeHolder { - - override fun getProperty( - name: Name, - inherit: Boolean, - includeStyles: Boolean, - includeDefaults: Boolean, - ): MetaItem? = null - - override fun setProperty(name: Name, item: MetaItem?, notify: Boolean) { - error("Can't set property of a prototypes container") - } - - override val descriptor: NodeDescriptor? = null - - override fun prototypes(builder: VisionContainerBuilder.() -> Unit) { - apply(builder) - } - - override fun getPrototype(name: Name): Solid? = get(name) as? Solid -} - -internal class PrototypeSerializer : KSerializer { - - private val mapSerializer: KSerializer> = - MapSerializer( - NameToken.serializer(), - PolymorphicSerializer(Vision::class) - ) - - override val descriptor: SerialDescriptor get() = mapSerializer.descriptor - - override fun deserialize(decoder: Decoder): MutableVisionGroup { - val map = mapSerializer.deserialize(decoder) - return Prototypes(map.toMutableMap()) - } - - override fun serialize(encoder: Encoder, value: MutableVisionGroup) { - mapSerializer.serialize(encoder, value.children) - } -} \ No newline at end of file diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidReference.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidReference.kt index 8778657f..401f8097 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidReference.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidReference.kt @@ -11,10 +11,27 @@ import space.kscience.dataforge.misc.DFExperimental import space.kscience.dataforge.names.* import space.kscience.visionforge.* -public interface SolidReference : Solid { + +public interface SolidReference : VisionGroup { + /** + * The prototype for this reference. Always returns a "real" prototype, not a reference + */ public val prototype: Solid } + +/** + * Get a vision prototype if it is a [SolidReference] or vision itself if it is not. + * Unref is recursive, so it always returns a non-reference. + */ +public val Vision.unref: Solid + get() = when (this) { + is SolidReference -> prototype.unref + is Solid -> this + else -> error("This Vision is neither Solid nor SolidReference") + } + + private fun SolidReference.getRefProperty( name: Name, inherit: Boolean, @@ -31,6 +48,12 @@ private fun SolidReference.getRefProperty( } }.merge() +private fun childToken(childName: Name): NameToken = + NameToken(SolidReferenceGroup.REFERENCE_CHILD_PROPERTY_PREFIX, childName.toString()) + +private fun childPropertyName(childName: Name, propertyName: Name): Name = + childToken(childName) + propertyName + /** * A reference [Solid] to reuse a template object */ @@ -38,48 +61,24 @@ private fun SolidReference.getRefProperty( @SerialName("solid.ref") public class SolidReferenceGroup( public val refName: Name, -) : SolidBase(), SolidReference, VisionGroup { +) : VisionBase(), SolidReference, VisionGroup, Solid { /** * Recursively search for defined template in the parent */ - override val prototype: Solid - get() { - if (parent == null) error("No parent is present for SolidReferenceGroup") - if (parent !is SolidGroup) error("Reference parent is not a group") - return (parent as? SolidGroup)?.getPrototype(refName) - ?: error("Prototype with name $refName not found") - } + override val prototype: Solid by lazy { + if (parent == null) error("No parent is present for SolidReferenceGroup") + if (parent !is PrototypeHolder) error("Parent does not hold prototypes") + (parent as? PrototypeHolder)?.getPrototype(refName) ?: error("Prototype with name $refName not found") + } override val children: Map get() = (prototype as? VisionGroup)?.children - ?.filter { !it.key.toString().startsWith("@") } + ?.filter { it.key != SolidGroup.PROTOTYPES_TOKEN } ?.mapValues { - ReferenceChild(it.key.asName()) + ReferenceChild(this, it.key.asName()) } ?: emptyMap() - private fun childToken(childName: Name): NameToken = - NameToken(REFERENCE_CHILD_PROPERTY_PREFIX, childName.toString()) - - private fun childPropertyName(childName: Name, propertyName: Name): Name = - childToken(childName) + propertyName - - private fun getChildProperty(childName: Name, propertyName: Name): MetaItem? { - return getOwnProperty(childPropertyName(childName, propertyName)) - } - - private fun setChildProperty(childName: Name, propertyName: Name, item: MetaItem?, notify: Boolean) { - setProperty(childPropertyName(childName, propertyName), item, notify) - } - - private fun prototypeFor(name: Name): Solid { - return if (name.isEmpty()) prototype else { - val proto = (prototype as? SolidGroup)?.get(name) - ?: error("Prototype with name $name not found in SolidReferenceGroup $refName") - proto as? Solid ?: error("Prototype with name $name is ${proto::class} but expected Solid") - } - } - override fun getProperty( name: Name, inherit: Boolean, @@ -94,20 +93,31 @@ public class SolidReferenceGroup( * A ProxyChild is created temporarily only to interact with properties, it does not store any values * (properties are stored in external cache) and created and destroyed on-demand). */ - private inner class ReferenceChild(private val childName: Name) : SolidReference, VisionGroup { - override val prototype: Solid get() = prototypeFor(childName) + private class ReferenceChild( + val owner: SolidReferenceGroup, + private val childName: Name + ) : SolidReference, VisionGroup { + + override val prototype: Solid by lazy { + if (childName.isEmpty()) owner.prototype else { + val proto = (owner.prototype as? VisionGroup)?.get(childName) + ?: error("Prototype with name $childName not found in SolidReferenceGroup ${owner.refName}") + proto.unref as? Solid ?: error("Prototype with name $childName is ${proto::class} but expected Solid") + } + } override val children: Map get() = (prototype as? VisionGroup)?.children - ?.filter { !it.key.toString().startsWith("@") } + ?.filter { it.key != SolidGroup.PROTOTYPES_TOKEN } ?.mapValues { (key, _) -> - ReferenceChild(childName + key.asName()) + ReferenceChild(owner, childName + key.asName()) } ?: emptyMap() - override fun getOwnProperty(name: Name): MetaItem? = getChildProperty(childName, name) + override fun getOwnProperty(name: Name): MetaItem? = + owner.getOwnProperty(childPropertyName(childName, name)) override fun setProperty(name: Name, item: MetaItem?, notify: Boolean) { - setChildProperty(childName, name, item, notify) + owner.setProperty(childPropertyName(childName, name), item, notify) } override fun getProperty( @@ -124,7 +134,7 @@ public class SolidReferenceGroup( override var parent: VisionGroup? get() { val parentName = childName.cutLast() - return if (parentName.isEmpty()) this@SolidReferenceGroup else ReferenceChild(parentName) + return if (parentName.isEmpty()) owner else ReferenceChild(owner, parentName) } set(_) { error("Setting a parent for a reference child is not possible") @@ -132,7 +142,7 @@ public class SolidReferenceGroup( @DFExperimental override val propertyChanges: Flow - get() = this@SolidReferenceGroup.propertyChanges.mapNotNull { name -> + get() = owner.propertyChanges.mapNotNull { name -> if (name.startsWith(childToken(childName))) { name.cutFirst() } else { @@ -141,7 +151,7 @@ public class SolidReferenceGroup( } override fun invalidateProperty(propertyName: Name) { - this@SolidReferenceGroup.invalidateProperty(childPropertyName(childName, propertyName)) + owner.invalidateProperty(childPropertyName(childName, propertyName)) } override fun update(change: VisionChange) { @@ -159,12 +169,6 @@ public class SolidReferenceGroup( } } -/** - * Get a vision prototype if it is a [SolidReferenceGroup] or vision itself if it is not - */ -public val Vision.prototype: Vision - get() = if (this is SolidReference) prototype.prototype else this - /** * Create ref for existing prototype */ From 5af8fe3e994b0b61b130535442a704bd5c043066 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Mon, 12 Jul 2021 13:23:25 +0300 Subject: [PATCH 10/29] Minor ref cleanup --- .../kscience/visionforge/solid/SolidGroup.kt | 13 ++++++-- .../visionforge/solid/SolidReference.kt | 33 ++++++++++--------- 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidGroup.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidGroup.kt index 27f95c17..b78ec4a5 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidGroup.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidGroup.kt @@ -7,10 +7,19 @@ import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.NameToken import space.kscience.visionforge.* +/** + * A container with prototype support + */ public interface PrototypeHolder { + /** + * Build or update prototype tree + */ @VisionBuilder public fun prototypes(builder: VisionContainerBuilder.() -> Unit) + /** + * Resolve a prototype from this container. Should never return a ref. + */ public fun getPrototype(name: Name): Solid? } @@ -24,7 +33,7 @@ public class SolidGroup : VisionGroupBase(), Solid, PrototypeHolder { override val children: Map get() = super.childrenInternal.filter { it.key != PROTOTYPES_TOKEN } - public var prototypes: MutableVisionGroup? + private var prototypes: MutableVisionGroup? get() = childrenInternal[PROTOTYPES_TOKEN] as? MutableVisionGroup set(value) { set(PROTOTYPES_TOKEN, value) @@ -35,7 +44,7 @@ public class SolidGroup : VisionGroupBase(), Solid, PrototypeHolder { /** * Get a prototype redirecting the request to the parent if prototype is not found. - * If prototype is a ref, then it is unfolded until + * If prototype is a ref, then it is unfolded automatically. */ override fun getPrototype(name: Name): Solid? = prototypes?.get(name)?.unref ?: (parent as? PrototypeHolder)?.getPrototype(name) diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidReference.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidReference.kt index 401f8097..2b7a8358 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidReference.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidReference.kt @@ -37,16 +37,20 @@ private fun SolidReference.getRefProperty( inherit: Boolean, includeStyles: Boolean, includeDefaults: Boolean, -): MetaItem? = buildList { - add(getOwnProperty(name)) - if (includeStyles) { - addAll(getStyleItems(name)) - } - add(prototype.getProperty(name, inherit, includeStyles, includeDefaults)) - if (inherit) { - add(parent?.getProperty(name, inherit)) - } -}.merge() +): MetaItem? = if (!inherit && !includeStyles && !includeDefaults) { + getOwnProperty(name) +} else { + buildList { + add(getOwnProperty(name)) + if (includeStyles) { + addAll(getStyleItems(name)) + } + add(prototype.getProperty(name, inherit, includeStyles, includeDefaults)) + if (inherit) { + add(parent?.getProperty(name, inherit)) + } + }.merge() +} private fun childToken(childName: Name): NameToken = NameToken(SolidReferenceGroup.REFERENCE_CHILD_PROPERTY_PREFIX, childName.toString()) @@ -102,7 +106,8 @@ public class SolidReferenceGroup( if (childName.isEmpty()) owner.prototype else { val proto = (owner.prototype as? VisionGroup)?.get(childName) ?: error("Prototype with name $childName not found in SolidReferenceGroup ${owner.refName}") - proto.unref as? Solid ?: error("Prototype with name $childName is ${proto::class} but expected Solid") + proto.unref as? Solid + ?: error("Prototype with name $childName is ${proto::class} but expected Solid") } } @@ -125,11 +130,7 @@ public class SolidReferenceGroup( inherit: Boolean, includeStyles: Boolean, includeDefaults: Boolean, - ): MetaItem? = if (!inherit && !includeStyles && !includeDefaults) { - getOwnProperty(name) - } else { - getRefProperty(name, inherit, includeStyles, includeDefaults) - } + ): MetaItem? = getRefProperty(name, inherit, includeStyles, includeDefaults) override var parent: VisionGroup? get() { From 0d53b6f77dc2463120de8709e16663f7d99e8837 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Mon, 12 Jul 2021 15:22:02 +0300 Subject: [PATCH 11/29] Make solid arguments immutable --- CHANGELOG.md | 2 + .../kscience/visionforge/solid/demo/demo.kt | 7 ++- .../visionforge/solid/demo/VariableBox.kt | 2 +- .../visionforge/VisionPropertyContainer.kt | 19 +++++++- .../visionforge/gdml/GdmlTransformer.kt | 29 ++++++------ .../kscience/visionforge/solid/ConeSegment.kt | 16 ++++--- .../kscience/visionforge/solid/ConeSurface.kt | 18 +++++--- .../kscience/visionforge/solid/Extruded.kt | 45 +++++++++++-------- .../kscience/visionforge/solid/PolyLine.kt | 2 +- .../space/kscience/visionforge/solid/Solid.kt | 2 + .../kscience/visionforge/solid/SolidBase.kt | 16 ------- .../kscience/visionforge/solid/SolidLabel.kt | 6 +-- .../kscience/visionforge/solid/Sphere.kt | 13 +++--- .../kscience/visionforge/solid/SphereLayer.kt | 20 ++++++--- .../kscience/visionforge/solid/geometry.kt | 13 ++++++ .../{ThreeVision.kt => ThreeJsVision.kt} | 2 +- .../visionforge/solid/three/ThreePlugin.kt | 2 +- 17 files changed, 128 insertions(+), 86 deletions(-) rename visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/{ThreeVision.kt => ThreeJsVision.kt} (83%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ea6fc9b..aff57288 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,8 @@ - VisionGroup builder accepts `null` as name for statics instead of `""` - gdml sphere is rendered as a SphereLayer instead of Sphere (#35) - Tube is replaced by more general ConeSurface +- position, rotation and size moved to properties +- prototypes moved to children ### Deprecated diff --git a/demo/solid-showcase/src/commonMain/kotlin/space/kscience/visionforge/solid/demo/demo.kt b/demo/solid-showcase/src/commonMain/kotlin/space/kscience/visionforge/solid/demo/demo.kt index bfa90827..2385fef1 100644 --- a/demo/solid-showcase/src/commonMain/kotlin/space/kscience/visionforge/solid/demo/demo.kt +++ b/demo/solid-showcase/src/commonMain/kotlin/space/kscience/visionforge/solid/demo/demo.kt @@ -27,7 +27,7 @@ fun VisionLayout.demo(name: String, title: String = name, block: SolidGro } val canvasOptions = Canvas3DOptions { - size{ + size { minSize = 400 } axes { @@ -57,9 +57,8 @@ fun VisionLayout.showcase() { rotationX = PI / 4 color("blue") } - sphereLayer(50,40){ - theta = (PI/2).toFloat() - rotationX = - PI * 3 / 4 + sphereLayer(50, 40, theta = PI / 2) { + rotationX = -PI * 3 / 4 z = 110 color(Colors.pink) } diff --git a/demo/solid-showcase/src/jsMain/kotlin/space/kscience/visionforge/solid/demo/VariableBox.kt b/demo/solid-showcase/src/jsMain/kotlin/space/kscience/visionforge/solid/demo/VariableBox.kt index f372fa38..22cac2c6 100644 --- a/demo/solid-showcase/src/jsMain/kotlin/space/kscience/visionforge/solid/demo/VariableBox.kt +++ b/demo/solid-showcase/src/jsMain/kotlin/space/kscience/visionforge/solid/demo/VariableBox.kt @@ -23,7 +23,7 @@ internal fun SolidGroup.varBox( action: VariableBox.() -> Unit = {}, ): 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 { val geometry = BoxGeometry(xSize, ySize, 1) diff --git a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionPropertyContainer.kt b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionPropertyContainer.kt index 68567ee3..112295c9 100644 --- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionPropertyContainer.kt +++ b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionPropertyContainer.kt @@ -1,12 +1,15 @@ package space.kscience.visionforge +import space.kscience.dataforge.meta.Config import space.kscience.dataforge.meta.MetaItem +import space.kscience.dataforge.meta.get +import space.kscience.dataforge.meta.set import space.kscience.dataforge.names.Name /** * Property containers are used to create a symmetric behaviors for vision properties and style builders */ -public interface VisionPropertyContainer { +public interface VisionPropertyContainer { public fun getProperty( name: Name, inherit: Boolean = false, @@ -15,4 +18,18 @@ public interface VisionPropertyContainer { ): MetaItem? public fun setProperty(name: Name, item: MetaItem?, notify: Boolean = true) +} + +public open class SimpleVisionPropertyContainer(protected val config: Config): VisionPropertyContainer{ + 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 + } + } \ No newline at end of file diff --git a/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/GdmlTransformer.kt b/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/GdmlTransformer.kt index 3a7b48af..98b4509e 100644 --- a/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/GdmlTransformer.kt +++ b/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/GdmlTransformer.kt @@ -232,11 +232,10 @@ private class GdmlTransformerEnv(val settings: GdmlTransformer) { bottomRadius = solid.rmax1 * lScale, height = solid.z * lScale, upperRadius = solid.rmax2 * lScale, + startAngle = solid.startphi * aScale, + angle = solid.deltaphi * aScale, name = name - ) { - startAngle = solid.startphi * aScale - angle = solid.deltaphi * aScale - } + ) } else { coneSurface( bottomOuterRadius = solid.rmax1 * lScale, @@ -244,11 +243,10 @@ private class GdmlTransformerEnv(val settings: GdmlTransformer) { height = solid.z * lScale, topOuterRadius = solid.rmax2 * lScale, topInnerRadius = solid.rmin2 * lScale, + startAngle = solid.startphi * aScale, + angle = solid.deltaphi * aScale, name = name - ) { - startAngle = solid.startphi * aScale - angle = solid.deltaphi * aScale - } + ) } is GdmlXtru -> extrude(name) { shape { @@ -276,12 +274,15 @@ private class GdmlTransformerEnv(val settings: GdmlTransformer) { scaleZ = solid.scale.z.toFloat() } } - is GdmlSphere -> sphereLayer(solid.rmax * lScale, solid.rmin * lScale, name) { - phi = solid.deltaphi * aScale - theta = solid.deltatheta * aScale - phiStart = solid.startphi * aScale - thetaStart = solid.starttheta * aScale - } + is GdmlSphere -> sphereLayer( + outerRadius = solid.rmax * lScale, + innerRadius = solid.rmin * lScale, + phi = solid.deltaphi * aScale, + theta = solid.deltatheta * aScale, + phiStart = solid.startphi * aScale, + thetaStart = solid.starttheta * aScale, + name = name, + ) is GdmlOrb -> sphere(solid.r * lScale, name = name) is GdmlPolyhedra -> extrude(name) { //getting the radius of first diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/ConeSegment.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/ConeSegment.kt index 211e3af2..560ec496 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/ConeSegment.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/ConeSegment.kt @@ -15,11 +15,11 @@ import kotlin.math.sin @Serializable @SerialName("solid.cone") public class ConeSegment( - public var bottomRadius: Float, - public var height: Float, - public var topRadius: Float, - public var startAngle: Float = 0f, - public var angle: Float = PI2 + public val bottomRadius: Float, + public val height: Float, + public val topRadius: Float, + public val startAngle: Float = 0f, + public val angle: Float = PI2 ) : SolidBase(), GeometrySolid { override fun toGeometry(geometryBuilder: GeometryBuilder) { @@ -83,10 +83,14 @@ public inline fun VisionContainerBuilder.cone( bottomRadius: Number, height: Number, upperRadius: Number = 0.0, + startAngle: Number = 0f, + angle: Number = PI2, name: String? = null, block: ConeSegment.() -> Unit = {} ): ConeSegment = ConeSegment( bottomRadius.toFloat(), height.toFloat(), - topRadius = upperRadius.toFloat() + topRadius = upperRadius.toFloat(), + startAngle = startAngle.toFloat(), + angle = angle.toFloat() ).apply(block).also { set(name, it) } \ No newline at end of file diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/ConeSurface.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/ConeSurface.kt index caa8c746..a9c5622b 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/ConeSurface.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/ConeSurface.kt @@ -16,13 +16,13 @@ import kotlin.math.sin @Serializable @SerialName("solid.coneSurface") public class ConeSurface( - public var bottomRadius: Float, - public var bottomInnerRadius: Float, - public var height: Float, - public var topRadius: Float, - public var topInnerRadius: Float, - public var startAngle: Float = 0f, - public var angle: Float = PI2, + public val bottomRadius: Float, + public val bottomInnerRadius: Float, + public val height: Float, + public val topRadius: Float, + public val topInnerRadius: Float, + public val startAngle: Float = 0f, + public val angle: Float = PI2, ) : SolidBase(), GeometrySolid { init { @@ -148,6 +148,8 @@ public inline fun VisionContainerBuilder.coneSurface( height: Number, topOuterRadius: Number, topInnerRadius: Number, + startAngle: Number = 0f, + angle: Number = PI2, name: String? = null, block: ConeSurface.() -> Unit = {}, ): ConeSurface = ConeSurface( @@ -156,4 +158,6 @@ public inline fun VisionContainerBuilder.coneSurface( height = height.toFloat(), topRadius = topOuterRadius.toFloat(), topInnerRadius = topInnerRadius.toFloat(), + startAngle = startAngle.toFloat(), + angle = angle.toFloat() ).apply(block).also { set(name, it) } \ No newline at end of file diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Extruded.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Extruded.kt index d5943e3a..40e03512 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Extruded.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Extruded.kt @@ -2,9 +2,8 @@ package space.kscience.visionforge.solid import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable -import space.kscience.visionforge.VisionBuilder -import space.kscience.visionforge.VisionContainerBuilder -import space.kscience.visionforge.set +import space.kscience.dataforge.meta.Config +import space.kscience.visionforge.* import kotlin.math.PI import kotlin.math.cos import kotlin.math.sin @@ -13,7 +12,7 @@ import kotlin.math.sin public typealias Shape2D = List @Serializable -public class Shape2DBuilder(private val points: MutableList = ArrayList()) { +public class Shape2DBuilder(private val points: ArrayList = ArrayList()) { public fun point(x: Number, y: Number) { 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 @SerialName("solid.extrude") public class Extruded( - public var shape: List = ArrayList(), - public var layers: MutableList = ArrayList() -) : SolidBase(), GeometrySolid { - - 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 - } + public val shape: List, + public val layers: List +) : SolidBase(), GeometrySolid, VisionPropertyContainer { override fun toGeometry(geometryBuilder: GeometryBuilder) { val shape: Shape2D = shape @@ -103,6 +92,24 @@ public class Extruded( } } +public class ExtrudeBuilder( + public var shape: List = emptyList(), + public var layers: ArrayList = ArrayList(), + config: Config = Config() +) : SimpleVisionPropertyContainer(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 -public fun VisionContainerBuilder.extrude(name: String? = null, action: Extruded.() -> Unit = {}): Extruded = - Extruded().apply(action).also { set(name, it) } \ No newline at end of file +public fun VisionContainerBuilder.extrude( + name: String? = null, + action: ExtrudeBuilder.() -> Unit = {} +): Extruded = ExtrudeBuilder().apply(action).build().also { set(name, it) } \ No newline at end of file diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/PolyLine.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/PolyLine.kt index 41fe9903..cd9f2cbd 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/PolyLine.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/PolyLine.kt @@ -13,7 +13,7 @@ import space.kscience.visionforge.set @Serializable @SerialName("solid.line") -public class PolyLine(public var points: List) : SolidBase(), Solid { +public class PolyLine(public val points: List) : SolidBase(), Solid { //var lineType by string() public var thickness: Number by allProperties(inherit = false).number(1.0, diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solid.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solid.kt index a4c8e69c..0a59d141 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solid.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solid.kt @@ -37,6 +37,8 @@ public interface Solid : Vision { override val descriptor: NodeDescriptor get() = Companion.descriptor + + public companion object { // val SELECTED_KEY = "selected".asName() public val DETAIL_KEY: Name = "detail".asName() diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidBase.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidBase.kt index c88052b2..d2fee33a 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidBase.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidBase.kt @@ -2,11 +2,7 @@ package space.kscience.visionforge.solid import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable -import space.kscience.dataforge.meta.Meta 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.VisionChange @@ -20,15 +16,3 @@ public open class SolidBase : VisionBase(), Solid { 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 } -} \ No newline at end of file diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidLabel.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidLabel.kt index ac45e22e..3e725d0d 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidLabel.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidLabel.kt @@ -9,9 +9,9 @@ import space.kscience.visionforge.set @Serializable @SerialName("solid.label") public class SolidLabel( - public var text: String, - public var fontSize: Double, - public var fontFamily: String, + public val text: String, + public val fontSize: Double, + public val fontFamily: String, ) : SolidBase(), Solid @VisionBuilder diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Sphere.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Sphere.kt index c4d67f97..a6af3cd8 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Sphere.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Sphere.kt @@ -4,6 +4,7 @@ import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import space.kscience.visionforge.VisionBuilder import space.kscience.visionforge.VisionContainerBuilder +import space.kscience.visionforge.VisionPropertyContainer import space.kscience.visionforge.set import kotlin.math.PI import kotlin.math.cos @@ -12,12 +13,12 @@ import kotlin.math.sin @Serializable @SerialName("solid.sphere") public class Sphere( - public var radius: Float, - public var phiStart: Float = 0f, - public var phi: Float = PI2, - public var thetaStart: Float = 0f, - public var theta: Float = PI.toFloat(), -) : SolidBase(), GeometrySolid { + public val radius: Float, + public val phiStart: Float = 0f, + public val phi: Float = PI2, + public val thetaStart: Float = 0f, + public val theta: Float = PI.toFloat(), +) : SolidBase(), GeometrySolid, VisionPropertyContainer { override fun toGeometry(geometryBuilder: GeometryBuilder) { fun point3DfromSphCoord(r: Float, theta: Float, phi: Float): Point3D { diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SphereLayer.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SphereLayer.kt index 83e358e2..05149e2e 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SphereLayer.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SphereLayer.kt @@ -15,12 +15,12 @@ import kotlin.math.sin @Serializable @SerialName("solid.sphereLayer") public class SphereLayer( - public var outerRadius: Float, - public var innerRadius: Float, - public var phiStart: Float = 0f, - public var phi: Float = PI2, - public var thetaStart: Float = 0f, - public var theta: Float = PI.toFloat(), + public val outerRadius: Float, + public val innerRadius: Float, + public val phiStart: Float = 0f, + public val phi: Float = PI2, + public val thetaStart: Float = 0f, + public val theta: Float = PI.toFloat(), ) : SolidBase(), GeometrySolid { override fun toGeometry(geometryBuilder: GeometryBuilder): Unit = geometryBuilder.run { @@ -72,9 +72,17 @@ public class SphereLayer( public inline fun VisionContainerBuilder.sphereLayer( outerRadius: Number, innerRadius: Number, + phiStart: Number = 0f, + phi: Number = PI2, + thetaStart: Number = 0f, + theta: Number = PI.toFloat(), name: String? = null, action: SphereLayer.() -> Unit = {}, ): SphereLayer = SphereLayer( outerRadius.toFloat(), innerRadius.toFloat(), + phiStart.toFloat(), + phi.toFloat(), + thetaStart.toFloat(), + theta.toFloat() ).apply(action).also { set(name, it) } \ No newline at end of file diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/geometry.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/geometry.kt index e8813779..f5aa2d4a 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/geometry.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/geometry.kt @@ -105,4 +105,17 @@ public fun Point3D.toMeta(): MetaBuilder = Meta { X_KEY put x Y_KEY put y 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 } } \ No newline at end of file diff --git a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeVision.kt b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeJsVision.kt similarity index 83% rename from visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeVision.kt rename to visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeJsVision.kt index 16d1bd4f..27a5da44 100644 --- a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeVision.kt +++ b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeJsVision.kt @@ -6,6 +6,6 @@ import space.kscience.visionforge.solid.SolidBase /** * 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 } diff --git a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreePlugin.kt b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreePlugin.kt index 68fa692a..e6d85dc5 100644 --- a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreePlugin.kt +++ b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreePlugin.kt @@ -49,7 +49,7 @@ public class ThreePlugin : AbstractPlugin(), ElementVisionRenderer { } public fun buildObject3D(obj: Solid): Object3D = when (obj) { - is ThreeVision -> obj.render(this) + is ThreeJsVision -> obj.render(this) is SolidReferenceGroup -> ThreeReferenceFactory(this, obj) is SolidGroup -> { val group = ThreeGroup() From f2e7e16d624479fdb41545beb312ff31c6a7e3d2 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Mon, 12 Jul 2021 22:50:00 +0300 Subject: [PATCH 12/29] [WIP] layer marking --- CHANGELOG.md | 1 + .../visionforge/gdml/demo/GDMLAppComponent.kt | 5 +- .../kscience/visionforge/gdml/layerMarker.kt | 23 ------- .../kscience/visionforge/gdml/markLayers.kt | 62 +++++++++++++++++++ .../visionforge/solid/SolidReference.kt | 2 +- .../kscience/visionforge/solid/Sphere.kt | 2 +- visionforge-threejs/build.gradle.kts | 2 +- .../solid/three/ThreeGeometryBuilder.kt | 3 - 8 files changed, 70 insertions(+), 30 deletions(-) delete mode 100644 visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/layerMarker.kt create mode 100644 visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/markLayers.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index aff57288..8c84f7aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ - Tube is replaced by more general ConeSurface - position, rotation and size moved to properties - prototypes moved to children +- Immutable Solid instances ### Deprecated diff --git a/demo/gdml/src/jsMain/kotlin/space/kscience/visionforge/gdml/demo/GDMLAppComponent.kt b/demo/gdml/src/jsMain/kotlin/space/kscience/visionforge/gdml/demo/GDMLAppComponent.kt index 1d619dfb..fe2d377c 100644 --- a/demo/gdml/src/jsMain/kotlin/space/kscience/visionforge/gdml/demo/GDMLAppComponent.kt +++ b/demo/gdml/src/jsMain/kotlin/space/kscience/visionforge/gdml/demo/GDMLAppComponent.kt @@ -32,7 +32,10 @@ val GDMLApp = functionalComponent("GDMLApp") { props -> val parsedVision = when { name.endsWith(".gdml") || name.endsWith(".xml") -> { val gdml = Gdml.decodeFromString(data) - gdml.toVision() + gdml.toVision().apply { +// console.info("Marking layers for file $name") +// markLayers() + } } name.endsWith(".json") -> visionManager.decodeFromString(data) else -> { diff --git a/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/layerMarker.kt b/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/layerMarker.kt deleted file mode 100644 index 17b75e79..00000000 --- a/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/layerMarker.kt +++ /dev/null @@ -1,23 +0,0 @@ -package space.kscience.visionforge.gdml - -import space.kscience.dataforge.names.Name -import space.kscience.dataforge.names.plus -import space.kscience.visionforge.VisionGroup - -private fun VisionGroup.countChildren(namePrefix: Name, cache: MutableMap = hashMapOf()): Int { - var counter = 0 - children.forEach { (token, child) -> - if (child is VisionGroup) { - counter += child.countChildren(namePrefix + token, cache) - } else { - counter++ - } - } - cache[namePrefix] = counter - return counter -} - - -public fun VisionGroup.processLayers() { - -} \ No newline at end of file diff --git a/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/markLayers.kt b/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/markLayers.kt new file mode 100644 index 00000000..2689d1d6 --- /dev/null +++ b/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/markLayers.kt @@ -0,0 +1,62 @@ +package space.kscience.visionforge.gdml + +import space.kscience.dataforge.names.Name +import space.kscience.dataforge.names.NameToken +import space.kscience.dataforge.names.length +import space.kscience.dataforge.names.plus +import space.kscience.visionforge.VisionGroup +import space.kscience.visionforge.solid.Solid +import space.kscience.visionforge.solid.SolidGroup +import space.kscience.visionforge.solid.layer + +private class VisionCounterTree( + val name: Name, + val vision: Solid, +) { + val children: Map = + (vision as? VisionGroup)?.children?.mapValues { + VisionCounterTree(name + it.key, it.value as Solid) + } ?: emptyMap() + +// +// val directChildrenCount: Int by lazy { +// children.size +// } + + val childrenCount: Int = + children.values.sumOf { it.childrenCount + 1 } + +} + + +private fun VisionCounterTree.topToBottom(): Sequence = sequence { + yield(this@topToBottom) + children.values.forEach { + yieldAll(it.topToBottom()) + } +} + +public fun SolidGroup.markLayers(thresholds: List = listOf(1000, 20000, 100000)) { + val counterTree = VisionCounterTree(Name.EMPTY, this) + val totalCount = counterTree.childrenCount + if (totalCount > thresholds.firstOrNull() ?: 0) { + val allNodes = counterTree.topToBottom().toMutableList() + //println("tree construction finished") + allNodes.sortWith(compareBy({ it.name.length }, { it.childrenCount }).reversed()) + + //mark layers + var removed = 0 + var thresholdIndex = thresholds.indexOfLast { it < totalCount } + + for (node in allNodes) { + node.vision.layer = thresholdIndex + 1 + removed++ + if (totalCount - removed < thresholds[thresholdIndex]) { + thresholdIndex-- + } + if (thresholdIndex < 0) break + } + + + } +} \ No newline at end of file diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidReference.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidReference.kt index 2b7a8358..1ba659b9 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidReference.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidReference.kt @@ -100,7 +100,7 @@ public class SolidReferenceGroup( private class ReferenceChild( val owner: SolidReferenceGroup, private val childName: Name - ) : SolidReference, VisionGroup { + ) : SolidReference, VisionGroup, Solid { override val prototype: Solid by lazy { if (childName.isEmpty()) owner.prototype else { diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Sphere.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Sphere.kt index a6af3cd8..bae8d83d 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Sphere.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Sphere.kt @@ -17,7 +17,7 @@ public class Sphere( public val phiStart: Float = 0f, public val phi: Float = PI2, public val thetaStart: Float = 0f, - public val theta: Float = PI.toFloat(), + public val theta: Float = PI .toFloat(), ) : SolidBase(), GeometrySolid, VisionPropertyContainer { override fun toGeometry(geometryBuilder: GeometryBuilder) { diff --git a/visionforge-threejs/build.gradle.kts b/visionforge-threejs/build.gradle.kts index 32803a61..a862f776 100644 --- a/visionforge-threejs/build.gradle.kts +++ b/visionforge-threejs/build.gradle.kts @@ -5,5 +5,5 @@ plugins { dependencies { api(project(":visionforge-solid")) implementation(npm("three", "0.130.1")) - implementation(npm("three-csg-ts", "3.1.4")) + implementation(npm("three-csg-ts", "3.1.5")) } diff --git a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeGeometryBuilder.kt b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeGeometryBuilder.kt index c1c5aa72..4f3e0b58 100644 --- a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeGeometryBuilder.kt +++ b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeGeometryBuilder.kt @@ -54,9 +54,6 @@ public class ThreeGeometryBuilder : GeometryBuilder { setAttribute("position", Float32BufferAttribute(positions.toTypedArray(), 3)) setAttribute("normal", Float32BufferAttribute(normals.toTypedArray(), 3)) //setAttribute("color", Float32BufferAttribute(colors.toFloatArray(), 3)) - //a temporary fix for CSG problem - val uvsArray = Array((counter+1)*2){0f} - setAttribute("uv", Float32BufferAttribute(uvsArray, 2)) computeBoundingSphere() } From 8f95d6f48592018896bcb040823ed528915c8c9c Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Wed, 14 Jul 2021 15:45:01 +0300 Subject: [PATCH 13/29] layer marking --- .../visionforge/gdml/demo/GDMLAppComponent.kt | 6 +- .../kscience/visionforge/gdml/markLayers.kt | 72 +++++++++++++------ .../visionforge/solid/SolidReference.kt | 22 +++--- .../solid/three/MeshThreeFactory.kt | 4 +- .../visionforge/solid/three/ThreeCanvas.kt | 7 +- .../solid/three/ThreeGeometryBuilder.kt | 3 + 6 files changed, 75 insertions(+), 39 deletions(-) diff --git a/demo/gdml/src/jsMain/kotlin/space/kscience/visionforge/gdml/demo/GDMLAppComponent.kt b/demo/gdml/src/jsMain/kotlin/space/kscience/visionforge/gdml/demo/GDMLAppComponent.kt index fe2d377c..4f6560b6 100644 --- a/demo/gdml/src/jsMain/kotlin/space/kscience/visionforge/gdml/demo/GDMLAppComponent.kt +++ b/demo/gdml/src/jsMain/kotlin/space/kscience/visionforge/gdml/demo/GDMLAppComponent.kt @@ -10,6 +10,7 @@ import space.kscience.dataforge.context.fetch import space.kscience.dataforge.names.Name import space.kscience.gdml.Gdml import space.kscience.gdml.decodeFromString +import space.kscience.visionforge.gdml.markLayers import space.kscience.visionforge.gdml.toVision import space.kscience.visionforge.ring.ThreeCanvasWithControls import space.kscience.visionforge.ring.tab @@ -33,8 +34,9 @@ val GDMLApp = functionalComponent("GDMLApp") { props -> name.endsWith(".gdml") || name.endsWith(".xml") -> { val gdml = Gdml.decodeFromString(data) gdml.toVision().apply { -// console.info("Marking layers for file $name") -// markLayers() + root(visionManager) + console.info("Marking layers for file $name") + markLayers() } } name.endsWith(".json") -> visionManager.decodeFromString(data) diff --git a/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/markLayers.kt b/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/markLayers.kt index 2689d1d6..a47374d0 100644 --- a/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/markLayers.kt +++ b/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/markLayers.kt @@ -1,5 +1,7 @@ package space.kscience.visionforge.gdml +import space.kscience.dataforge.context.info +import space.kscience.dataforge.context.logger import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.NameToken import space.kscience.dataforge.names.length @@ -7,24 +9,36 @@ import space.kscience.dataforge.names.plus import space.kscience.visionforge.VisionGroup import space.kscience.visionforge.solid.Solid import space.kscience.visionforge.solid.SolidGroup +import space.kscience.visionforge.solid.SolidReferenceGroup import space.kscience.visionforge.solid.layer + private class VisionCounterTree( val name: Name, val vision: Solid, + val prototypes: HashMap ) { - val children: Map = - (vision as? VisionGroup)?.children?.mapValues { - VisionCounterTree(name + it.key, it.value as Solid) + + // self count for prototypes + var selfCount = 1 + + val children: Map by lazy { + (vision as? VisionGroup)?.children?.mapValues { (key, vision) -> + if (vision is SolidReferenceGroup) { + prototypes.getOrPut(vision.refName) { + VisionCounterTree(vision.refName, vision.prototype, prototypes) + }.apply { + selfCount += 1 + } + } else { + VisionCounterTree(name + key, vision as Solid, prototypes) + } } ?: emptyMap() + } -// -// val directChildrenCount: Int by lazy { -// children.size -// } - - val childrenCount: Int = + val childrenCount: Int by lazy { children.values.sumOf { it.childrenCount + 1 } + } } @@ -36,27 +50,41 @@ private fun VisionCounterTree.topToBottom(): Sequence = seque } } -public fun SolidGroup.markLayers(thresholds: List = listOf(1000, 20000, 100000)) { - val counterTree = VisionCounterTree(Name.EMPTY, this) +public fun SolidGroup.markLayers(thresholds: List = listOf(500, 1000, 20000, 50000)) { + val logger = manager?.context?.logger + val counterTree = VisionCounterTree(Name.EMPTY, this, hashMapOf()) val totalCount = counterTree.childrenCount if (totalCount > thresholds.firstOrNull() ?: 0) { - val allNodes = counterTree.topToBottom().toMutableList() + val allNodes = counterTree.topToBottom().filter { it.selfCount > 1 }.distinct().toMutableList() //println("tree construction finished") - allNodes.sortWith(compareBy({ it.name.length }, { it.childrenCount }).reversed()) + allNodes.sortWith( + compareBy( + { it.name.length }, + { it.childrenCount * it.selfCount } + ).reversed() + ) //mark layers - var removed = 0 - var thresholdIndex = thresholds.indexOfLast { it < totalCount } + var remaining = totalCount for (node in allNodes) { - node.vision.layer = thresholdIndex + 1 - removed++ - if (totalCount - removed < thresholds[thresholdIndex]) { - thresholdIndex-- + val layerIndex = if (remaining > thresholds.last()) + thresholds.size + else + thresholds.indexOfLast { remaining < it } + + if (layerIndex == 0) break + + node.vision.layer = layerIndex + val removedCount = node.selfCount * node.children.size + logger?.apply { + if (node.selfCount > 1) { + info { "Prototype with name ${node.name} moved to layer $layerIndex" } + } else { + info { "Vision with name ${node.name} moved to layer $layerIndex" } + } } - if (thresholdIndex < 0) break + remaining -= removedCount } - - } } \ No newline at end of file diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidReference.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidReference.kt index 1ba659b9..1cb5eac8 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidReference.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidReference.kt @@ -99,15 +99,15 @@ public class SolidReferenceGroup( */ private class ReferenceChild( val owner: SolidReferenceGroup, - private val childName: Name + private val refName: Name ) : SolidReference, VisionGroup, Solid { override val prototype: Solid by lazy { - if (childName.isEmpty()) owner.prototype else { - val proto = (owner.prototype as? VisionGroup)?.get(childName) - ?: error("Prototype with name $childName not found in SolidReferenceGroup ${owner.refName}") + if (refName.isEmpty()) owner.prototype else { + val proto = (owner.prototype as? VisionGroup)?.get(refName) + ?: error("Prototype with name $refName not found in SolidReferenceGroup ${owner.refName}") proto.unref as? Solid - ?: error("Prototype with name $childName is ${proto::class} but expected Solid") + ?: error("Prototype with name $refName is ${proto::class} but expected Solid") } } @@ -115,14 +115,14 @@ public class SolidReferenceGroup( get() = (prototype as? VisionGroup)?.children ?.filter { it.key != SolidGroup.PROTOTYPES_TOKEN } ?.mapValues { (key, _) -> - ReferenceChild(owner, childName + key.asName()) + ReferenceChild(owner, refName + key.asName()) } ?: emptyMap() override fun getOwnProperty(name: Name): MetaItem? = - owner.getOwnProperty(childPropertyName(childName, name)) + owner.getOwnProperty(childPropertyName(refName, name)) override fun setProperty(name: Name, item: MetaItem?, notify: Boolean) { - owner.setProperty(childPropertyName(childName, name), item, notify) + owner.setProperty(childPropertyName(refName, name), item, notify) } override fun getProperty( @@ -134,7 +134,7 @@ public class SolidReferenceGroup( override var parent: VisionGroup? get() { - val parentName = childName.cutLast() + val parentName = refName.cutLast() return if (parentName.isEmpty()) owner else ReferenceChild(owner, parentName) } set(_) { @@ -144,7 +144,7 @@ public class SolidReferenceGroup( @DFExperimental override val propertyChanges: Flow get() = owner.propertyChanges.mapNotNull { name -> - if (name.startsWith(childToken(childName))) { + if (name.startsWith(childToken(refName))) { name.cutFirst() } else { null @@ -152,7 +152,7 @@ public class SolidReferenceGroup( } override fun invalidateProperty(propertyName: Name) { - owner.invalidateProperty(childPropertyName(childName, propertyName)) + owner.invalidateProperty(childPropertyName(refName, propertyName)) } override fun update(change: VisionChange) { diff --git a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/MeshThreeFactory.kt b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/MeshThreeFactory.kt index 14665a8b..7cbd4d3d 100644 --- a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/MeshThreeFactory.kt +++ b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/MeshThreeFactory.kt @@ -74,9 +74,9 @@ internal fun Mesh.applyProperties(obj: Solid): Mesh = apply { updateMaterial(obj) applyEdges(obj) //applyWireFrame(obj) - layers.enable(obj.layer) + layers.set(obj.layer) children.forEach { - it.layers.enable(obj.layer) + it.layers.set(obj.layer) } } diff --git a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeCanvas.kt b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeCanvas.kt index 7dd89a32..3afb6776 100644 --- a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeCanvas.kt +++ b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeCanvas.kt @@ -250,8 +250,11 @@ public class ThreeCanvas( } public fun render(vision: Solid) { - three.logger.info { "Replacing root node in three canvas" } - scene.findChild("@root".asName())?.let { scene.remove(it) } + if (root != null) { + three.logger.info { "Replacing root node in three canvas" } + scene.findChild("@root".asName())?.let { scene.remove(it) } + root?.dispose() + } val object3D = three.buildObject3D(vision) object3D.name = "@root" diff --git a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeGeometryBuilder.kt b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeGeometryBuilder.kt index 4f3e0b58..c1c5aa72 100644 --- a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeGeometryBuilder.kt +++ b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeGeometryBuilder.kt @@ -54,6 +54,9 @@ public class ThreeGeometryBuilder : GeometryBuilder { setAttribute("position", Float32BufferAttribute(positions.toTypedArray(), 3)) setAttribute("normal", Float32BufferAttribute(normals.toTypedArray(), 3)) //setAttribute("color", Float32BufferAttribute(colors.toFloatArray(), 3)) + //a temporary fix for CSG problem + val uvsArray = Array((counter+1)*2){0f} + setAttribute("uv", Float32BufferAttribute(uvsArray, 2)) computeBoundingSphere() } From 38c76e824d550bcadbd9ff1ab3feb04b28e50e23 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Wed, 14 Jul 2021 15:50:56 +0300 Subject: [PATCH 14/29] layer marking --- .../kotlin/space/kscience/visionforge/gdml/markLayers.kt | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/markLayers.kt b/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/markLayers.kt index a47374d0..dfee104e 100644 --- a/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/markLayers.kt +++ b/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/markLayers.kt @@ -76,15 +76,14 @@ public fun SolidGroup.markLayers(thresholds: List = listOf(500, 1000, 20000 if (layerIndex == 0) break node.vision.layer = layerIndex - val removedCount = node.selfCount * node.children.size + remaining -= node.selfCount * node.childrenCount logger?.apply { if (node.selfCount > 1) { - info { "Prototype with name ${node.name} moved to layer $layerIndex" } + info { "Prototype with name ${node.name} moved to layer $layerIndex. $remaining nodes remains" } } else { - info { "Vision with name ${node.name} moved to layer $layerIndex" } + info { "Vision with name ${node.name} moved to layer $layerIndex. $remaining nodes remains" } } } - remaining -= removedCount } } } \ No newline at end of file From e1138be8618fcb1bf52038c0915ff3b0085748cb Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Thu, 15 Jul 2021 12:28:25 +0300 Subject: [PATCH 15/29] layer marking --- .../kotlin/space/kscience/visionforge/gdml/markLayers.kt | 6 +++--- .../kotlin/space/kscience/visionforge/solid/Solid.kt | 2 -- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/markLayers.kt b/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/markLayers.kt index dfee104e..befc69bb 100644 --- a/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/markLayers.kt +++ b/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/markLayers.kt @@ -55,12 +55,12 @@ public fun SolidGroup.markLayers(thresholds: List = listOf(500, 1000, 20000 val counterTree = VisionCounterTree(Name.EMPTY, this, hashMapOf()) val totalCount = counterTree.childrenCount if (totalCount > thresholds.firstOrNull() ?: 0) { - val allNodes = counterTree.topToBottom().filter { it.selfCount > 1 }.distinct().toMutableList() + val allNodes = counterTree.topToBottom().distinct().toMutableList() //println("tree construction finished") allNodes.sortWith( compareBy( { it.name.length }, - { it.childrenCount * it.selfCount } + { (it.children.size + 1) * it.selfCount } ).reversed() ) @@ -76,7 +76,7 @@ public fun SolidGroup.markLayers(thresholds: List = listOf(500, 1000, 20000 if (layerIndex == 0) break node.vision.layer = layerIndex - remaining -= node.selfCount * node.childrenCount + remaining -= node.selfCount * (node.children.size + 1) logger?.apply { if (node.selfCount > 1) { info { "Prototype with name ${node.name} moved to layer $layerIndex. $remaining nodes remains" } diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solid.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solid.kt index 0a59d141..a4c8e69c 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solid.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solid.kt @@ -37,8 +37,6 @@ public interface Solid : Vision { override val descriptor: NodeDescriptor get() = Companion.descriptor - - public companion object { // val SELECTED_KEY = "selected".asName() public val DETAIL_KEY: Name = "detail".asName() From 95220422cc15cd25ed1b18b1a38f8597d51d5a16 Mon Sep 17 00:00:00 2001 From: kiruma524 <71787194+kiruma524@users.noreply.github.com> Date: Thu, 15 Jul 2021 12:47:25 +0300 Subject: [PATCH 16/29] Updated OrbitControls Made some changes, but there're still some problems --- .../visionforge/solid/OrbitControls.kt | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/OrbitControls.kt b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/OrbitControls.kt index a32e44f5..6b82e2a0 100644 --- a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/OrbitControls.kt +++ b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/OrbitControls.kt @@ -38,7 +38,7 @@ class OrbitControls internal constructor(camera: Camera, canvas: SubScene, spec: val baseZProperty = SimpleDoubleProperty(0.0) var z by baseZProperty - private val baseTranslate = Translate() + private val baseTranslate = Translate(0.0, 0.0, 0.0) // val basePositionProperty: ObjectBinding = // nonNullObjectBinding(baseXProperty, baseYProperty, baseZProperty) { @@ -59,13 +59,13 @@ class OrbitControls internal constructor(camera: Camera, canvas: SubScene, spec: private val ry = Rotate(0.0, Rotate.Y_AXIS) - private val rz = Rotate(0.0, Rotate.Z_AXIS) + private val translate = Translate(0.0, 0.0, 0.0) - private val translate = Translate() + //private val rz = Rotate(0.0, Rotate.Z_AXIS) init { - camera.transforms.setAll(rx, ry, rz, translate) + camera.transforms.setAll(baseTranslate, ry, rx, translate) update() val listener = InvalidationListener { update() @@ -78,8 +78,8 @@ class OrbitControls internal constructor(camera: Camera, canvas: SubScene, spec: baseZProperty.addListener(listener) canvas.apply { -// center.xProperty().bind(widthProperty().divide(2)) -// center.zProperty().bind(heightProperty().divide(2)) + //center.xProperty().bind(widthProperty().divide(2)) + //center.zProperty().bind(heightProperty().divide(2)) handleMouse() } // coordinateContainer?.vbox { @@ -93,32 +93,32 @@ class OrbitControls internal constructor(camera: Camera, canvas: SubScene, spec: val spherePosition = Point3D( sin(zenith) * sin(azimuth), cos(zenith), - sin(zenith) * cos(azimuth) + sin(zenith) * cos(azimuth), ).times(distance) val basePosition = Point3D(x, y, z) baseTranslate.x = x baseTranslate.y = y baseTranslate.z = z //Create direction vector - val cameraPosition = basePosition + spherePosition + val camPosition = basePosition+spherePosition val camDirection: Point3D = (-spherePosition).normalize() val xRotation = Math.toDegrees(asin(-camDirection.y)) val yRotation = Math.toDegrees(atan2(camDirection.x, camDirection.z)) - rx.pivotX = cameraPosition.x - rx.pivotY = cameraPosition.y - rx.pivotZ = cameraPosition.z + rx.pivotX = camPosition.x + rx.pivotY = camPosition.y + rx.pivotZ = camPosition.z rx.angle = xRotation - ry.pivotX = cameraPosition.x - ry.pivotY = cameraPosition.y - ry.pivotZ = cameraPosition.z + ry.pivotX = camPosition.x + ry.pivotY = camPosition.y + ry.pivotZ = camPosition.z ry.angle = yRotation - translate.x = cameraPosition.x - translate.y = cameraPosition.y - translate.z = cameraPosition.z + translate.x = camPosition.x + translate.y = camPosition.y + translate.z = camPosition.z } From 493c527743d34c38d8be3b8fc49ad6d0221f664d Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Thu, 15 Jul 2021 18:39:43 +0300 Subject: [PATCH 17/29] OrbitControls for FX finally working --- visionforge-fx/build.gradle.kts | 2 +- .../visionforge/solid/OrbitControls.kt | 150 +++++++----------- 2 files changed, 58 insertions(+), 94 deletions(-) diff --git a/visionforge-fx/build.gradle.kts b/visionforge-fx/build.gradle.kts index 391517d7..09adb66a 100644 --- a/visionforge-fx/build.gradle.kts +++ b/visionforge-fx/build.gradle.kts @@ -22,7 +22,7 @@ dependencies { exclude(group = "org.openjfx") } - api("org.fxyz3d:fxyz3d:0.5.2") { + api("org.fxyz3d:fxyz3d:0.5.4") { exclude(module = "slf4j-simple") } api("org.jetbrains.kotlinx:kotlinx-coroutines-javafx:${ru.mipt.npm.gradle.KScienceVersions.coroutinesVersion}") diff --git a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/OrbitControls.kt b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/OrbitControls.kt index 32d17d63..5f15fe37 100644 --- a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/OrbitControls.kt +++ b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/OrbitControls.kt @@ -1,55 +1,73 @@ package space.kscience.visionforge.solid -import javafx.beans.InvalidationListener import javafx.beans.property.SimpleBooleanProperty import javafx.beans.property.SimpleDoubleProperty import javafx.event.EventHandler -import javafx.geometry.Point3D import javafx.scene.Camera import javafx.scene.Node import javafx.scene.SubScene -import javafx.scene.input.MouseEvent -import javafx.scene.input.ScrollEvent import javafx.scene.shape.Sphere import javafx.scene.transform.Rotate +import javafx.scene.transform.Rotate.X_AXIS +import javafx.scene.transform.Rotate.Y_AXIS import javafx.scene.transform.Translate +import space.kscience.dataforge.meta.useProperty import tornadofx.* -import kotlin.math.* +import kotlin.math.PI +import kotlin.math.cos +import kotlin.math.max +import kotlin.math.sin import space.kscience.visionforge.solid.specifications.Camera as CameraSpec - public class OrbitControls internal constructor(camera: Camera, canvas: SubScene, spec: CameraSpec) { - public val distanceProperty: SimpleDoubleProperty = SimpleDoubleProperty(spec.distance) - public var distance: Double by distanceProperty - public val azimuthProperty: SimpleDoubleProperty = SimpleDoubleProperty(spec.azimuth) public var azimuth: Double by azimuthProperty public val zenithProperty: SimpleDoubleProperty = SimpleDoubleProperty(PI / 2 - spec.latitude) public var zenith: Double by zenithProperty -// -// public val latitudeProperty: DoubleBinding = zenithProperty.unaryMinus().plus(PI / 2) -// public val latitude by latitudeProperty - public val baseXProperty: SimpleDoubleProperty = SimpleDoubleProperty(0.0) - public var x: Double by baseXProperty - public val baseYProperty: SimpleDoubleProperty = SimpleDoubleProperty(0.0) - public var y: Double by baseYProperty - public val baseZProperty: SimpleDoubleProperty = SimpleDoubleProperty(0.0) - public var z: Double by baseZProperty private val baseTranslate = Translate(0.0, 0.0, 0.0) -// val basePositionProperty: ObjectBinding = -// nonNullObjectBinding(baseXProperty, baseYProperty, baseZProperty) { -// Point3D(x, y, z) -// } -// -// val basePosition by basePositionProperty + public var x: Double by baseTranslate.xProperty() + public var y: Double by baseTranslate.yProperty() + public var z: Double by baseTranslate.zProperty() + + private val distanceProperty = SimpleDoubleProperty().apply { + spec.useProperty(CameraSpec::distance) { + set(it) + } + } + + private val distanceTranslation = Translate().apply { + zProperty().bind(-distanceProperty) + } + + public var distance: Double by distanceProperty + + private val centering = Translate().apply { + xProperty().bind(-canvas.widthProperty() / 2) + yProperty().bind(-canvas.heightProperty() / 2) + } + + private val yUpRotation = Rotate(180.0, X_AXIS) + + private val azimuthRotation = Rotate().apply { + axis = Y_AXIS + angleProperty().bind(azimuthProperty * (180.0 / PI)) + } + + private val zenithRotation = Rotate().apply { + axisProperty().bind(objectBinding(azimuthProperty) { + azimuthRotation.inverseTransform(X_AXIS) + }) + angleProperty().bind(-zenithProperty * (180.0 / PI)) + } private val inProgressProperty = SimpleBooleanProperty(false) + public val centerMarker: Node by lazy { Sphere(10.0).also { it.transforms.setAll(baseTranslate) @@ -57,75 +75,21 @@ public class OrbitControls internal constructor(camera: Camera, canvas: SubScene } } - - private val rx = Rotate(0.0, Rotate.X_AXIS) - - private val ry = Rotate(0.0, Rotate.Y_AXIS) - - private val translate = Translate(0.0, 0.0, 0.0) - - //private val rz = Rotate(0.0, Rotate.Z_AXIS) - - init { - camera.transforms.setAll(baseTranslate, ry, rx, translate) - - update() - val listener = InvalidationListener { - update() - } - distanceProperty.addListener(listener) - azimuthProperty.addListener(listener) - zenithProperty.addListener(listener) - baseXProperty.addListener(listener) - baseYProperty.addListener(listener) - baseZProperty.addListener(listener) + camera.transforms.setAll( + baseTranslate, + yUpRotation, + azimuthRotation, + zenithRotation, + distanceTranslation, + centering, + ) canvas.apply { - //center.xProperty().bind(widthProperty().divide(2)) - //center.zProperty().bind(heightProperty().divide(2)) handleMouse() } -// coordinateContainer?.vbox { -// label(distanceProperty.asString()) -// label(azimuthProperty.asString()) -// label(zenithProperty.asString()) -// } } - private fun update() { - val spherePosition = Point3D( - sin(zenith) * sin(azimuth), - cos(zenith), - sin(zenith) * cos(azimuth), - ).times(distance) - val basePosition = Point3D(x, y, z) - baseTranslate.x = x - baseTranslate.y = y - baseTranslate.z = z - //Create direction vector - val camPosition = basePosition+spherePosition - val camDirection: Point3D = (-spherePosition).normalize() - - val xRotation = Math.toDegrees(asin(-camDirection.y)) - val yRotation = Math.toDegrees(atan2(camDirection.x, camDirection.z)) - - rx.pivotX = camPosition.x - rx.pivotY = camPosition.y - rx.pivotZ = camPosition.z - rx.angle = xRotation - - ry.pivotX = camPosition.x - ry.pivotY = camPosition.y - ry.pivotZ = camPosition.z - ry.angle = yRotation - - translate.x = camPosition.x - translate.y = camPosition.y - translate.z = camPosition.z - } - - private fun Node.handleMouse() { var mousePosX = 0.0 @@ -135,7 +99,7 @@ public class OrbitControls internal constructor(camera: Camera, canvas: SubScene var mouseDeltaX: Double var mouseDeltaY: Double - onMousePressed = EventHandler { me -> + onMousePressed = EventHandler { me -> mousePosX = me.sceneX mousePosY = me.sceneY mouseOldX = me.sceneX @@ -143,7 +107,7 @@ public class OrbitControls internal constructor(camera: Camera, canvas: SubScene inProgressProperty.set(true) } - onMouseDragged = EventHandler { me -> + onMouseDragged = EventHandler { me -> mouseOldX = mousePosX mouseOldY = mousePosY mousePosX = me.sceneX @@ -158,11 +122,11 @@ public class OrbitControls internal constructor(camera: Camera, canvas: SubScene } if (me.isPrimaryButtonDown) { - azimuth = (azimuth - mouseDeltaX * MOUSE_SPEED * modifier * ROTATION_SPEED).coerceIn(0.0, 2 * PI) - zenith = (zenith - mouseDeltaY * MOUSE_SPEED * modifier * ROTATION_SPEED).coerceIn(0.0, PI) + azimuth = (azimuth - mouseDeltaX * MOUSE_SPEED * modifier * ROTATION_SPEED) + zenith = (zenith - mouseDeltaY * MOUSE_SPEED * modifier * ROTATION_SPEED).coerceIn(-PI, PI) } else if (me.isSecondaryButtonDown) { - x += MOUSE_SPEED * modifier * TRACK_SPEED * (mouseDeltaX * cos(azimuth) + mouseDeltaY * sin(azimuth)) - z += MOUSE_SPEED * modifier * TRACK_SPEED * (-mouseDeltaX * sin(azimuth) + mouseDeltaY * cos(azimuth)) + x += MOUSE_SPEED * modifier * TRACK_SPEED * (mouseDeltaX * cos(azimuth) - mouseDeltaY * sin(azimuth)) + z += MOUSE_SPEED * modifier * TRACK_SPEED * ( mouseDeltaX * sin(azimuth) + mouseDeltaY * cos(azimuth)) } } @@ -170,7 +134,7 @@ public class OrbitControls internal constructor(camera: Camera, canvas: SubScene inProgressProperty.set(false) } - onScroll = EventHandler { event -> + onScroll = EventHandler { event -> distance = max(1.0, distance - MOUSE_SPEED * event.deltaY * RESIZE_SPEED) } } From c1627b450413893e10820925f3f084ca536e0cfd Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Thu, 15 Jul 2021 18:56:29 +0300 Subject: [PATCH 18/29] Minor FX fixes --- .../kscience/visionforge/solid/FX3DPlugin.kt | 19 +++++++++-------- .../visionforge/solid/FXCompositeFactory.kt | 2 +- .../visionforge/solid/FXConvexFactory.kt | 2 +- .../visionforge/solid/FXShapeFactory.kt | 2 +- .../visionforge/solid/OrbitControls.kt | 21 ++++++++++++++++--- .../solid/specifications/Camera.kt | 5 +++-- 6 files changed, 34 insertions(+), 17 deletions(-) diff --git a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/FX3DPlugin.kt b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/FX3DPlugin.kt index 6bd56fcf..aac30150 100644 --- a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/FX3DPlugin.kt +++ b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/FX3DPlugin.kt @@ -65,6 +65,7 @@ class FX3DPlugin : AbstractPlugin() { } is SolidLabel -> Text(obj.text).apply { font = Font.font(obj.fontFamily, obj.fontSize) + x = -layoutBounds.width / 2 y = layoutBounds.height / 2 } @@ -129,10 +130,10 @@ class FX3DPlugin : AbstractPlugin() { } } - companion object : PluginFactory { - override val tag = PluginTag("vision.fx3D", PluginTag.DATAFORGE_GROUP) - override val type = FX3DPlugin::class - override fun invoke(meta: Meta, context: Context) = FX3DPlugin() + public companion object : PluginFactory { + override val tag: PluginTag = PluginTag("vision.fx3D", PluginTag.DATAFORGE_GROUP) + override val type: KClass = FX3DPlugin::class + override fun invoke(meta: Meta, context: Context): FX3DPlugin = FX3DPlugin() } } @@ -140,14 +141,14 @@ class FX3DPlugin : AbstractPlugin() { * Builder and updater for three.js object */ @Type(TYPE) -interface FX3DFactory { +public interface FX3DFactory { - val type: KClass + public val type: KClass - operator fun invoke(obj: T, binding: VisualObjectFXBinding): Node + public operator fun invoke(obj: T, binding: VisualObjectFXBinding): Node - companion object { - const val TYPE = "fx3DFactory" + public companion object { + public const val TYPE = "fx3DFactory" } } diff --git a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/FXCompositeFactory.kt b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/FXCompositeFactory.kt index 663a927b..1cdcf914 100644 --- a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/FXCompositeFactory.kt +++ b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/FXCompositeFactory.kt @@ -38,7 +38,7 @@ private fun MeshView.toCSG(): CSG { return CSG.fromPolygons(polygons) } -class FXCompositeFactory(val plugin: FX3DPlugin) : FX3DFactory { +public class FXCompositeFactory(public val plugin: FX3DPlugin) : FX3DFactory { override val type: KClass get() = Composite::class diff --git a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/FXConvexFactory.kt b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/FXConvexFactory.kt index 7538d6c6..7bc44207 100644 --- a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/FXConvexFactory.kt +++ b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/FXConvexFactory.kt @@ -7,7 +7,7 @@ import javafx.scene.Node import kotlin.reflect.KClass -object FXConvexFactory : FX3DFactory { +public object FXConvexFactory : FX3DFactory { override val type: KClass get() = Convex::class override fun invoke(obj: Convex, binding: VisualObjectFXBinding): Node { diff --git a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/FXShapeFactory.kt b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/FXShapeFactory.kt index ad88aac0..116075ce 100644 --- a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/FXShapeFactory.kt +++ b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/FXShapeFactory.kt @@ -8,7 +8,7 @@ import org.fxyz3d.geometry.Face3 import space.kscience.dataforge.meta.Meta import kotlin.reflect.KClass -object FXShapeFactory : FX3DFactory { +public object FXShapeFactory : FX3DFactory { override val type: KClass get() = GeometrySolid::class override fun invoke(obj: GeometrySolid, binding: VisualObjectFXBinding): MeshView { diff --git a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/OrbitControls.kt b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/OrbitControls.kt index 5f15fe37..2fe573e0 100644 --- a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/OrbitControls.kt +++ b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/OrbitControls.kt @@ -21,10 +21,25 @@ import space.kscience.visionforge.solid.specifications.Camera as CameraSpec public class OrbitControls internal constructor(camera: Camera, canvas: SubScene, spec: CameraSpec) { - public val azimuthProperty: SimpleDoubleProperty = SimpleDoubleProperty(spec.azimuth) + /** + * Azimuth angle in radians + */ + public val azimuthProperty: SimpleDoubleProperty = SimpleDoubleProperty().apply { + spec.useProperty(CameraSpec::azimuth){ + set(spec.azimuth) + } + } public var azimuth: Double by azimuthProperty - public val zenithProperty: SimpleDoubleProperty = SimpleDoubleProperty(PI / 2 - spec.latitude) + /** + * Zenith angle in radians + */ + public val zenithProperty: SimpleDoubleProperty = SimpleDoubleProperty().apply { + spec.useProperty(CameraSpec::latitude){ + set(PI / 2 - spec.latitude) + } + } + public var zenith: Double by zenithProperty @@ -123,7 +138,7 @@ public class OrbitControls internal constructor(camera: Camera, canvas: SubScene if (me.isPrimaryButtonDown) { azimuth = (azimuth - mouseDeltaX * MOUSE_SPEED * modifier * ROTATION_SPEED) - zenith = (zenith - mouseDeltaY * MOUSE_SPEED * modifier * ROTATION_SPEED).coerceIn(-PI, PI) + zenith = (zenith - mouseDeltaY * MOUSE_SPEED * modifier * ROTATION_SPEED).coerceIn(-PI/2, PI/2) } else if (me.isSecondaryButtonDown) { x += MOUSE_SPEED * modifier * TRACK_SPEED * (mouseDeltaX * cos(azimuth) - mouseDeltaY * sin(azimuth)) z += MOUSE_SPEED * modifier * TRACK_SPEED * ( mouseDeltaX * sin(azimuth) + mouseDeltaY * cos(azimuth)) diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/specifications/Camera.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/specifications/Camera.kt index b6209b54..905fa234 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/specifications/Camera.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/specifications/Camera.kt @@ -18,7 +18,6 @@ public class Camera : Scheme() { public var distance: Double by double(INITIAL_DISTANCE) public var azimuth: Double by double(INITIAL_AZIMUTH) public var latitude: Double by double(INITIAL_LATITUDE) - public val zenith: Double get() = PI / 2 - latitude public companion object : SchemeSpec(::Camera) { public const val INITIAL_DISTANCE: Double = 300.0 @@ -51,4 +50,6 @@ public class Camera : Scheme() { } } } -} \ No newline at end of file +} + +public val Camera.zenith: Double get() = PI / 2 - latitude \ No newline at end of file From a87692ae1f33fe08bffcd1a42d68dc82ff7ca10d Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Thu, 15 Jul 2021 19:45:43 +0300 Subject: [PATCH 19/29] Fix labels for JavaFX --- .../kotlin/space/kscience/visionforge/solid/demo/FXDemoApp.kt | 1 + .../main/kotlin/space/kscience/visionforge/solid/FX3DPlugin.kt | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/demo/solid-showcase/src/jvmMain/kotlin/space/kscience/visionforge/solid/demo/FXDemoApp.kt b/demo/solid-showcase/src/jvmMain/kotlin/space/kscience/visionforge/solid/demo/FXDemoApp.kt index 1ed557ea..3ce92f0f 100644 --- a/demo/solid-showcase/src/jvmMain/kotlin/space/kscience/visionforge/solid/demo/FXDemoApp.kt +++ b/demo/solid-showcase/src/jvmMain/kotlin/space/kscience/visionforge/solid/demo/FXDemoApp.kt @@ -14,6 +14,7 @@ class FXDemoApp : App(FXDemoGrid::class) { stage.height = 600.0 view.showcase() + view.showcaseCSG() } } diff --git a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/FX3DPlugin.kt b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/FX3DPlugin.kt index aac30150..f843e02c 100644 --- a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/FX3DPlugin.kt +++ b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/FX3DPlugin.kt @@ -65,7 +65,8 @@ class FX3DPlugin : AbstractPlugin() { } is SolidLabel -> Text(obj.text).apply { font = Font.font(obj.fontFamily, obj.fontSize) - + transforms.add(Rotate(180.0, Rotate.Y_AXIS)) + transforms.add(Rotate(180.0, Rotate.Z_AXIS)) x = -layoutBounds.width / 2 y = layoutBounds.height / 2 } From 87260cea86b3732d0820a0956d1657b92005894b Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Fri, 16 Jul 2021 20:52:01 +0300 Subject: [PATCH 20/29] Feedback connection for client. --- CHANGELOG.md | 2 + .../space/kscience/visionforge/VisionBase.kt | 9 +- .../kscience/visionforge/VisionChange.kt | 6 +- .../kscience/visionforge/VisionGroupBase.kt | 2 +- .../kscience/visionforge/VisionManager.kt | 2 + .../kscience/visionforge/VisionClient.kt | 163 ++++++++++-------- .../visionforge/three/server/VisionServer.kt | 11 ++ .../kscience/visionforge/solid/three/csg.kt | 18 +- 8 files changed, 125 insertions(+), 88 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c84f7aa..d638f0c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,8 @@ - position, rotation and size moved to properties - prototypes moved to children - Immutable Solid instances +- Property listeners are not triggered if there are no changes. +- Feedback websocket connection in the client. ### Deprecated diff --git a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionBase.kt b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionBase.kt index 62f90f52..78b75124 100644 --- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionBase.kt +++ b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionBase.kt @@ -74,9 +74,12 @@ public open class VisionBase( } override fun setProperty(name: Name, item: MetaItem?, notify: Boolean) { - getOrCreateProperties().setItem(name, item) - if (notify) { - invalidateProperty(name) + val oldItem = properties?.getItem(name) + if(oldItem!= item) { + getOrCreateProperties().setItem(name, item) + if (notify) { + invalidateProperty(name) + } } } diff --git a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionChange.kt b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionChange.kt index 85b147ab..06ccb7bc 100644 --- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionChange.kt +++ b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionChange.kt @@ -65,14 +65,14 @@ private fun Vision.isolate(manager: VisionManager): Vision { } /** - * @param void flag showing that this vision child should be removed + * @param delete flag showing that this vision child should be removed * @param vision a new value for vision content * @param properties updated properties - * @param children a map of children changed in ths [VisionChange]. If a child to be removed, set [void] flag to true. + * @param children a map of children changed in ths [VisionChange]. If a child to be removed, set [delete] flag to true. */ @Serializable public data class VisionChange( - public val void: Boolean = false, + public val delete: Boolean = false, public val vision: Vision? = null, @Serializable(MetaSerializer::class) public val properties: Meta? = null, public val children: Map? = null, diff --git a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionGroupBase.kt b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionGroupBase.kt index 997789c1..933b55cd 100644 --- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionGroupBase.kt +++ b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionGroupBase.kt @@ -134,7 +134,7 @@ public open class VisionGroupBase( override fun update(change: VisionChange) { change.children?.forEach { (name, change) -> when { - change.void -> set(name, null) + change.delete -> set(name, null) change.vision != null -> set(name, change.vision) else -> get(name)?.update(change) } diff --git a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionManager.kt b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionManager.kt index b3e9faf4..4f01e839 100644 --- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionManager.kt +++ b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionManager.kt @@ -39,6 +39,8 @@ public class VisionManager(meta: Meta) : AbstractPlugin(meta) { public fun decodeFromString(string: String): Vision = jsonFormat.decodeFromString(visionSerializer, string) public fun encodeToString(vision: Vision): String = jsonFormat.encodeToString(visionSerializer, vision) + public fun encodeToString(change: VisionChange): String = + jsonFormat.encodeToString(VisionChange.serializer(), change) public fun decodeFromJson(json: JsonElement): Vision = jsonFormat.decodeFromJsonElement(visionSerializer, json) diff --git a/visionforge-core/src/jsMain/kotlin/space/kscience/visionforge/VisionClient.kt b/visionforge-core/src/jsMain/kotlin/space/kscience/visionforge/VisionClient.kt index 98803115..017c615d 100644 --- a/visionforge-core/src/jsMain/kotlin/space/kscience/visionforge/VisionClient.kt +++ b/visionforge-core/src/jsMain/kotlin/space/kscience/visionforge/VisionClient.kt @@ -2,6 +2,9 @@ package space.kscience.visionforge import kotlinx.browser.document import kotlinx.browser.window +import kotlinx.coroutines.Job +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach import org.w3c.dom.* import org.w3c.dom.url.URL import space.kscience.dataforge.context.* @@ -13,14 +16,14 @@ import space.kscience.visionforge.html.VisionTagConsumer.Companion.OUTPUT_CONNEC import space.kscience.visionforge.html.VisionTagConsumer.Companion.OUTPUT_ENDPOINT_ATTRIBUTE import space.kscience.visionforge.html.VisionTagConsumer.Companion.OUTPUT_FETCH_ATTRIBUTE import space.kscience.visionforge.html.VisionTagConsumer.Companion.OUTPUT_NAME_ATTRIBUTE -import kotlin.collections.set import kotlin.reflect.KClass +import kotlin.time.Duration public class VisionClient : AbstractPlugin() { override val tag: PluginTag get() = Companion.tag private val visionManager: VisionManager by require(VisionManager) - private val visionMap = HashMap() + //private val visionMap = HashMap() /** * Up-going tree traversal in search for endpoint attribute @@ -53,11 +56,73 @@ public class VisionClient : AbstractPlugin() { private fun Element.getFlag(attribute: String): Boolean = attributes[attribute]?.value != null - private fun renderVision(element: Element, vision: Vision?, outputMeta: Meta) { + private fun renderVision(name: String, element: Element, vision: Vision?, outputMeta: Meta) { if (vision != null) { - visionMap[element] = vision val renderer = findRendererFor(vision) ?: error("Could nof find renderer for $vision") renderer.render(element, vision, outputMeta) + + element.attributes[OUTPUT_CONNECT_ATTRIBUTE]?.let { attr -> + val wsUrl = if (attr.value.isBlank() || attr.value == "auto") { + val endpoint = resolveEndpoint(element) + logger.info { "Vision server is resolved to $endpoint" } + URL(endpoint).apply { + pathname += "/ws" + } + } else { + URL(attr.value) + }.apply { + protocol = "ws" + searchParams.append("name", name) + } + + logger.info { "Updating vision data from $wsUrl" } + + //Individual websocket for this element + WebSocket(wsUrl.toString()).apply { + onmessage = { messageEvent -> + val stringData: String? = messageEvent.data as? String + if (stringData != null) { + val change: VisionChange = visionManager.jsonFormat.decodeFromString( + VisionChange.serializer(), + stringData + ) + + if (change.vision != null) { + renderer.render(element, vision, outputMeta) + } + + logger.debug { "Got update $change for output with name $name" } + vision.update(change) + } else { + console.error("WebSocket message data is not a string") + } + } + + + //Backward change propagation + var feedbackJob: Job? = null + + onopen = { + feedbackJob = vision.flowChanges( + visionManager, + Duration.Companion.milliseconds(300) + ).onEach { change -> + send(visionManager.encodeToString(change)) + }.launchIn(visionManager.context) + + console.info("WebSocket update channel established for output '$name'") + } + + onclose = { + feedbackJob?.cancel() + console.info("WebSocket update channel closed for output '$name'") + } + onerror = { + feedbackJob?.cancel() + console.error("WebSocket update channel error for output '$name'") + } + } + } } } @@ -79,85 +144,39 @@ public class VisionClient : AbstractPlugin() { visionManager.decodeFromString(it) } - if (embeddedVision != null) { - logger.info { "Found embedded vision for output with name $name" } - renderVision(element, embeddedVision, outputMeta) - } - - element.attributes[OUTPUT_FETCH_ATTRIBUTE]?.let { attr -> - - val fetchUrl = if (attr.value.isBlank() || attr.value == "auto") { - val endpoint = resolveEndpoint(element) - logger.info { "Vision server is resolved to $endpoint" } - URL(endpoint).apply { - pathname += "/vision" - } - } else { - URL(attr.value) - }.apply { - searchParams.append("name", name) + when { + embeddedVision != null -> { + logger.info { "Found embedded vision for output with name $name" } + renderVision(name, element, embeddedVision, outputMeta) } + element.attributes[OUTPUT_FETCH_ATTRIBUTE] != null -> { + val attr = element.attributes[OUTPUT_FETCH_ATTRIBUTE]!! - logger.info { "Fetching vision data from $fetchUrl" } - window.fetch(fetchUrl).then { response -> - if (response.ok) { - response.text().then { text -> - val vision = visionManager.decodeFromString(text) - renderVision(element, vision, outputMeta) + val fetchUrl = if (attr.value.isBlank() || attr.value == "auto") { + val endpoint = resolveEndpoint(element) + logger.info { "Vision server is resolved to $endpoint" } + URL(endpoint).apply { + pathname += "/vision" } } else { - logger.error { "Failed to fetch initial vision state from $fetchUrl" } + URL(attr.value) + }.apply { + searchParams.append("name", name) } - } - } - - element.attributes[OUTPUT_CONNECT_ATTRIBUTE]?.let { attr -> - val wsUrl = if (attr.value.isBlank() || attr.value == "auto") { - val endpoint = resolveEndpoint(element) - logger.info { "Vision server is resolved to $endpoint" } - URL(endpoint).apply { - pathname += "/ws" - } - } else { - URL(attr.value) - }.apply { - protocol = "ws" - searchParams.append("name", name) - } - - logger.info { "Updating vision data from $wsUrl" } - - WebSocket(wsUrl.toString()).apply { - onmessage = { messageEvent -> - val stringData: String? = messageEvent.data as? String - if (stringData != null) { - val change = visionManager.jsonFormat.decodeFromString( - VisionChange.serializer(), - stringData - ) - - if (change.vision != null) { - renderVision(element, change.vision, outputMeta) + logger.info { "Fetching vision data from $fetchUrl" } + window.fetch(fetchUrl).then { response -> + if (response.ok) { + response.text().then { text -> + val vision = visionManager.decodeFromString(text) + renderVision(name, element, vision, outputMeta) } - - logger.debug { "Got update $change for output with name $name" } - visionMap[element]?.update(change) - ?: console.info("Target vision for element $element with name $name not found") } else { - console.error("WebSocket message data is not a string") + logger.error { "Failed to fetch initial vision state from $fetchUrl" } } } - onopen = { - console.info("WebSocket update channel established for output '$name'") - } - onclose = { - console.info("WebSocket update channel closed for output '$name'") - } - onerror = { - console.error("WebSocket update channel error for output '$name'") - } } + else -> error("No embedded vision data / fetch url for $name") } } diff --git a/visionforge-server/src/main/kotlin/space/kscience/visionforge/three/server/VisionServer.kt b/visionforge-server/src/main/kotlin/space/kscience/visionforge/three/server/VisionServer.kt index 6f0a3959..2c9ed631 100644 --- a/visionforge-server/src/main/kotlin/space/kscience/visionforge/three/server/VisionServer.kt +++ b/visionforge-server/src/main/kotlin/space/kscience/visionforge/three/server/VisionServer.kt @@ -19,7 +19,9 @@ import io.ktor.server.engine.embeddedServer import io.ktor.websocket.WebSockets import io.ktor.websocket.webSocket import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.channels.consumeEach import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import kotlinx.html.* import kotlinx.html.stream.createHTML @@ -131,6 +133,15 @@ public class VisionServer internal constructor( application.log.debug("Opened server socket for $name") val vision: Vision = visions[name.toName()] ?: error("Plot with id='$name' not registered") + launch { + incoming.consumeEach { + val change = visionManager.jsonFormat.decodeFromString( + VisionChange.serializer(), it.data.decodeToString() + ) + vision.update(change) + } + } + try { withContext(visionManager.context.coroutineContext) { vision.flowChanges(visionManager, Duration.milliseconds(updateInterval)).collect { update -> diff --git a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/csg.kt b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/csg.kt index 2bee0a7a..50e48ee9 100644 --- a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/csg.kt +++ b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/csg.kt @@ -14,17 +14,17 @@ import info.laht.threekt.math.Matrix4 import info.laht.threekt.math.Vector3 import info.laht.threekt.objects.Mesh -external class CSG { - fun clone(): CSG - fun toPolygons(): Array - fun toGeometry(toMatrix: Matrix4): BufferGeometry - fun union(csg: CSG): CSG - fun subtract(csg: CSG): CSG - fun intersect(csg: CSG): CSG - fun inverse(): CSG +public external class CSG { + public fun clone(): CSG + public fun toPolygons(): Array + public fun toGeometry(toMatrix: Matrix4): BufferGeometry + public fun union(csg: CSG): CSG + public fun subtract(csg: CSG): CSG + public fun intersect(csg: CSG): CSG + public fun inverse(): CSG - companion object { + public companion object { fun fromPolygons(polygons: Array): CSG fun fromGeometry(geom: BufferGeometry, objectIndex: dynamic = definedExternally): CSG fun fromMesh(mesh: Mesh, objectIndex: dynamic = definedExternally): CSG From 01ea6b5494daca7c82ee8fa291c888bfd90cf579 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sat, 17 Jul 2021 10:27:51 +0300 Subject: [PATCH 21/29] Bump version --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 8236106e..4ab2a7d5 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -20,7 +20,7 @@ allprojects { } group = "space.kscience" - version = "0.2.0-dev-21" + version = "0.2.0-dev-22" } subprojects { From e50e266f9496f39daad51840bc0abe44eb58b0e8 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sat, 17 Jul 2021 10:55:02 +0300 Subject: [PATCH 22/29] Updated three-csg to 3.1.6 fix issues --- visionforge-threejs/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/visionforge-threejs/build.gradle.kts b/visionforge-threejs/build.gradle.kts index a862f776..a6407d13 100644 --- a/visionforge-threejs/build.gradle.kts +++ b/visionforge-threejs/build.gradle.kts @@ -5,5 +5,5 @@ plugins { dependencies { api(project(":visionforge-solid")) implementation(npm("three", "0.130.1")) - implementation(npm("three-csg-ts", "3.1.5")) + implementation(npm("three-csg-ts", "3.1.6")) } From a0d62c65d73a69abd8518e8e4415a8a287f5c882 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Thu, 22 Jul 2021 20:11:14 +0300 Subject: [PATCH 23/29] Fix FX ValueChooser crash --- ui/ring/build.gradle.kts | 1 - .../visionforge/editor/TextValueChooser.kt | 2 +- .../visionforge/editor/ValueChooser.kt | 7 +++---- .../visionforge/editor/ValueChooserBase.kt | 12 ++++++----- .../editor/VisualObjectEditorFragment.kt | 20 +++++++++---------- .../editor/VisualObjectTreeFragment.kt | 15 ++++++++------ .../kscience/visionforge/solid/FX3DPlugin.kt | 6 +++--- .../visionforge/solid/FXReferenceFactory.kt | 2 +- .../solid/VisualObjectFXBinding.kt | 12 +++++------ 9 files changed, 39 insertions(+), 38 deletions(-) diff --git a/ui/ring/build.gradle.kts b/ui/ring/build.gradle.kts index 84d33b43..4469b8cf 100644 --- a/ui/ring/build.gradle.kts +++ b/ui/ring/build.gradle.kts @@ -22,7 +22,6 @@ dependencies{ implementation(npm("@jetbrains/icons", "3.14.1")) implementation(npm("@jetbrains/ring-ui", "4.0.7")) - implementation(npm("core-js","3.12.1")) implementation(npm("file-saver", "2.0.2")) compileOnly(npm("url-loader","4.1.1")) compileOnly(npm("postcss-loader","5.2.0")) diff --git a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/editor/TextValueChooser.kt b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/editor/TextValueChooser.kt index ea55fc83..e7beac2b 100644 --- a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/editor/TextValueChooser.kt +++ b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/editor/TextValueChooser.kt @@ -15,7 +15,7 @@ import space.kscience.dataforge.names.asName import space.kscience.dataforge.values.* import tornadofx.* -class TextValueChooser : ValueChooserBase() { +public class TextValueChooser : ValueChooserBase() { private val displayText: String get() = currentValue().let { diff --git a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/editor/ValueChooser.kt b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/editor/ValueChooser.kt index c3796fa0..8816a250 100644 --- a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/editor/ValueChooser.kt +++ b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/editor/ValueChooser.kt @@ -14,7 +14,6 @@ import space.kscience.dataforge.meta.descriptors.ValueDescriptor import space.kscience.dataforge.misc.Named import space.kscience.dataforge.misc.Type import space.kscience.dataforge.names.toName -import space.kscience.dataforge.provider.provideByType import space.kscience.dataforge.values.Null import space.kscience.dataforge.values.Value import space.kscience.visionforge.widget @@ -63,7 +62,7 @@ public interface ValueChooser { public fun setCallback(callback: ValueCallback) - @Type("space.kscience.dataforge.vis.fx.valueChooserFactory") + @Type("space.kscience..fx.valueChooserFactory") public interface Factory : Named { public operator fun invoke(meta: Meta = Meta.EMPTY): ValueChooser } @@ -75,7 +74,7 @@ public interface ValueChooser { TextValueChooser.name -> TextValueChooser ColorValueChooser.name -> ColorValueChooser ComboBoxValueChooser.name -> ComboBoxValueChooser - else -> context.provideByType(type)//Search for additional factories in the plugin + else -> null//context.provideByType(type)//Search for additional factories in the plugin } } @@ -101,7 +100,7 @@ public interface ValueChooser { } } - fun build( + public fun build( context: Context, value: ObservableValue, descriptor: ValueDescriptor? = null, diff --git a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/editor/ValueChooserBase.kt b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/editor/ValueChooserBase.kt index 81dc42ac..98790f96 100644 --- a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/editor/ValueChooserBase.kt +++ b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/editor/ValueChooserBase.kt @@ -18,16 +18,18 @@ import tornadofx.* * * @author Alexander Nozik */ -abstract class ValueChooserBase : ValueChooser { +public abstract class ValueChooserBase : ValueChooser { - override val node by lazy { buildNode() } - final override val valueProperty = SimpleObjectProperty(Null) - final override val descriptorProperty = SimpleObjectProperty() + override val node: T by lazy { buildNode() } + final override val valueProperty: SimpleObjectProperty = + SimpleObjectProperty(Null) + final override val descriptorProperty: SimpleObjectProperty = + SimpleObjectProperty() override var descriptor: ValueDescriptor? by descriptorProperty override var value: Value? by valueProperty - fun resetValue() { + public fun resetValue() { setDisplayValue(currentValue()) } diff --git a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/editor/VisualObjectEditorFragment.kt b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/editor/VisualObjectEditorFragment.kt index 929c7e85..a918a3a5 100644 --- a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/editor/VisualObjectEditorFragment.kt +++ b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/editor/VisualObjectEditorFragment.kt @@ -13,13 +13,13 @@ import space.kscience.dataforge.meta.update import space.kscience.visionforge.* import tornadofx.* -class VisualObjectEditorFragment(val selector: (Vision) -> Meta) : Fragment() { +public class VisualObjectEditorFragment(public val selector: (Vision) -> Meta) : Fragment() { - val itemProperty = SimpleObjectProperty() - var item: Vision? by itemProperty - val descriptorProperty = SimpleObjectProperty() + public val itemProperty: SimpleObjectProperty = SimpleObjectProperty() + public var item: Vision? by itemProperty + public val descriptorProperty: SimpleObjectProperty = SimpleObjectProperty() - constructor( + public constructor( item: Vision?, descriptor: NodeDescriptor?, selector: (Vision) -> MutableItemProvider = { it.allProperties() }, @@ -30,13 +30,13 @@ class VisualObjectEditorFragment(val selector: (Vision) -> Meta) : Fragment() { private var currentConfig: Config? = null - private val configProperty: Binding = itemProperty.objectBinding { visualObject -> - if (visualObject == null) return@objectBinding null - val meta = selector(visualObject) + private val configProperty: Binding = itemProperty.objectBinding { vision -> + if (vision == null) return@objectBinding null + val meta = selector(vision) val config = Config().apply { update(meta) onChange(this@VisualObjectEditorFragment) { key, _, after -> - visualObject.setProperty(key, after) + vision.setProperty(key, after) } } //remember old config reference to cleanup listeners @@ -51,7 +51,7 @@ class VisualObjectEditorFragment(val selector: (Vision) -> Meta) : Fragment() { } } - private val styleBoxProperty: Binding = configProperty.objectBinding() { + private val styleBoxProperty: Binding = configProperty.objectBinding { VBox().apply { item?.styles?.forEach { styleName -> val styleMeta = item?.getStyle(styleName) diff --git a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/editor/VisualObjectTreeFragment.kt b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/editor/VisualObjectTreeFragment.kt index f1faaf1a..2fa6cee1 100644 --- a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/editor/VisualObjectTreeFragment.kt +++ b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/editor/VisualObjectTreeFragment.kt @@ -3,6 +3,7 @@ package space.kscience.visionforge.editor import javafx.beans.property.SimpleObjectProperty import javafx.scene.control.SelectionMode import javafx.scene.control.TreeItem +import javafx.scene.layout.VBox import space.kscience.visionforge.Vision import space.kscience.visionforge.VisionGroup import tornadofx.* @@ -29,13 +30,13 @@ private fun toTreeItem(vision: Vision, title: String): TreeItem() - var item: Vision? by itemProperty +public class VisualObjectTreeFragment : Fragment() { + public val itemProperty: SimpleObjectProperty = SimpleObjectProperty() + public var item: Vision? by itemProperty - val selectedProperty = SimpleObjectProperty() + public val selectedProperty: SimpleObjectProperty = SimpleObjectProperty() - override val root = vbox { + override val root: VBox = vbox { titledpane("Object tree", collapsible = false) { treeview> { cellFormat { @@ -47,7 +48,9 @@ class VisualObjectTreeFragment : Fragment() { } } selectionModel.selectionMode = SelectionMode.SINGLE - val selectedValue = selectionModel.selectedItemProperty().objectBinding { it?.value?.second } + val selectedValue = selectionModel.selectedItemProperty().objectBinding { + it?.value?.second + } selectedProperty.bind(selectedValue) } } diff --git a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/FX3DPlugin.kt b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/FX3DPlugin.kt index f843e02c..d46bab32 100644 --- a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/FX3DPlugin.kt +++ b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/FX3DPlugin.kt @@ -23,7 +23,7 @@ import kotlin.collections.set import kotlin.math.PI import kotlin.reflect.KClass -class FX3DPlugin : AbstractPlugin() { +public class FX3DPlugin : AbstractPlugin() { override val tag: PluginTag get() = Companion.tag private val objectFactories = HashMap, FX3DFactory<*>>() @@ -42,7 +42,7 @@ class FX3DPlugin : AbstractPlugin() { as FX3DFactory? } - fun buildNode(obj: Solid): Node { + public fun buildNode(obj: Solid): Node { val binding = VisualObjectFXBinding(this, obj) return when (obj) { is SolidReferenceGroup -> referenceFactory(obj, binding) @@ -149,7 +149,7 @@ public interface FX3DFactory { public operator fun invoke(obj: T, binding: VisualObjectFXBinding): Node public companion object { - public const val TYPE = "fx3DFactory" + public const val TYPE: String = "fx3DFactory" } } diff --git a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/FXReferenceFactory.kt b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/FXReferenceFactory.kt index dc72f7f1..022900df 100644 --- a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/FXReferenceFactory.kt +++ b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/FXReferenceFactory.kt @@ -7,7 +7,7 @@ import space.kscience.visionforge.Vision import space.kscience.visionforge.onPropertyChange import kotlin.reflect.KClass -class FXReferenceFactory(val plugin: FX3DPlugin) : FX3DFactory { +public class FXReferenceFactory(public val plugin: FX3DPlugin) : FX3DFactory { override val type: KClass get() = SolidReferenceGroup::class override fun invoke(obj: SolidReferenceGroup, binding: VisualObjectFXBinding): Node { diff --git a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/VisualObjectFXBinding.kt b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/VisualObjectFXBinding.kt index 5045a375..a2f41fbe 100644 --- a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/VisualObjectFXBinding.kt +++ b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/VisualObjectFXBinding.kt @@ -14,7 +14,7 @@ import tornadofx.* /** * A caching binding collection for [Vision] properties */ -public class VisualObjectFXBinding(public val fx: FX3DPlugin, public val obj: Vision) { +public class VisualObjectFXBinding(private val fx: FX3DPlugin, public val obj: Vision) { private val bindings = HashMap>() init { @@ -33,15 +33,13 @@ public class VisualObjectFXBinding(public val fx: FX3DPlugin, public val obj: Vi } } - public operator fun get(key: Name): ObjectBinding { - return bindings.getOrPut(key) { - object : ObjectBinding() { - override fun computeValue(): MetaItem? = obj.getProperty(key) - } + public operator fun get(key: Name): ObjectBinding = bindings.getOrPut(key) { + object : ObjectBinding() { + override fun computeValue(): MetaItem? = obj.getProperty(key) } } - public operator fun get(key: String) = get(key.toName()) + public operator fun get(key: String): ObjectBinding?> = get(key.toName()) } public fun ObjectBinding.value(): Binding = objectBinding { it.value } From a474ad7b3b9217220b9379308745e066857c7073 Mon Sep 17 00:00:00 2001 From: kiruma524 <71787194+kiruma524@users.noreply.github.com> Date: Thu, 29 Jul 2021 14:19:29 +0300 Subject: [PATCH 24/29] Delete tutorial.md --- docs/tutorial.md | 209 ----------------------------------------------- 1 file changed, 209 deletions(-) delete mode 100644 docs/tutorial.md diff --git a/docs/tutorial.md b/docs/tutorial.md deleted file mode 100644 index 9de1432b..00000000 --- a/docs/tutorial.md +++ /dev/null @@ -1,209 +0,0 @@ -#Tutorial - -###The main goal of this tutorial is to show all capabilities of ... (this part will be supplemented) - -The simple visualization can be made with function `main`. (this part will be supplemented as well) -```kotlin -import kotlinx.html.div -import space.kscience.dataforge.context.Context -import space.kscience.visionforge.html.ResourceLocation -import space.kscience.visionforge.solid.* -import java.nio.file.Paths - -fun main(){ - val context = Context{ - plugin(Solids) - } - - context.makeVisionFile ( - Paths.get("customFile.html"), - resourceLocation = ResourceLocation.EMBED - ){ - div { - vision { - solid { - } - } - } - } -} -``` -##Solids properties -**We will analyze which basic properties solids have using `box` solid.** - -Basic properties: -1. `opacity` - It is set in `float`. It takes on values from 0 to 1, which represent percents of solid opacity. It's initial value is 1. -2. `color` - It can be specified as `Int`, `String`, or as three `Ubytes`, which represent color in `rgb`. Elementally, the solid will have `green` color. -3. `rotation` - it's the point, around which the solid will be rotated. Initially, the value is `Point3D(0, 0, 0)` -4. position, which is given by values `x`, `y`, `z`. Initial values are `x = 0`, `y = 0`, `z = 0` - -Let's see how properties are set in solids. -The `small box` will have elemental values of properties. If you will not set properties, it will have the same `position`, `color`, `rotation`, and `opacity` values. - -***You can see that `box` take four values. Later, we will discuss what they are doing in more detail. Now, it does not really matter.*** -```kotlin -box(10, 10, 10, name = "small box"){ - x = 0 - y = 0 - z = 0 - opacity = 1 //100% opacity - color("red") //as string - rotation = Point3D(0, 0, 0) -} -``` -![](../docs/images/small-box.png) - -The `big box` will have properties with custom values. -```kotlin -box(40, 40, 40, name = "big box"){ - x = 20 - y = 10 - z = 60 - opacity = 0.5 //50% opacity - color(0u, 179u, 179u) //color in rgb - rotation = Point3D(60, 80, 0) -} -``` -![](../docs/images/big-rotated-box.png) - -If we compare these boxes, we will see all differences. - -Here is the function `main` with both boxes. -```kotlin -fun main(){ - val context = Context{ - plugin(Solids) - } - - context.makeVisionFile ( - Paths.get("customFile.html"), - resourceLocation = ResourceLocation.EMBED - ){ - div { - vision { - solid { - box(10, 10, 10, name = "small box"){ - x = 0 - y = 0 - z = 0 - opacity = 1 //100% opacity - color("red") //as string - rotation = Point3D(0, 0, 0) - } - box(40, 40, 40, name = "big box"){ - x = 20 - y = 10 - z = 60 - opacity = 0.5 //50% opacity - color(0u, 179u, 179u) //rgb - rotation = Point3D(60, 80, 0) - } - } - } - } - } -} -``` -![](../docs/images/two-boxes-1.png) -![](../docs/images/two-boxes-2.png) - -###Basic Solids - -Now, let's see which solids can be visualized: -1) PolyLine -2) Box - ```kotlin - box(50, 50, 50, name = "box") { - x = 0 - y = 0 - z = 0 - color("pink") - } - ``` - ![](../docs/images/box.png) - ```kotlin - box(10, 25, 10, name = "high_box") { - x = 0 - y = 0 - z = 0 - color("black") - } - ``` - ![](../docs/images/high-box.png) - - ```kotlin - box(65, 40, 40, name = "wide_box") { - x = 0 - y = 0 - z = 0 - color("black") - } - ``` - ![](../docs/images/wide-box.png) - -3) Sphere - ```kotlin - sphere(50, name = "sphere") { - x = 0 - y = 0 - z = 0 - color("blue") - } - ``` - ![](../docs/images/sphere.png) -4) Hexagon - ```kotlin - hexagon( - Point3D(25, 30, 25), - Point3D(35, 30, 25), - Point3D(35, 30, 15), - Point3D(25, 30, 15), - Point3D(30, 18, 20), - Point3D(40, 18, 20), - Point3D(40, 18, 10), - Point3D(30, 18, 10), - name = "classic_hexagon"){ - color("green") - } - ``` - ![](../docs/images/classic-hexagon.png) - ```kotlin - hexagon( - Point3D(5, 30, 5), - Point3D(24, 30, 8), - Point3D(20, 30, -10), - Point3D(5, 30, -7), - Point3D(8, 16, 0), - Point3D(12, 16, 0), - Point3D(10, 16, -5), - Point3D(6.5, 12, -3), - name = "custom_hexagon"){ - color("brown") - } - ``` - ![](../docs/images/custom-hexagon.png) -5) Cone - ```kotlin - cone(60, 80, name = "cone") { - x = 0 - y = 0 - z = 0 - color("beige") - } - ``` - ![](../docs/images/cone-1.png) - ![](../docs/images/cone-2.png) -6) Cone Surface - ```kotlin - coneSurface(60, 50, 30, 10, 100, name = "cone_surface") { - x = 0 - y = 0 - z = 0 - color("red") - rotation = Point3D(2, 50, -9) - } - ``` - ![](../docs/images/cone-surface-1.png) - ![](../docs/images/cone-surface-2.png) -7) Extruded - From d51a38eac41a0fe64cbf1a88809c877c96773ac0 Mon Sep 17 00:00:00 2001 From: kiruma524 <71787194+kiruma524@users.noreply.github.com> Date: Thu, 29 Jul 2021 14:20:15 +0300 Subject: [PATCH 25/29] Add files via upload Not final version of tutorial --- docs/tutorial.md | 333 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 333 insertions(+) create mode 100644 docs/tutorial.md diff --git a/docs/tutorial.md b/docs/tutorial.md new file mode 100644 index 00000000..15b24b3c --- /dev/null +++ b/docs/tutorial.md @@ -0,0 +1,333 @@ +# Tutorial + +#### The main goal of this tutorial is to show all capabilities of ... (this part will be supplemented) + +The simple visualization can be made with function `main`. (this part will be supplemented as well) +```kotlin +import kotlinx.html.div +import space.kscience.dataforge.context.Context +import space.kscience.visionforge.html.ResourceLocation +import space.kscience.visionforge.solid.* +import java.nio.file.Paths + +fun main(){ + val context = Context{ + plugin(Solids) + } + + context.makeVisionFile ( + Paths.get("customFile.html"), + resourceLocation = ResourceLocation.EMBED + ){ + div { + vision { + solid { + } + } + } + } +} +``` +## Solids properties +**We will analyze which basic properties solids have using `box` solid.** + +*Basic properties:* +1. `opacity` - It is set in `float`. It takes on values from 0 to 1, which represent percents of solid opacity. It's initial value is 1. +2. `color` - It can be specified as `Int`, `String`, or as three `Ubytes`, which represent color in `rgb`. Elementally, the solid will have `green` color. +3. `rotation` - it's the point, around which the solid will be rotated. Initially, the value is `Point3D(0, 0, 0)`. Changing `x` coordinate of the point, you make pivot around `x axis`. The same for other coordinates: changing `y` - pivot around `y axis`, changing `z` - pivot around `z axis`. +4. position, which is given by values `x`, `y`, `z`. Initial values are `x = 0`, `y = 0`, `z = 0`. The coordinate system is Cartesian. It's elemental position is this - vertical `y` axis and horizontal `Oxz` plane. + +Let's see how properties are set in solids. +The `small box` will have elemental values of properties. If you will not set properties, it will have the same `position`, `color`, `rotation`, and `opacity` values. + +***You can see that `box` take four values. Later, we will discuss what they do in more detail. Now, it does not really matter.*** +```kotlin +box(10, 10, 10, name = "small box"){ + x = 0 + y = 0 + z = 0 + opacity = 1 //100% opacity + color("red") //as string + rotation = Point3D(0, 0, 0) +} +``` +![](../docs/images/small-box.png) + +The `big box` will have properties with custom values. +```kotlin +box(40, 40, 40, name = "big box"){ + x = 20 + y = 10 + z = 60 + opacity = 0.5 //50% opacity + color(0u, 179u, 179u) //color in rgb + rotation = Point3D(60, 80, 0) +} +``` +![](../docs/images/big-rotated-box.png) +If we compare these boxes, we will see all differences. + +Here is the function `main` with both boxes. +```kotlin +fun main(){ + val context = Context{ + plugin(Solids) + } + + context.makeVisionFile ( + Paths.get("customFile.html"), + resourceLocation = ResourceLocation.EMBED + ){ + div { + vision { + solid { + box(10, 10, 10, name = "small box"){ + x = 0 + y = 0 + z = 0 + opacity = 1 //100% opacity + color("red") //as string + rotation = Point3D(0, 0, 0) + } + box(40, 40, 40, name = "big box"){ + x = 20 + y = 10 + z = 60 + opacity = 0.5 //50% opacity + color(0u, 179u, 179u) //rgb + rotation = Point3D(60, 80, 0) + } + } + } + } + } +} +``` +![](../docs/images/two-boxes-1.png) +![](../docs/images/two-boxes-2.png) + +***There is plenty of other properties, especially of those, which you can create by yourself. Here we mention just small part.*** + +## Basic Solids +Now, let's see which solids can be visualized: +### 1) PolyLine +### 2) Box + +First thing which has to be mentioned is that `box` takes four values: `box(x, y, z, name)` +* `x` - x-axis length of the `box` +* `y` - y-axis length of the `box` +* `z` - z-axis length of the `box` + +These values have `Float` type. *`x`, `y`, and `z` are necessary values, which cannot be ignored. You have to set them.* + +* `name` - `box`'es identifier with `String` type. *It's an optional value, but without it you won't be able to control solid.* + +Let's create just usual `box` with equal ribs. + +```kotlin + box(50, 50, 50, name = "box") { + color("pink") + } +``` + ![](../docs/images/box.png) + +Now, let's make `box` with bigger `y` value. + ```kotlin + box(10, 25, 10, name = "high box") { + color("black") + } + ``` +As you can see, only rib of `y-axis` differs from other ribs. + + ![](../docs/images/high-box.png) + +For final trial, let's create `box` with bigger `x` value. + + ```kotlin + box(65, 40, 40, name = "wide box") { + x = 0 + y = 0 + z = 0 + color("black") + } + ``` +Predictably, only `x-axis` rib bigger than other ribs. + + ![](../docs/images/wide-box.png) + +### 3) Sphere + +It takes in two values: `radius`, and `name`. +Actually, `name` is general value for all solids, so do not wonder, since all solids need their own identifier. + +As for `radius`, it has `Float` type, and, as you can guess, it sets radius of the sphere, which will be created. + ```kotlin + sphere(50, name = "sphere") { + x = 0 + y = 0 + z = 0 + opacity = 0.9 + color("blue") + } + ``` + ![](../docs/images/sphere.png) + +### 4) Hexagon + +It is solid which has six edges. It is set by eight values: `node1`,..., `node8`. They all have `Point3D` type, so they are just points, vertices. + +*Six edges are these:* +1) Edge with vertices `node1`, `node4`, `node3`, `node2` +2) Edge with vertices `node1`, `node2`, `node6`, `node5` +3) Edge with vertices `node2`, `node3`, `node7`, `node6` +4) Edge with vertices `node4`, `node8`, `node7`, `node3` +5) Edge with vertices `node1`, `node5`, `node8`, `node4` +6) Edge with vertices `node8`, `node5`, `node6`, `node7` + +![](../docs/images/scheme.png) + +As hexagon takes in specific points, we understand that this solid cannot be moved, it fixed in space, and it can't make pivots. + +Let's make classic parallelepiped. +```kotlin + hexagon( + Point3D(25, 30, 25), + Point3D(35, 30, 25), + Point3D(35, 30, 15), + Point3D(25, 30, 15), + Point3D(30, 18, 20), + Point3D(40, 18, 20), + Point3D(40, 18, 10), + Point3D(30, 18, 10), + name = "classic hexagon"){ + color("green") + } +``` + ![](../docs/images/classic-hexagon.png) + +Now, let's make a custom hexagon. + + ```kotlin + hexagon( + Point3D(5, 30, 5), + Point3D(24, 30, 8), + Point3D(20, 30, -10), + Point3D(5, 30, -7), + Point3D(8, 16, 0), + Point3D(12, 16, 0), + Point3D(10, 16, -5), + Point3D(6.5, 12, -3), + name = "custom_hexagon"){ + color("brown") + } + ``` + ![](../docs/images/custom-hexagon.png) +### 3) Cone +It takes in six values: `bottomRadius`, `height`, `upperRadius`, `startAngle`, `angle`, and `name`. + +Obviously, `bottomRadius` is responsible for radius of a bottom base, and `height` sets height of a cone along the `z-axis`. + +As it takes such values as `upperRadius`, `startAngle`, `angle`, `cone` can build not only usual cones, but also cone segments. Initially, `upperRadius` will have `0.0` value, `startAngle` - `0f`, `angle` - `PI2`, so if you don't set them, you'll get just a simple cone. + +Setting `upperRadius`, you make a frustum cone, since it sets a radius of the upper base of a cone. Set `startAngle`, and `angle` let to cut off segments by planes perpendicular to the base. `startAngle` - an angle, starting with which segment will be left, `angle` - an angle of cone, which will be set from `startAngle`. + +Let's build a classic cone: +```kotlin + cone(60, 80, name = "cone") { + color("beige") + } + ``` + ![](../docs/images/cone-1.png) + ![](../docs/images/cone-2.png) + +First of all, we have to try to build a frustum cone: +```kotlin +cone(60, 80, name = "cone") { + color(0u, 40u, 0u) +} +``` +![](../docs/images/frustum-cone.png) + +Now, we need to make a try to build a cone segment: + +```kotlin +cone(60, 80, angle = PI, name = "cone") { + color(0u, 0u, 200u) +} +``` +![](../docs/images/cone-segment-1.png) +![](../docs/images/cone-segment-2.png) + +Finally, the segment of frustum cone is left for a try: +```kotlin +cone(60, 100, 20, PI*3/4, angle = PI/3, name = "cone") { + color(190u, 0u, 0u) +} +``` +![](../docs/images/frustum-cone-segment.png) + +### 4) Cone Surface +This solid is set by seven values:`bottomOuterRadius`, `bottomInnerRadius`, `height`, `topOuterRadius`, `topInnerRadius`, `startAngle`, and `angle`. + +In addition to `height`, `startAngle`, and `angle`, which work as they work in `cone`, there are some new values. +`bottomOuterRadius`, and `bottomInnerRadius` set properties of the bottom circle, `topOuterRadius`, `topInnerRadius` - of the upper circle. They have no initial value, so that means they have to be set. + +Generally, `cone`, and `coneSurface` buildings work in the same way, it's possible to make `coneSurface`'s fragments as in `cone` + +Let's build usual cone surface with almost all properties set: +```kotlin + coneSurface(60, 50, 30, 10, 100, name = "cone surface") { + color("red") + rotation = Point3D(2, 50, -9) + } + ``` +![](../docs/images/cone-surface-1.png) +![](../docs/images/cone-surface-2.png) + +Now, let's create a cone surface and set all it's properties: + +```kotlin +coneSurface(30, 25, 10, 10, 8,0f, pi*3/4, name = "cone surface") { + color("fuchsia") + rotation = Point3D(2, 50, -9) +} +``` +![](../docs/images/cone-surface-fragment.png) +![](../docs/images/cone-surface-fragment-2.png) + +### 5) Cylinder + +This solid is set by `radius`, and `height`. As you can see by accepting values, there's no option of building fragments of cylinders. + +Here's a demonstration of a cylinder: + +```kotlin +cylinder(40, 100, "cylinder"){ + rotation = Point3D(40, 0, 0) + color("indigo") +} +``` +![](../docs/images/cylinder-1.png) +![](../docs/images/cylinder-2.png) +### 6) Tube + +`tube` takes in `radius`, `height`, `innerRadius`, `startAngle`, `angle`, and `name`. *All values are familiar from `cone`, and `coneSurface` solids.* + +Here is an example of classic tube: +```kotlin +tube(50, 40, 20, name = "usual tube"){ + opacity = 0.4 +} +``` +![](../docs/images/tube.png) + +This is an example of tube fragment: + +```kotlin +tube(50, 40, 20, 0f, PI, name = "fragmented tube"){ + color("white") +} +``` +![](../docs/images/tube-fragment.png) +### 7) Extruded + From 4bdea746fc35a8c19d62254e466fa9989e80f6f6 Mon Sep 17 00:00:00 2001 From: kiruma524 <71787194+kiruma524@users.noreply.github.com> Date: Wed, 4 Aug 2021 22:07:51 +0300 Subject: [PATCH 26/29] Images for polyline --- docs/images/polyline-points-2.png | Bin 0 -> 2912 bytes docs/images/polyline-points.png | Bin 0 -> 2547 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/images/polyline-points-2.png create mode 100644 docs/images/polyline-points.png diff --git a/docs/images/polyline-points-2.png b/docs/images/polyline-points-2.png new file mode 100644 index 0000000000000000000000000000000000000000..716ebb181df3321015fbcc3309a6cb808c54995b GIT binary patch literal 2912 zcmeHJX;>3?8XwLE$~6QLXt>6LAgFlICF;uI7!n8&*2IwatO1~c{pEtU3`)y| zkX;!7pwxgp5*v){;s8K?iUM2zo$2vjSaI?zTS=bxp755s$l5(lp(mVm-1}n$?r|Bi zVeL1jyP7gXxi@L=BWW#T;ac$~PX2Dt(!kMlDt6G}7UqL)T`csyOtrJ33Bx>LF$8JTVaD9k%ICVHuL>9?U-1{`=! zats7>BTRMD%MKP98kL)ZS1C^$edu=kc7|DxBOxGYIsKu;=**+|Y9kMsPykPaD{jR#N~V zLzPQppf0W=8-0^n6h+CRkK@2+U#4Xh!oN>x57+RQ4THK|=IeCeId3$jqq!Ug! z00}h5XQ(j!bpjeQL6zf(@Ur2T`vNSKGJAxF+^FwdM2!cmF78yJ{)I_dJZn6XbJA?% zE{-E%ufu#rTFP##92Vi954UGAEpu2jJjXFFs)YTxJearzn&=aZ++yL(!8dT!qgz{T zk2fO=i$bTmq1f4Ju`9P*!PWu3#UgJOAcQ?BcK-@;A*Jx|G#tW%fslapGeoDBRb?K6 z1U43dkc|Vpr@|Ljnld}$x>K+5&L)A|D%THA4LDI<*@)aGq~;=M1WFkf677|8SV2z@ zSF3V7Rt(0gZ=$#5R%PaI68KmIz7j>g#T!C`cn^r~-`r<+3Vicdf;o8A5Yiqshj@fU z18rJ%3g2C#&w0g9`Hkf$LtEnd1L10|6<5JT?C`5zuK{P6gv0V7CU0*ymI{qAIe$1N z$a-PeTP@u~)zKp#7D&RvumM#t-ZR|BC!HeZ{& z>}t-Jp}yN19!+m|eI~tpQsI#n=#q#$+dK~!%0U9Ce?Hz3!NsV$`JY38Z2Xir3l~%A zB%Q0bx?#&tcO&)mCa*-%9|WHruXnLtiCsx+2m^1KI~)%`!}hM-y6Cg zHRHCl^(4(t4Qlv)akB2=2XXkBnpoMkcKrwcfh)dg6|1=9uhFs_q>Ns{i?UoF&s zLlJKV+Rv%wYr8fo=~WAYy^gNloi)(QH;>V775uLd%1P3t2iE!B&?{v#jfQ}((seLW z?~mO6y7@()QD@i9bpBn?B?&2~@EV+vFWc;4jf=JQ_h4zA&QMUz;tCoBBTW5IfVDo# c^skw>JR2O}b5~UV6^e=h%0WlC)W+-F?+ouEhX4Qo literal 0 HcmV?d00001 diff --git a/docs/images/polyline-points.png b/docs/images/polyline-points.png new file mode 100644 index 0000000000000000000000000000000000000000..68d5d1416b059d3433259b4bb8e4e9f6cf536add GIT binary patch literal 2547 zcmeH}ZBP?O7{@P00?2^@DkdQ!g1lHjQZCA?0uc!yqGD@NQKRT3YQ_p-1SM#IAfPF= zN|7Ycm_mz6Rgf7eA`ssI&0UCP~p{moRlUG&{lS0Z=?QK18A2zEVN-Z0x^>f)!W$$_+xNCHv?OX4vq``Fn zaa^fg2ZWiJ154yMdnYtR7NZC{Oipp2GxyvvT9KRZG2J9+sWV& z^HISXOGz>9;tF>iJr?^%&;b%Cv8UD4w7KN&bRnDoL+jH^C5JRByI4h~vC_InRBe&O@>eo7~9+6^XW_ zEwGf_D?o=<6CAja9QgSvp=UY2p;ZVwz>vbu6pcjSu`QFE+E1y6HYky%WpstF3A)%_ z`qtxhOSzL=ocSxU?x%Y4atFFKO^VZCL$G$=$H%OUb7Me0m1MiS_L=4;=u7^3z~6MH_xdc+CTC^`?!%Hi#D*Wq5RTDO7Y0S!EXFA?XiVJn1 zJ6`=wRXr|sSWM6ON-AfKi%zRW4NcZ0LmL) zf-K^6FNC+f9v~QCx1V^=!S|O6e5LI_(~>kb-lo0WLsRtVleLZgkITFVYO-o}_@zuc zw?HnwGjdY4e0e7Xe{69mam!y$qtkYdqufjwKV9gr1=>g zir}#9mB9jDp-+Yf7I1eGsdI1Mb=a9UOD+~}EgZKQWlFaN-VXhsr>(wlosAsrz>eQ$4O`G?CCM3EYF^Hqp*YG_{c&&qF?h-@VVFBUhz*zjVYq44 zV%~!IYk~N}lLpnKPH$NNPY>D}41&hi8Y_+m&Yd#px;L$LR#yHasoQ}}*bH;%{-5N}dH+AYZ-{ Date: Wed, 4 Aug 2021 22:08:38 +0300 Subject: [PATCH 27/29] Delete tutorial.md --- docs/tutorial.md | 333 ----------------------------------------------- 1 file changed, 333 deletions(-) delete mode 100644 docs/tutorial.md diff --git a/docs/tutorial.md b/docs/tutorial.md deleted file mode 100644 index 15b24b3c..00000000 --- a/docs/tutorial.md +++ /dev/null @@ -1,333 +0,0 @@ -# Tutorial - -#### The main goal of this tutorial is to show all capabilities of ... (this part will be supplemented) - -The simple visualization can be made with function `main`. (this part will be supplemented as well) -```kotlin -import kotlinx.html.div -import space.kscience.dataforge.context.Context -import space.kscience.visionforge.html.ResourceLocation -import space.kscience.visionforge.solid.* -import java.nio.file.Paths - -fun main(){ - val context = Context{ - plugin(Solids) - } - - context.makeVisionFile ( - Paths.get("customFile.html"), - resourceLocation = ResourceLocation.EMBED - ){ - div { - vision { - solid { - } - } - } - } -} -``` -## Solids properties -**We will analyze which basic properties solids have using `box` solid.** - -*Basic properties:* -1. `opacity` - It is set in `float`. It takes on values from 0 to 1, which represent percents of solid opacity. It's initial value is 1. -2. `color` - It can be specified as `Int`, `String`, or as three `Ubytes`, which represent color in `rgb`. Elementally, the solid will have `green` color. -3. `rotation` - it's the point, around which the solid will be rotated. Initially, the value is `Point3D(0, 0, 0)`. Changing `x` coordinate of the point, you make pivot around `x axis`. The same for other coordinates: changing `y` - pivot around `y axis`, changing `z` - pivot around `z axis`. -4. position, which is given by values `x`, `y`, `z`. Initial values are `x = 0`, `y = 0`, `z = 0`. The coordinate system is Cartesian. It's elemental position is this - vertical `y` axis and horizontal `Oxz` plane. - -Let's see how properties are set in solids. -The `small box` will have elemental values of properties. If you will not set properties, it will have the same `position`, `color`, `rotation`, and `opacity` values. - -***You can see that `box` take four values. Later, we will discuss what they do in more detail. Now, it does not really matter.*** -```kotlin -box(10, 10, 10, name = "small box"){ - x = 0 - y = 0 - z = 0 - opacity = 1 //100% opacity - color("red") //as string - rotation = Point3D(0, 0, 0) -} -``` -![](../docs/images/small-box.png) - -The `big box` will have properties with custom values. -```kotlin -box(40, 40, 40, name = "big box"){ - x = 20 - y = 10 - z = 60 - opacity = 0.5 //50% opacity - color(0u, 179u, 179u) //color in rgb - rotation = Point3D(60, 80, 0) -} -``` -![](../docs/images/big-rotated-box.png) -If we compare these boxes, we will see all differences. - -Here is the function `main` with both boxes. -```kotlin -fun main(){ - val context = Context{ - plugin(Solids) - } - - context.makeVisionFile ( - Paths.get("customFile.html"), - resourceLocation = ResourceLocation.EMBED - ){ - div { - vision { - solid { - box(10, 10, 10, name = "small box"){ - x = 0 - y = 0 - z = 0 - opacity = 1 //100% opacity - color("red") //as string - rotation = Point3D(0, 0, 0) - } - box(40, 40, 40, name = "big box"){ - x = 20 - y = 10 - z = 60 - opacity = 0.5 //50% opacity - color(0u, 179u, 179u) //rgb - rotation = Point3D(60, 80, 0) - } - } - } - } - } -} -``` -![](../docs/images/two-boxes-1.png) -![](../docs/images/two-boxes-2.png) - -***There is plenty of other properties, especially of those, which you can create by yourself. Here we mention just small part.*** - -## Basic Solids -Now, let's see which solids can be visualized: -### 1) PolyLine -### 2) Box - -First thing which has to be mentioned is that `box` takes four values: `box(x, y, z, name)` -* `x` - x-axis length of the `box` -* `y` - y-axis length of the `box` -* `z` - z-axis length of the `box` - -These values have `Float` type. *`x`, `y`, and `z` are necessary values, which cannot be ignored. You have to set them.* - -* `name` - `box`'es identifier with `String` type. *It's an optional value, but without it you won't be able to control solid.* - -Let's create just usual `box` with equal ribs. - -```kotlin - box(50, 50, 50, name = "box") { - color("pink") - } -``` - ![](../docs/images/box.png) - -Now, let's make `box` with bigger `y` value. - ```kotlin - box(10, 25, 10, name = "high box") { - color("black") - } - ``` -As you can see, only rib of `y-axis` differs from other ribs. - - ![](../docs/images/high-box.png) - -For final trial, let's create `box` with bigger `x` value. - - ```kotlin - box(65, 40, 40, name = "wide box") { - x = 0 - y = 0 - z = 0 - color("black") - } - ``` -Predictably, only `x-axis` rib bigger than other ribs. - - ![](../docs/images/wide-box.png) - -### 3) Sphere - -It takes in two values: `radius`, and `name`. -Actually, `name` is general value for all solids, so do not wonder, since all solids need their own identifier. - -As for `radius`, it has `Float` type, and, as you can guess, it sets radius of the sphere, which will be created. - ```kotlin - sphere(50, name = "sphere") { - x = 0 - y = 0 - z = 0 - opacity = 0.9 - color("blue") - } - ``` - ![](../docs/images/sphere.png) - -### 4) Hexagon - -It is solid which has six edges. It is set by eight values: `node1`,..., `node8`. They all have `Point3D` type, so they are just points, vertices. - -*Six edges are these:* -1) Edge with vertices `node1`, `node4`, `node3`, `node2` -2) Edge with vertices `node1`, `node2`, `node6`, `node5` -3) Edge with vertices `node2`, `node3`, `node7`, `node6` -4) Edge with vertices `node4`, `node8`, `node7`, `node3` -5) Edge with vertices `node1`, `node5`, `node8`, `node4` -6) Edge with vertices `node8`, `node5`, `node6`, `node7` - -![](../docs/images/scheme.png) - -As hexagon takes in specific points, we understand that this solid cannot be moved, it fixed in space, and it can't make pivots. - -Let's make classic parallelepiped. -```kotlin - hexagon( - Point3D(25, 30, 25), - Point3D(35, 30, 25), - Point3D(35, 30, 15), - Point3D(25, 30, 15), - Point3D(30, 18, 20), - Point3D(40, 18, 20), - Point3D(40, 18, 10), - Point3D(30, 18, 10), - name = "classic hexagon"){ - color("green") - } -``` - ![](../docs/images/classic-hexagon.png) - -Now, let's make a custom hexagon. - - ```kotlin - hexagon( - Point3D(5, 30, 5), - Point3D(24, 30, 8), - Point3D(20, 30, -10), - Point3D(5, 30, -7), - Point3D(8, 16, 0), - Point3D(12, 16, 0), - Point3D(10, 16, -5), - Point3D(6.5, 12, -3), - name = "custom_hexagon"){ - color("brown") - } - ``` - ![](../docs/images/custom-hexagon.png) -### 3) Cone -It takes in six values: `bottomRadius`, `height`, `upperRadius`, `startAngle`, `angle`, and `name`. - -Obviously, `bottomRadius` is responsible for radius of a bottom base, and `height` sets height of a cone along the `z-axis`. - -As it takes such values as `upperRadius`, `startAngle`, `angle`, `cone` can build not only usual cones, but also cone segments. Initially, `upperRadius` will have `0.0` value, `startAngle` - `0f`, `angle` - `PI2`, so if you don't set them, you'll get just a simple cone. - -Setting `upperRadius`, you make a frustum cone, since it sets a radius of the upper base of a cone. Set `startAngle`, and `angle` let to cut off segments by planes perpendicular to the base. `startAngle` - an angle, starting with which segment will be left, `angle` - an angle of cone, which will be set from `startAngle`. - -Let's build a classic cone: -```kotlin - cone(60, 80, name = "cone") { - color("beige") - } - ``` - ![](../docs/images/cone-1.png) - ![](../docs/images/cone-2.png) - -First of all, we have to try to build a frustum cone: -```kotlin -cone(60, 80, name = "cone") { - color(0u, 40u, 0u) -} -``` -![](../docs/images/frustum-cone.png) - -Now, we need to make a try to build a cone segment: - -```kotlin -cone(60, 80, angle = PI, name = "cone") { - color(0u, 0u, 200u) -} -``` -![](../docs/images/cone-segment-1.png) -![](../docs/images/cone-segment-2.png) - -Finally, the segment of frustum cone is left for a try: -```kotlin -cone(60, 100, 20, PI*3/4, angle = PI/3, name = "cone") { - color(190u, 0u, 0u) -} -``` -![](../docs/images/frustum-cone-segment.png) - -### 4) Cone Surface -This solid is set by seven values:`bottomOuterRadius`, `bottomInnerRadius`, `height`, `topOuterRadius`, `topInnerRadius`, `startAngle`, and `angle`. - -In addition to `height`, `startAngle`, and `angle`, which work as they work in `cone`, there are some new values. -`bottomOuterRadius`, and `bottomInnerRadius` set properties of the bottom circle, `topOuterRadius`, `topInnerRadius` - of the upper circle. They have no initial value, so that means they have to be set. - -Generally, `cone`, and `coneSurface` buildings work in the same way, it's possible to make `coneSurface`'s fragments as in `cone` - -Let's build usual cone surface with almost all properties set: -```kotlin - coneSurface(60, 50, 30, 10, 100, name = "cone surface") { - color("red") - rotation = Point3D(2, 50, -9) - } - ``` -![](../docs/images/cone-surface-1.png) -![](../docs/images/cone-surface-2.png) - -Now, let's create a cone surface and set all it's properties: - -```kotlin -coneSurface(30, 25, 10, 10, 8,0f, pi*3/4, name = "cone surface") { - color("fuchsia") - rotation = Point3D(2, 50, -9) -} -``` -![](../docs/images/cone-surface-fragment.png) -![](../docs/images/cone-surface-fragment-2.png) - -### 5) Cylinder - -This solid is set by `radius`, and `height`. As you can see by accepting values, there's no option of building fragments of cylinders. - -Here's a demonstration of a cylinder: - -```kotlin -cylinder(40, 100, "cylinder"){ - rotation = Point3D(40, 0, 0) - color("indigo") -} -``` -![](../docs/images/cylinder-1.png) -![](../docs/images/cylinder-2.png) -### 6) Tube - -`tube` takes in `radius`, `height`, `innerRadius`, `startAngle`, `angle`, and `name`. *All values are familiar from `cone`, and `coneSurface` solids.* - -Here is an example of classic tube: -```kotlin -tube(50, 40, 20, name = "usual tube"){ - opacity = 0.4 -} -``` -![](../docs/images/tube.png) - -This is an example of tube fragment: - -```kotlin -tube(50, 40, 20, 0f, PI, name = "fragmented tube"){ - color("white") -} -``` -![](../docs/images/tube-fragment.png) -### 7) Extruded - From 145673752e145dc3dac5c0db859e0a675d441fbf Mon Sep 17 00:00:00 2001 From: kiruma524 <71787194+kiruma524@users.noreply.github.com> Date: Wed, 4 Aug 2021 22:09:15 +0300 Subject: [PATCH 28/29] Updated tutorial, some details left --- docs/tutorial.md | 373 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 373 insertions(+) create mode 100644 docs/tutorial.md diff --git a/docs/tutorial.md b/docs/tutorial.md new file mode 100644 index 00000000..d70d306d --- /dev/null +++ b/docs/tutorial.md @@ -0,0 +1,373 @@ +# Tutorial + +#### The main goal of this tutorial is to show main capabilities of the visualization instrument. + +The simple visualization can be made with function `main`. (this part will be supplemented) +```kotlin +import kotlinx.html.div +import space.kscience.dataforge.context.Context +import space.kscience.visionforge.html.ResourceLocation +import space.kscience.visionforge.solid.* +import java.nio.file.Paths + +fun main(){ + val context = Context{ + plugin(Solids) + } + + context.makeVisionFile ( + Paths.get("nameFile.html"), + resourceLocation = ResourceLocation.EMBED + ){ + div { + //first vision + vision { + solid { + //solids which you want to visualize + } + } + //second vision + vision { + solid { + //solids which you want to visualize + } + } + } + } +} +``` +## Solids properties +**We will analyze which basic properties solids have using `box` solid.** + +*Basic properties:* +1. `opacity` - It is set in `float`. It takes on values from 0 to 1, which represent percents of solid opacity. It's initial value is 1. +2. `color` - It can be specified as `Int`, `String`, or as three `Ubytes`, which represent color in `rgb`. Elementally, the solid will have `green` color. +3. `rotation` - it's the point, which set rotations along axes. Initially, the value is `Point3D(0, 0, 0)`. Changing `x` coordinate of the point, you make pivot around `x axis`. The same for other coordinates: changing `y` - pivot around `y axis`, changing `z` - pivot around `z axis`. +4. position, which is given by values `x`, `y`, `z`. Initial values are `x = 0`, `y = 0`, `z = 0`. The coordinate system is Cartesian. It's elemental position is this - vertical `y` axis and horizontal `Oxz` plane. + +Let's see how properties are set in solids. +The `small box` will have elemental values of properties. If you don't set properties, it will have the same `position`, `color`, `rotation`, and `opacity` values. + +***You can see that `box` take four values. Later, we will discuss what they do in more detail. Now, it does not really matter.*** +```kotlin +box(10, 10, 10, name = "small box"){ + x = 0 + y = 0 + z = 0 + opacity = 1 //100% opacity + color("red") //as string + rotation = Point3D(0, 0, 0) +} +``` +![](../docs/images/small-box.png) + +The `big box` will have properties with custom values. +```kotlin +box(40, 40, 40, name = "big box"){ + x = 20 + y = 10 + z = 60 + opacity = 0.5 //50% opacity + color(0u, 179u, 179u) //color in rgb + rotation = Point3D(60, 80, 0) +} +``` +![](../docs/images/big-rotated-box.png) +If we compare these boxes, we will see all differences. + +Here is the function `main` with both boxes. +```kotlin +fun main(){ + val context = Context{ + plugin(Solids) + } + + context.makeVisionFile ( + Paths.get("customFile.html"), + resourceLocation = ResourceLocation.EMBED + ){ + div { + vision { + solid { + box(10, 10, 10, name = "small box"){ + x = 0 + y = 0 + z = 0 + opacity = 1 //100% opacity + color("red") //as string + rotation = Point3D(0, 0, 0) + } + box(40, 40, 40, name = "big box"){ + x = 20 + y = 10 + z = 60 + opacity = 0.5 //50% opacity + color(0u, 179u, 179u) //rgb + rotation = Point3D(60, 80, 0) + } + } + } + } + } +} +``` +![](../docs/images/two-boxes-1.png) +![](../docs/images/two-boxes-2.png) + +***There is plenty of other properties, especially of those, which you can create by yourself. Here we mention just small part.*** + +## Basic Solids +Now, let's see which solids can be visualized: +### 1) PolyLine + +It's scarcely a solid, but it can be visualized, so we mention it. +`polyline` build lines, obviously. Let's take a look at it's work. + +`polyline` requires two values - `points`, and `name`: +* `points` is a `vararg` with `Point3D` type. It takes pairs of points, which you want to connect. +* `name` is an identifier of *any solid*, but in this case it is an identifier of `polyline`. +It's type is `String`. **This value can be required by any solid; +you can set it, you can not to set it, but without you won't be able to control solid, since it won't be inherited.** + +This is an example of polyline with other solid `box`: +```kotlin +box(100, 100, 100, name = "box"){ + x = -10 + y = -10 + z = -10 + opacity = 0.4 +} +polyline(Point3D(30, 20, 10), Point3D(30, -100, 30), Point3D(30, -100, 30), Point3D(50, -100, 30), name = "polyline"){ + color("red") +} +``` + +![](../docs/images/polyline-points.png) +![](../docs/images/polyline-points-2.png) + +### 2) Box + +First thing which has to be mentioned is that `box` takes four values: `box(x, y, z, name)` +* `x` - x-axis length of the `box` +* `y` - y-axis length of the `box` +* `z` - z-axis length of the `box` + +These values have `Float` type. + +*`x`, `y`, and `z` are necessary values, which cannot be ignored. You have to set them.* + +* `name` - `box`'es identifier. You've already met it. + +Let's create just usual `box` with equal ribs. + +```kotlin + box(50, 50, 50, name = "box") { + color("pink") + } +``` + ![](../docs/images/box.png) + +Now, let's make `box` with bigger `y` value. + ```kotlin + box(10, 25, 10, name = "high box") { + color("black") + } + ``` +As you can see, only rib of `y-axis` differs from other ribs. + + ![](../docs/images/high-box.png) + +For final trial, let's create `box` with bigger `x` value. + + ```kotlin + box(65, 40, 40, name = "wide box") { + x = 0 + y = 0 + z = 0 + color("black") + } + ``` +Predictably, only `x-axis` rib bigger than other ribs. + + ![](../docs/images/wide-box.png) + +### 3) Sphere + +It takes in two values: `radius`, and `name`. +We bring you to mind that `name` is a general value for all solids, so do not wonder, since all solids need their own identifier. + +As for `radius`, it has `Float` type, and, as you can guess, it sets radius of the sphere, which will be created. + ```kotlin + sphere(50, name = "sphere") { + x = 0 + y = 0 + z = 0 + opacity = 0.9 + color("blue") + } + ``` + ![](../docs/images/sphere.png) + +### 4) Hexagon + +It is solid which has six edges. It is set by eight values: `node1`,..., `node8`. They all have `Point3D` type, so they are just points, vertices. + +*Six edges are these:* +1) Edge with vertices `node1`, `node4`, `node3`, `node2` +2) Edge with vertices `node1`, `node2`, `node6`, `node5` +3) Edge with vertices `node2`, `node3`, `node7`, `node6` +4) Edge with vertices `node4`, `node8`, `node7`, `node3` +5) Edge with vertices `node1`, `node5`, `node8`, `node4` +6) Edge with vertices `node8`, `node5`, `node6`, `node7` + +![](../docs/images/scheme.png) + +As hexagon takes in specific points, we understand that this solid cannot be moved, it fixed in space, and it can't make pivots. + +Let's make classic parallelepiped. +```kotlin + hexagon( + Point3D(25, 30, 25), + Point3D(35, 30, 25), + Point3D(35, 30, 15), + Point3D(25, 30, 15), + Point3D(30, 18, 20), + Point3D(40, 18, 20), + Point3D(40, 18, 10), + Point3D(30, 18, 10), + name = "classic hexagon"){ + color("green") + } +``` + ![](../docs/images/classic-hexagon.png) + +Now, let's make a custom hexagon. + + ```kotlin + hexagon( + Point3D(5, 30, 5), + Point3D(24, 30, 8), + Point3D(20, 30, -10), + Point3D(5, 30, -7), + Point3D(8, 16, 0), + Point3D(12, 16, 0), + Point3D(10, 16, -5), + Point3D(6.5, 12, -3), + name = "custom_hexagon"){ + color("brown") + } + ``` + ![](../docs/images/custom-hexagon.png) +### 3) Cone +It takes in six values: `bottomRadius`, `height`, `upperRadius`, `startAngle`, `angle`, and `name`. + +Obviously, `bottomRadius` is responsible for radius of a bottom base, and `height` sets height of a cone along the `z-axis`. + +As it takes such values as `upperRadius`, `startAngle`, `angle`, `cone` can build not only usual cones, but also cone segments. Initially, `upperRadius` will have `0.0` value, `startAngle` - `0f`, `angle` - `PI2`, so if you don't set them, you'll get just a simple cone. + +Setting `upperRadius`, you make a frustum cone, since it sets a radius of the upper base of a cone. Set `startAngle`, and `angle` let to cut off segments by planes perpendicular to the base. `startAngle` - an angle, starting with which segment will be left, `angle` - an angle of cone, which will be set from `startAngle`. + +Let's build a classic cone: +```kotlin + cone(60, 80, name = "cone") { + color("beige") + } + ``` + ![](../docs/images/cone-1.png) + ![](../docs/images/cone-2.png) + +First of all, we have to try to build a frustum cone: +```kotlin +cone(60, 80, name = "cone") { + color(0u, 40u, 0u) +} +``` +![](../docs/images/frustum-cone.png) + +Now, we need to make a try to build a cone segment: + +```kotlin +cone(60, 80, angle = PI, name = "cone") { + color(0u, 0u, 200u) +} +``` +![](../docs/images/cone-segment-1.png) +![](../docs/images/cone-segment-2.png) + +Finally, the segment of frustum cone is left for a try: +```kotlin +cone(60, 100, 20, PI*3/4, angle = PI/3, name = "cone") { + color(190u, 0u, 0u) +} +``` +![](../docs/images/frustum-cone-segment.png) + +### 4) Cone Surface +This solid is set by seven values:`bottomOuterRadius`, `bottomInnerRadius`, `height`, `topOuterRadius`, `topInnerRadius`, `startAngle`, and `angle`. + +In addition to `height`, `startAngle`, and `angle`, which work as they work in `cone`, there are some new values. +`bottomOuterRadius`, and `bottomInnerRadius` set properties of the bottom circle, `topOuterRadius`, `topInnerRadius` - of the upper circle. They have no initial value, so that means they have to be set. + +Generally, `cone`, and `coneSurface` buildings work in the same way, it's possible to make `coneSurface`'s fragments as in `cone` + +Let's build usual cone surface with almost all properties set: +```kotlin + coneSurface(60, 50, 30, 10, 100, name = "cone surface") { + color("red") + rotation = Point3D(2, 50, -9) + } + ``` +![](../docs/images/cone-surface-1.png) +![](../docs/images/cone-surface-2.png) + +Now, let's create a cone surface and set all it's properties: + +```kotlin +coneSurface(30, 25, 10, 10, 8,0f, pi*3/4, name = "cone surface") { + color("fuchsia") + rotation = Point3D(2, 50, -9) +} +``` +![](../docs/images/cone-surface-fragment.png) +![](../docs/images/cone-surface-fragment-2.png) + +### 5) Cylinder + +This solid is set by `radius`, and `height`. As you can see by accepting values, there's no option of building fragments of cylinders. + +Here's a demonstration of a cylinder: + +```kotlin +cylinder(40, 100, "cylinder"){ + rotation = Point3D(40, 0, 0) + color("indigo") +} +``` +![](../docs/images/cylinder-1.png) +![](../docs/images/cylinder-2.png) +### 6) Tube + +`tube` takes in `radius`, `height`, `innerRadius`, `startAngle`, `angle`, and `name`. *All values are familiar from `cone`, and `coneSurface` solids.* + +Here is an example of classic tube: +```kotlin +tube(50, 40, 20, name = "usual tube"){ + opacity = 0.4 +} +``` +![](../docs/images/tube.png) + +This is an example of tube fragment: + +```kotlin +tube(50, 40, 20, 0f, PI, name = "fragmented tube"){ + color("white") +} +``` +![](../docs/images/tube-fragment.png) +### 7) Extruded + +`extruded` is set by two values: `shape`, and `layer`. +* `shape` is a value of `List` type. It' s just a list of all points of the solid. *`shape` has to consist of not less than two points!* +* `layer` is `MutableList` types variable. (here is a sentence with description of the work of this function). *The amount of `layer`-s has to be more than one* + From 639a192d59ce1b8bbdb263a380d8515e0aa76793 Mon Sep 17 00:00:00 2001 From: kiruma524 <71787194+kiruma524@users.noreply.github.com> Date: Wed, 4 Aug 2021 22:11:09 +0300 Subject: [PATCH 29/29] Small renamings --- .../kscience/visionforge/solid/Extruded.kt | 45 +++++++++++-------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Extruded.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Extruded.kt index d5943e3a..480da818 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Extruded.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Extruded.kt @@ -2,9 +2,8 @@ package space.kscience.visionforge.solid import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable -import space.kscience.visionforge.VisionBuilder -import space.kscience.visionforge.VisionContainerBuilder -import space.kscience.visionforge.set +import space.kscience.dataforge.meta.Config +import space.kscience.visionforge.* import kotlin.math.PI import kotlin.math.cos import kotlin.math.sin @@ -13,7 +12,7 @@ import kotlin.math.sin public typealias Shape2D = List @Serializable -public class Shape2DBuilder(private val points: MutableList = ArrayList()) { +public class Shape2DBuilder(private val points: ArrayList = ArrayList()) { public fun point(x: Number, y: Number) { 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 @SerialName("solid.extrude") public class Extruded( - public var shape: List = ArrayList(), - public var layers: MutableList = ArrayList() -) : SolidBase(), GeometrySolid { - - 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 - } + public val shape: List, + public val layers: List +) : SolidBase(), GeometrySolid, VisionPropertyContainer { override fun toGeometry(geometryBuilder: GeometryBuilder) { val shape: Shape2D = shape @@ -103,6 +92,24 @@ public class Extruded( } } +public class ExtrudeBuilder( + public var shape: List = emptyList(), + public var layers: MutableList = ArrayList(), + config: Config = Config() +) : SimpleVisionPropertyContainer(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 -public fun VisionContainerBuilder.extrude(name: String? = null, action: Extruded.() -> Unit = {}): Extruded = - Extruded().apply(action).also { set(name, it) } \ No newline at end of file +public fun VisionContainerBuilder.extruded( + name: String? = null, + action: ExtrudeBuilder.() -> Unit = {} +): Extruded = ExtrudeBuilder().apply(action).build().also { set(name, it) }