Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AMI.CamerasOrthographic is not a constructor #410

Open
1 of 7 tasks
SarahMohamedLotfy opened this issue Jul 14, 2020 · 3 comments
Open
1 of 7 tasks

AMI.CamerasOrthographic is not a constructor #410

SarahMohamedLotfy opened this issue Jul 14, 2020 · 3 comments

Comments

@SarahMohamedLotfy
Copy link

SarahMohamedLotfy commented Jul 14, 2020

I am making a project which is a website that used as a Dicom viewer.
I used the AMI library with an Angular 8 project.

I tried viewers_upload example but this error occurred when I used viewers_upload.js.
the error is "AMI.CamerasOrthographic is not a constructor"

I will tell you what I did
1- I made a new Angular 8 project.
2- I run yarn add ami.js
3- Put viewers_upload.html in app.component.html
4- Put viewers_upload.js code inside a function and put it in the assets folder and I added
"scripts": [ "src/assets/js/viewers_upload.js" ]
in the angular.json file.

5- I called the function that contains viewers_upload.js code inside app.component.ts.

Please can you help me because I was trying in this error for 3 days?
Thanks a lot

Browsers Affected

  • All
  • Chrome
  • Firefox
  • Edge
  • Safari 9
  • Safari 8
  • IE 11

Versions

  • AMI: vX.X.X
  • THREEJS: vX.X.X

Code of viewers_update.js

/* globals dat*/

// standard global variables
let controls;
let renderer;
let scene;
let camera;
let threeD;
let lut;

let ctrlDown = false;
let drag = {
  start: {
    x: null,
    y: null,
  },
};

// probe
let camUtils = {
  invertRows: false,
  invertColumns: false,
  rotate: false,
  orientation: 'default',
  convention: 'radio',
};


