/**
* Copyright (C) 2011 Brian Ferris <bdferris@onebusaway.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onebusaway.geospatial.grid;
import junit.framework.TestCase;
import java.util.List;
public class BoundaryFactoryTest extends TestCase {
private static final EDirection DU = EDirection.UP;
private static final EDirection DL = EDirection.LEFT;
private static final EDirection DR = EDirection.RIGHT;
private static final EDirection DD = EDirection.DOWN;
public void testBoundaryFactory() {
Grid<String> grid = new MapGrid<String>();
grid.set(0, 0, "a");
BoundaryFactory bf = new BoundaryFactory();
List<Boundary> boundaries = bf.getBoundaries(grid);
assertEquals(1, boundaries.size());
Boundary boundary = boundaries.get(0);
BoundaryPath expected = pathFactory().add(0, 0, DU).add(0, 0, DR).add(0, 0,
DD).add(0, 0, DL).path();
BoundaryPath actual = boundary.getOuterBoundary();
assertTrue(arePathsEquivalent(expected, actual));
assertTrue(boundary.getInnerBoundaries().isEmpty());
}
public void testBoundaryFactoryWithHole() {
Grid<String> grid = new MapGrid<String>();
for (int x = 0; x < 6; x++) {
for (int y = 0; y < 6; y++) {
if (2 <= x && x < 4 && 2 <= y && y < 4)
continue;
grid.set(x, y, "a");
}
}
BoundaryFactory bf = new BoundaryFactory();
List<Boundary> boundaries = bf.getBoundaries(grid);
assertEquals(1, boundaries.size());
Boundary boundary = boundaries.get(0);
BoundaryPathFactory factory = pathFactory();
for (int i = 0; i < 6; i++)
factory.add(0, i, DL);
for (int i = 0; i < 6; i++)
factory.add(i, 5, DU);
for (int i = 5; i >= 0; i--)
factory.add(5, i, DR);
for (int i = 5; i >= 0; i--)
factory.add(i, 0, DD);
BoundaryPath expected = factory.path();
BoundaryPath actual = boundary.getOuterBoundary();
assertTrue(arePathsEquivalent(expected, actual));
assertEquals(1, boundary.getInnerBoundaries().size());
BoundaryPath innerExpected = pathFactory().add(2, 1, DU).add(3, 1, DU).add(
4, 2, DL).add(4, 3, DL).add(3, 4, DD).add(2, 4, DD).add(1, 3, DR).add(
1, 2, DR).path();
BoundaryPath innerActual = boundary.getInnerBoundaries().get(0);
assertTrue(arePathsEquivalent(innerExpected, innerActual));
}
public void testBoundaryFactoryTwoClusters() {
Grid<String> grid = new MapGrid<String>();
grid.set(0, 0, "a");
grid.set(0, 1, "a");
grid.set(0, 3, "b");
BoundaryFactory bf = new BoundaryFactory();
List<Boundary> boundaries = bf.getBoundaries(grid);
assertEquals(2, boundaries.size());
Boundary ba = boundaries.get(0);
Boundary bb = boundaries.get(1);
if (ba.getOuterBoundary().size() < bb.getOuterBoundary().size()) {
Boundary bt = ba;
ba = bb;
bb = bt;
}
BoundaryPath expectedPathA = pathFactory().add(0, 0, DR).add(0, 0, DD).add(
0, 0, DL).add(0, 1, DL).add(0, 1, DU).add(0, 1, DR).path();
BoundaryPath actualPathA = ba.getOuterBoundary();
assertTrue(arePathsEquivalent(expectedPathA, actualPathA));
BoundaryPath expectedPathB = pathFactory().add(0, 3, DL).add(0, 3, DU).add(
0, 3, DR).add(0, 3, DD).path();
BoundaryPath actualPathB = bb.getOuterBoundary();
assertTrue(arePathsEquivalent(expectedPathB, actualPathB));
}
public void testClusterWithTwoHoles() {
Grid<String> grid = new MapGrid<String>();
grid.set(0, 0, "a");
grid.set(0, 1, "a");
grid.set(0, 2, "a");
grid.set(1, 0, "a");
grid.set(1, 2, "a");
grid.set(2, 0, "a");
grid.set(2, 1, "a");
grid.set(2, 2, "a");
grid.set(3, 0, "a");
grid.set(3, 2, "a");
grid.set(4, 0, "a");
grid.set(4, 1, "a");
grid.set(4, 2, "a");
BoundaryFactory bf = new BoundaryFactory();
List<Boundary> boundaries = bf.getBoundaries(grid);
assertEquals(1, boundaries.size());
Boundary boundary = boundaries.get(0);
BoundaryPathFactory factory = pathFactory();
for (int i = 0; i < 3; i++)
factory.add(0, i, DL);
for (int i = 0; i < 5; i++)
factory.add(i, 2, DU);
for (int i = 2; i >= 0; i--)
factory.add(4, i, DR);
for (int i = 4; i >= 0; i--)
factory.add(i, 0, DD);
BoundaryPath expectedOuterPath = factory.path();
BoundaryPath actualOuterPath = boundary.getOuterBoundary();
assertTrue(arePathsEquivalent(expectedOuterPath, actualOuterPath));
List<BoundaryPath> innerBoundaries = boundary.getInnerBoundaries();
assertEquals(2, innerBoundaries.size());
BoundaryPath pathA = pathFactory().add(1, 0, DU).add(2, 1, DL).add(1, 2, DD).add(
0, 1, DR).path();
BoundaryPath pathB = pathFactory().add(3, 0, DU).add(4, 1, DL).add(3, 2, DD).add(
2, 1, DR).path();
BoundaryPath actualPathA = innerBoundaries.get(0);
BoundaryPath actualPathB = innerBoundaries.get(1);
if (!arePathsEquivalent(pathA, actualPathA)) {
BoundaryPath temp = actualPathA;
actualPathA = actualPathB;
actualPathB = temp;
}
assertTrue(arePathsEquivalent(pathA, actualPathA));
assertTrue(arePathsEquivalent(pathB, actualPathB));
}
public void testPruneAllButCorners() {
Grid<String> grid = new MapGrid<String>();
for (int x = 0; x < 6; x++) {
for (int y = 0; y < 6; y++) {
if (2 <= x && x < 4 && 2 <= y && y < 4)
continue;
grid.set(x, y, "a");
}
}
BoundaryFactory factory = new BoundaryFactory();
factory.setPruneAllButCorners(true);
List<Boundary> boundaries = factory.getBoundaries(grid);
assertEquals(1, boundaries.size());
Boundary boundary = boundaries.get(0);
BoundaryPath expectedOuter = pathFactory().add(0, 0, DL).add(0, 5, DU).add(
5, 5, DR).add(5, 0, DD).path();
BoundaryPath actualOuter = boundary.getOuterBoundary();
assertTrue(arePathsEquivalent(expectedOuter, actualOuter));
}
/*****************************************************************************
* Private Methods
****************************************************************************/
private boolean arePathsEquivalent(BoundaryPath a, BoundaryPath b) {
if (a.size() != b.size())
return false;
GridIndex firstIndex = a.getIndex(0);
EDirection firstDirection = a.getDirection(0);
for (int offset = 0; offset < b.size(); offset++) {
if (firstIndex.equals(b.getIndex(offset))
&& firstDirection.equals(b.getDirection(offset))) {
for (int ia = 0; ia < a.size(); ia++) {
int ib = (ia + offset) % b.size();
if (!a.getIndex(ia).equals(b.getIndex(ib)))
return false;
if (!a.getDirection(ia).equals(b.getDirection(ib)))
return false;
}
return true;
}
}
return false;
}
private BoundaryPathFactory pathFactory() {
return new BoundaryPathFactory();
}
private class BoundaryPathFactory {
private BoundaryPath _path = new BoundaryPath();
public BoundaryPathFactory add(int x, int y, EDirection direction) {
_path.addEdge(new GridIndex(x, y), direction);
return this;
}
public BoundaryPath path() {
return _path;
}
}
}