org.openstreetmap.atlas.checks.validation.relations.OneMemberRelationCheck Maven / Gradle / Ivy
package org.openstreetmap.atlas.checks.validation.relations;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import org.openstreetmap.atlas.checks.base.BaseCheck;
import org.openstreetmap.atlas.checks.flag.CheckFlag;
import org.openstreetmap.atlas.geography.atlas.items.AtlasObject;
import org.openstreetmap.atlas.geography.atlas.items.ItemType;
import org.openstreetmap.atlas.geography.atlas.items.Relation;
import org.openstreetmap.atlas.geography.atlas.items.RelationMemberList;
import org.openstreetmap.atlas.utilities.configuration.Configuration;
/**
* This check flags {@link Relation}s which contain only one member.
*
* @author savannahostrowski
*/
public class OneMemberRelationCheck extends BaseCheck
{
public static final String OMR_INSTRUCTIONS = "This relation, {0,number,#}, contains only "
+ "one member.";
public static final String MULTIPOLYGON_OMR_INSTRUCTIONS = "This relation, {0,number,#}, contains only "
+ "one member. Multi-polygon relations need multiple polygons.";
public static final String MEMBER_RELATION_INSTRUCTIONS = "This relation, {0,number,#}, contains only relation {1,number,#}.";
private static final List FALLBACK_INSTRUCTIONS = Arrays.asList(OMR_INSTRUCTIONS,
MULTIPOLYGON_OMR_INSTRUCTIONS, MEMBER_RELATION_INSTRUCTIONS);
@Override
protected List getFallbackInstructions()
{
return FALLBACK_INSTRUCTIONS;
}
public OneMemberRelationCheck(final Configuration configuration)
{
super(configuration);
}
@Override
public boolean validCheckForObject(final AtlasObject object)
{
return object instanceof Relation;
}
@Override
protected Optional flag(final AtlasObject object)
{
final Relation relation = (Relation) object;
final RelationMemberList members = relation.members();
// If the number of members in the relation is 1
if (members.size() == 1)
{
if (members.get(0).getEntity().getType().equals(ItemType.RELATION))
{
return Optional.of(createFlag(getRelationMembers((Relation) object),
this.getLocalizedInstruction(2, relation.getOsmIdentifier(),
members.get(0).getEntity().getOsmIdentifier())));
}
// If the relation is a multi-polygon,
if (relation.isMultiPolygon())
{
return Optional.of(createFlag(getRelationMembers((Relation) object),
this.getLocalizedInstruction(1, relation.getOsmIdentifier())));
}
return Optional.of(createFlag(getRelationMembers((Relation) object),
this.getLocalizedInstruction(0, relation.getOsmIdentifier())));
}
return Optional.empty();
}
/**
* Gathers all the members of a relation, replacing child relations with their members.
*
* @param relation
* {@link Relation} to get the members of
* @return A {@link Set} of the relations members as {@link AtlasObject}s
*/
private Set getRelationMembers(final Relation relation)
{
final Set relationMembers = new HashSet<>();
final ArrayDeque toProcess = new ArrayDeque<>();
AtlasObject polledMember;
toProcess.add(relation);
while (!toProcess.isEmpty())
{
polledMember = toProcess.poll();
// If a member is a relation do not add it to the set and instead add its members to the
// queue for processing
if (polledMember instanceof Relation)
{
((Relation) polledMember).members()
.forEach(member -> toProcess.add(member.getEntity()));
}
// Otherwise add the member to the returned set
else
{
relationMembers.add(polledMember);
}
}
return relationMembers;
}
}