import { jsxs, jsx, Fragment } from "react/jsx-runtime";
import React__default, { useRef, useState, useEffect, Suspense, forwardRef } from "react";
import { Canvas } from "@react-three/fiber";
import { Center, Text, Line, Bvh, OrbitControls } from "@react-three/drei";
import { Matrix3, Matrix4, Vector3, Vector2, UniformsUtils, Data3DTexture, RedFormat, FloatType, LinearFilter, FrontSide, Scene, Group, MeshPhysicalMaterial, MeshBasicMaterial, MeshStandardMaterial, BackSide } from "three";
import { C as CoordinationType, g as getImageSize } from "./index-DAhtQMo7.js";
function MeasureLine({ currentLine, scale }) {
  const textRef = useRef(null);
  return jsxs("group", { children: [jsx(Center, { bottom: true, right: true, position: [currentLine.midPoint.x, currentLine.midPoint.y, currentLine.midPoint.z], rotation: [0, 0, 0], children: jsx(Text, { color: "gray", scale: 0.05, ref: textRef, children: `${(currentLine.startPoint.distanceTo(currentLine.endPoint) * scale).toFixed(2)} µm` }) }), jsx(Line, {
    points: [currentLine.startPoint, currentLine.endPoint],
    color: "white",
    lineWidth: 2,
    dashed: false,
    segments: true
  })] });
}
class Volume {
  spacing = [1, 1, 1];
  // Offset of the volume in the RAS coordinate system
  offset = [0, 0, 0];
  // The IJK to RAS matrix
  matrix = new Matrix3().identity();
  // The list of all the slices associated to this volume
  sliceList = [];
  /**
   * The voxels with values under this
   * threshold won't appear in the slices.
   * If changed, geometryNeedsUpdate is automatically set to true on all
   * the slices associated to this volume
   */
  lowerThresholdValue = -Infinity;
  /**
   * The voxels with values over this
   * threshold won't appear in the slices.
   * If changed, geometryNeedsUpdate is automatically set to true on all
   * the slices associated to this volume
   */
  upperThresholdValue = Infinity;
  // Width of the volume in the IJK coordinate system
  xLength = 1;
  // Height of the volume in the IJK coordinate system
  yLength = 1;
  // Depth of the volume in the IJK coordinate system
  zLength = 1;
  // Data of the volume
  data;
  RASDimensions;
  inverseMatrix;
  min;
  max;
  /**
   * @param {number} xLength Width of the volume
   * @param {number} yLength Length of the volume
   * @param {number} zLength Depth of the volume
   * @param {string} type The type of data (uint8, uint16, ...)
   * @param {ArrayBuffer} arrayBuffer The buffer with volume data
   */
  constructor(xLength, yLength, zLength, type, arrayBuffer) {
    if (xLength !== void 0) {
      this.xLength = Number(xLength) || 1;
      this.yLength = Number(yLength) || 1;
      this.zLength = Number(zLength) || 1;
      switch (type) {
        case "Uint8":
        case "uint8":
        case "uchar":
        case "unsigned char":
        case "uint8_t":
          this.data = new Uint8Array(arrayBuffer);
          break;
        case "Int8":
        case "int8":
        case "signed char":
        case "int8_t":
          this.data = new Int8Array(arrayBuffer);
          break;
        case "Int16":
        case "int16":
        case "short":
        case "short int":
        case "signed short":
        case "signed short int":
        case "int16_t":
          this.data = new Int16Array(arrayBuffer);
          break;
        case "Uint16":
        case "uint16":
        case "ushort":
        case "unsigned short":
        case "unsigned short int":
        case "uint16_t":
          this.data = new Uint16Array(arrayBuffer);
          break;
        case "Int32":
        case "int32":
        case "int":
        case "signed int":
        case "int32_t":
          this.data = new Int32Array(arrayBuffer);
          break;
        case "Uint32":
        case "uint32":
        case "uint":
        case "unsigned int":
        case "uint32_t":
          this.data = new Uint32Array(arrayBuffer);
          break;
        case "longlong":
        case "long long":
        case "long long int":
        case "signed long long":
        case "signed long long int":
        case "int64":
        case "int64_t":
        case "ulonglong":
        case "unsigned long long":
        case "unsigned long long int":
        case "uint64":
        case "uint64_t":
          throw new Error("uint64_t type is not supported in JavaScript");
        case "Float32":
        case "float32":
        case "float":
          this.data = new Float32Array(arrayBuffer);
          break;
        case "Float64":
        case "float64":
        case "double":
          this.data = new Float64Array(arrayBuffer);
          break;
        default:
          this.data = new Uint8Array(arrayBuffer);
      }
      if (this.data.length !== this.xLength * this.yLength * this.zLength) {
        throw new Error("lengths are not matching arrayBuffer size");
      }
    }
  }
  get lowerThreshold() {
    return this.lowerThresholdValue;
  }
  set lowerThreshold(value) {
    this.lowerThresholdValue = value;
    this.sliceList.forEach((slice) => {
      slice.geometryNeedsUpdate = true;
    });
  }
  get upperThreshold() {
    return this.upperThresholdValue;
  }
  set upperThreshold(value) {
    this.upperThresholdValue = value;
    this.sliceList.forEach((slice) => {
      slice.geometryNeedsUpdate = true;
    });
  }
  /**
   * Shortcut for data[access(i,j,k)]
   */
  getData(i, j, k) {
    return this.data[k * this.xLength * this.yLength + j * this.xLength + i];
  }
  /**
   * Compute the index in the data
   * array corresponding to the given coordinates in IJK system
   */
  access(i, j, k) {
    return k * this.xLength * this.yLength + j * this.xLength + i;
  }
  /**
   * Retrieve the IJK coordinates of the voxel
   * corresponding of the given index in the data
   */
  reverseAccess(index2) {
    const z = Math.floor(index2 / (this.yLength * this.xLength));
    const y = Math.floor((index2 - z * this.yLength * this.xLength) / this.xLength);
    const x = index2 - z * this.yLength * this.xLength - y * this.xLength;
    return [x, y, z];
  }
  /**
   * Apply a function to all the voxels, be careful,
   * the value will be replaced
   */
  // eslint-disable-next-line max-len
  map(functionToMap, contextParam) {
    const { length } = this.data;
    const context = contextParam || this;
    for (let i = 0; i < length; i++) {
      this.data[i] = functionToMap.call(context, this.data[i], i, this.data);
    }
    return this;
  }
  /**
   * Compute the orientation
   * of the slice and returns all the information relative to the
   * geometry such as sliceAccess,
   * the plane matrix (orientation and position in RAS coordinate)
   * and the dimensions of the plane in both coordinate system.
   */
  extractPerpendicularPlane(axis, RASIndex) {
    const planeMatrix = new Matrix4().identity();
    const volume = this;
    let firstSpacing;
    let secondSpacing;
    let positionOffset;
    let IJKIndex;
    const axisInIJK = new Vector3();
    const firstDirection = new Vector3();
    const secondDirection = new Vector3();
    const dimensions = new Vector3(this.xLength, this.yLength, this.zLength);
    switch (axis) {
      case "x":
        axisInIJK.set(1, 0, 0);
        firstDirection.set(0, 0, -1);
        secondDirection.set(0, -1, 0);
        firstSpacing = this.spacing[2];
        secondSpacing = this.spacing[1];
        IJKIndex = new Vector3(RASIndex, 0, 0);
        planeMatrix.multiply(new Matrix4().makeRotationY(Math.PI / 2));
        positionOffset = (volume.RASDimensions[0] - 1) / 2;
        planeMatrix.setPosition(new Vector3(RASIndex - positionOffset, 0, 0));
        break;
      case "y":
        axisInIJK.set(0, 1, 0);
        firstDirection.set(1, 0, 0);
        secondDirection.set(0, 0, 1);
        firstSpacing = this.spacing[0];
        secondSpacing = this.spacing[2];
        IJKIndex = new Vector3(0, RASIndex, 0);
        planeMatrix.multiply(new Matrix4().makeRotationX(-Math.PI / 2));
        positionOffset = (volume.RASDimensions[1] - 1) / 2;
        planeMatrix.setPosition(new Vector3(0, RASIndex - positionOffset, 0));
        break;
      case "z":
      default:
        axisInIJK.set(0, 0, 1);
        firstDirection.set(1, 0, 0);
        secondDirection.set(0, -1, 0);
        firstSpacing = this.spacing[0];
        secondSpacing = this.spacing[1];
        IJKIndex = new Vector3(0, 0, RASIndex);
        positionOffset = (volume.RASDimensions[2] - 1) / 2;
        planeMatrix.setPosition(new Vector3(0, 0, RASIndex - positionOffset));
        break;
    }
    firstDirection.applyMatrix4(volume.inverseMatrix).normalize();
    firstDirection.argVar = "i";
    secondDirection.applyMatrix4(volume.inverseMatrix).normalize();
    secondDirection.argVar = "j";
    axisInIJK.applyMatrix4(volume.inverseMatrix).normalize();
    const iLength = Math.floor(Math.abs(firstDirection.dot(dimensions)));
    const jLength = Math.floor(Math.abs(secondDirection.dot(dimensions)));
    const planeWidth = Math.abs(iLength * firstSpacing);
    const planeHeight = Math.abs(jLength * secondSpacing);
    IJKIndex = Math.abs(Math.round(IJKIndex.applyMatrix4(volume.inverseMatrix).dot(axisInIJK)));
    const base = [new Vector3(1, 0, 0), new Vector3(0, 1, 0), new Vector3(0, 0, 1)];
    const iDirection = [firstDirection, secondDirection, axisInIJK].find((x) => Math.abs(x.dot(base[0])) > 0.9);
    const jDirection = [firstDirection, secondDirection, axisInIJK].find((x) => Math.abs(x.dot(base[1])) > 0.9);
    const kDirection = [firstDirection, secondDirection, axisInIJK].find((x) => Math.abs(x.dot(base[2])) > 0.9);
    function sliceAccess(i, j) {
      const si = iDirection === axisInIJK ? IJKIndex : iDirection.argVar === "i" ? i : j;
      const sj = jDirection === axisInIJK ? IJKIndex : jDirection.argVar === "i" ? i : j;
      const sk = kDirection === axisInIJK ? IJKIndex : kDirection.argVar === "i" ? i : j;
      const accessI = iDirection.dot(base[0]) > 0 ? si : volume.xLength - 1 - si;
      const accessJ = jDirection.dot(base[1]) > 0 ? sj : volume.yLength - 1 - sj;
      const accessK = kDirection.dot(base[2]) > 0 ? sk : volume.zLength - 1 - sk;
      return volume.access(accessI, accessJ, accessK);
    }
    return {
      iLength,
      jLength,
      sliceAccess,
      matrix: planeMatrix,
      planeWidth,
      planeHeight
    };
  }
  /**
   * Compute the minimum
   * and the maximum of the data in the volume
   * @returns {Array} [min,max]
   */
  computeMinMax() {
    let min = Infinity;
    let max = -Infinity;
    const datasize = this.data.length;
    let i = 0;
    for (i = 0; i < datasize; i++) {
      if (!Number.isNaN(this.data[i])) {
        const value = this.data[i];
        min = Math.min(min, value);
        max = Math.max(max, value);
      }
    }
    this.min = min;
    this.max = max;
    return [min, max];
  }
}
const VolumeRenderShaderPerspective = {
  uniforms: {
    u_size: { value: new Vector3(1, 1, 1) },
    u_renderstyle: { value: 0 },
    u_renderthreshold: { value: 0.5 },
    u_opacity: { value: 0.5 },
    u_clim: { value: new Vector2(0.2, 0.8) },
    u_clim2: { value: new Vector2(0.2, 0.8) },
    u_clim3: { value: new Vector2(0.2, 0.8) },
    u_clim4: { value: new Vector2(0.2, 0.8) },
    u_clim5: { value: new Vector2(0.2, 0.8) },
    u_clim6: { value: new Vector2(0.2, 0.8) },
    u_xClip: { value: new Vector2(-1, 1e6) },
    u_yClip: { value: new Vector2(-1, 1e6) },
    u_zClip: { value: new Vector2(-1, 1e6) },
    u_data: { value: null },
    u_stop_geom: { value: null },
    u_geo_color: { value: null },
    u_window_size: { value: new Vector2(1, 1) },
    u_vol_scale: { value: new Vector3(1, 1, 1) },
    u_physical_Pixel: { value: 0.5 },
    volumeTex: { value: null },
    volumeTex2: { value: null },
    volumeTex3: { value: null },
    volumeTex4: { value: null },
    volumeTex5: { value: null },
    volumeTex6: { value: null },
    u_color: { value: new Vector3(0, 0, 0) },
    u_color2: { value: new Vector3(0, 0, 0) },
    u_color3: { value: new Vector3(0, 0, 0) },
    u_color4: { value: new Vector3(0, 0, 0) },
    u_color5: { value: new Vector3(0, 0, 0) },
    u_color6: { value: new Vector3(0, 0, 0) },
    u_cmdata: { value: null },
    near: { value: 0.1 },
    far: { value: 1e4 },
    alphaScale: { value: 0 },
    dtScale: { value: 1 },
    volumeCount: { value: 0 },
    finalGamma: { value: 0 },
    boxSize: { value: new Vector3(1, 1, 1) }
  },
  vertexShader: [
    "out vec3 rayDirUnnorm;",
    "out vec3 cameraCorrected;",
    "uniform vec3 u_vol_scale;",
    "uniform vec3 u_size;",
    "varying vec3 worldSpaceCoords;",
    "varying vec2 vUv;",
    "varying vec4 glPosition;",
    "uniform highp vec3 boxSize;",
    "void main()",
    "{",
    "   worldSpaceCoords = position / boxSize + vec3(0.5, 0.5, 0.5); //move it from [-0.5;0.5] to [0,1]",
    "   cameraCorrected = (inverse(modelMatrix) * vec4(cameraPosition, 1.)).xyz;",
    "   rayDirUnnorm = position - cameraCorrected;",
    "   gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);",
    "   glPosition = gl_Position;",
    "   vUv = uv;",
    "}"
  ].join("\n"),
  fragmentShader: [
    "#include <packing>",
    "precision highp float;",
    " precision mediump sampler3D;",
    "in vec3 rayDirUnnorm;",
    "in vec3 cameraCorrected;",
    "uniform sampler3D volumeTex;",
    "uniform sampler3D volumeTex2;",
    "uniform sampler3D volumeTex3;",
    "uniform sampler3D volumeTex4;",
    "uniform sampler3D volumeTex5;",
    "uniform sampler3D volumeTex6;",
    "uniform vec2 u_clim;",
    "uniform vec2 u_clim2;",
    "uniform vec2 u_clim3;",
    "uniform vec2 u_clim4;",
    "uniform vec2 u_clim5;",
    "uniform vec2 u_clim6;",
    "uniform vec2 u_window_size;",
    "uniform vec2 u_xClip;",
    "uniform vec2 u_yClip;",
    "uniform vec2 u_zClip;",
    "uniform sampler2D u_cmdata;",
    "uniform sampler2D u_stop_geom;",
    "uniform sampler2D u_geo_color;",
    "uniform vec3 u_color;",
    "uniform vec3 u_color2;",
    "uniform vec3 u_color3;",
    "uniform vec3 u_color4;",
    "uniform vec3 u_color5;",
    "uniform vec3 u_color6;",
    "uniform float alphaScale;",
    "uniform float dtScale;",
    "uniform float finalGamma;",
    "uniform float volumeCount;",
    "uniform highp vec3 boxSize;",
    "uniform vec3 u_size;",
    "uniform int u_renderstyle;",
    "uniform float u_opacity;",
    "uniform vec3 u_vol_scale;",
    "uniform float near;",
    "uniform float u_physical_Pixel;",
    "varying vec2 vUv;",
    "varying vec4 glPosition;",
    "uniform float far;",
    "varying vec3 worldSpaceCoords;",
    "float linearize_z(float z) {",
    "        return near * far / (far + z * (near - far));",
    "}",
    "vec2 intersect_hit(vec3 orig, vec3 dir) {",
    "  vec3 boxMin = vec3(-0.5) * boxSize;",
    "  vec3 boxMax = vec3( 0.5) * boxSize;",
    "  if(u_xClip.x > -1.0){   boxMin.x = u_xClip.x-(boxSize.x/2.0);",
    "   if(u_xClip.y < boxSize.x)",
    "       boxMax.x = u_xClip.y-(boxSize.x/2.0);",
    "  }",
    "  if(u_yClip.x > -1.0){   boxMin.y = u_yClip.x-(boxSize.y/2.0);",
    "   if(u_yClip.y < boxSize.y)",
    "      boxMax.y = u_yClip.y-(boxSize.y/2.0);",
    "  }",
    "  if(u_zClip.x > -1.0){   boxMin.z = u_zClip.x-(boxSize.z/2.0);",
    "   if(u_zClip.y < boxSize.z)       boxMax.z = u_zClip.y-(boxSize.z/2.0);",
    "  }",
    "  vec3 invDir = 1.0 / dir;",
    "  vec3 tmin0 = (boxMin - orig) * invDir;",
    "  vec3 tmax0 = (boxMax - orig) * invDir;",
    "  vec3 tmin = min(tmin0, tmax0);",
    "  vec3 tmax = max(tmin0, tmax0);",
    "  float t0 = max(tmin.x, max(tmin.y, tmin.z));",
    "  float t1 = min(tmax.x, min(tmax.y, tmax.z));",
    "  return vec2(t0, t1);",
    "}",
    "   // Pseudo-random number gen from",
    "   // http://www.reedbeta.com/blog/quick-and-easy-gpu-random-numbers-in-d3d11/",
    "   // with some tweaks for the range of values",
    "       float wang_hash(int seed) {",
    "     seed = (seed ^ 61) ^ (seed >> 16);",
    "     seed *= 9;",
    "     seed = seed ^ (seed >> 4);",
    "     seed *= 0x27d4eb2d;",
    "     seed = seed ^ (seed >> 15);",
    "     return float(seed % 2147483647) / float(2147483647);",
    "     }",
    "float linear_to_srgb(float x) {",
    "   if (x <= 0.0031308f) {",
    "     return 12.92f * x;",
    "   }",
    "   return 1.055f * pow(x, 1.f / 2.4f) - 0.055f;",
    "}",
    "void main(void) {",
    // For finding the settings for the MESH
    // "  gl_FragColor = vec4(worldSpaceCoords.x,worldSpaceCoords.y,worldSpaceCoords.z,0.5);",
    // "  return;",
    //
    "  //STEP 1: Normalize the view Ray",
    "  vec3 rayDir = normalize(rayDirUnnorm);",
    "  //STEP 2: Intersect the ray with the volume bounds to find the interval along the ray overlapped by the volume",
    "  vec2 t_hit = intersect_hit(cameraCorrected, rayDir);",
    "  if (t_hit.x >= t_hit.y) {",
    "    discard;",
    "  }",
    "  //No sample behind the eye",
    "  t_hit.x = max(t_hit.x, 0.0);",
    "  //STEP 3: Compute the step size to march through the volume grid",
    "  ivec3 volumeTexSize = textureSize(volumeTex, 0);",
    "  vec3 dt_vec = 1.0 / (vec3(volumeTexSize) * abs(rayDir));",
    "  float dt = min(dt_vec.x, min(dt_vec.y, dt_vec.z));",
    "  dt = max(1.0, dt);",
    "  // Ray starting point, in the real space where the box may not be a cube.",
    "  // Prevents a lost WebGL context.",
    // "   if (dt < 0.0000001) {",
    // "     gl_FragColor = vec4(1.0);",
    // "     return;",
    // "   }",
    " float offset = wang_hash(int(gl_FragCoord.x + 640.0 * gl_FragCoord.y));",
    " vec3 p = cameraCorrected + (t_hit.x + offset + dt) * rayDir;",
    "  // Most browsers do not need this initialization, but add it to be safe.",
    "  gl_FragColor = vec4(0.0);",
    "  p = p / boxSize + vec3(0.5);",
    "  vec3 step = (rayDir * dt) / boxSize;",
    "  // ",
    "  // Initialization of some variables.",
    "  float max_val = 0.0;",
    "  float max_val2 = 0.0;",
    "  float max_val3 = 0.0;",
    "  float max_val4 = 0.0;",
    "  float max_val5 = 0.0;",
    "  float max_val6 = 0.0;",
    "  vec3 rgbCombo = vec3(0.0);",
    "  float total = 0.0;",
    "  int max_i = 30000;",
    "  int i = 0;",
    "  float x = gl_FragCoord.x/u_window_size.x;",
    "  float y = gl_FragCoord.y/u_window_size.y;",
    "  vec3 meshPos = texture2D(u_stop_geom, vec2(x,y)).xyz;",
    // "  vec3 meshPos = texture2D(u_stop_geom, vec2(gl_FragCoord.x,gl_FragCoord.y)).xyz;",
    //  "  gl_FragColor = vec4(meshPos,1.0);",
    //  "  return;",
    "  float dist = 1000.0;",
    "  for (float t = t_hit.x; t < t_hit.y; t += dt) {",
    "       if(meshPos != vec3(0.0))           dist = distance(p,meshPos);",
    "      float val = texture(volumeTex, p.xyz).r;",
    "      val = max(0.0, (val - u_clim[0]) / (u_clim[1] - u_clim[0]));",
    "      rgbCombo += max(0.0, min(1.0, val)) * u_color;",
    "      total += val;",
    "      if(volumeCount > 1.0){           float val2 = texture(volumeTex2, p.xyz).r;",
    "           val2 = max(0.0,(val2 - u_clim2[0]) / (u_clim2[1] - u_clim2[0]));",
    "           rgbCombo += max(0.0, min(1.0, val2)) * u_color2;",
    "           total += val2;",
    "       }",
    "       if(volumeCount > 2.0){           float val3 = texture(volumeTex3, p.xyz).r;",
    "           val3 = max(0.0,(val3 - u_clim3[0]) / (u_clim3[1] - u_clim3[0]));",
    "           rgbCombo += max(0.0, min(1.0, val3)) * u_color3;",
    "           total += val3;",
    "       }",
    "       if(volumeCount > 3.0){           float val4 = texture(volumeTex4, p.xyz).r;",
    "           val4 = max(0.0,(val4 - u_clim4[0]) / (u_clim4[1] - u_clim4[0]));",
    "           rgbCombo += max(0.0, min(1.0, val4)) * u_color4;",
    "           total += val4;",
    "       }",
    "       if(volumeCount > 4.0){           float val5 = texture(volumeTex5, p.xyz).r;",
    "           val5 = max(0.0,(val5 - u_clim5[0]) / (u_clim5[1] - u_clim5[0]));",
    "           rgbCombo += max(0.0, min(1.0, val5)) * u_color5;",
    "           total += val5;",
    "        }",
    "        if(volumeCount > 5.0){           float val6 = texture(volumeTex6, p.xyz).r;",
    "           val6 = max(0.0,(val6 - u_clim6[0]) / (u_clim6[1] - u_clim6[0]));",
    "           rgbCombo += max(0.0, min(1.0, val6)) * u_color6;",
    "           total += val6;",
    "       }",
    // STOP the traversal if there has been data and the distance to the object is too small
    "       if(total > 0.0 && dist < 0.1){",
    "           break;",
    "       }else if(dist < 0.1){           gl_FragColor = vec4(0.0,0.0,0.0,0.0);",
    "           break;",
    "       }",
    "       if(u_renderstyle == 0 && (max_val > u_clim[1] && max_val2 >= u_clim2[1] && max_val3 >= u_clim3[1] && max_val4 >= u_clim4[1] && max_val5 >= u_clim5[1] &&  max_val6 >= u_clim6[1])) break;",
    "       if(u_renderstyle == 2){           total = min(total, 1.0);",
    "           vec4 val_color = vec4(rgbCombo, total);",
    "           val_color.a = 1.0 - pow(1.0 - val_color.a, 1.0);",
    "           gl_FragColor.rgb += (1.0 - gl_FragColor.a) * val_color.a * val_color.rgb;",
    "           gl_FragColor.a += (1.0 - gl_FragColor.a) * val_color.a * dtScale;",
    "           if (gl_FragColor.a >= 0.95) {",
    "               break;",
    "           }",
    "       }",
    // "       }",
    "       p += step;",
    "  }",
    "   gl_FragDepth = distance(worldSpaceCoords,p)*u_physical_Pixel;",
    // "   gl_FragColor = vec4(gl_FragDepth,gl_FragDepth,gl_FragDepth,1.0);",
    // "   return;",
    "   if(u_renderstyle == 0 && (max_val <  u_clim[0] && max_val2 < u_clim2[0] && max_val3 < u_clim3[0] &&   max_val4 <  u_clim4[0] && max_val5 <  u_clim5[0] && max_val6 <  u_clim6[0])){",
    "        gl_FragColor = vec4(0,0,0,0);",
    "   }else if(u_renderstyle == 0){",
    "       max_val = (max_val - u_clim[0]) / (u_clim[1] - u_clim[0]);",
    "       max_val2 = (max_val2 - u_clim2[0]) / (u_clim2[1] - u_clim2[0]);",
    "       max_val3 = (max_val3 - u_clim3[0]) / (u_clim3[1] - u_clim3[0]);",
    "       max_val4 = (max_val4 - u_clim4[0]) / (u_clim4[1] - u_clim4[0]);",
    "       max_val5 = (max_val5 - u_clim5[0]) / (u_clim5[1] - u_clim5[0]);",
    "       max_val6 = (max_val6 - u_clim6[0]) / (u_clim6[1] - u_clim6[0]);",
    "       vec3 color = u_color * max_val;",
    "       if(volumeCount > 1.0) color = color +  u_color2 * max_val2;",
    "       if(volumeCount > 3.0) color = color +  u_color4 * max_val4;",
    "       if(volumeCount > 2.0) color = color +  u_color3 * max_val3;",
    "       if(volumeCount > 4.0) color = color +  u_color5 * max_val5;",
    "       if(volumeCount > 5.0) color = color +  u_color6 * max_val6;",
    "       vec3 colorCorrected = vec3(min(color[0], 1.0), min(color[1],1.0), min(color[2],1.0));",
    "        gl_FragColor = vec4(color,1.0);",
    "    }",
    "    gl_FragColor.r = linear_to_srgb(gl_FragColor.r);",
    "    gl_FragColor.g = linear_to_srgb(gl_FragColor.g);",
    "    gl_FragColor.b = linear_to_srgb(gl_FragColor.b);",
    "}"
  ].join("\n")
};
const renderingModeMap = {
  maximumIntensityProjection: 0,
  minimumIntensityProjection: 1,
  additive: 2
};
function extractInformationFromProps(layerScope, layerCoordination, channelScopes, channelCoordination, image, props) {
  const { spatialRenderingMode } = props;
  const data = image?.image?.instance?.getData();
  if (!data) {
    return {
      channelsVisible: null,
      resolution: null,
      data: null,
      colors: null,
      contrastLimits: null,
      allChannels: null,
      channelTargetC: null,
      is3dMode: false,
      renderingMode: null,
      layerTransparency: 1,
      xSlice: null,
      ySlice: null,
      zSlice: null
    };
  }
  const imageWrapperInstance = image.image.instance;
  const is3dMode = spatialRenderingMode === "3D";
  const isRgb = layerCoordination[CoordinationType.PHOTOMETRIC_INTERPRETATION] === "RGB";
  const renderingModeStr = layerCoordination[CoordinationType.VOLUMETRIC_RENDERING_ALGORITHM];
  const renderingMode = renderingModeMap[renderingModeStr];
  const visible = layerCoordination[CoordinationType.SPATIAL_LAYER_VISIBLE];
  const layerTransparency = layerCoordination[CoordinationType.SPATIAL_LAYER_OPACITY];
  if (imageWrapperInstance.isInterleaved()) ;
  const colors = isRgb ? [
    [255, 0, 0],
    [0, 255, 0],
    [0, 0, 255]
  ] : channelScopes.map((cScope) => channelCoordination[cScope][CoordinationType.SPATIAL_CHANNEL_COLOR]);
  const contrastLimits = isRgb ? [
    [0, 255],
    [0, 255],
    [0, 255]
  ] : channelScopes.map((cScope) => channelCoordination[cScope][CoordinationType.SPATIAL_CHANNEL_WINDOW] || [0, 255]);
  const channelsVisible = isRgb ? [
    // Layer visible AND channel visible
    visible && true,
    visible && true,
    visible && true
  ] : channelScopes.map((cScope) => (
    // Layer visible AND channel visible
    visible && channelCoordination[cScope][CoordinationType.SPATIAL_CHANNEL_VISIBLE]
  ));
  const channelTargetC = isRgb ? [
    // Layer visible AND channel visible
    visible && true,
    visible && true,
    visible && true
  ] : channelScopes.map((cScope) => (
    // Layer visible AND channel visible
    visible && imageWrapperInstance.getChannelIndex(channelCoordination[cScope][CoordinationType.SPATIAL_TARGET_C])
  ));
  const autoTargetResolution = imageWrapperInstance.getAutoTargetResolution();
  const targetResolution = layerCoordination[CoordinationType.SPATIAL_TARGET_RESOLUTION];
  const resolution = targetResolution === null || Number.isNaN(targetResolution) ? autoTargetResolution : targetResolution;
  const allChannels = image.image.loaders[0].channels ?? [];
  let xSlice = layerCoordination[CoordinationType.SPATIAL_SLICE_X];
  let ySlice = layerCoordination[CoordinationType.SPATIAL_SLICE_Y];
  let zSlice = layerCoordination[CoordinationType.SPATIAL_SLICE_Z];
  xSlice = xSlice !== null ? xSlice : [-1, 1e5];
  ySlice = ySlice !== null ? ySlice : [-1, 1e5];
  zSlice = zSlice !== null ? zSlice : [-1, 1e5];
  return {
    channelsVisible,
    allChannels,
    channelTargetC,
    resolution,
    data,
    colors,
    contrastLimits,
    is3dMode,
    renderingMode,
    layerTransparency,
    xSlice,
    ySlice,
    zSlice
  };
}
function useVolumeSettings(props, volumeSettings, setVolumeSettings, dataReady, setDataReady) {
  const { images = {}, imageLayerScopes, imageLayerCoordination, imageChannelScopesByLayer, imageChannelCoordination } = props;
  const layerScope = imageLayerScopes[0];
  const channelScopes = imageChannelScopesByLayer[layerScope];
  const layerCoordination = imageLayerCoordination[0][layerScope];
  const channelCoordination = imageChannelCoordination[0][layerScope];
  const { channelsVisible, allChannels, channelTargetC, resolution, data, colors, contrastLimits, is3dMode, renderingMode, layerTransparency, xSlice, ySlice, zSlice } = extractInformationFromProps(layerScope, layerCoordination, channelScopes, channelCoordination, images[layerScope], props);
  if (channelTargetC !== null) {
    if (volumeSettings.channelTargetC?.length !== 0 && (volumeSettings.channelTargetC?.toString() !== channelTargetC.toString() || volumeSettings.resolution?.toString() !== resolution.toString())) {
      if (!dataReady)
        setDataReady(true);
    } else if (volumeSettings.channelsVisible?.toString() !== channelsVisible?.toString() || volumeSettings.colors?.toString() !== colors?.toString() || volumeSettings.is3dMode !== is3dMode || volumeSettings.contrastLimits?.toString() !== contrastLimits?.toString() || volumeSettings.renderingMode?.toString() !== renderingMode.toString() || volumeSettings.layerTransparency.toString() !== layerTransparency.toString() || volumeSettings.xSlice?.toString() !== xSlice.toString() || volumeSettings.ySlice?.toString() !== ySlice.toString() || volumeSettings.zSlice?.toString() !== zSlice.toString()) {
      setVolumeSettings({
        channelsVisible,
        allChannels,
        channelTargetC,
        resolution,
        data,
        colors,
        contrastLimits,
        is3dMode,
        renderingMode,
        layerTransparency,
        xSlice,
        ySlice,
        zSlice
      });
      setDataReady(false);
    }
  }
  return {
    images,
    layerScope,
    imageLayerScopes,
    imageLayerCoordination,
    imageChannelScopesByLayer,
    imageChannelCoordination,
    channelsVisible,
    allChannels,
    channelTargetC,
    resolution,
    data,
    colors,
    contrastLimits,
    is3dMode,
    renderingMode,
    layerTransparency,
    xSlice,
    ySlice,
    zSlice
  };
}
function getMinMaxValue(value, minMax) {
  const [min, max] = minMax;
  return (value - min) / Math.sqrt(max ** 2 - min ** 2);
}
function setUniformsTextures(uniforms, textures, volume, volConfig, renderstyle, contrastLimits, colors, layerTransparency, xSlice, ySlice, zSlice, meshScale, originalScale) {
  uniforms.boxSize.value.set(volume.xLength, volume.yLength, volume.zLength);
  uniforms.volumeTex.value = textures.length > 0 ? textures[0] : null;
  uniforms.volumeTex2.value = textures.length > 1 ? textures[1] : null;
  uniforms.volumeTex3.value = textures.length > 2 ? textures[2] : null;
  uniforms.volumeTex4.value = textures.length > 3 ? textures[3] : null;
  uniforms.volumeTex5.value = textures.length > 4 ? textures[4] : null;
  uniforms.volumeTex6.value = textures.length > 5 ? textures[5] : null;
  uniforms.near.value = 0.1;
  uniforms.far.value = 3e3;
  uniforms.alphaScale.value = 1;
  uniforms.dtScale.value = layerTransparency;
  uniforms.finalGamma.value = 4.5;
  uniforms.volumeCount.value = textures.length;
  uniforms.u_size.value.set(volume.xLength, volume.yLength, volume.zLength);
  uniforms.u_stop_geom.value = null;
  uniforms.u_window_size.value.set(0, 0);
  uniforms.u_vol_scale.value.set(1 / volume.xLength, 1 / volume.yLength, 1 / volume.zLength * 2);
  uniforms.u_renderstyle.value = renderstyle;
  uniforms.u_clim.value.set(contrastLimits.length > 0 ? contrastLimits[0][0] : null, contrastLimits.length > 0 ? contrastLimits[0][1] : null);
  uniforms.u_clim2.value.set(contrastLimits.length > 1 ? contrastLimits[1][0] : null, contrastLimits.length > 1 ? contrastLimits[1][1] : null);
  uniforms.u_clim3.value.set(contrastLimits.length > 2 ? contrastLimits[2][0] : null, contrastLimits.length > 2 ? contrastLimits[2][1] : null);
  uniforms.u_clim4.value.set(contrastLimits.length > 3 ? contrastLimits[3][0] : null, contrastLimits.length > 3 ? contrastLimits[3][1] : null);
  uniforms.u_clim5.value.set(contrastLimits.length > 4 ? contrastLimits[4][0] : null, contrastLimits.length > 4 ? contrastLimits[4][1] : null);
  uniforms.u_clim6.value.set(contrastLimits.length > 5 ? contrastLimits[5][0] : null, contrastLimits.length > 5 ? contrastLimits[5][1] : null);
  uniforms.u_xClip.value.set(xSlice[0] * (1 / meshScale[0]) / originalScale[0] * volume.xLength, xSlice[1] * (1 / meshScale[0]) / originalScale[0] * volume.xLength);
  uniforms.u_yClip.value.set(ySlice[0] * (1 / meshScale[1]) / originalScale[1] * volume.yLength, ySlice[1] * (1 / meshScale[1]) / originalScale[1] * volume.yLength);
  uniforms.u_zClip.value.set(zSlice[0] * (1 / meshScale[2]) / originalScale[2] * volume.zLength, zSlice[1] * (1 / meshScale[1]) / originalScale[2] * volume.zLength);
  uniforms.u_color.value.set(colors.length > 0 ? colors[0][0] : null, colors.length > 0 ? colors[0][1] : null, colors.length > 0 ? colors[0][2] : null);
  uniforms.u_color2.value.set(colors.length > 1 ? colors[1][0] : null, colors.length > 1 ? colors[1][1] : null, colors.length > 1 ? colors[1][2] : null);
  uniforms.u_color3.value.set(colors.length > 2 ? colors[2][0] : null, colors.length > 2 ? colors[2][1] : null, colors.length > 2 ? colors[2][2] : null);
  uniforms.u_color4.value.set(colors.length > 3 ? colors[3][0] : null, colors.length > 3 ? colors[3][1] : null, colors.length > 3 ? colors[3][2] : null);
  uniforms.u_color5.value.set(colors.length > 4 ? colors[4][0] : null, colors.length > 4 ? colors[4][1] : null, colors.length > 4 ? colors[4][2] : null);
  uniforms.u_color6.value.set(colors.length > 5 ? colors[5][0] : null, colors.length > 5 ? colors[5][1] : null, colors.length > 5 ? colors[5][2] : null);
}
function create3DRendering(volumes, channelTargetC, channelsVisible, colors, textures, contrastLimits, volumeMinMax, scaleOrUndefined, renderstyle, layerTransparency, xSlice, ySlice, zSlice, originalScale) {
  const texturesList = [];
  const colorsSave = [];
  const contrastLimitsList = [];
  let volume = null;
  let scale = scaleOrUndefined;
  if (scale === void 0 || scale === null || !Array.isArray(scale) || scale.length < 3) {
    scale = [
      { size: scale?.[0]?.size ?? 1 },
      { size: scale?.[1]?.size ?? 1 },
      { size: scale?.[2]?.size ?? 1 }
    ];
  } else {
    for (let i = 0; i < scale.length; i++) {
      if (!scale[i] || scale[i].size === void 0 || scale[i].size === null) {
        scale[i] = { size: 1 };
      }
    }
  }
  channelTargetC.forEach((channel, id) => {
    if (channelsVisible[id]) {
      volume = volumes.get(channel);
      texturesList.push(textures.get(channel));
      colorsSave.push([colors[id][0] / 255, colors[id][1] / 255, colors[id][2] / 255]);
      if (contrastLimits[id][0] === 0 && contrastLimits[id][1] === 255) {
        contrastLimitsList.push([
          getMinMaxValue(volumeMinMax.get(channel)[0], volumeMinMax.get(channel)),
          getMinMaxValue(volumeMinMax.get(channel)[1], volumeMinMax.get(channel))
        ]);
      } else {
        contrastLimitsList.push([
          getMinMaxValue(contrastLimits[id][0], volumeMinMax.get(channel)),
          getMinMaxValue(contrastLimits[id][1], volumeMinMax.get(channel))
        ]);
      }
    }
  });
  if (volume === null) {
    return null;
  }
  const vol = volume;
  const volconfig = {};
  const shader = VolumeRenderShaderPerspective;
  const uniforms = UniformsUtils.clone(shader.uniforms);
  setUniformsTextures(uniforms, texturesList, vol, volconfig, renderstyle, contrastLimitsList, colorsSave, layerTransparency, xSlice, ySlice, zSlice, [scale[0].size, scale[1].size, scale[2] ? scale[2].size : 1], originalScale);
  return [
    uniforms,
    shader,
    [1, scale[1].size / scale[0].size, scale[2] ? scale[2].size / scale[0].size : 1],
    [vol.xLength, vol.yLength, vol.zLength],
    [1, vol.yLength / vol.xLength, vol.zLength / vol.xLength]
  ];
}
const dtypeToTypedArray = {
  Uint8: Uint8Array,
  Uint16: Uint16Array,
  Uint32: Uint32Array,
  Int8: Int8Array,
  Int16: Int16Array,
  Int32: Int32Array,
  Float32: Float32Array,
  Float64: Float64Array
};
async function getVolumeIntern({
  source,
  selection,
  // eslint-disable-next-line @typescript-eslint/no-empty-function
  onUpdate = () => {
  },
  downsampleDepth = 1,
  signal
}) {
  const { shape, labels, dtype } = source;
  const { height, width } = getImageSize(source);
  const depth = shape[labels.indexOf("z")];
  const depthDownsampled = Math.max(1, Math.floor(depth / downsampleDepth));
  const rasterSize = height * width;
  const TypedArrayClass = dtypeToTypedArray[dtype];
  const volumeData = new TypedArrayClass(rasterSize * depthDownsampled);
  await Promise.all(new Array(depthDownsampled).fill(0).map(async (_, z) => {
    const depthSelection = {
      ...selection,
      z: z * downsampleDepth
    };
    const { data: rasterData } = await source.getRaster({
      selection: depthSelection,
      signal
    });
    let r = 0;
    onUpdate({ z, total: depthDownsampled, progress: 0.5 });
    while (r < rasterSize) {
      const volIndex = z * rasterSize + (rasterSize - r - 1);
      const rasterIndex = (width - r - 1) % width + width * Math.floor(r / width);
      volumeData[volIndex] = rasterData[rasterIndex];
      r += 1;
    }
    onUpdate({ z, total: depthDownsampled, progress: 1 });
  }));
  return {
    data: volumeData,
    height,
    width,
    depth: depthDownsampled
  };
}
function getVolumeByChannel(channel, resolution, loader) {
  return getVolumeIntern({
    source: loader[resolution],
    selection: { t: 0, c: channel },
    // corresponds to the first channel of the first timepoint
    downsampleDepth: 2 ** resolution
  });
}
function getVolumeFromOrigin(volumeOrigin) {
  const volume = new Volume();
  volume.xLength = volumeOrigin.width;
  volume.yLength = volumeOrigin.height;
  volume.zLength = volumeOrigin.depth;
  volume.data = volumeOrigin.data;
  return volume;
}
function getData3DTexture(volume) {
  const texture = new Data3DTexture(volume.data, volume.xLength, volume.yLength, volume.zLength);
  texture.format = RedFormat;
  texture.type = FloatType;
  texture.generateMipmaps = false;
  texture.minFilter = LinearFilter;
  texture.magFilter = LinearFilter;
  texture.needsUpdate = true;
  return texture;
}
function getPhysicalSizeScalingMatrix(loader) {
  const { x, y, z } = loader?.meta?.physicalSizes ?? {};
  return [
    x ?? { size: 1 },
    y ?? { size: 1 },
    z ?? { size: 1 }
  ];
}
function minMaxVolume(volume) {
  const [min, max] = volume.computeMinMax();
  const dataASFloat32 = new Float32Array(volume.data.length);
  for (let i = 0; i < volume.data.length; i++) {
    dataASFloat32[i] = (volume.data[i] - min) / Math.sqrt(max ** 2 - min ** 2);
  }
  return dataASFloat32;
}
async function initialDataLoading(channelTargetC, resolution, data, volumes, textures, volumeMinMax, oldResolution) {
  let volume = null;
  let scale = null;
  const { shape, labels } = data[0];
  const channelsToLoad = channelTargetC.filter((channel) => !volumes.has(channel) || resolution !== oldResolution);
  const volumeOrigins = await Promise.all(channelsToLoad.map((channel) => getVolumeByChannel(channel, resolution, data)));
  channelsToLoad.forEach((channel, channelIndex) => {
    const volumeOrigin = volumeOrigins[channelIndex];
    volume = getVolumeFromOrigin(volumeOrigin);
    const minMax = volume.computeMinMax();
    volume.data = minMaxVolume(volume);
    volumes.set(channel, volume);
    textures.set(channel, getData3DTexture(volume));
    volumeMinMax.set(channel, minMax);
    scale = getPhysicalSizeScalingMatrix(data[resolution]);
  });
  return [
    volumes,
    textures,
    volumeMinMax,
    scale,
    [shape[labels.indexOf("x")], shape[labels.indexOf("y")], shape[labels.indexOf("z")]]
  ];
}
function stringifyLineData(lineData) {
  return `${lineData.startPoint.x},${lineData.startPoint.y},${lineData.startPoint.z};${lineData.endPoint.x},${lineData.endPoint.y},${lineData.endPoint.z}`;
}
function isValidGeometrySize(size) {
  if (!Array.isArray(size) || size.length !== 3) {
    return false;
  }
  return size.every((s) => typeof s === "number" && Number.isFinite(s));
}
function GeometryAndMesh(props) {
  const { segmentationGroup, segmentationSettings, segmentationSceneScale, renderingSettings, materialRef, highlightEntity, setObsHighlight } = props;
  const model = useRef(null);
  const [lines] = useState([]);
  return jsxs("group", { children: [jsxs("group", { children: [segmentationGroup?.visible ? jsxs("group", { children: [jsx("hemisphereLight", { color: 8421504, groundColor: 6316128 }), jsx("directionalLight", { color: 16777215, position: [0, -800, 0] }), jsx("directionalLight", { color: 16777215, position: [0, 800, 0] }), jsx(Bvh, { firstHitOnly: true, children: jsx("primitive", { ref: model, object: segmentationGroup, position: [0, 0, 0], onClick: (e) => {
    if (e.object.parent?.userData.name === "finalPass") {
      highlightEntity(e.object.name, e.object.userData.layerScope, e.object.userData.channelScope);
    }
  }, onPointerOver: (e) => {
    setObsHighlight(e.object.name);
  }, onPointerOut: () => setObsHighlight(null) }) })] }) : null, renderingSettings.uniforms && renderingSettings.shader && renderingSettings.meshScale && renderingSettings.geometrySize ? jsx("group", { children: jsxs("mesh", { scale: renderingSettings.meshScale, ref: materialRef, children: [jsx("boxGeometry", { args: renderingSettings.geometrySize }), jsx("shaderMaterial", { customProgramCacheKey: () => "1", side: FrontSide, uniforms: renderingSettings.uniforms, needsUpdate: true, transparent: true, vertexShader: renderingSettings.shader.vertexShader, fragmentShader: renderingSettings.shader.fragmentShader })] }) }) : null] }), jsx("group", { name: "lines", children: lines.map((object) => jsx(MeasureLine, { currentLine: object, scale: 1 }, stringifyLineData(object))) })] });
}
const LazyGeometryAndMeshXR = React__default.lazy(() => import("./GeometryAndMeshXR-arbhswbx.js").catch(() => ({ default: GeometryAndMesh })));
const LazyXRSceneComponents = React__default.lazy(() => import("./XRSceneComponents-DnZLSAJz.js").catch(() => ({ default: () => null })));
function SpatialThree(props) {
  const materialRef = useRef(null);
  const orbitRef = useRef(null);
  const [initialStartup, setInitialStartup] = useState(false);
  const [dataReady, setDataReady] = useState(false);
  const [segmentationGroup, setSegmentationGroup] = useState(null);
  const [segmentationSceneScale, setSegmentationSceneScale] = useState([1, 1, 1]);
  const [renderingSettings, setRenderingSettings] = useState({
    uniforms: null,
    shader: null,
    meshScale: null,
    geometrySize: null,
    boxSize: null
  });
  const [volumeData, setVolumeData] = useState({
    volumes: /* @__PURE__ */ new Map(),
    textures: /* @__PURE__ */ new Map(),
    volumeMinMax: /* @__PURE__ */ new Map(),
    scale: null,
    resolution: null,
    originalScale: null
  });
  const [volumeSettings, setVolumeSettings] = useState({
    channelsVisible: [],
    allChannels: [],
    channelTargetC: [],
    resolution: null,
    data: null,
    colors: [],
    contrastLimits: [],
    is3dMode: false,
    renderingMode: null,
    layerTransparency: 1
  });
  const [segmentationSettings, setSegmentationSettings] = useState({
    visible: true,
    color: [1, 1, 1],
    opacity: 1,
    multiVisible: "",
    multiOpacity: "",
    multiColor: "",
    data: null,
    obsSets: []
  });
  const { images, layerScope, channelsVisible, allChannels, channelTargetC, resolution, data, colors, contrastLimits, is3dMode, renderingMode, layerTransparency, xSlice, ySlice, zSlice } = useVolumeSettings(props, volumeSettings, setVolumeSettings, dataReady, setDataReady);
  const { obsSegmentations, onEntitySelected, segmentationLayerCoordination, segmentationChannelCoordination, segmentationChannelScopesByLayer } = props;
  let setObsHighlightFct = () => {
  };
  const setsSave = [];
  if (segmentationChannelCoordination[0][layerScope] !== void 0) {
    const segmentationObsSetLayerProps = segmentationChannelCoordination[0][layerScope][layerScope];
    const setters = segmentationChannelCoordination[1][layerScope][layerScope];
    setObsHighlightFct = setters.setObsHighlight;
    const { additionalObsSets: sets } = segmentationObsSetLayerProps;
    if (sets !== null) {
      segmentationObsSetLayerProps.obsSetSelection.forEach((obsSetPath) => {
        const selectedElement = obsSetPath[1];
        sets.tree[0].children.forEach((child) => {
          if (child.name === selectedElement) {
            child.set.forEach(([obsId]) => {
              const info = { name: "", id: "", color: [255, 255, 255] };
              info.name = selectedElement;
              info.id = obsId;
              segmentationObsSetLayerProps.obsSetColor.forEach((color) => {
                if (color.path[1] === selectedElement) {
                  info.color = color.color;
                }
              });
              setsSave.push(info);
            });
          }
        });
      });
    }
    if (segmentationObsSetLayerProps.obsHighlight !== null) {
      setsSave.push({ name: "", id: segmentationObsSetLayerProps.obsHighlight, color: [255, 34, 0] });
    }
  }
  if (obsSegmentations?.[layerScope]?.obsSegmentations && segmentationGroup == null) {
    const { scene, sceneOptions } = obsSegmentations[layerScope].obsSegmentations;
    if (scene?.children) {
      const newScene = new Scene();
      const finalPass = new Group();
      finalPass.userData.name = "finalPass";
      scene.children.forEach((sceneChild) => {
        const childElement = "material" in sceneChild ? sceneChild : sceneChild.children[0];
        if (childElement.material instanceof MeshPhysicalMaterial || childElement.material instanceof MeshBasicMaterial) {
          childElement.material = new MeshStandardMaterial();
        }
        const mat = childElement.material;
        let name = childElement.name.replace("mesh_", "").replace("mesh", "").replace("glb", "").replace("_dec", "").replace("_Decobj", "").replace("obj", "").replace("_DEc", "").replace(".", "").replace("_Dec", "");
        if (name.includes("_")) {
          name = name.split("_")[0];
        }
        childElement.name = name;
        childElement.userData.name = name;
        childElement.userData.layerScope = layerScope;
        mat.transparent = true;
        mat.depthTest = true;
        mat.depthWrite = true;
        mat.needsUpdate = true;
        mat.side = sceneOptions?.materialSide === "back" ? BackSide : FrontSide;
        const simplified = childElement.clone();
        simplified.geometry = childElement.geometry.clone();
        simplified.geometry.translate(sceneOptions?.targetX ?? 0, sceneOptions?.targetY ?? 0, sceneOptions?.targetZ ?? 0);
        simplified.geometry.scale(sceneOptions?.scaleX ?? 1, sceneOptions?.scaleY ?? 1, sceneOptions?.scaleZ ?? 1);
        simplified.geometry.rotateX(sceneOptions?.rotationX ?? 0);
        simplified.geometry.rotateY(sceneOptions?.rotationY ?? 0);
        simplified.geometry.rotateZ(sceneOptions?.rotationZ ?? 0);
        const finalPassChild = childElement.clone();
        finalPassChild.material = mat.clone();
        finalPassChild.geometry = simplified.geometry.clone();
        finalPass.add(finalPassChild);
      });
      newScene.add(finalPass);
      newScene.scale.set(sceneOptions?.sceneScaleX ?? 1, sceneOptions?.sceneScaleY ?? 1, sceneOptions?.sceneScaleZ ?? 1);
      const sceneScale = [
        sceneOptions?.sceneScaleX ?? 1,
        sceneOptions?.sceneScaleY ?? 1,
        sceneOptions?.sceneScaleZ ?? 1
      ];
      setSegmentationSceneScale(sceneScale);
      newScene.rotateX(sceneOptions?.sceneRotationX ?? 0);
      newScene.rotateY(sceneOptions?.sceneRotationY ?? 0);
      newScene.rotateZ(sceneOptions?.sceneRotationZ ?? 0);
      setSegmentationGroup(newScene);
    }
  }
  if (segmentationChannelCoordination[0] !== void 0 && segmentationChannelCoordination[0][layerScope] !== void 0) {
    const segmentationLayerProps = segmentationChannelCoordination[0][layerScope][layerScope];
    let setsSaveString = "";
    setsSave.forEach((child) => {
      setsSaveString += `${child.id};${child.color.toString()};${child.name}`;
    });
    let settingsSaveString = "";
    segmentationSettings.obsSets.forEach((child) => {
      settingsSaveString += `${child.id};${child.color.toString()};${child.name}`;
    });
    if (segmentationChannelScopesByLayer[layerScope].length > 1) {
      let color = "";
      let opacity = "";
      let visible = "";
      let visibleCombined = false;
      let opacityCombined = 0;
      segmentationChannelScopesByLayer[layerScope].forEach((channelScope) => {
        const channelSet = segmentationChannelCoordination[0][layerScope][channelScope];
        color += `${channelSet.spatialChannelColor.toString()};`;
        opacity += `${channelSet.spatialChannelOpacity};`;
        visible += `${channelSet.spatialChannelVisible};`;
        visibleCombined = visibleCombined || channelSet.spatialChannelVisible;
        opacityCombined += channelSet.spatialChannelOpacity;
      });
      if (color !== segmentationSettings.multiColor || opacity !== segmentationSettings.multiOpacity || visible !== segmentationSettings.multiVisible) {
        setSegmentationSettings({
          color: segmentationLayerProps.spatialChannelColor,
          opacity: opacityCombined,
          visible: visibleCombined,
          multiColor: color,
          multiVisible: visible,
          multiOpacity: opacity,
          data: obsSegmentations ?? null,
          obsSets: setsSave
        });
      }
    } else if (segmentationLayerProps.spatialChannelColor.toString() !== segmentationSettings.color.toString() || segmentationLayerProps.spatialChannelVisible !== segmentationSettings.visible || segmentationLayerProps.spatialChannelOpacity !== segmentationSettings.opacity || setsSaveString !== settingsSaveString) {
      setSegmentationSettings({
        color: segmentationLayerProps.spatialChannelColor,
        opacity: segmentationLayerProps.spatialChannelOpacity,
        visible: segmentationLayerProps.spatialChannelVisible,
        multiColor: "",
        multiVisible: "",
        multiOpacity: "",
        data: obsSegmentations ?? null,
        obsSets: setsSave
      });
    }
  }
  useEffect(() => {
    if (segmentationGroup !== null) {
      let firstGroupIndex = 0;
      let finalGroupIndex = 0;
      for (let i = 0; i < segmentationGroup.children.length; i++) {
        if (segmentationGroup.children[i].userData.name === "finalPass") {
          finalGroupIndex = i;
        } else {
          firstGroupIndex = i;
        }
      }
      segmentationGroup.children[finalGroupIndex].children.forEach((sceneChild, childIndex) => {
        const child = sceneChild;
        let { color } = segmentationSettings;
        const id = child.userData.name;
        segmentationSettings.obsSets.forEach((obsSet) => {
          if (obsSet.id === id) {
            color = obsSet.color;
          }
        });
        if (segmentationChannelScopesByLayer[layerScope].length > 1) {
          segmentationChannelScopesByLayer[layerScope].forEach((channelScope) => {
            const channelSet = segmentationChannelCoordination[0][layerScope][channelScope];
            if (channelSet.spatialTargetC === id) {
              child.material.color.r = channelSet.spatialChannelColor[0] / 255;
              child.material.color.g = channelSet.spatialChannelColor[1] / 255;
              child.material.color.b = channelSet.spatialChannelColor[2] / 255;
              child.material.opacity = channelSet.spatialChannelOpacity;
              child.visible = channelSet.spatialChannelVisible;
              child.material.needsUpdate = true;
              child.userData.layerScope = layerScope;
              child.userData.channelScope = channelScope;
              const firstChild = segmentationGroup.children[firstGroupIndex].children[childIndex];
              firstChild.material.needsUpdate = true;
            }
          });
        } else {
          child.material.color.r = color[0] / 255;
          child.material.color.g = color[1] / 255;
          child.material.color.b = color[2] / 255;
          child.material.opacity = segmentationSettings.opacity;
          child.material.visible = segmentationSettings.visible;
          child.material.needsUpdate = true;
          child.userData.layerScope = layerScope;
          const firstChannelScope = Object.keys(segmentationChannelCoordination[0][layerScope])?.[0];
          child.userData.channelScope = firstChannelScope;
        }
      });
    }
  }, [segmentationSettings, segmentationGroup]);
  const dataToCheck = images[layerScope]?.image?.instance?.getData();
  if (dataToCheck !== void 0 && !dataReady && !initialStartup && contrastLimits !== null && contrastLimits[0][1] !== 255 && is3dMode) {
    setDataReady(true);
    setInitialStartup(true);
  }
  useEffect(() => {
    const fetchRendering = async () => {
      const loadingResult = await initialDataLoading(channelTargetC, resolution, data, volumeData.volumes, volumeData.textures, volumeData.volumeMinMax, volumeData.resolution);
      if (loadingResult[0] !== null) {
        setVolumeData({
          resolution,
          volumes: loadingResult[0],
          textures: loadingResult[1],
          volumeMinMax: loadingResult[2],
          scale: loadingResult[3] !== null ? loadingResult[3] : volumeData.scale,
          originalScale: loadingResult[4]
        });
        if (!renderingSettings.uniforms || !renderingSettings.shader) {
          const rendering = create3DRendering(loadingResult[0], channelTargetC, channelsVisible, colors, loadingResult[1], contrastLimits, loadingResult[2], loadingResult[3], renderingMode, layerTransparency, xSlice, ySlice, zSlice, loadingResult[4]);
          if (rendering !== null) {
            setRenderingSettings({
              uniforms: rendering[0],
              shader: rendering[1],
              meshScale: rendering[2],
              geometrySize: rendering[3],
              boxSize: rendering[4]
            });
          }
        } else {
          setVolumeSettings({
            channelsVisible,
            allChannels,
            channelTargetC,
            resolution,
            data,
            colors,
            contrastLimits,
            is3dMode,
            renderingMode,
            layerTransparency,
            xSlice,
            ySlice,
            zSlice
          });
        }
      }
    };
    if (dataReady) {
      if (resolution !== volumeSettings.resolution && materialRef.current) {
        materialRef.current.material.uniforms.volumeCount.value = 0;
        materialRef.current.material.uniforms.volumeTex.value = null;
      }
      fetchRendering();
      setDataReady(false);
    }
  }, [dataReady]);
  useEffect(() => {
    if (renderingSettings.uniforms && renderingSettings.shader) {
      const rendering = create3DRendering(volumeData.volumes, volumeSettings.channelTargetC, volumeSettings.channelsVisible, volumeSettings.colors, volumeData.textures, volumeSettings.contrastLimits, volumeData.volumeMinMax, volumeData.scale, volumeSettings.renderingMode, volumeSettings.layerTransparency, volumeSettings.xSlice, volumeSettings.ySlice, volumeSettings.zSlice, volumeData.originalScale);
      if (rendering !== null) {
        let volumeCount = 0;
        volumeSettings.channelsVisible?.forEach((channelVisible) => {
          if (channelVisible)
            volumeCount++;
        });
        setDataReady(false);
        if (materialRef?.current?.material?.uniforms) {
          materialRef.current.material.uniforms.u_clim.value = rendering[0].u_clim.value;
          materialRef.current.material.uniforms.u_clim2.value = rendering[0].u_clim2.value;
          materialRef.current.material.uniforms.u_clim3.value = rendering[0].u_clim3.value;
          materialRef.current.material.uniforms.u_clim4.value = rendering[0].u_clim4.value;
          materialRef.current.material.uniforms.u_clim5.value = rendering[0].u_clim5.value;
          materialRef.current.material.uniforms.u_clim6.value = rendering[0].u_clim6.value;
          materialRef.current.material.uniforms.u_xClip.value = rendering[0].u_xClip.value;
          materialRef.current.material.uniforms.u_yClip.value = rendering[0].u_yClip.value;
          materialRef.current.material.uniforms.u_zClip.value = rendering[0].u_zClip.value;
          materialRef.current.material.uniforms.u_color.value = rendering[0].u_color.value;
          materialRef.current.material.uniforms.u_color2.value = rendering[0].u_color2.value;
          materialRef.current.material.uniforms.u_color3.value = rendering[0].u_color3.value;
          materialRef.current.material.uniforms.u_color4.value = rendering[0].u_color4.value;
          materialRef.current.material.uniforms.u_color5.value = rendering[0].u_color5.value;
          materialRef.current.material.uniforms.u_color6.value = rendering[0].u_color6.value;
          materialRef.current.material.uniforms.volumeTex.value = rendering[0].volumeTex.value;
          materialRef.current.material.uniforms.volumeTex2.value = rendering[0].volumeTex2.value;
          materialRef.current.material.uniforms.volumeTex3.value = rendering[0].volumeTex3.value;
          materialRef.current.material.uniforms.volumeTex4.value = rendering[0].volumeTex4.value;
          materialRef.current.material.uniforms.volumeTex5.value = rendering[0].volumeTex5.value;
          materialRef.current.material.uniforms.volumeTex6.value = rendering[0].volumeTex6.value;
          materialRef.current.material.uniforms.volumeCount.value = volumeCount;
          materialRef.current.material.uniforms.u_renderstyle.value = volumeSettings.renderingMode;
          materialRef.current.material.uniforms.dtScale.value = volumeSettings.layerTransparency;
        }
      } else if (materialRef?.current?.material?.uniforms) {
        materialRef.current.material.uniforms.volumeCount.value = 0;
        materialRef.current.material.uniforms.volumeTex.value = null;
      }
    }
  }, [volumeSettings]);
  if (!volumeSettings.is3dMode) {
    return null;
  }
  if (volumeSettings.is3dMode && (!renderingSettings.uniforms || !renderingSettings.shader)) {
    return jsxs("group", { children: [jsx("ambientLight", {}), jsx("pointLight", { position: [10, 10, 10] }), jsx(Text, { color: "white", scale: 20, fontWeight: 1e3, children: "Loading ..." })] });
  }
  const geometryAndMeshProps = {
    segmentationGroup,
    segmentationSettings,
    segmentationSceneScale,
    renderingSettings,
    materialRef,
    highlightEntity: onEntitySelected,
    setObsHighlight: setObsHighlightFct
  };
  const { xrEnabled } = props;
  return jsxs("group", { children: [xrEnabled ? jsxs(Fragment, { children: [jsx(Suspense, { fallback: null, children: jsx(LazyXRSceneComponents, {}) }), jsx(Suspense, { fallback: jsx(GeometryAndMesh, { ...geometryAndMeshProps }), children: jsx(LazyGeometryAndMeshXR, { ...geometryAndMeshProps }) })] }) : jsx(GeometryAndMesh, { ...geometryAndMeshProps }), jsx(OrbitControls, { ref: orbitRef, enableDamping: false, dampingFactor: 0 })] });
}
const LazyXRWrapper = React__default.lazy(
  // eslint-disable-next-line implicit-arrow-linebreak, function-paren-newline
  () => import("./XRWrapper-C94X82Mb.js").catch(() => ({
    default: ({ children }) => children
  }))
);
const LazyXREnterButton = React__default.lazy(
  // eslint-disable-next-line implicit-arrow-linebreak, function-paren-newline
  () => import("./XREnterButton-vmEhdF4L.js").catch(() => ({
    default: () => null
  }))
);
const SpatialWrapper = forwardRef((props, canvasRef) => {
  const [xrAvailable, setXrAvailable] = useState(false);
  useEffect(() => {
    import("@react-three/xr").then(() => setXrAvailable(true)).catch(() => {
    });
  }, []);
  return jsxs("div", { style: { width: "100%", height: "100%" }, children: [xrAvailable && jsx(Suspense, { fallback: null, children: jsx(LazyXREnterButton, {}) }), jsx(Canvas, { style: { position: "absolute", top: 0, left: 0 }, camera: {
    fov: 50,
    up: [0, 1, 0],
    position: [0, 0, 800],
    near: 0.1,
    far: 3e3
  }, gl: { antialias: true, logarithmicDepthBuffer: false }, ref: canvasRef, children: xrAvailable ? jsx(Suspense, { fallback: jsx(SpatialThree, { ...props }), children: jsx(LazyXRWrapper, { children: jsx(SpatialThree, { ...props, xrEnabled: true }) }) }) : jsx(SpatialThree, { ...props }) })] });
});
const index = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
  __proto__: null,
  SpatialWrapper
}, Symbol.toStringTag, { value: "Module" }));
export {
  MeasureLine as M,
  index as a,
  isValidGeometrySize as i,
  stringifyLineData as s
};
