com.github.dougkelly88.FLIMPlateReaderGUI.InstrumentInterfaceClasses.XYZMotionInterface.java Source code

Java tutorial

Introduction

Here is the source code for com.github.dougkelly88.FLIMPlateReaderGUI.InstrumentInterfaceClasses.XYZMotionInterface.java

Source

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.github.dougkelly88.FLIMPlateReaderGUI.InstrumentInterfaceClasses;

import com.github.dougkelly88.FLIMPlateReaderGUI.GeneralClasses.PlateProperties;
import com.github.dougkelly88.FLIMPlateReaderGUI.SequencingClasses.Classes.FOV;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import mmcorej.CMMCore;
import org.apache.commons.math3.linear.MatrixUtils;
import org.apache.commons.math3.linear.RealMatrix;
import org.apache.commons.math3.linear.LUDecomposition;

/**
 *
 * @author dk1109
 */
public final class XYZMotionInterface {

    PlateProperties pp_;
    CMMCore core_;
    String xystage_;
    String zstage_;
    Point2D.Double[] stageWellCentres_ = new Point2D.Double[3];
    Point2D.Double[] xpltWellCentres_ = new Point2D.Double[3];
    AffineTransform transform_;

    //TODO: implement safety checks for objective fouling. 
    //TODO: deal with objective focal shifts
    //TODO: deal (limited) with camera coregistration with stage move?
    //TODO: set first/last well centres in calibration method
    public XYZMotionInterface(PlateProperties pp, CMMCore core) {
        pp_ = pp;
        core_ = core;
        xystage_ = core.getXYStageDevice();
        zstage_ = core.getFocusDevice();
        stageWellCentres_[0] = new Point2D.Double(106100, 6700); //TL
        stageWellCentres_[1] = new Point2D.Double(7100, 69700); //BR
        stageWellCentres_[2] = new Point2D.Double(7100, 6700); //TR
        xpltWellCentres_[0] = new Point2D.Double(pp_.getTopLeftWellOffsetH(), pp_.getTopLeftWellOffsetV());
        xpltWellCentres_[1] = new Point2D.Double(
                pp_.getTopLeftWellOffsetH() + (pp_.getPlateColumns() - 1) * pp_.getWellSpacingH(),
                pp_.getTopLeftWellOffsetV() + (pp_.getPlateRows() - 1) * pp_.getWellSpacingV());
        xpltWellCentres_[2] = new Point2D.Double(
                pp_.getTopLeftWellOffsetH() + (pp_.getPlateColumns() - 1) * pp_.getWellSpacingH(),
                pp_.getTopLeftWellOffsetV());
        transform_ = deriveAffineTransform(xpltWellCentres_, stageWellCentres_);
    }

    public int gotoFOV(FOV fov) {

        try {
            Point2D.Double stage = fovXYtoStageXY(fov);
            core_.setXYPosition(xystage_, stage.getX(), stage.getY());
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }

        return 1;
    }

    public FOV getCurrentFOV() {

        try {
            Point2D.Double xy = stageXYtoFOVXY(core_.getXYStagePosition(xystage_));
            Double z = getZAbsolute();
            return new FOV(xy.getX(), xy.getY(), z, pp_);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }

        return new FOV("A1", pp_, 0); // replace with something that more clearly
        // indicated error?
    }

    public Point2D.Double fovXYtoStageXY(FOV fov) {

        Point2D.Double xy = new Point2D.Double(fov.getX(), fov.getY());
        Point2D.Double xyout = new Point2D.Double();

        transform_.transform(xy, xyout);

        return xyout;
    }

    public Point2D.Double stageXYtoFOVXY(Point2D.Double stagexy) {

        Point2D.Double xyout = new Point2D.Double();
        try {
            transform_.inverseTransform(stagexy, xyout);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        return xyout;
    }

    public void setStageWellCentres(Point2D.Double p1, Point2D.Double p2, Point2D.Double p3) {
        stageWellCentres_[0] = p1;
        stageWellCentres_[1] = p2;
        stageWellCentres_[2] = p3;
    }

    public void setXPLTWellCentres(Point2D.Double p1, Point2D.Double p2, Point2D.Double p3) {
        xpltWellCentres_[0] = p1;
        xpltWellCentres_[1] = p2;
        xpltWellCentres_[2] = p3;
    }

    public static AffineTransform deriveAffineTransform(Point2D.Double[] xplt, Point2D.Double[] stage) {
        // GENERAL CASE:    
        // if S is stage space and P is XPLT plate space, 
        // and T is the matrix to transform between the two:
        // S = TP
        // SP^-1 = TPP^-1
        // T = SP^-1;
        // where S is a 2x3 matrix with 3 points, T is a 2x3 matrix and P is a 
        // 3x3 matrix with 3 points and the bottom row occupied by ones...

        double[][] Parr = { { xplt[0].getX(), xplt[1].getX(), xplt[2].getX() },
                { xplt[0].getY(), xplt[1].getY(), xplt[2].getY() }, { 1, 1, 1 } };
        RealMatrix P = MatrixUtils.createRealMatrix(Parr);

        double[][] Sarr = { { stage[0].getX(), stage[1].getX(), stage[2].getX() },
                { stage[0].getY(), stage[1].getY(), stage[2].getY() } };
        RealMatrix S = MatrixUtils.createRealMatrix(Sarr);

        RealMatrix Pinv = (new LUDecomposition(P)).getSolver().getInverse();
        RealMatrix transformationMatrix = S.multiply(Pinv);

        double m00 = transformationMatrix.getEntry(0, 0);
        double m01 = transformationMatrix.getEntry(0, 1);
        double m02 = transformationMatrix.getEntry(0, 2);
        double m10 = transformationMatrix.getEntry(1, 0);
        double m11 = transformationMatrix.getEntry(1, 1);
        double m12 = transformationMatrix.getEntry(1, 2);

        return new AffineTransform(m00, m10, m01, m11, m02, m12);
    }

    public boolean moveXYRelative(double x, double y) {
        try {
            core_.setRelativeXYPosition(xystage_, x, y);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        return true;
    }

    public boolean moveZRelative(double z) {
        try {
            core_.setRelativePosition(zstage_, z);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        return true;
    }

    public boolean moveZAbsolute(double z) {
        try {
            // TODO: check within bounds?
            // TODO: calibrate to make up for lack of parfocality...
            core_.setPosition(zstage_, z);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        return true;
    }

    public Double getZAbsolute() {
        double z = 0.0;

        try {
            z = core_.getPosition(zstage_);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }

        return z;
    }

    public void enableManualXYControls(boolean on) {
        try {
            if (on)
                core_.setProperty(xystage_, "Enable joystick?", "True");
            else
                core_.setProperty(xystage_, "Enable joystick?", "False");
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }

    public void enableManualZControls(boolean on) {
        try {
            if (on)
                core_.setProperty("OlympusHub", "Control", "Manual + Computer");
            else
                core_.setProperty("OlympusHub", "Control", "Computer");
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }

    }

    public void enableManualZOnly(boolean on) {
        try {
            if (on)
                core_.setProperty("ManualFocus", "FocusWheel", "Frame");
            else
                core_.setProperty("ManualFocus", "FocusWheel", "Off");
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }

    }

    public void customAutofocus(Double offset) {
        try {
            this.moveZRelative(-offset);
            core_.setProperty("AutoFocusZDC", "MeasureOffset", "Now");
            Double focusOffset = Double.parseDouble(core_.getProperty("AutoFocusZDC", "Offset"));
            this.moveZRelative(offset - focusOffset);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }

}