Normalize all the line endings
This commit is contained in:
@@ -1,350 +1,350 @@
|
||||
/*
|
||||
* Copyright 2014 Hannes Janetzek
|
||||
*
|
||||
* This file is part of the OpenScienceMap project (http://www.opensciencemap.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.oscim.tiling.source.geojson;
|
||||
|
||||
import static com.fasterxml.jackson.core.JsonToken.END_ARRAY;
|
||||
import static com.fasterxml.jackson.core.JsonToken.END_OBJECT;
|
||||
import static com.fasterxml.jackson.core.JsonToken.FIELD_NAME;
|
||||
import static com.fasterxml.jackson.core.JsonToken.START_ARRAY;
|
||||
import static com.fasterxml.jackson.core.JsonToken.START_OBJECT;
|
||||
import static com.fasterxml.jackson.core.JsonToken.VALUE_NUMBER_FLOAT;
|
||||
import static com.fasterxml.jackson.core.JsonToken.VALUE_NUMBER_INT;
|
||||
import static com.fasterxml.jackson.core.JsonToken.VALUE_STRING;
|
||||
import static org.oscim.core.MercatorProjection.latitudeToY;
|
||||
import static org.oscim.core.MercatorProjection.longitudeToX;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
import org.oscim.core.GeometryBuffer.GeometryType;
|
||||
import org.oscim.core.MapElement;
|
||||
import org.oscim.core.Tile;
|
||||
import org.oscim.tiling.ITileDataSink;
|
||||
import org.oscim.tiling.source.ITileDecoder;
|
||||
import org.oscim.utils.ArrayUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonFactory;
|
||||
import com.fasterxml.jackson.core.JsonParseException;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.JsonToken;
|
||||
|
||||
public class GeoJsonTileDecoder implements ITileDecoder {
|
||||
static final Logger log = LoggerFactory.getLogger(GeoJsonTileDecoder.class);
|
||||
|
||||
private final MapElement mMapElement;
|
||||
private final GeoJsonTileSource mTileSource;
|
||||
private final LinkedHashMap<String, Object> mTagMap;
|
||||
private final JsonFactory mJsonFactory;
|
||||
|
||||
private final static char[] FIELD_FEATURES = "features".toCharArray();
|
||||
private final static char[] FIELD_GEOMETRY = "geometry".toCharArray();
|
||||
private final static char[] FIELD_PROPERTIES = "properties".toCharArray();
|
||||
private final static char[] FIELD_COORDINATES = "coordinates".toCharArray();
|
||||
private final static char[] FIELD_TYPE = "type".toCharArray();
|
||||
|
||||
private final static char[] LINETRING = "LineString".toCharArray();
|
||||
private final static char[] POLYGON = "Polygon".toCharArray();
|
||||
private final static char[] POINT = "Point".toCharArray();
|
||||
private final static char[] MULTI_LINESTRING = "MultiLineString".toCharArray();
|
||||
private final static char[] MULTI_POLYGON = "MultiPolygon".toCharArray();
|
||||
private final static char[] MULTI_POINT = "MultiPoint".toCharArray();
|
||||
|
||||
private ITileDataSink mTileDataSink;
|
||||
|
||||
private double mTileY, mTileX, mTileScale;
|
||||
|
||||
public GeoJsonTileDecoder(GeoJsonTileSource tileSource) {
|
||||
mTileSource = tileSource;
|
||||
mTagMap = new LinkedHashMap<String, Object>();
|
||||
mJsonFactory = new JsonFactory();
|
||||
|
||||
mMapElement = new MapElement();
|
||||
mMapElement.layer = 5;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean decode(Tile tile, ITileDataSink sink, InputStream is) throws IOException {
|
||||
mTileDataSink = sink;
|
||||
mTileScale = 1 << tile.zoomLevel;
|
||||
mTileX = tile.tileX / mTileScale;
|
||||
mTileY = tile.tileY / mTileScale;
|
||||
mTileScale *= Tile.SIZE;
|
||||
|
||||
JsonParser jp = mJsonFactory.createParser(new InputStreamReader(is));
|
||||
|
||||
for (JsonToken t; (t = jp.nextToken()) != null;) {
|
||||
if (t == FIELD_NAME) {
|
||||
if (match(jp, FIELD_FEATURES)) {
|
||||
if (jp.nextToken() != START_ARRAY)
|
||||
continue;
|
||||
|
||||
while ((t = jp.nextToken()) != null) {
|
||||
if (t == START_OBJECT)
|
||||
parseFeature(jp);
|
||||
|
||||
if (t == END_ARRAY)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void parseFeature(JsonParser jp)
|
||||
throws JsonParseException, IOException {
|
||||
|
||||
mMapElement.clear();
|
||||
mMapElement.tags.clear();
|
||||
mTagMap.clear();
|
||||
|
||||
for (JsonToken t; (t = jp.nextToken()) != null;) {
|
||||
if (t == FIELD_NAME) {
|
||||
if (match(jp, FIELD_GEOMETRY)) {
|
||||
if (jp.nextToken() == START_OBJECT)
|
||||
parseGeometry(jp);
|
||||
}
|
||||
|
||||
if (match(jp, FIELD_PROPERTIES)) {
|
||||
if (jp.nextToken() == START_OBJECT)
|
||||
parseProperties(jp);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (t == END_OBJECT)
|
||||
break;
|
||||
}
|
||||
|
||||
//add tag information
|
||||
mTileSource.decodeTags(mMapElement, mTagMap);
|
||||
if (mMapElement.tags.numTags == 0)
|
||||
return;
|
||||
|
||||
mTileSource.postGeomHook(mMapElement);
|
||||
|
||||
if (mMapElement.type == GeometryType.NONE)
|
||||
return;
|
||||
|
||||
//process this element
|
||||
mTileDataSink.process(mMapElement);
|
||||
}
|
||||
|
||||
private void parseProperties(JsonParser jp)
|
||||
throws JsonParseException, IOException {
|
||||
for (JsonToken t; (t = jp.nextToken()) != null;) {
|
||||
if (t == FIELD_NAME) {
|
||||
String text = jp.getCurrentName();
|
||||
|
||||
t = jp.nextToken();
|
||||
if (t == VALUE_STRING) {
|
||||
mTagMap.put(text, jp.getText());
|
||||
} else if (t == VALUE_NUMBER_INT) {
|
||||
mTagMap.put(text, jp.getNumberValue());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (t == END_OBJECT)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void parseGeometry(JsonParser jp)
|
||||
throws JsonParseException, IOException {
|
||||
|
||||
boolean multi = false;
|
||||
GeometryType type = GeometryType.NONE;
|
||||
|
||||
for (JsonToken t; (t = jp.nextToken()) != null;) {
|
||||
if (t == FIELD_NAME) {
|
||||
if (match(jp, FIELD_COORDINATES)) {
|
||||
if (jp.nextToken() != START_ARRAY)
|
||||
continue;
|
||||
if (multi) {
|
||||
parseMulti(jp, type);
|
||||
} else {
|
||||
if (type == GeometryType.POLY)
|
||||
parsePolygon(jp);
|
||||
|
||||
if (type == GeometryType.LINE)
|
||||
parseLineString(jp);
|
||||
|
||||
if (type == GeometryType.POINT)
|
||||
parseCoordinate(jp);
|
||||
|
||||
}
|
||||
} else if (match(jp, FIELD_TYPE)) {
|
||||
multi = false;
|
||||
|
||||
jp.nextToken();
|
||||
|
||||
if (match(jp, LINETRING))
|
||||
type = GeometryType.LINE;
|
||||
else if (match(jp, POLYGON))
|
||||
type = GeometryType.POLY;
|
||||
else if (match(jp, POINT))
|
||||
type = GeometryType.POINT;
|
||||
else if (match(jp, MULTI_LINESTRING)) {
|
||||
type = GeometryType.LINE;
|
||||
multi = true;
|
||||
}
|
||||
else if (match(jp, MULTI_POLYGON)) {
|
||||
type = GeometryType.POLY;
|
||||
multi = true;
|
||||
}
|
||||
else if (match(jp, MULTI_POINT)) {
|
||||
type = GeometryType.POINT;
|
||||
multi = true;
|
||||
}
|
||||
|
||||
if (type == GeometryType.POINT)
|
||||
mMapElement.startPoints();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (t == END_OBJECT)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void parseMulti(JsonParser jp, GeometryType type)
|
||||
throws JsonParseException, IOException {
|
||||
|
||||
for (JsonToken t; (t = jp.nextToken()) != null;) {
|
||||
if (t == END_ARRAY)
|
||||
break;
|
||||
|
||||
if (t == START_ARRAY) {
|
||||
if (type == GeometryType.POLY)
|
||||
parsePolygon(jp);
|
||||
|
||||
else if (type == GeometryType.LINE)
|
||||
parseLineString(jp);
|
||||
|
||||
else if (type == GeometryType.POINT)
|
||||
parseCoordinate(jp);;
|
||||
|
||||
} else {
|
||||
//....
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void parsePolygon(JsonParser jp)
|
||||
throws JsonParseException, IOException {
|
||||
int ring = 0;
|
||||
|
||||
for (JsonToken t; (t = jp.nextToken()) != null;) {
|
||||
if (t == START_ARRAY) {
|
||||
if (ring == 0)
|
||||
mMapElement.startPolygon();
|
||||
else
|
||||
mMapElement.startHole();
|
||||
|
||||
ring++;
|
||||
parseCoordSequence(jp);
|
||||
removeLastPoint();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (t == END_ARRAY)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void removeLastPoint() {
|
||||
mMapElement.pointPos -= 2;
|
||||
mMapElement.index[mMapElement.indexPos] -= 2;
|
||||
}
|
||||
|
||||
private void parseLineString(JsonParser jp)
|
||||
throws JsonParseException, IOException {
|
||||
mMapElement.startLine();
|
||||
parseCoordSequence(jp);
|
||||
}
|
||||
|
||||
private void parseCoordSequence(JsonParser jp)
|
||||
throws JsonParseException, IOException {
|
||||
|
||||
for (JsonToken t; (t = jp.nextToken()) != null;) {
|
||||
|
||||
if (t == START_ARRAY) {
|
||||
parseCoordinate(jp);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (t == END_ARRAY)
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void parseCoordinate(JsonParser jp)
|
||||
throws JsonParseException, IOException {
|
||||
int pos = 0;
|
||||
double x = 0, y = 0; //, z = 0;
|
||||
|
||||
for (JsonToken t; (t = jp.nextToken()) != null;) {
|
||||
if (t == VALUE_NUMBER_FLOAT || t == VALUE_NUMBER_INT) {
|
||||
|
||||
// avoid String allocation (by getDouble...)
|
||||
char[] val = jp.getTextCharacters();
|
||||
int offset = jp.getTextOffset();
|
||||
int length = jp.getTextLength();
|
||||
double c = ArrayUtils.parseNumber(val, offset, offset + length);
|
||||
|
||||
if (pos == 0)
|
||||
x = c;
|
||||
if (pos == 1)
|
||||
y = c;
|
||||
//if (pos == 2)
|
||||
//z = c;
|
||||
|
||||
pos++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (t == END_ARRAY)
|
||||
break;
|
||||
}
|
||||
|
||||
mMapElement.addPoint((float) ((longitudeToX(x) - mTileX) * mTileScale),
|
||||
(float) ((latitudeToY(y) - mTileY) * mTileScale));
|
||||
|
||||
}
|
||||
|
||||
private final static boolean match(JsonParser jp, char[] fieldName)
|
||||
throws JsonParseException, IOException {
|
||||
|
||||
int length = jp.getTextLength();
|
||||
if (length != fieldName.length)
|
||||
return false;
|
||||
|
||||
char[] val = jp.getTextCharacters();
|
||||
int offset = jp.getTextOffset();
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
if (fieldName[i] != val[i + offset])
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright 2014 Hannes Janetzek
|
||||
*
|
||||
* This file is part of the OpenScienceMap project (http://www.opensciencemap.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.oscim.tiling.source.geojson;
|
||||
|
||||
import static com.fasterxml.jackson.core.JsonToken.END_ARRAY;
|
||||
import static com.fasterxml.jackson.core.JsonToken.END_OBJECT;
|
||||
import static com.fasterxml.jackson.core.JsonToken.FIELD_NAME;
|
||||
import static com.fasterxml.jackson.core.JsonToken.START_ARRAY;
|
||||
import static com.fasterxml.jackson.core.JsonToken.START_OBJECT;
|
||||
import static com.fasterxml.jackson.core.JsonToken.VALUE_NUMBER_FLOAT;
|
||||
import static com.fasterxml.jackson.core.JsonToken.VALUE_NUMBER_INT;
|
||||
import static com.fasterxml.jackson.core.JsonToken.VALUE_STRING;
|
||||
import static org.oscim.core.MercatorProjection.latitudeToY;
|
||||
import static org.oscim.core.MercatorProjection.longitudeToX;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
import org.oscim.core.GeometryBuffer.GeometryType;
|
||||
import org.oscim.core.MapElement;
|
||||
import org.oscim.core.Tile;
|
||||
import org.oscim.tiling.ITileDataSink;
|
||||
import org.oscim.tiling.source.ITileDecoder;
|
||||
import org.oscim.utils.ArrayUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonFactory;
|
||||
import com.fasterxml.jackson.core.JsonParseException;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.JsonToken;
|
||||
|
||||
public class GeoJsonTileDecoder implements ITileDecoder {
|
||||
static final Logger log = LoggerFactory.getLogger(GeoJsonTileDecoder.class);
|
||||
|
||||
private final MapElement mMapElement;
|
||||
private final GeoJsonTileSource mTileSource;
|
||||
private final LinkedHashMap<String, Object> mTagMap;
|
||||
private final JsonFactory mJsonFactory;
|
||||
|
||||
private final static char[] FIELD_FEATURES = "features".toCharArray();
|
||||
private final static char[] FIELD_GEOMETRY = "geometry".toCharArray();
|
||||
private final static char[] FIELD_PROPERTIES = "properties".toCharArray();
|
||||
private final static char[] FIELD_COORDINATES = "coordinates".toCharArray();
|
||||
private final static char[] FIELD_TYPE = "type".toCharArray();
|
||||
|
||||
private final static char[] LINETRING = "LineString".toCharArray();
|
||||
private final static char[] POLYGON = "Polygon".toCharArray();
|
||||
private final static char[] POINT = "Point".toCharArray();
|
||||
private final static char[] MULTI_LINESTRING = "MultiLineString".toCharArray();
|
||||
private final static char[] MULTI_POLYGON = "MultiPolygon".toCharArray();
|
||||
private final static char[] MULTI_POINT = "MultiPoint".toCharArray();
|
||||
|
||||
private ITileDataSink mTileDataSink;
|
||||
|
||||
private double mTileY, mTileX, mTileScale;
|
||||
|
||||
public GeoJsonTileDecoder(GeoJsonTileSource tileSource) {
|
||||
mTileSource = tileSource;
|
||||
mTagMap = new LinkedHashMap<String, Object>();
|
||||
mJsonFactory = new JsonFactory();
|
||||
|
||||
mMapElement = new MapElement();
|
||||
mMapElement.layer = 5;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean decode(Tile tile, ITileDataSink sink, InputStream is) throws IOException {
|
||||
mTileDataSink = sink;
|
||||
mTileScale = 1 << tile.zoomLevel;
|
||||
mTileX = tile.tileX / mTileScale;
|
||||
mTileY = tile.tileY / mTileScale;
|
||||
mTileScale *= Tile.SIZE;
|
||||
|
||||
JsonParser jp = mJsonFactory.createParser(new InputStreamReader(is));
|
||||
|
||||
for (JsonToken t; (t = jp.nextToken()) != null;) {
|
||||
if (t == FIELD_NAME) {
|
||||
if (match(jp, FIELD_FEATURES)) {
|
||||
if (jp.nextToken() != START_ARRAY)
|
||||
continue;
|
||||
|
||||
while ((t = jp.nextToken()) != null) {
|
||||
if (t == START_OBJECT)
|
||||
parseFeature(jp);
|
||||
|
||||
if (t == END_ARRAY)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void parseFeature(JsonParser jp)
|
||||
throws JsonParseException, IOException {
|
||||
|
||||
mMapElement.clear();
|
||||
mMapElement.tags.clear();
|
||||
mTagMap.clear();
|
||||
|
||||
for (JsonToken t; (t = jp.nextToken()) != null;) {
|
||||
if (t == FIELD_NAME) {
|
||||
if (match(jp, FIELD_GEOMETRY)) {
|
||||
if (jp.nextToken() == START_OBJECT)
|
||||
parseGeometry(jp);
|
||||
}
|
||||
|
||||
if (match(jp, FIELD_PROPERTIES)) {
|
||||
if (jp.nextToken() == START_OBJECT)
|
||||
parseProperties(jp);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (t == END_OBJECT)
|
||||
break;
|
||||
}
|
||||
|
||||
//add tag information
|
||||
mTileSource.decodeTags(mMapElement, mTagMap);
|
||||
if (mMapElement.tags.numTags == 0)
|
||||
return;
|
||||
|
||||
mTileSource.postGeomHook(mMapElement);
|
||||
|
||||
if (mMapElement.type == GeometryType.NONE)
|
||||
return;
|
||||
|
||||
//process this element
|
||||
mTileDataSink.process(mMapElement);
|
||||
}
|
||||
|
||||
private void parseProperties(JsonParser jp)
|
||||
throws JsonParseException, IOException {
|
||||
for (JsonToken t; (t = jp.nextToken()) != null;) {
|
||||
if (t == FIELD_NAME) {
|
||||
String text = jp.getCurrentName();
|
||||
|
||||
t = jp.nextToken();
|
||||
if (t == VALUE_STRING) {
|
||||
mTagMap.put(text, jp.getText());
|
||||
} else if (t == VALUE_NUMBER_INT) {
|
||||
mTagMap.put(text, jp.getNumberValue());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (t == END_OBJECT)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void parseGeometry(JsonParser jp)
|
||||
throws JsonParseException, IOException {
|
||||
|
||||
boolean multi = false;
|
||||
GeometryType type = GeometryType.NONE;
|
||||
|
||||
for (JsonToken t; (t = jp.nextToken()) != null;) {
|
||||
if (t == FIELD_NAME) {
|
||||
if (match(jp, FIELD_COORDINATES)) {
|
||||
if (jp.nextToken() != START_ARRAY)
|
||||
continue;
|
||||
if (multi) {
|
||||
parseMulti(jp, type);
|
||||
} else {
|
||||
if (type == GeometryType.POLY)
|
||||
parsePolygon(jp);
|
||||
|
||||
if (type == GeometryType.LINE)
|
||||
parseLineString(jp);
|
||||
|
||||
if (type == GeometryType.POINT)
|
||||
parseCoordinate(jp);
|
||||
|
||||
}
|
||||
} else if (match(jp, FIELD_TYPE)) {
|
||||
multi = false;
|
||||
|
||||
jp.nextToken();
|
||||
|
||||
if (match(jp, LINETRING))
|
||||
type = GeometryType.LINE;
|
||||
else if (match(jp, POLYGON))
|
||||
type = GeometryType.POLY;
|
||||
else if (match(jp, POINT))
|
||||
type = GeometryType.POINT;
|
||||
else if (match(jp, MULTI_LINESTRING)) {
|
||||
type = GeometryType.LINE;
|
||||
multi = true;
|
||||
}
|
||||
else if (match(jp, MULTI_POLYGON)) {
|
||||
type = GeometryType.POLY;
|
||||
multi = true;
|
||||
}
|
||||
else if (match(jp, MULTI_POINT)) {
|
||||
type = GeometryType.POINT;
|
||||
multi = true;
|
||||
}
|
||||
|
||||
if (type == GeometryType.POINT)
|
||||
mMapElement.startPoints();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (t == END_OBJECT)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void parseMulti(JsonParser jp, GeometryType type)
|
||||
throws JsonParseException, IOException {
|
||||
|
||||
for (JsonToken t; (t = jp.nextToken()) != null;) {
|
||||
if (t == END_ARRAY)
|
||||
break;
|
||||
|
||||
if (t == START_ARRAY) {
|
||||
if (type == GeometryType.POLY)
|
||||
parsePolygon(jp);
|
||||
|
||||
else if (type == GeometryType.LINE)
|
||||
parseLineString(jp);
|
||||
|
||||
else if (type == GeometryType.POINT)
|
||||
parseCoordinate(jp);;
|
||||
|
||||
} else {
|
||||
//....
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void parsePolygon(JsonParser jp)
|
||||
throws JsonParseException, IOException {
|
||||
int ring = 0;
|
||||
|
||||
for (JsonToken t; (t = jp.nextToken()) != null;) {
|
||||
if (t == START_ARRAY) {
|
||||
if (ring == 0)
|
||||
mMapElement.startPolygon();
|
||||
else
|
||||
mMapElement.startHole();
|
||||
|
||||
ring++;
|
||||
parseCoordSequence(jp);
|
||||
removeLastPoint();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (t == END_ARRAY)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void removeLastPoint() {
|
||||
mMapElement.pointPos -= 2;
|
||||
mMapElement.index[mMapElement.indexPos] -= 2;
|
||||
}
|
||||
|
||||
private void parseLineString(JsonParser jp)
|
||||
throws JsonParseException, IOException {
|
||||
mMapElement.startLine();
|
||||
parseCoordSequence(jp);
|
||||
}
|
||||
|
||||
private void parseCoordSequence(JsonParser jp)
|
||||
throws JsonParseException, IOException {
|
||||
|
||||
for (JsonToken t; (t = jp.nextToken()) != null;) {
|
||||
|
||||
if (t == START_ARRAY) {
|
||||
parseCoordinate(jp);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (t == END_ARRAY)
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void parseCoordinate(JsonParser jp)
|
||||
throws JsonParseException, IOException {
|
||||
int pos = 0;
|
||||
double x = 0, y = 0; //, z = 0;
|
||||
|
||||
for (JsonToken t; (t = jp.nextToken()) != null;) {
|
||||
if (t == VALUE_NUMBER_FLOAT || t == VALUE_NUMBER_INT) {
|
||||
|
||||
// avoid String allocation (by getDouble...)
|
||||
char[] val = jp.getTextCharacters();
|
||||
int offset = jp.getTextOffset();
|
||||
int length = jp.getTextLength();
|
||||
double c = ArrayUtils.parseNumber(val, offset, offset + length);
|
||||
|
||||
if (pos == 0)
|
||||
x = c;
|
||||
if (pos == 1)
|
||||
y = c;
|
||||
//if (pos == 2)
|
||||
//z = c;
|
||||
|
||||
pos++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (t == END_ARRAY)
|
||||
break;
|
||||
}
|
||||
|
||||
mMapElement.addPoint((float) ((longitudeToX(x) - mTileX) * mTileScale),
|
||||
(float) ((latitudeToY(y) - mTileY) * mTileScale));
|
||||
|
||||
}
|
||||
|
||||
private final static boolean match(JsonParser jp, char[] fieldName)
|
||||
throws JsonParseException, IOException {
|
||||
|
||||
int length = jp.getTextLength();
|
||||
if (length != fieldName.length)
|
||||
return false;
|
||||
|
||||
char[] val = jp.getTextCharacters();
|
||||
int offset = jp.getTextOffset();
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
if (fieldName[i] != val[i + offset])
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,71 +1,71 @@
|
||||
/*
|
||||
* Copyright 2014 Hannes Janetzek
|
||||
*
|
||||
* This file is part of the OpenScienceMap project (http://www.opensciencemap.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.oscim.tiling.source.geojson;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.oscim.core.MapElement;
|
||||
import org.oscim.core.Tag;
|
||||
import org.oscim.tiling.ITileDataSource;
|
||||
import org.oscim.tiling.source.UrlTileDataSource;
|
||||
import org.oscim.tiling.source.UrlTileSource;
|
||||
|
||||
public abstract class GeoJsonTileSource extends UrlTileSource {
|
||||
|
||||
public GeoJsonTileSource(String url) {
|
||||
super(url, "/{Z}/{X}/{Y}.json");
|
||||
Map<String, String> opt = new HashMap<String, String>();
|
||||
opt.put("Accept-Encoding", "gzip");
|
||||
setHttpRequestHeaders(opt);
|
||||
}
|
||||
|
||||
public GeoJsonTileSource(String url, int zoomMin, int zoomMax) {
|
||||
super(url, "/{Z}/{X}/{Y}.json", zoomMin, zoomMax);
|
||||
Map<String, String> opt = new HashMap<String, String>();
|
||||
opt.put("Accept-Encoding", "gzip");
|
||||
setHttpRequestHeaders(opt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ITileDataSource getDataSource() {
|
||||
|
||||
return new UrlTileDataSource(this, new GeoJsonTileDecoder(this), getHttpEngine());
|
||||
}
|
||||
|
||||
public Tag getFeatureTag() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** allow overriding tag handling */
|
||||
public abstract void decodeTags(MapElement mapElement, Map<String, Object> properties);
|
||||
|
||||
public Tag rewriteTag(String key, Object value) {
|
||||
|
||||
if (value == null)
|
||||
return null;
|
||||
|
||||
String val = (value instanceof String) ? (String) value : String.valueOf(value);
|
||||
|
||||
return new Tag(key, val);
|
||||
}
|
||||
|
||||
/** modify mapElement before process() */
|
||||
public void postGeomHook(MapElement mapElement) {
|
||||
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright 2014 Hannes Janetzek
|
||||
*
|
||||
* This file is part of the OpenScienceMap project (http://www.opensciencemap.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.oscim.tiling.source.geojson;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.oscim.core.MapElement;
|
||||
import org.oscim.core.Tag;
|
||||
import org.oscim.tiling.ITileDataSource;
|
||||
import org.oscim.tiling.source.UrlTileDataSource;
|
||||
import org.oscim.tiling.source.UrlTileSource;
|
||||
|
||||
public abstract class GeoJsonTileSource extends UrlTileSource {
|
||||
|
||||
public GeoJsonTileSource(String url) {
|
||||
super(url, "/{Z}/{X}/{Y}.json");
|
||||
Map<String, String> opt = new HashMap<String, String>();
|
||||
opt.put("Accept-Encoding", "gzip");
|
||||
setHttpRequestHeaders(opt);
|
||||
}
|
||||
|
||||
public GeoJsonTileSource(String url, int zoomMin, int zoomMax) {
|
||||
super(url, "/{Z}/{X}/{Y}.json", zoomMin, zoomMax);
|
||||
Map<String, String> opt = new HashMap<String, String>();
|
||||
opt.put("Accept-Encoding", "gzip");
|
||||
setHttpRequestHeaders(opt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ITileDataSource getDataSource() {
|
||||
|
||||
return new UrlTileDataSource(this, new GeoJsonTileDecoder(this), getHttpEngine());
|
||||
}
|
||||
|
||||
public Tag getFeatureTag() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** allow overriding tag handling */
|
||||
public abstract void decodeTags(MapElement mapElement, Map<String, Object> properties);
|
||||
|
||||
public Tag rewriteTag(String key, Object value) {
|
||||
|
||||
if (value == null)
|
||||
return null;
|
||||
|
||||
String val = (value instanceof String) ? (String) value : String.valueOf(value);
|
||||
|
||||
return new Tag(key, val);
|
||||
}
|
||||
|
||||
/** modify mapElement before process() */
|
||||
public void postGeomHook(MapElement mapElement) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,366 +1,366 @@
|
||||
package org.oscim.utils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Triangulates a polygon into triangles - duh. Doesn't handle
|
||||
* holes in polys
|
||||
*
|
||||
* @author Public Source from FlipCode
|
||||
*/
|
||||
public class Triangulator {
|
||||
/** The accepted error value */
|
||||
private static final float EPSILON = 0.0000000001f;
|
||||
/** The list of points to be triangulated */
|
||||
private final PointList poly = new PointList();
|
||||
/** The list of points describing the triangles */
|
||||
private final PointList tris = new PointList();
|
||||
/** True if we've tried to triangulate */
|
||||
private boolean tried;
|
||||
|
||||
/**
|
||||
* Create a new triangulator
|
||||
*/
|
||||
public Triangulator() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a point describing the polygon to be triangulated
|
||||
*
|
||||
* @param x The x coordinate of the point
|
||||
* @param y the y coordinate of the point
|
||||
*/
|
||||
public void addPolyPoint(float x, float y) {
|
||||
poly.add(new Point(x, y));
|
||||
}
|
||||
|
||||
/**
|
||||
* Cause the triangulator to split the polygon
|
||||
*
|
||||
* @return True if we managed the task
|
||||
*/
|
||||
public boolean triangulate() {
|
||||
tried = true;
|
||||
|
||||
boolean worked = process(poly, tris);
|
||||
return worked;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a count of the number of triangles produced
|
||||
*
|
||||
* @return The number of triangles produced
|
||||
*/
|
||||
public int getTriangleCount() {
|
||||
if (!tried) {
|
||||
throw new RuntimeException("Call triangulate() before accessing triangles");
|
||||
}
|
||||
return tris.size() / 3;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a point on a specified generated triangle
|
||||
*
|
||||
* @param tri The index of the triangle to interegate
|
||||
* @param i The index of the point within the triangle to retrieve
|
||||
* (0 - 2)
|
||||
* @return The x,y coordinate pair for the point
|
||||
*/
|
||||
public float[] getTrianglePoint(int tri, int i) {
|
||||
if (!tried) {
|
||||
throw new RuntimeException("Call triangulate() before accessing triangles");
|
||||
}
|
||||
return tris.get((tri * 3) + i).toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the area of a polygon defined by the series of points
|
||||
* in the list
|
||||
*
|
||||
* @param contour The list of points defined the contour of the polygon
|
||||
* (Vector2f)
|
||||
* @return The area of the polygon defined
|
||||
*/
|
||||
private static float area(PointList contour) {
|
||||
int n = contour.size();
|
||||
|
||||
float A = 0.0f;
|
||||
|
||||
for (int p = n - 1, q = 0; q < n; p = q++) {
|
||||
Point contourP = contour.get(p);
|
||||
Point contourQ = contour.get(q);
|
||||
|
||||
A += contourP.getX() * contourQ.getY() - contourQ.getX()
|
||||
* contourP.getY();
|
||||
}
|
||||
return A * 0.5f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the point P is inside the triangle defined by
|
||||
* the points A,B,C
|
||||
*
|
||||
* @param Ax Point A x-coordinate
|
||||
* @param Ay Point A y-coordinate
|
||||
* @param Bx Point B x-coordinate
|
||||
* @param By Point B y-coordinate
|
||||
* @param Cx Point C x-coordinate
|
||||
* @param Cy Point C y-coordinate
|
||||
* @param Px Point P x-coordinate
|
||||
* @param Py Point P y-coordinate
|
||||
* @return True if the point specified is within the triangle
|
||||
*/
|
||||
private static boolean insideTriangle(float Ax, float Ay, float Bx,
|
||||
float By, float Cx, float Cy, float Px, float Py) {
|
||||
float ax, ay, bx, by, cx, cy, apx, apy, bpx, bpy, cpx, cpy;
|
||||
float cCROSSap, bCROSScp, aCROSSbp;
|
||||
|
||||
ax = Cx - Bx;
|
||||
ay = Cy - By;
|
||||
bx = Ax - Cx;
|
||||
by = Ay - Cy;
|
||||
cx = Bx - Ax;
|
||||
cy = By - Ay;
|
||||
apx = Px - Ax;
|
||||
apy = Py - Ay;
|
||||
bpx = Px - Bx;
|
||||
bpy = Py - By;
|
||||
cpx = Px - Cx;
|
||||
cpy = Py - Cy;
|
||||
|
||||
aCROSSbp = ax * bpy - ay * bpx;
|
||||
cCROSSap = cx * apy - cy * apx;
|
||||
bCROSScp = bx * cpy - by * cpx;
|
||||
|
||||
return ((aCROSSbp >= 0.0f) && (bCROSScp >= 0.0f) && (cCROSSap >= 0.0f));
|
||||
}
|
||||
|
||||
/**
|
||||
* Cut a the contour and add a triangle into V to describe the
|
||||
* location of the cut
|
||||
*
|
||||
* @param contour The list of points defining the polygon
|
||||
* @param u The index of the first point
|
||||
* @param v The index of the second point
|
||||
* @param w The index of the third point
|
||||
* @param n ?
|
||||
* @param V The array to populate with indicies of triangles
|
||||
* @return True if a triangle was found
|
||||
*/
|
||||
private static boolean snip(PointList contour, int u, int v, int w, int n,
|
||||
int[] V) {
|
||||
int p;
|
||||
float Ax, Ay, Bx, By, Cx, Cy, Px, Py;
|
||||
|
||||
Ax = contour.get(V[u]).getX();
|
||||
Ay = contour.get(V[u]).getY();
|
||||
|
||||
Bx = contour.get(V[v]).getX();
|
||||
By = contour.get(V[v]).getY();
|
||||
|
||||
Cx = contour.get(V[w]).getX();
|
||||
Cy = contour.get(V[w]).getY();
|
||||
|
||||
if (EPSILON > (((Bx - Ax) * (Cy - Ay)) - ((By - Ay) * (Cx - Ax)))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (p = 0; p < n; p++) {
|
||||
if ((p == u) || (p == v) || (p == w)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Px = contour.get(V[p]).getX();
|
||||
Py = contour.get(V[p]).getY();
|
||||
|
||||
if (insideTriangle(Ax, Ay, Bx, By, Cx, Cy, Px, Py)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a list of points defining a polygon
|
||||
*
|
||||
* @param contour The list of points describing the polygon
|
||||
* @param result The list of points describing the triangles. Groups
|
||||
* of 3 describe each triangle
|
||||
* @return True if we succeeded in completing triangulation
|
||||
*/
|
||||
private static boolean process(PointList contour, PointList result) {
|
||||
/* allocate and initialize list of Vertices in polygon */
|
||||
|
||||
int n = contour.size();
|
||||
if (n < 3)
|
||||
return false;
|
||||
|
||||
int[] V = new int[n];
|
||||
|
||||
/* we want a counter-clockwise polygon in V */
|
||||
|
||||
if (0.0f < area(contour)) {
|
||||
for (int v = 0; v < n; v++)
|
||||
V[v] = v;
|
||||
} else {
|
||||
for (int v = 0; v < n; v++)
|
||||
V[v] = (n - 1) - v;
|
||||
}
|
||||
|
||||
int nv = n;
|
||||
|
||||
/* remove nv-2 Vertices, creating 1 triangle every time */
|
||||
int count = 2 * nv; /* error detection */
|
||||
|
||||
//for (int m = 0, v = nv - 1; nv > 2;) {
|
||||
for (int v = nv - 1; nv > 2;) {
|
||||
/* if we loop, it is probably a non-simple polygon */
|
||||
if (0 >= (count--)) {
|
||||
//** Triangulate: ERROR - probable bad polygon!
|
||||
return false;
|
||||
}
|
||||
|
||||
/* three consecutive vertices in current polygon, <u,v,w> */
|
||||
int u = v;
|
||||
if (nv <= u)
|
||||
u = 0; /* previous */
|
||||
v = u + 1;
|
||||
if (nv <= v)
|
||||
v = 0; /* new v */
|
||||
int w = v + 1;
|
||||
if (nv <= w)
|
||||
w = 0; /* next */
|
||||
|
||||
if (snip(contour, u, v, w, nv, V)) {
|
||||
int a, b, c, s, t;
|
||||
|
||||
/* true names of the vertices */
|
||||
a = V[u];
|
||||
b = V[v];
|
||||
c = V[w];
|
||||
|
||||
/* output Triangle */
|
||||
result.add(contour.get(a));
|
||||
result.add(contour.get(b));
|
||||
result.add(contour.get(c));
|
||||
|
||||
//m++;
|
||||
|
||||
/* remove v from remaining polygon */
|
||||
for (s = v, t = v + 1; t < nv; s++, t++) {
|
||||
V[s] = V[t];
|
||||
}
|
||||
nv--;
|
||||
|
||||
/* resest error detection counter */
|
||||
count = 2 * nv;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* A single point handled by the triangulator
|
||||
*
|
||||
* @author Kevin Glass
|
||||
*/
|
||||
private class Point {
|
||||
/** The x coorindate of this point */
|
||||
private final float x;
|
||||
/** The y coorindate of this point */
|
||||
private final float y;
|
||||
|
||||
/**
|
||||
* Create a new point
|
||||
*
|
||||
* @param x The x coordindate of the point
|
||||
* @param y The y coordindate of the point
|
||||
*/
|
||||
public Point(float x, float y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the x coordinate of the point
|
||||
*
|
||||
* @return The x coordinate of the point
|
||||
*/
|
||||
public float getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the y coordinate of the point
|
||||
*
|
||||
* @return The y coordinate of the point
|
||||
*/
|
||||
public float getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert this point into a float array
|
||||
*
|
||||
* @return The contents of this point as a float array
|
||||
*/
|
||||
public float[] toArray() {
|
||||
return new float[] { x, y };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A list of type <code>Point</code>
|
||||
*
|
||||
* @author Kevin Glass
|
||||
*/
|
||||
private class PointList {
|
||||
/** The list of points */
|
||||
private final ArrayList<Point> points = new ArrayList<Point>();
|
||||
|
||||
/**
|
||||
* Create a new empty list
|
||||
*/
|
||||
public PointList() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a point to the list
|
||||
*
|
||||
* @param point The point to add
|
||||
*/
|
||||
public void add(Point point) {
|
||||
points.add(point);
|
||||
}
|
||||
|
||||
///**
|
||||
// * Remove a point from the list
|
||||
// *
|
||||
// * @param point The point to remove
|
||||
// */
|
||||
//public void remove(Point point) {
|
||||
// points.remove(point);
|
||||
//}
|
||||
|
||||
/**
|
||||
* Get the size of the list
|
||||
*
|
||||
* @return The size of the list
|
||||
*/
|
||||
public int size() {
|
||||
return points.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a point a specific index in the list
|
||||
*
|
||||
* @param i The index of the point to retrieve
|
||||
* @return The point
|
||||
*/
|
||||
public Point get(int i) {
|
||||
return points.get(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
package org.oscim.utils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Triangulates a polygon into triangles - duh. Doesn't handle
|
||||
* holes in polys
|
||||
*
|
||||
* @author Public Source from FlipCode
|
||||
*/
|
||||
public class Triangulator {
|
||||
/** The accepted error value */
|
||||
private static final float EPSILON = 0.0000000001f;
|
||||
/** The list of points to be triangulated */
|
||||
private final PointList poly = new PointList();
|
||||
/** The list of points describing the triangles */
|
||||
private final PointList tris = new PointList();
|
||||
/** True if we've tried to triangulate */
|
||||
private boolean tried;
|
||||
|
||||
/**
|
||||
* Create a new triangulator
|
||||
*/
|
||||
public Triangulator() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a point describing the polygon to be triangulated
|
||||
*
|
||||
* @param x The x coordinate of the point
|
||||
* @param y the y coordinate of the point
|
||||
*/
|
||||
public void addPolyPoint(float x, float y) {
|
||||
poly.add(new Point(x, y));
|
||||
}
|
||||
|
||||
/**
|
||||
* Cause the triangulator to split the polygon
|
||||
*
|
||||
* @return True if we managed the task
|
||||
*/
|
||||
public boolean triangulate() {
|
||||
tried = true;
|
||||
|
||||
boolean worked = process(poly, tris);
|
||||
return worked;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a count of the number of triangles produced
|
||||
*
|
||||
* @return The number of triangles produced
|
||||
*/
|
||||
public int getTriangleCount() {
|
||||
if (!tried) {
|
||||
throw new RuntimeException("Call triangulate() before accessing triangles");
|
||||
}
|
||||
return tris.size() / 3;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a point on a specified generated triangle
|
||||
*
|
||||
* @param tri The index of the triangle to interegate
|
||||
* @param i The index of the point within the triangle to retrieve
|
||||
* (0 - 2)
|
||||
* @return The x,y coordinate pair for the point
|
||||
*/
|
||||
public float[] getTrianglePoint(int tri, int i) {
|
||||
if (!tried) {
|
||||
throw new RuntimeException("Call triangulate() before accessing triangles");
|
||||
}
|
||||
return tris.get((tri * 3) + i).toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the area of a polygon defined by the series of points
|
||||
* in the list
|
||||
*
|
||||
* @param contour The list of points defined the contour of the polygon
|
||||
* (Vector2f)
|
||||
* @return The area of the polygon defined
|
||||
*/
|
||||
private static float area(PointList contour) {
|
||||
int n = contour.size();
|
||||
|
||||
float A = 0.0f;
|
||||
|
||||
for (int p = n - 1, q = 0; q < n; p = q++) {
|
||||
Point contourP = contour.get(p);
|
||||
Point contourQ = contour.get(q);
|
||||
|
||||
A += contourP.getX() * contourQ.getY() - contourQ.getX()
|
||||
* contourP.getY();
|
||||
}
|
||||
return A * 0.5f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the point P is inside the triangle defined by
|
||||
* the points A,B,C
|
||||
*
|
||||
* @param Ax Point A x-coordinate
|
||||
* @param Ay Point A y-coordinate
|
||||
* @param Bx Point B x-coordinate
|
||||
* @param By Point B y-coordinate
|
||||
* @param Cx Point C x-coordinate
|
||||
* @param Cy Point C y-coordinate
|
||||
* @param Px Point P x-coordinate
|
||||
* @param Py Point P y-coordinate
|
||||
* @return True if the point specified is within the triangle
|
||||
*/
|
||||
private static boolean insideTriangle(float Ax, float Ay, float Bx,
|
||||
float By, float Cx, float Cy, float Px, float Py) {
|
||||
float ax, ay, bx, by, cx, cy, apx, apy, bpx, bpy, cpx, cpy;
|
||||
float cCROSSap, bCROSScp, aCROSSbp;
|
||||
|
||||
ax = Cx - Bx;
|
||||
ay = Cy - By;
|
||||
bx = Ax - Cx;
|
||||
by = Ay - Cy;
|
||||
cx = Bx - Ax;
|
||||
cy = By - Ay;
|
||||
apx = Px - Ax;
|
||||
apy = Py - Ay;
|
||||
bpx = Px - Bx;
|
||||
bpy = Py - By;
|
||||
cpx = Px - Cx;
|
||||
cpy = Py - Cy;
|
||||
|
||||
aCROSSbp = ax * bpy - ay * bpx;
|
||||
cCROSSap = cx * apy - cy * apx;
|
||||
bCROSScp = bx * cpy - by * cpx;
|
||||
|
||||
return ((aCROSSbp >= 0.0f) && (bCROSScp >= 0.0f) && (cCROSSap >= 0.0f));
|
||||
}
|
||||
|
||||
/**
|
||||
* Cut a the contour and add a triangle into V to describe the
|
||||
* location of the cut
|
||||
*
|
||||
* @param contour The list of points defining the polygon
|
||||
* @param u The index of the first point
|
||||
* @param v The index of the second point
|
||||
* @param w The index of the third point
|
||||
* @param n ?
|
||||
* @param V The array to populate with indicies of triangles
|
||||
* @return True if a triangle was found
|
||||
*/
|
||||
private static boolean snip(PointList contour, int u, int v, int w, int n,
|
||||
int[] V) {
|
||||
int p;
|
||||
float Ax, Ay, Bx, By, Cx, Cy, Px, Py;
|
||||
|
||||
Ax = contour.get(V[u]).getX();
|
||||
Ay = contour.get(V[u]).getY();
|
||||
|
||||
Bx = contour.get(V[v]).getX();
|
||||
By = contour.get(V[v]).getY();
|
||||
|
||||
Cx = contour.get(V[w]).getX();
|
||||
Cy = contour.get(V[w]).getY();
|
||||
|
||||
if (EPSILON > (((Bx - Ax) * (Cy - Ay)) - ((By - Ay) * (Cx - Ax)))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (p = 0; p < n; p++) {
|
||||
if ((p == u) || (p == v) || (p == w)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Px = contour.get(V[p]).getX();
|
||||
Py = contour.get(V[p]).getY();
|
||||
|
||||
if (insideTriangle(Ax, Ay, Bx, By, Cx, Cy, Px, Py)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a list of points defining a polygon
|
||||
*
|
||||
* @param contour The list of points describing the polygon
|
||||
* @param result The list of points describing the triangles. Groups
|
||||
* of 3 describe each triangle
|
||||
* @return True if we succeeded in completing triangulation
|
||||
*/
|
||||
private static boolean process(PointList contour, PointList result) {
|
||||
/* allocate and initialize list of Vertices in polygon */
|
||||
|
||||
int n = contour.size();
|
||||
if (n < 3)
|
||||
return false;
|
||||
|
||||
int[] V = new int[n];
|
||||
|
||||
/* we want a counter-clockwise polygon in V */
|
||||
|
||||
if (0.0f < area(contour)) {
|
||||
for (int v = 0; v < n; v++)
|
||||
V[v] = v;
|
||||
} else {
|
||||
for (int v = 0; v < n; v++)
|
||||
V[v] = (n - 1) - v;
|
||||
}
|
||||
|
||||
int nv = n;
|
||||
|
||||
/* remove nv-2 Vertices, creating 1 triangle every time */
|
||||
int count = 2 * nv; /* error detection */
|
||||
|
||||
//for (int m = 0, v = nv - 1; nv > 2;) {
|
||||
for (int v = nv - 1; nv > 2;) {
|
||||
/* if we loop, it is probably a non-simple polygon */
|
||||
if (0 >= (count--)) {
|
||||
//** Triangulate: ERROR - probable bad polygon!
|
||||
return false;
|
||||
}
|
||||
|
||||
/* three consecutive vertices in current polygon, <u,v,w> */
|
||||
int u = v;
|
||||
if (nv <= u)
|
||||
u = 0; /* previous */
|
||||
v = u + 1;
|
||||
if (nv <= v)
|
||||
v = 0; /* new v */
|
||||
int w = v + 1;
|
||||
if (nv <= w)
|
||||
w = 0; /* next */
|
||||
|
||||
if (snip(contour, u, v, w, nv, V)) {
|
||||
int a, b, c, s, t;
|
||||
|
||||
/* true names of the vertices */
|
||||
a = V[u];
|
||||
b = V[v];
|
||||
c = V[w];
|
||||
|
||||
/* output Triangle */
|
||||
result.add(contour.get(a));
|
||||
result.add(contour.get(b));
|
||||
result.add(contour.get(c));
|
||||
|
||||
//m++;
|
||||
|
||||
/* remove v from remaining polygon */
|
||||
for (s = v, t = v + 1; t < nv; s++, t++) {
|
||||
V[s] = V[t];
|
||||
}
|
||||
nv--;
|
||||
|
||||
/* resest error detection counter */
|
||||
count = 2 * nv;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* A single point handled by the triangulator
|
||||
*
|
||||
* @author Kevin Glass
|
||||
*/
|
||||
private class Point {
|
||||
/** The x coorindate of this point */
|
||||
private final float x;
|
||||
/** The y coorindate of this point */
|
||||
private final float y;
|
||||
|
||||
/**
|
||||
* Create a new point
|
||||
*
|
||||
* @param x The x coordindate of the point
|
||||
* @param y The y coordindate of the point
|
||||
*/
|
||||
public Point(float x, float y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the x coordinate of the point
|
||||
*
|
||||
* @return The x coordinate of the point
|
||||
*/
|
||||
public float getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the y coordinate of the point
|
||||
*
|
||||
* @return The y coordinate of the point
|
||||
*/
|
||||
public float getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert this point into a float array
|
||||
*
|
||||
* @return The contents of this point as a float array
|
||||
*/
|
||||
public float[] toArray() {
|
||||
return new float[] { x, y };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A list of type <code>Point</code>
|
||||
*
|
||||
* @author Kevin Glass
|
||||
*/
|
||||
private class PointList {
|
||||
/** The list of points */
|
||||
private final ArrayList<Point> points = new ArrayList<Point>();
|
||||
|
||||
/**
|
||||
* Create a new empty list
|
||||
*/
|
||||
public PointList() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a point to the list
|
||||
*
|
||||
* @param point The point to add
|
||||
*/
|
||||
public void add(Point point) {
|
||||
points.add(point);
|
||||
}
|
||||
|
||||
///**
|
||||
// * Remove a point from the list
|
||||
// *
|
||||
// * @param point The point to remove
|
||||
// */
|
||||
//public void remove(Point point) {
|
||||
// points.remove(point);
|
||||
//}
|
||||
|
||||
/**
|
||||
* Get the size of the list
|
||||
*
|
||||
* @return The size of the list
|
||||
*/
|
||||
public int size() {
|
||||
return points.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a point a specific index in the list
|
||||
*
|
||||
* @param i The index of the point to retrieve
|
||||
* @return The point
|
||||
*/
|
||||
public Point get(int i) {
|
||||
return points.get(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user