/**
* This file is part of OSM2ShareNav
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
* See COPYING.
*
* Copyright (C) 2007 Harald Mueller
*/
package net.sharenav.osmToShareNav.model;
import java.util.ArrayList;
import java.util.LinkedList;
import net.sharenav.osmToShareNav.Configuration;
/**
*
*/
public class Relation extends Entity {
protected LinkedList<Member> members = new LinkedList<Member>();
public Long id;
/** Set if not all members of the relation are available */
private boolean partialMembers = false;
public Relation(long id) {
this.id = id;
}
/**
* @param m
*/
public void add(Member m) {
members.add(m);
}
public String toUrl() {
return "http://www.openstreetmap.org/browse/relation/" + id;
}
@Override
public String toString() {
StringBuffer ret = new StringBuffer("Relation (" + id + ") [");
for (String key : getTags()) {
ret.append(key + "=" + getAttribute(key) + " ");
}
for (Member m : members) {
ret.append(m.toString());
ret.append(", ");
}
ret.setLength(ret.length() - 2);
ret.append("]");
return ret.toString();
}
public ArrayList<Long> getWayIds(int role) {
ArrayList<Long> ret = new ArrayList<Long>();
for (Member m : members) {
if (m.getType() == Member.TYPE_WAY) {
if (m.getRole() == role) {
ret.add(new Long(m.getRef()));
}
}
}
return ret;
}
public ArrayList<Long> getWayIds() {
ArrayList<Long> ret = new ArrayList<Long>();
for (Member m : members) {
if (m.getType() == Member.TYPE_WAY) {
ret.add(new Long(m.getRef()));
}
}
return ret;
}
public ArrayList<Long> getNodeIds(int role) {
ArrayList<Long> ret = new ArrayList<Long>();
for (Member m : members) {
if (m.getType() == Member.TYPE_NODE) {
if (m.getRole() == role) {
ret.add(new Long(m.getRef()));
}
}
}
return ret;
}
public boolean isValid() {
if (members.size() > 0) {
//TODO: A more elaborate check is needed
//based on the type of relation and the
//partial members attribute is needed
String type = getAttribute("type");
if (type != null) {
if (type.equalsIgnoreCase("route")) {
return true;
}
if (type.equalsIgnoreCase("restriction")) {
int role_via = 0;
int role_from = 0;
int role_to = 0;
for (Member m : members) {
switch (m.getRole()) {
case Member.ROLE_FROM: {
if (m.getType() == Member.TYPE_WAY) {
role_from++;
}
break;
}
case Member.ROLE_VIA: {
role_via++;
break;
}
case Member.ROLE_TO: {
if (m.getType() == Member.TYPE_WAY) {
role_to++;
}
break;
}
}
}
if (role_from == 0) {
System.out.println(toUrl() + ": Missing from in restriction " + toString());
return false;
}
if (role_via == 0) {
System.out.println(toUrl() + ": Missing via in restriction " + toString());
return false;
}
if (role_to == 0) {
System.out.println(toUrl() + ": Missing to in restriction " + toString());
return false;
}
if (role_from > 1) {
System.out.println(toUrl() + ": Too many \"from\" in restriction " + toString());
return false;
}
if (role_via > 1) {
System.out.println(toUrl() + ": Too many \"via\" in restriction " + toString());
return false;
}
if (role_to > 1) {
System.out.println(toUrl() + ": Too many \"to\" in restriction " + toString());
return false;
}
String restrictionType = getAttribute("restriction");
if (restrictionType == null) {
System.out.println(toUrl() + ": No restriction type given in restriction " + toString());
return false;
}
restrictionType.toLowerCase();
if (! (restrictionType.startsWith("only_") || restrictionType.startsWith("no_"))) {
System.out.println(toUrl() + ": Neither a no_ nor an only_ restriction " + toString());
return false;
}
}
if (Configuration.getConfiguration().useHouseNumbers && (type.equalsIgnoreCase("associatedStreet") || type.equalsIgnoreCase("street"))) {
int streetcount = 0;
int housecount = 0;
boolean ok = false;
for (Member m : members) {
switch (m.getRole()) {
case Member.ROLE_STREET: {
if (m.getType() == Member.TYPE_WAY) {
streetcount++;
//System.out.println("Relation " + id + " way ref = " + wref);
break;
}
}
case Member.ROLE_HOUSE: {
if (m.getType() == Member.TYPE_NODE) {
housecount++;
//System.out.println("Relation " + id + " house ref = " + nref);
break;
}
if (m.getType() == Member.TYPE_WAY) {
//System.out.println("Info: trying to handle way (typically building, area) with housenumber, relation url: "
// + toUrl());
housecount++;
break;
}
}
}
}
if (streetcount >= 1 && housecount >= 1) {
//System.out.println("Housenumber relation ok, street count: "
// + streetcount + " house count " + housecount + " url: " + toUrl());
return true;
} else {
// Warn only about associatedStreet relations with no housenumbers,
// but not street relations, as there's nothing suspicious
// about a street relation with no houses
if (type.equalsIgnoreCase("street") && housecount == 0) {
// do nothing
} else {
System.out.println("Warning: ignoring map data: Housenumber relation not ok, street count: "
+ streetcount + " house count " + housecount + " url: " + toUrl());
return false;
}
}
}
return !isPartial();
} else {
return !isPartial();
}
} else {
return false;
}
}
public long getViaNodeOrWayRef() {
long ref = 0;
if (members.size() > 0) {
String type = getAttribute("type");
if (type != null) {
if (type.equalsIgnoreCase("restriction")) {
for (Member m : members) {
if (m.getRole() == Member.ROLE_VIA) {
if (m.getType() == Member.TYPE_NODE || m.getType() == Member.TYPE_WAY) {
ref = m.getRef();
} else {
System.out.println(toUrl()
+ ": Turn restrictions: Can only handle ROLE_VIA node and way types. Restriction: "
+ toString());
}
}
}
}
}
}
return ref;
}
public boolean isViaWay() {
if (members.size() > 0) {
for (Member m : members) {
if (m.getRole() == Member.ROLE_VIA) {
if (m.getType() == Member.TYPE_WAY) {
return true;
}
}
}
}
return false;
}
public void setPartial() {
partialMembers = true;
}
public boolean isPartial() {
return partialMembers;
}
}