List of usage examples for java.awt.geom AffineTransform inverseTransform
@SuppressWarnings("fallthrough") public Point2D inverseTransform(Point2D ptSrc, Point2D ptDst) throws NoninvertibleTransformException
From source file:MathFunctions.java
public static AffineTransform generateAffineTransformFromPointPairs( Map<Point2D.Double, Point2D.Double> pointPairs, double srcTol, double destTol) throws Exception { AffineTransform transform = generateAffineTransformFromPointPairs(pointPairs); double srcDevSqSum = 0; double destDevSqSum = 0; for (Map.Entry pair : pointPairs.entrySet()) { try {/*from w w w .j a v a2 s . c om*/ Point2D.Double srcPt = (Point2D.Double) pair.getKey(); Point2D.Double destPt = (Point2D.Double) pair.getValue(); Point2D.Double srcPt2 = (Point2D.Double) transform.inverseTransform(destPt, null); Point2D.Double destPt2 = (Point2D.Double) transform.transform(srcPt, null); srcDevSqSum += srcPt.distanceSq(srcPt2); destDevSqSum += destPt.distanceSq(destPt2); } catch (NoninvertibleTransformException ex) { throw new Exception(); } } int n = pointPairs.size(); double srcRMS = Math.sqrt(srcDevSqSum / n); double destRMS = Math.sqrt(destDevSqSum / n); if (srcRMS > srcTol || destRMS > destTol) { throw new Exception("Point mapping scatter exceeds tolerance."); } return transform; }
From source file:org.esa.snap.rcp.statistics.ScatterPlotPanel.java
private void compute(final Mask selectedMask) { final RasterDataNode raster = getRaster(); final AttributeDescriptor dataField = scatterPlotModel.dataField; if (raster == null || dataField == null) { return;//from ww w . j a v a2 s . c o m } SwingWorker<ComputedData[], Object> swingWorker = new SwingWorker<ComputedData[], Object>() { @Override protected ComputedData[] doInBackground() throws Exception { SystemUtils.LOG.finest("start computing scatter plot data"); final List<ComputedData> computedDataList = new ArrayList<>(); final FeatureCollection<SimpleFeatureType, SimpleFeature> collection = scatterPlotModel.pointDataSource .getFeatureCollection(); final SimpleFeature[] features = collection.toArray(new SimpleFeature[collection.size()]); final int boxSize = scatterPlotModel.boxSize; final Rectangle sceneRect = new Rectangle(raster.getRasterWidth(), raster.getRasterHeight()); final GeoCoding geoCoding = raster.getGeoCoding(); final AffineTransform imageToModelTransform; imageToModelTransform = Product.findImageToModelTransform(geoCoding); for (SimpleFeature feature : features) { final Point point = (Point) feature.getDefaultGeometryProperty().getValue(); Point2D modelPos = new Point2D.Float((float) point.getX(), (float) point.getY()); final Point2D imagePos = imageToModelTransform.inverseTransform(modelPos, null); if (!sceneRect.contains(imagePos)) { continue; } final float imagePosX = (float) imagePos.getX(); final float imagePosY = (float) imagePos.getY(); final Rectangle imageRect = sceneRect.intersection(new Rectangle( ((int) imagePosX) - boxSize / 2, ((int) imagePosY) - boxSize / 2, boxSize, boxSize)); if (imageRect.isEmpty()) { continue; } final double[] rasterValues = new double[imageRect.width * imageRect.height]; raster.readPixels(imageRect.x, imageRect.y, imageRect.width, imageRect.height, rasterValues); final int[] maskBuffer = new int[imageRect.width * imageRect.height]; Arrays.fill(maskBuffer, 1); if (selectedMask != null) { selectedMask.readPixels(imageRect.x, imageRect.y, imageRect.width, imageRect.height, maskBuffer); } final int centerIndex = imageRect.width * (imageRect.height / 2) + (imageRect.width / 2); if (maskBuffer[centerIndex] == 0) { continue; } double sum = 0; double sumSqr = 0; int n = 0; boolean valid = false; for (int y = 0; y < imageRect.height; y++) { for (int x = 0; x < imageRect.width; x++) { final int index = y * imageRect.height + x; if (raster.isPixelValid(x + imageRect.x, y + imageRect.y) && maskBuffer[index] != 0) { final double rasterValue = rasterValues[index]; sum += rasterValue; sumSqr += rasterValue * rasterValue; n++; valid = true; } } } if (!valid) { continue; } double rasterMean = sum / n; double rasterSigma = n > 1 ? Math.sqrt((sumSqr - (sum * sum) / n) / (n - 1)) : 0.0; String localName = dataField.getLocalName(); Number attribute = (Number) feature.getAttribute(localName); final Collection<org.opengis.feature.Property> featureProperties = feature.getProperties(); final float correlativeData = attribute.floatValue(); final GeoPos geoPos = new GeoPos(); if (geoCoding.canGetGeoPos()) { final PixelPos pixelPos = new PixelPos(imagePosX, imagePosY); geoCoding.getGeoPos(pixelPos, geoPos); } else { geoPos.setInvalid(); } computedDataList.add( new ComputedData(imagePosX, imagePosY, (float) geoPos.getLat(), (float) geoPos.getLon(), (float) rasterMean, (float) rasterSigma, correlativeData, featureProperties)); } return computedDataList.toArray(new ComputedData[computedDataList.size()]); } @Override public void done() { try { final ValueAxis xAxis = getPlot().getDomainAxis(); final ValueAxis yAxis = getPlot().getRangeAxis(); xAxis.setAutoRange(false); yAxis.setAutoRange(false); scatterpointsDataset.removeAllSeries(); acceptableDeviationDataset.removeAllSeries(); regressionDataset.removeAllSeries(); getPlot().removeAnnotation(r2Annotation); computedDatas = null; final ComputedData[] data = get(); if (data.length == 0) { return; } computedDatas = data; final XYIntervalSeries scatterValues = new XYIntervalSeries(getCorrelativeDataName()); for (ComputedData computedData : computedDatas) { final float rasterMean = computedData.rasterMean; final float rasterSigma = computedData.rasterSigma; final float correlativeData = computedData.correlativeData; scatterValues.add(correlativeData, correlativeData, correlativeData, rasterMean, rasterMean - rasterSigma, rasterMean + rasterSigma); } computingData = true; scatterpointsDataset.addSeries(scatterValues); xAxis.setAutoRange(true); yAxis.setAutoRange(true); xAxis.setAutoRange(false); yAxis.setAutoRange(false); xAutoRangeAxisRange = new Range(xAxis.getLowerBound(), xAxis.getUpperBound()); yAutoRangeAxisRange = new Range(yAxis.getLowerBound(), yAxis.getUpperBound()); if (xAxisRangeControl.isAutoMinMax()) { xAxisRangeControl.adjustComponents(xAxis, 3); } else { xAxisRangeControl.adjustAxis(xAxis, 3); } if (yAxisRangeControl.isAutoMinMax()) { yAxisRangeControl.adjustComponents(yAxis, 3); } else { yAxisRangeControl.adjustAxis(yAxis, 3); } computeRegressionAndAcceptableDeviationData(); computingData = false; } catch (InterruptedException | CancellationException e) { SystemUtils.LOG.log(Level.WARNING, "Failed to compute correlative plot.", e); Dialogs.showMessage(CHART_TITLE, "Failed to compute correlative plot.\n" + "Calculation canceled.", JOptionPane.ERROR_MESSAGE, null); } catch (ExecutionException e) { SystemUtils.LOG.log(Level.WARNING, "Failed to compute correlative plot.", e); Dialogs.showMessage(CHART_TITLE, "Failed to compute correlative plot.\n" + "An error occurred:\n" + e.getCause().getMessage(), JOptionPane.ERROR_MESSAGE, null); } } }; swingWorker.execute(); }
From source file:org.esa.beam.visat.toolviews.stat.ScatterPlotPanel.java
private void compute(final Mask selectedMask) { final RasterDataNode raster = getRaster(); final AttributeDescriptor dataField = scatterPlotModel.dataField; if (raster == null || dataField == null) { return;// www . j a v a 2s .c o m } SwingWorker<ComputedData[], Object> swingWorker = new SwingWorker<ComputedData[], Object>() { @Override protected ComputedData[] doInBackground() throws Exception { BeamLogManager.getSystemLogger().finest("start computing scatter plot data"); final List<ComputedData> computedDataList = new ArrayList<>(); final FeatureCollection<SimpleFeatureType, SimpleFeature> collection = scatterPlotModel.pointDataSource .getFeatureCollection(); final SimpleFeature[] features = collection.toArray(new SimpleFeature[collection.size()]); final int boxSize = scatterPlotModel.boxSize; final Rectangle sceneRect = new Rectangle(raster.getSceneRasterWidth(), raster.getSceneRasterHeight()); final GeoCoding geoCoding = raster.getGeoCoding(); final AffineTransform imageToModelTransform; imageToModelTransform = ImageManager.getImageToModelTransform(geoCoding); for (SimpleFeature feature : features) { final Point point = (Point) feature.getDefaultGeometryProperty().getValue(); Point2D modelPos = new Point2D.Float((float) point.getX(), (float) point.getY()); final Point2D imagePos = imageToModelTransform.inverseTransform(modelPos, null); if (!sceneRect.contains(imagePos)) { continue; } final float imagePosX = (float) imagePos.getX(); final float imagePosY = (float) imagePos.getY(); final Rectangle imageRect = sceneRect.intersection(new Rectangle( ((int) imagePosX) - boxSize / 2, ((int) imagePosY) - boxSize / 2, boxSize, boxSize)); if (imageRect.isEmpty()) { continue; } final double[] rasterValues = new double[imageRect.width * imageRect.height]; raster.readPixels(imageRect.x, imageRect.y, imageRect.width, imageRect.height, rasterValues); final int[] maskBuffer = new int[imageRect.width * imageRect.height]; Arrays.fill(maskBuffer, 1); if (selectedMask != null) { selectedMask.readPixels(imageRect.x, imageRect.y, imageRect.width, imageRect.height, maskBuffer); } final int centerIndex = imageRect.width * (imageRect.height / 2) + (imageRect.width / 2); if (maskBuffer[centerIndex] == 0) { continue; } double sum = 0; double sumSqr = 0; int n = 0; boolean valid = false; for (int y = 0; y < imageRect.height; y++) { for (int x = 0; x < imageRect.width; x++) { final int index = y * imageRect.height + x; if (raster.isPixelValid(x + imageRect.x, y + imageRect.y) && maskBuffer[index] != 0) { final double rasterValue = rasterValues[index]; sum += rasterValue; sumSqr += rasterValue * rasterValue; n++; valid = true; } } } if (!valid) { continue; } double rasterMean = sum / n; double rasterSigma = n > 1 ? Math.sqrt((sumSqr - (sum * sum) / n) / (n - 1)) : 0.0; String localName = dataField.getLocalName(); Number attribute = (Number) feature.getAttribute(localName); final Collection<org.opengis.feature.Property> featureProperties = feature.getProperties(); final float correlativeData = attribute.floatValue(); final GeoPos geoPos = new GeoPos(); if (geoCoding.canGetGeoPos()) { final PixelPos pixelPos = new PixelPos(imagePosX, imagePosY); geoCoding.getGeoPos(pixelPos, geoPos); } else { geoPos.setInvalid(); } computedDataList.add(new ComputedData(imagePosX, imagePosY, geoPos.getLat(), geoPos.getLon(), (float) rasterMean, (float) rasterSigma, correlativeData, featureProperties)); } return computedDataList.toArray(new ComputedData[computedDataList.size()]); } @Override public void done() { try { final ValueAxis xAxis = getPlot().getDomainAxis(); final ValueAxis yAxis = getPlot().getRangeAxis(); xAxis.setAutoRange(false); yAxis.setAutoRange(false); scatterpointsDataset.removeAllSeries(); acceptableDeviationDataset.removeAllSeries(); regressionDataset.removeAllSeries(); getPlot().removeAnnotation(r2Annotation); computedDatas = null; final ComputedData[] data = get(); if (data.length == 0) { return; } computedDatas = data; final XYIntervalSeries scatterValues = new XYIntervalSeries(getCorrelativeDataName()); for (ComputedData computedData : computedDatas) { final float rasterMean = computedData.rasterMean; final float rasterSigma = computedData.rasterSigma; final float correlativeData = computedData.correlativeData; scatterValues.add(correlativeData, correlativeData, correlativeData, rasterMean, rasterMean - rasterSigma, rasterMean + rasterSigma); } computingData = true; scatterpointsDataset.addSeries(scatterValues); xAxis.setAutoRange(true); yAxis.setAutoRange(true); xAxis.setAutoRange(false); yAxis.setAutoRange(false); xAutoRangeAxisRange = new Range(xAxis.getLowerBound(), xAxis.getUpperBound()); yAutoRangeAxisRange = new Range(yAxis.getLowerBound(), yAxis.getUpperBound()); if (xAxisRangeControl.isAutoMinMax()) { xAxisRangeControl.adjustComponents(xAxis, 3); } else { xAxisRangeControl.adjustAxis(xAxis, 3); } if (yAxisRangeControl.isAutoMinMax()) { yAxisRangeControl.adjustComponents(yAxis, 3); } else { yAxisRangeControl.adjustAxis(yAxis, 3); } computeRegressionAndAcceptableDeviationData(); computingData = false; } catch (InterruptedException | CancellationException e) { BeamLogManager.getSystemLogger().log(Level.WARNING, "Failed to compute correlative plot.", e); JOptionPane.showMessageDialog(getParentDialogContentPane(), "Failed to compute correlative plot.\n" + "Calculation canceled.", /*I18N*/ CHART_TITLE, /*I18N*/ JOptionPane.ERROR_MESSAGE); } catch (ExecutionException e) { BeamLogManager.getSystemLogger().log(Level.WARNING, "Failed to compute correlative plot.", e); JOptionPane.showMessageDialog(getParentDialogContentPane(), "Failed to compute correlative plot.\n" + "An error occurred:\n" + e.getCause().getMessage(), CHART_TITLE, /*I18N*/ JOptionPane.ERROR_MESSAGE); } } }; swingWorker.execute(); }
From source file:org.jcurl.core.base.Collider.java
/** * Check distance, speed of approach, transform speeds to rock-coordinates, * call {@link #computeRC(Rock, Rock)}and transform back to wc afterwards. * //from www.j a v a 2 s .c o m * @param xa * @param xb * @param va * @param vb * @param mat * may be null. If not avoids frequent instanciations * @return <code>true</code> hit, <code>false</code> no hit. */ public boolean computeWC(final Rock xa, final Rock xb, final Rock va, final Rock vb, AffineTransform mat) { if (mat == null) mat = new AffineTransform(); // check distance if (xa.distanceSq(xb) > MaxDistSq) { if (log.isDebugEnabled()) log.debug("Too far away distance=" + (xa.distance(xb) - (_Rad + _Rad))); return false; } // change the coordinate system to rock-coordinates final Rock _va = (Rock) va.clone(); final Rock _vb = (Rock) vb.clone(); getInverseTrafo(vb, xa, xb, mat); try { // transform mat.inverseTransform(va, _va); mat.inverseTransform(vb, _vb); } catch (NoninvertibleTransformException e) { throw new RuntimeException("Matrix must be invertible", e); } // check speed of approach if (!_va.nonZero()) return false; if (log.isDebugEnabled()) log.debug("hit!"); // physical model computeRC(_va, _vb); // re-transform mat.transform(_va, va); va.setZ(_va.getZ()); mat.transform(_vb, vb); vb.setZ(_vb.getZ()); return true; }
From source file:org.jcurl.core.base.ColliderBase.java
/** * Check distance, speed of approach, transform speeds to rock-coordinates, * call {@link #computeRC(Rock, Rock)}and transform back to wc afterwards. * /* w w w . j a v a 2 s.co m*/ * @param xa * @param xb * @param va * @param vb * @param mat * may be null. If not avoids frequent instanciations * @return <code>true</code> hit, <code>false</code> no hit. */ protected boolean computeWC(final Rock xa, final Rock xb, final Rock va, final Rock vb, AffineTransform mat) { if (mat == null) mat = new AffineTransform(); // check distance if (xa.distanceSq(xb) > MaxDistSq) { if (log.isDebugEnabled()) log.debug("Too far away distance=" + (xa.distance(xb) - (_Rad + _Rad))); return false; } // change the coordinate system to rock-coordinates final Rock _va = (Rock) va.clone(); final Rock _vb = (Rock) vb.clone(); getInverseTrafo(vb, xa, xb, mat); try { // transform mat.inverseTransform(va, _va); mat.inverseTransform(vb, _vb); } catch (final NoninvertibleTransformException e) { throw new RuntimeException("Matrix must be invertible", e); } // check speed of approach if (!_va.nonZero()) return false; if (log.isDebugEnabled()) log.debug("hit!"); // physical model computeRC(_va, _vb); // re-transform mat.transform(_va, va); va.setZ(_va.getZ()); // FIXME apply angle delta from Collission coordinates to WC mat.transform(_vb, vb); vb.setZ(_vb.getZ()); // FIXME apply angle delta from Collission coordinates to WC return true; }
From source file:org.jcurl.core.base.CollissionStrategy.java
/** * Check distance, speed of approach, transform speeds to rock-coordinates, * call {@link #computeRC(Rock, Rock)}and transform back to wc afterwards. * /*from www . j a v a2 s. c om*/ * @param xa * @param xb * @param va * @param vb * @param mat * may be null. If not avoids frequent instanciations * @return <code>true</code> hit, <code>false</code> no hit. */ protected boolean computeWC(final Rock xa, final Rock xb, final Rock va, final Rock vb, AffineTransform mat) { if (mat == null) mat = new AffineTransform(); // check distance if (xa.distanceSq(xb) > MaxDistSq) { if (log.isDebugEnabled()) log.debug("Too far away distance=" + (xa.distance(xb) - (_Rad + _Rad))); return false; } // change the coordinate system to rock-coordinates final Rock _va = (Rock) va.clone(); final Rock _vb = (Rock) vb.clone(); getInverseTrafo(vb, xa, xb, mat); try { // transform mat.inverseTransform(va, _va); mat.inverseTransform(vb, _vb); } catch (NoninvertibleTransformException e) { throw new RuntimeException("Matrix must be invertible", e); } // check speed of approach if (!_va.nonZero()) return false; if (log.isDebugEnabled()) log.debug("hit!"); // physical model computeRC(_va, _vb); // re-transform mat.transform(_va, va); va.setZ(_va.getZ()); mat.transform(_vb, vb); vb.setZ(_vb.getZ()); return true; }
From source file:org.jcurl.core.impl.ColliderBase.java
/** * Check distance, speed of approach, transform speeds to * collission-coordinates, call {@link #computeCC(Rock, Rock)} and transform * back to wc afterwards.//from w ww . ja v a 2 s. c o m * <p> * The angle (not the angular speed!) remains in WC and untouched! * </p> * * @param xa * position before the hit (WC) * @param xb * position before the hit (WC) * @param va * speed before the hit (CC) * @param vb * speed before the hit (usually zero) * @param mat * may be null. If not avoids frequent instanciations * @return <code>true</code> hit, <code>false</code> no hit. */ protected boolean computeWC(final Rock<Pos> xa, final Rock<Pos> xb, final Rock<Vel> va, final Rock<Vel> vb, AffineTransform mat) { if (mat == null) mat = new AffineTransform(); // check distance if (xa.p().distanceSq(xb.p()) > MaxDistSq) { if (log.isDebugEnabled()) log.debug("Too far away distance=" + (xa.p().distance(xb.p()) - (_Rad + _Rad))); return false; } // change the coordinate system to collission-coordinates final Rock<Vel> _va = (Rock<Vel>) va.clone(); final Rock<Vel> _vb = (Rock<Vel>) vb.clone(); getInverseTrafo(vb.p(), xa.p(), xb.p(), mat); try { // transform mat.inverseTransform(va.p(), _va.p()); mat.inverseTransform(vb.p(), _vb.p()); } catch (final NoninvertibleTransformException e) { throw new RuntimeException("Matrix must be invertible", e); } // check speed of approach if (!_va.isNotZero()) return false; if (log.isDebugEnabled()) log.debug("hit!"); // physical model computeCC(_va, _vb); // re-transform mat.transform(_va.p(), va.p()); va.setA(_va.getA()); mat.transform(_vb.p(), vb.p()); vb.setA(_vb.getA()); return true; }
From source file:org.jcurl.model.PathSegmentTest.java
public void testTrafo() throws NoninvertibleTransformException { final Point2D x0 = new Point2D.Double(1.5, 2.5); // final Point2D x0 = new Point2D.Double(0, 0); final Point2D v0 = new Point2D.Double(2, 1); // build the trafo final AffineTransform rc2wc = new AffineTransform(); {/*from ww w. j av a 2 s . co m*/ rc2wc.rotate(-Math.acos((v0.getX() * 0 + v0.getY() * 1) / v0.distance(0, 0)), x0.getX(), x0.getY()); rc2wc.translate(x0.getX(), x0.getY()); } // check some points. // wc(x0) -> rc(0,0) Point2D tmp = rc2wc.inverseTransform(x0, null); assertEquals("", 0, tmp.getX(), 1e-9); assertEquals("", 0, tmp.getY(), 1e-9); // rc(0,1) -> wc(x0) tmp = rc2wc.transform(new Point2D.Double(0, 1), null); assertEquals("", x0.getX() + 0.8944271909999, tmp.getX(), 1e-6); assertEquals("", x0.getY() + 0.4472135954999, tmp.getY(), 1e-6); }
From source file:org.micromanager.plugins.magellan.propsandcovariants.SurfaceData.java
public double[] curvedSurfacePower(AcquisitionEvent event, double multiplier) { XYStagePosition xyPos = event.xyPosition_; double zPosition = event.zPosition_; Point2D.Double[] corners = xyPos.getFullTileCorners(); //square is aligned with axes in pixel space, so convert to pixel space to generate test points double xSpan = corners[2].getX() - corners[0].getX(); double ySpan = corners[2].getY() - corners[0].getY(); Point2D.Double pixelSpan = new Point2D.Double(); AffineTransform transform = AffineUtils.getAffineTransform(surface_.getCurrentPixelSizeConfig(), 0, 0); try {/*from w w w . j av a2 s . c o m*/ transform.inverseTransform(new Point2D.Double(xSpan, ySpan), pixelSpan); } catch (NoninvertibleTransformException ex) { Log.log("Problem inverting affine transform"); } double[] relativePower = new double[FOV_LASER_MODULATION_RESOLUTION * FOV_LASER_MODULATION_RESOLUTION]; for (int xInd = 0; xInd < FOV_LASER_MODULATION_RESOLUTION; xInd++) { for (int yInd = 0; yInd < FOV_LASER_MODULATION_RESOLUTION; yInd++) { double x = ((0.5 + pixelSpan.x) / (double) FOV_LASER_MODULATION_RESOLUTION) * xInd; double y = ((0.5 + pixelSpan.y) / (double) FOV_LASER_MODULATION_RESOLUTION) * yInd; //convert these abritray pixel coordinates back to stage coordinates double[] transformMaxtrix = new double[6]; transform.getMatrix(transformMaxtrix); transformMaxtrix[4] = corners[0].getX(); transformMaxtrix[5] = corners[0].getY(); //create new transform with translation applied transform = new AffineTransform(transformMaxtrix); Point2D.Double stageCoords = new Point2D.Double(); transform.transform(new Point2D.Double(x, y), stageCoords); //Index in the way Teensy expects data int flatIndex = xInd + FOV_LASER_MODULATION_RESOLUTION * yInd; try { //test point for inclusion of position if (!surface_.waitForCurentInterpolation().isInterpDefined(stageCoords.x, stageCoords.y)) { //if position is outside of convex hull, use minimum laser power relativePower[flatIndex] = basePower_; } else { float interpVal = surface_.waitForCurentInterpolation().getInterpolatedValue(stageCoords.x, stageCoords.y); float normalAngle = surface_.waitForCurentInterpolation() .getNormalAngleToVertical(stageCoords.x, stageCoords.y); relativePower[flatIndex] = basePower_ * CurvedSurfaceCalculations.getRelativePower(meanFreePath_, Math.max(0, zPosition - interpVal), normalAngle, radiusOfCurvature_) * multiplier; } } catch (InterruptedException ex) { Log.log("Couldn't calculate curved surface power"); Log.log(ex); return null; } } } return relativePower; }
From source file:org.micromanager.plugins.magellan.propsandcovariants.SurfaceData.java
/** */*from w ww. ja va 2s. co m*/ * @param corners * @param min true to get min, false to get max * @return {minDistance,maxDistance, minNormalAngle, maxNormalAngle) */ private double[] distanceAndNormalCalc(Point2D.Double[] corners, double zVal) throws InterruptedException { //check a grid of points spanning entire position //square is aligned with axes in pixel space, so convert to pixel space to generate test points double xSpan = corners[2].getX() - corners[0].getX(); double ySpan = corners[2].getY() - corners[0].getY(); Point2D.Double pixelSpan = new Point2D.Double(); AffineTransform transform = AffineUtils.getAffineTransform(surface_.getCurrentPixelSizeConfig(), 0, 0); try { transform.inverseTransform(new Point2D.Double(xSpan, ySpan), pixelSpan); } catch (NoninvertibleTransformException ex) { Log.log("Problem inverting affine transform"); } double minDistance = Integer.MAX_VALUE; double maxDistance = 0; double minNormalAngle = 90; double maxNormalAngle = 0; for (double x = 0; x <= pixelSpan.x; x += pixelSpan.x / (double) NUM_XY_TEST_POINTS) { for (double y = 0; y <= pixelSpan.y; y += pixelSpan.y / (double) NUM_XY_TEST_POINTS) { //convert these abritray pixel coordinates back to stage coordinates double[] transformMaxtrix = new double[6]; transform.getMatrix(transformMaxtrix); transformMaxtrix[4] = corners[0].getX(); transformMaxtrix[5] = corners[0].getY(); //create new transform with translation applied transform = new AffineTransform(transformMaxtrix); Point2D.Double stageCoords = new Point2D.Double(); transform.transform(new Point2D.Double(x, y), stageCoords); //test point for inclusion of position if (!surface_.waitForCurentInterpolation().isInterpDefined(stageCoords.x, stageCoords.y)) { //if position is outside of convex hull, assume min distance is 0 minDistance = 0; //get extrapolated value for max distance float interpVal = surface_.getExtrapolatedValue(stageCoords.x, stageCoords.y); maxDistance = Math.max(zVal - interpVal, maxDistance); //only take actual values for normals } else { float interpVal = surface_.waitForCurentInterpolation().getInterpolatedValue(stageCoords.x, stageCoords.y); float normalAngle = surface_.waitForCurentInterpolation() .getNormalAngleToVertical(stageCoords.x, stageCoords.y); minDistance = Math.min(Math.max(0, zVal - interpVal), minDistance); maxDistance = Math.max(zVal - interpVal, maxDistance); minNormalAngle = Math.min(minNormalAngle, normalAngle); maxNormalAngle = Math.max(maxNormalAngle, normalAngle); } } } return new double[] { minDistance, maxDistance, minNormalAngle, maxNormalAngle }; }