Skip to content

Commit

Permalink
Fix ad-hoc meshing with agglomerates and cumsum.json (#7449)
Browse files Browse the repository at this point in the history
* Fix ad-hoc meshing with agglomerates and cumsum.json

* update comments

* changelog
  • Loading branch information
fm3 authored Nov 22, 2023
1 parent b4744b8 commit aa6b0c0
Show file tree
Hide file tree
Showing 5 changed files with 27 additions and 29 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ For upgrade instructions, please check the [migration guide](MIGRATIONS.released
- Fixed styling issues with the maintenance banner so that it no longer overlaps other menus, tabs, and buttons. [#7421](https://github.com/scalableminds/webknossos/pull/7421)
- Exploring HTTP uris of unknown hosts no longer causes an exception error message to be displayed. [#7422](https://github.com/scalableminds/webknossos/pull/7422)
- Fixed the initialization of the dark theme if it was active during page load. [#7446](https://github.com/scalableminds/webknossos/pull/7446)
- Fixed a rare bug in ad-hoc meshing for voxelytics-created segmentations with agglomerate mappings. [#7449](https://github.com/scalableminds/webknossos/pull/7449)

### Removed

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ case class VoxelPosition(
def move(dx: Int, dy: Int, dz: Int): VoxelPosition =
VoxelPosition(mag1X + dx, mag1Y + dy, mag1Z + dz, mag)

def toMag1: VoxelPosition = this.copy(mag = Vec3Int.ones) // other properties are already in mag1 and do not change.

override def toString = s"($mag1X, $mag1Y, $mag1Z) / $mag"

override def equals(obj: scala.Any): Boolean =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,11 @@ case class Cuboid(topLeft: VoxelPosition, width: Int, height: Int, depth: Int) {
}

def mag: Vec3Int = topLeft.mag

def toMag1: Cuboid = Cuboid(
topLeft.toMag1,
width * mag.x,
height * mag.y,
depth * mag.z
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ class AdHocMeshService(binaryDataService: BinaryDataService,

for {
data <- binaryDataService.handleDataRequest(dataRequest)
agglomerateMappedData <- applyAgglomerate(data).toFox
agglomerateMappedData <- applyAgglomerate(data) ?~> "failed to apply agglomerate for ad-hoc meshing"
typedData = convertData(agglomerateMappedData)
mappedData <- applyMapping(typedData)
mappedSegmentId <- applyMapping(Array(typedSegmentId)).map(_.head)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ import java.util

import ch.systemsx.cisd.hdf5.{HDF5DataSet, IHDF5Reader}
import com.scalableminds.util.cache.LRUConcurrentCache
import com.scalableminds.util.geometry.Vec3Int
import com.scalableminds.webknossos.datastore.dataformats.SafeCachable
import com.scalableminds.webknossos.datastore.models.VoxelPosition
import com.scalableminds.webknossos.datastore.models.requests.{Cuboid, DataServiceDataRequest}
import com.typesafe.scalalogging.LazyLogging

Expand Down Expand Up @@ -117,52 +115,42 @@ class BoundingBoxCache(
val boundingBoxFinder: BoundingBoxFinder, // saves the bb top left positions
val maxReaderRange: Long) // config value for maximum amount of elements that are allowed to be read as once
extends LazyLogging {
private def getGlobalCuboid(cuboid: Cuboid): Cuboid = {
val res = cuboid.mag
val tl = cuboid.topLeft
Cuboid(
VoxelPosition(tl.voxelXInMag * res.x, tl.voxelYInMag * res.y, tl.voxelZInMag * res.z, Vec3Int(1, 1, 1)),
cuboid.width * res.x,
cuboid.height * res.y,
cuboid.depth * res.z
)
}

// get the segment ID range for one cuboid
// get the segment id range for one cuboid
private def getReaderRange(request: DataServiceDataRequest): (Long, Long) = {
// convert cuboid to global coordinates (in res 1)
val globalCuboid = getGlobalCuboid(request.cuboid)
val requestedCuboidMag1 = request.cuboid.toMag1

// get min bounds
val initialBoundingBox = boundingBoxFinder.findInitialBoundingBox(globalCuboid)
val initialBoundingBoxTopleft: (Long, Long, Long) = boundingBoxFinder.findInitialBoundingBox(requestedCuboidMag1)

// get max bounds
val requestedCuboid = globalCuboid.bottomRight
val dataLayerBox = request.dataLayer.boundingBox.bottomRight
val requestedCuboidBottomRight = requestedCuboidMag1.bottomRight
val dataLayerBoxBottomRight = request.dataLayer.boundingBox.bottomRight

// use the values of first bb to initialize the range and dimensions
val initialValues = cache(initialBoundingBox)
val initialValues = cache(initialBoundingBoxTopleft)
var range = initialValues.idRange
var currDimensions = initialValues.dimensions

var x = initialBoundingBox._1
var y = initialBoundingBox._2
var z = initialBoundingBox._3
var x = initialBoundingBoxTopleft._1
var y = initialBoundingBoxTopleft._2
var z = initialBoundingBoxTopleft._3

// step through each bb, but save starting coordinates to reset iteration once the outer bound is reached
while (x < requestedCuboid.voxelXInMag && x < dataLayerBox.x) {
while (x < requestedCuboidBottomRight.voxelXInMag && x < dataLayerBoxBottomRight.x) {
val nextBBinX = (x + currDimensions._1, y, z)
while (y < requestedCuboid.voxelYInMag && y < dataLayerBox.y) {
currDimensions = (currDimensions._1, initialValues.dimensions._2, currDimensions._3) // reset currDimensions y to start next loop at beginning
while (y < requestedCuboidBottomRight.voxelYInMag && y < dataLayerBoxBottomRight.y) {
val nextBBinY = (x, y + currDimensions._2, z)
while (z < requestedCuboid.voxelZInMag && z < dataLayerBox.z) {
currDimensions = (currDimensions._1, currDimensions._2, initialValues.dimensions._3) // reset currDimensions z to start next loop at beginning
while (z < requestedCuboidBottomRight.voxelZInMag && z < dataLayerBoxBottomRight.z) {
// get cached values for current bb and update the reader range by extending if necessary
cache.get((x, y, z)).foreach { value =>
range = (Math.min(range._1, value.idRange._1), Math.max(range._2, value.idRange._2))
currDimensions = value.dimensions
}
z = z + currDimensions._3
}
x = nextBBinY._1
y = nextBBinY._2
z = nextBBinY._3
}
Expand All @@ -177,7 +165,7 @@ class BoundingBoxCache(
readHDF: (IHDF5Reader, Long, Long) => Array[Long]): Array[Long] = {
val readerRange = getReaderRange(request)
if (readerRange._2 - readerRange._1 < maxReaderRange) {
val agglomerateIds = readHDF(reader, readerRange._1.toLong, (readerRange._2 - readerRange._1).toLong + 1)
val agglomerateIds = readHDF(reader, readerRange._1, (readerRange._2 - readerRange._1) + 1)
input.map(i => if (i == 0L) 0L else agglomerateIds((i - readerRange._1).toInt))
} else {
// if reader range does not fit in main memory, read agglomerate ids in chunks
Expand All @@ -186,7 +174,7 @@ class BoundingBoxCache(
val isTransformed = Array.fill(input.length)(false)
while (offset <= readerRange._2) {
val agglomerateIds: Array[Long] =
readHDF(reader, offset.toLong, spire.math.min(maxReaderRange, readerRange._2 - offset).toLong + 1)
readHDF(reader, offset, spire.math.min(maxReaderRange, readerRange._2 - offset) + 1)
for (i <- input.indices) {
val inputElement = input(i)
if (!isTransformed(i) && inputElement >= offset && inputElement < offset + maxReaderRange) {
Expand Down

0 comments on commit aa6b0c0

Please sign in to comment.