/*
* 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.Arrays;
import org.mapsforge.map.writer.util.GeoUtils;
import org.mapsforge.map.writer.util.OSMUtils;
import com.vividsolutions.jts.geom.Geometry;
import de.sfb.tilemap.writer.util.PGHStore;
/**
* Represents an OSM way.
*
* @author bross
*/
public class TDWay {
// private static final Logger LOGGER = Logger.getLogger(TDWay.class.getName());
// TODO these constants are not necessary anymore
/**
* Represents a line.
*/
public static final byte LINE = 0x0;
/**
* A simple closed polygon.
*/
public static final byte SIMPLE_POLYGON = 0x1;
/**
* A simple closed polygon with holes.
*/
public static final byte MULTI_POLYGON = 0x2;
private final long id;
private final byte layer;
private String name;
private String ref;
private final String houseNumber;
private short[] tags; // NOPMD by bross on 25.12.11 13:04
private byte shape;
private final TDNode[] wayNodes;
private boolean reversedInRelation;
private boolean invalid;
private Geometry geometry;
/**
* Creates a new TDWay from an osmosis way entity using the given NodeResolver.
*
* @param way
* the way
* @param resolver
* the resolver
* @param preferredLanguage
* the preferred language or null if no preference
* @return a new TDWay if it is valid, null otherwise
*/
public static TDWay fromWay(long id, PGHStore tags, Geometry geom, String preferredLanguage) {
SpecialTagExtractionResult ster = OSMUtils.extractSpecialFields(tags, preferredLanguage);
short[] knownWayTags = OSMUtils.extractKnownWayTags(tags);
// // only ways with at least 2 way nodes are valid ways
// if (way.getWayNodes().size() >= 2) {
//
// boolean validWay = true;
// // retrieve way nodes from data store
// TDNode[] waynodes = new TDNode[way.getWayNodes().size()];
// int i = 0;
// for (WayNode waynode : way.getWayNodes()) {
// // TODO adjust interface to support a method getWayNodes()
// waynodes[i] = resolver.getNode(waynode.getNodeId());
// if (waynodes[i] == null) {
// validWay = false;
// LOGGER.finer("unknown way node: " + waynode.getNodeId() + " in way " + way.getId());
// }
// i++;
// }
//
// // for a valid way all way nodes must be existent in the input data
// if (validWay) {
//
// // mark the way as polygon if the first and the last way node are the same
// // and if the way has at least 4 way nodes
//
// if (waynodes[0].getId() == waynodes[waynodes.length - 1].getId()) {
// if (waynodes.length >= GeoUtils.MIN_NODES_POLYGON) {
// shape = SIMPLE_POLYGON;
// } else {
// LOGGER.finer("Found closed polygon with fewer than 4 way nodes. Way-id: " + way.getId());
// return null;
// }
// }
java.util.Arrays.sort(knownWayTags);
byte shape = LINE;
//if ("LINESTRING".equals(geom.getGeometryType() == null)
return new TDWay(id, ster.getLayer(), ster.getName(), ster.getHousenumber(), ster.getRef(),
knownWayTags, shape, geom);
// }
// }
//return null;
}
/**
* Constructor.
*
* @param id
* the id
* @param layer
* the layer
* @param name
* the name if existent
* @param houseNumber
* the house number if existent
* @param ref
* the ref if existent
* @param wayNodes
* the way nodes
*/
public TDWay(long id, byte layer, String name, String houseNumber, String ref, TDNode[] wayNodes) {
this.id = id;
this.layer = layer;
this.name = name;
this.houseNumber = houseNumber;
this.ref = ref;
this.wayNodes = wayNodes;
}
public TDWay(long id, byte layer, String name, String houseNumber, String ref, short[] tags, byte shape, Geometry geom) {
this.id = id;
this.layer = layer;
this.name = name;
this.houseNumber = houseNumber;
this.ref = ref;
this.tags = tags;
this.shape = shape;
this.setGeometry(geom);
this.wayNodes = null;
}
/**
* Constructor.
*
* @param id
* the id
* @param layer
* the layer
* @param name
* the name if existent
* @param houseNumber
* the house number if existent
* @param ref
* the ref if existent
* @param tags
* the tags
* @param shape
* the shape
* @param wayNodes
* the way nodes
*/
public TDWay(long id, byte layer, String name, String houseNumber, String ref, short[] tags, byte shape,
TDNode[] wayNodes) {
this.id = id;
this.layer = layer;
this.name = name;
this.houseNumber = houseNumber;
this.ref = ref;
this.tags = tags;
this.shape = shape;
this.wayNodes = wayNodes;
}
/**
* Merges tags from a relation with the tags of this way and puts the result into the way tags of this way.
*
* @param relation
* the relation
*/
// public void mergeRelationInformation(TDRelation relation) {
// if (relation.hasTags()) {
// addTags(relation.getTags());
// }
// if (getName() == null && relation.getName() != null) {
// setName(relation.getName());
// }
// if (getRef() == null && relation.getRef() != null) {
// setRef(relation.getRef());
// }
// }
/**
* @return the zoom level this entity appears first
*/
public byte getMinimumZoomLevel() {
return OSMTagMapping.getInstance().getZoomAppearWay(this.tags);
}
/**
* @return the name
*/
public String getName() {
return this.name;
}
/**
* @param name
* the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the house number
*/
public String getHouseNumber() {
return this.houseNumber;
}
/**
* @return the ref
*/
public String getRef() {
return this.ref;
}
/**
* @param ref
* the ref to set
*/
public void setRef(String ref) {
this.ref = ref;
}
/**
* @return the tags
*/
public short[] getTags() { // NOPMD by bross on 25.12.11 13:04
return this.tags; // NOPMD by bross on 25.12.11 13:07
}
/**
* @param tags
* the tags to set
*/
public void setTags(short[] tags) { // NOPMD by bross on 25.12.11 13:04
this.tags = tags;
}
/**
* @return the shape
*/
public byte getShape() {
return this.shape;
}
/**
* @param shape
* the shape to set
*/
public void setShape(byte shape) {
this.shape = shape;
}
/**
* @return the id
*/
public long getId() {
return this.id;
}
/**
* @return the layer
*/
public byte getLayer() {
return this.layer;
}
/**
* @return true, if the way has tags
*/
public boolean hasTags() {
return this.tags != null && this.tags.length > 0;
}
/**
* @return true, if the way is relevant for rendering
*/
public boolean isRenderRelevant() {
return hasTags() || getName() != null && !getName().isEmpty() || getRef() != null && !getRef().isEmpty();
}
// private void addTags(short[] addendum) { // NOPMD by bross on 25.12.11 13:04
// if (this.tags == null) {
// this.tags = addendum;
// } else {
// TShortSet tags2 = new TShortHashSet();
// tags2.addAll(this.tags);
// tags2.addAll(addendum);
// this.tags = tags2.toArray();
// }
//
// }
/**
* @return true, if the way has at least 4 coordinates and the first and last coordinate are equal
*/
public boolean isPolygon() {
return this.wayNodes != null && this.wayNodes.length >= GeoUtils.MIN_NODES_POLYGON
&& this.wayNodes[0].getId() == this.wayNodes[this.wayNodes.length - 1].getId();
}
/**
* @return true, if the way represents a coastline
*/
public boolean isCoastline() {
if (this.tags == null) {
return false;
}
OSMTag tag;
for (short tagID : this.tags) { // NOPMD by bross on 25.12.11 13:04
tag = OSMTagMapping.getInstance().getWayTag(tagID);
if (tag.isCoastline()) {
return true;
}
}
return false;
}
/**
* @return the way nodes
*/
public TDNode[] getWayNodes() {
return this.wayNodes; // NOPMD by bross on 25.12.11 13:07
}
/**
* @return true, if the way nodes have been reversed with respect to a particular relation
*/
public boolean isReversedInRelation() {
return this.reversedInRelation;
}
/**
* @param reversedInRelation
* set the flag that indicates whether the order of the way nodes are reversed by a particular relation
*/
public void setReversedInRelation(boolean reversedInRelation) {
this.reversedInRelation = reversedInRelation;
}
/**
* @return true, if the way has a tag that forces a closed way to be a polygon line (instead of an area)
*/
public boolean isForcePolygonLine() {
if (!hasTags()) {
return false;
}
OSMTagMapping mapping = OSMTagMapping.getInstance();
for (short tag : this.tags) { // NOPMD by bross on 25.12.11 13:05
if (mapping.getWayTag(tag).isForcePolygonLine()) {
return true;
}
}
return false;
}
/**
* @return the invalid
*/
public boolean isInvalid() {
return this.invalid;
}
/**
* @param invalid
* the invalid to set
*/
public void setInvalid(boolean invalid) {
this.invalid = invalid;
}
@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;
}
TDWay other = (TDWay) obj;
if (this.id != other.id) {
return false;
}
return true;
}
@Override
public String toString() {
return "TDWay [id=" + this.id + ", name=" + this.name + ", ref=" + this.ref + ", tags=" + Arrays.toString(this.tags) + ", polygon="
+ this.shape + "]";
}
public Geometry getGeometry() {
return geometry;
}
public void setGeometry(Geometry geometry) {
this.geometry = geometry;
}
}