package org.openstreetmap.josm.plugins.piclayer.transform; import java.awt.geom.AffineTransform; import java.awt.geom.Point2D; import java.util.ArrayList; import java.util.List; import org.openstreetmap.josm.data.coor.EastNorth; public class PictureTransform { private AffineTransform cachedTransform; private EastNorth imagePosition; public EastNorth getImagePosition() { return imagePosition; } public void setImagePosition(EastNorth imagePosition) { this.imagePosition = imagePosition; } private boolean modified = false; private List<Point2D> originPoints; public PictureTransform() { cachedTransform = new AffineTransform(); originPoints = new ArrayList<>(3); } public AffineTransform getTransform() { return cachedTransform; } private AffineTransform solveEquation(List<Point2D> desiredPoints) throws NoSolutionException { Matrix3D X = new Matrix3D(originPoints); Matrix3D Y = new Matrix3D(desiredPoints); Matrix3D result = Y.multiply(X.inverse()); return result.toAffineTransform(); } public void addOriginPoint(Point2D originPoint) { if (originPoints.size() < 3) originPoints.add(originPoint); } public void resetCalibration() { originPoints.clear(); modified = false; cachedTransform = new AffineTransform(); } /** * updates pair of points (suppose that other pairs are (origin=>origin) points are the same), * solves equation, * applies transform matrix to the existing cachedTransform * * @param originPoint - should be one of origin points, otherwise - no transform applied * @param desiredPoint - new place for the point */ public void updatePair(Point2D originPoint, Point2D desiredPoint) { if (originPoint == null) return; switch (originPoints.size()) { case 1: { cachedTransform.concatenate(AffineTransform.getTranslateInstance(desiredPoint.getX()-originPoint.getX(), desiredPoint.getY()-originPoint.getY())); break; } case 2: { // find triangle and move it List<Point2D> desiredPoints = new ArrayList<>(3); Point2D o1 = originPoints.get(0); Point2D o2 = originPoints.get(1); Point2D d1, d2; if (o2 == originPoint) { d2 = desiredPoint; d1 = (Point2D) o1.clone(); } else { d1 = desiredPoint; d2 = (Point2D) o2.clone(); } Point2D o3 = calculateTrianglePoint(o1, o2); Point2D d3 = calculateTrianglePoint(d1, d2); originPoints.add(o3); desiredPoints.add(d1); desiredPoints.add(d2); desiredPoints.add(d3); trySolve(desiredPoints); originPoints.remove(2); break; } case 3: { List<Point2D> desiredPoints = new ArrayList<>(3); for (Point2D origin : originPoints) { if (origin.equals(originPoint)) desiredPoints.add(desiredPoint); else desiredPoints.add(origin); } trySolve(desiredPoints); break; } default: } } private Point2D calculateTrianglePoint(Point2D d1, Point2D d2) { Point2D result; if (d1 instanceof Point2D.Double) { result = new Point2D.Double(); } else { result = new Point2D.Float(); } result.setLocation((d1.getX()+d2.getX()-d2.getY()+d1.getY())/2, (d1.getY()+d2.getY()+d2.getX()-d1.getX())/2); return result; } private void trySolve(List<Point2D> desiredPoints) { if (desiredPoints.size() == 3 && originPoints.size() == 3) { try { cachedTransform.concatenate(solveEquation(desiredPoints)); modified = true; desiredPoints.clear(); } catch (NoSolutionException e) { System.err.println(e.getMessage()); } } } public void replaceOriginPoint(Point2D originPoint, Point2D newOriginPoint) { if (originPoint == null || newOriginPoint == null) return; int index = originPoints.indexOf(originPoint); if (index < 0) return; originPoints.set(index, newOriginPoint); } public void concatenateTransformPoint(AffineTransform transform, Point2D trans) { if (trans != null) { AffineTransform centered = AffineTransform.getTranslateInstance(trans.getX(), trans.getY()); centered.concatenate(transform); centered.translate(-trans.getX(), -trans.getY()); cachedTransform.concatenate(centered); } else { cachedTransform.concatenate(transform); } for (int i = 0; i < originPoints.size(); i++) { Point2D point = originPoints.get(i); transform.transform(point, point); } modified = true; } public boolean isModified() { return modified; } public void setModified() { modified = true; } public void resetModified() { modified = false; } public void setTransform(AffineTransform newTransform) { cachedTransform = new AffineTransform(newTransform); } public List<Point2D> getOriginPoints() { return originPoints; } public void setOriginPoints(List<Point2D> list) { this.originPoints = new ArrayList<>(list); } public void removeOriginPoint(Point2D selectedPoint) { originPoints.remove(selectedPoint); } }