Fix meshline

This commit is contained in:
Alexander Nozik 2025-02-10 11:56:48 +03:00
parent 82538ad70c
commit 674ade5a59
22 changed files with 79 additions and 53 deletions
CHANGELOG.md
demo
js-playground/src/jsMain/kotlin
playground
sat-demo/src/jvmMain/kotlin/ru/mipt/npm/sat
solid-showcase/src/commonMain/kotlin/space/kscience/visionforge/solid/demo
plotly/examples
visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid
visionforge-tables
visionforge-threejs

@ -3,10 +3,12 @@
## Unreleased ## Unreleased
### Added ### Added
- Plotly refactored on top of visionforge/server
### Changed ### Changed
- Simplified Vision and VisionGroup logic. Observation logic moved out. - Simplified Vision and VisionGroup logic. Observation logic moved out.
- Use `Name` for child designation and `Path` for tree access - Use `Name` for child designation and `Path` for tree access
- Default intensity for AmbientLight is 2.0
### Deprecated ### Deprecated

@ -2,7 +2,7 @@ import org.jetbrains.compose.web.css.*
import org.jetbrains.compose.web.dom.Div import org.jetbrains.compose.web.dom.Div
import org.jetbrains.compose.web.renderComposable import org.jetbrains.compose.web.renderComposable
import space.kscience.dataforge.context.Context import space.kscience.dataforge.context.Context
import space.kscience.plotly.PlotlyPlugin import space.kscience.plotly.PlotlyJSPlugin
import space.kscience.plotly.models.Trace import space.kscience.plotly.models.Trace
import space.kscience.plotly.models.scatter import space.kscience.plotly.models.scatter
import space.kscience.visionforge.Colors import space.kscience.visionforge.Colors
@ -25,7 +25,7 @@ fun Trace.appendXYLatest(x: Number, y: Number, history: Int = 400, xErr: Number?
public fun main() { public fun main() {
val playgroundContext = Context { val playgroundContext = Context {
plugin(ThreePlugin) plugin(ThreePlugin)
plugin(PlotlyPlugin) plugin(PlotlyJSPlugin)
plugin(MarkupPlugin) plugin(MarkupPlugin)
} }
startApplication { document -> startApplication { document ->

@ -1,8 +1,8 @@
plugins { plugins {
kotlin("multiplatform") kotlin("multiplatform")
kotlin("jupyter.api") kotlin("jupyter.api")
id("com.github.johnrengelman.shadow") version "7.1.2" id("com.gradleup.shadow") version "8.3.6"
// application
} }
repositories { repositories {
@ -15,13 +15,15 @@ kotlin {
jvmToolchain(17) jvmToolchain(17)
js(IR) { js(IR) {
browser { browser {
commonWebpackConfig {
cssSupport {
enabled = true
}
scssSupport {
enabled = true
}
}
webpackTask { webpackTask {
cssSupport{
enabled = true
}
scssSupport{
enabled = true
}
mainOutputFileName.set("js/visionforge-playground.js") mainOutputFileName.set("js/visionforge-playground.js")
} }
} }
@ -43,9 +45,9 @@ kotlin {
val commonMain by getting { val commonMain by getting {
dependencies { dependencies {
implementation(projects.visionforgeSolid) implementation(projects.visionforgeSolid)
// implementation(projects.visionforgePlotly) implementation(projects.plotly.plotlyktCore)
implementation(projects.visionforgeMarkdown) implementation(projects.visionforgeMarkdown)
// implementation(projects.visionforgeTables) implementation(projects.visionforgeTables)
implementation(projects.cernRootLoader) implementation(projects.cernRootLoader)
api(projects.visionforgeJupyter.visionforgeJupyterCommon) api(projects.visionforgeJupyter.visionforgeJupyterCommon)
} }
@ -60,7 +62,7 @@ kotlin {
val jvmMain by getting { val jvmMain by getting {
dependencies { dependencies {
implementation("io.ktor:ktor-server-cio:${spclibs.versions.ktor.get()}") implementation("io.ktor:ktor-server-cio")
implementation(projects.visionforgeGdml) implementation(projects.visionforgeGdml)
implementation(projects.visionforgeServer) implementation(projects.visionforgeServer)
implementation(spclibs.logback.classic) implementation(spclibs.logback.classic)
@ -77,9 +79,7 @@ val jsBrowserDistribution = tasks.getByName("jsBrowserDistribution")
tasks.getByName<ProcessResources>("jvmProcessResources") { tasks.getByName<ProcessResources>("jvmProcessResources") {
dependsOn(jsBrowserDistribution) dependsOn(jsBrowserDistribution)
from(jsBrowserDistribution) { from(jsBrowserDistribution)
exclude("**/*.js.map")
}
} }
val processJupyterApiResources by tasks.getting(org.jetbrains.kotlinx.jupyter.api.plugin.tasks.JupyterApiResourcesTask::class) { val processJupyterApiResources by tasks.getting(org.jetbrains.kotlinx.jupyter.api.plugin.tasks.JupyterApiResourcesTask::class) {

@ -1,5 +1,5 @@
import space.kscience.dataforge.misc.DFExperimental import space.kscience.dataforge.misc.DFExperimental
import space.kscience.plotly.PlotlyPlugin import space.kscience.plotly.PlotlyJSPlugin
import space.kscience.visionforge.html.runVisionClient import space.kscience.visionforge.html.runVisionClient
import space.kscience.visionforge.jupyter.VFNotebookClient import space.kscience.visionforge.jupyter.VFNotebookClient
import space.kscience.visionforge.markup.MarkupPlugin import space.kscience.visionforge.markup.MarkupPlugin
@ -9,7 +9,7 @@ import space.kscience.visionforge.tables.TableVisionJsPlugin
@DFExperimental @DFExperimental
fun main() = runVisionClient { fun main() = runVisionClient {
plugin(ThreePlugin) plugin(ThreePlugin)
plugin(PlotlyPlugin) plugin(PlotlyJSPlugin)
plugin(MarkupPlugin) plugin(MarkupPlugin)
plugin(TableVisionJsPlugin) plugin(TableVisionJsPlugin)
plugin(VFNotebookClient) plugin(VFNotebookClient)

@ -2,6 +2,7 @@ package space.kscience.visionforge.examples
import kotlinx.html.h2 import kotlinx.html.h2
import space.kscience.dataforge.meta.ValueType import space.kscience.dataforge.meta.ValueType
import space.kscience.plotly.PlotlyPlugin
import space.kscience.plotly.layout import space.kscience.plotly.layout
import space.kscience.plotly.models.ScatterMode import space.kscience.plotly.models.ScatterMode
import space.kscience.plotly.models.TextPosition import space.kscience.plotly.models.TextPosition
@ -43,6 +44,7 @@ fun main() = makeVisionFile(
h2 { +"Interactive plots with Plotly" } h2 { +"Interactive plots with Plotly" }
vision("plot") { vision("plot") {
requirePlugin(PlotlyPlugin)
plotly { plotly {
scatter { scatter {
x(1, 2, 3, 4) x(1, 2, 3, 4)

@ -19,7 +19,11 @@ import kotlin.math.PI
import kotlin.math.cos import kotlin.math.cos
import kotlin.math.sin import kotlin.math.sin
suspend fun main() = serve { suspend fun main() = serve(
routeConfiguration = {
updateInterval = 100
}
) {
// val azimuth = 60.degrees // val azimuth = 60.degrees
// val inclination = 15.degrees // val inclination = 15.degrees
@ -45,6 +49,7 @@ suspend fun main() = serve {
//axes(200) //axes(200)
ambientLight { ambientLight {
color(Colors.white) color(Colors.white)
intensity = 3.0
} }
val platform = solidGroup("platform") { val platform = solidGroup("platform") {
cylinder(50, 5, name = "base") cylinder(50, 5, name = "base")
@ -87,7 +92,7 @@ suspend fun main() = serve {
var time: Long = 0L var time: Long = 0L
while (isActive) { while (isActive) {
with(QuaternionAlgebra) { with(QuaternionAlgebra) {
delay(200) delay(100)
platform.quaternion = Quaternion.fromRotation( platform.quaternion = Quaternion.fromRotation(
15.degrees * sin(time.toDouble() * 2 * PI / xPeriod), 15.degrees * sin(time.toDouble() * 2 * PI / xPeriod),
Float64Space3D.xAxis Float64Space3D.xAxis
@ -100,7 +105,7 @@ suspend fun main() = serve {
antenna.quaternion = qi.conjugate * incRot.conjugate * target antenna.quaternion = qi.conjugate * incRot.conjugate * target
time += 200 time += 100
//antenna.quaternion = Quaternion.fromRotation(5.degrees, Euclidean3DSpace.zAxis) * antenna.quaternion //antenna.quaternion = Quaternion.fromRotation(5.degrees, Euclidean3DSpace.zAxis) * antenna.quaternion
} }
} }

@ -27,7 +27,7 @@ fun main() = makeVisionFile(Path.of("curves.html"), resourceLocation = ResourceL
val cathodeTeflonDiskThickness = 5 val cathodeTeflonDiskThickness = 5
val cathodeCopperSupportOuterRadius = 45 val cathodeCopperSupportOuterRadius = 45
val cathodeCopperSupportInnerRadius = 8.5 val cathodeCopperSupportInnerRadius = 8.5
val cathodeCopperSupportThickness = 1 val cathodeCopperSupportThickness = 1.0
// mylar cathode // mylar cathode
val mylarCathodeThickness = 0.004 val mylarCathodeThickness = 0.004
// patern // patern

@ -9,6 +9,7 @@ import space.kscience.dataforge.context.Global
import space.kscience.plotly.PlotlyPlugin import space.kscience.plotly.PlotlyPlugin
import space.kscience.visionforge.html.* import space.kscience.visionforge.html.*
import space.kscience.visionforge.markup.MarkupPlugin import space.kscience.visionforge.markup.MarkupPlugin
import space.kscience.visionforge.server.VisionRoute
import space.kscience.visionforge.server.close import space.kscience.visionforge.server.close
import space.kscience.visionforge.server.openInBrowser import space.kscience.visionforge.server.openInBrowser
import space.kscience.visionforge.server.visionPage import space.kscience.visionforge.server.visionPage
@ -42,6 +43,7 @@ public fun makeVisionFile(
public suspend fun serve( public suspend fun serve(
title: String = "VisionForge page", title: String = "VisionForge page",
show: Boolean = true, show: Boolean = true,
routeConfiguration: VisionRoute.() -> Unit = {},
content: HtmlVisionFragment, content: HtmlVisionFragment,
) { ) {
val context = Context("playground") { val context = Context("playground") {
@ -62,6 +64,7 @@ public suspend fun serve(
defer = true defer = true
}, },
VisionPage.title(title), VisionPage.title(title),
routeConfiguration = routeConfiguration,
visionFragment = content visionFragment = content
) )
}.start(false) }.start(false)

@ -36,6 +36,7 @@ suspend fun main() {
val sat = solids.visionOfSatellite(ySegments = 3).apply { val sat = solids.visionOfSatellite(ySegments = 3).apply {
ambientLight { ambientLight {
color(Colors.white) color(Colors.white)
intensity = 3.0
} }
} }
val server = embeddedServer(CIO, port = 7777) { val server = embeddedServer(CIO, port = 7777) {

@ -25,7 +25,6 @@ fun VisionLayout<Solid>.demo(name: String, title: String = name, block: SolidGro
block() block()
ambientLight { ambientLight {
color(Colors.white) color(Colors.white)
intensity = 0.5
} }
pointLight(0, 0, 1000) { pointLight(0, 0, 1000) {
color(Colors.white) color(Colors.white)

@ -11,7 +11,7 @@ dependencies {
implementation(projects.plotly.plotlyktServer) implementation(projects.plotly.plotlyktServer)
implementation(projects.plotly.plotlyktScript) implementation(projects.plotly.plotlyktScript)
implementation(kotlin("script-runtime")) implementation(kotlin("script-runtime"))
implementation("org.jetbrains.kotlinx:dataframe:0.13.1") implementation("org.jetbrains.kotlinx:dataframe:0.15.0")
} }
kotlin{ kotlin{

@ -16,7 +16,7 @@ dependencies {
javafx{ javafx{
modules("javafx.web") modules("javafx.web")
version = "11" version = "17"
} }
application { application {
@ -24,6 +24,6 @@ application {
} }
kotlin{ kotlin{
jvmToolchain(11) jvmToolchain(17)
} }

@ -1,11 +1,14 @@
@file:UseSerializers(Float32Space2D.VectorSerializer::class)
package space.kscience.visionforge.solid package space.kscience.visionforge.solid
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.UseSerializers
import space.kscience.dataforge.meta.MutableMeta import space.kscience.dataforge.meta.MutableMeta
import space.kscience.dataforge.meta.update import space.kscience.dataforge.meta.update
import space.kscience.kmath.geometry.component1 import space.kscience.kmath.geometry.component1
import space.kscience.kmath.geometry.component2 import space.kscience.kmath.geometry.component2
import space.kscience.kmath.geometry.euclidean2d.Float32Space2D
import space.kscience.kmath.geometry.euclidean2d.Float32Vector2D import space.kscience.kmath.geometry.euclidean2d.Float32Vector2D
import space.kscience.kmath.geometry.euclidean3d.Float32Vector3D import space.kscience.kmath.geometry.euclidean3d.Float32Vector3D
import space.kscience.visionforge.MutableVisionContainer import space.kscience.visionforge.MutableVisionContainer

@ -17,7 +17,7 @@ public abstract class LightSource : MiscSolid() {
override val descriptor: MetaDescriptor get() = LightSource.descriptor override val descriptor: MetaDescriptor get() = LightSource.descriptor
public val color: ColorAccessor by colorProperty(SolidMaterial.COLOR_KEY) public val color: ColorAccessor by colorProperty(SolidMaterial.COLOR_KEY)
public var intensity: Number by properties.number(INTENSITY_KEY) { 1.0 } public var intensity: Number by properties.number(INTENSITY_KEY) { 2.0 }
public companion object { public companion object {
public val INTENSITY_KEY: Name = "intensity".asName() public val INTENSITY_KEY: Name = "intensity".asName()

@ -1,6 +1,9 @@
@file:UseSerializers(Float32Space2D.VectorSerializer::class)
package space.kscience.visionforge.solid package space.kscience.visionforge.solid
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.UseSerializers
import space.kscience.kmath.geometry.euclidean2d.Float32Space2D
import space.kscience.kmath.geometry.euclidean2d.Float32Vector2D import space.kscience.kmath.geometry.euclidean2d.Float32Vector2D
import kotlin.math.PI import kotlin.math.PI
import kotlin.math.cos import kotlin.math.cos

@ -10,6 +10,9 @@ kscience {
binaries.library() binaries.library()
browser { browser {
webpackTask{ webpackTask{
cssSupport {
enabled = true
}
scssSupport { scssSupport {
enabled = true enabled = true
} }
@ -23,8 +26,8 @@ kscience {
api("space.kscience:tables-kt:${tablesVersion}") api("space.kscience:tables-kt:${tablesVersion}")
} }
jsMain { jsMain {
api(npm("tabulator-tables", "5.5.2")) api(npm("tabulator-tables", "6.3.1"))
api(npm("@types/tabulator-tables", "5.5.3")) api(npm("@types/tabulator-tables", "6.2.3"))
} }
} }

@ -25,7 +25,7 @@ kscience {
// api(npm("@types/file-saver", "2.0.7")) // api(npm("@types/file-saver", "2.0.7"))
implementation(npm("three", "0.173.0")) implementation(npm("three", "0.173.0"))
implementation(npm("three-csg-ts", "3.2.0")) implementation(npm("three-csg-ts", "3.2.0"))
implementation(npm("three.meshline", "1.4.0")) implementation(npm("meshline", "3.3.1"))
} }
} }

@ -8,8 +8,13 @@ import org.w3c.dom.Node
import org.w3c.dom.events.MouseEvent import org.w3c.dom.events.MouseEvent
import space.kscience.dataforge.context.info import space.kscience.dataforge.context.info
import space.kscience.dataforge.context.logger import space.kscience.dataforge.context.logger
import space.kscience.dataforge.meta.* import space.kscience.dataforge.meta.get
import space.kscience.dataforge.names.* import space.kscience.dataforge.meta.isEmpty
import space.kscience.dataforge.meta.string
import space.kscience.dataforge.meta.useProperty
import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.asName
import space.kscience.dataforge.names.plus
import space.kscience.visionforge.Colors import space.kscience.visionforge.Colors
import space.kscience.visionforge.solid.Solid import space.kscience.visionforge.solid.Solid
import space.kscience.visionforge.solid.specifications.* import space.kscience.visionforge.solid.specifications.*
@ -21,7 +26,10 @@ import three.external.controls.OrbitControls
import three.external.controls.TrackballControls import three.external.controls.TrackballControls
import three.geometries.EdgesGeometry import three.geometries.EdgesGeometry
import three.materials.Material import three.materials.Material
import three.math.* import three.math.Box3
import three.math.Plane
import three.math.Vector2
import three.math.Vector3
import three.meshline.MeshLine import three.meshline.MeshLine
import three.meshline.MeshLineMaterial import three.meshline.MeshLineMaterial
import three.meshline.isMeshLineMaterial import three.meshline.isMeshLineMaterial
@ -104,10 +112,6 @@ public class ThreeCanvas(
camera.updateProjectionMatrix() camera.updateProjectionMatrix()
} }
/**
* Attach canvas to given [HTMLElement]
*/
init { init {
check(element.getElementsByClassName("three-canvas").length == 0) { check(element.getElementsByClassName("three-canvas").length == 0) {
"Three canvas already created in this element" "Three canvas already created in this element"
@ -311,13 +315,13 @@ public class ThreeCanvas(
public companion object { public companion object {
public val SELECTED_MATERIAL: MeshLineMaterial = MeshLineMaterial().apply { public val SELECTED_MATERIAL: MeshLineMaterial = MeshLineMaterial().apply {
color.set(Colors.ivory) color.set(Colors.ivory)
thickness = 2f lineWidth = 2f
cached = true cached = true
} }
public val HIGHLIGHT_MATERIAL: MeshLineMaterial = MeshLineMaterial().apply { public val HIGHLIGHT_MATERIAL: MeshLineMaterial = MeshLineMaterial().apply {
color.set(Colors.blue) color.set(Colors.blue)
thickness = 1f lineWidth = 1f
cached = true cached = true
} }
// //

@ -23,7 +23,7 @@ public object ThreeMeshLineFactory : ThreeFactory<PolyLine> {
) )
val material = MeshLineMaterial().apply { val material = MeshLineMaterial().apply {
thickness = vision.thickness.toFloat() lineWidth = vision.thickness.toFloat()
color = vision.color.string?.let { Color(it) } ?: ThreeMaterials.DEFAULT_LINE_COLOR color = vision.color.string?.let { Color(it) } ?: ThreeMaterials.DEFAULT_LINE_COLOR
} }

@ -11,7 +11,7 @@ public object ThreeSmartLineFactory : ThreeFactory<PolyLine> {
three: ThreePlugin, three: ThreePlugin,
vision: PolyLine, vision: PolyLine,
observe: Boolean, observe: Boolean,
): Object3D = if (vision.thickness == 1.0) { ): Object3D = if (vision.thickness == PolyLine.DEFAULT_THICKNESS) {
ThreeLineFactory.build(three, vision, observe) ThreeLineFactory.build(three, vision, observe)
} else { } else {
ThreeMeshLineFactory.build(three, vision, observe) ThreeMeshLineFactory.build(three, vision, observe)

@ -1,4 +1,4 @@
@file:JsModule("three.meshline") @file:JsModule("meshline")
package three.meshline package three.meshline
@ -6,6 +6,7 @@ package three.meshline
import three.core.BufferGeometry import three.core.BufferGeometry
import three.materials.ShaderMaterial import three.materials.ShaderMaterial
import three.math.Color import three.math.Color
import three.math.Vector2
import three.math.Vector3 import three.math.Vector3
import three.textures.Texture import three.textures.Texture
@ -13,25 +14,25 @@ import three.textures.Texture
* https://github.com/spite/THREE.MeshLine * https://github.com/spite/THREE.MeshLine
*/ */
public external class MeshLine : BufferGeometry { public external class MeshLineGeometry : BufferGeometry {
public fun setGeometry(geometry: BufferGeometry) // public fun setGeometry(geometry: BufferGeometry)
public fun setPoints(points: Array<Vector3>) public fun setPoints(points: Array<Vector3>)
} }
public external class MeshLineMaterial : ShaderMaterial { public external class MeshLineMaterial : ShaderMaterial {
@JsName("lineWidth") public var lineWidth: Float
public var thickness: Float
public var color: Color public var color: Color
public var map: Texture? public var map: Texture?
public var useMap: Boolean public var useMap: Float
public var alphaMap: Texture? public var alphaMap: Texture?
public var useAlphaMap: Boolean public var useAlphaMap: Float
public var gradient: Array<Color>
public var repeat: dynamic // - THREE.Vector2 to define the texture tiling (applies to map and alphaMap - MIGHT CHANGE IN THE FUTURE) public var repeat: Vector2 // - THREE.Vector2 to define the texture tiling (applies to map and alphaMap - MIGHT CHANGE IN THE FUTURE)
public var dashArray: dynamic //- the length and space between dashes. (0 - no dash) public var dashArray: Float //- the length and space between dashes. (0 - no dash)
public var dashOffset: dynamic // - defines the location where the dash will begin. Ideal to animate the line. public var dashOffset: dynamic // - defines the location where the dash will begin. Ideal to animate the line.
public var dashRatio: dynamic // - defines the ratio between that is visible or not (0 - more visible, 1 - more invisible). public var dashRatio: dynamic // - defines the ratio between that is visible or not (0 - more visible, 1 - more invisible).
public var resolution: dynamic // - THREE.Vector2 specifying the canvas size (REQUIRED) public var resolution: Vector2 // - THREE.Vector2 specifying the canvas size (REQUIRED)
public var sizeAttenuation: Int // - makes the line width constant regardless distance (1 unit is 1px on screen) (0 - attenuate, 1 - don't attenuate) public var sizeAttenuation: Int // - makes the line width constant regardless distance (1 unit is 1px on screen) (0 - attenuate, 1 - don't attenuate)
} }

@ -4,8 +4,8 @@ import three.core.BufferGeometry
import three.materials.Material import three.materials.Material
import three.math.Vector3 import three.math.Vector3
public fun MeshLine(geometry: BufferGeometry): MeshLine = MeshLine().apply { setGeometry(geometry) } public fun MeshLine(geometry: BufferGeometry): MeshLineGeometry = MeshLineGeometry().apply { copy(geometry) }
public fun MeshLine(points: Array<Vector3>): MeshLine = MeshLine().apply { setPoints(points) } public fun MeshLine(points: Array<Vector3>): MeshLineGeometry = MeshLineGeometry().apply { setPoints(points) }
internal fun isMeshLineMaterial(material: Material): Boolean = material.asDynamic().isMeshLineMaterial == true internal fun isMeshLineMaterial(material: Material): Boolean = material.asDynamic().isMeshLineMaterial == true