From a7841edb3c9d09e13bb26324d3e30395d6858aaf Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Wed, 30 Jun 2021 18:39:56 +0300 Subject: [PATCH 01/35] 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) { -- 2.34.1 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/35] 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) -- 2.34.1 From 199cad1dc162b087d4867806b8c62f6368f09f27 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sat, 10 Jul 2021 16:51:57 +0300 Subject: [PATCH 03/35] 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() -- 2.34.1 From c82c0ecea3b6f9fb17d7a86b9d4a39ee9952b7f7 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sat, 10 Jul 2021 17:37:56 +0300 Subject: [PATCH 04/35] 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 } } -- 2.34.1 From ba637413c770910060202e03a557d5a22ddccd2e Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 11 Jul 2021 09:58:01 +0300 Subject: [PATCH 05/35] 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() } -- 2.34.1 From 2b6942b827f055df13709aa280185b81dd675594 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 11 Jul 2021 12:07:04 +0300 Subject: [PATCH 06/35] 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 -- 2.34.1 From 7b30b62849c60c7a7aaec7508b9f74e23bbfaa4b Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 11 Jul 2021 13:43:56 +0300 Subject: [PATCH 07/35] 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) -- 2.34.1 From 42e2530f6fb3b8db94a8c55f50817a2d1a13a7ad Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 11 Jul 2021 15:16:04 +0300 Subject: [PATCH 08/35] 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 -- 2.34.1 From 073d374a9e84255b0997ed687add95847448210c Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Mon, 12 Jul 2021 10:01:21 +0300 Subject: [PATCH 09/35] 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 */ -- 2.34.1 From 5af8fe3e994b0b61b130535442a704bd5c043066 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Mon, 12 Jul 2021 13:23:25 +0300 Subject: [PATCH 10/35] 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() { -- 2.34.1 From 0d53b6f77dc2463120de8709e16663f7d99e8837 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Mon, 12 Jul 2021 15:22:02 +0300 Subject: [PATCH 11/35] 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() -- 2.34.1 From f2e7e16d624479fdb41545beb312ff31c6a7e3d2 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Mon, 12 Jul 2021 22:50:00 +0300 Subject: [PATCH 12/35] [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() } -- 2.34.1 From 8f95d6f48592018896bcb040823ed528915c8c9c Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Wed, 14 Jul 2021 15:45:01 +0300 Subject: [PATCH 13/35] 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() } -- 2.34.1 From 38c76e824d550bcadbd9ff1ab3feb04b28e50e23 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Wed, 14 Jul 2021 15:50:56 +0300 Subject: [PATCH 14/35] 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 -- 2.34.1 From e1138be8618fcb1bf52038c0915ff3b0085748cb Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Thu, 15 Jul 2021 12:28:25 +0300 Subject: [PATCH 15/35] 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() -- 2.34.1 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/35] 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 } -- 2.34.1 From 493c527743d34c38d8be3b8fc49ad6d0221f664d Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Thu, 15 Jul 2021 18:39:43 +0300 Subject: [PATCH 17/35] 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) } } -- 2.34.1 From c1627b450413893e10820925f3f084ca536e0cfd Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Thu, 15 Jul 2021 18:56:29 +0300 Subject: [PATCH 18/35] 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 -- 2.34.1 From a87692ae1f33fe08bffcd1a42d68dc82ff7ca10d Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Thu, 15 Jul 2021 19:45:43 +0300 Subject: [PATCH 19/35] 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 } -- 2.34.1 From 6435f717838bf54f413f393e5fde05fbadf70c69 Mon Sep 17 00:00:00 2001 From: kiruma524 <71787194+kiruma524@users.noreply.github.com> Date: Fri, 16 Jul 2021 14:08:53 +0300 Subject: [PATCH 20/35] Update README.md --- demo/gdml/README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/demo/gdml/README.md b/demo/gdml/README.md index 6ad546f1..5c2a5abe 100644 --- a/demo/gdml/README.md +++ b/demo/gdml/README.md @@ -1,12 +1,10 @@ - ### GDML Example Visualization example for geometry defined as GDML file. ##### Building project -To build the app, run `demo/gdml/Tasks/distribution/jsBrowserDistribution` Gradle task, then open -`demo/gdml/build/distribuions/gdml-js-0.1.3-dev/index.html` file in your browser, and +To build the app, run `demo/gdml/Tasks/kotlin browser/jsBrowserDistribution` Gradle task, then drag-and-drop GDML file to the window to see visualization. For an example file, you can use `demo/gdml/src/jsMain/resources/cubes.gdml`. -- 2.34.1 From bdb28eb338f8b4cfcd300b558c70456aa4afc118 Mon Sep 17 00:00:00 2001 From: kiruma524 <71787194+kiruma524@users.noreply.github.com> Date: Fri, 16 Jul 2021 14:10:09 +0300 Subject: [PATCH 21/35] Update README.md --- demo/muon-monitor/README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/demo/muon-monitor/README.md b/demo/muon-monitor/README.md index 87b3cf43..df95c968 100644 --- a/demo/muon-monitor/README.md +++ b/demo/muon-monitor/README.md @@ -26,9 +26,8 @@ with it. ##### Building project To run full-stack Muon Monitor Visualization application (both JVM server and Web browser front-end), -run `demo/muon-monitor/application/run` task. +run `demo/muon-monitor/Tasks/application/run` task. ##### Example view: ![](../../docs/images/muon-monitor.png) - -- 2.34.1 From 87260cea86b3732d0820a0956d1657b92005894b Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Fri, 16 Jul 2021 20:52:01 +0300 Subject: [PATCH 22/35] 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 -- 2.34.1 From 01ea6b5494daca7c82ee8fa291c888bfd90cf579 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sat, 17 Jul 2021 10:27:51 +0300 Subject: [PATCH 23/35] 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 { -- 2.34.1 From e50e266f9496f39daad51840bc0abe44eb58b0e8 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sat, 17 Jul 2021 10:55:02 +0300 Subject: [PATCH 24/35] 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")) } -- 2.34.1 From eb3786c5ca8ff2f9b084a8564a10e8037572e3f9 Mon Sep 17 00:00:00 2001 From: kiruma524 <71787194+kiruma524@users.noreply.github.com> Date: Wed, 28 Jul 2021 14:49:13 +0300 Subject: [PATCH 25/35] Add files via upload --- docs/images/all-solids.png | Bin 0 -> 8107 bytes docs/images/big rotated box.png | Bin 0 -> 2206 bytes docs/images/box.png | Bin 0 -> 1326 bytes docs/images/classic-hexagon.png | Bin 0 -> 2441 bytes docs/images/cone-1.png | Bin 0 -> 2768 bytes docs/images/cone-2.png | Bin 0 -> 2508 bytes docs/images/cone-surface-1.png | Bin 0 -> 9500 bytes docs/images/cone-surface-2.png | Bin 0 -> 4938 bytes docs/images/custom-hexagon.png | Bin 0 -> 2190 bytes docs/images/high-box.png | Bin 0 -> 1756 bytes docs/images/small box.png | Bin 0 -> 1503 bytes docs/images/sphere.png | Bin 0 -> 2446 bytes docs/images/two-boxes-1.png | Bin 0 -> 2353 bytes docs/images/two-boxes-2.png | Bin 0 -> 3021 bytes docs/images/wide-box.png | Bin 0 -> 1584 bytes 15 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/images/all-solids.png create mode 100644 docs/images/big rotated box.png create mode 100644 docs/images/box.png create mode 100644 docs/images/classic-hexagon.png create mode 100644 docs/images/cone-1.png create mode 100644 docs/images/cone-2.png create mode 100644 docs/images/cone-surface-1.png create mode 100644 docs/images/cone-surface-2.png create mode 100644 docs/images/custom-hexagon.png create mode 100644 docs/images/high-box.png create mode 100644 docs/images/small box.png create mode 100644 docs/images/sphere.png create mode 100644 docs/images/two-boxes-1.png create mode 100644 docs/images/two-boxes-2.png create mode 100644 docs/images/wide-box.png diff --git a/docs/images/all-solids.png b/docs/images/all-solids.png new file mode 100644 index 0000000000000000000000000000000000000000..9be7b40e27239d75efd5723cc819ad94fca8d636 GIT binary patch literal 8107 zcmeHMS6EYBvkr&~A|M^E1tPtdP*3pt&+}iLt8;Pg&c%NAvu3S#X3smb*P6X2`k9Uf)eY7g004kW6Rf5W z0FX)m03=%Eq(n&^X6N!o;-#zEnDJNNCPj!;{B&mLg

