forked from kscience/visionforge
initial commit
This commit is contained in:
commit
4db090c240
10
.gitignore
vendored
Normal file
10
.gitignore
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
.idea/
|
||||||
|
*.iws
|
||||||
|
out/
|
||||||
|
.gradle
|
||||||
|
build/
|
||||||
|
|
||||||
|
|
||||||
|
!gradle-wrapper.jar
|
||||||
|
gradle.properties
|
145
build.gradle.kts
Normal file
145
build.gradle.kts
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
|
||||||
|
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||||
|
|
||||||
|
buildscript {
|
||||||
|
val kotlinVersion: String by rootProject.extra("1.3.21")
|
||||||
|
val ioVersion: String by rootProject.extra("0.1.5")
|
||||||
|
val coroutinesVersion: String by rootProject.extra("1.1.1")
|
||||||
|
val atomicfuVersion: String by rootProject.extra("0.12.1")
|
||||||
|
val dokkaVersion: String by rootProject.extra("0.9.17")
|
||||||
|
val serializationVersion: String by rootProject.extra("0.10.0")
|
||||||
|
|
||||||
|
val dataforgeVersion: String by rootProject.extra("0.1.1-dev-5")
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
jcenter()
|
||||||
|
maven("https://dl.bintray.com/kotlin/kotlin-eap")
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion")
|
||||||
|
classpath("org.jfrog.buildinfo:build-info-extractor-gradle:4+")
|
||||||
|
classpath("com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.4")
|
||||||
|
classpath("org.jetbrains.dokka:dokka-gradle-plugin:$dokkaVersion")
|
||||||
|
classpath("org.jetbrains.kotlin:kotlin-frontend-plugin:0.0.45")
|
||||||
|
classpath("org.openjfx:javafx-plugin:0.0.7")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
id("com.jfrog.artifactory") version "4.8.1" apply false
|
||||||
|
// id("org.jetbrains.kotlin.multiplatform") apply false
|
||||||
|
}
|
||||||
|
|
||||||
|
allprojects {
|
||||||
|
apply(plugin = "maven")
|
||||||
|
apply(plugin = "maven-publish")
|
||||||
|
apply(plugin = "com.jfrog.artifactory")
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
jcenter()
|
||||||
|
maven("https://kotlin.bintray.com/kotlinx")
|
||||||
|
maven("http://npm.mipt.ru:8081/artifactory/gradle-dev")
|
||||||
|
}
|
||||||
|
|
||||||
|
group = "hep.dataforge"
|
||||||
|
version = "0.0.1-dev-1"
|
||||||
|
|
||||||
|
// apply bintray configuration
|
||||||
|
apply(from = "${rootProject.rootDir}/gradle/bintray.gradle")
|
||||||
|
|
||||||
|
//apply artifactory configuration
|
||||||
|
apply(from = "${rootProject.rootDir}/gradle/artifactory.gradle")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
subprojects {
|
||||||
|
|
||||||
|
// dokka {
|
||||||
|
// outputFormat = "html"
|
||||||
|
// outputDirectory = javadoc.destinationDir
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// task dokkaJar (type: Jar, dependsOn: dokka) {
|
||||||
|
// from javadoc . destinationDir
|
||||||
|
// classifier = "javadoc"
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Create empty jar for sources classifier to satisfy maven requirements
|
||||||
|
val stubSources by tasks.registering(Jar::class) {
|
||||||
|
archiveClassifier.set("sources")
|
||||||
|
//from(sourceSets.main.get().allSource)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create empty jar for javadoc classifier to satisfy maven requirements
|
||||||
|
val stubJavadoc by tasks.registering(Jar::class) {
|
||||||
|
archiveClassifier.set("javadoc")
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.withType<KotlinCompile> {
|
||||||
|
kotlinOptions {
|
||||||
|
jvmTarget = "1.8"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
afterEvaluate {
|
||||||
|
extensions.findByType<KotlinMultiplatformExtension>()?.apply {
|
||||||
|
jvm {
|
||||||
|
compilations.all {
|
||||||
|
kotlinOptions {
|
||||||
|
jvmTarget = "1.8"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
js {
|
||||||
|
compilations.all {
|
||||||
|
tasks.getByName(compileKotlinTaskName) {
|
||||||
|
kotlinOptions {
|
||||||
|
metaInfo = true
|
||||||
|
sourceMap = true
|
||||||
|
sourceMapEmbedSources = "always"
|
||||||
|
moduleKind = "umd"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
configure(listOf(compilations["main"])) {
|
||||||
|
tasks.getByName(compileKotlinTaskName) {
|
||||||
|
kotlinOptions {
|
||||||
|
main = "call"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
targets.all {
|
||||||
|
sourceSets.all {
|
||||||
|
languageSettings.progressiveMode = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
configure<PublishingExtension> {
|
||||||
|
|
||||||
|
publications.filterIsInstance<MavenPublication>().forEach { publication ->
|
||||||
|
if (publication.name == "kotlinMultiplatform") {
|
||||||
|
// for our root metadata publication, set artifactId with a package and project name
|
||||||
|
publication.artifactId = project.name
|
||||||
|
} else {
|
||||||
|
// for targets, set artifactId with a package, project name and target name (e.g. iosX64)
|
||||||
|
publication.artifactId = "${project.name}-${publication.name}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
targets.all {
|
||||||
|
val publication = publications.findByName(name) as MavenPublication
|
||||||
|
|
||||||
|
// Patch publications with fake javadoc
|
||||||
|
publication.artifact(stubJavadoc.get())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
30
dataforge-vis-common/build.gradle.kts
Normal file
30
dataforge-vis-common/build.gradle.kts
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
plugins {
|
||||||
|
kotlin("multiplatform")
|
||||||
|
}
|
||||||
|
|
||||||
|
val dataforgeVersion: String by rootProject.extra
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
jvm()
|
||||||
|
js()
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
val commonMain by getting {
|
||||||
|
dependencies {
|
||||||
|
api("hep.dataforge:dataforge-io:$dataforgeVersion")
|
||||||
|
api("hep.dataforge:dataforge-io-metadata:$dataforgeVersion")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val jvmMain by getting {
|
||||||
|
dependencies {
|
||||||
|
api("hep.dataforge:dataforge-io-jvm:$dataforgeVersion")
|
||||||
|
//api("no.tornado:tornadofx:1.7.18")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val jsMain by getting {
|
||||||
|
dependencies {
|
||||||
|
api("hep.dataforge:dataforge-io-js:$dataforgeVersion")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,150 @@
|
|||||||
|
package hep.dataforge.vis
|
||||||
|
|
||||||
|
import hep.dataforge.meta.*
|
||||||
|
import hep.dataforge.names.Name
|
||||||
|
import hep.dataforge.names.toName
|
||||||
|
import hep.dataforge.vis.DisplayObject.Companion.DEFAULT_TYPE
|
||||||
|
import hep.dataforge.vis.DisplayObject.Companion.META_KEY
|
||||||
|
import hep.dataforge.vis.DisplayObject.Companion.TAGS_KEY
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A root type for display hierarchy
|
||||||
|
*/
|
||||||
|
interface DisplayObject {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The parent object of this one. If null, this one is a root.
|
||||||
|
*/
|
||||||
|
val parent: DisplayObject?
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of this object. Uses `.` notation. Empty type means untyped group
|
||||||
|
*/
|
||||||
|
val type: String
|
||||||
|
|
||||||
|
val properties: Styled
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val DEFAULT_TYPE = ""
|
||||||
|
const val TYPE_KEY = "@type"
|
||||||
|
const val CHILDREN_KEY = "@children"
|
||||||
|
const val META_KEY = "@meta"
|
||||||
|
const val TAGS_KEY = "@tags"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DisplayGroup : DisplayObject {
|
||||||
|
|
||||||
|
val children: List<DisplayObject>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a child object and notify listeners
|
||||||
|
*/
|
||||||
|
fun addChild(obj: DisplayObject)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a specific child and notify listeners
|
||||||
|
*/
|
||||||
|
fun removeChild(obj: DisplayObject)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add listener for children change
|
||||||
|
* TODO add detailed information into change listener
|
||||||
|
*/
|
||||||
|
fun onChildrenChange(owner: Any? = null, action: () -> Unit)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove children change listener
|
||||||
|
*/
|
||||||
|
fun removeChildrenChangeListener(owner: Any? = null)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the property of this display object of parent's if not found
|
||||||
|
*/
|
||||||
|
tailrec operator fun DisplayObject.get(name: Name): MetaItem<*>? = properties[name] ?: parent?.get(name)
|
||||||
|
|
||||||
|
operator fun DisplayObject.get(name: String) = get(name.toName())
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A change listener for [DisplayObject] configuration.
|
||||||
|
*/
|
||||||
|
fun DisplayObject.onChange(owner: Any?, action: (Name, before: MetaItem<*>?, after: MetaItem<*>?) -> Unit) {
|
||||||
|
properties.style.onChange(owner, action)
|
||||||
|
parent?.onChange(owner, action)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove all meta listeners with matching owners
|
||||||
|
*/
|
||||||
|
fun DisplayObject.removeChangeListener(owner: Any?) {
|
||||||
|
properties.style.removeListener(owner)
|
||||||
|
parent?.removeChangeListener(owner)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Additional meta not relevant to display
|
||||||
|
*/
|
||||||
|
val DisplayObject.meta: Meta get() = properties[META_KEY]?.node ?: EmptyMeta
|
||||||
|
|
||||||
|
val DisplayObject.tags: List<String> get() = properties[TAGS_KEY].stringList
|
||||||
|
|
||||||
|
internal data class ObjectListener(
|
||||||
|
val owner: Any?,
|
||||||
|
val action: () -> Unit
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Basic group of display objects
|
||||||
|
*/
|
||||||
|
open class DisplayNode(
|
||||||
|
override val parent: DisplayObject? = null,
|
||||||
|
override val type: String = DEFAULT_TYPE,
|
||||||
|
meta: Meta = EmptyMeta
|
||||||
|
) : DisplayGroup {
|
||||||
|
|
||||||
|
private val _children = ArrayList<DisplayObject>()
|
||||||
|
override val children: List<DisplayObject> get() = _children
|
||||||
|
override val properties = Styled(meta)
|
||||||
|
private val listeners = HashSet<ObjectListener>()
|
||||||
|
|
||||||
|
override fun addChild(obj: DisplayObject) {
|
||||||
|
// val before = _children[name]
|
||||||
|
// if (obj == null) {
|
||||||
|
// _children.remove(name)
|
||||||
|
// } else {
|
||||||
|
// _children[name] = obj
|
||||||
|
// }
|
||||||
|
// listeners.forEach { it.action(name, before, obj) }
|
||||||
|
_children.add(obj)
|
||||||
|
listeners.forEach { it.action() }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun removeChild(obj: DisplayObject) {
|
||||||
|
if (_children.remove(obj)) {
|
||||||
|
listeners.forEach { it.action }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onChildrenChange(owner: Any?, action: () -> Unit) {
|
||||||
|
listeners.add(ObjectListener(owner, action))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun removeChildrenChangeListener(owner: Any?) {
|
||||||
|
listeners.removeAll { it.owner === owner }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Basic [DisplayObject] leaf element
|
||||||
|
*/
|
||||||
|
open class DisplayLeaf(
|
||||||
|
override val parent: DisplayObject?,
|
||||||
|
override val type: String,
|
||||||
|
meta: Meta = EmptyMeta
|
||||||
|
) : DisplayObject {
|
||||||
|
final override val properties = Styled(meta)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,120 @@
|
|||||||
|
package hep.dataforge.vis
|
||||||
|
|
||||||
|
import hep.dataforge.meta.*
|
||||||
|
import hep.dataforge.names.Name
|
||||||
|
import hep.dataforge.names.toName
|
||||||
|
import hep.dataforge.values.Value
|
||||||
|
import kotlin.jvm.JvmName
|
||||||
|
import kotlin.properties.ReadOnlyProperty
|
||||||
|
import kotlin.properties.ReadWriteProperty
|
||||||
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A delegate for display object properties
|
||||||
|
*/
|
||||||
|
class DisplayObjectDelegate(
|
||||||
|
val key: Name?,
|
||||||
|
val default: MetaItem<*>?,
|
||||||
|
val inherited: Boolean
|
||||||
|
) : ReadWriteProperty<DisplayObject, MetaItem<*>?> {
|
||||||
|
override fun getValue(thisRef: DisplayObject, property: KProperty<*>): MetaItem<*>? {
|
||||||
|
val name = key ?: property.name.toName()
|
||||||
|
return if (inherited) {
|
||||||
|
thisRef[name]
|
||||||
|
} else {
|
||||||
|
thisRef.properties[name]
|
||||||
|
} ?: default
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setValue(thisRef: DisplayObject, property: KProperty<*>, value: MetaItem<*>?) {
|
||||||
|
val name = key ?: property.name.toName()
|
||||||
|
thisRef.properties.style[name] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DisplayObjectDelegateWrapper<T>(
|
||||||
|
val key: Name?,
|
||||||
|
val default: T,
|
||||||
|
val inherited: Boolean,
|
||||||
|
val write: Config.(name: Name, value: T) -> Unit = { name, value -> set(name, value) },
|
||||||
|
val read: (MetaItem<*>?) -> T?
|
||||||
|
) : ReadWriteProperty<DisplayObject, T> {
|
||||||
|
override fun getValue(thisRef: DisplayObject, property: KProperty<*>): T {
|
||||||
|
val name = key ?: property.name.toName()
|
||||||
|
return if (inherited) {
|
||||||
|
read(thisRef[name])
|
||||||
|
} else {
|
||||||
|
read(thisRef.properties[name])
|
||||||
|
} ?: default
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setValue(thisRef: DisplayObject, property: KProperty<*>, value: T) {
|
||||||
|
val name = key ?: property.name.toName()
|
||||||
|
thisRef.properties.style.write(name, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun DisplayObject.value(default: Value? = null, key: String? = null, inherited: Boolean = true) =
|
||||||
|
DisplayObjectDelegateWrapper(key?.toName(), default, inherited) { it.value }
|
||||||
|
|
||||||
|
fun DisplayObject.string(default: String? = null, key: String? = null, inherited: Boolean = true) =
|
||||||
|
DisplayObjectDelegateWrapper(key?.toName(), default, inherited) { it.string }
|
||||||
|
|
||||||
|
fun DisplayObject.boolean(default: Boolean? = null, key: String? = null, inherited: Boolean = true) =
|
||||||
|
DisplayObjectDelegateWrapper(key?.toName(), default, inherited) { it.boolean }
|
||||||
|
|
||||||
|
fun DisplayObject.number(default: Number? = null, key: String? = null, inherited: Boolean = true) =
|
||||||
|
DisplayObjectDelegateWrapper(key?.toName(), default, inherited) { it.number }
|
||||||
|
|
||||||
|
fun DisplayObject.double(default: Double? = null, key: String? = null, inherited: Boolean = true) =
|
||||||
|
DisplayObjectDelegateWrapper(key?.toName(), default, inherited) { it.double }
|
||||||
|
|
||||||
|
fun DisplayObject.int(default: Int? = null, key: String? = null, inherited: Boolean = true) =
|
||||||
|
DisplayObjectDelegateWrapper(key?.toName(), default, inherited) { it.int }
|
||||||
|
|
||||||
|
|
||||||
|
fun DisplayObject.node(key: String? = null, inherited: Boolean = true) =
|
||||||
|
DisplayObjectDelegateWrapper(key?.toName(), null, inherited) { it.node }
|
||||||
|
|
||||||
|
//fun <T : Configurable> Configurable.spec(spec: Specification<T>, key: String? = null) = ChildConfigDelegate<T>(key) { spec.wrap(this) }
|
||||||
|
|
||||||
|
@JvmName("safeString")
|
||||||
|
fun DisplayObject.string(default: String, key: String? = null, inherited: Boolean = true) =
|
||||||
|
DisplayObjectDelegateWrapper(key?.toName(), default, inherited) { it.string }
|
||||||
|
|
||||||
|
@JvmName("safeBoolean")
|
||||||
|
fun DisplayObject.boolean(default: Boolean, key: String? = null, inherited: Boolean = true) =
|
||||||
|
DisplayObjectDelegateWrapper(key?.toName(), default, inherited) { it.boolean }
|
||||||
|
|
||||||
|
@JvmName("safeNumber")
|
||||||
|
fun DisplayObject.number(default: Number, key: String? = null, inherited: Boolean = true) =
|
||||||
|
DisplayObjectDelegateWrapper(key?.toName(), default, inherited) { it.number }
|
||||||
|
|
||||||
|
@JvmName("safeDouble")
|
||||||
|
fun DisplayObject.double(default: Double, key: String? = null, inherited: Boolean = true) =
|
||||||
|
DisplayObjectDelegateWrapper(key?.toName(), default, inherited) { it.double }
|
||||||
|
|
||||||
|
inline fun <reified E : Enum<E>> DisplayObject.enum(default: E, key: String? = null, inherited: Boolean = true) =
|
||||||
|
DisplayObjectDelegateWrapper(key?.toName(), default, inherited) { item -> item.string?.let { enumValueOf<E>(it) } }
|
||||||
|
|
||||||
|
//merge properties
|
||||||
|
|
||||||
|
fun <T> DisplayObject.merge(
|
||||||
|
key: String? = null,
|
||||||
|
transformer: (Sequence<MetaItem<*>>) -> T
|
||||||
|
): ReadOnlyProperty<DisplayObject, T> {
|
||||||
|
return object : ReadOnlyProperty<DisplayObject, T> {
|
||||||
|
override fun getValue(thisRef: DisplayObject, property: KProperty<*>): T {
|
||||||
|
val name = key?.toName() ?: property.name.toName()
|
||||||
|
val sequence = sequence<MetaItem<*>> {
|
||||||
|
var thisObj: DisplayObject? = thisRef
|
||||||
|
while (thisObj != null) {
|
||||||
|
thisObj.properties[name]?.let { yield(it) }
|
||||||
|
thisObj = thisObj.parent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return transformer(sequence)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
package hep.dataforge.vis
|
||||||
|
|
||||||
|
import hep.dataforge.names.Name
|
||||||
|
import hep.dataforge.names.NameToken
|
||||||
|
|
||||||
|
interface NamedObject : DisplayObject {
|
||||||
|
val name: String
|
||||||
|
|
||||||
|
operator fun get(nameToken: NameToken): DisplayGroup?
|
||||||
|
|
||||||
|
operator fun set(nameToken: NameToken, group: DisplayGroup)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively get a child
|
||||||
|
*/
|
||||||
|
tailrec operator fun NamedObject.get(name: Name): DisplayObject? = when (name.length) {
|
||||||
|
0 -> this
|
||||||
|
1 -> this[name[0]]
|
||||||
|
else -> name.first()?.let { this[it] as? NamedObject }?.get(name.cutFirst())
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set given object creating intermediate empty groups if needed
|
||||||
|
* @param name - the full name of a child
|
||||||
|
* @param objFactory - a function that creates child object from parent (to avoid mutable parent parameter)
|
||||||
|
*/
|
||||||
|
fun NamedObject.set(name: Name, objFactory: (parent: DisplayObject) -> DisplayGroup): Unit = when (name.length) {
|
||||||
|
0 -> error("Can't set object with empty name")
|
||||||
|
1 -> set(name[0], objFactory(this))
|
||||||
|
else -> (this[name.first()!!] ?: DisplayNode(this))
|
||||||
|
.run {
|
||||||
|
if (this is NamedObject) {
|
||||||
|
this.set(name.cutFirst(), objFactory)
|
||||||
|
} else {
|
||||||
|
error("Can't assign child to a leaf element $this")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
16
dataforge-vis-spatial-fx/build.gradle.kts
Normal file
16
dataforge-vis-spatial-fx/build.gradle.kts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import org.openjfx.gradle.JavaFXOptions
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
kotlin("jvm")
|
||||||
|
id("org.openjfx.javafxplugin")
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
api(project(":dataforge-vis-spatial"))
|
||||||
|
api("no.tornado:tornadofx:1.7.18")
|
||||||
|
implementation("org.fxyz3d:fxyz3d:0.4.0")
|
||||||
|
}
|
||||||
|
|
||||||
|
configure<JavaFXOptions> {
|
||||||
|
modules("javafx.controls")
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
package hep.dataforge.vis
|
||||||
|
|
||||||
|
import hep.dataforge.meta.*
|
||||||
|
import hep.dataforge.names.Name
|
||||||
|
import hep.dataforge.names.toName
|
||||||
|
import javafx.beans.binding.ObjectBinding
|
||||||
|
import tornadofx.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A caching binding collection for [DisplayObject] properties
|
||||||
|
*/
|
||||||
|
class DisplayObjectFXListener(val obj: DisplayObject) {
|
||||||
|
private val binndings = HashMap<Name, ObjectBinding<MetaItem<*>?>>()
|
||||||
|
|
||||||
|
init {
|
||||||
|
obj.onChange(this) { name, _, _ ->
|
||||||
|
binndings[name]?.invalidate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun get(key: Name): ObjectBinding<MetaItem<*>?> {
|
||||||
|
return binndings.getOrPut(key) {
|
||||||
|
object : ObjectBinding<MetaItem<*>?>() {
|
||||||
|
override fun computeValue(): MetaItem<*>? = obj.get(key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun get(key: String) = get(key.toName())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun ObjectBinding<MetaItem<*>?>.value() = this.objectBinding { it.value }
|
||||||
|
fun ObjectBinding<MetaItem<*>?>.string() = this.stringBinding { it.string }
|
||||||
|
fun ObjectBinding<MetaItem<*>?>.number() = this.objectBinding { it.number }
|
||||||
|
fun ObjectBinding<MetaItem<*>?>.double() = this.objectBinding { it.double }
|
||||||
|
fun ObjectBinding<MetaItem<*>?>.float() = this.objectBinding { it.number?.toFloat() }
|
||||||
|
fun ObjectBinding<MetaItem<*>?>.int() = this.objectBinding { it.int }
|
||||||
|
fun ObjectBinding<MetaItem<*>?>.long() = this.objectBinding { it.long }
|
||||||
|
fun ObjectBinding<MetaItem<*>?>.node() = this.objectBinding { it.node }
|
||||||
|
|
||||||
|
fun <T> ObjectBinding<MetaItem<*>?>.transform(transform: (MetaItem<*>) -> T) = this.objectBinding { it?.let(transform) }
|
@ -0,0 +1,166 @@
|
|||||||
|
package hep.dataforge.vis.spatial
|
||||||
|
|
||||||
|
import hep.dataforge.vis.spatial.World.CAMERA_FAR_CLIP
|
||||||
|
import hep.dataforge.vis.spatial.World.CAMERA_INITIAL_DISTANCE
|
||||||
|
import hep.dataforge.vis.spatial.World.CAMERA_INITIAL_X_ANGLE
|
||||||
|
import hep.dataforge.vis.spatial.World.CAMERA_INITIAL_Y_ANGLE
|
||||||
|
import hep.dataforge.vis.spatial.World.CAMERA_INITIAL_Z_ANGLE
|
||||||
|
import hep.dataforge.vis.spatial.World.CAMERA_NEAR_CLIP
|
||||||
|
import javafx.event.EventHandler
|
||||||
|
import javafx.scene.*
|
||||||
|
import javafx.scene.input.KeyCode
|
||||||
|
import javafx.scene.input.KeyEvent
|
||||||
|
import javafx.scene.input.MouseEvent
|
||||||
|
import javafx.scene.input.ScrollEvent
|
||||||
|
import javafx.scene.paint.Color
|
||||||
|
import org.fxyz3d.utils.CameraTransformer
|
||||||
|
import tornadofx.*
|
||||||
|
|
||||||
|
class Canvas3D : Fragment() {
|
||||||
|
val world: Group = Group()
|
||||||
|
|
||||||
|
private val camera = PerspectiveCamera().apply {
|
||||||
|
nearClip = CAMERA_NEAR_CLIP
|
||||||
|
farClip = CAMERA_FAR_CLIP
|
||||||
|
translateZ = CAMERA_INITIAL_DISTANCE
|
||||||
|
}
|
||||||
|
|
||||||
|
private val cameraShift = CameraTransformer().apply {
|
||||||
|
val cameraFlip = CameraTransformer()
|
||||||
|
cameraFlip.children.add(camera)
|
||||||
|
cameraFlip.setRotateZ(180.0)
|
||||||
|
children.add(cameraFlip)
|
||||||
|
}
|
||||||
|
|
||||||
|
val translationXProperty get() = cameraShift.t.xProperty()
|
||||||
|
var translateX by translationXProperty
|
||||||
|
val translationYProperty get() = cameraShift.t.yProperty()
|
||||||
|
var translateY by translationYProperty
|
||||||
|
val translationZProperty get() = cameraShift.t.zProperty()
|
||||||
|
var translateZ by translationZProperty
|
||||||
|
|
||||||
|
private val cameraRotation = CameraTransformer().apply {
|
||||||
|
children.add(cameraShift)
|
||||||
|
ry.angle = CAMERA_INITIAL_Y_ANGLE
|
||||||
|
rx.angle = CAMERA_INITIAL_X_ANGLE
|
||||||
|
rz.angle = CAMERA_INITIAL_Z_ANGLE
|
||||||
|
}
|
||||||
|
|
||||||
|
val rotationXProperty get() = cameraRotation.rx.angleProperty()
|
||||||
|
var angleX by rotationXProperty
|
||||||
|
val rotationYProperty get() = cameraRotation.ry.angleProperty()
|
||||||
|
var angleY by rotationYProperty
|
||||||
|
val rotationZProperty get() = cameraRotation.rz.angleProperty()
|
||||||
|
var angleZ by rotationZProperty
|
||||||
|
|
||||||
|
|
||||||
|
override val root =borderpane {
|
||||||
|
center = SubScene(
|
||||||
|
Group(world, cameraRotation).apply { DepthTest.ENABLE },
|
||||||
|
1024.0,
|
||||||
|
768.0,
|
||||||
|
true,
|
||||||
|
SceneAntialiasing.BALANCED
|
||||||
|
).apply {
|
||||||
|
fill = Color.GREY
|
||||||
|
this.camera = this@Canvas3D.camera
|
||||||
|
id = "canvas"
|
||||||
|
handleKeyboard(this)
|
||||||
|
handleMouse(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun handleKeyboard(scene: SubScene) {
|
||||||
|
scene.onKeyPressed = EventHandler<KeyEvent> { event ->
|
||||||
|
if (event.isControlDown) {
|
||||||
|
when (event.code) {
|
||||||
|
KeyCode.Z -> {
|
||||||
|
cameraShift.t.x = 0.0
|
||||||
|
cameraShift.t.y = 0.0
|
||||||
|
camera.translateZ = CAMERA_INITIAL_DISTANCE
|
||||||
|
cameraRotation.ry.angle = CAMERA_INITIAL_Y_ANGLE
|
||||||
|
cameraRotation.rx.angle = CAMERA_INITIAL_X_ANGLE
|
||||||
|
}
|
||||||
|
// KeyCode.X -> axisGroup.isVisible = !axisGroup.isVisible
|
||||||
|
// KeyCode.S -> snapshot()
|
||||||
|
// KeyCode.DIGIT1 -> pixelMap.filterKeys { it.getLayerNumber() == 1 }.values.forEach {
|
||||||
|
// toggleTransparency(
|
||||||
|
// it
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
// KeyCode.DIGIT2 -> pixelMap.filterKeys { it.getLayerNumber() == 2 }.values.forEach {
|
||||||
|
// toggleTransparency(
|
||||||
|
// it
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
// KeyCode.DIGIT3 -> pixelMap.filterKeys { it.getLayerNumber() == 3 }.values.forEach {
|
||||||
|
// toggleTransparency(
|
||||||
|
// it
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
else -> {
|
||||||
|
}//do nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleMouse(scene: SubScene) {
|
||||||
|
|
||||||
|
var mousePosX: Double = 0.0
|
||||||
|
var mousePosY: Double = 0.0
|
||||||
|
var mouseOldX: Double = 0.0
|
||||||
|
var mouseOldY: Double = 0.0
|
||||||
|
var mouseDeltaX: Double = 0.0
|
||||||
|
var mouseDeltaY: Double = 0.0
|
||||||
|
|
||||||
|
scene.onMousePressed = EventHandler<MouseEvent> { me ->
|
||||||
|
mousePosX = me.sceneX
|
||||||
|
mousePosY = me.sceneY
|
||||||
|
mouseOldX = me.sceneX
|
||||||
|
mouseOldY = me.sceneY
|
||||||
|
}
|
||||||
|
|
||||||
|
scene.onMouseDragged = EventHandler<MouseEvent> { me ->
|
||||||
|
mouseOldX = mousePosX
|
||||||
|
mouseOldY = mousePosY
|
||||||
|
mousePosX = me.sceneX
|
||||||
|
mousePosY = me.sceneY
|
||||||
|
mouseDeltaX = mousePosX - mouseOldX
|
||||||
|
mouseDeltaY = mousePosY - mouseOldY
|
||||||
|
|
||||||
|
val modifier = when {
|
||||||
|
me.isControlDown -> CONTROL_MULTIPLIER
|
||||||
|
me.isShiftDown -> SHIFT_MULTIPLIER
|
||||||
|
else -> 1.0
|
||||||
|
}
|
||||||
|
|
||||||
|
if (me.isPrimaryButtonDown) {
|
||||||
|
cameraRotation.rz.angle =
|
||||||
|
cameraRotation.rz.angle + mouseDeltaX * MOUSE_SPEED * modifier * ROTATION_SPEED
|
||||||
|
cameraRotation.rx.angle =
|
||||||
|
cameraRotation.rx.angle + mouseDeltaY * MOUSE_SPEED * modifier * ROTATION_SPEED
|
||||||
|
} else if (me.isSecondaryButtonDown) {
|
||||||
|
cameraShift.t.x = cameraShift.t.x + mouseDeltaX * MOUSE_SPEED * modifier * TRACK_SPEED
|
||||||
|
cameraShift.t.y = cameraShift.t.y + mouseDeltaY * MOUSE_SPEED * modifier * TRACK_SPEED
|
||||||
|
}
|
||||||
|
}
|
||||||
|
scene.onScroll = EventHandler<ScrollEvent> { event ->
|
||||||
|
val z = camera.translateZ
|
||||||
|
val newZ = z + MOUSE_SPEED * event.deltaY * RESIZE_SPEED
|
||||||
|
camera.translateZ = newZ
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val AXIS_LENGTH = 2000.0
|
||||||
|
private const val CONTROL_MULTIPLIER = 0.1
|
||||||
|
private const val SHIFT_MULTIPLIER = 10.0
|
||||||
|
private const val MOUSE_SPEED = 0.1
|
||||||
|
private const val ROTATION_SPEED = 2.0
|
||||||
|
private const val TRACK_SPEED = 6.0
|
||||||
|
private const val RESIZE_SPEED = 50.0
|
||||||
|
private const val LINE_WIDTH = 3.0
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
package hep.dataforge.vis.spatial
|
||||||
|
|
||||||
|
import hep.dataforge.context.Context
|
||||||
|
import hep.dataforge.io.Output
|
||||||
|
import hep.dataforge.meta.Meta
|
||||||
|
import hep.dataforge.vis.*
|
||||||
|
import javafx.scene.Group
|
||||||
|
import javafx.scene.Node
|
||||||
|
import org.fxyz3d.shapes.primitives.CuboidMesh
|
||||||
|
import tornadofx.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://github.com/miho/JCSG for operations
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class FX3DOutput(override val context: Context) : Output<DisplayObject> {
|
||||||
|
val canvas by lazy { Canvas3D() }
|
||||||
|
|
||||||
|
|
||||||
|
private fun buildNode(obj: DisplayObject): Node? {
|
||||||
|
val listener = DisplayObjectFXListener(obj)
|
||||||
|
val x = listener["pos.x"].float()
|
||||||
|
val y = listener["pos.y"].float()
|
||||||
|
val z = listener["pos.z"].float()
|
||||||
|
val center = objectBinding(x, y, z) {
|
||||||
|
org.fxyz3d.geometry.Point3D(x.value ?: 0f, y.value ?: 0f, z.value ?: 0f)
|
||||||
|
}
|
||||||
|
return when (obj) {
|
||||||
|
is DisplayGroup -> Group(obj.children.map { buildNode(it) }).apply {
|
||||||
|
this.translateXProperty().bind(x)
|
||||||
|
this.translateYProperty().bind(y)
|
||||||
|
this.translateZProperty().bind(z)
|
||||||
|
}
|
||||||
|
is Box -> CuboidMesh(obj.xSize, obj.ySize, obj.zSize).apply {
|
||||||
|
this.centerProperty().bind(center)
|
||||||
|
this.materialProperty().bind(listener["color"].transform { it.material() })
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
logger.error { "No renderer defined for ${obj::class}" }
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun render(obj: DisplayObject, meta: Meta) {
|
||||||
|
buildNode(obj)?.let { canvas.world.children.add(it) }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,69 @@
|
|||||||
|
package hep.dataforge.vis.spatial
|
||||||
|
|
||||||
|
import hep.dataforge.meta.MetaItem
|
||||||
|
import hep.dataforge.meta.double
|
||||||
|
import hep.dataforge.meta.get
|
||||||
|
import hep.dataforge.meta.int
|
||||||
|
import hep.dataforge.values.ValueType
|
||||||
|
import javafx.scene.paint.Color
|
||||||
|
import javafx.scene.paint.Material
|
||||||
|
import javafx.scene.paint.PhongMaterial
|
||||||
|
|
||||||
|
object Materials {
|
||||||
|
val RED = PhongMaterial().apply {
|
||||||
|
diffuseColor = Color.DARKRED
|
||||||
|
specularColor = Color.RED
|
||||||
|
}
|
||||||
|
|
||||||
|
val WHITE = PhongMaterial().apply {
|
||||||
|
diffuseColor = Color.WHITE
|
||||||
|
specularColor = Color.LIGHTBLUE
|
||||||
|
}
|
||||||
|
|
||||||
|
val GREY = PhongMaterial().apply {
|
||||||
|
diffuseColor = Color.DARKGREY
|
||||||
|
specularColor = Color.GREY
|
||||||
|
}
|
||||||
|
|
||||||
|
val BLUE = PhongMaterial(Color.BLUE)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Infer color based on meta item
|
||||||
|
*/
|
||||||
|
fun MetaItem<*>.color(): Color {
|
||||||
|
return when (this) {
|
||||||
|
is MetaItem.ValueItem -> if (this.value.type == ValueType.STRING) {
|
||||||
|
Color.web(this.value.string)
|
||||||
|
} else {
|
||||||
|
val int = value.number.toInt()
|
||||||
|
val red = int and 0x00ff0000 shr 16
|
||||||
|
val green = int and 0x0000ff00 shr 8
|
||||||
|
val blue = int and 0x000000ff
|
||||||
|
Color.rgb(red, green, blue)
|
||||||
|
}
|
||||||
|
is MetaItem.NodeItem -> {
|
||||||
|
Color.rgb(
|
||||||
|
node["red"]?.int ?: 0,
|
||||||
|
node["green"]?.int ?: 0,
|
||||||
|
node["blue"]?.int ?: 0,
|
||||||
|
node["opacity"]?.double ?: 1.0
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Infer FX material based on meta item
|
||||||
|
*/
|
||||||
|
fun MetaItem<*>?.material(): Material {
|
||||||
|
return when (this) {
|
||||||
|
null -> Materials.GREY
|
||||||
|
is MetaItem.ValueItem -> PhongMaterial(color())
|
||||||
|
is MetaItem.NodeItem -> PhongMaterial().apply {
|
||||||
|
(node["color"]?: this@material).let { diffuseColor = it.color() }
|
||||||
|
node["specularColor"]?.let { specularColor = it.color() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,64 @@
|
|||||||
|
package hep.dataforge.vis.spatial
|
||||||
|
|
||||||
|
import hep.dataforge.context.Global
|
||||||
|
import hep.dataforge.meta.number
|
||||||
|
import hep.dataforge.vis.DisplayGroup
|
||||||
|
import javafx.scene.Parent
|
||||||
|
import kotlinx.coroutines.GlobalScope
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.isActive
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import tornadofx.*
|
||||||
|
import kotlin.random.Random
|
||||||
|
|
||||||
|
|
||||||
|
class RendererDemoApp : App(RendererDemoView::class)
|
||||||
|
|
||||||
|
|
||||||
|
class RendererDemoView : View() {
|
||||||
|
val renderer = FX3DOutput(Global)
|
||||||
|
override val root: Parent = borderpane {
|
||||||
|
center = renderer.canvas.root
|
||||||
|
}
|
||||||
|
|
||||||
|
lateinit var group: DisplayGroup
|
||||||
|
|
||||||
|
init {
|
||||||
|
|
||||||
|
renderer.render {
|
||||||
|
group = group {
|
||||||
|
box {
|
||||||
|
xSize = 100.0
|
||||||
|
ySize = 100.0
|
||||||
|
zSize = 100.0
|
||||||
|
}
|
||||||
|
box {
|
||||||
|
x = 110.0
|
||||||
|
xSize = 100.0
|
||||||
|
ySize = 100.0
|
||||||
|
zSize = 100.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var color by group.properties.number(1530).int
|
||||||
|
|
||||||
|
GlobalScope.launch {
|
||||||
|
val random = Random(111)
|
||||||
|
while (isActive) {
|
||||||
|
delay(1000)
|
||||||
|
color = random.nextInt(0, Int.MAX_VALUE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
renderer.canvas.apply {
|
||||||
|
angleY = -30.0
|
||||||
|
angleX = -15.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
launch<RendererDemoApp>()
|
||||||
|
}
|
59
dataforge-vis-spatial-js/build.gradle.kts
Normal file
59
dataforge-vis-spatial-js/build.gradle.kts
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
import org.jetbrains.kotlin.gradle.frontend.KotlinFrontendExtension
|
||||||
|
import org.jetbrains.kotlin.gradle.frontend.npm.NpmExtension
|
||||||
|
import org.jetbrains.kotlin.gradle.frontend.webpack.WebPackExtension
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
id("kotlin2js")
|
||||||
|
id("kotlin-dce-js")
|
||||||
|
id("org.jetbrains.kotlin.frontend")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
api(project(":dataforge-vis-spatial"))
|
||||||
|
implementation("info.laht.threekt:threejs-wrapper:0.88-npm-1")
|
||||||
|
}
|
||||||
|
|
||||||
|
configure<KotlinFrontendExtension> {
|
||||||
|
downloadNodeJsVersion = "latest"
|
||||||
|
|
||||||
|
configure<NpmExtension> {
|
||||||
|
dependency("three")
|
||||||
|
dependency("three-orbitcontrols")
|
||||||
|
dependency("style-loader")
|
||||||
|
devDependency("karma")
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceMaps = true
|
||||||
|
|
||||||
|
bundle("webpack") {
|
||||||
|
this as WebPackExtension
|
||||||
|
bundleName = "main"
|
||||||
|
proxyUrl = "http://localhost:8080"
|
||||||
|
contentPath = file("src/main/web")
|
||||||
|
sourceMapEnabled = true
|
||||||
|
//mode = "production"
|
||||||
|
mode = "development"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks{
|
||||||
|
compileKotlin2Js{
|
||||||
|
kotlinOptions{
|
||||||
|
metaInfo = true
|
||||||
|
outputFile = "${project.buildDir.path}/js/${project.name}.js"
|
||||||
|
sourceMap = true
|
||||||
|
moduleKind = "umd"
|
||||||
|
main = "call"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
compileTestKotlin2Js{
|
||||||
|
kotlinOptions{
|
||||||
|
metaInfo = true
|
||||||
|
outputFile = "${project.buildDir.path}/js/${project.name}-test.js"
|
||||||
|
sourceMap = true
|
||||||
|
moduleKind = "umd"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
package hep.dataforge.vis.hmr
|
||||||
|
|
||||||
|
external val module: Module
|
||||||
|
|
||||||
|
external interface Module {
|
||||||
|
val hot: Hot?
|
||||||
|
}
|
||||||
|
|
||||||
|
external interface Hot {
|
||||||
|
val data: dynamic
|
||||||
|
|
||||||
|
fun accept()
|
||||||
|
fun accept(dependency: String, callback: () -> Unit)
|
||||||
|
fun accept(dependencies: Array<String>, callback: (updated: Array<String>) -> Unit)
|
||||||
|
|
||||||
|
fun dispose(callback: (data: dynamic) -> Unit)
|
||||||
|
}
|
||||||
|
|
||||||
|
external fun require(name: String): dynamic
|
@ -0,0 +1,50 @@
|
|||||||
|
package hep.dataforge.vis
|
||||||
|
|
||||||
|
import hep.dataforge.vis.hmr.module
|
||||||
|
import hep.dataforge.vis.spatial.ThreeDemoApp
|
||||||
|
import kotlin.browser.document
|
||||||
|
import kotlin.dom.hasClass
|
||||||
|
|
||||||
|
|
||||||
|
abstract class ApplicationBase {
|
||||||
|
abstract val stateKeys: List<String>
|
||||||
|
|
||||||
|
abstract fun start(state: Map<String, Any>)
|
||||||
|
abstract fun dispose(): Map<String, Any>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
var application: ApplicationBase? = null
|
||||||
|
|
||||||
|
val state: dynamic = module.hot?.let { hot ->
|
||||||
|
hot.accept()
|
||||||
|
|
||||||
|
hot.dispose { data ->
|
||||||
|
data.appState = application?.dispose()
|
||||||
|
application = null
|
||||||
|
}
|
||||||
|
|
||||||
|
hot.data
|
||||||
|
}
|
||||||
|
|
||||||
|
if (document.body != null) {
|
||||||
|
application = start(state)
|
||||||
|
} else {
|
||||||
|
application = null
|
||||||
|
document.addEventListener("DOMContentLoaded", { application = start(state) })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun start(state: dynamic): ApplicationBase? {
|
||||||
|
return if (document.body?.hasClass("testApp") == true) {
|
||||||
|
val application = ThreeDemoApp()
|
||||||
|
|
||||||
|
@Suppress("UnsafeCastFromDynamic")
|
||||||
|
application.start(state?.appState ?: emptyMap())
|
||||||
|
|
||||||
|
application
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,59 @@
|
|||||||
|
package hep.dataforge.vis.spatial
|
||||||
|
|
||||||
|
import hep.dataforge.meta.MetaItem
|
||||||
|
import hep.dataforge.meta.double
|
||||||
|
import hep.dataforge.meta.get
|
||||||
|
import hep.dataforge.meta.int
|
||||||
|
import hep.dataforge.values.ValueType
|
||||||
|
import info.laht.threekt.materials.Material
|
||||||
|
import info.laht.threekt.materials.MeshPhongMaterial
|
||||||
|
import info.laht.threekt.math.Color
|
||||||
|
import info.laht.threekt.math.ColorConstants
|
||||||
|
|
||||||
|
object Materials {
|
||||||
|
val DEFAULT = MeshPhongMaterial().apply {
|
||||||
|
this.color.set(ColorConstants.darkgreen)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Infer color based on meta item
|
||||||
|
*/
|
||||||
|
fun MetaItem<*>.color(): Color {
|
||||||
|
return when (this) {
|
||||||
|
is MetaItem.ValueItem -> if (this.value.type == ValueType.STRING) {
|
||||||
|
Color(this.value.string)
|
||||||
|
} else {
|
||||||
|
val int = value.number.toInt()
|
||||||
|
// val red = int and 0x00ff0000 shr 16
|
||||||
|
// val green = int and 0x0000ff00 shr 8
|
||||||
|
// val blue = int and 0x000000ff
|
||||||
|
Color(int)
|
||||||
|
}
|
||||||
|
is MetaItem.NodeItem -> {
|
||||||
|
Color(
|
||||||
|
node["red"]?.int ?: 0,
|
||||||
|
node["green"]?.int ?: 0,
|
||||||
|
node["blue"]?.int ?: 0
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Infer FX material based on meta item
|
||||||
|
*/
|
||||||
|
fun MetaItem<*>?.material(): Material {
|
||||||
|
return when (this) {
|
||||||
|
null -> Materials.DEFAULT
|
||||||
|
is MetaItem.ValueItem -> MeshPhongMaterial().apply {
|
||||||
|
color = this@material.color()
|
||||||
|
}
|
||||||
|
is MetaItem.NodeItem -> MeshPhongMaterial().apply {
|
||||||
|
(node["color"] ?: this@material).let { color = it.color() }
|
||||||
|
opacity = node["opacity"]?.double ?: 1.0
|
||||||
|
node["specularColor"]?.let { specular = it.color() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,66 @@
|
|||||||
|
package hep.dataforge.vis.spatial
|
||||||
|
|
||||||
|
import hep.dataforge.context.Global
|
||||||
|
import hep.dataforge.meta.number
|
||||||
|
import hep.dataforge.meta.set
|
||||||
|
import hep.dataforge.vis.ApplicationBase
|
||||||
|
import hep.dataforge.vis.DisplayGroup
|
||||||
|
import kotlinx.coroutines.GlobalScope
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.isActive
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlin.browser.document
|
||||||
|
import kotlin.random.Random
|
||||||
|
|
||||||
|
|
||||||
|
class ThreeDemoApp : ApplicationBase() {
|
||||||
|
|
||||||
|
override val stateKeys: List<String> = emptyList()
|
||||||
|
|
||||||
|
override fun start(state: Map<String, Any>) {
|
||||||
|
val renderer = ThreeOutput(Global)
|
||||||
|
renderer.start(document.getElementById("canvas")!!)
|
||||||
|
println("started")
|
||||||
|
|
||||||
|
lateinit var group: DisplayGroup
|
||||||
|
|
||||||
|
renderer.render {
|
||||||
|
group = group {
|
||||||
|
box {
|
||||||
|
xSize = 100.0
|
||||||
|
ySize = 100.0
|
||||||
|
zSize = 100.0
|
||||||
|
}
|
||||||
|
box {
|
||||||
|
x = 110.0
|
||||||
|
xSize = 100.0
|
||||||
|
ySize = 100.0
|
||||||
|
zSize = 100.0
|
||||||
|
properties.style["color"] = 1530
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var color by group.properties.number(1530).int
|
||||||
|
|
||||||
|
GlobalScope.launch {
|
||||||
|
val random = Random(111)
|
||||||
|
while (isActive) {
|
||||||
|
delay(1000)
|
||||||
|
color = random.nextInt(0, Int.MAX_VALUE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// view.animate()
|
||||||
|
|
||||||
|
// view = WebLinesView(document.getElementById("lines")!!, document.getElementById("addForm")!!)
|
||||||
|
// presenter = LinesPresenter(view)
|
||||||
|
//
|
||||||
|
// state["lines"]?.let { linesState ->
|
||||||
|
// @Suppress("UNCHECKED_CAST")
|
||||||
|
// presenter.restore(linesState as Array<String>)
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun dispose() = emptyMap<String,Any>()//mapOf("lines" to presenter.dispose())
|
||||||
|
}
|
@ -0,0 +1,141 @@
|
|||||||
|
package hep.dataforge.vis.spatial
|
||||||
|
|
||||||
|
import hep.dataforge.context.Context
|
||||||
|
import hep.dataforge.io.Output
|
||||||
|
import hep.dataforge.meta.Meta
|
||||||
|
import hep.dataforge.vis.DisplayGroup
|
||||||
|
import hep.dataforge.vis.DisplayObject
|
||||||
|
import hep.dataforge.vis.get
|
||||||
|
import hep.dataforge.vis.onChange
|
||||||
|
import info.laht.threekt.WebGLRenderer
|
||||||
|
import info.laht.threekt.cameras.PerspectiveCamera
|
||||||
|
import info.laht.threekt.core.Object3D
|
||||||
|
import info.laht.threekt.external.controls.OrbitControls
|
||||||
|
import info.laht.threekt.geometries.BoxBufferGeometry
|
||||||
|
import info.laht.threekt.lights.AmbientLight
|
||||||
|
import info.laht.threekt.math.ColorConstants
|
||||||
|
import info.laht.threekt.objects.Mesh
|
||||||
|
import info.laht.threekt.scenes.Scene
|
||||||
|
import org.w3c.dom.Element
|
||||||
|
import kotlin.browser.window
|
||||||
|
|
||||||
|
class ThreeOutput(override val context: Context) : Output<DisplayObject> {
|
||||||
|
|
||||||
|
private val renderer = WebGLRenderer { antialias = true }.apply {
|
||||||
|
setClearColor(ColorConstants.skyblue, 1)
|
||||||
|
setSize(window.innerWidth, window.innerHeight)
|
||||||
|
}
|
||||||
|
|
||||||
|
val scene: Scene = Scene().apply {
|
||||||
|
add(AmbientLight())
|
||||||
|
}
|
||||||
|
|
||||||
|
val camera = PerspectiveCamera(
|
||||||
|
75,
|
||||||
|
window.innerWidth.toDouble() / window.innerHeight,
|
||||||
|
World.CAMERA_NEAR_CLIP,
|
||||||
|
World.CAMERA_FAR_CLIP
|
||||||
|
).apply {
|
||||||
|
position.setZ(World.CAMERA_INITIAL_DISTANCE)
|
||||||
|
rotation.set(World.CAMERA_INITIAL_X_ANGLE, World.CAMERA_INITIAL_Y_ANGLE, World.CAMERA_INITIAL_Z_ANGLE)
|
||||||
|
}
|
||||||
|
|
||||||
|
val controls: OrbitControls = OrbitControls(camera, renderer.domElement)
|
||||||
|
|
||||||
|
val root get() = renderer.domElement
|
||||||
|
|
||||||
|
private fun animate() {
|
||||||
|
window.requestAnimationFrame {
|
||||||
|
animate()
|
||||||
|
}
|
||||||
|
renderer.render(scene, camera)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun start(element: Element) {
|
||||||
|
window.addEventListener("resize", {
|
||||||
|
camera.aspect = window.innerWidth.toDouble() / window.innerHeight;
|
||||||
|
camera.updateProjectionMatrix();
|
||||||
|
|
||||||
|
renderer.setSize(window.innerWidth, window.innerHeight)
|
||||||
|
}, false)
|
||||||
|
element.appendChild(root)
|
||||||
|
animate()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun buildNode(obj: DisplayObject): Object3D? {
|
||||||
|
|
||||||
|
// general properties updater
|
||||||
|
val updateProperties: Object3D.(DisplayObject) -> Unit = {
|
||||||
|
position.set(obj.x, obj.y, obj.z)
|
||||||
|
setRotationFromEuler(obj.euler)
|
||||||
|
scale.set(obj.scaleX, obj.scaleY, obj.scaleZ)
|
||||||
|
visible = obj.visible
|
||||||
|
}
|
||||||
|
|
||||||
|
return when (obj) {
|
||||||
|
is DisplayGroup -> Group(obj.children.mapNotNull { buildNode(it) })
|
||||||
|
is Box -> {
|
||||||
|
val geometry = BoxBufferGeometry(obj.xSize, obj.ySize, obj.zSize)
|
||||||
|
val update: Mesh.(Box) -> Unit = { box ->
|
||||||
|
this.geometry = BoxBufferGeometry(box.xSize, box.ySize, box.zSize)
|
||||||
|
material = box["color"].material()
|
||||||
|
}
|
||||||
|
Mesh(geometry, obj["color"].material()).also { mesh ->
|
||||||
|
obj.onChange(this) { _, _, _ ->
|
||||||
|
mesh.updateProperties(obj)
|
||||||
|
mesh.update(obj)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
logger.error { "No renderer defined for ${obj::class}" }
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}.apply {
|
||||||
|
updateProperties(obj)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun render(obj: DisplayObject, meta: Meta) {
|
||||||
|
buildNode(obj)?.let { scene.add(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
// init {
|
||||||
|
// val cube: Mesh
|
||||||
|
//
|
||||||
|
// cube = Mesh(
|
||||||
|
// BoxBufferGeometry(1, 1, 1),
|
||||||
|
// MeshPhongMaterial().apply {
|
||||||
|
// this.color.set(ColorConstants.darkgreen)
|
||||||
|
// }
|
||||||
|
// ).also(scene::add)
|
||||||
|
//
|
||||||
|
// Mesh(cube.geometry as BufferGeometry,
|
||||||
|
// MeshBasicMaterial().apply {
|
||||||
|
// this.wireframe = true
|
||||||
|
// this.color.set(ColorConstants.black)
|
||||||
|
// }
|
||||||
|
// ).also(cube::add)
|
||||||
|
//
|
||||||
|
// val points = CatmullRomCurve3(
|
||||||
|
// arrayOf(
|
||||||
|
// Vector3(-10, 0, 10),
|
||||||
|
// Vector3(-5, 5, 5),
|
||||||
|
// Vector3(0, 0, 0),
|
||||||
|
// Vector3(5, -5, 5),
|
||||||
|
// Vector3(10, 0, 10)
|
||||||
|
// )
|
||||||
|
// ).getPoints(50)
|
||||||
|
//
|
||||||
|
// val geometry = BufferGeometry().setFromPoints(points)
|
||||||
|
//
|
||||||
|
// val material = LineBasicMaterial().apply {
|
||||||
|
// color.set(0xff0000)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // Create the final object to add to the scene
|
||||||
|
// Line(geometry, material).apply(scene::add)
|
||||||
|
// }
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
package hep.dataforge.vis.spatial
|
||||||
|
|
||||||
|
import hep.dataforge.meta.MetaItem
|
||||||
|
import hep.dataforge.meta.float
|
||||||
|
import hep.dataforge.meta.get
|
||||||
|
import hep.dataforge.meta.node
|
||||||
|
import hep.dataforge.vis.DisplayObject
|
||||||
|
import info.laht.threekt.core.Object3D
|
||||||
|
import info.laht.threekt.math.Euler
|
||||||
|
import info.laht.threekt.math.Vector3
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility methods for three.kt.
|
||||||
|
* TODO move to three project
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Suppress("FunctionName")
|
||||||
|
fun Group(children: Collection<Object3D>) = info.laht.threekt.objects.Group().apply {
|
||||||
|
children.forEach { this.add(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
val DisplayObject.euler get() = Euler(rotationX, rotationY, rotationZ, rotationOrder.name)
|
||||||
|
|
||||||
|
val MetaItem<*>.vector get() = Vector3(node["x"].float ?: 0f, node["y"].float ?: 0f, node["z"].float ?: 0f)
|
19
dataforge-vis-spatial-js/src/main/web/index.html
Normal file
19
dataforge-vis-spatial-js/src/main/web/index.html
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Three js demo for particle physics</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
margin: 0px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<!--<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/three.js/88/three.min.js"></script>-->
|
||||||
|
<!--<script type="text/javascript" src="js/OrbitControls.js"></script>-->
|
||||||
|
<script type="text/javascript" language="JavaScript" src="main.bundle.js"></script>
|
||||||
|
</head>
|
||||||
|
<body class="testApp">
|
||||||
|
<h1>Demo canvas</h1>
|
||||||
|
<div id="canvas"></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
27
dataforge-vis-spatial/build.gradle.kts
Normal file
27
dataforge-vis-spatial/build.gradle.kts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
plugins {
|
||||||
|
kotlin("multiplatform")
|
||||||
|
}
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
jvm()
|
||||||
|
js()
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
val commonMain by getting {
|
||||||
|
dependencies {
|
||||||
|
api(project(":dataforge-vis-common"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val jvmMain by getting {
|
||||||
|
dependencies {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val jsMain by getting {
|
||||||
|
dependencies {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,23 @@
|
|||||||
|
package hep.dataforge.vis.spatial
|
||||||
|
|
||||||
|
import hep.dataforge.meta.EmptyMeta
|
||||||
|
import hep.dataforge.meta.Meta
|
||||||
|
import hep.dataforge.vis.DisplayGroup
|
||||||
|
import hep.dataforge.vis.DisplayLeaf
|
||||||
|
import hep.dataforge.vis.DisplayObject
|
||||||
|
import hep.dataforge.vis.double
|
||||||
|
|
||||||
|
class Box(parent: DisplayObject?, meta: Meta) : DisplayLeaf(parent, TYPE, meta) {
|
||||||
|
var xSize by double(1.0)
|
||||||
|
var ySize by double(1.0)
|
||||||
|
var zSize by double(1.0)
|
||||||
|
|
||||||
|
//TODO add helper for color configuration
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val TYPE = "geometry.spatial.box"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun DisplayGroup.box(meta: Meta = EmptyMeta, action: Box.() -> Unit = {}) =
|
||||||
|
Box(this, meta).apply(action).also { addChild(it) }
|
@ -0,0 +1,18 @@
|
|||||||
|
package hep.dataforge.vis.spatial
|
||||||
|
|
||||||
|
import hep.dataforge.meta.EmptyMeta
|
||||||
|
import hep.dataforge.meta.Meta
|
||||||
|
import hep.dataforge.vis.DisplayGroup
|
||||||
|
import hep.dataforge.vis.DisplayLeaf
|
||||||
|
import hep.dataforge.vis.DisplayObject
|
||||||
|
|
||||||
|
class Extruded(parent: DisplayObject?, meta: Meta) : DisplayLeaf(parent, TYPE, meta) {
|
||||||
|
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val TYPE = "geometry.spatial.extruded"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun DisplayGroup.extrude(meta: Meta = EmptyMeta, action: Extruded.() -> Unit = {}) =
|
||||||
|
Extruded(this, meta).apply(action).also { addChild(it) }
|
@ -0,0 +1 @@
|
|||||||
|
package hep.dataforge.vis.spatial
|
@ -0,0 +1,109 @@
|
|||||||
|
package hep.dataforge.vis.spatial
|
||||||
|
|
||||||
|
import hep.dataforge.io.Output
|
||||||
|
import hep.dataforge.meta.*
|
||||||
|
import hep.dataforge.vis.DisplayGroup
|
||||||
|
import hep.dataforge.vis.DisplayNode
|
||||||
|
import hep.dataforge.vis.DisplayObject
|
||||||
|
import hep.dataforge.vis.DisplayObject.Companion.DEFAULT_TYPE
|
||||||
|
|
||||||
|
fun DisplayGroup.group(meta: Meta = EmptyMeta, action: DisplayGroup.() -> Unit = {}) =
|
||||||
|
DisplayNode(this, DEFAULT_TYPE, meta).apply(action).also { addChild(it) }
|
||||||
|
|
||||||
|
|
||||||
|
fun Output<DisplayObject>.render(meta: Meta = EmptyMeta, action: DisplayGroup.() -> Unit) =
|
||||||
|
render(DisplayNode(null, DEFAULT_TYPE, EmptyMeta).apply(action), meta)
|
||||||
|
|
||||||
|
//TODO replace properties by containers?
|
||||||
|
|
||||||
|
// Common properties
|
||||||
|
|
||||||
|
var DisplayObject.visible
|
||||||
|
get() = properties["visible"].boolean ?: true
|
||||||
|
set(value) {
|
||||||
|
properties.style["visible"] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3D Object position
|
||||||
|
|
||||||
|
var DisplayObject.x
|
||||||
|
get() = properties["pos.x"].number ?: 0.0
|
||||||
|
set(value) {
|
||||||
|
properties.style["pos.x"] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
var DisplayObject.y
|
||||||
|
get() = properties["pos.y"].number ?: 0.0
|
||||||
|
set(value) {
|
||||||
|
properties.style["pos.y"] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
var DisplayObject.z
|
||||||
|
get() = properties["pos.z"].number ?: 0.0
|
||||||
|
set(value) {
|
||||||
|
properties.style["pos.z"] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3D Object rotation
|
||||||
|
|
||||||
|
var DisplayObject.rotationX
|
||||||
|
get() = properties["rotation.x"].number ?: 0.0
|
||||||
|
set(value) {
|
||||||
|
properties.style["rotation.x"] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
var DisplayObject.rotationY
|
||||||
|
get() = properties["rotation.y"].number ?: 0.0
|
||||||
|
set(value) {
|
||||||
|
properties.style["rotation.y"] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
var DisplayObject.rotationZ
|
||||||
|
get() = properties["rotation.z"].number ?: 0.0
|
||||||
|
set(value) {
|
||||||
|
properties.style["rotation.z"] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class RotationOrder {
|
||||||
|
XYZ,
|
||||||
|
YZX,
|
||||||
|
ZXY,
|
||||||
|
XZY,
|
||||||
|
YXZ,
|
||||||
|
ZYX
|
||||||
|
}
|
||||||
|
|
||||||
|
var DisplayObject.rotationOrder: RotationOrder
|
||||||
|
get() = properties["rotation.order"].enum<RotationOrder>() ?: RotationOrder.XYZ
|
||||||
|
set(value) {
|
||||||
|
properties.style["rotation.order"] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3D object scale
|
||||||
|
|
||||||
|
var DisplayObject.scaleX
|
||||||
|
get() = properties["scale.x"].number ?: 1.0
|
||||||
|
set(value) {
|
||||||
|
properties.style["scale.x"] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
var DisplayObject.scaleY
|
||||||
|
get() = properties["scale.y"].number ?: 1.0
|
||||||
|
set(value) {
|
||||||
|
properties.style["scale.y"] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
var DisplayObject.scaleZ
|
||||||
|
get() = properties["scale.z"].number ?: 1.0
|
||||||
|
set(value) {
|
||||||
|
properties.style["scale.z"] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
object World {
|
||||||
|
const val CAMERA_INITIAL_DISTANCE = -500.0
|
||||||
|
const val CAMERA_INITIAL_X_ANGLE = -50.0
|
||||||
|
const val CAMERA_INITIAL_Y_ANGLE = 0.0
|
||||||
|
const val CAMERA_INITIAL_Z_ANGLE = -210.0
|
||||||
|
const val CAMERA_NEAR_CLIP = 0.1
|
||||||
|
const val CAMERA_FAR_CLIP = 10000.0
|
||||||
|
}
|
31
gradle/artifactory.gradle
Normal file
31
gradle/artifactory.gradle
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
apply plugin: "com.jfrog.artifactory"
|
||||||
|
|
||||||
|
artifactory {
|
||||||
|
def artifactory_user = project.hasProperty('artifactoryUser') ? project.property('artifactoryUser') : ""
|
||||||
|
def artifactory_password = project.hasProperty('artifactoryPassword') ? project.property('artifactoryPassword') : ""
|
||||||
|
def artifactory_contextUrl = 'http://npm.mipt.ru:8081/artifactory'
|
||||||
|
|
||||||
|
contextUrl = artifactory_contextUrl //The base Artifactory URL if not overridden by the publisher/resolver
|
||||||
|
publish {
|
||||||
|
repository {
|
||||||
|
repoKey = 'gradle-dev-local'
|
||||||
|
username = artifactory_user
|
||||||
|
password = artifactory_password
|
||||||
|
}
|
||||||
|
|
||||||
|
defaults {
|
||||||
|
publications('jvm', 'js', 'kotlinMultiplatform', 'metadata')
|
||||||
|
publishBuildInfo = false
|
||||||
|
publishArtifacts = true
|
||||||
|
publishPom = true
|
||||||
|
publishIvy = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
resolve {
|
||||||
|
repository {
|
||||||
|
repoKey = 'gradle-dev'
|
||||||
|
username = artifactory_user
|
||||||
|
password = artifactory_password
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
85
gradle/bintray.gradle
Normal file
85
gradle/bintray.gradle
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
apply plugin: 'com.jfrog.bintray'
|
||||||
|
|
||||||
|
def vcs = "https://github.com/mipt-npm/kmath"
|
||||||
|
|
||||||
|
def pomConfig = {
|
||||||
|
licenses {
|
||||||
|
license {
|
||||||
|
name "The Apache Software License, Version 2.0"
|
||||||
|
url "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||||
|
distribution "repo"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
developers {
|
||||||
|
developer {
|
||||||
|
id "MIPT-NPM"
|
||||||
|
name "MIPT nuclear physics methods laboratory"
|
||||||
|
organization "MIPT"
|
||||||
|
organizationUrl "http://npm.mipt.ru"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
scm {
|
||||||
|
url vcs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
project.ext.configureMavenCentralMetadata = { pom ->
|
||||||
|
def root = asNode()
|
||||||
|
root.appendNode('name', project.name)
|
||||||
|
root.appendNode('description', project.description)
|
||||||
|
root.appendNode('url', vcs)
|
||||||
|
root.children().last() + pomConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
project.ext.configurePom = pomConfig
|
||||||
|
|
||||||
|
|
||||||
|
// Configure publishing
|
||||||
|
publishing {
|
||||||
|
repositories {
|
||||||
|
maven {
|
||||||
|
url = "https://bintray.com/mipt-npm/scientifik"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process each publication we have in this project
|
||||||
|
publications.all { publication ->
|
||||||
|
// apply changes to pom.xml files, see pom.gradle
|
||||||
|
pom.withXml(configureMavenCentralMetadata)
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bintray {
|
||||||
|
user = project.hasProperty('bintrayUser') ? project.property('bintrayUser') : System.getenv('BINTRAY_USER')
|
||||||
|
key = project.hasProperty('bintrayApiKey') ? project.property('bintrayApiKey') : System.getenv('BINTRAY_API_KEY')
|
||||||
|
publish = true
|
||||||
|
override = true // for multi-platform Kotlin/Native publishing
|
||||||
|
|
||||||
|
pkg {
|
||||||
|
userOrg = "mipt-npm"
|
||||||
|
repo = "scientifik"
|
||||||
|
name = "scientifik.kmath"
|
||||||
|
issueTrackerUrl = "https://github.com/mipt-npm/kmath/issues"
|
||||||
|
licenses = ['Apache-2.0']
|
||||||
|
vcsUrl = vcs
|
||||||
|
version {
|
||||||
|
name = project.version
|
||||||
|
vcsTag = project.version
|
||||||
|
released = new Date()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bintrayUpload.dependsOn publishToMavenLocal
|
||||||
|
|
||||||
|
// This is for easier debugging of bintray uploading problems
|
||||||
|
bintrayUpload.doFirst {
|
||||||
|
publications = project.publishing.publications.findAll {
|
||||||
|
!it.name.contains('-test') && it.name != 'kotlinMultiplatform'
|
||||||
|
}.collect {
|
||||||
|
println("Uploading artifact '$it.groupId:$it.artifactId:$it.version' from publication '$it.name'")
|
||||||
|
it.name//https://github.com/bintray/gradle-bintray-plugin/issues/256
|
||||||
|
}
|
||||||
|
}
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
5
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
5
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
distributionBase=GRADLE_USER_HOME
|
||||||
|
distributionPath=wrapper/dists
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-bin.zip
|
||||||
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
zipStorePath=wrapper/dists
|
172
gradlew
vendored
Normal file
172
gradlew
vendored
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
##
|
||||||
|
## Gradle start up script for UN*X
|
||||||
|
##
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
# Attempt to set APP_HOME
|
||||||
|
# Resolve links: $0 may be a link
|
||||||
|
PRG="$0"
|
||||||
|
# Need this for relative symlinks.
|
||||||
|
while [ -h "$PRG" ] ; do
|
||||||
|
ls=`ls -ld "$PRG"`
|
||||||
|
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||||
|
if expr "$link" : '/.*' > /dev/null; then
|
||||||
|
PRG="$link"
|
||||||
|
else
|
||||||
|
PRG=`dirname "$PRG"`"/$link"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
SAVED="`pwd`"
|
||||||
|
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||||
|
APP_HOME="`pwd -P`"
|
||||||
|
cd "$SAVED" >/dev/null
|
||||||
|
|
||||||
|
APP_NAME="Gradle"
|
||||||
|
APP_BASE_NAME=`basename "$0"`
|
||||||
|
|
||||||
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
DEFAULT_JVM_OPTS='"-Xmx64m"'
|
||||||
|
|
||||||
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
|
MAX_FD="maximum"
|
||||||
|
|
||||||
|
warn () {
|
||||||
|
echo "$*"
|
||||||
|
}
|
||||||
|
|
||||||
|
die () {
|
||||||
|
echo
|
||||||
|
echo "$*"
|
||||||
|
echo
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# OS specific support (must be 'true' or 'false').
|
||||||
|
cygwin=false
|
||||||
|
msys=false
|
||||||
|
darwin=false
|
||||||
|
nonstop=false
|
||||||
|
case "`uname`" in
|
||||||
|
CYGWIN* )
|
||||||
|
cygwin=true
|
||||||
|
;;
|
||||||
|
Darwin* )
|
||||||
|
darwin=true
|
||||||
|
;;
|
||||||
|
MINGW* )
|
||||||
|
msys=true
|
||||||
|
;;
|
||||||
|
NONSTOP* )
|
||||||
|
nonstop=true
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||||
|
|
||||||
|
# Determine the Java command to use to start the JVM.
|
||||||
|
if [ -n "$JAVA_HOME" ] ; then
|
||||||
|
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||||
|
# IBM's JDK on AIX uses strange locations for the executables
|
||||||
|
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||||
|
else
|
||||||
|
JAVACMD="$JAVA_HOME/bin/java"
|
||||||
|
fi
|
||||||
|
if [ ! -x "$JAVACMD" ] ; then
|
||||||
|
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
JAVACMD="java"
|
||||||
|
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Increase the maximum file descriptors if we can.
|
||||||
|
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||||
|
MAX_FD_LIMIT=`ulimit -H -n`
|
||||||
|
if [ $? -eq 0 ] ; then
|
||||||
|
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||||
|
MAX_FD="$MAX_FD_LIMIT"
|
||||||
|
fi
|
||||||
|
ulimit -n $MAX_FD
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# For Darwin, add options to specify how the application appears in the dock
|
||||||
|
if $darwin; then
|
||||||
|
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||||
|
fi
|
||||||
|
|
||||||
|
# For Cygwin, switch paths to Windows format before running java
|
||||||
|
if $cygwin ; then
|
||||||
|
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||||
|
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||||
|
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||||
|
|
||||||
|
# We build the pattern for arguments to be converted via cygpath
|
||||||
|
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||||
|
SEP=""
|
||||||
|
for dir in $ROOTDIRSRAW ; do
|
||||||
|
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||||
|
SEP="|"
|
||||||
|
done
|
||||||
|
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||||
|
# Add a user-defined pattern to the cygpath arguments
|
||||||
|
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||||
|
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||||
|
fi
|
||||||
|
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||||
|
i=0
|
||||||
|
for arg in "$@" ; do
|
||||||
|
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||||
|
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||||
|
|
||||||
|
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||||
|
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||||
|
else
|
||||||
|
eval `echo args$i`="\"$arg\""
|
||||||
|
fi
|
||||||
|
i=$((i+1))
|
||||||
|
done
|
||||||
|
case $i in
|
||||||
|
(0) set -- ;;
|
||||||
|
(1) set -- "$args0" ;;
|
||||||
|
(2) set -- "$args0" "$args1" ;;
|
||||||
|
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||||
|
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||||
|
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||||
|
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||||
|
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||||
|
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||||
|
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Escape application args
|
||||||
|
save () {
|
||||||
|
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||||
|
echo " "
|
||||||
|
}
|
||||||
|
APP_ARGS=$(save "$@")
|
||||||
|
|
||||||
|
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||||
|
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||||
|
|
||||||
|
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
|
||||||
|
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
|
||||||
|
cd "$(dirname "$0")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec "$JAVACMD" "$@"
|
84
gradlew.bat
vendored
Normal file
84
gradlew.bat
vendored
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
@if "%DEBUG%" == "" @echo off
|
||||||
|
@rem ##########################################################################
|
||||||
|
@rem
|
||||||
|
@rem Gradle startup script for Windows
|
||||||
|
@rem
|
||||||
|
@rem ##########################################################################
|
||||||
|
|
||||||
|
@rem Set local scope for the variables with windows NT shell
|
||||||
|
if "%OS%"=="Windows_NT" setlocal
|
||||||
|
|
||||||
|
set DIRNAME=%~dp0
|
||||||
|
if "%DIRNAME%" == "" set DIRNAME=.
|
||||||
|
set APP_BASE_NAME=%~n0
|
||||||
|
set APP_HOME=%DIRNAME%
|
||||||
|
|
||||||
|
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
set DEFAULT_JVM_OPTS="-Xmx64m"
|
||||||
|
|
||||||
|
@rem Find java.exe
|
||||||
|
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||||
|
|
||||||
|
set JAVA_EXE=java.exe
|
||||||
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
|
if "%ERRORLEVEL%" == "0" goto init
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
echo.
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
echo location of your Java installation.
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:findJavaFromJavaHome
|
||||||
|
set JAVA_HOME=%JAVA_HOME:"=%
|
||||||
|
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||||
|
|
||||||
|
if exist "%JAVA_EXE%" goto init
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||||
|
echo.
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
echo location of your Java installation.
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:init
|
||||||
|
@rem Get command-line arguments, handling Windows variants
|
||||||
|
|
||||||
|
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||||
|
|
||||||
|
:win9xME_args
|
||||||
|
@rem Slurp the command line arguments.
|
||||||
|
set CMD_LINE_ARGS=
|
||||||
|
set _SKIP=2
|
||||||
|
|
||||||
|
:win9xME_args_slurp
|
||||||
|
if "x%~1" == "x" goto execute
|
||||||
|
|
||||||
|
set CMD_LINE_ARGS=%*
|
||||||
|
|
||||||
|
:execute
|
||||||
|
@rem Setup the command line
|
||||||
|
|
||||||
|
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||||
|
|
||||||
|
@rem Execute Gradle
|
||||||
|
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||||
|
|
||||||
|
:end
|
||||||
|
@rem End local scope for the variables with windows NT shell
|
||||||
|
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||||
|
|
||||||
|
:fail
|
||||||
|
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||||
|
rem the _cmd.exe /c_ return code!
|
||||||
|
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||||
|
exit /b 1
|
||||||
|
|
||||||
|
:mainEnd
|
||||||
|
if "%OS%"=="Windows_NT" endlocal
|
||||||
|
|
||||||
|
:omega
|
27
settings.gradle.kts
Normal file
27
settings.gradle.kts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
pluginManagement {
|
||||||
|
repositories {
|
||||||
|
jcenter()
|
||||||
|
gradlePluginPortal()
|
||||||
|
maven("https://dl.bintray.com/kotlin/kotlin-eap")
|
||||||
|
}
|
||||||
|
resolutionStrategy {
|
||||||
|
eachPlugin {
|
||||||
|
when (requested.id.id) {
|
||||||
|
"kotlinx-atomicfu" -> useModule("org.jetbrains.kotlinx:atomicfu-gradle-plugin:${requested.version}")
|
||||||
|
"kotlin-multiplatform" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:${requested.version}")
|
||||||
|
"kotlin2js" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:${requested.version}")
|
||||||
|
"org.jetbrains.kotlin.frontend" -> useModule("org.jetbrains.kotlin:kotlin-frontend-plugin:0.0.45")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enableFeaturePreview("GRADLE_METADATA")
|
||||||
|
|
||||||
|
rootProject.name = "dataforge-vis"
|
||||||
|
include(
|
||||||
|
":dataforge-vis-common",
|
||||||
|
":dataforge-vis-spatial",
|
||||||
|
":dataforge-vis-spatial-fx",
|
||||||
|
":dataforge-vis-spatial-js"
|
||||||
|
)
|
Loading…
Reference in New Issue
Block a user