/*
* Copyright (C) 2010 Brockmann Consult GmbH (info@brockmann-consult.de)
*
* 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 com.bc.ceres.grender.support;
import com.bc.ceres.grender.Viewport;
import org.junit.Test;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import static com.bc.ceres.glayer.Assert2D.assertEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.fail;
public class DefaultViewportTest {
@Test
public void testDefaultSettings() {
final DefaultViewport viewport = new DefaultViewport(true);
assertEquals(new AffineTransform(), viewport.getModelToViewTransform());
assertEquals(new AffineTransform(), viewport.getViewToModelTransform());
assertEquals(p(0.0, 0.0), getModelOffset(viewport));
assertEquals(1.0, viewport.getZoomFactor(), 1e-10);
}
@Test
public void testClone() {
final DefaultViewport viewport = new DefaultViewport(new Rectangle(40, 50), true);
viewport.setOrientation(0.3);
viewport.setZoomFactor(1.2);
viewport.setOffset(-4.0, 3.7);
viewport.setModelYAxisDown(true);
assertEquals(0.3, viewport.getOrientation(), 1e-10);
assertEquals(-4.0, viewport.getOffsetX(), 1e-10);
assertEquals(3.7, viewport.getOffsetY(), 1e-10);
assertEquals(1.2, viewport.getZoomFactor(), 1e-10);
assertEquals(true, viewport.isModelYAxisDown());
Viewport viewportClone = viewport.clone();
assertEquals(0.3, viewportClone.getOrientation(), 1e-10);
assertEquals(-4.0, viewportClone.getOffsetX(), 1e-10);
assertEquals(3.7, viewportClone.getOffsetY(), 1e-10);
assertEquals(1.2, viewportClone.getZoomFactor(), 1e-10);
assertEquals(true, viewportClone.isModelYAxisDown());
}
@Test
public void testTransformsAreNotLife() {
final DefaultViewport viewport = new DefaultViewport();
final AffineTransform m2v = viewport.getModelToViewTransform();
assertNotSame(m2v, viewport.getModelToViewTransform());
final AffineTransform v2u = viewport.getViewToModelTransform();
assertNotSame(v2u, viewport.getViewToModelTransform());
viewport.moveViewDelta(150.0, -10.0);
assertNotSame(m2v, viewport.getModelToViewTransform());
assertNotSame(v2u, viewport.getViewToModelTransform());
}
@Test
public void testInverse() {
final DefaultViewport viewport = new DefaultViewport(true);
final AffineTransform m2v = viewport.getModelToViewTransform();
assertNotSame(m2v, viewport.getModelToViewTransform());
final AffineTransform v2u = viewport.getViewToModelTransform();
assertNotSame(v2u, viewport.getViewToModelTransform());
viewport.moveViewDelta(150.0, -10.0);
assertEquals(p(-150, 10), t(viewport.getViewToModelTransform(), p(0, 0)));
assertEquals(p(0, 0), t(viewport.getModelToViewTransform(), p(-150, 10)));
assertEquals(p(150, -10), t(viewport.getModelToViewTransform(), p(0, 0)));
assertEquals(p(0.0, 0.0), t(viewport.getViewToModelTransform(), p(150, -10)));
}
@Test
public void testMove() {
final DefaultViewport viewport = new DefaultViewport(true);
viewport.moveViewDelta(15.0, 10.0);
assertEquals(p(-15.0, -10.0), getModelOffset(viewport));
viewport.moveViewDelta(-15.0, -10.0);
assertEquals(p(0.0, 0.0), getModelOffset(viewport));
}
@Test
public void testZoomFactor() {
final DefaultViewport viewport = new DefaultViewport(true);
Point2D vc, uc;
viewport.moveViewDelta(-10, -10);
/////////////////////////////
// view center 1
viewport.setViewBounds(new Rectangle(0, 0, 30, 20));
vc = p(15, 10);
uc = t(viewport.getViewToModelTransform(), vc);
viewport.setZoomFactor(0.5);
assertEquals(0.5, viewport.getZoomFactor(), 1e-10);
assertEquals(p(-5.0, 0.0), getModelOffset(viewport));
assertEquals(uc, t(viewport.getViewToModelTransform(), vc));
viewport.setZoomFactor(2.0);
assertEquals(2.0, viewport.getZoomFactor(), 1e-10);
assertEquals(p(17.5, 15.0), getModelOffset(viewport));
assertEquals(uc, t(viewport.getViewToModelTransform(), vc));
/////////////////////////////
// view center 2
viewport.setViewBounds(new Rectangle(0, 0, 100, 50));
vc = p(50, 25);
uc = t(viewport.getViewToModelTransform(), vc);
viewport.setZoomFactor(1.0 / 1.2);
assertEquals(1.0 / 1.2, viewport.getZoomFactor(), 1e-10);
assertEquals(p(-17.5, -2.5), getModelOffset(viewport));
assertEquals(uc, t(viewport.getViewToModelTransform(), vc));
viewport.setZoomFactor(1.0 / 0.8);
assertEquals(1.0 / 0.8, viewport.getZoomFactor(), 1e-10);
assertEquals(p(2.5, 7.5), getModelOffset(viewport));
assertEquals(uc, t(viewport.getViewToModelTransform(), vc));
}
@Test
public void testRelativeZoomWithAffineTransform() {
Point2D vc; // zoom center in view CS
final Point2D v0 = p(0, 0);
Point2D u0;
AffineTransform v2u = new AffineTransform(); // view to model CS transformation
v2u.translate(10, 10); // (10,10) are the model coordinates at (0,0) in view coordinates
u0 = t(v2u, v0);
assertEquals(1.0, v2u.getScaleX(), 1.0e-10);
assertEquals(1.0, v2u.getScaleY(), 1.0e-10);
assertEquals(p(10, 10), u0);
/////////////////////////////
// view center 1
vc = p(15, 10);
assertEquals(p(25.0, 20.0), t(v2u, vc));
zoom(v2u, vc, 2.0);
assertEquals(p(25.0, 20.0), t(v2u, vc));
assertEquals(2.0, v2u.getScaleX(), 1.0e-10);
assertEquals(2.0, v2u.getScaleY(), 1.0e-10);
assertEquals(p(-5.0, 0.0), t(v2u, v0));
zoom(v2u, vc, 0.5);
assertEquals(p(25.0, 20.0), t(v2u, vc));
assertEquals(0.5, v2u.getScaleX(), 1.0e-10);
assertEquals(0.5, v2u.getScaleY(), 1.0e-10);
assertEquals(p(17.5, 15.0), t(v2u, v0));
/////////////////////////////
// view center 2
vc = p(50, 25);
assertEquals(p(42.5, 27.5), t(v2u, vc));
zoom(v2u, vc, 1.2);
assertEquals(p(42.5, 27.5), t(v2u, vc));
assertEquals(1.2, v2u.getScaleX(), 1.0e-10);
assertEquals(1.2, v2u.getScaleY(), 1.0e-10);
assertEquals(p(-17.5, -2.5), t(v2u, v0));
zoom(v2u, vc, 0.8);
assertEquals(p(42.5, 27.5), t(v2u, vc));
assertEquals(0.8, v2u.getScaleX(), 1.0e-10);
assertEquals(0.8, v2u.getScaleY(), 1.0e-10);
assertEquals(p(2.5, 7.5), t(v2u, v0));
}
@Test
public void testRelativeZoomWithViewport() {
final DefaultViewport viewport = new DefaultViewport(new Rectangle(40, 50), true);
viewport.moveViewDelta(10, 10);
Point2D vc; // zoom center in view CS
final Point2D v0 = p(0, 0);
Point2D u0;
viewport.setOffset(10, 10);
AffineTransform v2m = viewport.getViewToModelTransform();
u0 = t(v2m, v0);
assertEquals(1.0, v2m.getScaleX(), 1.0e-10);
assertEquals(1.0, v2m.getScaleY(), 1.0e-10);
assertEquals(p(10, 10), u0);
/////////////////////////////
// view center 1
vc = p(15, 10);
assertEquals(p(25.0, 20.0), t(v2m, vc));
viewport.setZoomFactor(0.5, vc);
v2m = viewport.getViewToModelTransform();
assertEquals(0.5, viewport.getZoomFactor(), 1.0e-10);
assertEquals(p(25.0, 20.0), t(v2m, vc));
assertEquals(2.0, v2m.getScaleX(), 1.0e-10);
assertEquals(2.0, v2m.getScaleY(), 1.0e-10);
assertEquals(p(-5.0, 0.0), t(v2m, v0));
viewport.setZoomFactor(2.0, vc);
v2m = viewport.getViewToModelTransform();
assertEquals(2.0, viewport.getZoomFactor(), 1.0e-10);
assertEquals(p(25.0, 20.0), t(v2m, vc));
assertEquals(0.5, v2m.getScaleX(), 1.0e-10);
assertEquals(0.5, v2m.getScaleY(), 1.0e-10);
assertEquals(p(17.5, 15.0), t(v2m, v0));
/////////////////////////////
// view center 2
vc = p(50, 25);
assertEquals(p(42.5, 27.5), t(v2m, vc));
viewport.setZoomFactor(1 / 1.2, vc);
v2m = viewport.getViewToModelTransform();
assertEquals(1 / 1.2, viewport.getZoomFactor(), 1.0e-10);
assertEquals(p(42.5, 27.5), t(v2m, vc));
assertEquals(1.2, v2m.getScaleX(), 1.0e-10);
assertEquals(1.2, v2m.getScaleY(), 1.0e-10);
assertEquals(p(-17.5, -2.5), t(v2m, v0));
viewport.setZoomFactor(1 / 0.8, vc);
v2m = viewport.getViewToModelTransform();
assertEquals(1 / 0.8, viewport.getZoomFactor(), 1.0e-10);
assertEquals(p(42.5, 27.5), t(v2m, vc));
assertEquals(0.8, v2m.getScaleX(), 1.0e-10);
assertEquals(0.8, v2m.getScaleY(), 1.0e-10);
assertEquals(p(2.5, 7.5), t(v2m, v0));
}
@Test
public void testZoomToModelPoint() {
final DefaultViewport viewport = new DefaultViewport(new Rectangle(40, 50), true);
final Point2D m0 = p(3, 3);
final Point2D m1 = p(1, 1);
Rectangle viewBounds = viewport.getViewBounds();
viewport.setZoomFactor(2.0, 3.0, 3.0);
AffineTransform m2v = viewport.getModelToViewTransform();
assertEquals(2.0, viewport.getZoomFactor(), 1.0e-10);
assertEquals(2.0, viewport.getZoomFactor(), 1.0e-10);
assertEquals(2.0, m2v.getScaleX(), 1.0e-10);
assertEquals(2.0, m2v.getScaleY(), 1.0e-10);
assertEquals(p(20.0, 25.0), t(m2v, m0));
assertEquals(p(16.0, 21.0), t(m2v, m1));
Rectangle2D modelBounds = viewport.getViewToModelTransform().createTransformedShape(viewBounds).getBounds2D();
double centerX = modelBounds.getCenterX();
assertEquals(3.0, centerX, 1.0e-10);
double centerY = modelBounds.getCenterY();
assertEquals(3.0, centerY, 1.0e-10);
assertEquals(new Rectangle2D.Double(-7.0, -9.5, 20.0, 25.0), modelBounds);
viewport.setZoomFactor(2.0, 9.0, 9.0);
m2v = viewport.getModelToViewTransform();
assertEquals(2.0, viewport.getZoomFactor(), 1.0e-10);
assertEquals(2.0, m2v.getScaleX(), 1.0e-10);
assertEquals(2.0, m2v.getScaleY(), 1.0e-10);
assertEquals(p(8.0, 13.0), t(m2v, m0));
assertEquals(p(4.0, 9.0), t(m2v, m1));
viewport.setZoomFactor(3.0, 3.0, 3.0);
m2v = viewport.getModelToViewTransform();
assertEquals(3.0, viewport.getZoomFactor(), 1.0e-10);
assertEquals(3.0, m2v.getScaleX(), 1.0e-10);
assertEquals(3.0, m2v.getScaleY(), 1.0e-10);
assertEquals(p(20.0, 25.0), t(m2v, m0));
assertEquals(p(14.0, 19.0), t(m2v, m1));
}
@Test
public void testIllegalZoomFactor() {
final DefaultViewport viewport = new DefaultViewport();
try {
viewport.setZoomFactor(0.0);
fail("IAE expected");
} catch (Exception e) {
// ok
}
try {
viewport.setZoomFactor(-4.0);
fail("IAE expected");
} catch (Exception e) {
// ok
}
try {
viewport.setZoomFactor(0.0, 3.0, 3.0);
fail("IAE expected");
} catch (IllegalArgumentException e) {
// ok
}
try {
viewport.setZoomFactor(-0.01, 3.0, 3.0);
fail("IAE expected");
} catch (IllegalArgumentException e) {
// ok
}
}
// V0 = {0,0}
// U0 = T x V0
// Uc = T x Vc
// U0' = Uc - s'/s * (Uc - U0)
// U0' = T' x V0
// --> T x ((1 - s'/s) * Vc) = T' x V0
//
private static void zoom(AffineTransform t, Point2D vc, double s) {
final double m00 = t.getScaleX();
final double m10 = t.getShearY();
final double m01 = t.getShearX();
final double m11 = t.getScaleY();
// todo - this code is correct only if sx and sy are the same! (rq)
final double sx = Math.sqrt(m00 * m00 + m10 * m10);
final double sy = Math.sqrt(m01 * m01 + m11 * m11);
t.translate(vc.getX(), vc.getY());
t.scale(s / sx, s / sy);
t.translate(-vc.getX(), -vc.getY());
}
private static Point2D t(AffineTransform t, Point2D p) {
return t.transform(p, null);
}
static Point2D p(double x, double y) {
return new Point2D.Double(x, y);
}
public static Point2D getModelOffset(Viewport vp) {
return vp.getViewToModelTransform().transform(new Point(0, 0), null);
}
}