5EP-~cCAB_64ZGIsfF6J4xv5Mb9SG8p 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 literal 0 HcmV?d00001 diff --git a/docs/images/big rotated box.png b/docs/images/big rotated box.png new file mode 100644 index 0000000000000000000000000000000000000000..7b7cdc14dad92f2d151a2fbf735e3af14b4f54e4 GIT binary patch literal 2206 zcmeAS@N?(olHy`uVBq!ia0y~yV4MKL985qF{<{lj11ZMhAa^H*b?0PW0y!+{j=qiz z3>*8o|0J>k`J4qFk;M!Qe1}1p@p%4<6b1$kV^0^ykczmschBYqM@lq2Oqr%5Xu82I zq`^fr#6Wbz0w(=sOj--LRJ1xGE;D6J+dOafL!l4;Z;m`}`7LMPud~CPF;Q%f)$`9A zcgDol?q$&Uk^E0G;Uf$82>~4i=M4=!2bqjUIiq1fK|0t0OjvXE6(8L_o&NbM|LWEG zpGBR8b*80SyNT!TJ0ott=ile~KVR9)-?xw4TWfXSz~tbgiElJ6J_+b~m&A4LX!~=q z$mb3lEE<)kxvH1QuE`9~m{`ij(p@W;7g^%eRBFf4J%8QjEpm(RM=#nvBkSv5&$^ng zht?HT^qFo*`*r;P>*Rl0I?V|i)1sE23Ac=v4n3wE!IKol|8Cw6Ljh3g?k;`VJ2m#< z3m`*&-g$9WbA7=gHJ0u|iDX{?4HDh44==EEo36L7<(r?AP||dC+9#!>>k4w3SW`H} zqLuVT?)?&4Xn1W0OZUYaqI^D}9Fycy*4iwjV`h2tKoX}Iv(YiBsRRzhto(O5zhe2!uW*XJu35#ytrjsy*!|vPU<4ogQSe>5thKbs z_0ryB5y8dza-XMX6s>9Wz3skH?m4g3_tN4W4-?wzYX4o6-b!FZXM#Ot{J^Hrr2njqtkuZFjdvUY@*B-bYx+ zY;X0?H`hDfa9%qo;rq|OpHFB_v2sMtEskqXwi(!F^t^i%cW{%uOhYp7os(CVy*>VC z@BQ>uSEnre*=DQ|F^BiP)hnPGYuD|I+_u4|>1gB*xdh4W-#NwD-&9U5;OyCWt}9_< zcOiebO2iy?PPwK8M#(1Edj}1tb^bPB>6V?7lQ5H|+c=@Ylnb051>Z;}OD6QXY}nD7 zD*}pbze-3n8+Oc1)?r?AkV9;@W!F(APBCZW15(`}(~iE)Iz749a2n&a3UFzCEVaQ@ z=3tVBond88)6un;)TMbgv_Vpu2J;$0PO-&?$E0Q?Y@A-o<*gLabMi>7$Mn^!*MC;c zsr>%w=9kAz|DQiU>wEu~SHM~~)rdErcQs%txZJ>+-Opd^0I?5UNFgSAb=zitK XkKfnK-t`&SreN@N^>bP0l+XkK2=+1# literal 0 HcmV?d00001 diff --git a/docs/images/box.png b/docs/images/box.png new file mode 100644 index 0000000000000000000000000000000000000000..6824b2d3584dfcf81d66b99a22136f3fcbc5f5e0 GIT binary patch literal 1326 zcmeAS@N?(olHy`uVBq!ia0y~yVAKR+Mh+&R$ZD1&eL#w_ILO_JVcj{Imp~3nx}&cn z1H;CC?mvmFKt5-IM`SSr1K(i~W;~w1A_b`Cu&0Y-NJZS+TaI1Q**vWm@6~Rb`m;Gl zrQ3tYw(`W&&ezlPQuyW+nm7Fp41KU(et#YF=Pm4#x0-q0I<|dNaIT)P(DuXyxs(ik zqv0cbZ_E1i_VsoD%I`mZ@1qr7F#p>!+p-v~sD&{HYj4dCGu!LBv+4I1^R+ou-9@b5 zGxM)p5MV!qs`a&8fyd1k)f z%uiNNW%4fFoA6eD4!_;cb3oRn$Guz1r+sUiBC8+T_lWPU?~exYbNNs8-d(uI^7f-o zweYE?@1IVVPxyAL_Kfp;$7=S>^>e@NShBY)b>Ho&uPbJMtE#=^{65-p!uHJd*B9@# zKK1TD>r;n&%l5{Z|NdFu{=ctC`TfPX^~Zy}{cdNz7kT^jlHB@?_1B+o4d;83d+YU5 z+qjEy`fopW0nLf1w)@6+DNg@9LM*dCe9Lw3>OG70#@%`>`gW`K?Yrw@j^EyLeO*rZ z?jqUz%W=Cm-FVYCp&Ng8URa^L^GWYY(6)HQ|@Cmg|1iF_)kcTaK%~-Fg`& zc&}yCgT1F>?=0NQnR>8#>h2xR;2_p2FKqv&Hih+l=sQp(XmH29I-P&2@6x>%qen|Y z5u`RnP=D#(&0EYD_Ec!Tox2pM{fKwwdmW%!FY?yx z4-vUHKe~a1wj4Kp>w7`&{1$V^YMaZ@n6+EHw@3t-EDo`6dA_iG&NsD+cc2JIQ=8Pk qM1AW2bH2knnXuIbq#@K9D}E;pUXO@geCy=go(BQ literal 0 HcmV?d00001 diff --git a/docs/images/classic-hexagon.png b/docs/images/classic-hexagon.png new file mode 100644 index 0000000000000000000000000000000000000000..f0053ae405957afb0c4b4ee6f356b34cdad147e8 GIT binary patch literal 2441 zcmeHJ`(G2+5)Y+R(I_gB3k4F{-XJRfdXTEdh%*>h3 znVAA%Ab-<_w>Qvev`v1#KEX7aiI$?6^>0uJZ(Kh?EheeK{6n<5e!Jf&=FJn{0p2uP zy?oC;lC;5h@(rBAI*T|$h@hb_1G5vhJkDQ8nq74Yw`da6T9=bmB|186+_u_cH z;u-S?gT-5PtEM9#{_py}6X!S%7R)>CMxU}{QP~Gfw)}EyF@)AsL(sSkn;p4;={2F` z3gUQ*Djm9K`*x6P!n!)b|dbDgy^gfTjN;${^-d(rfdS3>BoJW98|{{#I9fiMQs)Np8xOaK2HJ z^X4&;&z?`&D21MLA*W)EPzlWE zXc3D4g1h!zCoJGrGZ??hkcD_opReOW?^0*Z0rN#TeKlBT|1-Ns3f0yS%3p`EXnSOW z(_A=5N*sj}6vCp-kO^nFbsvoXz>qzlwA(?b_BdNiSt!Bj_9DrgHHXsHgN9c!^}6qb zI)|3Xp*XfUf30fhM8%pkT%)WYOp}FqNvI%B3XKIQx~J1kGz^;_9u~$|T!>{K-ia_3 z{L|ZUO>G5nJBHmE#E=Q4DToyMfD3KHHM>4gbnCYsqxeG5Ffit_0|f>t<8GkgAt@oK zgl&z3ZQ84e1oeF6-G8CvSuNr$h2%m>Q!Kml1WMv~L?KR&Gw=-N@AsM*Hgho6DhCz| zaJp@<3HYlj9@vHTQulf*j5z=FKptSJ5lDSeGLn>hbWq_J$A+26Oce8X z?~^ELI_9zg#*6}mM#_e_Au~K_O0*PWfsn<=_LMKtAe7K2m?;7pb8xyV2$haxDElOr z7DSlGJ0t5fHU-XHUe@Di>EG}dw5WT3lMTcbxsDSt6 z{|z`9NTvKcd0bZnDPR@@;;6!R@^F&Lg}$}!?Zq|K!4k)BJXC#>biU&2y6Mn~WM!Yu zfeSg`k;mP5!R&UMTe!q4p1m?WIeTS59sM#u+f;G51I_B(WPhOk_NmZ4&`q1($xLlm ziYH`?_m#|FLuO8Pz{V$-Up@{(woa+)hxJ6a)kYqR3u&ETl?U2jm3kh)s_usN%NwlV zUd$`lZeN=3TwwVh_Sv_8JE4q~ju7gwH1+xtO*$__EIH)t8RN4(tWb6tz&@S|4a{$_ zYRm_)r&BJ8p}N?7PB;mn0v6LF=C-^+Brrz>ZcN+WzN*?TWi|2X%tZZI1raWYM+MnW z?R%e7@K7c3Y;M+N7;LZ-W58fD>youuH3iRRiw2ty0~VuRx(3y+OXaTs_nJMncxj7F z9qNfqI=-jgT}?dhS>j*hSD#L(-!fQs!>q00MSk*1<7P%e*Zb1)x^9CU9(7@#DI)iK z?NU97i5Vdtk1bnv+*(5~0&vcwN%cSsz=f*!@{PWQnrl=i^&B<*r=$LDV+B1Z=(Xuj X;;z)pKD+-=;}gvf3G}Hubo|_(N0#&X literal 0 HcmV?d00001 diff --git a/docs/images/cone-1.png b/docs/images/cone-1.png new file mode 100644 index 0000000000000000000000000000000000000000..47272f2426381cb736f7d13fbafdf14cbb909c25 GIT binary patch literal 2768 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 Si|`*9;iS8dTb1kIQ~nEkMU{F0 literal 0 HcmV?d00001 diff --git a/docs/images/cone-surface-1.png b/docs/images/cone-surface-1.png new file mode 100644 index 0000000000000000000000000000000000000000..dad20dda54bc82b5068da45f40c92764bf1beb1e GIT binary patch literal 9500 zcmeHN`#;oq+t=ADN-C3MOS`sNVbm@Wvuzm_smYYA!#J$0E!ji|r>Rw|nAi@eyU;da zN)d_LLgg?UZ8pB9=R38}{SQ1pJ@@N165s1{eXjHMzOJuB>pWbw zwG6a0G&HnVtz5BQLt|VGzIJPl$8TJ|GGXD{xEtnfJWszAWUqKp`Ajv|s8ZUQnOW6`80a#VS&0uG{3P-uYlZu- z4U5f!e)i4N)zy1td-&jqd6{7=Y9?NHH#htIkN=YXzqPa2IS6m9@OlI`vcJY!9I(FC|E@<`}?A-3_G-`X0y`Xo4s(`h0t(DmRP{Ha< zuhHE)0^6V2-ai(}i)Jv``1P5>b4)w&ctPYW^5AK0SJihlF4x_IxqizOA<~sjqj*q~ zf(NDgT~!e^pImou|7~Zx(T2uKqxFrIZ-O{wjE3>?6Li}nPyVt!Us`@IO!lVXQ-1x| ztdI$UriY$wt7-~;^ZKXQt>oq3!wG&cr`~LAr0TIh%Z9#wZM>Uq8lt>tOKD-+;P$gI zgCXlw-95c$2Aj2{+m}1Za$QzhiMfXz&sKf)ufgW}S+X}NrB60ypQ|XdJ)14pF<*_R z$!@<@eQpv~bjjDNu{W{`JPw6f%bm?5PbwXHS@xifWXFbgta*6FT3e7N-_~x|5F$_M zva-*|6OPm9K(^$36VH-g**TnrGg@Q+j-CWoL^g#agA{Ad3{C2%cQ%e!%06>{jE2vGM-i^GTH>7Q-(Uj1bfuCFLR z%k&+iU3ce=R|Hv0nDG_iK^&d)q1?-sZv12$a9s@z=Zb`j`Qwe7q^VW6v7;J2;v}Dll2sH&}kWlR3 zJUUChrOve>=e=it@I&kO3HoFe&{Po0Eo0EN1Gi1s&}0}HuM{6{ks_-kCY^P$G6o97xQ(#xmo3#m$QudwdEZx zUcw|+$RYMeGATK=ks%ijXo{=sWPi;)XqU%ysc>j9>5x6># zV*=+GWbNM_ILq?|@f{%!`RmVT3*W?2lX?FEH2bTael9)1GuL z=dqg&-IcgQN=yHRNTW@;MNm>BG^*_is4;}eA4>%>vsoPziH&{%D>b1L5r5Bq_LAfW zPY>=wX2f@QN*B=5iDzLY16J+_qro$2NV_x}@Yb6d@mXf~sh638wkFpPzSD+t=?Bzz z0TO8Gt|tzsfv;0m#%{fl>YL_@ z-OiH)CCO@D>xnFs_PVT)*@E%ppC<9XL%V*hs&9GF`1$}X-H*8Pqp%0ms!_yE5ZI#Y z@0x~=wFCacC%f$4FQBP|4HnlDfHg6M+NPheI=(Q@-hFAzsa2CXL-Cz|3e56!_*ydI zcL$*bLr^-xVzY^Ku-JlRue%{~meg_2LRQC&e++v^xRqsW#s?N2~8bX1YGt7unSPoj=*`ti3 zh(5@3fIW^VLAm`iR*0c^&@4-MjjNnoR6gwY=3S>n0LOzwI(5Y)zSajts2I|gyV1ecTQDvr%Z1`vKsy~T-##8d3h2>{uUrGv@_PAKPv|=x5=4)NTuJti zXF<~w&&fA70=a?l)5ulT$9ssx&?%Ck&0S zw`?)>no1moMDn4aLz6UT*wpyW2`g^@)VQqv&Q1F#Fue#g7@#V}Eu)1=&V_S`ggCO? zX_TZ$Qed=BaA91P^Q+?Eju0$Gzl*OO|QeY z!f?uWu4BKtT$2_pWYBM*kh|i`WJjs{*tPFq(O}NkHn4rVILaXSY~1x-;uo!Dn&Jcw z%19z1ro!f_l|rOcbcr5~Clz$58nWz1T0hvw_l`W-nk=|j{oH5&v8swMY3a+UkPhVB znwIdUO;*g~CipHSrLF!#%wWeC#B|yY#~5yvPkm&ezsD-7bGZB1OD<%`d)EqQyNJ_#zxF9p%VP_Qox+%uQ9ydm?h}yJ0$& zBruA^r@dF>$KH>OBL=OW`vex4Zm}s;?!=(yqxZQXqI;WoHwP-mHWAe<@w@isEnkLs zBjfT2y<^4n&`nbaJxowQ0_)b+E`W;g%(ozQue=NFm53qo^FwMEJGEH_Xs%pDuidX z1tjE_Kw4HV@ZsJE-iLRT+^mdE8o9AIAG*l-g0>rWhRYBjB}92H!Xvvbj<2|T@d zC}z+l^sD=Khj!~3x5WagO=i$7U`9jQ?1!Eq?>g9R3EYIOBo+_{hY+Wdr>)Vx?fZT6 z?9O|}CMv~GTDJ4+&H1Z~D#```&DWpk-BlsIp*TC#A%eFqq7)SR?9U$?m7UcybVW3* za;#k2=Ay?|qx6V( zpGW)WZ-LAdoPPR6Zv}6Gy!nALO;Q}^t=Kdv{s;ox2-vSOm|%-#^46EaxJ0`b*CcQJ zVa1cFq^7@tFIGC4rYm#1rgAT+w)8S(oy@@@?hmG3ZcrieI6&(u0#$%-A}n?8hQv%s zJ+Je23AE1-;$;6;QPxzDzgl%i($YHE$CLJ$zG>?b5DdEHoJuO&X(TX19N5QuZC_bg z>G;#S=pU!U%FhzX)nq_fOq!K`S4-<7m8d5~7VL?DUN=1WVmyMg%#|T84Dz)SJO0Fq z{&5%4ew#?R6)@7{hoVc1?+y5IWoP7}67F8-40yJX*q#I1<3cMIm&0#>tj15ZA*nvB zUdFgu0aT9D>l&3fc}>1cVtSr;nK+(}8<)`1!*TNKcsGVs+jC?4T!#|4WzTPe-}UjF zPhZs(DQ{!o`R>6`97kb}X(43Qi6$i*5-?)|xyhpOrXJ`+T2yv*}|f(16_67T7*9do#xLYK(a@ z6!-0Dehh|-XFupFUo=j^%pgw=T32~3zdbJUo6&Z;Y;ZCH5w4jap!~#p=r-L?Va9p3PwP8ep{-^RW;bi%hKed)>$g+Ynnb| zBhj?>PvVyq^2F@)tHw5l{EjGIm08)}>4p9bhG+-8hr4FCAiIBK z3U22Nxg`-=_<@-4~zp%Y)OP%(G^~rw^@~JFxlunVFz&o?}^;WEq z=jW%YGh?_>Papc!)qOds0Dr$crI<6ZON#`PE*WM96J3~?=G`8qb&Y1_Q4rOo= z@?!A&ly|i`Nzfvxt0hHyq~z_b;)ipygxT?Xj>eP?#q7C&c$j%bUhJ=Y%`5%8sx*!6 zghbwU8>nA6t!Y*2KSzKB_Lyug-x|yz-=N4ZDi00fz}E(> zko_K!TmQ(6*7L|q?Vb&d-ot+furv@#A*dm$w=}mR;^xCxRWTl-Ndz_Cpk=+< zJwLO1js0(U z;e>9w2i+F%+E$3I0Cpbtx`*UKg5u3dLNwM0Nn!lj#^G*1b_u7t_$H{8OAQG=-D3iv zlW1yMQT}t~V&w96qSQEky(Kc8kXN2R^^;{Z%N4xr0tgyyT!$8R;x_5pAKK8T$e}oO z<$%BiQAgX4#Ch7i*d*a^LmF-a{j?ygX9z$vx#G8zdErcU{1G@{3Aw8ML|HrPAF)B( z!!`C94g%6uhXOb{WTis}!XeaZ>Y>0{mHVWdu(*zl!g{$%FP4yu$Im#$fDo#?PpMc^{{-H)T0)2ic>TS|q_27e1iGV8tBGI5Hqn~*e9HZzrxW3;^ z#S;O96F1A^)x!fpG?@T!?`^_SdJ}0IEtX^q7(c&ozk}Eptv?*Y1guRb^AW~r5yc;p zSlG~8FjqL-Ek54Ywe7UKvDhMz^LY>l%d}3i3c<`!bMfOWb3_`t)EqvN!-Wpgfu^NE6kh+V}HyddNa?5v3kkuzi@kXCt1TP+0|u zCma785=#wEuQh&*)kil>D5j;8EMFdbX^3fR62RF=I{a(&V|1Gv1Uu_M7Tb7jkNo>R zZ1n~C3<7zVZio#BY$xq`W?nAGg(j$WK znyVvBeKU{MF_%VC4wG_2MD^CVXSG7?5o7+72Gdu^DvC%KMAo-4qXMx|3$uK?42-`s zLpk|7F(S?9*UtvX2hnuo3XBMViTt7&KSuz|SD$8QHIu2~y$xNTK~J)|DjV>GEivCw zbmLjB6gQfPGsTOR-WkY257P;h7MBi8fb|R^Bi3!3y`#1TVtc5GfK*wz!rtE6W2pg~8-f46@b{)cgt9fvI4w=(0m`F`X;! zd9>$}*vDcRcO!B>;n$yWxi2N5WELRCeUvzd-;a<5C6Y3csy);` z94!a91fJg6eZ0bVu+82D5R9MK81H3JKwd`20vdY8jX*twfZ zR{@DKwWFz5BE)1-I>BC*CDSi2?Lx^54d4`h3_I8vEr*H<+f*cmX0Vr)csf=ZSTm^U zJOYT}AU^H{-3)aCQFM)ed5qAhQj$VTS6@r1Lc;Mju9dimtXZ#oMrplgrV0k8p*~Yt zVNbX~G|<4Bb&QMm{rP{C4>BajL4|7aA5`E3qku{$FlsPpg_U@1$x*ipdt*i zsdd23r#<|p)$0!h+V@7kY-v#EHIg9dV{}s{vpx9WNXjzo`=^Cgc*LnD>^5O_IIw`S zNf1Ii$X-KkWOd!Fy%x7CCuvcU=`AD_Y6Q~cA6~c)N*sQ$DrI@($%OfeY1#YP*Hf_; z!t(SZ2P*%x`KjJUSax}m<==@E_Q{_qqWvfvxRUj1V+5oHLErZjAkVm%CF*A zxDD}#xcbNiw`oNsyiATe#ni6SRRkbi^cV#5Sx^RtLNJoQRT`>5VvDZRHM2&(kGsCHF4 z%!P`-^MXnHx=#=xIgigqhJ!}`e5h)k5Fo$%XRXjzM3U+>!C2&D$&iahi&Q+LKS}(kAF7|v zV)0&*E%&giV%n(bD_93T6U7^C6CXC9v|@X^30~w*ty-?IogPS9Wg!(dxZfi{%I1l$ zt-MqE*)zYY2jb!z=R0wgZHnrq%l zjsA6`>8Vs3whH=S9FKrair$wABZf5@^4n!?z2+1$hGZz#lyJ%)`)A_avnkU{vG)KQ z(452&atvW~E?XX4TYy)^pUQ58Gur|Gkr3)8gPag%%MEL{;N|xOiQTh=rVwwK6xYI} z5Njtxext?_e>;)XAN-d0cW*q35(0QJDNWcp%Q_F*9cfs6U&xJC-0azz`iG3tSaw^U4c*Ekt3*6Yz{zgR;vhrt>qyo}KfX8=bh7ibDADepr$G_m}N3)s08b z`#ZI~|0yuYz=lJO=?#nh1%8%16Ju5g`l%TPq}WI0y3B8^#Jd^WGJX$H`Yvi~v!K!w zuvyyXlyDSp@U5B;zmFbrM=aw7OLKv8OWj&&E5uzp=48N5w}-) zl&-v)1apO1yQsE^ijFocc3yv@N`B)_W3aX$vf1pF&S4&8%vrw6sM$wlm2!ExDvfm< y7ai+1@y%7OtU-nR@1MN}wVmm+EruTq~VntWS;Y0ssK6_P>Fy^GTT-0KhYA zVxVss>bRbh+_2QhY3ONjdk9@=D*L`N2bL?w6UqfnxdK5S#ca%&nqJYrxR{Z+eR<;W z>^M!gl@4I`CvB@00MH&_0d(m}04`rh1;lbF(*th&zcQc&x8Ba4l~?Z2ss1_L2ghKg zv_yF0&!dhVHCwk%r_L!fHO?#8uXBN@Vmztn0>SqzGb%b>^ zrg@vq>xZ)$tf^9LJWCRUD*|A4ke|Bn?4K!J3U1f1lIx{VH5A7O$rT3k={ZMxSV=^ctn`BPPKU-j(5K4 zOXZayU~*F&?4+$V=Gf-p<92+RX-*KUlBG^9vFu*$pc|pTIuhnVmP91&KZEgAMH;^< zB)_icDMG+fRMnfN^+Jl8-)PVD=%v-Pcgd?PdZ5zh?-T%I2KiZZk5F6n6PX)#JJbrU z?i1}^HT%ouy{#80O%foE!5}kqAf-b(ag+ZR5ZP8$sC^|KlS0~p0dHE#M0cTBn_gu7lBfDX|Po|hV4);8#Oj}eti!yfIc<1CiU=2Ig%sz z!~Tg}nctCQ`&H~qN*#=WuoW3b-IO6O=t-y+7CWK3lS277+l^HbTJ*mV_N`J+m39O5 zb#OOh={wZ@u6P&lanq+>GF&DS0(UAa&D68pgvrGTx$BNcPT20U%Y!%2C1&ei1YZfm zsVoC%E=|%XZX1PiZ-ZPthKOCr!vDfXcX@J7;A*azuI!+>9+A3`S!s%Q^dY`|M&}W! z<;5EQ1O0{F<3sj_8SP_vY~x&Chw?1qgI*nA5*ivoC&V=2w$|eo%4}4yd7Jvw{x6}j znm>ypsE*&mec7~u|CR||QLZl*n+3^`tLIP);qr1PbypK@sN;HS7&{*YZxX-CRkuN` zY;r?T=F;*U7wMoS>Id5yw8tCH+ONIPJNlrna;>s6*sWU;+xIF;wPbn;cE?X+1Ssv& zsqKgbMDwRfJp7(94f5D&1Sw?S*VIkKR}?aAn_2tycD7p}9k_x>P9m0Y(xQg=nY_~L z(Xz5vs{Jm8-ls&o$8E`CpwkFwgfCN1v{pJ8v*0d0^={seZJnuG@A=E#Vd4y?s|+#d z(yiNB;x!GNFZv(S+!h75)Ii$X%t7sHQw_r^f#4O+-$+=h^ehWfB4p zn3Wxa-A-l2mWMX}2!~qN9zZ{8n31|%@QiLtY01OSI)=8|{P(NTE*^mjG@pW0NjizP_ z|Jmu7d%3!c7zCI~8?I&FR3R54j85Xf4PPFFOXd4BuPaD-s+kjEMpMaL$TO2%RpZP{ zSMJuTs*pGS;_i-9gtU2~`ve~wLigtx+rGtYy@8#+%Q@5HC5Ry3wyC`ij%YEao?D9u3DU zJl`8$evC?|v*ijh=+GZE$hf|IGvBA<13vnDdH}Sdi|WV}-m9seQ5v*fBPk%)Q6KfQdr-RNKTp zEGDz&##6{A+|Vp*yh7gFX;id-%0n5C2CVhJxUHs*1697pAZrFrD%daNC+dNcChWP< zwsN{|=Xy76#&wpPR5%u7GfZscv;vo0vx_bfNE4(Ig)qZKZ~9-OG}mW452ZJ!t=u=ix$8vUp(3 zFP|41@`HJ69qNNL)Ch2GCAv+E`M!-OA?E@SS2(%Z|NeY3{2+AQHCmGU117h@F78$lG}vp@YPrrGmZxRX8rVU@2NBN_}0i zp&=6km%i>EvXzJ*?yN-wzbgt#1!`QvPkE{NtlyK989-}m%zu2aM*lWS7gE z!+IHVy!OkRrw4--nuR>xPJTsCPl6?RTf8Y>KN)rQ6=6K~N5r}MYGHWwRoSI@a$!YI99-Lnys$v8}L9=W_YQpTPT z_{;X_fz3(L7f856cp!PlodV06Y^Ee38#8R~oCTB~{`6nWC^fY1LuaXwTz)mp#mn3a)nR)WiIWtmm<+mME+=qXP4(wn7L z?-OS0`~_aQl19M`-9}yNM298kX~CGn0*v}aem>l5S6}?{7NY(riPH-k?Qv3DyUx)u zyKn9lF&fS16zqMB8^o%kkVRy|wdhSf35>h7l#ivSqDFyHF=u+8e`L5?SJGU@`4G#m zCz+F#W%+GYUxF^$@oH3T`jH?uu14pg0M#U%+W zEVEb7B#M=&_#8PigdLI4;$4c>4m27X)T&0Nk>d6~%Q1VJS4Y-r-StTV;et`hn^ zCHQTU#;4r*OC~Zz@4!dWs0Hs&t`4Z1DtGjD=2Yj;}n$JtF|dB=9Eki@?$OQ}n|#9F>O@IhOiO_kW;!r`HzsGrcXAfLVO zLLs=&9!GSosL z3HsNp5W|(tr1)v=n3AsVTUYvP%YOtXpmT|58cAc0pjY>j1-1;QD%n)x!?0sF^(A~s zK*o4O;!hzfjNR?lrqj`l0iIG)CC5IZe#1&j75P}o@!q-5*L^g!?zza$-KWtZ(irA|) zmAMeL51+kd0{J0TKZUgHwrpUAh=C<dc|`E)m&0h+^ziRr!Gb%XTT31hu9mO03a%WiJh&y{gA#e$kbCBgKh>b zMH1gah}#$o`qWU4FnvEO3sl1fMrPDhS~Be5k<18tz6nEWC=Zg6+{3l>_#wE?ps=p8 z@|YdYsyrWN$w-c;r)o^P=_0v*fFt6kmV~DB6?wf#64bc1ntk^bd~~`&;pBV5=7G_3 znAWA&ti(=TJI^htFpK=myYQ{o+HpnX*fd4S0kkJCdy=ar&xZ)Ab}~I)>TVrVe=- zyOxT>w~iFZQ@)!oqg)}+U@ce)M{W7ZQ^t7&4}@CS zt$(j~Gwn5PP)k~;qYH_~TrXbS?ss}T0cHSEqxZsh->*=2z+YHReWXo-z!f4D;N2>k zWCwhE7D*lN)$&*PusWKLatx_SHe4?l?4b8Fa(S;7l|Z@Y%#+O&XZ zV|mUJ^gXk)x`R^)Z8wONQH$ISP318G!k5{F+&49U2q@1N3z@SCha0V8o(Aq&-`fJ> z7(jGux)zZ)nzI9q+|yC6F8jwlG+Vr{z6&bPV?0>~JUaYI+Kb`j&hF|ny+xAGlNC&N zS?TJ2P9~2R!-&JysvlU}0+iY3;*}UMHpv2_i>k<`w;sp<2+8TU1km)*V}k#S$6XvS zNQ|F;BFF2+(EHq?szgrw23(Ys2bKrX6^oSeS+zydn?p~UX7Mz=orT^akR*nD_pz|6 z**zpqeFsUaF?eC;GibceqmDqdVnNa4AYO_zjICM#mcB-x0KE-OrgCTdW6RY7V1y z_H*qb+y#asaSEN|ufa}ABkhliaNLZku{R4!Y+nQpZ-mH54zQ@F-OO-Ze0Q{wBColG zoEU95UZM&9c>;mdO5SWeKfo)~)#$}YuXC3Wphd0iI6M}o&vaV)LzYMgReQh8Eiq2jowwK8M<&JH?#bg8lT1DY*FGHXp19~q;FP8PH|@dr?3VYW0{t!`{5 z@AEK^Wmf)Y7)SK?k=dD{iO&S}=Xjo`zt|iHfnf;3=<{}{gIz5<4;nZDKj zhzmgdqaj~fzsF|s4nOR1a_;HnAMW&&%wPY<&Wzb~*?EBF;IhLtu5WuuUlN<|LytP` z-t-WeA}@w>4(6a~SFj6a^d0*Fzxv80=8A>h$;&Gkbw9&W6PrCnw5!qA2UucTFCF^$ zRny!K2yvHf|`T9Owab`SXp(`PHg$sa;@e(kNR4 z<0?z6JL#HW$KGlIZcRQ+b6epyt(BaztL<4saei;gwBA`TKZ5}%DVFW89GcfBbZUSv z`x`o}Rxi_NA3S7F)vw85V*dL_bM}!5;6|(a4-KwIBL)b0G5o(XT>sYe`->IathFF3pGV5&12O(f=DgNklYdlbyWzJ+AMb?wNtjj z%(TF_q)Y=_6Sk$q6lK(2@hI6M(7YHAG(m9R_CMI!Uz>TJdFJ^X- zUAlHD3G3CTv^(32GK5?g`rigH;zTn~VPj z>X*=iqSIk8xa><>$!UTF7;Ld~u>T%BBW|?QN_e(z&AIkyCAAj$Df75<&98;X5TVJ2 zk+*U8n0H5{|3&vj4Qp=(%g0&rASTJx|)~qGBKCwv&0%vyajroB%lbJL;6U(hiLjsaeCE4%wr-Z(B zgWjm{mtg|qStB2(z+RMQO=~ur&R*l|(g0r}yHhq-rgT;(4LDEbquuhCRT@v2o%?5B zu`8{^Rq9|S@$g>I#!&S6Pu2WNI8MbtYco#`_w=*ABw6;5ii-{1Ib3Rgq z?3vn!Ip|=I(NVp#LrrMf>2!e+uSsWz_b+W|-# z=L~w<@pcZ^juxGmE1YQJ1%TWe$Wzq<@xs|vfW(?W+JYLH@YKe86##Bs63Yr%_S{3+ z>P)w|{#H({W}*Tzh$Bup$itcU6hxt8pC>Yc)mq#ZRMiz{>F%HJmdlFF`tV2Y()UNdQj^f<|GsiAKtsC&uVCe?@%dl8@y z0JCO(>}GA&ljzAh4ZOt};@M}O-MHO4yan#&YVhn1XtsFW0Hm^GK9q#kX@z+h74!B` zkB`d%gX+)-|KdZY`#W0-C0Kn1kiLHZ7>74}$ZfvuRSHNI$AVaQkML>+{<7uV+OkfU z4Oo1uc&~WPP32@_t8SK~61{j5+r}TFWuV%z=@@fa-F2Uwgr_udlrMkHD+bSLNcKMzFx_1j(ql)A%((gVyr zX89xAHjRdnI&uE#Z1QvJ*$0AModGOL1#>Hvpe_Z-IU7a_P5=@+f=l1xdR}i+hRD6D zWNX&IRsb&Ujz^&Qm7^uCR<_6i+_p~!)F~`13IMmyd<_sYu{>r-IK?gSPab|Gm z{_C-HG+{oVO7`Bp-Pg196c3Y>*kU{!0!oQ?3`~BErBD+%N{zmeRB067vL2J0X>0U0 zGM|pZmYa}hPW6^i58IEh_8I$wG%@ vZtB=>a6NyB6}7V>@@xEu4J6DC>)Eh!$?1J0Di{FW5U}8V`~8J`kN)xx^weSs literal 0 HcmV?d00001 diff --git a/docs/images/high-box.png b/docs/images/high-box.png new file mode 100644 index 0000000000000000000000000000000000000000..a3da538425823ef7ad168954968732d62f42c170 GIT binary patch literal 1756 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 literal 0 HcmV?d00001 diff --git a/docs/images/two-boxes-2.png b/docs/images/two-boxes-2.png new file mode 100644 index 0000000000000000000000000000000000000000..8acaaea5db1c38644075bca966177097715bc7c3 GIT binary patch literal 3021 zcmeHJ`B&2E8b_nl!KKB)HLS_Ba%nVCZ@IK+nrm5KKvYCaQb;o`l`NbKk=;u!dEJey zDNr`S2yM*ekdbFpv{E!Rwc|`W;ZlmEqTt2(AMUxo^uu%B_jx|gd7kGy=Y2ot^RLrk z0Y*Pq{s01jj7|mmMSws$g&U@?tBsh9KC03lI_VJs$3b;H)}OTw_~Nn9V<1p{0c0(1 zv(`6A4U9|&fsETXOsC^=?FA4B5`W6?*tsms?5H&F145VjcEGX4bjI`kUP6kM-9cg@%qrMCj`Hke~12u+ejRKG3Z;?s3GSr zO{k}QS2G{&jj0(UIelqfSz6aDt7~cs_+vSm%W9;TBZM}2l_PI&^r&tvJ|`oXf%Um>dghO?iEH2`>I3F`24nZ!2Xrq zg}5tL9SGUS_szozcyCJxjTh6vHg*-k@~D!Go;tR;m?-M%zrGa;jY6dYJ1^k9^~Lcq zgc|&5SlcRwXELrL%-!3wn@~XlSyyDktoOHlSi+AwKxm(m|E@DvPL;%~q5{o$Y;lPK zU&gwY1Ey_`zM&dv#0uC8zi4#lQ#`k)m5e;lF!zOXz1m6YZ9Ok1(qh=9m=n{~UW0jK z6e_xQ#L*^JJ)b0D-Fy&p_lF{bMU;Na7CQ{tOU#44CZ47;xvfER{1L2Xgo+8gtkLx)%L(0SdQ z7$!mprd8N!;h=(un$p4Aq`O%E>r1M#am;#zrm=0Tb5YyGSM+NoP`oZ=BF?UTO)rY5 zZBu3DWX&%=8?uQv#J)dPC6gcs>Axvl)u$3*rS)I!CUKjK6OR8Eh@! zt7r(Bi~0OHn_E~>o!j)K26>y)W#xYc)0D*2nb|?~EzMIGI52AQZK=9>CUy_lpzbhJ;5{3Mof?CPV}{I4wx)4 ztYY9#SHWGP%p3|XWBj)|8vo-e?1LvjQB^%iEF~&E!L)j{0z2wCQiC7-jEi}^*wY-e z8+G6HiM&C?#tTmlrSa8|^r6|U)p}JyvWGs^7o|-Lvdh+69_vGU`xRIUYgoyRM4Hxk z-659v3(Pqp`9U;Lb!~PwLvbJvJ0H^MdA#*50mupARdjRw$P(0wt8*8lEfGaW_U7jb z%aQ*C(>CFS&ai`4(*?Qd4|qiFKlkL`@NQdICJ3dLqb&!dl^&vQP6%1D-^qh8{t8!t z{0&Sy)P#d)1QXo&8KH+^mB@N9O)-&@L@!5A0&e2?qKu6@@VuZb@r?6 zj?Vo($;-l^&;4>AeJFBhrgR`d!9HSe{n*eORrb0NC6gz7@i>~dkO|65SLU_HI1?SW(GU~BRh}H5yuDxsNkU^gz2H>$W%Spt8=tkdovuE=OD_`T7Pp+TYpQk7Y0POomvSFI^`ecS9css{x8^t1#JKT literal 0 HcmV?d00001 diff --git a/docs/images/wide-box.png b/docs/images/wide-box.png new file mode 100644 index 0000000000000000000000000000000000000000..762a76ac171c1282778b4f99e83f0b6406c26369 GIT binary patch literal 1584 zcmeAS@N?(olHy`uVBq!ia0y~yUM1MG6B0>rqb^$B>G+w|8QLq^(6-1JmZ;OjVLR z!W+|lEN}tyva8FN?)6*Co>P}If6~6`Ax~c(KOgU4B-&7-#qctO;nGTmCBcjy%b6zl zu`0~vaw^DZzxiC*Q~ND1nP({z>#dppzvpa!WOn=T+nJ`%-t#YIS{~HM^mavk z_O{u@yKU|setrI*bXa5XN{7a>EAGDKySKI9HV*y#vwRU$p}0>u|L*qYXN}VXpsLoJ z-j1!k9{${V|8EdsyjZzp3jNm^yWjouI}ogI zt5(5mW&6PGdTyIPGHGqFzq?D~>@n^Y2mY13PBM|!U%>SH^4ji;IeQwo-uMrMBB{4~ z)*EXX7)r0dc<#4VaRTd~^5pd3Mya<4z`~*{F7o}cTFfL&nUKB_yV`@wkOw(h0gGjS zxVo`ETgGI1t1&($Bq5Jp})HKQ1`oNAD7Xhgp|_t_WAhzjBAg)*=gMIvkzFxGkCiCxvXJBb?r literal 0 HcmV?d00001 -- 2.34.1 From 5bd6f98c6eab38384f7a52c476c2900d4ae59b2a Mon Sep 17 00:00:00 2001 From: kiruma524 <71787194+kiruma524@users.noreply.github.com> Date: Wed, 28 Jul 2021 14:49:52 +0300 Subject: [PATCH 26/35] Add files via upload --- docs/tutorial.md | 207 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 207 insertions(+) create mode 100644 docs/tutorial.md diff --git a/docs/tutorial.md b/docs/tutorial.md new file mode 100644 index 00000000..5d8bc1e3 --- /dev/null +++ b/docs/tutorial.md @@ -0,0 +1,207 @@ +#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 + -- 2.34.1 From e37bc779883857d078712ced7500ec03b98e6658 Mon Sep 17 00:00:00 2001 From: kiruma524 <71787194+kiruma524@users.noreply.github.com> Date: Wed, 28 Jul 2021 15:37:59 +0300 Subject: [PATCH 27/35] Delete big rotated box.png --- docs/images/big rotated box.png | Bin 2206 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 docs/images/big rotated box.png diff --git a/docs/images/big rotated box.png b/docs/images/big rotated box.png deleted file mode 100644 index 7b7cdc14dad92f2d151a2fbf735e3af14b4f54e4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2206 zcmeAS@N?(olHy`uVBq!ia0y~yV4MKL985qF{<{lj11ZMhAa^H*b?0PW0y!+{j=qiz z3>*8o|0J>k`J4qFk;M!Qe1}1p@p%4<6b1$kV^0^ykczmschBYqM@lq2Oqr%5Xu82I zq`^fr#6Wbz0w(=sOj--LRJ1xGE;D6J+dOafL!l4;Z;m`}`7LMPud~CPF;Q%f)$`9A zcgDol?q$&Uk^E0G;Uf$82>~4i=M4=!2bqjUIiq1fK|0t0OjvXE6(8L_o&NbM|LWEG zpGBR8b*80SyNT!TJ0ott=ile~KVR9)-?xw4TWfXSz~tbgiElJ6J_+b~m&A4LX!~=q z$mb3lEE<)kxvH1QuE`9~m{`ij(p@W;7g^%eRBFf4J%8QjEpm(RM=#nvBkSv5&$^ng zht?HT^qFo*`*r;P>*Rl0I?V|i)1sE23Ac=v4n3wE!IKol|8Cw6Ljh3g?k;`VJ2m#< z3m`*&-g$9WbA7=gHJ0u|iDX{?4HDh44==EEo36L7<(r?AP||dC+9#!>>k4w3SW`H} zqLuVT?)?&4Xn1W0OZUYaqI^D}9Fycy*4iwjV`h2tKoX}Iv(YiBsRRzhto(O5zhe2!uW*XJu35#ytrjsy*!|vPU<4ogQSe>5thKbs z_0ryB5y8dza-XMX6s>9Wz3skH?m4g3_tN4W4-?wzYX4o6-b!FZXM#Ot{J^Hrr2njqtkuZFjdvUY@*B-bYx+ zY;X0?H`hDfa9%qo;rq|OpHFB_v2sMtEskqXwi(!F^t^i%cW{%uOhYp7os(CVy*>VC z@BQ>uSEnre*=DQ|F^BiP)hnPGYuD|I+_u4|>1gB*xdh4W-#NwD-&9U5;OyCWt}9_< zcOiebO2iy?PPwK8M#(1Edj}1tb^bPB>6V?7lQ5H|+c=@Ylnb051>Z;}OD6QXY}nD7 zD*}pbze-3n8+Oc1)?r?AkV9;@W!F(APBCZW15(`}(~iE)Iz749a2n&a3UFzCEVaQ@ z=3tVBond88)6un;)TMbgv_Vpu2J;$0PO-&?$E0Q?Y@A-o<*gLabMi>7$Mn^!*MC;c zsr>%w=9kAz|DQiU>wEu~SHM~~)rdErcQs%txZJ>+-Opd^0I?5UNFgSAb=zitK XkKfnK-t`&SreN@N^>bP0l+XkK2=+1# -- 2.34.1 From 3a5da762d12c2099c407cc79e0cb9ac4fb59e5fb Mon Sep 17 00:00:00 2001 From: kiruma524 <71787194+kiruma524@users.noreply.github.com> Date: Wed, 28 Jul 2021 15:38:14 +0300 Subject: [PATCH 28/35] Delete small box.png --- docs/images/small box.png | Bin 1503 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 docs/images/small box.png diff --git a/docs/images/small box.png b/docs/images/small box.png deleted file mode 100644 index 4ebc0cb390e5e336b7ecefed54ab3c47d5666d84..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1503 zcmeAS@N?(olHy`uVBq!ia0y~yV4MKL985qF{<{lj11ZMhAa^H*b?0PW0y!+{j=qiz z3>*8o|0J>k`J4qFk;M!Qe1}1p@p%4<6b1&?5>FS$kczmscQ)o8HV|=eG%`*R%Ad}; zWvKv;O-=d;LBpNxuk(wgg7WCe{=Vu?dQ!oY62C-048T@R;yNee(o? T_j6r Date: Wed, 28 Jul 2021 15:38:56 +0300 Subject: [PATCH 29/35] Add files via upload --- docs/images/big-rotated-box.png | Bin 0 -> 2206 bytes docs/images/small-box.png | Bin 0 -> 1503 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/images/big-rotated-box.png create mode 100644 docs/images/small-box.png diff --git a/docs/images/big-rotated-box.png b/docs/images/big-rotated-box.png new file mode 100644 index 0000000000000000000000000000000000000000..7b7cdc14dad92f2d151a2fbf735e3af14b4f54e4 GIT binary patch literal 2206 zcmeAS@N?(olHy`uVBq!ia0y~yV4MKL985qF{<{lj11ZMhAa^H*b?0PW0y!+{j=qiz z3>*8o|0J>k`J4qFk;M!Qe1}1p@p%4<6b1$kV^0^ykczmschBYqM@lq2Oqr%5Xu82I zq`^fr#6Wbz0w(=sOj--LRJ1xGE;D6J+dOafL!l4;Z;m`}`7LMPud~CPF;Q%f)$`9A zcgDol?q$&Uk^E0G;Uf$82>~4i=M4=!2bqjUIiq1fK|0t0OjvXE6(8L_o&NbM|LWEG zpGBR8b*80SyNT!TJ0ott=ile~KVR9)-?xw4TWfXSz~tbgiElJ6J_+b~m&A4LX!~=q z$mb3lEE<)kxvH1QuE`9~m{`ij(p@W;7g^%eRBFf4J%8QjEpm(RM=#nvBkSv5&$^ng zht?HT^qFo*`*r;P>*Rl0I?V|i)1sE23Ac=v4n3wE!IKol|8Cw6Ljh3g?k;`VJ2m#< z3m`*&-g$9WbA7=gHJ0u|iDX{?4HDh44==EEo36L7<(r?AP||dC+9#!>>k4w3SW`H} zqLuVT?)?&4Xn1W0OZUYaqI^D}9Fycy*4iwjV`h2tKoX}Iv(YiBsRRzhto(O5zhe2!uW*XJu35#ytrjsy*!|vPU<4ogQSe>5thKbs z_0ryB5y8dza-XMX6s>9Wz3skH?m4g3_tN4W4-?wzYX4o6-b!FZXM#Ot{J^Hrr2njqtkuZFjdvUY@*B-bYx+ zY;X0?H`hDfa9%qo;rq|OpHFB_v2sMtEskqXwi(!F^t^i%cW{%uOhYp7os(CVy*>VC z@BQ>uSEnre*=DQ|F^BiP)hnPGYuD|I+_u4|>1gB*xdh4W-#NwD-&9U5;OyCWt}9_< zcOiebO2iy?PPwK8M#(1Edj}1tb^bPB>6V?7lQ5H|+c=@Ylnb051>Z;}OD6QXY}nD7 zD*}pbze-3n8+Oc1)?r?AkV9;@W!F(APBCZW15(`}(~iE)Iz749a2n&a3UFzCEVaQ@ z=3tVBond88)6un;)TMbgv_Vpu2J;$0PO-&?$E0Q?Y@A-o<*gLabMi>7$Mn^!*MC;c zsr>%w=9kAz|DQiU>wEu~SHM~~)rdErcQs%txZJ>+-Opd^0I?5UNFgSAb=zitK XkKfnK-t`&SreN@N^>bP0l+XkK2=+1# literal 0 HcmV?d00001 diff --git a/docs/images/small-box.png b/docs/images/small-box.png new file mode 100644 index 0000000000000000000000000000000000000000..4ebc0cb390e5e336b7ecefed54ab3c47d5666d84 GIT binary patch literal 1503 zcmeAS@N?(olHy`uVBq!ia0y~yV4MKL985qF{<{lj11ZMhAa^H*b?0PW0y!+{j=qiz z3>*8o|0J>k`J4qFk;M!Qe1}1p@p%4<6b1&?5>FS$kczmscQ)o8HV|=eG%`*R%Ad}; zWvKv;O-=d;LBpNxuk(wgg7WCe{=Vu?dQ!oY62C-048T@R;yNee(o? T_j6r Date: Wed, 28 Jul 2021 15:40:06 +0300 Subject: [PATCH 30/35] Update tutorial.md --- docs/tutorial.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/tutorial.md b/docs/tutorial.md index 5d8bc1e3..2e695b7c 100644 --- a/docs/tutorial.md +++ b/docs/tutorial.md @@ -51,7 +51,7 @@ box(10, 10, 10, name = "small box"){ rotation = Point3D(0, 0, 0) } ``` -![](../docs/images/small box.png) +![](../docs/images/small-box.png) The `big box` will have properties with custom values. ```kotlin @@ -64,7 +64,7 @@ box(40, 40, 40, name = "big box"){ rotation = Point3D(60, 80, 0) } ``` -![](../docs/images/big rotated box.png) +![](../docs/images/big-rotated-box.png) If we compare these boxes, we will see all differences. Here is the function `main` with both boxes. -- 2.34.1 From 44da86d49641626c4436a874777a1c6c7b2fc277 Mon Sep 17 00:00:00 2001 From: kiruma524 <71787194+kiruma524@users.noreply.github.com> Date: Wed, 28 Jul 2021 15:40:25 +0300 Subject: [PATCH 31/35] Update tutorial.md --- docs/tutorial.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/tutorial.md b/docs/tutorial.md index 2e695b7c..9dba5f3c 100644 --- a/docs/tutorial.md +++ b/docs/tutorial.md @@ -65,6 +65,7 @@ box(40, 40, 40, name = "big box"){ } ``` ![](../docs/images/big-rotated-box.png) + If we compare these boxes, we will see all differences. Here is the function `main` with both boxes. -- 2.34.1 From f611409208c1ed072b9069cd571049ab50875a2b Mon Sep 17 00:00:00 2001 From: kiruma524 <71787194+kiruma524@users.noreply.github.com> Date: Wed, 28 Jul 2021 15:41:04 +0300 Subject: [PATCH 32/35] Update tutorial.md --- docs/tutorial.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/tutorial.md b/docs/tutorial.md index 9dba5f3c..9de1432b 100644 --- a/docs/tutorial.md +++ b/docs/tutorial.md @@ -108,6 +108,7 @@ fun main(){ ![](../docs/images/two-boxes-2.png) ###Basic Solids + Now, let's see which solids can be visualized: 1) PolyLine 2) Box -- 2.34.1 From e818ecdcc3175f46e44a27534f40bbc3b08b508a Mon Sep 17 00:00:00 2001 From: kiruma524 <71787194+kiruma524@users.noreply.github.com> Date: Wed, 28 Jul 2021 15:56:54 +0300 Subject: [PATCH 33/35] Update README.md --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index c9312320..621f474f 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ * [visionforge-gdml](#visionforge-gdml) * [Visualization for External Systems](#visualization-for-external-systems) * [Demonstrations](#demonstrations) - * [Simple Example - Spatial Showcase](#simple-example---spatial-showcase) + * [Simple Example - Solid Showcase](#simple-example---solid-showcase) * [Full-Stack Application Example - Muon Monitor](#full-stack-application-example---muon-monitor-visualization) * [GDML Example](#gdml-example) @@ -118,16 +118,16 @@ The `demo` module contains several example projects (demonstrations) of using th They are briefly described in this section, for more details please consult the corresponding per-project README file. -### Simple Example - Spatial Showcase +### Simple Example - Solid Showcase Contains a simple demonstration with a grid including a few shapes that you can rotate, move camera, and so on. Some shapes will also periodically change their color and visibility. -[More details](demo/spatial-showcase/README.md) +[More details](demo/solid-showcase/README.md) **Example view:** -![](docs/images/spatial-showcase.png) +![](docs/images/solid-showcase.png) ### Full-Stack Application Example - Muon Monitor Visualization @@ -156,4 +156,4 @@ Visualization example for geometry defined as GDML file. ## Thanks and references The original three.js bindings were made by [Lars Ivar Hatledal](https://github.com/markaren), but the project is discontinued right now. -All other libraries are explicitly shown as dependencies. We would like to express specific thanks to JetBrains Kotlin-JS team for consulting us during the work. \ No newline at end of file +All other libraries are explicitly shown as dependencies. We would like to express specific thanks to JetBrains Kotlin-JS team for consulting us during the work. -- 2.34.1 From 786b902fd9acdf21ab03d055eda54a13bfe95d99 Mon Sep 17 00:00:00 2001 From: kiruma524 <71787194+kiruma524@users.noreply.github.com> Date: Wed, 28 Jul 2021 16:46:43 +0300 Subject: [PATCH 34/35] Update README.md --- demo/solid-showcase/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/demo/solid-showcase/README.md b/demo/solid-showcase/README.md index 20866220..f8771e13 100644 --- a/demo/solid-showcase/README.md +++ b/demo/solid-showcase/README.md @@ -5,8 +5,8 @@ Some shapes will also periodically change their color and visibility. ##### Building project -To see the JS demo: run `demo/spatial-showcase/Tasks/distribution/jsBrowserDistribution` Gradle task, then open -`build/distribuions/spatial-showcase-js-0.1.3-dev/index.html` file in your browser. +To see the JS demo: run `demo/solid-showcase/Tasks/kotlin browser/jsBrowserRun` Gradle task, then open +`build/distribuions/solid-showcase-js-0.1.3-dev/index.html` file in your browser. To see Java FX demo, run `demo/spatial-showcase/Tasks/application/run` Gradle task, or `main()` from `FXDemoApp.kt`. -- 2.34.1 From 72d3503dc34d4fa298cdf63942f9ecd209244263 Mon Sep 17 00:00:00 2001 From: kiruma524 <71787194+kiruma524@users.noreply.github.com> Date: Thu, 29 Jul 2021 14:13:27 +0300 Subject: [PATCH 35/35] Add files via upload --- docs/images/cone-segment-1.png | Bin 0 -> 2691 bytes docs/images/cone-segment-2.png | Bin 0 -> 2754 bytes docs/images/cone-surface-fragment-2.png | Bin 0 -> 2169 bytes docs/images/cone-surface-fragment.png | Bin 0 -> 2410 bytes docs/images/cylinder-1.png | Bin 0 -> 2710 bytes docs/images/cylinder-2.png | Bin 0 -> 3225 bytes docs/images/cylinder.png | Bin 0 -> 2196 bytes docs/images/frustum-cone-segment.png | Bin 0 -> 2399 bytes docs/images/frustum-cone.png | Bin 0 -> 3016 bytes docs/images/scheme.png | Bin 0 -> 6981 bytes docs/images/tube-fragment.png | Bin 0 -> 2912 bytes docs/images/tube.png | Bin 0 -> 4630 bytes 12 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/images/cone-segment-1.png create mode 100644 docs/images/cone-segment-2.png create mode 100644 docs/images/cone-surface-fragment-2.png create mode 100644 docs/images/cone-surface-fragment.png create mode 100644 docs/images/cylinder-1.png create mode 100644 docs/images/cylinder-2.png create mode 100644 docs/images/cylinder.png create mode 100644 docs/images/frustum-cone-segment.png create mode 100644 docs/images/frustum-cone.png create mode 100644 docs/images/scheme.png create mode 100644 docs/images/tube-fragment.png create mode 100644 docs/images/tube.png diff --git a/docs/images/cone-segment-1.png b/docs/images/cone-segment-1.png new file mode 100644 index 0000000000000000000000000000000000000000..b59005552588063eb38e7812efe3fb6719fa6908 GIT binary patch literal 2691 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 literal 0 HcmV?d00001 diff --git a/docs/images/cone-surface-fragment-2.png b/docs/images/cone-surface-fragment-2.png new file mode 100644 index 0000000000000000000000000000000000000000..2d8eaa991ca335cc221f73a2329e13b37c2c1a99 GIT binary patch literal 2169 zcmeAS@N?(olHy`uVBq!ia0y~yV4MKL985qF{<{lj11ZMhAa^H*b?0PW0y!+{j=qiz z3>*8o|0J>k`J4qFk;M!Qe1}1p@p%4<6b1$kK2I0NkczmscLIy9SV=WpOu1%IuDmAi z9oG$6=|n+erK}Jw^ORNZnBShaV-NrAZRYP;yYwBy`}qB}^~@SSu0JksxGb!r;Jl%M z=OB|23-<|uQO?K;gU5egZ-3t}X!qyu)Ah%{e0z4gIap9fE^YZg>$==~_wOA)SMjy> zkYt7T3I4@l%0BH;yxHmYWd~Pth~@wP`RV=hkhjlb&pvv}^7@)vv)fv^ZvWailOM(` zulGH>ec(9rT7K{gX?K}K2i!I~Zi-4tu>$7c**+9A{hAw>`wKg#}IourB}Di^?0*tCu`8Eq}&bAkfq0p zH2pj_tb0FU-bNYQDjmBsb0t@n+P*tDljBIMdmoMLHym{-o%5ur`Hu;C< zt3*uSdOY=OhTi<$#%0Hht51BB^mE#v_inWf_$^T-bMLvchU@*-o_)EY#olMbx=gY3Z>jnh?Rx%NuDQO~ z{nioAz4d>;{WUC7{Jj5lwCAkP6|twAe?IwlhHKh;fpdpBUpIZ@-w;-QtVZLaQMPH@ zPph+$Yb}8BwPUa2W%Zl4+CQ!eo70;Rd*S`0E!B2DzRCBd7icw=D$iHRxpT|BRcZ~cB6;@XrDd-m6nzr~9K9?v>^>-5(11!hg9*`E_iE#i99D(z1IRhwFB z6nZw5n*M)tS))7Qy?tA6 YQMomwJ+p%m*j!-nboFyt=akR{02*#hU;qFB literal 0 HcmV?d00001 diff --git a/docs/images/cone-surface-fragment.png b/docs/images/cone-surface-fragment.png new file mode 100644 index 0000000000000000000000000000000000000000..2d82835f702b02da61d672d6227c20da8f9b5f8f GIT binary patch literal 2410 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 AAOHXW literal 0 HcmV?d00001 diff --git a/docs/images/cylinder-2.png b/docs/images/cylinder-2.png new file mode 100644 index 0000000000000000000000000000000000000000..88c406bf915e4fb3b7f57ace8aac2caa20326168 GIT binary patch literal 3225 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 AzyJUM literal 0 HcmV?d00001 diff --git a/docs/images/frustum-cone-segment.png b/docs/images/frustum-cone-segment.png new file mode 100644 index 0000000000000000000000000000000000000000..96e4170feebebce4effc85ba48f84feb4c921adb GIT binary patch literal 2399 zcmeHJ`!`g36hG?R7(&QgDb0`&BYD3c;}M3q3vrU%L*7JQ-7)3SOeiCd-X&Cu%CLs6 z>2?W+PAJa^xuQl<88jC|X6T;!1MbiL&<}g9{n=}O_xkL;*Z%H(<~I*#X-Q>C005+2 zT^zjtK&$|ha}w(?i@hR%0YEI#%h?{N?%wth17J9L9~l5@@})#UzhD@5)a5`T0LZj{ z6S20qyCDD|vEb@R_MryOjFJ<$5Zpps7ZtK)T+pjA^(+qmL%J}+?p6rZ`$T|a1s(llQ=c80cniFh;r5 zXpS%(`dvRYv`1kt+`>&P*WI8Bb?!Xaa2@8~Y<;e>yB)8m4q4fAs5nG&$-kh*S}2`4yB{PLuVgsua!o)=DGecc5H}Owm<$_gAsE-Zt#Z5@z5{D zE2QLQuWKj`jJCC*^a!>^*2p8DQeZ*K8&$&9FL%mmQFu>HXq1x_STA!mjGshD4G5XM z$;CS_8A32Rz;krMrWSdap()Q=9e#7;(}AJ4`gAl$^f2A(GRz0N?+<6eXQ#{f?@n5f zEOwQW9;cm8EvQf+HBzn&=fX93amcC|)*o^{KhR~}H;gKSOgH~lHW(e@P!`wFU#N?@LqdD=S0E+~`_^ZzR9cpzK59ijLe zp-R_=v9!N-rtfR*%5mLVDNnL7Z3<>mv2)|b2juWZ%i=ue&<>QC@jOLk=7obLq^YuiLU3!c~xAD`mrvFHf(KiYqYp0_>@`*T0LmFmBAy z?}kvTJDW@M+|pFr+rjCo)R7&l!CG`hL8Q$k!TWyUKjJC62rYWa)Ny`unH*{IgH9DN+#_O;%H)B>^u-n4TZALK?~EZ@ENzGY_Zb^{qCC&i2~PoTzo3W*b& zSgX*VZ3kAg4_M+;r_ zZ4hp|P5UxfIn|)?M_y--t?`se?p#s28*^=$zeHtvBc z=I_lX9CG}WBy1{?&wWO@k|f#d?wuEAr97zJZs>E)iEmz_F)-|LG>At(@8<1J*(M2!B`3@&47@m#6Xlg=1o;>DI zU?CBji&gF)$dN>%gj`=U>rrKw)9_=xI<>ZO`AOZ?`j++4L?;bagE+^&PL0AIW9~Ti z0@R6H^P20;u|P%`<_F&zLH87su@bOO@)+<8Qry>ZQ}MVOWEr2RlN5n=OAN-|Qxr~Q zmI>q6B)y`E^&u@I`Tf3keR&t*nVcQR1YHz~kSjk|+mF85{`U@1OB2qdo4s+5IIU_Y Qg&jqJtCNRgwLMJ#4}kX4f&c&j literal 0 HcmV?d00001 diff --git a/docs/images/frustum-cone.png b/docs/images/frustum-cone.png new file mode 100644 index 0000000000000000000000000000000000000000..e5f6786c138e1ccf6b7dfa0367b9f1767cc39ace GIT binary patch literal 3016 zcmeHJ`8$+t8=kf|$@0l-ZDHhjzXa% z?T=ZzqEPGZu7%ioQAW#3Ni?F?g}K^UqAFjbKZ(G`APXl86pE3$b@}Wj5#Dm~7#M~^ zNwL;qU0dj*02FGgkG-{pTcq#w;MS0Lp4)7CI-dr0v!Z0L#7;a^Yb&T$n^kAL=C7BJ zu})B%lqbY?7W`bE*EJXCtWU?ur&%L6_rja@_Gs@+fY#XqTaOik=G*=){ZDVhi zjf}b7rm+yC-HX2ZV|-q}Ynh)%D z*Ilhoh`djMlE-ddbCg=@P9WY-g(OGl%68;)#9_M=2R<~T#Y%cVmvmTnHF7hfoCHENcam}PRsQ$%JR^!C5L49@YsCNB`{!LB4)-9S zUu6Y)Uqh!pt4;&QbNnDpNAE8Jv|=H85xA$9CQ;BB0X_@8@wxEE+QOGRHvl>>-B+qE zj$nhuU^#PSu?V#4rlCmRl<(lO+E}}C{3G_)9TZUVhX{NwZDx|^LkhNLLGSBJiA{g% zy_{jQo4K@jAo!&1;9HJ7j%QVuT8Y*N0ctHX^aAEQ?*c!q-T!*D8hK|07*Z=biXSY{ zhAEDSup*BKVnv(SXVCOe)xGfaJ|-r(^%G@-IvK(|0P}FXdVpHaJa-h&Q!%J4LmTdQ ztSkxN5~(p0qaISLkH^}P8imKtXL->bTX`-Z9R;^g6}?P~xhZsR>gtRFpDe=yDmlo*);tXEPlTq;k+_Fob6>JUPX)M@BGY~E7G_)1Qagu8 zrPv_KJ+yN;?C%^x>5OaI1a!qT$=}n5=KW(IV}eVoZS!cg@Phko-WTTrRFA7_f#{k* zH=j&7_&6fYQNHg|`}q1ehB|mLJy2tz6x8WkN#K@&+cS&0GmL6aW~rw_vzlX08s=j~6;{xL0W@b*$=XuUk`% zX64%M+&n+ZK;7VKh^mAvjyD?)J`u9T2X23!!_NC04XK*atoasQV7~NICl~DlWEKiK}z0}GI6W*rI zMTO}$p8uIEXNhl+S#0m~yeKT_-aoX=BVu`~lkjPoWhMEEQC%R!;bx-@oszA|0 z*!J6iMJ-3N!iAjvHb2SoYaGspx}?}ANfn7In)9Uiu5;O;(=QIjLnH=i*4cwvb*R8s zY4ZgRwh z*?25t8Py?%b4EloB*y%ghR!~kS)RQ#;`fChXgc!&v)zfOf=HL4kF4Z^CV}N4y)+Xb z*c;-#9*XADOrV0ZM%RQ~S~xVFcg76(qS)~_w*Vr!xhKj&02OT_lSD76_N3&|a#dB_ zjKX&-df8Phh^tB%h(3%o`~YWQX532rY~4*unbFBRqeJ|*w}T;Tfxs187uWPA+MEB} z{w&dnvgxY2ht`l`4RN^iV8g>v{NZQ$rJGqEaDN}&iCXnF4NA5_gu(_$AO{IAUFJX9 z;vX4J!Ek8;Ab4loz(5^FmX`c<#~C9+jH0ifu|Rv(Kr0s#2;OMVzHP~#*S2%|4~IZM zu-$9ftd;mGK<^okUCl^~lZZ*^HjcMib`Su6wp2B?ip;`vi4 z*@m`?h38eMlvuU9`+xiTN4@k3vPiZhNGl$dBE6H)kM*L{hXRr<5&u55fCOUBsD8)Z zKlRv&~7QP+A^7ZmXJ`TaGy%&hesuXlPf4p}-8f z!(-braCWjc-^&QydaiYLh!9Q8AgzZnF-&IA=@jxVrFpR-Li42zk`#=&&3rz7O6m`n z+yz6nRDpw$_;1kQN5e0&#bqxIdT2#`fk)zrVo98)cw(!U&S6l!1S~1nGGopOl=AON zKRPdX&Q=(gaEvw&x?;KD7U=+E9y0&hqv@BMaq#=u=JyvQudql1Y>CD literal 0 HcmV?d00001 diff --git a/docs/images/scheme.png b/docs/images/scheme.png new file mode 100644 index 0000000000000000000000000000000000000000..baa6a8770a2603c1f6024b4f5d701a1a50673add GIT binary patch literal 6981 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 literal 0 HcmV?d00001 diff --git a/docs/images/tube-fragment.png b/docs/images/tube-fragment.png new file mode 100644 index 0000000000000000000000000000000000000000..e2a20ebe67e0657fba74df58fd5f3354e49471d7 GIT binary patch literal 2912 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 T2mm$KEC*n2Vrg7!crWHZO*{K8 literal 0 HcmV?d00001 -- 2.34.1