0.2.0 #71
@ -105,6 +105,8 @@ public class DGeoVolume(meta: Meta, refCache: DObjectCache) : DNamed(meta, refCa
|
||||
public val fShape: DGeoShape? by dObject(::DGeoShape)
|
||||
public val fMedium: DGeoMedium? by dObject(::DGeoMedium)
|
||||
|
||||
public val fFillColor: Int? by meta.int()
|
||||
|
||||
override val name: Name by lazy { Name.parse(fName.ifEmpty { "volume[${meta.hashCode().toUInt()}]" }) }
|
||||
}
|
||||
|
||||
|
@ -1,12 +1,11 @@
|
||||
package ru.mipt.npm.root
|
||||
|
||||
import space.kscience.dataforge.meta.double
|
||||
import space.kscience.dataforge.meta.get
|
||||
import space.kscience.dataforge.meta.int
|
||||
import space.kscience.dataforge.meta.isEmpty
|
||||
import space.kscience.dataforge.meta.*
|
||||
import space.kscience.dataforge.names.Name
|
||||
import space.kscience.dataforge.names.plus
|
||||
import space.kscience.dataforge.values.doubleArray
|
||||
import space.kscience.visionforge.solid.*
|
||||
import space.kscience.visionforge.solid.SolidMaterial.Companion.MATERIAL_COLOR_KEY
|
||||
import kotlin.math.*
|
||||
|
||||
private val volumesName = Name.EMPTY //"volumes".asName()
|
||||
@ -50,9 +49,8 @@ private fun Solid.useMatrix(matrix: DGeoMatrix?) {
|
||||
val fTranslation by matrix.meta.doubleArray()
|
||||
|
||||
translate(fTranslation)
|
||||
if (matrix.meta["fRotationMatrix"] != null) {
|
||||
val fRotationMatrix by matrix.meta.doubleArray()
|
||||
rotate(fRotationMatrix)
|
||||
matrix.meta["fRotation.fRotationMatrix"]?.value?.let {
|
||||
rotate(it.doubleArray)
|
||||
}
|
||||
}
|
||||
"TGeoHMatrix" -> {
|
||||
@ -77,15 +75,15 @@ private fun SolidGroup.addShape(
|
||||
val compositeType = when (node.typename) {
|
||||
"TGeoIntersection" -> CompositeType.INTERSECT
|
||||
"TGeoSubtraction" -> CompositeType.SUBTRACT
|
||||
"TGeoUnion" -> CompositeType.UNION
|
||||
"TGeoUnion" -> CompositeType.GROUP
|
||||
else -> error("Unknown bool node type ${node.typename}")
|
||||
}
|
||||
composite(compositeType, name = name) {
|
||||
addShape(node.fLeft!!, context, "left").also {
|
||||
smartComposite(compositeType, name = name) {
|
||||
addShape(node.fLeft!!, context, null).also {
|
||||
if (it == null) TODO()
|
||||
it.useMatrix(node.fLeftMat)
|
||||
}
|
||||
addShape(node.fRight!!, context, "right").also {
|
||||
addShape(node.fRight!!, context, null).also {
|
||||
if (it == null) TODO()
|
||||
it.useMatrix(node.fRightMat)
|
||||
}
|
||||
@ -277,7 +275,11 @@ private fun SolidGroup.addRootVolume(
|
||||
}
|
||||
}
|
||||
|
||||
return ref(templateName, name)
|
||||
ref(templateName, name)
|
||||
}.apply {
|
||||
volume.fFillColor?.let {
|
||||
meta[MATERIAL_COLOR_KEY] = RootColors[it]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,42 @@
|
||||
package ru.mipt.npm.root
|
||||
|
||||
public object RootColors {
|
||||
private val colorMap = Array<String>(924) { "white" }
|
||||
|
||||
//colorMap[110] = "white"
|
||||
|
||||
private val moreCol = listOf(
|
||||
11 to "c1b7ad4d4d4d6666668080809a9a9ab3b3b3cdcdcde6e6e6f3f3f3cdc8accdc8acc3c0a9bbb6a4b3a697b8a49cae9a8d9c8f83886657b1cfc885c3a48aa9a1839f8daebdc87b8f9a768a926983976e7b857d9ad280809caca6c0d4cf88dfbb88bd9f83c89a7dc08378cf5f61ac8f94a6787b946971d45a549300ff7b00ff6300ff4b00ff3300ff1b00ff0300ff0014ff002cff0044ff005cff0074ff008cff00a4ff00bcff00d4ff00ecff00fffd00ffe500ffcd00ffb500ff9d00ff8500ff6d00ff5500ff3d00ff2600ff0e0aff0022ff003aff0052ff006aff0082ff009aff00b1ff00c9ff00e1ff00f9ff00ffef00ffd700ffbf00ffa700ff8f00ff7700ff6000ff4800ff3000ff1800ff0000",
|
||||
201 to "5c5c5c7b7b7bb8b8b8d7d7d78a0f0fb81414ec4848f176760f8a0f14b81448ec4876f1760f0f8a1414b84848ec7676f18a8a0fb8b814ecec48f1f1768a0f8ab814b8ec48ecf176f10f8a8a14b8b848ecec76f1f1",
|
||||
390 to "ffffcdffff9acdcd9affff66cdcd669a9a66ffff33cdcd339a9a33666633ffff00cdcd009a9a00666600333300",
|
||||
406 to "cdffcd9aff9a9acd9a66ff6666cd66669a6633ff3333cd33339a3333663300ff0000cd00009a00006600003300",
|
||||
422 to "cdffff9affff9acdcd66ffff66cdcd669a9a33ffff33cdcd339a9a33666600ffff00cdcd009a9a006666003333",
|
||||
590 to "cdcdff9a9aff9a9acd6666ff6666cd66669a3333ff3333cd33339a3333660000ff0000cd00009a000066000033",
|
||||
606 to "ffcdffff9affcd9acdff66ffcd66cd9a669aff33ffcd33cd9a339a663366ff00ffcd00cd9a009a660066330033",
|
||||
622 to "ffcdcdff9a9acd9a9aff6666cd66669a6666ff3333cd33339a3333663333ff0000cd00009a0000660000330000",
|
||||
791 to "ffcd9acd9a669a66339a6600cd9a33ffcd66ff9a00ffcd33cd9a00ffcd00ff9a33cd66006633009a3300cd6633ff9a66ff6600ff6633cd3300ff33009aff3366cd00336600339a0066cd339aff6666ff0066ff3333cd0033ff00cdff9a9acd66669a33669a009acd33cdff669aff00cdff339acd00cdff009affcd66cd9a339a66009a6633cd9a66ffcd00ff6633ffcd00cd9a00ffcd33ff9a00cd66006633009a3333cd6666ff9a00ff9a33ff6600cd3300ff339acdff669acd33669a00339a3366cd669aff0066ff3366ff0033cd0033ff339aff0066cd00336600669a339acd66cdff009aff33cdff009acd00cdffcd9aff9a66cd66339a66009a9a33cdcd66ff9a00ffcd33ff9a00cdcd00ff9a33ff6600cd33006633009a6633cd9a66ff6600ff6633ff3300cd3300ffff339acd00666600339a0033cd3366ff669aff0066ff3366cd0033ff0033ff9acdcd669a9a33669a0066cd339aff66cdff009acd009aff33cdff009a",
|
||||
920 to "cdcdcd9a9a9a666666333333"
|
||||
)
|
||||
|
||||
init {
|
||||
colorMap[0] = "white"
|
||||
colorMap[1] = "black"
|
||||
colorMap[2] = "red"
|
||||
colorMap[3] = "green"
|
||||
colorMap[4] = "blue"
|
||||
colorMap[5] = "yellow"
|
||||
colorMap[6] = "magenta"
|
||||
colorMap[7] = "cyan"
|
||||
colorMap[8] = "rgb(89,212,84)"
|
||||
colorMap[9] = "rgb(89,84,217)"
|
||||
colorMap[10] = "white"
|
||||
|
||||
moreCol.forEach { (n, s) ->
|
||||
for (i in 0 until (s.length / 6)) {
|
||||
colorMap[n + i] = "#" + s.substring(i * 6, (i + 1) * 6)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public operator fun get(index: Int): String = colorMap[index]
|
||||
}
|
@ -1,72 +0,0 @@
|
||||
package ru.mipt.npm.root
|
||||
|
||||
import kotlinx.serialization.json.JsonArray
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
import kotlinx.serialization.json.JsonObject
|
||||
import kotlinx.serialization.json.jsonPrimitive
|
||||
import ru.mipt.npm.root.serialization.TGeoManager
|
||||
import space.kscience.dataforge.meta.Meta
|
||||
import space.kscience.dataforge.meta.get
|
||||
import space.kscience.dataforge.meta.isLeaf
|
||||
import space.kscience.dataforge.values.string
|
||||
import space.kscience.visionforge.solid.Solids
|
||||
import java.nio.file.Paths
|
||||
import java.time.Duration
|
||||
import kotlin.io.path.writeText
|
||||
import kotlin.system.measureTimeMillis
|
||||
|
||||
private fun JsonElement.countTypes(): Sequence<String> = sequence {
|
||||
when (val json = this@countTypes) {
|
||||
is JsonObject -> {
|
||||
json["_typename"]?.let { yield(it.jsonPrimitive.content) }
|
||||
json.values.forEach { yieldAll(it.countTypes()) }
|
||||
}
|
||||
is JsonArray -> {
|
||||
json.forEach {
|
||||
yieldAll(it.countTypes())
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun Meta.countTypes() :Sequence<String> = sequence {
|
||||
if(!isLeaf){
|
||||
get("_typename")?.value?.let { yield(it.string) }
|
||||
items.forEach { yieldAll(it.value.countTypes()) }
|
||||
}
|
||||
}
|
||||
|
||||
fun main() {
|
||||
val string = TGeoManager::class.java.getResourceAsStream("/BM@N.root.json")!!
|
||||
.readAllBytes().decodeToString()
|
||||
val time = measureTimeMillis {
|
||||
val geo = DGeoManager.parse(string)
|
||||
|
||||
val sizes = geo.meta.countTypes().groupBy { it }.mapValues { it.value.size }
|
||||
sizes.forEach {
|
||||
println(it)
|
||||
}
|
||||
|
||||
val solid = geo.toSolid()
|
||||
|
||||
Paths.get("BM@N.vf.json").writeText(Solids.encodeToString(solid))
|
||||
//println(Solids.encodeToString(solid))
|
||||
}
|
||||
|
||||
// val json = Json.parseToJsonElement(string)
|
||||
// val sizes = json.countTypes().groupBy { it }.mapValues { it.value.size }
|
||||
// sizes.forEach {
|
||||
// println(it)
|
||||
// }
|
||||
//
|
||||
// val time = measureTimeMillis {
|
||||
// val geo = TObject.decodeFromString(TGeoManager.serializer(), string)
|
||||
// val solid = geo.toSolid()
|
||||
//
|
||||
// println(Solids.encodeToString(solid))
|
||||
// }
|
||||
//
|
||||
println(Duration.ofMillis(time))
|
||||
}
|
@ -55,6 +55,7 @@ kotlin {
|
||||
api(project(":visionforge-gdml"))
|
||||
api(project(":visionforge-plotly"))
|
||||
api(projects.visionforge.visionforgeMarkdown)
|
||||
api(projects.visionforge.cernRootLoader)
|
||||
}
|
||||
}
|
||||
|
||||
|
104
demo/playground/src/jvmMain/kotlin/rootParser.kt
Normal file
104
demo/playground/src/jvmMain/kotlin/rootParser.kt
Normal file
@ -0,0 +1,104 @@
|
||||
package space.kscience.visionforge.examples
|
||||
|
||||
import ru.mipt.npm.root.DGeoManager
|
||||
import ru.mipt.npm.root.serialization.TGeoManager
|
||||
import ru.mipt.npm.root.toSolid
|
||||
import space.kscience.dataforge.context.Context
|
||||
import space.kscience.dataforge.meta.Meta
|
||||
import space.kscience.dataforge.meta.get
|
||||
import space.kscience.dataforge.meta.isLeaf
|
||||
import space.kscience.dataforge.values.string
|
||||
import space.kscience.visionforge.solid.Solids
|
||||
|
||||
|
||||
private fun Meta.countTypes(): Sequence<String> = sequence {
|
||||
if (!isLeaf) {
|
||||
get("_typename")?.value?.let { yield(it.string) }
|
||||
items.forEach { yieldAll(it.value.countTypes()) }
|
||||
}
|
||||
}
|
||||
|
||||
fun main() {
|
||||
val context = Context {
|
||||
plugin(Solids)
|
||||
}
|
||||
|
||||
val string = TGeoManager::class.java.getResourceAsStream("/root/BM@N.root.json")!!
|
||||
.readAllBytes().decodeToString()
|
||||
|
||||
val geo = DGeoManager.parse(string)
|
||||
|
||||
|
||||
val sizes = geo.meta.countTypes().groupBy { it }.mapValues { it.value.size }
|
||||
sizes.forEach {
|
||||
println(it)
|
||||
}
|
||||
|
||||
|
||||
val solid = geo.toSolid()
|
||||
|
||||
//Paths.get("BM@N.vf.json").writeText(Solids.encodeToString(solid))
|
||||
//println(Solids.encodeToString(solid))
|
||||
|
||||
context.makeVisionFile {
|
||||
vision("canvas") {
|
||||
solid
|
||||
/* SolidGroup {
|
||||
set(
|
||||
"Coil",
|
||||
solid.getPrototype("Coil".asName())!!.apply {
|
||||
parent = null
|
||||
}
|
||||
)
|
||||
*//* group("Shade") {
|
||||
y = 200
|
||||
color("red")
|
||||
coneSurface(
|
||||
bottomOuterRadius = 135,
|
||||
bottomInnerRadius = 25,
|
||||
height = 50,
|
||||
topOuterRadius = 135,
|
||||
topInnerRadius = 25,
|
||||
angle = 1.5707964
|
||||
) {
|
||||
position = Point3D(79.6, 0, -122.1)
|
||||
rotation = Point3D(-1.5707964, 0, 0)
|
||||
}
|
||||
coneSurface(
|
||||
bottomOuterRadius = 135,
|
||||
bottomInnerRadius = 25,
|
||||
height = 50,
|
||||
topOuterRadius = 135,
|
||||
topInnerRadius = 25,
|
||||
angle = 1.5707964
|
||||
) {
|
||||
position = Point3D(-79.6, 0, -122.1)
|
||||
rotation = Point3D(1.5707964, 0, -3.1415927)
|
||||
}
|
||||
coneSurface(
|
||||
bottomOuterRadius = 135,
|
||||
bottomInnerRadius = 25,
|
||||
height = 50,
|
||||
topOuterRadius = 135,
|
||||
topInnerRadius = 25,
|
||||
angle = 1.5707964
|
||||
) {
|
||||
position = Point3D(79.6, 0, 122.1)
|
||||
rotation = Point3D(1.5707964, 0, 0)
|
||||
}
|
||||
coneSurface(
|
||||
bottomOuterRadius = 135,
|
||||
bottomInnerRadius = 25,
|
||||
height = 50,
|
||||
topOuterRadius = 135,
|
||||
topInnerRadius = 25,
|
||||
angle = 1.5707964
|
||||
) {
|
||||
position = Point3D(-79.6, 0, 122.1)
|
||||
rotation = Point3D(-1.5707964, 0, -3.1415927)
|
||||
}
|
||||
}*//*
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}
|
@ -48,7 +48,7 @@ public class FXCompositeFactory(public val plugin: FX3DPlugin) : FX3DFactory<Com
|
||||
val firstCSG = first.toCSG()
|
||||
val secondCSG = second.toCSG()
|
||||
val resultCSG = when (obj.compositeType) {
|
||||
CompositeType.SUM, CompositeType.UNION -> firstCSG.union(secondCSG)
|
||||
CompositeType.GROUP, CompositeType.UNION -> firstCSG.union(secondCSG)
|
||||
CompositeType.INTERSECT -> firstCSG.intersect(secondCSG)
|
||||
CompositeType.SUBTRACT -> firstCSG.difference(secondCSG)
|
||||
}
|
||||
|
@ -215,12 +215,12 @@ private class GdmlLoader(val settings: GdmlLoaderOptions) {
|
||||
val first: GdmlSolid = solid.first.resolve(root) ?: error("")
|
||||
val second: GdmlSolid = solid.second.resolve(root) ?: error("")
|
||||
val type: CompositeType = when (solid) {
|
||||
is GdmlUnion -> CompositeType.SUM // dumb sum for better performance
|
||||
is GdmlUnion -> CompositeType.GROUP // dumb sum for better performance
|
||||
is GdmlSubtraction -> CompositeType.SUBTRACT
|
||||
is GdmlIntersection -> CompositeType.INTERSECT
|
||||
}
|
||||
|
||||
return composite(type, name) {
|
||||
return smartComposite(type, name) {
|
||||
addSolid(root, first).withPosition(
|
||||
solid.resolveFirstPosition(root),
|
||||
solid.resolveFirstRotation(root),
|
||||
|
@ -2,6 +2,7 @@ package space.kscience.visionforge.solid
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import space.kscience.dataforge.meta.isEmpty
|
||||
import space.kscience.dataforge.meta.update
|
||||
import space.kscience.visionforge.VisionBuilder
|
||||
import space.kscience.visionforge.VisionContainerBuilder
|
||||
@ -9,7 +10,7 @@ import space.kscience.visionforge.VisionPropertyContainer
|
||||
import space.kscience.visionforge.set
|
||||
|
||||
public enum class CompositeType {
|
||||
SUM, // Dumb sum of meshes
|
||||
GROUP, // Dumb sum of meshes
|
||||
UNION, //CSG union
|
||||
INTERSECT,
|
||||
SUBTRACT
|
||||
@ -50,6 +51,31 @@ public inline fun VisionContainerBuilder<Solid>.composite(
|
||||
return res
|
||||
}
|
||||
|
||||
/**
|
||||
* A smart form of [Composite] that in case of [CompositeType.GROUP] creates a static group instead
|
||||
*/
|
||||
@VisionBuilder
|
||||
public fun SolidGroup.smartComposite(
|
||||
type: CompositeType,
|
||||
name: String? = null,
|
||||
builder: SolidGroup.() -> Unit,
|
||||
): Solid = if (type == CompositeType.GROUP) {
|
||||
val group = SolidGroup(builder)
|
||||
if (name == null && group.meta.isEmpty()) {
|
||||
//append directly to group if no properties are defined
|
||||
group.children.forEach { (key, value) ->
|
||||
value.parent = null
|
||||
set(null, value)
|
||||
}
|
||||
this
|
||||
} else {
|
||||
set(name, group)
|
||||
group
|
||||
}
|
||||
} else {
|
||||
composite(type, name, builder)
|
||||
}
|
||||
|
||||
@VisionBuilder
|
||||
public inline fun VisionContainerBuilder<Solid>.union(
|
||||
name: String? = null,
|
||||
|
@ -82,8 +82,8 @@ public fun SolidGroup(block: SolidGroup.() -> Unit): SolidGroup {
|
||||
@VisionBuilder
|
||||
public fun VisionContainerBuilder<Vision>.group(
|
||||
name: Name? = null,
|
||||
action: SolidGroup.() -> Unit = {},
|
||||
): SolidGroup = SolidGroup().apply(action).also { set(name, it) }
|
||||
builder: SolidGroup.() -> Unit = {},
|
||||
): SolidGroup = SolidGroup().apply(builder).also { set(name, it) }
|
||||
|
||||
/**
|
||||
* Define a group with given [name], attach it to this parent and return it.
|
||||
|
@ -5,5 +5,5 @@ plugins {
|
||||
dependencies {
|
||||
api(project(":visionforge-solid"))
|
||||
implementation(npm("three", "0.130.1"))
|
||||
implementation(npm("three-csg-ts", "3.1.6"))
|
||||
implementation(npm("three-csg-ts", "3.1.9"))
|
||||
}
|
||||
|
@ -167,7 +167,7 @@ public class ThreeCanvas(
|
||||
}
|
||||
|
||||
//Clipping planes
|
||||
options.useProperty(Canvas3DOptions::clipping){clipping ->
|
||||
options.useProperty(Canvas3DOptions::clipping) { clipping ->
|
||||
if (!clipping.meta.isEmpty()) {
|
||||
renderer.localClippingEnabled = true
|
||||
boundingBox?.let { boundingBox ->
|
||||
@ -192,7 +192,7 @@ public class ThreeCanvas(
|
||||
}
|
||||
}
|
||||
|
||||
options.useProperty(Canvas3DOptions::size){
|
||||
options.useProperty(Canvas3DOptions::size) {
|
||||
canvas.style.apply {
|
||||
minWidth = "${options.size.minWith.toInt()}px"
|
||||
maxWidth = "${options.size.maxWith.toInt()}px"
|
||||
@ -273,18 +273,14 @@ public class ThreeCanvas(
|
||||
return
|
||||
}
|
||||
if (this is Mesh) {
|
||||
if (highlight) {
|
||||
val edges = LineSegments(
|
||||
val edges = getObjectByName(edgesName) ?: LineSegments(
|
||||
EdgesGeometry(geometry),
|
||||
material
|
||||
).apply {
|
||||
name = edgesName
|
||||
}
|
||||
add(edges)
|
||||
} else {
|
||||
val highlightEdges = children.find { it.name == edgesName }
|
||||
highlightEdges?.let { remove(it) }
|
||||
).also {
|
||||
it.name = edgesName
|
||||
add(it)
|
||||
}
|
||||
edges.visible = highlight
|
||||
} else {
|
||||
children.filter { it.name != edgesName }.forEach {
|
||||
it.toggleHighlight(highlight, edgesName, material)
|
||||
|
@ -1,7 +1,6 @@
|
||||
package space.kscience.visionforge.solid.three
|
||||
|
||||
import CSG
|
||||
import info.laht.threekt.core.Object3D
|
||||
import info.laht.threekt.objects.Mesh
|
||||
import space.kscience.dataforge.names.startsWith
|
||||
import space.kscience.visionforge.onPropertyChange
|
||||
@ -38,11 +37,11 @@ public class ThreeCompositeFactory(public val three: ThreePlugin) : ThreeFactory
|
||||
|
||||
override val type: KClass<in Composite> get() = Composite::class
|
||||
|
||||
override fun invoke(three: ThreePlugin, obj: Composite): Object3D {
|
||||
override fun invoke(three: ThreePlugin, obj: Composite): Mesh {
|
||||
val first = three.buildObject3D(obj.first) as? Mesh ?: error("First part of composite is not a mesh")
|
||||
val second = three.buildObject3D(obj.second) as? Mesh ?: error("Second part of composite is not a mesh")
|
||||
return when (obj.compositeType) {
|
||||
CompositeType.SUM, CompositeType.UNION -> CSG.union(first, second)
|
||||
CompositeType.GROUP, CompositeType.UNION -> CSG.union(first, second)
|
||||
CompositeType.INTERSECT -> CSG.intersect(first, second)
|
||||
CompositeType.SUBTRACT -> CSG.subtract(first, second)
|
||||
}.apply {
|
||||
|
Loading…
Reference in New Issue
Block a user