- 
                Notifications
    You must be signed in to change notification settings 
- Fork 29
Use datastore segment index when loading ad-hoc meshes #8922
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
Changes from 11 commits
fc75c5e
              32dae79
              ad0fb3d
              c7127ba
              bc96b43
              66089d0
              46fa4df
              5e58f24
              2cfdbb3
              a55cfb8
              458a36c
              be864da
              c5f4b80
              c97b9df
              82821e3
              3786af5
              76091f9
              30f80f6
              75d920d
              f0911f7
              c5fd2be
              a459350
              189617f
              09c9074
              1765442
              086162f
              399241e
              File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| ### Added | ||
| - The segment index file is now used while rendering ad-hoc meshes for static segmentation layers, e.g. when viewing a dataset. | 
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
|  | @@ -13,6 +13,7 @@ import com.scalableminds.webknossos.datastore.services._ | |
| import com.typesafe.scalalogging.LazyLogging | ||
| import com.scalableminds.util.tools.Box.tryo | ||
| import com.scalableminds.webknossos.datastore.services.mapping.MappingService | ||
| import com.scalableminds.webknossos.datastore.services.segmentindex.SegmentIndexFileService | ||
| import play.api.i18n.MessagesProvider | ||
| import play.api.libs.json.{Json, OFormat} | ||
|  | ||
|  | @@ -40,6 +41,7 @@ class DSFullMeshService @Inject()(meshFileService: MeshFileService, | |
| val dsRemoteTracingstoreClient: DSRemoteTracingstoreClient, | ||
| mappingService: MappingService, | ||
| config: DataStoreConfig, | ||
| segmentIndexFileService: SegmentIndexFileService, | ||
| adHocMeshServiceHolder: AdHocMeshServiceHolder) | ||
| extends LazyLogging | ||
| with FullMeshHelper | ||
|  | @@ -66,26 +68,85 @@ class DSFullMeshService @Inject()(meshFileService: MeshFileService, | |
| fullMeshRequest: FullMeshRequest)(implicit ec: ExecutionContext, tc: TokenContext): Fox[Array[Byte]] = | ||
| for { | ||
| mag <- fullMeshRequest.mag.toFox ?~> "mag.neededForAdHoc" | ||
| seedPosition <- fullMeshRequest.seedPosition.toFox ?~> "seedPosition.neededForAdHoc" | ||
| segmentationLayer <- tryo(dataLayer.asInstanceOf[SegmentationLayer]).toFox ?~> "dataLayer.mustBeSegmentation" | ||
| hasSegmentIndexFile = segmentationLayer.attachments.flatMap(_.segmentIndex).isDefined | ||
| before = Instant.now | ||
| verticesForChunks <- getAllAdHocChunks(dataSource, | ||
| segmentationLayer, | ||
| fullMeshRequest, | ||
| VoxelPosition(seedPosition.x, seedPosition.y, seedPosition.z, mag), | ||
| adHocChunkSize) | ||
| verticesForChunks <- if (hasSegmentIndexFile) | ||
| getAllAdHocChunksWithSegmentIndex(dataSource, segmentationLayer, fullMeshRequest, mag) | ||
| else { | ||
| for { | ||
| seedPosition <- fullMeshRequest.seedPosition.toFox ?~> "seedPosition.neededForAdHocWithoutSegmentIndex" | ||
| chunks <- getAllAdHocChunksWithNeighborLogic( | ||
| dataSource, | ||
| segmentationLayer, | ||
| fullMeshRequest, | ||
| VoxelPosition(seedPosition.x, seedPosition.y, seedPosition.z, mag), | ||
| adHocChunkSize) | ||
| } yield chunks | ||
| } | ||
|  | ||
| encoded = verticesForChunks.map(adHocMeshToStl) | ||
| array = combineEncodedChunksToStl(encoded) | ||
| _ = logMeshingDuration(before, "ad-hoc meshing", array.length) | ||
| } yield array | ||
|  | ||
| private def getAllAdHocChunks( | ||
| private def getAllAdHocChunksWithSegmentIndex( | ||
| dataSource: UsableDataSource, | ||
| segmentationLayer: SegmentationLayer, | ||
| fullMeshRequest: FullMeshRequest, | ||
| topLeft: VoxelPosition, | ||
| chunkSize: Vec3Int, | ||
| visited: collection.mutable.Set[VoxelPosition] = collection.mutable.Set[VoxelPosition]())( | ||
| mag: Vec3Int, | ||
| )(implicit ec: ExecutionContext, tc: TokenContext): Fox[List[Array[Float]]] = | ||
| for { | ||
| segmentIndexFileKey <- segmentIndexFileService.lookUpSegmentIndexFileKey(dataSource.id, segmentationLayer) | ||
| segmentIds <- segmentIdsForAgglomerateIdIfNeeded( | ||
| dataSource.id, | ||
| segmentationLayer, | ||
| fullMeshRequest.mappingName, | ||
| fullMeshRequest.editableMappingTracingId, | ||
| fullMeshRequest.segmentId, | ||
| mappingNameForMeshFile = None, | ||
| omitMissing = false | ||
| ) | ||
| topLeftsNested: Seq[Array[Vec3Int]] <- Fox.serialCombined(segmentIds)(sId => | ||
| segmentIndexFileService.readSegmentIndex(segmentIndexFileKey, sId)) | ||
| topLefts: Array[Vec3Int] = topLeftsNested.toArray.flatten | ||
| targetMagPositions = segmentIndexFileService.topLeftsToDistinctTargetMagBucketPositions(topLefts, mag) | ||
| vertexChunksWithNeighbors: List[(Array[Float], List[Int])] <- Fox.serialCombined(targetMagPositions) { | ||
| There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just a thought: We are using serial combined here and got the feedback that adhoc mesh generation is rather slow. So should we maybe parallelize these requests? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes that’s something to keep in mind. But for the moment, I’d like to stick with the policy that answering a single request should not use all the parallelization it can get, especially for compute-heavy stuff like mesh generation. Otherwise, a single request could busy the server and other user’s (simple) requests might not get answered quickly. But that’s certainly something to validate and consider. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we open an issue tagged with discussion to not forget this? | ||
| targetMagPosition => | ||
| val adHocMeshRequest = AdHocMeshRequest( | ||
| Some(dataSource.id), | ||
| segmentationLayer, | ||
| Cuboid( | ||
| VoxelPosition( | ||
| targetMagPosition.x * mag.x * DataLayer.bucketLength, | ||
| targetMagPosition.y * mag.y * DataLayer.bucketLength, | ||
| targetMagPosition.z * mag.z * DataLayer.bucketLength, | ||
| mag | ||
| ), | ||
| DataLayer.bucketLength + 1, | ||
| DataLayer.bucketLength + 1, | ||
| DataLayer.bucketLength + 1 | ||
| ), | ||
| fullMeshRequest.segmentId, | ||
| dataSource.scale.factor, | ||
| tc, | ||
| fullMeshRequest.mappingName, | ||
| fullMeshRequest.mappingType, | ||
| fullMeshRequest.additionalCoordinates, | ||
| findNeighbors = false, | ||
| ) | ||
| adHocMeshService.requestAdHocMeshViaActor(adHocMeshRequest) | ||
| } | ||
| allVertices = vertexChunksWithNeighbors.map(_._1) | ||
| } yield allVertices | ||
|  | ||
| private def getAllAdHocChunksWithNeighborLogic(dataSource: UsableDataSource, | ||
| segmentationLayer: SegmentationLayer, | ||
| fullMeshRequest: FullMeshRequest, | ||
| topLeft: VoxelPosition, | ||
| chunkSize: Vec3Int, | ||
| visited: collection.mutable.Set[VoxelPosition] = | ||
| collection.mutable.Set[VoxelPosition]())( | ||
| implicit ec: ExecutionContext, | ||
| tc: TokenContext): Fox[List[Array[Float]]] = { | ||
| val adHocMeshRequest = AdHocMeshRequest( | ||
|  | @@ -105,7 +166,7 @@ class DSFullMeshService @Inject()(meshFileService: MeshFileService, | |
| nextPositions: List[VoxelPosition] = generateNextTopLeftsFromNeighbors(topLeft, neighbors, chunkSize, visited) | ||
| _ = visited ++= nextPositions | ||
| neighborVerticesNested <- Fox.serialCombined(nextPositions) { position: VoxelPosition => | ||
| getAllAdHocChunks(dataSource, segmentationLayer, fullMeshRequest, position, chunkSize, visited) | ||
| getAllAdHocChunksWithNeighborLogic(dataSource, segmentationLayer, fullMeshRequest, position, chunkSize, visited) | ||
| } | ||
| allVertices: List[Array[Float]] = vertices +: neighborVerticesNested.flatten | ||
| } yield allVertices | ||
|  | ||
Uh oh!
There was an error while loading. Please reload this page.