@vitessce/spatial-accelerated 3.9.3 → 3.9.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -46770,14 +46770,14 @@ reconciler.injectIntoDevTools({
46770
46770
  rendererPackageName: "@react-three/fiber",
46771
46771
  version: React.version
46772
46772
  });
46773
- function _extends$3() {
46774
- return _extends$3 = Object.assign ? Object.assign.bind() : function(n) {
46773
+ function _extends$2() {
46774
+ return _extends$2 = Object.assign ? Object.assign.bind() : function(n) {
46775
46775
  for (var e = 1; e < arguments.length; e++) {
46776
46776
  var t = arguments[e];
46777
46777
  for (var r2 in t) ({}).hasOwnProperty.call(t, r2) && (n[r2] = t[r2]);
46778
46778
  }
46779
46779
  return n;
46780
- }, _extends$3.apply(null, arguments);
46780
+ }, _extends$2.apply(null, arguments);
46781
46781
  }
46782
46782
  var debounce_1;
46783
46783
  var hasRequiredDebounce;
@@ -47258,7 +47258,7 @@ const CanvasImpl = /* @__PURE__ */ React.forwardRef(function Canvas({
47258
47258
  if (canvas) return () => unmountComponentAtNode(canvas);
47259
47259
  }, []);
47260
47260
  const pointerEvents = eventSource ? "none" : "auto";
47261
- return /* @__PURE__ */ React.createElement("div", _extends$3({
47261
+ return /* @__PURE__ */ React.createElement("div", _extends$2({
47262
47262
  ref: divRef,
47263
47263
  style: {
47264
47264
  position: "relative",
@@ -47282,7 +47282,7 @@ const CanvasImpl = /* @__PURE__ */ React.forwardRef(function Canvas({
47282
47282
  }, fallback)));
47283
47283
  });
47284
47284
  const Canvas2 = /* @__PURE__ */ React.forwardRef(function CanvasWrapper(props, ref) {
47285
- return /* @__PURE__ */ React.createElement(FiberProvider, null, /* @__PURE__ */ React.createElement(CanvasImpl, _extends$3({}, props, {
47285
+ return /* @__PURE__ */ React.createElement(FiberProvider, null, /* @__PURE__ */ React.createElement(CanvasImpl, _extends$2({}, props, {
47286
47286
  ref
47287
47287
  })));
47288
47288
  });
@@ -48165,7 +48165,7 @@ const OrbitControls2 = /* @__PURE__ */ React.forwardRef(({
48165
48165
  });
48166
48166
  }
48167
48167
  }, [makeDefault, controls]);
48168
- return /* @__PURE__ */ React.createElement("primitive", _extends$3({
48168
+ return /* @__PURE__ */ React.createElement("primitive", _extends$2({
48169
48169
  ref,
48170
48170
  object: controls,
48171
48171
  enableDamping
@@ -50021,14 +50021,14 @@ var createCache = function createCache2(options) {
50021
50021
  cache.sheet.hydrate(nodesToHydrate);
50022
50022
  return cache;
50023
50023
  };
50024
- function _extends$2() {
50025
- return _extends$2 = Object.assign ? Object.assign.bind() : function(n) {
50024
+ function _extends$1() {
50025
+ return _extends$1 = Object.assign ? Object.assign.bind() : function(n) {
50026
50026
  for (var e = 1; e < arguments.length; e++) {
50027
50027
  var t = arguments[e];
50028
50028
  for (var r2 in t) ({}).hasOwnProperty.call(t, r2) && (n[r2] = t[r2]);
50029
50029
  }
50030
50030
  return n;
50031
- }, _extends$2.apply(null, arguments);
50031
+ }, _extends$1.apply(null, arguments);
50032
50032
  }
50033
50033
  var isBrowser$1 = true;
50034
50034
  function getRegisteredStyles(registered, registeredStyles, classNames) {
@@ -51171,7 +51171,7 @@ var createStyled$1 = function createStyled(tag, options) {
51171
51171
  }
51172
51172
  });
51173
51173
  Styled.withComponent = function(nextTag, nextOptions) {
51174
- var newStyled2 = createStyled(nextTag, _extends$2({}, options, nextOptions, {
51174
+ var newStyled2 = createStyled(nextTag, _extends$1({}, options, nextOptions, {
51175
51175
  shouldForwardProp: composeShouldForwardProps(Styled, nextOptions, true)
51176
51176
  }));
51177
51177
  return newStyled2.apply(void 0, styles);
@@ -55843,6 +55843,18 @@ function useForkRef$1(...refs) {
55843
55843
  };
55844
55844
  }, refs);
55845
55845
  }
55846
+ function _setPrototypeOf(t, e) {
55847
+ return _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function(t2, e2) {
55848
+ return t2.__proto__ = e2, t2;
55849
+ }, _setPrototypeOf(t, e);
55850
+ }
55851
+ function _inheritsLoose(t, o) {
55852
+ t.prototype = Object.create(o.prototype), t.prototype.constructor = t, _setPrototypeOf(t, o);
55853
+ }
55854
+ function _assertThisInitialized(e) {
55855
+ if (void 0 === e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
55856
+ return e;
55857
+ }
55846
55858
  function hasCorrectMainProperty(obj) {
55847
55859
  return typeof obj.main === "string";
55848
55860
  }
@@ -56437,7 +56449,7 @@ var defineProperty = function(obj, key, value) {
56437
56449
  }
56438
56450
  return obj;
56439
56451
  };
56440
- var _extends$1 = Object.assign || function(target) {
56452
+ var _extends = Object.assign || function(target) {
56441
56453
  for (var i2 = 1; i2 < arguments.length; i2++) {
56442
56454
  var source = arguments[i2];
56443
56455
  for (var key in source) {
@@ -56449,7 +56461,7 @@ var _extends$1 = Object.assign || function(target) {
56449
56461
  return target;
56450
56462
  };
56451
56463
  function getClientRect(offsets) {
56452
- return _extends$1({}, offsets, {
56464
+ return _extends({}, offsets, {
56453
56465
  right: offsets.left + offsets.width,
56454
56466
  bottom: offsets.top + offsets.height
56455
56467
  });
@@ -56633,7 +56645,7 @@ function computeAutoPlacement(placement, refRect, popper, reference, boundariesE
56633
56645
  }
56634
56646
  };
56635
56647
  var sortedAreas = Object.keys(rects).map(function(key) {
56636
- return _extends$1({
56648
+ return _extends({
56637
56649
  key
56638
56650
  }, rects[key], {
56639
56651
  area: getArea(rects[key])
@@ -56941,9 +56953,9 @@ function computeStyle(data, options) {
56941
56953
  var attributes = {
56942
56954
  "x-placement": data.placement
56943
56955
  };
56944
- data.attributes = _extends$1({}, attributes, data.attributes);
56945
- data.styles = _extends$1({}, styles, data.styles);
56946
- data.arrowStyles = _extends$1({}, data.offsets.arrow, data.arrowStyles);
56956
+ data.attributes = _extends({}, attributes, data.attributes);
56957
+ data.styles = _extends({}, styles, data.styles);
56958
+ data.arrowStyles = _extends({}, data.offsets.arrow, data.arrowStyles);
56947
56959
  return data;
56948
56960
  }
56949
56961
  function isModifierRequired(modifiers2, requestingName, requestedName) {
@@ -57078,7 +57090,7 @@ function flip(data, options) {
57078
57090
  variation = getOppositeVariation(variation);
57079
57091
  }
57080
57092
  data.placement = placement + (variation ? "-" + variation : "");
57081
- data.offsets.popper = _extends$1({}, data.offsets.popper, getPopperOffsets(data.instance.popper, data.offsets.reference, data.placement));
57093
+ data.offsets.popper = _extends({}, data.offsets.popper, getPopperOffsets(data.instance.popper, data.offsets.reference, data.placement));
57082
57094
  data = runModifiers(data.instance.modifiers, data, "flip");
57083
57095
  }
57084
57096
  });
@@ -57237,7 +57249,7 @@ function preventOverflow(data, options) {
57237
57249
  };
57238
57250
  order.forEach(function(placement) {
57239
57251
  var side = ["left", "top"].indexOf(placement) !== -1 ? "primary" : "secondary";
57240
- popper = _extends$1({}, popper, check[side](placement));
57252
+ popper = _extends({}, popper, check[side](placement));
57241
57253
  });
57242
57254
  data.offsets.popper = popper;
57243
57255
  return data;
@@ -57255,7 +57267,7 @@ function shift(data) {
57255
57267
  start: defineProperty({}, side, reference[side]),
57256
57268
  end: defineProperty({}, side, reference[side] + reference[measurement] - popper[measurement])
57257
57269
  };
57258
- data.offsets.popper = _extends$1({}, popper, shiftOffsets[shiftvariation]);
57270
+ data.offsets.popper = _extends({}, popper, shiftOffsets[shiftvariation]);
57259
57271
  }
57260
57272
  return data;
57261
57273
  }
@@ -57658,7 +57670,7 @@ var Popper = function() {
57658
57670
  return requestAnimationFrame(_this.update);
57659
57671
  };
57660
57672
  this.update = debounce(this.update.bind(this));
57661
- this.options = _extends$1({}, Popper2.Defaults, options);
57673
+ this.options = _extends({}, Popper2.Defaults, options);
57662
57674
  this.state = {
57663
57675
  isDestroyed: false,
57664
57676
  isCreated: false,
@@ -57667,11 +57679,11 @@ var Popper = function() {
57667
57679
  this.reference = reference && reference.jquery ? reference[0] : reference;
57668
57680
  this.popper = popper && popper.jquery ? popper[0] : popper;
57669
57681
  this.options.modifiers = {};
57670
- Object.keys(_extends$1({}, Popper2.Defaults.modifiers, options.modifiers)).forEach(function(name) {
57671
- _this.options.modifiers[name] = _extends$1({}, Popper2.Defaults.modifiers[name] || {}, options.modifiers ? options.modifiers[name] : {});
57682
+ Object.keys(_extends({}, Popper2.Defaults.modifiers, options.modifiers)).forEach(function(name) {
57683
+ _this.options.modifiers[name] = _extends({}, Popper2.Defaults.modifiers[name] || {}, options.modifiers ? options.modifiers[name] : {});
57672
57684
  });
57673
57685
  this.modifiers = Object.keys(this.options.modifiers).map(function(name) {
57674
- return _extends$1({
57686
+ return _extends({
57675
57687
  name
57676
57688
  }, _this.options.modifiers[name]);
57677
57689
  }).sort(function(a, b) {
@@ -57901,38 +57913,6 @@ React.forwardRef((props, ref) => {
57901
57913
  ...style2
57902
57914
  }, children: typeof children === "function" ? children(childProps) : children }) });
57903
57915
  });
57904
- function _extends() {
57905
- _extends = Object.assign ? Object.assign.bind() : function(target) {
57906
- for (var i2 = 1; i2 < arguments.length; i2++) {
57907
- var source = arguments[i2];
57908
- for (var key in source) {
57909
- if (Object.prototype.hasOwnProperty.call(source, key)) {
57910
- target[key] = source[key];
57911
- }
57912
- }
57913
- }
57914
- return target;
57915
- };
57916
- return _extends.apply(this, arguments);
57917
- }
57918
- function _assertThisInitialized(self2) {
57919
- if (self2 === void 0) {
57920
- throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
57921
- }
57922
- return self2;
57923
- }
57924
- function _setPrototypeOf(o, p) {
57925
- _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf2(o2, p2) {
57926
- o2.__proto__ = p2;
57927
- return o2;
57928
- };
57929
- return _setPrototypeOf(o, p);
57930
- }
57931
- function _inheritsLoose(subClass, superClass) {
57932
- subClass.prototype = Object.create(superClass.prototype);
57933
- subClass.prototype.constructor = subClass;
57934
- _setPrototypeOf(subClass, superClass);
57935
- }
57936
57916
  var safeIsNaN = Number.isNaN || function ponyfill(value) {
57937
57917
  return typeof value === "number" && value !== value;
57938
57918
  };
@@ -58300,7 +58280,7 @@ function createListComponent(_ref) {
58300
58280
  className,
58301
58281
  onScroll,
58302
58282
  ref: this._outerRefSetter,
58303
- style: _extends({
58283
+ style: _extends$2({
58304
58284
  position: "relative",
58305
58285
  height: height2,
58306
58286
  width: width2,
@@ -59488,9 +59468,17 @@ function _ptToZarr(ptx, pty, ptz, ptInfo) {
59488
59468
  z
59489
59469
  };
59490
59470
  }
59491
- function _requestBufferToRequestObjects(buffer, k) {
59471
+ const DEFAULT_SIGMA_NORMALIZED = 0.25;
59472
+ function _requestBufferToRequestObjects(buffer, k, optsForWeighting) {
59492
59473
  const counts = /* @__PURE__ */ new Map();
59493
- for (let i2 = 0; i2 < buffer.length; i2 += 4) {
59474
+ const { width: width2, height: height2, sigmaNormalized } = optsForWeighting;
59475
+ const useWeighting = Number.isInteger(width2) && Number.isInteger(height2) && width2 > 0 && height2 > 0 && typeof sigmaNormalized === "number";
59476
+ if (!useWeighting) {
59477
+ log.warn("_requestBufferToRequestObjects: proceeding without weighting");
59478
+ }
59479
+ const maxPixels = Math.floor(buffer.length / 4);
59480
+ for (let pix = 0; pix < maxPixels; pix += 1) {
59481
+ const i2 = pix * 4;
59494
59482
  const r2 = buffer[i2];
59495
59483
  const g = buffer[i2 + 1];
59496
59484
  const b = buffer[i2 + 2];
@@ -59499,7 +59487,17 @@ function _requestBufferToRequestObjects(buffer, k) {
59499
59487
  continue;
59500
59488
  }
59501
59489
  const packed = (r2 << 24 | g << 16 | b << 8 | a) >>> 0;
59502
- counts.set(packed, (counts.get(packed) || 0) + 1);
59490
+ let weight = 1;
59491
+ if (useWeighting) {
59492
+ const x = pix % width2;
59493
+ const y = Math.floor(pix / width2);
59494
+ const dx = x - width2 / 2;
59495
+ const dy = y - height2 / 2;
59496
+ const nd = Math.sqrt(dx * dx / (width2 * width2) + dy * dy / (height2 * height2));
59497
+ const norm = nd / sigmaNormalized;
59498
+ weight = Math.exp(-0.5 * norm * norm);
59499
+ }
59500
+ counts.set(packed, (counts.get(packed) || 0) + weight);
59503
59501
  }
59504
59502
  const requests = [...counts.entries()].sort((a, b) => b[1] - a[1]).slice(0, k).map(([packed]) => ({
59505
59503
  x: packed >> 22 & 1023,
@@ -60160,7 +60158,19 @@ class VolumeDataManager {
60160
60158
  }
60161
60159
  return chunkEntry.data;
60162
60160
  }
60163
- async processRequestData(buffer) {
60161
+ /**
60162
+ * Process the buffer of brick requests from the shader, turning them into
60163
+ * actual Promises for Zarr chunks on the JS side.
60164
+ * @param {Uint8Array} buffer The bufRequest (of length width*height*4)
60165
+ * containing the brick requests from the shader.
60166
+ * @param {object} optsForWeighting
60167
+ * @param {number} optsForWeighting.width The width of the render target.
60168
+ * @param {number} optsForWeighting.height The height of the render target.
60169
+ * @param {number} optsForWeighting.sigmaNormalized The normalized sigma value
60170
+ * to use for weighting the brick requests based on their distance from
60171
+ * the center of the render target.
60172
+ */
60173
+ async processRequestData(buffer, optsForWeighting) {
60164
60174
  if (this.isBusy) {
60165
60175
  log.debug("processRequestData: already busy, skipping");
60166
60176
  return;
@@ -60175,7 +60185,7 @@ class VolumeDataManager {
60175
60185
  }
60176
60186
  this.isBusy = true;
60177
60187
  this.triggerRequest = false;
60178
- const { requests, origRequestCount } = _requestBufferToRequestObjects(buffer, this.k);
60188
+ const { requests, origRequestCount } = _requestBufferToRequestObjects(buffer, this.k, optsForWeighting);
60179
60189
  if (requests.length === 0) {
60180
60190
  this.noNewRequests = true;
60181
60191
  }
@@ -62922,7 +62932,14 @@ function handleRequests(_gl, { frameRef, dataManager, mrtRef, bufRequest, bufUsa
62922
62932
  ctx.UNSIGNED_BYTE,
62923
62933
  bufRequest.current
62924
62934
  );
62925
- dataManager.processRequestData(bufRequest.current);
62935
+ dataManager.processRequestData(bufRequest.current, {
62936
+ // If width/height are not yet available,
62937
+ // processRequestData will proceed without weighting.
62938
+ width: mrtRef?.current?.width,
62939
+ height: mrtRef?.current?.height,
62940
+ // Default sigmaNormalized = 0.25; can be tuned
62941
+ sigmaNormalized: DEFAULT_SIGMA_NORMALIZED
62942
+ });
62926
62943
  } else if (dataManager.triggerUsage === true && dataManager.noNewRequests === false) {
62927
62944
  ctx.bindFramebuffer(ctx.READ_FRAMEBUFFER, framebufferFor(_gl, mrtRef.current));
62928
62945
  ctx.readBuffer(ctx.COLOR_ATTACHMENT2);
@@ -27,7 +27,7 @@ export function _ptToZarr(ptx: any, pty: any, ptz: any, ptInfo: any): {
27
27
  y: number;
28
28
  z: number;
29
29
  };
30
- export function _requestBufferToRequestObjects(buffer: any, k: any): {
30
+ export function _requestBufferToRequestObjects(buffer: any, k: any, optsForWeighting: any): {
31
31
  requests: {
32
32
  x: number;
33
33
  y: number;
@@ -41,6 +41,7 @@ export namespace INIT_STATUS {
41
41
  let COMPLETE: string;
42
42
  let FAILED: string;
43
43
  }
44
+ export const DEFAULT_SIGMA_NORMALIZED: 0.25;
44
45
  export class VolumeDataManager {
45
46
  constructor(glParam: any);
46
47
  gl: any;
@@ -198,7 +199,23 @@ export class VolumeDataManager {
198
199
  * @returns {Promise<Uint8Array>} 32x32x32 chunk data
199
200
  */
200
201
  loadZarrChunk(t: number | undefined, c: number | undefined, z: number, y: number, x: number, resolution: number): Promise<Uint8Array>;
201
- processRequestData(buffer: any): Promise<void>;
202
+ /**
203
+ * Process the buffer of brick requests from the shader, turning them into
204
+ * actual Promises for Zarr chunks on the JS side.
205
+ * @param {Uint8Array} buffer The bufRequest (of length width*height*4)
206
+ * containing the brick requests from the shader.
207
+ * @param {object} optsForWeighting
208
+ * @param {number} optsForWeighting.width The width of the render target.
209
+ * @param {number} optsForWeighting.height The height of the render target.
210
+ * @param {number} optsForWeighting.sigmaNormalized The normalized sigma value
211
+ * to use for weighting the brick requests based on their distance from
212
+ * the center of the render target.
213
+ */
214
+ processRequestData(buffer: Uint8Array, optsForWeighting: {
215
+ width: number;
216
+ height: number;
217
+ sigmaNormalized: number;
218
+ }): Promise<void>;
202
219
  processUsageData(buffer: any): Promise<void>;
203
220
  _evictBrick(bcIndex: any): void;
204
221
  _purgeChannel(ptChannelIndex: any): void;
@@ -1 +1 @@
1
- {"version":3,"file":"VolumeDataManager.d.ts","sourceRoot":"","sources":["../src/VolumeDataManager.js"],"names":[],"mappings":"AA8DA,yEAaC;AACD,8EAeC;AAED;;;;GAIG;AACH,kDAHW,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,8BAC1B,MAAM;;;;;;;;;;;;;EAyHhB;AAMD,kFAaC;AAqBD;;;;;;EA2DC;AAED;;;;;;;EA0BC;;;;;;;AAID;IACE,0BAgLC;IAjKG,QAAyB;IAa3B,cAAwB;IAyBxB,sBAA+B;IAC/B,wBAA2B;IAC3B,iCAAmC;IAenC;;;;;MAKC;IAED;;;;;;;;;;;;MAcC;IAED,8BAAmB;IACnB,8BAAmB;IAEnB;;;;;;MAMC;IAED;;;;;;;;;MAiBC;IAQD,2BAAiC;IAYjC,gBAAmB;IAGnB,oBAAuD;IACvD,gBAAwD;IACxD,gBAAmB;IACnB,sBAAsB;IAGtB,aAAmD;IAGnD,gBAAkB;IAElB,sBAAwB;IACxB,wBAA2B;IAC3B,kBAAkB;IAClB,UAAW;IACX,uBAA0B;IAC1B,yBAA4B;IAE5B,sBAAyB;IAGzB,mBAAyC;IACzC,eAAqB;IAGrB;;;;;;;;;;aAA8B;IAG9B,4BAA4B;IAC5B,6BAA6B;IAK/B;;;OAGG;IACH,sBAFa,MAAM,CAiBlB;IAED;;OAEG;IACH,oBAQC;IAED;;OAEG;IACH,uBASC;IAED;;OAEG;IACH,qCAeC;IAED;;OAEG;IACH,yCAqCC;IAED;;OAEG;IACH,qBAMC;IAED;;OAEG;IACH,uCAIC;IAED,qDAIC;IAFC,YAAoB;IACpB,sBAAwC;IAG1C;;;;;OAKG;IACH,mBAFa,OAAO,CAAC,MAAM,CAAC,CA8S3B;IAjQG,kBAAmD;IAmQvD;;;;;;;;OAQG;IACH,mBAkBC;IAGD,6BAMC;IAED,wCAqHC;IAED;;;;;OAKG;IAqBH;;;OAGG;IACH,kCAQC;IAED;;;OAGG;IACH,uBAFa,MAAM,CAUlB;IAED,+BAQC;IAED,kCASC;IAED,gCASC;IAED;;;;;;;;;OASG;IACH,iBARW,MAAM,iBACN,MAAM,iBACN,MAAM,KACN,MAAM,KACN,MAAM,cACN,MAAM,GACJ,OAAO,CAAC,UAAU,CAAC,CA+B/B;IAED,+CAgCC;IAGD,6CA0DC;IAGD,gCAcC;IAED,yCAmDC;IAGD,+DAqBC;IAKD;;;;OAIG;IACH,oBAHW,MAAM,GACJ;QAAE,OAAO,MAAC;QAAC,CAAC,MAAC;QAAC,CAAC,MAAC;QAAC,CAAC,MAAA;KAAE,EAAE,CAyClC;IAKD,uDA6LC;IAKD,oDAwDC;IAKD,kBAWC;CACF;8BAttDM,OAAO"}
1
+ {"version":3,"file":"VolumeDataManager.d.ts","sourceRoot":"","sources":["../src/VolumeDataManager.js"],"names":[],"mappings":"AA8DA,yEAaC;AACD,8EAeC;AAED;;;;GAIG;AACH,kDAHW,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,8BAC1B,MAAM;;;;;;;;;;;;;EAyHhB;AAMD,kFAaC;AAqBD;;;;;;EA2DC;AAKD;;;;;;;EAuDC;;;;;;;AAzDD,4CAA6C;AA6D7C;IACE,0BAgLC;IAjKG,QAAyB;IAa3B,cAAwB;IAyBxB,sBAA+B;IAC/B,wBAA2B;IAC3B,iCAAmC;IAenC;;;;;MAKC;IAED;;;;;;;;;;;;MAcC;IAED,8BAAmB;IACnB,8BAAmB;IAEnB;;;;;;MAMC;IAED;;;;;;;;;MAiBC;IAQD,2BAAiC;IAYjC,gBAAmB;IAGnB,oBAAuD;IACvD,gBAAwD;IACxD,gBAAmB;IACnB,sBAAsB;IAGtB,aAAmD;IAGnD,gBAAkB;IAElB,sBAAwB;IACxB,wBAA2B;IAC3B,kBAAkB;IAClB,UAAW;IACX,uBAA0B;IAC1B,yBAA4B;IAE5B,sBAAyB;IAGzB,mBAAyC;IACzC,eAAqB;IAGrB;;;;;;;;;;aAA8B;IAG9B,4BAA4B;IAC5B,6BAA6B;IAK/B;;;OAGG;IACH,sBAFa,MAAM,CAiBlB;IAED;;OAEG;IACH,oBAQC;IAED;;OAEG;IACH,uBASC;IAED;;OAEG;IACH,qCAeC;IAED;;OAEG;IACH,yCAqCC;IAED;;OAEG;IACH,qBAMC;IAED;;OAEG;IACH,uCAIC;IAED,qDAIC;IAFC,YAAoB;IACpB,sBAAwC;IAG1C;;;;;OAKG;IACH,mBAFa,OAAO,CAAC,MAAM,CAAC,CA8S3B;IAjQG,kBAAmD;IAmQvD;;;;;;;;OAQG;IACH,mBAkBC;IAGD,6BAMC;IAED,wCAqHC;IAED;;;;;OAKG;IAqBH;;;OAGG;IACH,kCAQC;IAED;;;OAGG;IACH,uBAFa,MAAM,CAUlB;IAED,+BAQC;IAED,kCASC;IAED,gCASC;IAED;;;;;;;;;OASG;IACH,iBARW,MAAM,iBACN,MAAM,iBACN,MAAM,KACN,MAAM,KACN,MAAM,cACN,MAAM,GACJ,OAAO,CAAC,UAAU,CAAC,CA+B/B;IAED;;;;;;;;;;;OAWG;IACH,2BATW,UAAU,oBAGlB;QAAiC,KAAK,EAA9B,MAAM;QACmB,MAAM,EAA/B,MAAM;QACmB,eAAe,EAAxC,MAAM;KAGhB,iBAiCA;IAGD,6CA0DC;IAGD,gCAcC;IAED,yCAmDC;IAGD,+DAqBC;IAKD;;;;OAIG;IACH,oBAHW,MAAM,GACJ;QAAE,OAAO,MAAC;QAAC,CAAC,MAAC;QAAC,CAAC,MAAC;QAAC,CAAC,MAAA;KAAE,EAAE,CAyClC;IAKD,uDA6LC;IAKD,oDAwDC;IAKD,kBAWC;CACF;8BAlwDM,OAAO"}
@@ -268,9 +268,21 @@ export function _ptToZarr(ptx, pty, ptz, ptInfo) {
268
268
  z,
269
269
  };
270
270
  }
271
- export function _requestBufferToRequestObjects(buffer, k) {
271
+ // sigmaNormalized: fraction of half-dimension that determines Gaussian spread
272
+ export const DEFAULT_SIGMA_NORMALIZED = 0.25;
273
+ export function _requestBufferToRequestObjects(buffer, k, optsForWeighting) {
272
274
  const counts = new Map();
273
- for (let i = 0; i < buffer.length; i += 4) {
275
+ const { width, height, sigmaNormalized } = optsForWeighting;
276
+ const useWeighting = (Number.isInteger(width) && Number.isInteger(height)
277
+ && width > 0 && height > 0
278
+ && typeof sigmaNormalized === 'number');
279
+ if (!useWeighting) {
280
+ log.warn('_requestBufferToRequestObjects: proceeding without weighting');
281
+ }
282
+ // Number of pixels present in buffer
283
+ const maxPixels = Math.floor(buffer.length / 4);
284
+ for (let pix = 0; pix < maxPixels; pix += 1) {
285
+ const i = pix * 4;
274
286
  const r = buffer[i];
275
287
  const g = buffer[i + 1];
276
288
  const b = buffer[i + 2];
@@ -280,11 +292,20 @@ export function _requestBufferToRequestObjects(buffer, k) {
280
292
  continue;
281
293
  }
282
294
  const packed = ((r << 24) | (g << 16) | (b << 8) | a) >>> 0;
283
- counts.set(packed, (counts.get(packed) || 0) + 1);
295
+ let weight = 1.0;
296
+ if (useWeighting) {
297
+ const x = pix % width;
298
+ const y = Math.floor(pix / width);
299
+ const dx = x - (width / 2);
300
+ const dy = y - (height / 2);
301
+ // normalized distance relative to full width/height to be resolution-independent
302
+ const nd = Math.sqrt((dx * dx) / (width * width) + (dy * dy) / (height * height));
303
+ const norm = nd / sigmaNormalized;
304
+ weight = Math.exp(-0.5 * norm * norm);
305
+ }
306
+ counts.set(packed, (counts.get(packed) || 0) + weight);
284
307
  }
285
- // log.debug('counts', counts);
286
- // log.debug('this.k', this.k);
287
- // Get the top K (potentially fewer than K) page table requests.
308
+ // Get the top K (potentially fewer than K) page table requests by weighted count.
288
309
  const requests = [...counts.entries()]
289
310
  .sort((a, b) => b[1] - a[1])
290
311
  .slice(0, k)
@@ -1074,7 +1095,19 @@ export class VolumeDataManager {
1074
1095
  }
1075
1096
  return chunkEntry.data;
1076
1097
  }
1077
- async processRequestData(buffer) {
1098
+ /**
1099
+ * Process the buffer of brick requests from the shader, turning them into
1100
+ * actual Promises for Zarr chunks on the JS side.
1101
+ * @param {Uint8Array} buffer The bufRequest (of length width*height*4)
1102
+ * containing the brick requests from the shader.
1103
+ * @param {object} optsForWeighting
1104
+ * @param {number} optsForWeighting.width The width of the render target.
1105
+ * @param {number} optsForWeighting.height The height of the render target.
1106
+ * @param {number} optsForWeighting.sigmaNormalized The normalized sigma value
1107
+ * to use for weighting the brick requests based on their distance from
1108
+ * the center of the render target.
1109
+ */
1110
+ async processRequestData(buffer, optsForWeighting) {
1078
1111
  if (this.isBusy) {
1079
1112
  log.debug('processRequestData: already busy, skipping');
1080
1113
  return;
@@ -1091,7 +1124,7 @@ export class VolumeDataManager {
1091
1124
  }
1092
1125
  this.isBusy = true;
1093
1126
  this.triggerRequest = false;
1094
- const { requests, origRequestCount } = _requestBufferToRequestObjects(buffer, this.k);
1127
+ const { requests, origRequestCount } = _requestBufferToRequestObjects(buffer, this.k, optsForWeighting);
1095
1128
  if (requests.length === 0) {
1096
1129
  this.noNewRequests = true;
1097
1130
  }
@@ -147,7 +147,7 @@ describe('spatial-accelerated data utils', () => {
147
147
  });
148
148
  });
149
149
  describe('_requestBufferToRequestObjects', () => {
150
- it('correctly converts a buffer to request objects', () => {
150
+ it('correctly converts a buffer to request objects without optsForWeighting', () => {
151
151
  const buffer = new Uint8Array([
152
152
  0, 0, 0, 0,
153
153
  0, 0, 0, 0,
@@ -155,7 +155,28 @@ describe('spatial-accelerated data utils', () => {
155
155
  0, 0, 0, 0,
156
156
  ]);
157
157
  const k = 40;
158
- const { requests: result } = _requestBufferToRequestObjects(buffer, k);
158
+ const { requests: result } = _requestBufferToRequestObjects(buffer, k, {
159
+ width: undefined,
160
+ height: undefined,
161
+ sigmaNormalized: undefined,
162
+ });
163
+ expect(result).toEqual([
164
+ { x: 2, y: 1, z: 13 },
165
+ ]);
166
+ });
167
+ it('correctly converts a buffer to request objects with optsForWeighting', () => {
168
+ const buffer = new Uint8Array([
169
+ 0, 0, 0, 0,
170
+ 0, 0, 0, 0,
171
+ 0, 128, 16, 13,
172
+ 0, 0, 0, 0,
173
+ ]);
174
+ const k = 40;
175
+ const { requests: result } = _requestBufferToRequestObjects(buffer, k, {
176
+ width: 1,
177
+ height: 1,
178
+ sigmaNormalized: 0.25,
179
+ });
159
180
  expect(result).toEqual([
160
181
  { x: 2, y: 1, z: 13 },
161
182
  ]);
@@ -1 +1 @@
1
- {"version":3,"file":"VolumeView.d.ts","sourceRoot":"","sources":["../src/VolumeView.js"],"names":[],"mappings":"AAuLA,2DA6gBC"}
1
+ {"version":3,"file":"VolumeView.d.ts","sourceRoot":"","sources":["../src/VolumeView.js"],"names":[],"mappings":"AAkMA,2DA6gBC"}
@@ -13,7 +13,7 @@ import * as THREE from 'three';
13
13
  import { WebGLMultipleRenderTargets } from 'three';
14
14
  import { log, atLeastLogLevel, LogLevel } from '@vitessce/globals';
15
15
  import { useEventCallback } from '@vitessce/styles';
16
- import { VolumeDataManager, INIT_STATUS } from './VolumeDataManager.js';
16
+ import { VolumeDataManager, INIT_STATUS, DEFAULT_SIGMA_NORMALIZED, } from './VolumeDataManager.js';
17
17
  import { VolumeRenderManager } from './VolumeRenderManager.js';
18
18
  import { gaussianVertexShader } from './shaders/GaussianVertexShader.js';
19
19
  import { gaussianFragmentShader } from './shaders/GaussianFragmentShader.js';
@@ -57,8 +57,15 @@ function handleRequests(_gl, { frameRef, dataManager, mrtRef, bufRequest, bufUsa
57
57
  ctx.readPixels(0, 0, mrtRef.current.width, mrtRef.current.height, ctx.RGBA, ctx.UNSIGNED_BYTE, bufRequest.current);
58
58
  // Based on the request buffer contents, process the requests
59
59
  // (e.g., start loading the brick data and upload to the brick cache).
60
- // Finally, it will set triggerUsage to true.
61
- dataManager.processRequestData(bufRequest.current);
60
+ // Pass width/height so the data manager can compute Gaussian weighting.
61
+ dataManager.processRequestData(bufRequest.current, {
62
+ // If width/height are not yet available,
63
+ // processRequestData will proceed without weighting.
64
+ width: mrtRef?.current?.width,
65
+ height: mrtRef?.current?.height,
66
+ // Default sigmaNormalized = 0.25; can be tuned
67
+ sigmaNormalized: DEFAULT_SIGMA_NORMALIZED,
68
+ });
62
69
  }
63
70
  else if (dataManager.triggerUsage === true && dataManager.noNewRequests === false) {
64
71
  // Read the pixels of the usage buffer into the width*height*RGBA bufUsage.current array.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vitessce/spatial-accelerated",
3
- "version": "3.9.3",
3
+ "version": "3.9.5",
4
4
  "author": "HIDIVE Lab at HMS",
5
5
  "homepage": "http://vitessce.io",
6
6
  "repository": {
@@ -28,16 +28,16 @@
28
28
  "short-number": "^1.0.6",
29
29
  "three": "^0.154.0",
30
30
  "zarrita": "0.6.1",
31
- "@vitessce/constants-internal": "3.9.3",
32
- "@vitessce/legend": "3.9.3",
33
- "@vitessce/sets-utils": "3.9.3",
34
- "@vitessce/spatial-utils": "3.9.3",
35
- "@vitessce/gl": "3.9.3",
36
- "@vitessce/utils": "3.9.3",
37
- "@vitessce/vit-s": "3.9.3",
38
- "@vitessce/styles": "3.9.3",
39
- "@vitessce/tooltip": "3.9.3",
40
- "@vitessce/globals": "3.9.3"
31
+ "@vitessce/constants-internal": "3.9.5",
32
+ "@vitessce/gl": "3.9.5",
33
+ "@vitessce/legend": "3.9.5",
34
+ "@vitessce/tooltip": "3.9.5",
35
+ "@vitessce/spatial-utils": "3.9.5",
36
+ "@vitessce/sets-utils": "3.9.5",
37
+ "@vitessce/styles": "3.9.5",
38
+ "@vitessce/utils": "3.9.5",
39
+ "@vitessce/vit-s": "3.9.5",
40
+ "@vitessce/globals": "3.9.5"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@types/three": "^0.154.0",
@@ -316,9 +316,28 @@ export function _ptToZarr(ptx, pty, ptz, ptInfo) {
316
316
  };
317
317
  }
318
318
 
319
- export function _requestBufferToRequestObjects(buffer, k) {
319
+ // sigmaNormalized: fraction of half-dimension that determines Gaussian spread
320
+ export const DEFAULT_SIGMA_NORMALIZED = 0.25;
321
+
322
+ export function _requestBufferToRequestObjects(buffer, k, optsForWeighting) {
320
323
  const counts = new Map();
321
- for (let i = 0; i < buffer.length; i += 4) {
324
+
325
+ const { width, height, sigmaNormalized } = optsForWeighting;
326
+
327
+ const useWeighting = (
328
+ Number.isInteger(width) && Number.isInteger(height)
329
+ && width > 0 && height > 0
330
+ && typeof sigmaNormalized === 'number'
331
+ );
332
+ if (!useWeighting) {
333
+ log.warn('_requestBufferToRequestObjects: proceeding without weighting');
334
+ }
335
+
336
+ // Number of pixels present in buffer
337
+ const maxPixels = Math.floor(buffer.length / 4);
338
+
339
+ for (let pix = 0; pix < maxPixels; pix += 1) {
340
+ const i = pix * 4;
322
341
  const r = buffer[i];
323
342
  const g = buffer[i + 1];
324
343
  const b = buffer[i + 2];
@@ -328,11 +347,23 @@ export function _requestBufferToRequestObjects(buffer, k) {
328
347
  continue;
329
348
  }
330
349
  const packed = ((r << 24) | (g << 16) | (b << 8) | a) >>> 0;
331
- counts.set(packed, (counts.get(packed) || 0) + 1);
350
+
351
+ let weight = 1.0;
352
+ if (useWeighting) {
353
+ const x = pix % width;
354
+ const y = Math.floor(pix / width);
355
+ const dx = x - (width / 2);
356
+ const dy = y - (height / 2);
357
+ // normalized distance relative to full width/height to be resolution-independent
358
+ const nd = Math.sqrt((dx * dx) / (width * width) + (dy * dy) / (height * height));
359
+ const norm = nd / sigmaNormalized;
360
+ weight = Math.exp(-0.5 * norm * norm);
361
+ }
362
+
363
+ counts.set(packed, (counts.get(packed) || 0) + weight);
332
364
  }
333
- // log.debug('counts', counts);
334
- // log.debug('this.k', this.k);
335
- // Get the top K (potentially fewer than K) page table requests.
365
+
366
+ // Get the top K (potentially fewer than K) page table requests by weighted count.
336
367
  const requests = [...counts.entries()]
337
368
  .sort((a, b) => b[1] - a[1])
338
369
  .slice(0, k)
@@ -341,6 +372,7 @@ export function _requestBufferToRequestObjects(buffer, k) {
341
372
  y: (packed >> 12) & 0x3FF,
342
373
  z: packed & 0xFFF,
343
374
  }));
375
+
344
376
  return { requests, origRequestCount: counts.size };
345
377
  }
346
378
 
@@ -1253,7 +1285,19 @@ export class VolumeDataManager {
1253
1285
  return chunkEntry.data;
1254
1286
  }
1255
1287
 
1256
- async processRequestData(buffer) {
1288
+ /**
1289
+ * Process the buffer of brick requests from the shader, turning them into
1290
+ * actual Promises for Zarr chunks on the JS side.
1291
+ * @param {Uint8Array} buffer The bufRequest (of length width*height*4)
1292
+ * containing the brick requests from the shader.
1293
+ * @param {object} optsForWeighting
1294
+ * @param {number} optsForWeighting.width The width of the render target.
1295
+ * @param {number} optsForWeighting.height The height of the render target.
1296
+ * @param {number} optsForWeighting.sigmaNormalized The normalized sigma value
1297
+ * to use for weighting the brick requests based on their distance from
1298
+ * the center of the render target.
1299
+ */
1300
+ async processRequestData(buffer, optsForWeighting) {
1257
1301
  if (this.isBusy) {
1258
1302
  log.debug('processRequestData: already busy, skipping');
1259
1303
  return;
@@ -1274,7 +1318,7 @@ export class VolumeDataManager {
1274
1318
  this.isBusy = true;
1275
1319
  this.triggerRequest = false;
1276
1320
 
1277
- const { requests, origRequestCount } = _requestBufferToRequestObjects(buffer, this.k);
1321
+ const { requests, origRequestCount } = _requestBufferToRequestObjects(buffer, this.k, optsForWeighting);
1278
1322
 
1279
1323
  if (requests.length === 0) {
1280
1324
  this.noNewRequests = true;
@@ -163,7 +163,7 @@ describe('spatial-accelerated data utils', () => {
163
163
  });
164
164
  });
165
165
  describe('_requestBufferToRequestObjects', () => {
166
- it('correctly converts a buffer to request objects', () => {
166
+ it('correctly converts a buffer to request objects without optsForWeighting', () => {
167
167
  const buffer = new Uint8Array([
168
168
  0, 0, 0, 0,
169
169
  0, 0, 0, 0,
@@ -171,7 +171,28 @@ describe('spatial-accelerated data utils', () => {
171
171
  0, 0, 0, 0,
172
172
  ]);
173
173
  const k = 40;
174
- const { requests: result } = _requestBufferToRequestObjects(buffer, k);
174
+ const { requests: result } = _requestBufferToRequestObjects(buffer, k, {
175
+ width: undefined,
176
+ height: undefined,
177
+ sigmaNormalized: undefined,
178
+ });
179
+ expect(result).toEqual([
180
+ { x: 2, y: 1, z: 13 },
181
+ ]);
182
+ });
183
+ it('correctly converts a buffer to request objects with optsForWeighting', () => {
184
+ const buffer = new Uint8Array([
185
+ 0, 0, 0, 0,
186
+ 0, 0, 0, 0,
187
+ 0, 128, 16, 13,
188
+ 0, 0, 0, 0,
189
+ ]);
190
+ const k = 40;
191
+ const { requests: result } = _requestBufferToRequestObjects(buffer, k, {
192
+ width: 1,
193
+ height: 1,
194
+ sigmaNormalized: 0.25,
195
+ });
175
196
  expect(result).toEqual([
176
197
  { x: 2, y: 1, z: 13 },
177
198
  ]);
package/src/VolumeView.js CHANGED
@@ -14,7 +14,11 @@ import { WebGLMultipleRenderTargets } from 'three';
14
14
  import { log, atLeastLogLevel, LogLevel } from '@vitessce/globals';
15
15
  import { useEventCallback } from '@vitessce/styles';
16
16
 
17
- import { VolumeDataManager, INIT_STATUS } from './VolumeDataManager.js';
17
+ import {
18
+ VolumeDataManager,
19
+ INIT_STATUS,
20
+ DEFAULT_SIGMA_NORMALIZED,
21
+ } from './VolumeDataManager.js';
18
22
  import { VolumeRenderManager } from './VolumeRenderManager.js';
19
23
 
20
24
  import { gaussianVertexShader } from './shaders/GaussianVertexShader.js';
@@ -69,8 +73,15 @@ function handleRequests(_gl, { frameRef, dataManager, mrtRef, bufRequest, bufUsa
69
73
  ctx.RGBA, ctx.UNSIGNED_BYTE, bufRequest.current);
70
74
  // Based on the request buffer contents, process the requests
71
75
  // (e.g., start loading the brick data and upload to the brick cache).
72
- // Finally, it will set triggerUsage to true.
73
- dataManager.processRequestData(bufRequest.current);
76
+ // Pass width/height so the data manager can compute Gaussian weighting.
77
+ dataManager.processRequestData(bufRequest.current, {
78
+ // If width/height are not yet available,
79
+ // processRequestData will proceed without weighting.
80
+ width: mrtRef?.current?.width,
81
+ height: mrtRef?.current?.height,
82
+ // Default sigmaNormalized = 0.25; can be tuned
83
+ sigmaNormalized: DEFAULT_SIGMA_NORMALIZED,
84
+ });
74
85
  } else if (dataManager.triggerUsage === true && dataManager.noNewRequests === false) {
75
86
  // Read the pixels of the usage buffer into the width*height*RGBA bufUsage.current array.
76
87
  ctx.bindFramebuffer(ctx.READ_FRAMEBUFFER, framebufferFor(_gl, mrtRef.current));