/* * Copyright (c) 2012 Diamond Light Source Ltd. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ package uk.ac.diamond.scisoft.analysis.dataset.function; import java.util.ArrayList; import java.util.List; import javax.vecmath.Vector3d; import org.eclipse.dawnsci.analysis.dataset.impl.function.DatasetToDatasetFunction; import org.eclipse.january.dataset.Dataset; import org.eclipse.january.dataset.DatasetFactory; import org.eclipse.january.dataset.DatasetUtils; import org.eclipse.january.dataset.IDataset; import org.eclipse.january.dataset.Maths; import uk.ac.diamond.scisoft.analysis.diffraction.QSpace; /** * Project a 2D dataset from image coordinates to a plane (through origin) in q-space * <p> * q is the scattering wave-vector = difference of incident wave-vector * and final wave-vector */ public class ProjectToQSpacePlane implements DatasetToDatasetFunction { private QSpace qspace; private Vector3d row; private Vector3d col; private double rdel; private double cdel; private int roff; // row offset private int coff; // column offset private int[] pshape; // shape of projected dataset private Dataset image; // projected dataset private Dataset count; // tally dataset - counts number of datasets have added pixels /** * Set up projection to plane in q-space * @param qNormal normal to projection plane * @param qRow vector to describe direction of a row * @param qDeltas array of pixel sizes in q-space * @param rowLimits array containing start and (exclusive) stop values of row index * @param colLimits array containing start and (exclusive) stop values of columns index */ public ProjectToQSpacePlane(Vector3d qNormal, Vector3d qRow, double[] qDeltas, int[] rowLimits, int[] colLimits) { qNormal.normalize(); row = qRow; row.normalize(); col = new Vector3d(); col.cross(qNormal, col); col.normalize(); rdel = qDeltas[0]; cdel = qDeltas[1]; pshape = new int[2]; pshape[0] = rowLimits[1] - rowLimits[0]; pshape[1] = colLimits[1] - colLimits[0]; roff = rowLimits[0]; coff = colLimits[0]; } /** * */ public void createDataset(int dType) { image = DatasetFactory.zeros(pshape, dType); count = DatasetFactory.zeros(pshape, Dataset.INT16); } /** * */ public void setQSpace(QSpace qSpace) { qspace = qSpace; } /** * */ public void clearDataset() { image.fill(0); count.fill(0); } /** * @param datasets * input 2D dataset * @return one 2D dataset */ @Override public List<Dataset> value(IDataset... datasets) { if (datasets.length == 0) return null; List<Dataset> result = new ArrayList<Dataset>(); for (IDataset ids : datasets) { Dataset ds = DatasetUtils.convertToDataset(ids); // check if input is 2D int[] s = ds.getShape(); if (s.length != 2) return null; // find extent of projected dataset int[] pos = new int[2]; int[] start = pshape.clone(); int[] stop = new int[2]; qToPixel(qspace.qFromPixelPosition(0, 0), pos); adjustBoundingBox(start, stop, pos); qToPixel(qspace.qFromPixelPosition(s[0], 0), pos); adjustBoundingBox(start, stop, pos); qToPixel(qspace.qFromPixelPosition(0, s[1]), pos); adjustBoundingBox(start, stop, pos); qToPixel(qspace.qFromPixelPosition(s[0], s[1]), pos); adjustBoundingBox(start, stop, pos); stop[0]++; stop[1]++; // iterate over bounding box in project dataset // find image point // calculate interpolated value // store running average // (could have done this using a slice iterator) Vector3d qy = new Vector3d(); Vector3d q = new Vector3d(); Vector3d t = new Vector3d(); double delta, value; int i = 0, n; for (int y = start[0]; y < stop[0]; y++) { qy.scale((y + roff) * cdel, col); for (int x = start[1]; x < stop[1]; x++) { q.scaleAdd((x + coff) * rdel, row, qy); qspace.pixelPosition(q, t); n = (int) (count.getElementLongAbs(i) + 1); value = image.getElementDoubleAbs(i); delta = Maths.interpolate(ds, t.y, t.x) - value; image.setObjectAbs(i, value + (delta / n)); count.setObjectAbs(i, n); i++; } } result.add(image); result.add(count); } return result; } /** * Convert from q to a pixel coordinate (discretization) * @param q * @param pos (to be used for a dataset so is row-major: x->2, y->1) */ private void qToPixel(final Vector3d q, int[] pos) { pos[0] = -1; pos[1] = -1; final int x = (int) Math.floor(q.dot(row)/rdel) - roff; pos[1] = (x < 0 || x > pshape[1]) ? -1: x; final int y = (int) Math.floor(q.dot(col)/cdel) - coff; pos[0] = (y < 0 || y > pshape[0]) ? -1: y; } private void adjustBoundingBox(int[] start, int[] stop, int[] pos) { if (pos[0] >= 0) { if (pos[0] < start[0]) start[0] = pos[0]; if (pos[0] > stop[0]) stop[0] = pos[0]; } if (pos[1] >= 0) { if (pos[1] < start[1]) start[1] = pos[1]; if (pos[1] > stop[1]) stop[1] = pos[1]; } } }