/* Copyright (c) 2014 Boundless and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Distribution License v1.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/org/documents/edl-v10.html * * Contributors: * Jillian Crossley (Cornell University) - initial implementation */ package org.locationtech.geogig.api.plumbing; import java.util.ArrayList; import java.util.List; import javax.annotation.Nullable; import org.geotools.data.DataUtilities; import org.geotools.feature.SchemaException; import org.geotools.geometry.jts.ReferencedEnvelope; import org.geotools.referencing.CRS; import org.junit.Test; import org.locationtech.geogig.api.DefaultProgressListener; import org.locationtech.geogig.api.RevCommit; import org.locationtech.geogig.api.RevTree; import org.locationtech.geogig.api.plumbing.diff.DiffSummary; import org.locationtech.geogig.api.porcelain.AddOp; import org.locationtech.geogig.api.porcelain.CommitOp; import org.locationtech.geogig.repository.WorkingTree; import org.locationtech.geogig.test.integration.RepositoryTestCase; import org.opengis.feature.Feature; import org.opengis.feature.simple.SimpleFeatureType; import org.opengis.geometry.BoundingBox; import org.opengis.referencing.crs.CoordinateReferenceSystem; import com.google.common.base.Throwables; import com.google.common.collect.AbstractIterator; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import com.vividsolutions.jts.io.ParseException; public class DiffBoundsTest extends RepositoryTestCase { private static final CoordinateReferenceSystem DEFAULT_CRS; static { try { DEFAULT_CRS = CRS.decode("EPSG:4326", true); } catch (Exception e) { throw Throwables.propagate(e); } } private Feature l1Modified; private Feature l2Modified; private RevCommit points1_modified_commit; @Override protected void setUpInternal() throws Exception { // create one commit per feature ArrayList<RevCommit> commits = Lists.newArrayList(populate(true, points1, points3, points1_modified)); this.points1_modified_commit = commits.get(2); Feature p1ModifiedAgain = feature(pointsType, idP1, "StringProp1_1a", new Integer(1001), "POINT(10 20)");// used to be POINT(1 2) insertAndAdd(p1ModifiedAgain); commits.add(geogig.command(CommitOp.class).call()); points1B_modified = feature(pointsType, idP1, "StringProp1B_1a", new Integer(2000), "POINT(10 220)"); insertAndAdd(points1B_modified); commits.add(geogig.command(CommitOp.class).call()); l1Modified = feature(linesType, idL1, "StringProp2_1", new Integer(1000), "LINESTRING (1 1, -2 -2)");// used to be LINESTRING (1 1, 2 2) l2Modified = feature(linesType, idL2, "StringProp2_2", new Integer(2000), "LINESTRING (3 3, 4 4)");// used to be LINESTRING (3 3, 4 4) } @Test public void testDiffBetweenDifferentTrees() { String oldRefSpec = "HEAD~3"; String newRefSpec = "HEAD"; DiffSummary<BoundingBox, BoundingBox> diffBounds = geogig.command(DiffBounds.class) .setOldVersion(oldRefSpec).setNewVersion(newRefSpec) .setCRS(pointsType.getCoordinateReferenceSystem()).call(); BoundingBox bounds = diffBounds.getMergedResult().get(); assertEquals(1.0, bounds.getMinX(), 0.0); assertEquals(1.0, bounds.getMinY(), 0.0); assertEquals(10.0, bounds.getMaxX(), 0.0); assertEquals(220.0, bounds.getMaxY(), 0.0); } @Test public void testDiffBetweenIdenticalTrees() { String oldRefSpec = "HEAD"; String newRefSpec = "HEAD"; DiffSummary<BoundingBox, BoundingBox> diffBounds = geogig.command(DiffBounds.class) .setOldVersion(oldRefSpec).setNewVersion(newRefSpec).call(); assertTrue(diffBounds.getLeft().isEmpty()); assertTrue(diffBounds.getRight().isEmpty()); assertTrue(diffBounds.getMergedResult().get().isEmpty()); } @Test public void testPathFiltering() throws Exception { insertAndAdd(l1Modified); geogig.command(CommitOp.class).call(); insert(l2Modified); testPathFiltering("HEAD~3", "HEAD", l1Modified.getBounds(), linesName); testPathFiltering("HEAD", "WORK_HEAD", l2Modified.getBounds(), linesName); testPathFiltering("HEAD~3", "HEAD~2", null, linesName); testPathFiltering("HEAD~3", "HEAD~2", null, linesName); String head = points1_modified_commit.getId().toString(); BoundingBox expected = points1.getBounds(); expected.include(points1_modified.getBounds()); testPathFiltering(head + "^", head, expected, pointsName); testPathFiltering(head + "^", head, null, linesName); testPathFiltering("HEAD^", "HEAD", null, pointsName); } private void testPathFiltering(String oldVersion, String newVersion, @Nullable BoundingBox expected, @Nullable String... pathFilters) { List<String> filter = ImmutableList.<String> copyOf(pathFilters); CoordinateReferenceSystem crs = DEFAULT_CRS; if (expected != null) { crs = expected.getCoordinateReferenceSystem(); } DiffSummary<BoundingBox, BoundingBox> result = geogig.command(DiffBounds.class)// .setOldVersion(oldVersion)// .setNewVersion(newVersion)// .setPathFilters(filter)// .setCRS(crs)// .call(); BoundingBox actual = result.getMergedResult().get(); if (null == expected) { assertTrue(actual.isEmpty()); } else { assertEquals(expected, actual); } } @Test public void testDefaultCrs() { DiffSummary<BoundingBox, BoundingBox> diffBounds = geogig.command(DiffBounds.class) .setOldVersion("HEAD^").setNewVersion("HEAD").call(); assertEquals(DEFAULT_CRS, diffBounds.getLeft().getCoordinateReferenceSystem()); assertEquals(DEFAULT_CRS, diffBounds.getRight().getCoordinateReferenceSystem()); assertEquals(DEFAULT_CRS, diffBounds.getMergedResult().get().getCoordinateReferenceSystem()); } @Test public void testReprojectToTargetCRS() throws Exception { DiffBounds cmd = geogig.command(DiffBounds.class).setOldVersion("HEAD^") .setNewVersion("HEAD"); DiffSummary<BoundingBox, BoundingBox> defaultCrs = cmd.call(); CoordinateReferenceSystem target = CRS.decode("EPSG:26986"); cmd.setCRS(target); DiffSummary<BoundingBox, BoundingBox> reprojected = cmd.call(); assertEquals(target, reprojected.getLeft().getCoordinateReferenceSystem()); assertEquals(target, reprojected.getRight().getCoordinateReferenceSystem()); assertEquals(target, reprojected.getMergedResult().get().getCoordinateReferenceSystem()); assertFalse(defaultCrs.getLeft().isEmpty()); assertFalse(defaultCrs.getRight().isEmpty()); assertFalse(defaultCrs.getMergedResult().get().isEmpty()); ReferencedEnvelope e = new ReferencedEnvelope(defaultCrs.getLeft()); ReferencedEnvelope expected = e.transform(target, true); assertEquals(expected, reprojected.getLeft()); } @Test public void testReprojectToTargetBucketTree() throws Exception { final int leftCount = RevTree.NORMALIZED_SIZE_LIMIT * 2; final int rightCount = RevTree.NORMALIZED_SIZE_LIMIT * 3; WorkingTree workingTree = geogig.getRepository().workingTree(); final String typeName = "newpoints"; final DefaultProgressListener listener = new DefaultProgressListener(); workingTree.insert(typeName, new TestFeatureIterator(typeName, leftCount), listener, null, null); geogig.command(AddOp.class).call(); workingTree.insert(typeName, new TestFeatureIterator(typeName, rightCount), listener, null, null); {// sanity check long diffFeatures = geogig.command(DiffCount.class).setOldVersion("STAGE_HEAD") .setNewVersion("WORK_HEAD").call().featureCount(); assertEquals(rightCount - leftCount, diffFeatures); } DiffBounds cmd = geogig.command(DiffBounds.class).setOldVersion("STAGE_HEAD") .setNewVersion("WORK_HEAD"); final CoordinateReferenceSystem nativeCrs = CRS.decode("EPSG:3857"); final DiffSummary<BoundingBox, BoundingBox> diffInNativeCrs = cmd.setCRS(nativeCrs).call(); CoordinateReferenceSystem targetcrs = CRS.decode("EPSG:4326", true); cmd.setCRS(targetcrs); DiffSummary<BoundingBox, BoundingBox> reprojected = cmd.call(); assertEquals(targetcrs, reprojected.getLeft().getCoordinateReferenceSystem()); assertEquals(targetcrs, reprojected.getRight().getCoordinateReferenceSystem()); assertEquals(targetcrs, reprojected.getMergedResult().get().getCoordinateReferenceSystem()); ReferencedEnvelope e = new ReferencedEnvelope(diffInNativeCrs.getRight()); ReferencedEnvelope expected = e.transform(targetcrs, true); BoundingBox actual = reprojected.getRight(); assertEquals(expected, actual); } private final class TestFeatureIterator extends AbstractIterator<Feature> { final int fcount; int c; private SimpleFeatureType featureType; TestFeatureIterator(String typeName, int featureCount) { try { String typeSpec = "pp:Point:srid=3857"; this.featureType = DataUtilities.createType(typeName, typeSpec); } catch (SchemaException e) { throw Throwables.propagate(e); } this.fcount = featureCount; } @Override protected Feature computeNext() { c++; if (c == fcount) { return endOfData(); } try { String geomWkt = String.format("POINT(%d %d)", c, c); return feature(featureType, String.valueOf(c), geomWkt); } catch (ParseException e) { throw Throwables.propagate(e); } } } }