package storm.applications.model.gis;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import org.geotools.data.FeatureSource;
import org.geotools.data.shapefile.ShapefileDataStore;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.FeatureIterator;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.postgis.MultiLineString;
import storm.applications.constants.TrafficMonitoringConstants.Conf;
import storm.applications.util.config.Configuration;
public class RoadGridList {
private HashMap<String, RoadList> gridList = new HashMap<>();
private String idKey;
private String widthKey;
public RoadGridList(Configuration config, String path) throws SQLException, IOException {
gridList = read(path);
idKey = config.getString(Conf.ROAD_FEATURE_ID_KEY);
widthKey = config.getString(Conf.ROAD_FEATURE_WIDTH_KEY, null);
}
public RoadList getGridByID(String mapId) {
for (Map.Entry<String, RoadList> g : gridList.entrySet()) {
if (g.getKey().equals(mapId)) {
return g.getValue();
}
}
return null;
}
public Boolean isExits(HashMap<String, RoadList> gridList, String mapId) {
for (Map.Entry<String, RoadList> g : gridList.entrySet()) {
if (g.getKey().equals(mapId)) {
return true;
}
}
return false;
}
private HashMap<String, RoadList> read(String path) throws IOException, SQLException {
File file = new File(path);
ShapefileDataStore shpDataStore = new ShapefileDataStore(file.toURI().toURL());
shpDataStore.setCharset(Charset.forName("GBK"));
//Feature Access
String typeName = shpDataStore.getTypeNames()[0];
FeatureSource<SimpleFeatureType, SimpleFeature> featureSource = (FeatureSource<SimpleFeatureType, SimpleFeature>) shpDataStore.getFeatureSource(typeName);
FeatureCollection<SimpleFeatureType, SimpleFeature> result = featureSource.getFeatures();
FeatureIterator<SimpleFeature> iterator = result.features();
while(iterator.hasNext()) {
//Data Reader
SimpleFeature feature = iterator.next();
String geoStr = feature.getDefaultGeometry().toString();
MultiLineString linearRing = new MultiLineString(geoStr);
String mapID;
if (feature.getAttributes().contains("MapID")) {
mapID = feature.getAttribute("MapID").toString();
} else {
int len = linearRing.getLine(0).numPoints();
Double centerX = (linearRing.getLine(0).getPoint(0).x+linearRing.getLine(0).getPoint(len-1).x)/2*10;
Double centerY = (linearRing.getLine(0).getPoint(0).y+linearRing.getLine(0).getPoint(len-1).y)/2*10;
mapID = (centerY.toString()).substring(0, 3)+"_"+ (centerX.toString()).substring(0, 4);
}
if (!isExits(gridList, mapID)) {
RoadList roadList = new RoadList();
roadList.add(feature);
gridList.put(mapID,roadList);
} else {
RoadList roadList = getGridByID(mapID);
roadList.add(feature);
}
}
iterator.close();
shpDataStore.dispose();
return gridList;
}
public int fetchRoadID(Point p) throws SQLException {
int lastMiniRoadID = -2;
Integer mapID_lon = (int)(p.getX()*10);
Integer mapID_lan = (int)(p.getY()*10);
String mapID = mapID_lan.toString()+"_" +mapID_lon.toString();
double minD = Double.MAX_VALUE;
int width = 0;
int gridCount = 0;
int roadCount = 0;
for (Map.Entry<String, RoadList> grid : gridList.entrySet()) {
gridCount++;
String s = grid.getKey();
if (mapID.equals(s)) {
for (SimpleFeature feature: grid.getValue()) {
roadCount++;
int returnRoadID = Integer.parseInt(feature.getAttribute(idKey).toString());
if (widthKey != null) {
width = Integer.parseInt(feature.getAttribute(widthKey).toString());
} else {
width = 5;
}
if (width <= 0) width = 5;
String geoStr = feature.getDefaultGeometry().toString();
MultiLineString linearRing = new MultiLineString(geoStr);
ArrayList<Point> ps = new ArrayList<>();
for (int idx = 0; idx < linearRing.getLine(0).numPoints(); idx++) {
Point pt = new Point(linearRing.getLine(0).getPoint(idx).x, linearRing.getLine(0).getPoint(idx).y);
ps.add(pt);
}
int n = ps.size();
for (int i = 0; i < n - 1; i++) {
double distance = Polygon.pointToLine(ps.get(i).getX(), ps.get(i).getY(), ps.get(i+1).getX(), ps.get(i+1).getY(), p.getX(), p.getY())*111.2*1000;
if (distance < width) {
//System.out.printf("\ngridCount:%2d roadCount:%5d LessWidth,dist=%7.3f ",gridCount,roadCount,distance);
return returnRoadID;
} else if (distance < minD) {
minD = distance;
lastMiniRoadID = returnRoadID;
}
}
}
//System.out.printf("\ngridCount:%2d roadCount:%5d Minimum dist=%7.3f ",gridCount,roadCount,minD);
if (minD < Math.sqrt(Math.pow(width, 2) + Math.pow(10, 2))) {
return lastMiniRoadID;
} else
return -1;
}
}
return -1;
}
public class RoadList extends ArrayList<SimpleFeature> {
SimpleFeature road;
RoadList(){}
RoadList(SimpleFeature road) {
this.road = road;
}
}
}