text: "use strict";
  /**
   * Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
   *
   * @author Alexander Rose <alexander.rose@weirdbyte.de>
   */
  Object.defineProperty(exports, "__esModule", { value: true });
  exports.AngleRepresentation = exports.AngleParams = void 0;
  var tslib_1 = require("tslib");
  var loci_1 = require("../../../mol-model/loci");
  var lines_1 = require("../../../mol-geo/geometry/lines/lines");
  var text_1 = require("../../../mol-geo/geometry/text/text");
  var param_definition_1 = require("../../../mol-util/param-definition");
  var names_1 = require("../../../mol-util/color/names");
  var representation_1 = require("../representation");
  var representation_2 = require("../../representation");
  var shape_1 = require("../../../mol-model/shape");
  var lines_builder_1 = require("../../../mol-geo/geometry/lines/lines-builder");
  var text_builder_1 = require("../../../mol-geo/geometry/text/text-builder");
  var linear_algebra_1 = require("../../../mol-math/linear-algebra");
  var mesh_1 = require("../../../mol-geo/geometry/mesh/mesh");
  var mesh_builder_1 = require("../../../mol-geo/geometry/mesh/mesh-builder");
  var misc_1 = require("../../../mol-math/misc");
  var circle_1 = require("../../../mol-geo/primitive/circle");
  var primitive_1 = require("../../../mol-geo/primitive/primitive");
  var marker_action_1 = require("../../../mol-util/marker-action");
  var label_1 = require("../../../mol-theme/label");
  var geometry_1 = require("../../../mol-math/geometry");
  var common_1 = require("./common");
  var SharedParams = {
      color: param_definition_1.ParamDefinition.Color(names_1.ColorNames.lightgreen),
      arcScale: param_definition_1.ParamDefinition.Numeric(0.7, { min: 0.01, max: 1, step: 0.01 })
  };
  var LinesParams = (0, tslib_1.__assign)((0, tslib_1.__assign)((0, tslib_1.__assign)({}, lines_1.Lines.Params), SharedParams), { lineSizeAttenuation: param_definition_1.ParamDefinition.Boolean(true), linesSize: param_definition_1.ParamDefinition.Numeric(0.04, { min: 0.01, max: 5, step: 0.01 }), dashLength: param_definition_1.ParamDefinition.Numeric(0.04, { min: 0.01, max: 0.2, step: 0.01 }) });
  var VectorsParams = (0, tslib_1.__assign)({}, LinesParams);
  var ArcParams = (0, tslib_1.__assign)({}, LinesParams);
  var SectorParams = (0, tslib_1.__assign)((0, tslib_1.__assign)((0, tslib_1.__assign)({}, mesh_1.Mesh.Params), SharedParams), { ignoreLight: param_definition_1.ParamDefinition.Boolean(true), sectorOpacity: param_definition_1.ParamDefinition.Numeric(0.75, { min: 0, max: 1, step: 0.01 }) });
  var AngleVisuals = {
      'vectors': function (ctx, getParams) { return (0, representation_1.ShapeRepresentation)(getVectorsShape, lines_1.Lines.Utils, { modifyState: function (s) { return ((0, tslib_1.__assign)((0, tslib_1.__assign)({}, s), { pickable: false })); } }); },
      'arc': function (ctx, getParams) { return (0, representation_1.ShapeRepresentation)(getArcShape, lines_1.Lines.Utils, { modifyState: function (s) { return ((0, tslib_1.__assign)((0, tslib_1.__assign)({}, s), { pickable: false })); } }); },
      'sector': function (ctx, getParams) { return (0, representation_1.ShapeRepresentation)(getSectorShape, mesh_1.Mesh.Utils, { modifyProps: function (p) { return ((0, tslib_1.__assign)((0, tslib_1.__assign)({}, p), { alpha: p.sectorOpacity })); }, modifyState: function (s) { return ((0, tslib_1.__assign)((0, tslib_1.__assign)({}, s), { markerActions: marker_action_1.MarkerActions.Highlighting })); } }); },
      'text': function (ctx, getParams) { return (0, representation_1.ShapeRepresentation)(getTextShape, text_1.Text.Utils, { modifyState: function (s) { return ((0, tslib_1.__assign)((0, tslib_1.__assign)({}, s), { markerActions: marker_action_1.MarkerAction.None })); } }); },
  };
  exports.AngleParams = (0, tslib_1.__assign)((0, tslib_1.__assign)((0, tslib_1.__assign)((0, tslib_1.__assign)((0, tslib_1.__assign)({}, VectorsParams), ArcParams), SectorParams), common_1.LociLabelTextParams), { visuals: param_definition_1.ParamDefinition.MultiSelect(['vectors', 'sector', 'text'], param_definition_1.ParamDefinition.objectToOptions(AngleVisuals)) });
  //
  function getAngleState() {
      return {
          sphereA: (0, geometry_1.Sphere3D)(),
          sphereB: (0, geometry_1.Sphere3D)(),
          sphereC: (0, geometry_1.Sphere3D)(),
          arcDirA: (0, linear_algebra_1.Vec3)(),
          arcDirC: (0, linear_algebra_1.Vec3)(),
          arcNormal: (0, linear_algebra_1.Vec3)(),
          radius: 0,
          angle: 0,
      };
  }
  var tmpVec = (0, linear_algebra_1.Vec3)();
  var tmpMat = (0, linear_algebra_1.Mat4)();
  function setAngleState(triple, state, arcScale) {
      var sphereA = state.sphereA, sphereB = state.sphereB, sphereC = state.sphereC;
      var arcDirA = state.arcDirA, arcDirC = state.arcDirC, arcNormal = state.arcNormal;
      var _a = triple.loci, lociA = _a[0], lociB = _a[1], lociC = _a[2];
      loci_1.Loci.getBoundingSphere(lociA, sphereA);
      loci_1.Loci.getBoundingSphere(lociB, sphereB);
      loci_1.Loci.getBoundingSphere(lociC, sphereC);
      linear_algebra_1.Vec3.sub(arcDirA, sphereA.center, sphereB.center);
      linear_algebra_1.Vec3.sub(arcDirC, sphereC.center, sphereB.center);
      linear_algebra_1.Vec3.cross(arcNormal, arcDirA, arcDirC);
      var len = Math.min(linear_algebra_1.Vec3.magnitude(arcDirA), linear_algebra_1.Vec3.magnitude(arcDirC));
      var radius = len * arcScale;
      state.radius = radius;
      state.angle = linear_algebra_1.Vec3.angle(arcDirA, arcDirC);
      return state;
  }
  function getCircle(state, segmentLength) {
      var radius = state.radius, angle = state.angle;
      var segments = segmentLength ? (0, misc_1.arcLength)(angle, radius) / segmentLength : 32;
      linear_algebra_1.Mat4.targetTo(tmpMat, state.sphereB.center, state.sphereA.center, state.arcNormal);
      linear_algebra_1.Mat4.setTranslation(tmpMat, state.sphereB.center);
      linear_algebra_1.Mat4.mul(tmpMat, tmpMat, linear_algebra_1.Mat4.rotY180);
      var circle = (0, circle_1.Circle)({ radius: radius, thetaLength: angle, segments: segments });
      return (0, primitive_1.transformPrimitive)(circle, tmpMat);
  }
  var tmpState = getAngleState();
  function getAngleName(data) {
      return data.triples.length === 1 ? "Angle ".concat((0, label_1.angleLabel)(data.triples[0], { measureOnly: true })) : "".concat(data.triples.length, " Angles");
  }
  //
  function buildVectorsLines(data, props, lines) {
      var builder = lines_builder_1.LinesBuilder.create(128, 64, lines);
      for (var i = 0, il = data.triples.length; i < il; ++i) {
          setAngleState(data.triples[i], tmpState, props.arcScale);
          builder.addFixedLengthDashes(tmpState.sphereB.center, tmpState.sphereA.center, props.dashLength, i);
          builder.addFixedLengthDashes(tmpState.sphereB.center, tmpState.sphereC.center, props.dashLength, i);
      }
      return builder.getLines();
  }
  function getVectorsShape(ctx, data, props, shape) {
      var lines = buildVectorsLines(data, props, shape && shape.geometry);
      var name = getAngleName(data);
      return shape_1.Shape.create(name, data, lines, function () { return props.color; }, function () { return props.linesSize; }, function () { return ''; });
  }
  //
  function buildArcLines(data, props, lines) {
      var builder = lines_builder_1.LinesBuilder.create(128, 64, lines);
      for (var i = 0, il = data.triples.length; i < il; ++i) {
          setAngleState(data.triples[i], tmpState, props.arcScale);
          var circle = getCircle(tmpState, props.dashLength);
          var indices = circle.indices, vertices = circle.vertices;
          for (var j = 0, jl = indices.length; j < jl; j += 3) {
              if (j % 2 === 1)
                  continue; // draw every other segment to get dashes
              var start = indices[j] * 3;
              var end = indices[j + 1] * 3;
              var startX = vertices[start];
              var startY = vertices[start + 1];
              var startZ = vertices[start + 2];
              var endX = vertices[end];
              var endY = vertices[end + 1];
              var endZ = vertices[end + 2];
              builder.add(startX, startY, startZ, endX, endY, endZ, i);
          }
      }
      return builder.getLines();
  }
  function getArcShape(ctx, data, props, shape) {
      var lines = buildArcLines(data, props, shape && shape.geometry);
      var name = getAngleName(data);
      return shape_1.Shape.create(name, data, lines, function () { return props.color; }, function () { return props.linesSize; }, function () { return ''; });
  }
  //
  function buildSectorMesh(data, props, mesh) {
      var state = mesh_builder_1.MeshBuilder.createState(128, 64, mesh);
      for (var i = 0, il = data.triples.length; i < il; ++i) {
          setAngleState(data.triples[i], tmpState, props.arcScale);
          var circle = getCircle(tmpState);
          state.currentGroup = i;
          mesh_builder_1.MeshBuilder.addPrimitive(state, linear_algebra_1.Mat4.id, circle);
          mesh_builder_1.MeshBuilder.addPrimitiveFlipped(state, linear_algebra_1.Mat4.id, circle);
      }
      return mesh_builder_1.MeshBuilder.getMesh(state);
  }
  function getSectorShape(ctx, data, props, shape) {
      var mesh = buildSectorMesh(data, props, shape && shape.geometry);
      var name = getAngleName(data);
      var getLabel = function (groupId) { return (0, label_1.angleLabel)(data.triples[groupId]); };
      return shape_1.Shape.create(name, data, mesh, function () { return props.color; }, function () { return 1; }, getLabel);
  }
  //
  function buildText(data, props, text) {
      var builder = text_builder_1.TextBuilder.create(props, 128, 64, text);
      for (var i = 0, il = data.triples.length; i < il; ++i) {
          setAngleState(data.triples[i], tmpState, props.arcScale);
          linear_algebra_1.Vec3.add(tmpVec, tmpState.arcDirA, tmpState.arcDirC);
          linear_algebra_1.Vec3.setMagnitude(tmpVec, tmpVec, tmpState.radius);
          linear_algebra_1.Vec3.add(tmpVec, tmpState.sphereB.center, tmpVec);
          var angle = (0, misc_1.radToDeg)(tmpState.angle).toFixed(2);
          var label = props.customText || "".concat(angle, "\u00B0");
          var radius = Math.max(2, tmpState.sphereA.radius, tmpState.sphereB.radius, tmpState.sphereC.radius);
          var scale = radius / 2;
          builder.add(label, tmpVec[0], tmpVec[1], tmpVec[2], 0.1, scale, i);
      }
      return builder.getText();
  }
  function getTextShape(ctx, data, props, shape) {
      var text = buildText(data, props, shape && shape.geometry);
      var name = getAngleName(data);
      var getLabel = function (groupId) { return (0, label_1.angleLabel)(data.triples[groupId]); };
      return shape_1.Shape.create(name, data, text, function () { return props.textColor; }, function () { return props.textSize; }, getLabel);
  }
  function AngleRepresentation(ctx, getParams) {
      return representation_2.Representation.createMulti('Angle', ctx, getParams, representation_2.Representation.StateBuilder, AngleVisuals);
  }
  exports.AngleRepresentation = AngleRepresentation;
  //# sourceMappingURL=angle.js.map