diff --git a/src/neuroglancer/datasource/cave/backend.ts b/src/neuroglancer/datasource/cave/backend.ts index f3fe20624..c7d396535 100644 --- a/src/neuroglancer/datasource/cave/backend.ts +++ b/src/neuroglancer/datasource/cave/backend.ts @@ -3,20 +3,14 @@ import { AnnotationSubsetGeometryChunk } from "src/neuroglancer/annotation/backe import { WithParameters } from "src/neuroglancer/chunk_manager/backend"; import { WithSharedCredentialsProviderCounterpart } from "src/neuroglancer/credentials_provider/shared_counterpart"; import { CancellationToken } from "src/neuroglancer/util/cancellation"; -import { responseJson } from "src/neuroglancer/util/http_request"; +import { responseArrayBuffer, responseJson } from "src/neuroglancer/util/http_request"; import { SpecialProtocolCredentials } from "src/neuroglancer/util/special_protocol_request"; import { registerSharedObject } from "src/neuroglancer/worker_rpc"; import { AnnotationSourceParameters, AnnotationSpatialIndexSourceParameters, API_STRING } from "./base"; import {cancellableFetchSpecialOk} from 'neuroglancer/util/special_protocol_request'; - import {vec3} from 'neuroglancer/util/geom'; -import { Annotation, AnnotationBase, AnnotationSerializer, AnnotationType, Line, Point, makeAnnotationPropertySerializers } from "src/neuroglancer/annotation"; -import {Uint64} from "src/neuroglancer/util/uint64"; - - -const annotationPropertySerializers = - makeAnnotationPropertySerializers(/*rank=*/ 3, /*propertySpecs=*/[]); - +import {Annotation, AnnotationBase, AnnotationSerializer, AnnotationType, Line, Point, makeAnnotationPropertySerializers} from "src/neuroglancer/annotation"; +import {Uint64} from "neuroglancer/util/uint64"; function parseCaveAnnototations(segmentId: Uint64, annotationsJson: any[], parameters: AnnotationSourceParameters) { @@ -34,7 +28,7 @@ function parseCaveAnnototations(segmentId: Uint64, annotationsJson: any[], param type: AnnotationType.POINT, id: `${segmentId}_${x.id}`, description: `size: ${x.size}`, - properties: [], // [x.size] + properties: parameters.properties.map(p => x[p.identifier]), }; if (points.length > 1) { return { @@ -57,38 +51,33 @@ function parseCaveAnnototations(segmentId: Uint64, annotationsJson: any[], param @registerSharedObject() // export class CaveAnnotationSpatialIndexSourceBackend extends (WithParameters(WithSharedCredentialsProviderCounterpart()(AnnotationGeometryChunkSourceBackend), AnnotationSpatialIndexSourceParameters)) { - // private minishardIndexSource = - // getMinishardIndexDataSource(this.chunkManager, this.credentialsProvider, this.parameters); parent: CaveAnnotationSourceBackend; async download(chunk: AnnotationGeometryChunk, cancellationToken: CancellationToken) { - console.log("SPATIAL DOWNLOAD!"); - cancellationToken; - console.log('chunk', chunk); - const {parent} = this; - console.log('parent', parent); - + const {parent} = this; const {parameters} = parent; // we probably don't need separate spatial index for now - - this.parent.parameters.timestamp; - - - - const url = `${parameters.url}/${API_STRING}/datastack/${parameters.datastack}/query?return_pyarrow=false&split_positions=false&count=false&allow_missing_lookups=false`; + const {datastack, table, timestamp, rank, properties} = parameters; + const binaryFormat = false; + const url = `${parameters.url}/${API_STRING}/datastack/${datastack}/query?return_pyarrow=${binaryFormat}&split_positions=false&count=false&allow_missing_lookups=false`; const payload = `{ - "timestamp": "${parameters.timestamp}", + "timestamp": "${timestamp}", "limit": 10000, - "table": "${parameters.table}" + "table": "${table}" }`; const response = await cancellableFetchSpecialOk(this.credentialsProvider, url, { method: 'POST', headers: {'Content-Type': 'application/json'}, body: payload, - }, responseJson, cancellationToken); + }, binaryFormat ? responseArrayBuffer : responseJson, cancellationToken); if (response !== undefined) { + if (binaryFormat) { + console.log("got arraybuffer!", response.byteLength); + return; + } console.log("got annotations!", response.length); const annotations = parseCaveAnnototations(Uint64.ZERO, response, parameters); // this.annotationCache[chunk.objectId.toJSON()] = annotations; - const serializer = new AnnotationSerializer(annotationPropertySerializers); + const propertySerializers = makeAnnotationPropertySerializers(rank, properties); + const serializer = new AnnotationSerializer(propertySerializers); for (const annotation of annotations) { // this.annotationCache.set(annotation.id, annotation); serializer.add(annotation); @@ -108,22 +97,17 @@ export class CaveAnnotationSourceBackend extends (WithParameters(WithSharedCrede chunk: AnnotationSubsetGeometryChunk, relationshipIndex: number, cancellationToken: CancellationToken) { const {parameters} = this; - const url = `${parameters.url}/${API_STRING}/datastack/${parameters.datastack}/query?return_pyarrow=false&split_positions=false&count=false&allow_missing_lookups=false`; + const {datastack, table, relationships, timestamp, rank, properties} = parameters; + const url = `${parameters.url}/${API_STRING}/datastack/${datastack}/query?return_pyarrow=false&split_positions=false&count=false&allow_missing_lookups=false`; const payload = `{ - "timestamp": "${parameters.timestamp}", + "timestamp": "${timestamp}", "filter_in_dict": { - "${parameters.table}":{ - "${parameters.relationships[relationshipIndex]}_root_id": [${chunk.objectId.toJSON()}] + "${table}":{ + "${relationships[relationshipIndex]}_root_id": [${chunk.objectId.toJSON()}] } }, - "table": "${parameters.table}" - }`; // TODO (hardcooding _root_id) - // parameters; for spatial - // const payload = `{ - // "timestamp": "${parameters.timestamp}", - // "limit": 10000, - // "table": "${parameters.table}" - // }`; + "table": "${table}" + }`; // TODO (hardcoding `_root_id`) const response = await cancellableFetchSpecialOk(this.credentialsProvider, url, { method: 'POST', headers: {'Content-Type': 'application/json'}, @@ -131,8 +115,8 @@ export class CaveAnnotationSourceBackend extends (WithParameters(WithSharedCrede }, responseJson, cancellationToken); if (response !== undefined) { const annotations = parseCaveAnnototations(chunk.objectId, response, this.parameters); - // this.annotationCache[chunk.objectId.toJSON()] = annotations; - const serializer = new AnnotationSerializer(annotationPropertySerializers); + const propertySerializers = makeAnnotationPropertySerializers(rank, properties); + const serializer = new AnnotationSerializer(propertySerializers); for (const annotation of annotations) { this.annotationCache.set(annotation.id, annotation); serializer.add(annotation); @@ -145,19 +129,7 @@ export class CaveAnnotationSourceBackend extends (WithParameters(WithSharedCrede cancellationToken; const {parameters} = this; console.log('downloadMetadata', chunk.key, chunk.annotation, parameters); - if (!chunk.key) return; chunk.annotation = this.annotationCache.get(chunk.key) || null; - - - - // this.annotationCache[chunk.ob] - - // if (response === undefined) { - // chunk.annotation = null; - // } else { - // chunk.annotation = parseSingleAnnotation( - // response, this.parameters, this.annotationPropertySerializer, chunk.key!); - // } } } diff --git a/src/neuroglancer/datasource/cave/frontend.ts b/src/neuroglancer/datasource/cave/frontend.ts index aec9bb260..d86673828 100644 --- a/src/neuroglancer/datasource/cave/frontend.ts +++ b/src/neuroglancer/datasource/cave/frontend.ts @@ -9,7 +9,7 @@ import { cancellableFetchSpecialOk, parseSpecialUrl, SpecialProtocolCredentials, import { CompleteUrlOptions, ConvertLegacyUrlOptions, DataSource, DataSourceProvider, GetDataSourceOptions, NormalizeUrlOptions, RedirectError } from ".."; import { parseMultiscaleVolumeInfo, parseProviderUrl } from "neuroglancer/datasource/precomputed/frontend"; import { AnnotationSourceParameters, AnnotationSpatialIndexSourceParameters, API_STRING, API_STRING_V2 } from "neuroglancer/datasource/cave/base"; -import { AnnotationType, parseAnnotationPropertySpecs } from "neuroglancer/annotation"; +import { AnnotationPropertySpec, AnnotationType, parseAnnotationPropertySpecs } from "neuroglancer/annotation"; import {SliceViewSingleResolutionSource} from "src/neuroglancer/sliceview/frontend"; import {AnnotationGeometryChunkSpecification} from "src/neuroglancer/annotation/base"; import * as matrix from 'neuroglancer/util/matrix'; @@ -66,8 +66,8 @@ class AnnotationMetadata { // type: verifyObjectProperty( // metadata, 'annotation_type', typeObj => verifyEnumString(typeObj, AnnotationType)), rank, - relationships: tableMetadata.properties, - properties: verifyObjectProperty(metadata, 'properties', parseAnnotationPropertySpecs), + relationships: tableMetadata.relationships, + properties: tableMetadata.shaderProperties, }; /* verifyObjectProperty( @@ -239,10 +239,16 @@ interface TableMetadata { voxel_resolution_x: number, voxel_resolution_y: number, voxel_resolution_z: number, - properties: string[], + relationships: string[], + shaderProperties: AnnotationPropertySpec[], +} + +const schemaFormatToPropertyType: {[key: string]: string} = { + 'float': 'float32', } const BOUND_SPATIAL_POINT = 'BoundSpatialPoint'; +const SPATIAL_POINT = 'SpatialPoint'; async function getTableMetadata(credentialsProvider: SpecialProtocolCredentialsProvider, url: string, datastack: string, version: number, table: string): Promise { const metadataURL = `${url}/${API_STRING_V2}/datastack/${datastack}/version/${version}/table/${table}/metadata`; @@ -272,20 +278,33 @@ async function getTableMetadata(credentialsProvider: SpecialProtocolCredentialsP const definitionName = refToName(ref); const definitions = verifyObjectProperty(schema, 'definitions', verifyObject); const definition = verifyObjectProperty(definitions, definitionName, verifyObject); - const properties = verifyObjectProperty(definition, 'properties', x => { - const res = []; + const [relationships, shaderProperties] = verifyObjectProperty(definition, 'properties', x => { + const relationships: string[] = []; + const shaderProps: unknown[] = []; const result = verifyObjectAsMap(x, verifyObject); for (const [name, obj] of result) { + console.log('name', name); verifyObject(obj); const ref = verifyOptionalObjectProperty(obj, '$ref', verifyString); - if (!ref) continue; - const refName = refToName(ref); - const order = verifyOptionalObjectProperty(obj, 'order', verifyNonnegativeInt) || 0; - if (refName === BOUND_SPATIAL_POINT) { // TODO, maybe we want to support SpatialPoint? - res[order] = name; + if (ref) { + const refName = refToName(ref); + const order = verifyOptionalObjectProperty(obj, 'order', verifyNonnegativeInt) || 0; + if (refName === BOUND_SPATIAL_POINT) { // TODO, maybe we want to support SpatialPoint? + relationships[order] = name; + } else if (refName === SPATIAL_POINT) { + // TODO + } + } + const format = obj['format']; + const type = schemaFormatToPropertyType[format]; + if (type) { + shaderProps.push({ + id: name, + type, + }); } } - return res.filter(x => x !== undefined); + return [relationships.filter(x => x !== undefined), parseAnnotationPropertySpecs(shaderProps)]; }); // TODO, maybe use flat_segmentation_source to automatically link up the segmentation? @@ -295,7 +314,8 @@ async function getTableMetadata(credentialsProvider: SpecialProtocolCredentialsP voxel_resolution_x, voxel_resolution_y, voxel_resolution_z, - properties, + relationships, + shaderProperties, } }