


(function () {
  'use strict';

  var MAX_POINTS = 8000;
  var MIN_STEP = 0.002;   

  function Trace(vizScene, opts) {
    opts = opts || {};
    this._positions = new Float32Array(MAX_POINTS * 3);
    var geom = new THREE.BufferGeometry();
    geom.setAttribute('position', new THREE.BufferAttribute(this._positions, 3));
    geom.setDrawRange(0, 0);
    var mat = new THREE.LineBasicMaterial({ color: opts.color || 0xffcc44 });
    this.line = new THREE.Line(geom, mat);
    this.line.frustumCulled = false;   
    this._geom = geom;
    this._count = 0;
    this._last = null;
    this._wantVisible = true;          
    this.line.visible = false;         
    this.scene = vizScene.scene;       
    this._preview = null;
    vizScene.scene.add(this.line);
  }

  


  Trace.prototype._sync = function () {
    this.line.visible = this._wantVisible && this._count >= 2;
  };

  Trace.prototype.add = function (xyz) {
    if (this._count >= MAX_POINTS) return;
    if (this._last) {
      var dx = xyz[0] - this._last[0], dy = xyz[1] - this._last[1], dz = xyz[2] - this._last[2];
      if (dx * dx + dy * dy + dz * dz < MIN_STEP * MIN_STEP) return;
    }
    var i = this._count * 3;
    this._positions[i] = xyz[0];
    this._positions[i + 1] = xyz[1];
    this._positions[i + 2] = xyz[2];
    this._count++;
    this._last = [xyz[0], xyz[1], xyz[2]];
    this._geom.setDrawRange(0, this._count);
    this._geom.attributes.position.needsUpdate = true;
    this._sync();
  };

  Trace.prototype.clear = function () {
    this._count = 0;
    this._last = null;
    this._geom.setDrawRange(0, 0);
    this._geom.attributes.position.needsUpdate = true;
    this._sync();
  };

  Trace.prototype.setVisible = function (on) {
    this._wantVisible = !!on;
    this._sync();
  };

  



  Trace.prototype.setPreview = function (pts) {
    if (this._preview) {
      this._preview.geometry.dispose();
      this.scene.remove(this._preview);
      this._preview = null;
    }
    if (!pts || pts.length < 2) return;
    var arr = new Float32Array(pts.length * 3);
    for (var i = 0; i < pts.length; i++) {
      arr[i * 3] = pts[i][0];
      arr[i * 3 + 1] = pts[i][1];
      arr[i * 3 + 2] = pts[i][2];
    }
    var g = new THREE.BufferGeometry();
    g.setAttribute('position', new THREE.BufferAttribute(arr, 3));
    var line = new THREE.Line(g, new THREE.LineBasicMaterial({ color: 0x4da3ff }));
    line.frustumCulled = false;
    this._preview = line;
    this.scene.add(line);
  };

  window.Trace = Trace;
})();
