Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avoid errors on zarr dataset settings page #7475

Merged
merged 3 commits into from
Dec 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ For upgrade instructions, please check the [migration guide](MIGRATIONS.released
### Fixed
- Fixed several deprecation warning for using antd's Tabs.TabPane components. [#7469]
- Fixed problems when requests for loading data failed (could impact volume data consistency and rendering). [#7477](https://github.com/scalableminds/webknossos/pull/7477)
- The settings page for non-wkw datasets no longer shows a wall of non-applying errors. [#7475](https://github.com/scalableminds/webknossos/pull/7475)

### Removed

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ object BoundingBox {
"\\s*((?:\\-)?[0-9]+),\\s*((?:\\-)?[0-9]+),\\s*((?:\\-)?[0-9]+)\\s*,\\s*([0-9]+),\\s*([0-9]+),\\s*([0-9]+)\\s*".r

def empty: BoundingBox =
BoundingBox(Vec3Int(0, 0, 0), 0, 0, 0)
BoundingBox(Vec3Int.zeros, 0, 0, 0)

def fromLiteral(s: String): Option[BoundingBox] =
s match {
Expand Down Expand Up @@ -111,7 +111,7 @@ object BoundingBox {
case head :: tail =>
tail.foldLeft(head)(_ union _)
case _ =>
BoundingBox(Vec3Int(0, 0, 0), 0, 0, 0)
BoundingBox.empty
}

def intersection(bbs: List[BoundingBox]): Option[BoundingBox] =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ object Vec3Double {

def ones: Vec3Double = Vec3Double(1.0, 1.0, 1.0)

def zeros: Vec3Double = Vec3Double(0.0, 0.0, 0.0)

implicit object Vector3DReads extends Format[Vec3Double] {
def reads(json: JsValue): JsResult[Vec3Double] = json match {
case JsArray(ts) if ts.size == 3 =>
Expand Down
13 changes: 8 additions & 5 deletions util/src/main/scala/com/scalableminds/util/io/PathUtils.scala
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,11 @@ trait PathUtils extends LazyLogging {
else
None

def listDirectoryEntries[A](directory: Path,
maxDepth: Int,
dropCount: Int,
silent: Boolean,
filters: (Path => Boolean)*)(f: Iterator[Path] => Box[A]): Box[A] =
private def listDirectoryEntries[A](directory: Path,
maxDepth: Int,
dropCount: Int,
silent: Boolean,
filters: (Path => Boolean)*)(f: Iterator[Path] => Box[A]): Box[A] =
try {
val directoryStream = Files.walk(directory, maxDepth, FileVisitOption.FOLLOW_LINKS)
val r = f(directoryStream.iterator().asScala.drop(dropCount).filter(d => filters.forall(_(d))))
Expand Down Expand Up @@ -82,6 +82,9 @@ trait PathUtils extends LazyLogging {
Failure(errorMsg)
}

def containsFile(directory: Path, maxDepth: Int, silent: Boolean, filters: (Path => Boolean)*): Box[Boolean] =
listDirectoryEntries(directory, maxDepth, dropCount = 0, silent, filters :+ fileFilter _: _*)(r => Full(r.nonEmpty))

def listDirectories(directory: Path, silent: Boolean, filters: (Path => Boolean)*): Box[List[Path]] =
listDirectoryEntries(directory, 1, 1, silent, filters :+ directoryFilter _: _*)(r => Full(r.toList))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -253,8 +253,8 @@ Expects:
}

@ApiOperation(hidden = true, value = "")
def explore(token: Option[String], organizationName: String, dataSetName: String): Action[AnyContent] = Action.async {
implicit request =>
def suggestDatasourceJson(token: Option[String], organizationName: String, dataSetName: String): Action[AnyContent] =
Action.async { implicit request =>
accessTokenService.validateAccessForSyncBlock(
UserAccessRequest.writeDataSource(DataSourceId(dataSetName, organizationName)),
urlOrHeaderToken(token, request)) {
Expand All @@ -280,7 +280,7 @@ Expects:
))
}
}
}
}

@ApiOperation(hidden = true, value = "")
def listMappings(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ object SkeletonTracingDefaults extends ProtoGeometryImplicits {
private def createdTimestamp = System.currentTimeMillis()
private val boundingBox = None
private val activeNodeId = None
val editPosition: Vec3Int = Vec3Int(0, 0, 0)
val editRotation: Vec3Double = Vec3Double(0, 0, 0)
val editPosition: Vec3Int = Vec3Int.zeros
val editRotation: Vec3Double = Vec3Double.zeros
val zoomLevel: Double = 2.0
private val version = 0
private val userBoundingBox = None
Expand All @@ -30,8 +30,8 @@ object SkeletonTracingDefaults extends ProtoGeometryImplicits {

object NodeDefaults extends ProtoGeometryImplicits {
val id: Int = 0
val rotation: Vec3Double = Vec3Double(0, 0, 0)
val position: Vec3Int = Vec3Int(0, 0, 0)
val rotation: Vec3Double = Vec3Double.zeros
val position: Vec3Int = Vec3Int.zeros
val radius: Float = 1.0f
val viewport: Int = 1
val resolution: Int = 1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ case class DataServiceDataRequest(
dataLayerMapping: Option[String],
cuboid: Cuboid,
settings: DataServiceRequestSettings,
subsamplingStrides: Vec3Int = Vec3Int(1, 1, 1) // if > 1, skip voxels when loading (used for adhoc mesh generation)
subsamplingStrides: Vec3Int = Vec3Int.ones // if > 1, skip voxels when loading (used for adhoc mesh generation)
)

case class DataReadInstruction(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class BinaryDataService(val dataBaseDir: Path,

if (!request.cuboid.hasValidDimensions) {
Fox.failure("Invalid cuboid dimensions (must be > 0 and <= 512).")
} else if (request.cuboid.isSingleBucket(DataLayer.bucketLength) && request.subsamplingStrides == Vec3Int(1, 1, 1)) {
} else if (request.cuboid.isSingleBucket(DataLayer.bucketLength) && request.subsamplingStrides == Vec3Int.ones) {
bucketQueue.headOption.toFox.flatMap { bucket =>
handleBucketRequest(request, bucket.copy(additionalCoordinates = request.settings.additionalCoordinates))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ trait DataFinder {
val voxelOffset = scaledX + scaledY + scaledZ
if (data.slice(voxelOffset, voxelOffset + bytesPerElement).exists(_ != 0)) return Vec3Int(x, y, z)
}
Vec3Int(0, 0, 0)
Vec3Int.zeros
}

def getPositionOfNonZeroData(data: Array[Byte],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.scalableminds.webknossos.datastore.services

import java.nio.file.Path

import com.scalableminds.util.geometry.{Vec3Double, Vec3Int}
import com.scalableminds.util.io.PathUtils
import com.scalableminds.webknossos.datastore.dataformats.MappingProvider
Expand All @@ -28,6 +27,11 @@ trait DataSourceImporter {
protected def exploreLayer(name: String, baseDir: Path, previous: Option[DataLayer])(
implicit report: DataSourceImportReport[Path]): Box[DataLayer]

private def wkwFileFilter(path: Path): Boolean = path.getFileName.toString.toLowerCase().endsWith(".wkw")

def looksLikeWKWDataSource(baseDir: Path): Box[Boolean] =
PathUtils.containsFile(baseDir, maxDepth = 3, silent = true, filters = wkwFileFilter)

def exploreDataSource(id: DataSourceId,
baseDir: Path,
previous: Option[DataSource],
Expand All @@ -40,10 +44,18 @@ trait DataSourceImporter {
}
GenericDataSource(id,
layers,
previous.map(_.scale).getOrElse(Vec3Double(0, 0, 0)),
previous.map(_.scale).getOrElse(Vec3Double.zeros),
previous.flatMap(_.defaultViewConfiguration))
}

def dummyDataSource(id: DataSourceId,
previous: Option[DataSource],
report: DataSourceImportReport[Path]): Box[DataSource] = {
report.warning(_ =>
"Automatic suggestions for the datasource-properties.json are not available since the dataset is not in WKW format.")
previous.orElse(Some(GenericDataSource(id, List.empty, Vec3Double.zeros)))
}

protected def guessLayerCategory(layerName: String, elementClass: ElementClass.Value)(
implicit report: DataSourceImportReport[Path]): Category.Value = {
val ColorRx = ".*color.*".r
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,9 @@ class DataSourceService @Inject()(
val path = dataBaseDir.resolve(id.team).resolve(id.name)
val report = DataSourceImportReport[Path](dataBaseDir.relativize(path))
for {
dataSource <- WKWDataFormat.exploreDataSource(id, path, previous, report)
looksLikeWKWDataSource <- WKWDataFormat.looksLikeWKWDataSource(path)
dataSource <- if (looksLikeWKWDataSource) WKWDataFormat.exploreDataSource(id, path, previous, report)
else WKWDataFormat.dummyDataSource(id, previous, report)
} yield (dataSource, report.messages.toList)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ GET /datasets/:organizationName/:dataSetName/readInboxDataSourceLike
GET /datasets/:organizationName/:dataSetName/readInboxDataSource @com.scalableminds.webknossos.datastore.controllers.DataSourceController.read(token: Option[String], organizationName: String, dataSetName: String, returnFormatLike: Boolean ?= false)
POST /datasets/:organizationName/:dataSetName @com.scalableminds.webknossos.datastore.controllers.DataSourceController.update(token: Option[String], organizationName: String, dataSetName: String)
PUT /datasets/:organizationName/:dataSetName @com.scalableminds.webknossos.datastore.controllers.DataSourceController.add(token: Option[String], organizationName: String, dataSetName: String, folderId: Option[String])
GET /datasets/:organizationName/:dataSetName @com.scalableminds.webknossos.datastore.controllers.DataSourceController.explore(token: Option[String], organizationName: String, dataSetName: String)
GET /datasets/:organizationName/:dataSetName @com.scalableminds.webknossos.datastore.controllers.DataSourceController.suggestDatasourceJson(token: Option[String], organizationName: String, dataSetName: String)
DELETE /datasets/:organizationName/:dataSetName/deleteOnDisk @com.scalableminds.webknossos.datastore.controllers.DataSourceController.deleteOnDisk(token: Option[String], organizationName: String, dataSetName: String)

# Actions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ class VolumeTracingController @Inject()(
for {
positionOpt <- tracingService.findData(tracingId)
} yield {
Ok(Json.obj("position" -> positionOpt, "resolution" -> positionOpt.map(_ => Vec3Int(1, 1, 1))))
Ok(Json.obj("position" -> positionOpt, "resolution" -> positionOpt.map(_ => Vec3Int.ones)))
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ case class VolumeTracingLayer(
def bucketProvider: AbstractVolumeTracingBucketProvider = volumeBucketProvider

override val resolutions: List[Vec3Int] =
if (volumeResolutions.nonEmpty) volumeResolutions else List(Vec3Int(1, 1, 1))
if (volumeResolutions.nonEmpty) volumeResolutions else List(Vec3Int.ones)

override def containsResolution(resolution: Vec3Int) =
true // allow requesting buckets of all resolutions. database takes care of missing.
Expand Down