function loadScene()
{
  alert("awaaaa");
/**
 * Init the scene
 */
function init() {
  /**
   * Animation loop
   */
  function animate() {
    // render
    controls.update();
    renderer.render(scene, camera);

    // request new frame
    requestAnimationFrame(function() {
      animate();
    });
  }

  // renderer
  threeD = document.getElementById('r3d');
  renderer = new THREE.WebGLRenderer({
    antialias: true,
  });
  renderer.setSize(threeD.clientWidth, threeD.clientHeight);
  renderer.setClearColor(0x212121, 1);

  threeD.appendChild(renderer.domElement);

  // scene
  scene = new THREE.Scene();
  // camera
  
  camera = new AMI.CamerasOrthographic(
    threeD.clientWidth / -2,
    threeD.clientWidth / 2,
    threeD.clientHeight / 2,
    threeD.clientHeight / -2,
    0.1,
    10000
  );

  // controls
  controls = new AMI.ControlsOrthographic(camera, threeD);
  controls.staticMoving = true;
  controls.noRotate = true;
  camera.controls = controls;

  animate();
}

window.onload = function() {
  // notify puppeteer to take screenshot
  const puppetDiv = document.createElement('div');
  puppetDiv.setAttribute('id', 'puppeteer');
  document.body.appendChild(puppetDiv);

  // hookup load button
  document.getElementById('buttoninput').onclick = function() {
    document.getElementById('filesinput').click();
  };

  // init threeJS...
  init();

  function updateLabels(labels, modality) {
    if (modality === 'CR' || modality === 'DX') return;

    let top = document.getElementById('top');
    top.innerHTML = labels[0];

    let bottom = document.getElementById('bottom');
    bottom.innerHTML = labels[1];

    let right = document.getElementById('right');
    right.innerHTML = labels[2];

    let left = document.getElementById('left');
    left.innerHTML = labels[3];
  }

  function buildGUI(stackHelper) {
    let stack = stackHelper._stack;

    let gui = new dat.GUI({
      autoPlace: false,
    });

    let customContainer = document.getElementById('my-gui-container');
    customContainer.appendChild(gui.domElement);

    let stackFolder = gui.addFolder('Stack');
    stackFolder
      .add(stackHelper.slice, 'windowWidth', 1, stack.minMax[1] - stack.minMax[0])
      .step(1)
      .listen();
    stackFolder
      .add(stackHelper.slice, 'windowCenter', stack.minMax[0], stack.minMax[1])
      .step(1)
      .listen();
    stackFolder
      .add(stackHelper.slice, 'lowerThreshold', stack.minMax[0], stack.minMax[1])
      .step(1)
      .listen();
    stackFolder
      .add(stackHelper.slice, 'upperThreshold', stack.minMax[0], stack.minMax[1])
      .step(1)
      .listen();
    stackFolder.add(stackHelper.slice, 'intensityAuto').listen();
    stackFolder.add(stackHelper.slice, 'invert');
    stackFolder
      .add(stackHelper.slice, 'interpolation', 0, 1)
      .step(1)
      .listen();

    // CREATE LUT
    lut = new HelpersLut(
      'my-lut-canvases',
      'default',
      'linear',
      [[0, 0, 0, 0], [1, 1, 1, 1]],
      [[0, 1], [1, 1]]
    );
    lut.luts = HelpersLut.presetLuts();

    let lutUpdate = stackFolder.add(stackHelper.slice, 'lut', lut.lutsAvailable());
    lutUpdate.onChange(function(value) {
      lut.lut = value;
      stackHelper.slice.lutTexture = lut.texture;
    });
    let lutDiscrete = stackFolder.add(lut, 'discrete', false);
    lutDiscrete.onChange(function(value) {
      lut.discrete = value;
      stackHelper.slice.lutTexture = lut.texture;
    });

    let index = stackFolder
      .add(stackHelper, 'index', 0, stack.dimensionsIJK.z - 1)
      .step(1)
      .listen();
    stackFolder.open();

    // camera
    let cameraFolder = gui.addFolder('Camera');
    let invertRows = cameraFolder.add(camUtils, 'invertRows');
    invertRows.onChange(function() {
      camera.invertRows();
      updateLabels(camera.directionsLabel, stack.modality);
    });

    let invertColumns = cameraFolder.add(camUtils, 'invertColumns');
    invertColumns.onChange(function() {
      camera.invertColumns();
      updateLabels(camera.directionsLabel, stack.modality);
    });

    let angle = cameraFolder
      .add(camera, 'angle', 0, 360)
      .step(1)
      .listen();
    angle.onChange(function() {
      updateLabels(camera.directionsLabel, stack.modality);
    });

    let rotate = cameraFolder.add(camUtils, 'rotate');
    rotate.onChange(function() {
      camera.rotate();
      updateLabels(camera.directionsLabel, stack.modality);
    });

    let orientationUpdate = cameraFolder.add(camUtils, 'orientation', [
      'default',
      'axial',
      'coronal',
      'sagittal',
    ]);
    orientationUpdate.onChange(function(value) {
      camera.orientation = value;
      camera.update();
      camera.fitBox(2);
      stackHelper.orientation = camera.stackOrientation;
      updateLabels(camera.directionsLabel, stack.modality);

      index.__max = stackHelper.orientationMaxIndex;
      stackHelper.index = Math.floor(index.__max / 2);
    });

    let conventionUpdate = cameraFolder.add(camUtils, 'convention', ['radio', 'neuro']);
    conventionUpdate.onChange(function(value) {
      camera.convention = value;
      camera.update();
      camera.fitBox(2);
      updateLabels(camera.directionsLabel, stack.modality);
    });
  }

  /**
   * Connect all callbevent observesrs
   */
  function hookCallbacks(stackHelper) {
    let stack = stackHelper._stack;
    // hook up callbacks
    controls.addEventListener('OnScroll', function(e) {
      if (e.delta > 0) {
        if (stackHelper.index >= stackHelper.orientationMaxIndex - 1) {
          return false;
        }
        stackHelper.index += 1;
      } else {
        if (stackHelper.index <= 0) {
          return false;
        }
        stackHelper.index -= 1;
      }
    });

    /**
     * On window resize callback
     */
    function onWindowResize() {
      let threeD = document.getElementById('r3d');
      camera.canvas = {
        width: threeD.clientWidth,
        height: threeD.clientHeight,
      };
      camera.fitBox(2);

      renderer.setSize(threeD.clientWidth, threeD.clientHeight);

      // update info to draw borders properly
      stackHelper.slice.canvasWidth = threeD.clientWidth;
      stackHelper.slice.canvasHeight = threeD.clientHeight;
    }

    window.addEventListener('resize', onWindowResize, false);
    onWindowResize();

    /**
     * On key pressed callback
     */
    function onWindowKeyPressed(event) {
      ctrlDown = event.ctrlKey;
      if (!ctrlDown) {
        drag.start.x = null;
        drag.start.y = null;
      }
    }
    document.addEventListener('keydown', onWindowKeyPressed, false);
    document.addEventListener('keyup', onWindowKeyPressed, false);

    /**
     * On mouse move callback
     */
    function onMouseMove(event) {
      if (ctrlDown) {
        if (drag.start.x === null) {
          drag.start.x = event.clientX;
          drag.start.y = event.clientY;
        }
        let threshold = 15;

        stackHelper.slice.intensityAuto = false;

        let dynamicRange = stack.minMax[1] - stack.minMax[0];
        dynamicRange /= threeD.clientWidth;

        if (Math.abs(event.clientX - drag.start.x) > threshold) {
          // window width
          stackHelper.slice.windowWidth += dynamicRange * (event.clientX - drag.start.x);
          drag.start.x = event.clientX;
        }

        if (Math.abs(event.clientY - drag.start.y) > threshold) {
          // window center
          stackHelper.slice.windowCenter -= dynamicRange * (event.clientY - drag.start.y);
          drag.start.y = event.clientY;
        }
      }
    }
    document.addEventListener('mousemove', onMouseMove);
  }

  /**
   * Visulaize incoming data
   */
  function handleSeries(seriesContainer) {
    // cleanup the loader and its progress bar
    loader.free();
    loader = null;
    // prepare for slice visualization
    // first stack of first series
    let stack = seriesContainer[0].mergeSeries(seriesContainer)[0].stack[0];

    let stackHelper = new HelpersStack(stack);
    stackHelper.bbox.visible = false;
    stackHelper.borderColor = '#2196F3';
    stackHelper.border.visible = false;
    scene.add(stackHelper);

    // set camera
    let worldbb = stack.worldBoundingBox();
    let lpsDims = new THREE.Vector3(
      (worldbb[1] - worldbb[0]) / 2,
      (worldbb[3] - worldbb[2]) / 2,
      (worldbb[5] - worldbb[4]) / 2
    );

    // box: {halfDimensions, center}
    let box = {
      center: stack.worldCenter().clone(),
      halfDimensions: new THREE.Vector3(lpsDims.x + 10, lpsDims.y + 10, lpsDims.z + 10),
    };

    // init and zoom
    let canvas = {
      width: threeD.clientWidth,
      height: threeD.clientHeight,
    };

    camera.directions = [stack.xCosine, stack.yCosine, stack.zCosine];
    camera.box = box;
    camera.canvas = canvas;
    camera.update();
    camera.fitBox(2);

    updateLabels(camera.directionsLabel, stack.modality);
    buildGUI(stackHelper);
    hookCallbacks(stackHelper);
  }

  let loader = new AMI.LoadersVolume(threeD);
  let seriesContainer = [];

  /**
   * Filter array of data by extension
   * extension {String}
   * item {Object}
   * @return {Boolean}
   */
  function _filterByExtension(extension, item) {
    if (item.extension.toUpperCase() === extension.toUpperCase()) {
      return true;
    }
    return false;
  }

  /**
   * Parse incoming files
   */
  function readMultipleFiles(evt) {
    // hide the upload button
    if (evt.target.files.length) {
      document.getElementById('home-container').style.display = 'none';
    }

    /**
     * Load sequence
     */
    function loadSequence(index, files) {
      return (
        Promise.resolve()
          // load the file
          .then(function() {
            return new Promise(function(resolve, reject) {
              let myReader = new FileReader();
              // should handle errors too...
              myReader.addEventListener('load', function(e) {
                resolve(e.target.result);
              });
              myReader.readAsArrayBuffer(files[index]);
            });
          })
          .then(function(buffer) {
            return loader.parse({ url: files[index].name, buffer });
          })
          .then(function(series) {
            seriesContainer.push(series);
          })
          .catch(function(error) {
            window.console.log('oops... something went wrong...');
            window.console.log(error);
          })
      );
    }

    /**
     * Load group sequence
     */
    function loadSequenceGroup(files) {
      const fetchSequence = [];

      for (let i = 0; i < files.length; i++) {
        fetchSequence.push(
          new Promise((resolve, reject) => {
            const myReader = new FileReader();
            // should handle errors too...
            myReader.addEventListener('load', function(e) {
              resolve(e.target.result);
            });
            myReader.readAsArrayBuffer(files[i].file);
          }).then(function(buffer) {
            return { url: files[i].file.name, buffer };
          })
        );
      }

      return Promise.all(fetchSequence)
        .then(rawdata => {
          return loader.parse(rawdata);
        })
        .then(function(series) {
          seriesContainer.push(series);
        })
        .catch(function(error) {
          window.console.log('oops... something went wrong...');
          window.console.log(error);
        });
    }

    const loadSequenceContainer = [];

    const data = [];
    const dataGroups = [];
    // convert object into array
    for (let i = 0; i < evt.target.files.length; i++) {
      let dataUrl = CoreUtils.parseUrl(evt.target.files[i].name);
      if (
        dataUrl.extension.toUpperCase() === 'MHD' ||
        dataUrl.extension.toUpperCase() === 'RAW' ||
        dataUrl.extension.toUpperCase() === 'ZRAW'
      ) {
        dataGroups.push({
          file: evt.target.files[i],
          extension: dataUrl.extension.toUpperCase(),
        });
      } else {
        data.push(evt.target.files[i]);
      }
    }

    // check if some files must be loaded together
    if (dataGroups.length === 2) {
      // if raw/mhd pair
      const mhdFile = dataGroups.filter(_filterByExtension.bind(null, 'MHD'));
      const rawFile = dataGroups.filter(_filterByExtension.bind(null, 'RAW'));
      const zrawFile = dataGroups.filter(_filterByExtension.bind(null, 'ZRAW'));
      if (mhdFile.length === 1 && (rawFile.length === 1 || zrawFile.length === 1)) {
        loadSequenceContainer.push(loadSequenceGroup(dataGroups));
      }
    }

    // load the rest of the files
    for (let i = 0; i < data.length; i++) {
      loadSequenceContainer.push(loadSequence(i, data));
    }

    // run the load sequence
    // load sequence for all files
    Promise.all(loadSequenceContainer)
      .then(function() {
        handleSeries(seriesContainer);
      })
      .catch(function(error) {
        window.console.log('oops... something went wrong...');
        window.console.log(error);
      });
  }
  // hook up file input listener
  document.getElementById('filesinput').addEventListener('change', readMultipleFiles, false);
};
}
@NicolasRannou
Copy link
Member

Hello, unfortunatly I am not familiar with angular - I have no clue what assets are and so on, in the angular context.

It sounds like the error is related to angular not finding AMI.

  • Does a simple threejs app work in your setup?
  • It seems like you are missing imports in you JS file, something like the following at the beginning of the file may help:
import * as THREE from 'three';
import * as AMI from 'ami.js';

Good luck,

@SarahMohamedLotfy
Copy link
Author

I solved the error thanks a lot.
But there is an error occurred while using viewers_update.js

Here is the error: "do not know how to order the frames..."
Can you help me

@WaelAlBasha
Copy link

@SarahMohamedLotfy please can you tell us how you solved the previously mentioned error.
Thanks
Best regards

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants