text: /**
   * Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
   *
   * @author Alexander Rose <alexander.rose@weirdbyte.de>
   */
  import { Grid } from './grid';
  import { OrderedSet } from '../../mol-data/int';
  import { Sphere3D } from '../../mol-math/geometry';
  import { Vec3, Mat4 } from '../../mol-math/linear-algebra';
  import { BoundaryHelper } from '../../mol-math/geometry/boundary-helper';
  import { CubeFormat } from '../../mol-model-formats/volume/cube';
  import { equalEps } from '../../mol-math/linear-algebra/3d/common';
  import { CustomProperties } from '../custom-property';
  import { ParamDefinition as PD } from '../../mol-util/param-definition';
  import { toPrecision } from '../../mol-util/number';
  import { DscifFormat } from '../../mol-model-formats/volume/density-server';
  export var Volume;
  (function (Volume) {
      function is(x) {
          var _a, _b, _c, _d;
          // TODO: improve
          return (((_d = (_c = (_b = (_a = x === null || x === void 0 ? void 0 : x.grid) === null || _a === void 0 ? void 0 : _a.cells) === null || _b === void 0 ? void 0 : _b.space) === null || _c === void 0 ? void 0 : _c.dimensions) === null || _d === void 0 ? void 0 : _d.length) &&
              (x === null || x === void 0 ? void 0 : x.sourceData) &&
              (x === null || x === void 0 ? void 0 : x.customProperties) &&
              (x === null || x === void 0 ? void 0 : x._propertyData));
      }
      Volume.is = is;
      var IsoValue;
      (function (IsoValue) {
          function areSame(a, b, stats) {
              return equalEps(toAbsolute(a, stats).absoluteValue, toAbsolute(b, stats).absoluteValue, stats.sigma / 100);
          }
          IsoValue.areSame = areSame;
          function absolute(value) { return { kind: 'absolute', absoluteValue: value }; }
          IsoValue.absolute = absolute;
          function relative(value) { return { kind: 'relative', relativeValue: value }; }
          IsoValue.relative = relative;
          function calcAbsolute(stats, relativeValue) {
              return relativeValue * stats.sigma + stats.mean;
          }
          IsoValue.calcAbsolute = calcAbsolute;
          function calcRelative(stats, absoluteValue) {
              return stats.sigma === 0 ? 0 : ((absoluteValue - stats.mean) / stats.sigma);
          }
          IsoValue.calcRelative = calcRelative;
          function toAbsolute(value, stats) {
              return value.kind === 'absolute' ? value : { kind: 'absolute', absoluteValue: IsoValue.calcAbsolute(stats, value.relativeValue) };
          }
          IsoValue.toAbsolute = toAbsolute;
          function toRelative(value, stats) {
              return value.kind === 'relative' ? value : { kind: 'relative', relativeValue: IsoValue.calcRelative(stats, value.absoluteValue) };
          }
          IsoValue.toRelative = toRelative;
          function toString(value) {
              return value.kind === 'relative'
                  ? "".concat(value.relativeValue.toFixed(2), " \u03C3")
                  : "".concat(value.absoluteValue.toPrecision(4));
          }
          IsoValue.toString = toString;
      })(IsoValue = Volume.IsoValue || (Volume.IsoValue = {}));
      // Converts iso value to relative if using downsample VolumeServer data
      function adjustedIsoValue(volume, value, kind) {
          if (kind === 'relative')
              return IsoValue.relative(value);
          var absolute = IsoValue.absolute(value);
          if (DscifFormat.is(volume.sourceData)) {
              var stats = {
                  min: volume.sourceData.data.volume_data_3d_info.min_source.value(0),
                  max: volume.sourceData.data.volume_data_3d_info.max_source.value(0),
                  mean: volume.sourceData.data.volume_data_3d_info.mean_source.value(0),
                  sigma: volume.sourceData.data.volume_data_3d_info.sigma_source.value(0),
              };
              return Volume.IsoValue.toRelative(absolute, stats);
          }
          return absolute;
      }
      Volume.adjustedIsoValue = adjustedIsoValue;
      var defaultStats = { min: -1, max: 1, mean: 0, sigma: 0.1 };
      function createIsoValueParam(defaultValue, stats) {
          var sts = stats || defaultStats;
          var min = sts.min, max = sts.max, mean = sts.mean, sigma = sts.sigma;
          // using ceil/floor could lead to "ouf of bounds" when converting
          var relMin = (min - mean) / sigma;
          var relMax = (max - mean) / sigma;
          var def = defaultValue;
          if (defaultValue.kind === 'absolute') {
              if (defaultValue.absoluteValue < min)
                  def = Volume.IsoValue.absolute(min);
              else if (defaultValue.absoluteValue > max)
                  def = Volume.IsoValue.absolute(max);
          }
          else {
              if (defaultValue.relativeValue < relMin)
                  def = Volume.IsoValue.relative(relMin);
              else if (defaultValue.relativeValue > relMax)
                  def = Volume.IsoValue.relative(relMax);
          }
          return PD.Conditioned(def, {
              'absolute': PD.Converted(function (v) { return Volume.IsoValue.toAbsolute(v, Grid.One.stats).absoluteValue; }, function (v) { return Volume.IsoValue.absolute(v); }, PD.Numeric(mean, { min: min, max: max, step: toPrecision(sigma / 100, 2) })),
              'relative': PD.Converted(function (v) { return Volume.IsoValue.toRelative(v, Grid.One.stats).relativeValue; }, function (v) { return Volume.IsoValue.relative(v); }, PD.Numeric(Math.min(1, relMax), { min: relMin, max: relMax, step: toPrecision(Math.round(((max - min) / sigma)) / 100, 2) }))
          }, function (v) { return v.kind === 'absolute' ? 'absolute' : 'relative'; }, function (v, c) { return c === 'absolute' ? Volume.IsoValue.toAbsolute(v, sts) : Volume.IsoValue.toRelative(v, sts); }, { isEssential: true });
      }
      Volume.createIsoValueParam = createIsoValueParam;
      Volume.IsoValueParam = createIsoValueParam(Volume.IsoValue.relative(2));
      Volume.One = {
          label: '',
          grid: Grid.One,
          sourceData: { kind: '', name: '', data: {} },
          customProperties: new CustomProperties(),
          _propertyData: Object.create(null),
      };
      function areEquivalent(volA, volB) {
          return Grid.areEquivalent(volA.grid, volB.grid);
      }
      Volume.areEquivalent = areEquivalent;
      function isEmpty(vol) {
          return Grid.isEmpty(vol.grid);
      }
      Volume.isEmpty = isEmpty;
      function isOrbitals(volume) {
          if (!CubeFormat.is(volume.sourceData))
              return false;
          return volume.sourceData.data.header.orbitals;
      }
      Volume.isOrbitals = isOrbitals;
      function Loci(volume) { return { kind: 'volume-loci', volume: volume }; }
      Volume.Loci = Loci;
      function isLoci(x) { return !!x && x.kind === 'volume-loci'; }
      Volume.isLoci = isLoci;
      function areLociEqual(a, b) { return a.volume === b.volume; }
      Volume.areLociEqual = areLociEqual;
      function isLociEmpty(loci) { return Grid.isEmpty(loci.volume.grid); }
      Volume.isLociEmpty = isLociEmpty;
      function getBoundingSphere(volume, boundingSphere) {
          return Grid.getBoundingSphere(volume.grid, boundingSphere);
      }
      Volume.getBoundingSphere = getBoundingSphere;
      var Isosurface;
      (function (Isosurface) {
          function Loci(volume, isoValue) { return { kind: 'isosurface-loci', volume: volume, isoValue: isoValue }; }
          Isosurface.Loci = Loci;
          function isLoci(x) { return !!x && x.kind === 'isosurface-loci'; }
          Isosurface.isLoci = isLoci;
          function areLociEqual(a, b) { return a.volume === b.volume && Volume.IsoValue.areSame(a.isoValue, b.isoValue, a.volume.grid.stats); }
          Isosurface.areLociEqual = areLociEqual;
          function isLociEmpty(loci) { return loci.volume.grid.cells.data.length === 0; }
          Isosurface.isLociEmpty = isLociEmpty;
          function getBoundingSphere(volume, isoValue, boundingSphere) {
              // TODO get bounding sphere for subgrid with values >= isoValue
              return Volume.getBoundingSphere(volume, boundingSphere);
          }
          Isosurface.getBoundingSphere = getBoundingSphere;
      })(Isosurface = Volume.Isosurface || (Volume.Isosurface = {}));
      var Cell;
      (function (Cell) {
          function Loci(volume, indices) { return { kind: 'cell-loci', volume: volume, indices: indices }; }
          Cell.Loci = Loci;
          function isLoci(x) { return !!x && x.kind === 'cell-loci'; }
          Cell.isLoci = isLoci;
          function areLociEqual(a, b) { return a.volume === b.volume && OrderedSet.areEqual(a.indices, b.indices); }
          Cell.areLociEqual = areLociEqual;
          function isLociEmpty(loci) { return OrderedSet.size(loci.indices) === 0; }
          Cell.isLociEmpty = isLociEmpty;
          var boundaryHelper = new BoundaryHelper('98');
          var tmpBoundaryPos = Vec3();
          function getBoundingSphere(volume, indices, boundingSphere) {
              boundaryHelper.reset();
              var transform = Grid.getGridToCartesianTransform(volume.grid);
              var getCoords = volume.grid.cells.space.getCoords;
              for (var i = 0, _i = OrderedSet.size(indices); i < _i; i++) {
                  var o = OrderedSet.getAt(indices, i);
                  getCoords(o, tmpBoundaryPos);
                  Vec3.transformMat4(tmpBoundaryPos, tmpBoundaryPos, transform);
                  boundaryHelper.includePosition(tmpBoundaryPos);
              }
              boundaryHelper.finishedIncludeStep();
              for (var i = 0, _i = OrderedSet.size(indices); i < _i; i++) {
                  var o = OrderedSet.getAt(indices, i);
                  getCoords(o, tmpBoundaryPos);
                  Vec3.transformMat4(tmpBoundaryPos, tmpBoundaryPos, transform);
                  boundaryHelper.radiusPosition(tmpBoundaryPos);
              }
              var bs = boundaryHelper.getSphere(boundingSphere);
              return Sphere3D.expand(bs, bs, Mat4.getMaxScaleOnAxis(transform) * 10);
          }
          Cell.getBoundingSphere = getBoundingSphere;
      })(Cell = Volume.Cell || (Volume.Cell = {}));
  })(Volume || (Volume = {}));
  //# sourceMappingURL=volume.js.map