Skip to content

Commit

Permalink
Merge pull request #353 from scenerygraphics/improve-add-returntype
Browse files Browse the repository at this point in the history
SciView: improve add methods
  • Loading branch information
kephale authored Mar 31, 2021
2 parents 780af76 + 8433897 commit 92add67
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 87 deletions.
100 changes: 57 additions & 43 deletions src/main/java/sc/iview/SciView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -576,7 +576,7 @@ class SciView : SceneryBase, CalibratedRealInterval<CalibratedAxis> {
*/
@JvmOverloads
fun addBox(position: Vector3f = Vector3f(0.0f, 0.0f, 0.0f), size: Vector3f = Vector3f(1.0f, 1.0f, 1.0f), color: ColorRGB = DEFAULT_COLOR,
inside: Boolean = false): Node? {
inside: Boolean = false, block: Box.() -> Unit = {}): Box {
// TODO: use a material from the current palate by default
val boxmaterial = Material()
boxmaterial.ambient = Vector3f(1.0f, 0.0f, 0.0f)
Expand All @@ -586,15 +586,15 @@ class SciView : SceneryBase, CalibratedRealInterval<CalibratedAxis> {
val box = Box(size, inside)
box.material = boxmaterial
box.position = position
return addNode(box)
return addNode(box, block = block)
}

/**
* Add a unit sphere at a given [position] with given [radius] and [color].
* @return the Node corresponding to the sphere
*/
@JvmOverloads
fun addSphere(position: Vector3f = Vector3f(0.0f, 0.0f, 0.0f), radius: Float = 1f, color: ColorRGB = DEFAULT_COLOR): Node? {
fun addSphere(position: Vector3f = Vector3f(0.0f, 0.0f, 0.0f), radius: Float = 1f, color: ColorRGB = DEFAULT_COLOR, block: Sphere.() -> Unit = {}): Sphere {
val material = Material()
material.ambient = Vector3f(1.0f, 0.0f, 0.0f)
material.diffuse = Utils.convertToVector3f(color)
Expand All @@ -603,8 +603,7 @@ class SciView : SceneryBase, CalibratedRealInterval<CalibratedAxis> {
val sphere = Sphere(radius, 20)
sphere.material = material
sphere.position = position

return addNode(sphere)
return addNode(sphere, block = block)
}

/**
Expand All @@ -615,10 +614,10 @@ class SciView : SceneryBase, CalibratedRealInterval<CalibratedAxis> {
* @param num_segments number of segments to represent the cylinder
* @return the Node corresponding to the cylinder
*/
fun addCylinder(position: Vector3f, radius: Float, height: Float, num_segments: Int): Node? {
fun addCylinder(position: Vector3f, radius: Float, height: Float, num_segments: Int, block: Cylinder.() -> Unit = {}): Cylinder {
val cyl = Cylinder(radius, height, num_segments)
cyl.position = position
return addNode(cyl)
return addNode(cyl, block = block)
}

/**
Expand All @@ -629,10 +628,10 @@ class SciView : SceneryBase, CalibratedRealInterval<CalibratedAxis> {
* @param num_segments number of segments used to represent cone
* @return the Node corresponding to the cone
*/
fun addCone(position: Vector3f, radius: Float, height: Float, num_segments: Int): Node? {
fun addCone(position: Vector3f, radius: Float, height: Float, num_segments: Int, block: Cone.() -> Unit = {}): Cone {
val cone = Cone(radius, height, num_segments, Vector3f(0.0f, 0.0f, 1.0f))
cone.position = position
return addNode(cone)
return addNode(cone, block = block)
}

/**
Expand All @@ -643,8 +642,8 @@ class SciView : SceneryBase, CalibratedRealInterval<CalibratedAxis> {
* @return the Node corresponding to the line
*/
@JvmOverloads
fun addLine(start: Vector3f = Vector3f(0.0f, 0.0f, 0.0f), stop: Vector3f = Vector3f(1.0f, 1.0f, 1.0f), color: ColorRGB = DEFAULT_COLOR): Node? {
return addLine(arrayOf(start, stop), color, 0.1)
fun addLine(start: Vector3f = Vector3f(0.0f, 0.0f, 0.0f), stop: Vector3f = Vector3f(1.0f, 1.0f, 1.0f), color: ColorRGB = DEFAULT_COLOR, block: Line.() -> Unit = {}): Line {
return addLine(arrayOf(start, stop), color, 0.1, block)
}

/**
Expand All @@ -654,7 +653,8 @@ class SciView : SceneryBase, CalibratedRealInterval<CalibratedAxis> {
* @param edgeWidth width of line segments
* @return the Node corresponding to the line
*/
fun addLine(points: Array<Vector3f>, color: ColorRGB, edgeWidth: Double): Node? {
@JvmOverloads
fun addLine(points: Array<Vector3f>, color: ColorRGB, edgeWidth: Double, block: Line.() -> Unit = {}): Line {
val material = Material()
material.ambient = Vector3f(1.0f, 1.0f, 1.0f)
material.diffuse = Utils.convertToVector3f(color)
Expand All @@ -666,14 +666,15 @@ class SciView : SceneryBase, CalibratedRealInterval<CalibratedAxis> {
line.edgeWidth = edgeWidth.toFloat()
line.material = material
line.position = points[0]
return addNode(line)
return addNode(line, block = block)
}

/**
* Add a PointLight source at the origin
* @return a Node corresponding to the PointLight
*/
fun addPointLight(): Node? {
@JvmOverloads
fun addPointLight(block: PointLight.() -> Unit = {}): PointLight {
val material = Material()
material.ambient = Vector3f(1.0f, 0.0f, 0.0f)
material.diffuse = Vector3f(0.0f, 1.0f, 0.0f)
Expand All @@ -682,7 +683,7 @@ class SciView : SceneryBase, CalibratedRealInterval<CalibratedAxis> {
light.material = material
light.position = Vector3f(0.0f, 0.0f, 0.0f)
lights!!.add(light)
return addNode(light)
return addNode(light, block = block)
}

/**
Expand Down Expand Up @@ -762,7 +763,8 @@ class SciView : SceneryBase, CalibratedRealInterval<CalibratedAxis> {
@JvmOverloads
fun addPointCloud(points: Collection<RealLocalizable>,
name: String? = "PointCloud",
pointSize : Float = 1.0f): Node? {
pointSize : Float = 1.0f,
block: PointCloud.() -> Unit = {}): PointCloud {
val flatVerts = FloatArray(points.size * 3)
var k = 0
for (point in points) {
Expand All @@ -782,18 +784,19 @@ class SciView : SceneryBase, CalibratedRealInterval<CalibratedAxis> {
pointCloud.position = Vector3f(0f, 0f, 0f)

pointCloud.setupPointCloud()
return addNode(pointCloud)
return addNode(pointCloud, block = block)
}

/**
* Add a PointCloud to the scene
* @param pointCloud existing PointCloud to add to scene
* @return a Node corresponding to the PointCloud
*/
fun addPointCloud(pointCloud: PointCloud): Node? {
@JvmOverloads
fun addPointCloud(pointCloud: PointCloud, block: PointCloud.() -> Unit = {}): PointCloud {
pointCloud.setupPointCloud()
pointCloud.position = Vector3f(0f, 0f, 0f)
return addNode(pointCloud)
return addNode(pointCloud, block = block)
}

/**
Expand All @@ -803,8 +806,9 @@ class SciView : SceneryBase, CalibratedRealInterval<CalibratedAxis> {
* @return a Node corresponding to the Node
*/
@JvmOverloads
fun addNode(n: Node?, activePublish: Boolean = true): Node? {
fun <N: Node?> addNode(n: N, activePublish: Boolean = true, block: N.() -> Unit = {}): N {
n?.let {
it.block()
scene.addChild(it)
objectService.addObject(n)
if (blockOnNewNodes) {
Expand All @@ -828,7 +832,7 @@ class SciView : SceneryBase, CalibratedRealInterval<CalibratedAxis> {
* @param scMesh scenery mesh to add to scene
* @return a Node corresponding to the mesh
*/
fun addMesh(scMesh: graphics.scenery.Mesh): Node? {
fun addMesh(scMesh: graphics.scenery.Mesh): graphics.scenery.Mesh {
val material = Material()
material.ambient = Vector3f(1.0f, 0.0f, 0.0f)
material.diffuse = Vector3f(0.0f, 1.0f, 0.0f)
Expand All @@ -844,7 +848,7 @@ class SciView : SceneryBase, CalibratedRealInterval<CalibratedAxis> {
* @param mesh net.imagej.mesh to add to scene
* @return a Node corresponding to the mesh
*/
fun addMesh(mesh: Mesh): Node? {
fun addMesh(mesh: Mesh): graphics.scenery.Mesh {
val scMesh = MeshConverter.toScenery(mesh)
return addMesh(scMesh)
}
Expand Down Expand Up @@ -1123,14 +1127,15 @@ class SciView : SceneryBase, CalibratedRealInterval<CalibratedAxis> {
* @param image image to add as a volume
* @return a Node corresponding to the Volume
*/
fun addVolume(image: Dataset): Node? {
@JvmOverloads
fun addVolume(image: Dataset, block: Volume.() -> Unit = {}): Volume {
val voxelDims = FloatArray(image.numDimensions())
for (d in voxelDims.indices) {
val inValue = image.axis(d).averageScale(0.0, 1.0)
if (image.axis(d).unit() == null) voxelDims[d] = inValue.toFloat() else voxelDims[d] = unitService.value(inValue, image.axis(d).unit(), axis(d)!!.unit()).toFloat()
}
logger.info("Adding with ${voxelDims.joinToString(",")}")
return addVolume(image, voxelDims)
return addVolume(image, voxelDims, block)
}

/**
Expand All @@ -1139,10 +1144,11 @@ class SciView : SceneryBase, CalibratedRealInterval<CalibratedAxis> {
* @param voxelDimensions dimensions of voxels in volume
* @return a Node corresponding to the Volume
*/
@JvmOverloads
@Suppress("UNCHECKED_CAST")
fun addVolume(image: Dataset, voxelDimensions: FloatArray): Node? {
return addVolume<RealType<*>>(image.imgPlus as RandomAccessibleInterval<RealType<*>>, image.name ?: "Volume",
*voxelDimensions)
fun addVolume(image: Dataset, voxelDimensions: FloatArray, block: Volume.() -> Unit = {}): Volume {
return addVolume(image.imgPlus as RandomAccessibleInterval<RealType<*>>, image.name ?: "Volume",
*voxelDimensions, block = block)
}

/**
Expand All @@ -1151,8 +1157,9 @@ class SciView : SceneryBase, CalibratedRealInterval<CalibratedAxis> {
* @param <T> pixel type of image
* @return a Node corresponding to the volume
</T> */
fun <T : RealType<T>> addVolume(image: RandomAccessibleInterval<T>, name: String = "Volume"): Node? {
return addVolume(image, name, 1f, 1f, 1f)
@JvmOverloads
fun <T : RealType<T>> addVolume(image: RandomAccessibleInterval<T>, name: String = "Volume", block: Volume.() -> Unit = {}): Volume {
return addVolume(image, name, 1f, 1f, 1f, block = block)
}

/**
Expand All @@ -1161,8 +1168,8 @@ class SciView : SceneryBase, CalibratedRealInterval<CalibratedAxis> {
* @param <T> pixel type of image
* @return a Node corresponding to the volume
</T> */
fun <T : RealType<T>> addVolume(image: RandomAccessibleInterval<T>, voxelDimensions: FloatArray): Node? {
return addVolume(image, "volume", *voxelDimensions)
fun <T : RealType<T>> addVolume(image: RandomAccessibleInterval<T>, voxelDimensions: FloatArray, block: Volume.() -> Unit): Volume {
return addVolume(image, "volume", *voxelDimensions, block = block)
}

/**
Expand All @@ -1173,7 +1180,7 @@ class SciView : SceneryBase, CalibratedRealInterval<CalibratedAxis> {
</T> */
@Suppress("UNCHECKED_CAST")
@Throws(Exception::class)
fun <T : RealType<T>?> addVolume(image: IterableInterval<T>): Node? {
fun <T : RealType<T>> addVolume(image: IterableInterval<T>): Volume {
return if (image is RandomAccessibleInterval<*>) {
addVolume(image as RandomAccessibleInterval<RealType<*>>, "Volume")
} else {
Expand All @@ -1190,7 +1197,7 @@ class SciView : SceneryBase, CalibratedRealInterval<CalibratedAxis> {
</T> */
@Suppress("UNCHECKED_CAST")
@Throws(Exception::class)
fun <T : RealType<T>?> addVolume(image: IterableInterval<T>, name: String = "Volume"): Node? {
fun <T : RealType<T>> addVolume(image: IterableInterval<T>, name: String = "Volume"): Volume {
return if (image is RandomAccessibleInterval<*>) {
addVolume(image as RandomAccessibleInterval<RealType<*>>, name, 1f, 1f, 1f)
} else {
Expand Down Expand Up @@ -1251,13 +1258,15 @@ class SciView : SceneryBase, CalibratedRealInterval<CalibratedAxis> {
* @param <T> Type of the dataset.
* @return THe node corresponding to the volume just added.
</T> */
@JvmOverloads
fun <T : RealType<T>> addVolume(sac: SourceAndConverter<T>,
numTimepoints: Int,
name: String = "Volume",
vararg voxelDimensions: Float): Node? {
vararg voxelDimensions: Float,
block: Volume.() -> Unit = {}): Volume {
val sources: MutableList<SourceAndConverter<T>> = ArrayList()
sources.add(sac)
return addVolume(sources, numTimepoints, name, *voxelDimensions)
return addVolume(sources, numTimepoints, name, *voxelDimensions, block = block)
}

/**
Expand All @@ -1269,8 +1278,9 @@ class SciView : SceneryBase, CalibratedRealInterval<CalibratedAxis> {
* @param <T> pixel type of image
* @return a Node corresponding to the Volume
</T> */
@JvmOverloads
fun <T : RealType<T>> addVolume(image: RandomAccessibleInterval<T>, name: String = "Volume",
vararg voxelDimensions: Float): Node? {
vararg voxelDimensions: Float, block: Volume.() -> Unit = {}): Volume {
//log.debug( "Add Volume " + name + " image: " + image );
val dimensions = LongArray(image.numDimensions())
image.dimensions(dimensions)
Expand Down Expand Up @@ -1299,8 +1309,8 @@ class SciView : SceneryBase, CalibratedRealInterval<CalibratedAxis> {
converterSetups.add(BigDataViewer.createConverterSetup(source, setupId.getAndIncrement()))
sources.add(source)
}
val v = addVolume(sources, numTimepoints, name, *voxelDimensions)
v?.metadata?.set("RandomAccessibleInterval", image)
val v = addVolume(sources, numTimepoints, name, *voxelDimensions, block = block)
v.metadata.set("RandomAccessibleInterval", image)
return v
}

Expand All @@ -1315,12 +1325,14 @@ class SciView : SceneryBase, CalibratedRealInterval<CalibratedAxis> {
* @param <T> Type of the dataset.
* @return THe node corresponding to the volume just added.
</T> */
@JvmOverloads
@Suppress("UNCHECKED_CAST")
fun <T : NumericType<T>> addVolume(sources: List<SourceAndConverter<T>>,
converterSetups: ArrayList<ConverterSetup>,
numTimepoints: Int,
name: String = "Volume",
vararg voxelDimensions: Float): Node? {
vararg voxelDimensions: Float,
block: Volume.() -> Unit = {}): Volume {
var timepoints = numTimepoints
var cacheControl: CacheControl? = null

Expand Down Expand Up @@ -1363,7 +1375,7 @@ class SciView : SceneryBase, CalibratedRealInterval<CalibratedAxis> {
tf.addControlPoint(1.0f, rampMax)
val bg = BoundingGrid()
bg.node = v
return addNode(v)
return addNode(v, block = block)
}

/**
Expand All @@ -1375,16 +1387,18 @@ class SciView : SceneryBase, CalibratedRealInterval<CalibratedAxis> {
* @param <T> Type of the dataset.
* @return THe node corresponding to the volume just added.
</T> */
@JvmOverloads
fun <T : RealType<T>> addVolume(sources: List<SourceAndConverter<T>>,
numTimepoints: Int,
name: String = "Volume",
vararg voxelDimensions: Float): Node? {
vararg voxelDimensions: Float,
block: Volume.() -> Unit = {}): Volume {
var setupId = 0
val converterSetups = ArrayList<ConverterSetup>()
for (source in sources) {
converterSetups.add(BigDataViewer.createConverterSetup(source, setupId++))
}
return addVolume(sources, converterSetups, numTimepoints, name, *voxelDimensions)
return addVolume(sources, converterSetups, numTimepoints, name, *voxelDimensions, block = block)
}

/**
Expand All @@ -1399,7 +1413,7 @@ class SciView : SceneryBase, CalibratedRealInterval<CalibratedAxis> {
</T> */
@Suppress("UNCHECKED_CAST")
fun <T : RealType<T>> updateVolume(image: IterableInterval<T>, name: String,
voxelDimensions: FloatArray, v: Volume): Node {
voxelDimensions: FloatArray, v: Volume): Volume {
val sacs = v.metadata["sources"] as List<SourceAndConverter<T>>?
val source = sacs!![0].spimSource.getSource(0, 0) // hard coded to timepoint and mipmap 0
val sCur = Views.iterable(source).cursor()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,19 +140,20 @@ class LoadCremiDatasetAndNeurons: Command {
cursor.get().set(0)
}

val volume = sciview.addVolume(nai.third, files.first().name) as? Volume
volume?.origin = Origin.FrontBottomLeft
volume?.scale = Vector3f(0.08f, 0.08f, 5.0f)
volume?.transferFunction = TransferFunction.ramp(0.3f, 0.1f, 0.1f)
// min 20, max 180, color map fire

volume?.transferFunction?.addControlPoint(0.3f, 0.5f)
volume?.transferFunction?.addControlPoint(0.8f, 0.01f)
volume?.converterSetups?.get(0)?.setDisplayRange(20.0, 220.0)
val colormap = lut.loadLUT(lut.findLUTs().get("Grays.lut"))
val colormapVolume = lut.loadLUT(lut.findLUTs().get("Grays.lut"))
val colormapNeurons = lut.loadLUT(lut.findLUTs().get("Fire.lut"))

volume?.colormap = Colormap.fromColorTable(colormap)
sciview.addVolume(nai.third, files.first().name) {
origin = Origin.FrontBottomLeft
scale = Vector3f(0.08f, 0.08f, 5.0f)
transferFunction = TransferFunction.ramp(0.3f, 0.1f, 0.1f)
// min 20, max 180, color map fire

transferFunction.addControlPoint(0.3f, 0.5f)
transferFunction.addControlPoint(0.8f, 0.01f)
converterSetups.get(0).setDisplayRange(20.0, 220.0)
colormap = Colormap.fromColorTable(colormapVolume)
}


task.status = "Creating labeling"
Expand Down Expand Up @@ -184,12 +185,12 @@ class LoadCremiDatasetAndNeurons: Command {
log.info("Converting neuron ${i + 1}/${largestNeuronLabels.size} to scenery format...")
// Convert the mesh into a scenery mesh for visualization
val mesh = MeshConverter.toScenery(m, false, flipWindingOrder = true)
mesh.scale = Vector3f(0.01f, 0.01f, 0.06f)
mesh.material.diffuse = colormapNeurons.lookupARGB(0.0, 255.0, kotlin.random.Random.nextDouble(0.0, 255.0)).toRGBColor().xyz()
mesh.material.roughness = 0.0f

mesh.name = "Neuron $i"
sciview.addNode(mesh)
sciview.addNode(mesh) {
scale = Vector3f(0.01f, 0.01f, 0.06f)
material.diffuse = colormapNeurons.lookupARGB(0.0, 255.0, kotlin.random.Random.nextDouble(0.0, 255.0)).toRGBColor().xyz()
material.roughness = 0.0f
name = "Neuron $i"
}
val completion = 10.0f + ((i+1)/largestNeuronLabels.size.toFloat())*90.0f
task.completion = completion
}
Expand Down
Loading

0 comments on commit 92add67

Please sign in to comment.