Java tutorial
/* * Copyright (C) 2013 by Array Systems Computing Inc. http://www.array.ca * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 3 of the License, or (at your option) * any later version. * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, see http://www.gnu.org/licenses/ */ package org.esa.nest.gpf; import com.bc.ceres.core.ProgressMonitor; import org.apache.commons.math.util.FastMath; import org.esa.beam.framework.datamodel.*; import org.esa.beam.framework.dataop.dem.ElevationModel; import org.esa.beam.framework.dataop.resamp.ResamplingFactory; import org.esa.beam.framework.gpf.Operator; import org.esa.beam.framework.gpf.OperatorException; import org.esa.beam.framework.gpf.OperatorSpi; import org.esa.beam.framework.gpf.Tile; import org.esa.beam.framework.gpf.annotations.OperatorMetadata; import org.esa.beam.framework.gpf.annotations.Parameter; import org.esa.beam.framework.gpf.annotations.SourceProduct; import org.esa.beam.framework.gpf.annotations.TargetProduct; import org.esa.beam.util.ProductUtils; import org.esa.nest.dataio.dem.DEMFactory; import org.esa.nest.datamodel.AbstractMetadata; import org.esa.nest.datamodel.PosVector; import org.esa.nest.eo.Constants; import org.esa.nest.eo.GeoUtils; import org.esa.nest.eo.SARGeocoding; import org.esa.nest.util.MathUtils; import java.awt.*; import java.util.HashMap; import java.util.Map; import java.util.Set; /** * Skew correction for ALOS product * Reference: ALOS-PALSAR-FAQ-001, ESRIN Contract No.20700/07/I-OL, IDEAS QC PALSAR Team */ @OperatorMetadata(alias = "ALOS-Deskewing", category = "Geometry", authors = "Jun Lu, Luis Veci", copyright = "Copyright (C) 2013 by Array Systems Computing Inc.", description = "Deskewing ALOS product") public class ALOSDeskewingOp extends Operator { public static final String PRODUCT_SUFFIX = "_DS"; @SourceProduct(alias = "source") Product sourceProduct; @TargetProduct Product targetProduct; @Parameter(description = "The list of source bands.", alias = "sourceBands", itemAlias = "band", rasterDataNodeType = Band.class, label = "Source Bands") private String[] sourceBandNames = null; //@Parameter(defaultValue="false", label="Use Mapready Shift Only") boolean useMapreadyShiftOnly = false; //@Parameter(defaultValue="false", label="Use FAQ Shift Only") boolean useFAQShiftOnly = false; //@Parameter(defaultValue="false", label="Use Mapready + FAQ Shift") boolean useBoth = false; //@Parameter(defaultValue="false", label="Use Mapready + Hybrid Shift") boolean useHybrid = true; private int sourceImageWidth = 0; private int sourceImageHeight = 0; private double absShift = 0; private double fracShift = 0.0; private AbstractMetadata.OrbitStateVector[] orbitStateVectors = null; private double firstLineTime = 0.0; private double lineTimeInterval = 0.0; private double lastLineTime = 0.0; private AbstractMetadata.DopplerCentroidCoefficientList[] dopplerCentroidCoefficientLists = null; private double rangeSpacing = 0.0; private double azimuthSpacing = 0.0; private double slantRangeToFirstPixel = 0.0; private double radarWaveLength = 0.0; private double[][] sensorPosition = null; private double[][] sensorVelocity = null; private double[] timeArray = null; private double[] xPosArray = null; private double[] yPosArray = null; private double[] zPosArray = null; private double[] xVelArray = null; private double[] yVelArray = null; private double[] zVelArray = null; private final HashMap<String, String[]> targetBandNameToSourceBandName = new HashMap<String, String[]>(); private final static double AngularVelocity = getAngularVelocity(); /* Note: if useMapreadyShiftOnly is true, the shift is computed using MapReady method; if useFAQShiftOnly is true, the shift is computed using method from FAQ; if useBoth is true, the shift for each pixel has two parts, one is the shift computed by using MapReady method, the second part is the shift computed using FAQ method; if useHybrid is true, the shift for each pixel has two parts, one is the shift computed by using MapReady method, the second part is a constant shift computed for pixel (0,0) using zero Doppler time. */ /** * Initializes this operator and sets the one and only target product. * <p>The target product can be either defined by a field of type {@link org.esa.beam.framework.datamodel.Product} annotated with the * {@link org.esa.beam.framework.gpf.annotations.TargetProduct TargetProduct} annotation or * by calling {@link #setTargetProduct} method.</p> * <p>The framework calls this method after it has created this operator. * Any client code that must be performed before computation of tile data * should be placed here.</p> * * @throws org.esa.beam.framework.gpf.OperatorException * If an error occurs during operator initialisation. * @see #getTargetProduct() */ @Override public void initialize() throws OperatorException { try { if (!useMapreadyShiftOnly && !useFAQShiftOnly && !useBoth && !useHybrid) { throw new OperatorException("No method was selected for shift calculation"); } getMetadata(); computeSensorPositionsAndVelocities(); createTargetProduct(); computeShift(); updateTargetProductMetadata(); } catch (Throwable e) { OperatorUtils.catchOperatorException(getId(), e); } } /** * Retrieve required data from Abstracted Metadata * @throws Exception if metadata not found */ private void getMetadata() throws Exception { sourceImageWidth = sourceProduct.getSceneRasterWidth(); sourceImageHeight = sourceProduct.getSceneRasterHeight(); final MetadataElement absRoot = AbstractMetadata.getAbstractedMetadata(sourceProduct); final String mission = absRoot.getAttributeString(AbstractMetadata.MISSION); if (!mission.equals("ALOS")) { throw new OperatorException("The deskewing operator is for ALOS PALSAR products only"); } orbitStateVectors = AbstractMetadata.getOrbitStateVectors(absRoot); if (orbitStateVectors == null) { throw new OperatorException("Invalid Obit State Vectors"); } else if (orbitStateVectors.length < 2) { throw new OperatorException("Not enough orbit state vectors"); } firstLineTime = absRoot.getAttributeUTC(AbstractMetadata.first_line_time).getMJD(); lastLineTime = absRoot.getAttributeUTC(AbstractMetadata.last_line_time).getMJD(); lineTimeInterval = absRoot.getAttributeDouble(AbstractMetadata.line_time_interval) / Constants.secondsInDay; // s to day dopplerCentroidCoefficientLists = AbstractMetadata.getDopplerCentroidCoefficients(absRoot); rangeSpacing = AbstractMetadata.getAttributeDouble(absRoot, AbstractMetadata.range_spacing); azimuthSpacing = AbstractMetadata.getAttributeDouble(absRoot, AbstractMetadata.azimuth_spacing); slantRangeToFirstPixel = AbstractMetadata.getAttributeDouble(absRoot, AbstractMetadata.slant_range_to_first_pixel); radarWaveLength = OperatorUtils.getRadarFrequency(absRoot); } /** * Create target product. */ private void createTargetProduct() { targetProduct = new Product(sourceProduct.getName(), sourceProduct.getProductType(), sourceImageWidth, sourceImageHeight); OperatorUtils.addSelectedBands(sourceProduct, sourceBandNames, targetProduct, targetBandNameToSourceBandName, false, false); OperatorUtils.copyProductNodes(sourceProduct, targetProduct); for (Band srcBand : sourceProduct.getBands()) { if (srcBand instanceof VirtualBand) { OperatorUtils.copyVirtualBand(targetProduct, (VirtualBand) srcBand, srcBand.getName()); } } } private void updateTargetProductMetadata() { final MetadataElement absTgt = AbstractMetadata.getAbstractedMetadata(targetProduct); final double fd = getDopplerFrequency(0); final stateVector v = getOrbitStateVector(firstLineTime); final double vel = Math.sqrt(v.xVel * v.xVel + v.yVel * v.yVel + v.zVel * v.zVel); final double newSlantRangeToFirstPixel = FastMath.cos(FastMath.asin(fd * radarWaveLength / (2.0 * vel))) * slantRangeToFirstPixel; AbstractMetadata.setAttribute(absTgt, AbstractMetadata.slant_range_to_first_pixel, newSlantRangeToFirstPixel); } private void computeSensorPositionsAndVelocities() { final int numVectorsUsed = Math.min(orbitStateVectors.length, 5); timeArray = new double[numVectorsUsed]; xPosArray = new double[numVectorsUsed]; yPosArray = new double[numVectorsUsed]; zPosArray = new double[numVectorsUsed]; xVelArray = new double[numVectorsUsed]; yVelArray = new double[numVectorsUsed]; zVelArray = new double[numVectorsUsed]; sensorPosition = new double[sourceImageHeight][3]; // xPos, yPos, zPos sensorVelocity = new double[sourceImageHeight][3]; // xVel, yVel, zVel SARGeocoding.computeSensorPositionsAndVelocities(orbitStateVectors, timeArray, xPosArray, yPosArray, zPosArray, xVelArray, yVelArray, zVelArray, sensorPosition, sensorVelocity, firstLineTime, lineTimeInterval, sourceImageHeight); } /** * Called by the framework in order to compute the stack of tiles for the given target bands. * <p>The default implementation throws a runtime exception with the message "not implemented".</p> * * @param targetTiles The current tiles to be computed for each target band. * @param targetRectangle The area in pixel coordinates to be computed (same for all rasters in <code>targetRasters</code>). * @param pm A progress monitor which should be used to determine computation cancelation requests. * @throws OperatorException if an error occurs during computation of the target rasters. */ @Override public void computeTileStack(Map<Band, Tile> targetTiles, Rectangle targetRectangle, ProgressMonitor pm) throws OperatorException { try { final int tx0 = targetRectangle.x; final int ty0 = targetRectangle.y; final int tw = targetRectangle.width; final int th = targetRectangle.height; final int tyMax = ty0 + th; final int txMax = tx0 + tw; //System.out.println("x0 = " + tx0 + ", y0 = " + ty0 + ", w = " + tw + ", h = " + th); final int maxShift = (int) computeMaxShift(txMax, ty0); final Rectangle sourceRectangle = getSourceRectangle(tx0, ty0, tw, th, maxShift); final int sx0 = sourceRectangle.x; final int sy0 = sourceRectangle.y; final int sw = sourceRectangle.width; final int sh = sourceRectangle.height; final int syMax = sy0 + sh; final int sxMax = sx0 + sw; final Set<Band> keySet = targetTiles.keySet(); double totalShift; for (Band targetBand : keySet) { final Tile targetTile = targetTiles.get(targetBand); final String srcBandName = targetBandNameToSourceBandName.get(targetBand.getName())[0]; final Tile sourceTile = getSourceTile(sourceProduct.getBand(srcBandName), sourceRectangle); final ProductData trgDataBuffer = targetTile.getDataBuffer(); final ProductData srcDataBuffer = sourceTile.getDataBuffer(); final TileIndex srcIndex = new TileIndex(sourceTile); for (int y = sy0; y < syMax; y++) { srcIndex.calculateStride(y); final stateVector v = getOrbitStateVector(firstLineTime + y * lineTimeInterval); for (int x = sx0; x < sxMax; x++) { if (useMapreadyShiftOnly) { totalShift = FastMath.round(fracShift * x); } else if (useFAQShiftOnly) { totalShift = computeFAQShift(v, x); } else if (useBoth) { totalShift = computeFAQShift(v, x) + FastMath.round(fracShift * x); } else if (useHybrid) { totalShift = absShift + FastMath.round(fracShift * x); } else { throw new OperatorException("No method was selected for shift calculation"); } final int newy = y + (int) totalShift; if (newy >= ty0 && newy < tyMax) { final int trgIdx = targetTile.getDataBufferIndex(x, newy); trgDataBuffer.setElemFloatAt(trgIdx, srcDataBuffer.getElemFloatAt(srcIndex.getIndex(x))); } } } } } catch (Throwable e) { OperatorUtils.catchOperatorException(getId(), e); } } private double computeMaxShift(final int txMax, final int ty0) throws Exception { if (useMapreadyShiftOnly) { return FastMath.round(txMax * fracShift); } else if (useFAQShiftOnly) { final stateVector v = getOrbitStateVector(firstLineTime + ty0 * lineTimeInterval); return computeFAQShift(v, txMax) + FastMath.round(txMax * fracShift); } else { // hybrid return absShift + FastMath.round(txMax * fracShift); } } private Rectangle getSourceRectangle(final int tx0, final int ty0, final int tw, final int th, final int maxShift) { final int sx0 = tx0; final int sw = tw; int sy0, syMax; if (maxShift > 0) { sy0 = Math.max(ty0 - maxShift, 0); syMax = ty0 + th - 1; } else if (maxShift < 0) { sy0 = ty0; syMax = Math.min(ty0 + th - 1 - maxShift, sourceImageHeight - 1); } else { // maxShift == 0 sy0 = ty0; syMax = ty0 + th - 1; } final int sh = syMax - sy0 + 1; return new Rectangle(sx0, sy0, sw, sh); } private double computeFAQShift(final stateVector v, final int x) throws Exception { final double slr = slantRangeToFirstPixel + x * rangeSpacing; final double fd = getDopplerFrequency(x); final double vel = Math.sqrt(v.xVel * v.xVel + v.yVel * v.yVel + v.zVel * v.zVel); return slr * fd * radarWaveLength / (2.0 * vel * azimuthSpacing); } /** * Compute deskewing shift for pixel at (0,0). * @throws Exception The exceptions. */ private void computeShift() throws Exception { if (useFAQShiftOnly) { return; } final stateVector v = getOrbitStateVector(firstLineTime); final double slr = slantRangeToFirstPixel + 0 * rangeSpacing; final double fd = getDopplerFrequency(0); // fractional shift final double[] lookYaw = new double[2]; computeLookYawAngles(v, slr, fd, lookYaw); fracShift = FastMath.sin(lookYaw[0]) * FastMath.sin(lookYaw[1]); if (useMapreadyShiftOnly) { return; } // compute absolute shift final String demName = "SRTM 3Sec"; final String demResamplingMethod = ResamplingFactory.BILINEAR_INTERPOLATION_NAME; DEMFactory.validateDEM(demName, sourceProduct); ElevationModel dem = DEMFactory.createElevationModel(demName, demResamplingMethod); final float demNoDataValue = dem.getDescriptor().getNoDataValue(); GeoPos geoPos = new GeoPos(); for (int y = 0; y < sourceImageHeight; y++) { sourceProduct.getGeoCoding().getGeoPos(new PixelPos(0.5f, y + 0.5f), geoPos); final double lat = geoPos.lat; double lon = geoPos.lon; if (lon >= 180.0) { lon -= 360.0; } final double alt = dem.getElevation(new GeoPos((float) lat, (float) lon)); if (alt == demNoDataValue) { continue; } final double[] earthPoint = new double[3]; final double[] sensorPos = new double[3]; GeoUtils.geo2xyzWGS84(geoPos.getLat(), geoPos.getLon(), alt, earthPoint); final double zeroDopplerTime = SARGeocoding.getEarthPointZeroDopplerTime(firstLineTime, lineTimeInterval, radarWaveLength, earthPoint, sensorPosition, sensorVelocity); if (zeroDopplerTime == SARGeocoding.NonValidZeroDopplerTime) { continue; } final double slantRange = SARGeocoding.computeSlantRange(zeroDopplerTime, timeArray, xPosArray, yPosArray, zPosArray, earthPoint, sensorPos); final double zeroDopplerTimeWithoutBias = zeroDopplerTime + slantRange / Constants.lightSpeedInMetersPerDay; absShift = (zeroDopplerTimeWithoutBias - firstLineTime) / lineTimeInterval - y; return; } absShift = computeFAQShift(v, 0); } /** * Get orbit state vector for given time. * @param time The given time. * @return Orbit state vector. */ private stateVector getOrbitStateVector(final double time) { final double[] weight = MathUtils.lagrangeWeight(timeArray, time); final PosVector pos = new PosVector(); MathUtils.lagrangeInterpolatingPolynomial(xPosArray, yPosArray, zPosArray, weight, pos); final PosVector vel = new PosVector(); MathUtils.lagrangeInterpolatingPolynomial(xVelArray, yVelArray, zVelArray, weight, vel); return new stateVector(time, pos.x, pos.y, pos.z, vel.x, vel.y, vel.z); } /** * Compute orbit state vector for given time using interpolation of two given vectors. * @param v1 First given vector. * @param v2 Second given vector. * @param time The given time. * @return The interpolated vector. */ private static stateVector vectorInterpolation(final AbstractMetadata.OrbitStateVector v1, final AbstractMetadata.OrbitStateVector v2, final double time) { final double[] pos1 = { v1.x_pos, v1.y_pos, v1.z_pos }; final double[] vel1 = { v1.x_vel, v1.y_vel, v1.z_vel }; final double[] pos2 = { v2.x_pos, v2.y_pos, v2.z_pos }; final double[] vel2 = { v2.x_vel, v2.y_vel, v2.z_vel }; final double t = time; final double t1 = v1.time.getMJD(); final double t2 = v2.time.getMJD(); final double dt = t2 - t1; final double alpha = (t - t1) / dt; final double alpha2 = alpha * alpha; final double alpha3 = alpha2 * alpha; final double[] pos = new double[3]; final double[] vel = new double[3]; double a0, a1, a2, a3; for (int i = 0; i < 3; i++) { a0 = pos1[i]; a1 = vel1[i] * dt; a2 = -3 * pos1[i] + 3 * pos2[i] - 2 * vel1[i] * dt - vel2[i] * dt; a3 = 2 * pos1[i] - 2 * pos2[i] + vel1[i] * dt + vel2[i] * dt; pos[i] = a0 + a1 * alpha + a2 * alpha2 + a3 * alpha3; vel[i] = (a1 + 2 * a2 * alpha + 3 * a3 * alpha2) / dt; } return new stateVector(time, pos[0], pos[1], pos[2], vel[0], vel[1], vel[2]); } private double getDopplerFrequency(final int x) { return dopplerCentroidCoefficientLists[0].coefficients[0] + dopplerCentroidCoefficientLists[0].coefficients[1] * x + dopplerCentroidCoefficientLists[0].coefficients[2] * x * x; } private void computeLookYawAngles(final stateVector v, final double slant, final double dopp, double[] lookYaw) { int iterations = 0, max_iter = 10000; double yaw = 0, deltaAz; final double[] look = { 0 }; double dopGuess, deltaDop, prevDeltaDop = -9999999; final double[] vRel = new double[3]; final double lambda = radarWaveLength; while (true) { double relativeVelocity; boolean succeed = getLook(v, slant, yaw, look); if (!succeed) { break; } dopGuess = getDoppler(v, look[0], yaw, vRel, radarWaveLength); deltaDop = dopp - dopGuess; relativeVelocity = Math.sqrt(vRel[0] * vRel[0] + vRel[1] * vRel[1] + vRel[2] * vRel[2]); deltaAz = deltaDop * (lambda / (2.0 * relativeVelocity)); if (Math.abs(deltaDop + prevDeltaDop) < 0.000001) { deltaAz /= 2.0; } if (Math.abs(deltaAz * slant) < 0.1) { break; } yaw += deltaAz; if (++iterations > max_iter) { break; } prevDeltaDop = deltaDop; } lookYaw[0] = look[0]; lookYaw[1] = yaw; } private boolean getLook(final stateVector v, final double slant, final double yaw, final double[] plook) { final GeoCoding geoCoding = sourceProduct.getGeoCoding(); if (geoCoding == null) { throw new OperatorException("GeoCoding is null"); } final GeoPos geoPos = geoCoding.getGeoPos(new PixelPos(0, 0), null); final double earthRadius = computeEarthRadius(geoPos); final double ht = Math.sqrt(v.xPos * v.xPos + v.yPos * v.yPos + v.zPos * v.zPos); double look = FastMath.acos((ht * ht + slant * slant - earthRadius * earthRadius) / (2.0 * slant * ht)); for (int iter = 0; iter < 100; iter++) { double delta_range = slant - calcRange(v, look, yaw); if (Math.abs(delta_range) < 0.1) { plook[0] = look; return true; } else { double sininc = (ht / earthRadius) * FastMath.sin(look); double taninc = sininc / Math.sqrt(1 - sininc * sininc); look += delta_range / (slant * taninc); } } return false; } private static double calcRange(final stateVector v, final double look, final double yaw) { final double[][] rM = new double[3][3]; getRotationMatrix(v, rM); final double cosyaw = FastMath.cos(yaw); final double x = FastMath.sin(yaw); final double y = -FastMath.sin(look) * cosyaw; final double z = -FastMath.cos(look) * cosyaw; final double rx = rM[0][0] * x + rM[1][0] * y + rM[2][0] * z; final double ry = rM[0][1] * x + rM[1][1] * y + rM[2][1] * z; final double rz = rM[0][2] * x + rM[1][2] * y + rM[2][2] * z; final double re = GeoUtils.WGS84.a; final double rp = re - re / GeoUtils.WGS84.b; final double re2 = re * re; final double rp2 = rp * rp; final double a = (rx * rx + ry * ry) / re2 + rz * rz / rp2; final double b = 2.0 * ((v.xPos * rx + v.yPos * ry) / re2 + v.zPos * rz / rp2); final double c = (v.xPos * v.xPos + v.yPos * v.yPos) / re2 + v.zPos * v.zPos / rp2 - 1.0; final double d = (b * b - 4.0 * a * c); if (d < 0) { return -1.0; } final double sqrtD = Math.sqrt(d); final double ans1 = (-b + sqrtD) / (2.0 * a); final double ans2 = (-b - sqrtD) / (2.0 * a); return Math.min(ans1, ans2); } private static void getRotationMatrix(final stateVector v, double[][] rM) { final double[] ax = new double[3]; final double[] ay = new double[3]; final double[] az = { v.xPos, v.yPos, v.zPos }; final double[] vl = { v.xVel, v.yVel, v.zVel }; MathUtils.normalizeVector(az); MathUtils.normalizeVector(vl); crossProduct(az, vl, ay); crossProduct(ay, az, ax); for (int i = 0; i < 3; i++) { rM[0][i] = ax[i]; rM[1][i] = ay[i]; rM[2][i] = az[i]; } } private static void crossProduct(final double[] a, final double[] b, final double[] c) { c[0] = a[1] * b[2] - a[2] * b[1]; c[1] = a[2] * b[0] - a[0] * b[2]; c[2] = a[0] * b[1] - a[1] * b[0]; } private static double getDoppler(final stateVector v, final double look, final double yaw, final double[] relVel, final double lambda) { final double spx = v.xPos, spy = v.yPos, spz = v.zPos; final double svx = v.xVel, svy = v.yVel, svz = v.zVel; final double x = FastMath.sin(yaw); final double y = -FastMath.sin(look) * FastMath.cos(yaw); final double z = -FastMath.cos(look) * FastMath.cos(yaw); final double[][] rM = new double[3][3]; getRotationMatrix(v, rM); double rpx = rM[0][0] * x + rM[1][0] * y + rM[2][0] * z; double rpy = rM[0][1] * x + rM[1][1] * y + rM[2][1] * z; double rpz = rM[0][2] * x + rM[1][2] * y + rM[2][2] * z; final double range = calcRange(v, look, yaw); rpx *= range; rpy *= range; rpz *= range; final double tpx = rpx + spx; final double tpy = rpy + spy; final double tpz = rpz + spz; final double tvx = -AngularVelocity * tpy; final double tvy = AngularVelocity * tpx; final double tvz = 0.0; final double rvx = tvx - svx; final double rvy = tvy - svy; final double rvz = tvz - svz; relVel[0] = rvx; relVel[1] = rvy; relVel[2] = rvz; return -2.0 / (lambda * range) * (rpx * rvx + rpy * rvy + rpz * rvz); } private static double getAngularVelocity() { final double dayLength = 24.0 * 60.0 * 60.0; return (366.225 / 365.225) * 2 * Math.PI / dayLength; } /** * Compute Earth radius for pixel at (0,0). * @param geoPos lat lon position * @return The Earth radius. */ private static double computeEarthRadius(final GeoPos geoPos) { final double lat = geoPos.lat; final double re = Constants.semiMajorAxis; final double rp = Constants.semiMinorAxis; return (re * rp) / Math.sqrt( rp * rp * FastMath.cos(lat) * FastMath.cos(lat) + re * re * FastMath.sin(lat) * FastMath.sin(lat)); } public static class stateVector { public double xPos; public double yPos; public double zPos; public double xVel; public double yVel; public double zVel; public double time; public stateVector(final double time, final double xPos, final double yPos, final double zPos, final double xVel, final double yVel, final double zVel) { this.time = time; this.xPos = xPos; this.yPos = yPos; this.zPos = zPos; this.xVel = xVel; this.yVel = yVel; this.zVel = zVel; } } /** * The SPI is used to register this operator in the graph processing framework * via the SPI configuration file * {@code META-INF/services/org.esa.beam.framework.gpf.OperatorSpi}. * This class may also serve as a factory for new operator instances. * @see org.esa.beam.framework.gpf.OperatorSpi#createOperator() * @see org.esa.beam.framework.gpf.OperatorSpi#createOperator(java.util.Map, java.util.Map) */ public static class Spi extends OperatorSpi { public Spi() { super(ALOSDeskewingOp.class); this.setOperatorUI(ALOSDeskewingUI.class); } } }