Composite Union is replaced by a Group. Colors for root

This commit is contained in:
Alexander Nozik 2021-09-06 22:48:03 +03:00
parent aea4eb7d45
commit 2e3b63c0f4
14 changed files with 207 additions and 107 deletions

View File

@ -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()}]" }) }
}

View File

@ -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]
}
}
}

View File

@ -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]
}

View File

@ -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))
}

View File

@ -55,6 +55,7 @@ kotlin {
api(project(":visionforge-gdml"))
api(project(":visionforge-plotly"))
api(projects.visionforge.visionforgeMarkdown)
api(projects.visionforge.cernRootLoader)
}
}

View 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)
}
}*//*
}*/
}
}
}

View File

@ -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)
}

View File

@ -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),

View File

@ -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,

View File

@ -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.

View File

@ -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"))
}

View File

@ -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(
EdgesGeometry(geometry),
material
).apply {
name = edgesName
}
add(edges)
} else {
val highlightEdges = children.find { it.name == edgesName }
highlightEdges?.let { remove(it) }
val edges = getObjectByName(edgesName) ?: LineSegments(
EdgesGeometry(geometry),
material
).also {
it.name = edgesName
add(it)
}
edges.visible = highlight
} else {
children.filter { it.name != edgesName }.forEach {
it.toggleHighlight(highlight, edgesName, material)

View File

@ -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 {