/*
* Copyright 2010, 2011, 2012 mapsforge.org
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mapsforge.map.writer.model;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Logger;
import org.mapsforge.map.writer.OSMTagMapping;
import org.mapsforge.map.writer.util.OSMUtils;
import org.openstreetmap.osmosis.core.domain.v0_6.EntityType;
import org.openstreetmap.osmosis.core.domain.v0_6.Relation;
import org.openstreetmap.osmosis.core.domain.v0_6.RelationMember;
/**
* Represents an OSM relation.
*
* @author bross
*/
public class TDRelation {
private static final Logger LOGGER = Logger.getLogger(TDRelation.class.getName());
private final long id;
private final byte layer;
private final String name;
private final String houseNumber;
private final String ref;
private final short[] tags;
private final TDWay[] memberWays;
/**
* Creates a new TDRelation from an osmosis entity using the given WayResolver.
*
* @param relation
* the relation
* @param resolver
* the resolver
* @param preferredLanguage
* the preferred language or null if no preference
* @return a new TDRelation if all members are valid and the relation is of a known type, null otherwise
*/
public static TDRelation fromRelation(Relation relation, WayResolver resolver, String preferredLanguage) {
if (relation == null) {
return null;
}
if (relation.getMembers().size() == 0) {
return null;
}
SpecialTagExtractionResult ster = OSMUtils.extractSpecialFields(relation, preferredLanguage);
short[] knownWayTags = OSMUtils.extractKnownWayTags(relation);
// special tags
// TODO what about the layer of relations?
// TODO exclude boundaries
if (!knownRelationType(ster.getType())) {
return null;
}
List<RelationMember> members = relation.getMembers();
List<TDWay> wayMembers = new ArrayList<TDWay>();
for (RelationMember relationMember : members) {
if (relationMember.getMemberType() != EntityType.Way) {
continue;
}
TDWay member = resolver.getWay(relationMember.getMemberId());
if (member == null) {
LOGGER.finest("relation is missing a member, rel-id: " + relation.getId() + " member id: "
+ relationMember.getMemberId());
continue;
}
wayMembers.add(member);
}
if (wayMembers.isEmpty()) {
LOGGER.finest("relation has no valid members: " + relation.getId());
return null;
}
return new TDRelation(relation.getId(), ster.getLayer(), ster.getName(), ster.getHousenumber(), ster.getRef(),
knownWayTags, wayMembers.toArray(new TDWay[wayMembers.size()]));
}
/**
* Constructor.
*
* @param id
* the id
* @param layer
* the layer
* @param name
* the name
* @param houseNumber
* the house number if existent
* @param ref
* the ref attribute
* @param tags
* the tags
* @param memberWays
* the member ways
*/
TDRelation(long id, byte layer, String name, String houseNumber, String ref, short[] tags, TDWay[] memberWays) {
this.id = id;
this.layer = layer;
this.name = name;
this.houseNumber = houseNumber;
this.ref = ref;
this.tags = tags;
this.memberWays = memberWays;
}
/**
* @return the id
*/
public long getId() {
return this.id;
}
/**
* @return the layer
*/
public byte getLayer() {
return this.layer;
}
/**
* @return the name
*/
public String getName() {
return this.name;
}
/**
* @return the houseNumber
*/
public String getHouseNumber() {
return this.houseNumber;
}
/**
* @return the ref
*/
public String getRef() {
return this.ref;
}
/**
* @return the tags
*/
public short[] getTags() {
return this.tags;
}
/**
* @return true if the relation has associated tags
*/
public boolean hasTags() {
return this.tags != null && this.tags.length > 0;
}
/**
* @return true if the relation is relevant for rendering
*/
public boolean isRenderRelevant() {
return hasTags() || getName() != null && !getName().isEmpty() || getRef() != null && !getRef().isEmpty();
}
/**
* @return the member ways
*/
public TDWay[] getMemberWays() {
return this.memberWays;
}
/**
* @return true if the relation represents a coastline
*/
public boolean isCoastline() {
if (this.tags == null) {
return false;
}
OSMTag tag;
for (short tagID : this.tags) {
tag = OSMTagMapping.getInstance().getWayTag(tagID);
if (tag.isCoastline()) {
return true;
}
}
return false;
}
/**
* @param type
* the type attribute of a relation
* @return true if the type if known, currently only multipolygons are known
*/
// TODO adjust if more relations should be supported
public static boolean knownRelationType(String type) {
return type != null && "multipolygon".equals(type);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) (this.id ^ (this.id >>> 32));
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
TDRelation other = (TDRelation) obj;
if (this.id != other.id) {
return false;
}
return true;
}
@Override
public String toString() {
return "TDRelation [id=" + this.id + ", layer=" + this.layer + ", name=" + this.name + ", ref=" + this.ref
+ ", tags=" + Arrays.toString(this.tags) + "]";
}
}