text: "use strict";
  /**
   * Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
   *
   * @author Alexander Rose <alexander.rose@weirdbyte.de>
   * @author David Sehnal <david.sehnal@gmail.com>
   */
  Object.defineProperty(exports, "__esModule", { value: true });
  exports.IntraUnitBondCylinderMeshVisual = exports.IntraUnitBondCylinderImpostorVisual = exports.IntraUnitBondCylinderVisual = exports.IntraUnitBondCylinderParams = void 0;
  var tslib_1 = require("tslib");
  var param_definition_1 = require("../../../mol-util/param-definition");
  var structure_1 = require("../../../mol-model/structure");
  var mesh_1 = require("../../../mol-geo/geometry/mesh/mesh");
  var linear_algebra_1 = require("../../../mol-math/linear-algebra");
  var mol_util_1 = require("../../../mol-util");
  var link_1 = require("./util/link");
  var units_visual_1 = require("../units-visual");
  var types_1 = require("../../../mol-model/structure/model/types");
  var bond_1 = require("./util/bond");
  var geometry_1 = require("../../../mol-math/geometry");
  var graph_1 = require("../../../mol-math/graph");
  var cylinders_1 = require("../../../mol-geo/geometry/cylinders/cylinders");
  var int_1 = require("../../../mol-data/int");
  var array_1 = require("../../../mol-util/array");
  // avoiding namespace lookup improved performance in Chrome (Aug 2020)
  var isBondType = types_1.BondType.is;
  function getIntraUnitBondCylinderBuilderProps(unit, structure, theme, props) {
      var elements = unit.elements;
      var bonds = unit.bonds;
      var edgeCount = bonds.edgeCount, a = bonds.a, b = bonds.b, edgeProps = bonds.edgeProps, offset = bonds.offset;
      var _order = edgeProps.order, _flags = edgeProps.flags;
      var sizeFactor = props.sizeFactor, sizeAspectRatio = props.sizeAspectRatio, adjustCylinderLength = props.adjustCylinderLength, aromaticBonds = props.aromaticBonds, includeTypes = props.includeTypes, excludeTypes = props.excludeTypes, multipleBonds = props.multipleBonds;
      var mbOff = multipleBonds === 'off';
      var mbSymmetric = multipleBonds === 'symmetric';
      var include = types_1.BondType.fromNames(includeTypes);
      var exclude = types_1.BondType.fromNames(excludeTypes);
      var ignoreComputedAromatic = (0, bond_1.ignoreBondType)(include, exclude, 32 /* Computed */);
      var vRef = (0, linear_algebra_1.Vec3)(), delta = (0, linear_algebra_1.Vec3)();
      var pos = unit.conformation.invariantPosition;
      var stub;
      var locE = structure_1.StructureElement.Location.create(structure, unit);
      var locB = structure_1.Bond.Location(structure, unit, undefined, structure, unit, undefined);
      var child = structure.child;
      if (props.includeParent && child) {
          var childUnit_1 = child.unitMap.get(unit.id);
          if (!childUnit_1)
              throw new Error('expected childUnit to exist');
          stub = function (edgeIndex) {
              var eA = elements[a[edgeIndex]];
              var eB = elements[b[edgeIndex]];
              return int_1.SortedArray.has(childUnit_1.elements, eA) && !int_1.SortedArray.has(childUnit_1.elements, eB);
          };
      }
      var radius = function (edgeIndex) {
          locB.aIndex = a[edgeIndex];
          locB.bIndex = b[edgeIndex];
          return theme.size.size(locB) * sizeFactor;
      };
      var radiusA = function (edgeIndex) {
          locE.element = elements[a[edgeIndex]];
          return theme.size.size(locE) * sizeFactor;
      };
      var radiusB = function (edgeIndex) {
          locE.element = elements[b[edgeIndex]];
          return theme.size.size(locE) * sizeFactor;
      };
      var _a = unit.rings, elementRingIndices = _a.elementRingIndices, elementAromaticRingIndices = _a.elementAromaticRingIndices;
      return {
          linkCount: edgeCount * 2,
          referencePosition: function (edgeIndex) {
              var _a, _b;
              var aI = a[edgeIndex], bI = b[edgeIndex];
              if (aI > bI)
                  _a = [bI, aI], aI = _a[0], bI = _a[1];
              if (offset[aI + 1] - offset[aI] === 1)
                  _b = [bI, aI], aI = _b[0], bI = _b[1];
              var aR = elementRingIndices.get(aI);
              var maxSize = 0;
              for (var i = offset[aI], il = offset[aI + 1]; i < il; ++i) {
                  var _bI = b[i];
                  if (_bI !== bI && _bI !== aI) {
                      if (aR) {
                          var _bR = elementRingIndices.get(_bI);
                          if (!_bR)
                              continue;
                          var size = (0, array_1.arrayIntersectionSize)(aR, _bR);
                          if (size > maxSize) {
                              maxSize = size;
                              pos(elements[_bI], vRef);
                          }
                      }
                      else {
                          return pos(elements[_bI], vRef);
                      }
                  }
              }
              return maxSize > 0 ? vRef : null;
          },
          position: function (posA, posB, edgeIndex) {
              pos(elements[a[edgeIndex]], posA);
              pos(elements[b[edgeIndex]], posB);
              if (adjustCylinderLength) {
                  var rA = radiusA(edgeIndex), rB = radiusB(edgeIndex);
                  var r = Math.min(rA, rB) * sizeAspectRatio;
                  var oA = Math.sqrt(Math.max(0, rA * rA - r * r)) - 0.05;
                  var oB = Math.sqrt(Math.max(0, rB * rB - r * r)) - 0.05;
                  if (oA <= 0.01 && oB <= 0.01)
                      return;
                  linear_algebra_1.Vec3.normalize(delta, linear_algebra_1.Vec3.sub(delta, posB, posA));
                  linear_algebra_1.Vec3.scaleAndAdd(posA, posA, delta, oA);
                  linear_algebra_1.Vec3.scaleAndAdd(posB, posB, delta, -oB);
              }
          },
          style: function (edgeIndex) {
              var o = _order[edgeIndex];
              var f = _flags[edgeIndex];
              if (isBondType(f, 2 /* MetallicCoordination */) || isBondType(f, 4 /* HydrogenBond */)) {
                  // show metallic coordinations and hydrogen bonds with dashed cylinders
                  return 1 /* Dashed */;
              }
              else if (o === 3) {
                  return mbOff ? 0 /* Solid */ :
                      mbSymmetric ? 4 /* Triple */ :
                          5 /* OffsetTriple */;
              }
              else if (aromaticBonds) {
                  var aI = a[edgeIndex], bI = b[edgeIndex];
                  var aR = elementAromaticRingIndices.get(aI);
                  var bR = elementAromaticRingIndices.get(bI);
                  var arCount = (aR && bR) ? (0, array_1.arrayIntersectionSize)(aR, bR) : 0;
                  if (isBondType(f, 16 /* Aromatic */) || (arCount && !ignoreComputedAromatic)) {
                      if (arCount === 2) {
                          return 8 /* MirroredAromatic */;
                      }
                      else {
                          return 7 /* Aromatic */;
                      }
                  }
              }
              return (o !== 2 || mbOff) ? 0 /* Solid */ :
                  mbSymmetric ? 2 /* Double */ :
                      3 /* OffsetDouble */;
          },
          radius: function (edgeIndex) {
              return radius(edgeIndex) * sizeAspectRatio;
          },
          ignore: (0, bond_1.makeIntraBondIgnoreTest)(structure, unit, props),
          stub: stub
      };
  }
  function createIntraUnitBondCylinderImpostors(ctx, unit, structure, theme, props, cylinders) {
      if (!structure_1.Unit.isAtomic(unit))
          return cylinders_1.Cylinders.createEmpty(cylinders);
      if (!unit.bonds.edgeCount)
          return cylinders_1.Cylinders.createEmpty(cylinders);
      var child = structure.child;
      var childUnit = child === null || child === void 0 ? void 0 : child.unitMap.get(unit.id);
      if (child && !childUnit)
          return cylinders_1.Cylinders.createEmpty(cylinders);
      var builderProps = getIntraUnitBondCylinderBuilderProps(unit, structure, theme, props);
      var c = (0, link_1.createLinkCylinderImpostors)(ctx, builderProps, props, cylinders);
      var sphere = geometry_1.Sphere3D.expand((0, geometry_1.Sphere3D)(), (childUnit !== null && childUnit !== void 0 ? childUnit : unit).boundary.sphere, 1 * props.sizeFactor);
      c.setBoundingSphere(sphere);
      return c;
  }
  function createIntraUnitBondCylinderMesh(ctx, unit, structure, theme, props, mesh) {
      if (!structure_1.Unit.isAtomic(unit))
          return mesh_1.Mesh.createEmpty(mesh);
      if (!unit.bonds.edgeCount)
          return mesh_1.Mesh.createEmpty(mesh);
      var child = structure.child;
      var childUnit = child === null || child === void 0 ? void 0 : child.unitMap.get(unit.id);
      if (child && !childUnit)
          return mesh_1.Mesh.createEmpty(mesh);
      var builderProps = getIntraUnitBondCylinderBuilderProps(unit, structure, theme, props);
      var m = (0, link_1.createLinkCylinderMesh)(ctx, builderProps, props, mesh);
      var sphere = geometry_1.Sphere3D.expand((0, geometry_1.Sphere3D)(), (childUnit !== null && childUnit !== void 0 ? childUnit : unit).boundary.sphere, 1 * props.sizeFactor);
      m.setBoundingSphere(sphere);
      return m;
  }
  exports.IntraUnitBondCylinderParams = (0, tslib_1.__assign)((0, tslib_1.__assign)((0, tslib_1.__assign)((0, tslib_1.__assign)({}, units_visual_1.UnitsMeshParams), units_visual_1.UnitsCylindersParams), bond_1.BondCylinderParams), { sizeFactor: param_definition_1.ParamDefinition.Numeric(0.3, { min: 0, max: 10, step: 0.01 }), sizeAspectRatio: param_definition_1.ParamDefinition.Numeric(2 / 3, { min: 0, max: 3, step: 0.01 }), tryUseImpostor: param_definition_1.ParamDefinition.Boolean(true), includeParent: param_definition_1.ParamDefinition.Boolean(false) });
  function IntraUnitBondCylinderVisual(materialId, structure, props, webgl) {
      return props.tryUseImpostor && webgl && webgl.extensions.fragDepth
          ? IntraUnitBondCylinderImpostorVisual(materialId)
          : IntraUnitBondCylinderMeshVisual(materialId);
  }
  exports.IntraUnitBondCylinderVisual = IntraUnitBondCylinderVisual;
  function IntraUnitBondCylinderImpostorVisual(materialId) {
      return (0, units_visual_1.UnitsCylindersVisual)({
          defaultProps: param_definition_1.ParamDefinition.getDefaultValues(exports.IntraUnitBondCylinderParams),
          createGeometry: createIntraUnitBondCylinderImpostors,
          createLocationIterator: bond_1.BondIterator.fromGroup,
          getLoci: bond_1.getIntraBondLoci,
          eachLocation: bond_1.eachIntraBond,
          setUpdateState: function (state, newProps, currentProps, newTheme, currentTheme, newStructureGroup, currentStructureGroup) {
              state.createGeometry = (newProps.sizeAspectRatio !== currentProps.sizeAspectRatio ||
                  newProps.linkScale !== currentProps.linkScale ||
                  newProps.linkSpacing !== currentProps.linkSpacing ||
                  newProps.ignoreHydrogens !== currentProps.ignoreHydrogens ||
                  newProps.linkCap !== currentProps.linkCap ||
                  newProps.aromaticScale !== currentProps.aromaticScale ||
                  newProps.aromaticSpacing !== currentProps.aromaticSpacing ||
                  newProps.aromaticDashCount !== currentProps.aromaticDashCount ||
                  newProps.dashCount !== currentProps.dashCount ||
                  newProps.dashScale !== currentProps.dashScale ||
                  newProps.dashCap !== currentProps.dashCap ||
                  newProps.stubCap !== currentProps.stubCap ||
                  !(0, mol_util_1.arrayEqual)(newProps.includeTypes, currentProps.includeTypes) ||
                  !(0, mol_util_1.arrayEqual)(newProps.excludeTypes, currentProps.excludeTypes) ||
                  newProps.adjustCylinderLength !== currentProps.adjustCylinderLength ||
                  newProps.aromaticBonds !== currentProps.aromaticBonds ||
                  newProps.multipleBonds !== currentProps.multipleBonds);
              var newUnit = newStructureGroup.group.units[0];
              var currentUnit = currentStructureGroup.group.units[0];
              if (structure_1.Unit.isAtomic(newUnit) && structure_1.Unit.isAtomic(currentUnit)) {
                  if (!graph_1.IntAdjacencyGraph.areEqual(newUnit.bonds, currentUnit.bonds)) {
                      state.createGeometry = true;
                      state.updateTransform = true;
                      state.updateColor = true;
                      state.updateSize = true;
                  }
              }
          },
          mustRecreate: function (structureGroup, props, webgl) {
              return !props.tryUseImpostor || !webgl;
          }
      }, materialId);
  }
  exports.IntraUnitBondCylinderImpostorVisual = IntraUnitBondCylinderImpostorVisual;
  function IntraUnitBondCylinderMeshVisual(materialId) {
      return (0, units_visual_1.UnitsMeshVisual)({
          defaultProps: param_definition_1.ParamDefinition.getDefaultValues(exports.IntraUnitBondCylinderParams),
          createGeometry: createIntraUnitBondCylinderMesh,
          createLocationIterator: bond_1.BondIterator.fromGroup,
          getLoci: bond_1.getIntraBondLoci,
          eachLocation: bond_1.eachIntraBond,
          setUpdateState: function (state, newProps, currentProps, newTheme, currentTheme, newStructureGroup, currentStructureGroup) {
              state.createGeometry = (newProps.sizeFactor !== currentProps.sizeFactor ||
                  newProps.sizeAspectRatio !== currentProps.sizeAspectRatio ||
                  newProps.radialSegments !== currentProps.radialSegments ||
                  newProps.linkScale !== currentProps.linkScale ||
                  newProps.linkSpacing !== currentProps.linkSpacing ||
                  newProps.ignoreHydrogens !== currentProps.ignoreHydrogens ||
                  newProps.linkCap !== currentProps.linkCap ||
                  newProps.aromaticScale !== currentProps.aromaticScale ||
                  newProps.aromaticSpacing !== currentProps.aromaticSpacing ||
                  newProps.aromaticDashCount !== currentProps.aromaticDashCount ||
                  newProps.dashCount !== currentProps.dashCount ||
                  newProps.dashScale !== currentProps.dashScale ||
                  newProps.dashCap !== currentProps.dashCap ||
                  newProps.stubCap !== currentProps.stubCap ||
                  !(0, mol_util_1.arrayEqual)(newProps.includeTypes, currentProps.includeTypes) ||
                  !(0, mol_util_1.arrayEqual)(newProps.excludeTypes, currentProps.excludeTypes) ||
                  newProps.adjustCylinderLength !== currentProps.adjustCylinderLength ||
                  newProps.aromaticBonds !== currentProps.aromaticBonds ||
                  newProps.multipleBonds !== currentProps.multipleBonds);
              var newUnit = newStructureGroup.group.units[0];
              var currentUnit = currentStructureGroup.group.units[0];
              if (structure_1.Unit.isAtomic(newUnit) && structure_1.Unit.isAtomic(currentUnit)) {
                  if (!graph_1.IntAdjacencyGraph.areEqual(newUnit.bonds, currentUnit.bonds)) {
                      state.createGeometry = true;
                      state.updateTransform = true;
                      state.updateColor = true;
                      state.updateSize = true;
                  }
              }
          },
          mustRecreate: function (structureGroup, props, webgl) {
              return props.tryUseImpostor && !!webgl;
          }
      }, materialId);
  }
  exports.IntraUnitBondCylinderMeshVisual = IntraUnitBondCylinderMeshVisual;
  //# sourceMappingURL=bond-intra-unit-cylinder.js.map