Skip to content

Commit

Permalink
Added in Relation flattening (#233)
Browse files Browse the repository at this point in the history
* Added in Relation flattening

* Formatting and removed faulty tests

* PR updates

* fixed check for id and added unit tests for same id
  • Loading branch information
adahn6 authored and MikeGost committed Oct 5, 2018
1 parent 3a678e6 commit 6d73202
Show file tree
Hide file tree
Showing 3 changed files with 167 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@

import java.util.ArrayList;
import java.util.Comparator;
import java.util.Deque;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
Expand All @@ -24,6 +27,8 @@
import org.openstreetmap.atlas.tags.annotations.validation.Validators;
import org.openstreetmap.atlas.utilities.collections.Iterables;
import org.openstreetmap.atlas.utilities.collections.StringList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* An OSM relation
Expand All @@ -44,6 +49,7 @@ public enum Ring
INNER
}

private static final Logger logger = LoggerFactory.getLogger(Relation.class);
private static final long serialVersionUID = -9013894610780915685L;

public static final Comparator<Relation> RELATION_ID_COMPARATOR = (final Relation relation1,
Expand Down Expand Up @@ -93,6 +99,43 @@ public String configurableString(final String betweenEachMemberAndRelation,
return builder.toString();
}

/**
* "Flattens" the relation by returning the set of non-Relation members. Adds any non-Relation
* members to the set, then loops on any Relation members to add their non-Relation members as
* well. Keeps track of Relations whose identifiers have already been operated on, so that
* recursively defined relations don't cause problems.
*
* @return a Set of AtlasObjects all related to this Relation, with no Relations.
*/
public Set<AtlasObject> flatten()
{
final Set<AtlasObject> relationMembers = new HashSet<>();
final Deque<AtlasObject> toProcess = new LinkedList<>();
final Set<Long> relationsSeen = new HashSet<>();
AtlasObject polledMember;

toProcess.add(this);
while (!toProcess.isEmpty())
{
polledMember = toProcess.poll();
if (polledMember instanceof Relation)
{
if (relationsSeen.contains(polledMember.getIdentifier()))
{
continue;
}
((Relation) polledMember).members()
.forEach(member -> toProcess.add(member.getEntity()));
relationsSeen.add(polledMember.getIdentifier());
}
else
{
relationMembers.add(polledMember);
}
}
return relationMembers;
}

@Override
public ItemType getType()
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package org.openstreetmap.atlas.geography.atlas.items;

import org.openstreetmap.atlas.geography.atlas.Atlas;
import org.openstreetmap.atlas.utilities.testing.CoreTestRule;
import org.openstreetmap.atlas.utilities.testing.TestAtlas;
import org.openstreetmap.atlas.utilities.testing.TestAtlas.Node;
import org.openstreetmap.atlas.utilities.testing.TestAtlas.Relation;
import org.openstreetmap.atlas.utilities.testing.TestAtlas.Relation.Member;

/**
* @author samuelgass
*/
public class RelationFlatteningRule extends CoreTestRule
{
@TestAtlas(nodes = { @Node(id = "1"), @Node(id = "2"), @Node(id = "3"), @Node(id = "4"),
@Node(id = "5"), @Node(id = "6") }, relations = {

@Relation(id = "6", members = {
@Member(id = "1", role = "outside", type = "node") }),
@Relation(id = "7", members = {
@Member(id = "1", role = "outside", type = "node"),
@Member(id = "2", role = "outside", type = "node"),
@Member(id = "6", role = "outside", type = "node") }),
@Relation(id = "8", members = {
@Member(id = "4", role = "outside", type = "node"),
@Member(id = "5", role = "outside", type = "node"),
@Member(id = "8", role = "outside", type = "relation") }),
@Relation(id = "9", members = {
@Member(id = "4", role = "outside", type = "node"),
@Member(id = "5", role = "outside", type = "node"),
@Member(id = "7", role = "outside", type = "relation"),
@Member(id = "6", role = "outside", type = "relation") }),
@Relation(id = "10", members = {
@Member(id = "6", role = "outside", type = "relation"),
@Member(id = "3", role = "outside", type = "node"),
@Member(id = "9", role = "outside", type = "relation") }),
@Relation(id = "2", members = {
@Member(id = "3", role = "outside", type = "node"),
@Member(id = "4", role = "outside", type = "node"),
@Member(id = "6", role = "outside", type = "relation") }),
@Relation(id = "1", members = {
@Member(id = "5", role = "outside", type = "node"),
@Member(id = "2", role = "outside", type = "node"),
@Member(id = "2", role = "outside", type = "relation") }) })
private Atlas atlas;

public Atlas getAtlas()
{
return this.atlas;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package org.openstreetmap.atlas.geography.atlas.items;

import static org.junit.Assert.assertEquals;

import java.util.Set;

import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* @author samuelgass
*/
public class RelationFlatteningTest
{
private static final Logger logger = LoggerFactory.getLogger(RelationFlatteningTest.class);

@Rule
public final RelationFlatteningRule rule = new RelationFlatteningRule();

@Test
public void testLoopingRelation()
{
final Relation loopingRelation = this.rule.getAtlas().relation(8);
logger.info("Looping (self-containing) Relation: {}", loopingRelation);
final Set<AtlasObject> flattened = loopingRelation.flatten();
logger.info("Flattened: {}", flattened);
assertEquals(2, flattened.size());
}

@Test
public void testNestedRelation()
{
final Relation nestedRelation = this.rule.getAtlas().relation(10);
logger.info("Nested Relation: {}", nestedRelation);
final Set<AtlasObject> flattened = nestedRelation.flatten();
logger.info("Flattened: {}", flattened);
assertEquals(6, flattened.size());
}

@Test
public void testNodesAndRelationsWithSameId()
{
final Relation relation = this.rule.getAtlas().relation(1);
logger.info("Relation containing nodes and relations with the same numeric id: {}",
relation);
final Set<AtlasObject> flattened = relation.flatten();
logger.info("Flattened: {}", flattened);
assertEquals(5, flattened.size());
}

@Test
public void testShallowRelation()
{
final Relation shallowRelation = this.rule.getAtlas().relation(6);
logger.info("Shallow (1-node) relation: {}", shallowRelation);
final Set<AtlasObject> flattened = shallowRelation.flatten();
logger.info("Flattened: {}", flattened);
assertEquals(1, flattened.size());
final AtlasObject memberNode = flattened.stream().findFirst().get();
if (memberNode instanceof Node)
{
assertEquals(1, ((Node) memberNode).getIdentifier());
}
else
{
Assert.fail("Member was not the expected type of 'Node'!");
}
}
}

0 comments on commit 6d73202

Please sign in to comment.