public class ContourPlot {
public static GeoJson generateGeoJson(GridData gridData, double[] clipXs, double[] clipYs,
double[] contourValues, Color colors[]) {
GeoJson json = null;
if (colors == null) { // 不填色则生成等值线(LineString类型的Geojson)
} else { // 填色则生成色斑图(polygon类型的Geojson)
List<Polygon> clippedPolygons = genCountourPolygons(
gridData, clipXs, clipYs, contourValues);
json = genGeoJson(clippedPolygons, contourValues, colors);
}
return json;
}
static class ContourCallable implements Callable<Object> {
private String callableName;
private GridData gridData;
private List<PolyLine> lines;
private List<Border> borders;
private double[] contourValues;
public ContourCallable(String callableName, GridData gridData, List<PolyLine> lines, List<Border> borders, double[] contourValues) {
this.callableName = callableName;
this.gridData = gridData;
this.lines = lines;
this.borders = borders;
this.contourValues = contourValues;
}
@Override
public List<wContour.Global.Polygon> call() throws Exception {
System.out.println(">>>" + callableName + "任务启动");
List<wContour.Global.Polygon> contourPolygons = Contour.tracingPolygons(gridData.getGrid(), lines,
borders, contourValues);
System.out.println(">>>" + callableName + "任务结束");
return contourPolygons;
}
}
private static List<wContour.Global.Polygon> genCountourPolygons(GridData gridData, double[] clipXs,
double[] clipYs, double[] contourValues) {
List<PointD> clipPList = new ArrayList<PointD>();
List<Border> borders = null;
List<PolyLine> contourLines = null;
List<wContour.Global.Polygon> contourPolygons = null;
List<wContour.Global.Polygon> clippedPolygons = null;
int nc = contourValues.length;
int[][] S1 = new int[gridData.getGridY().length][gridData.getGridX().length];
borders = Contour
.tracingBorders(gridData.getGrid(), gridData.getGridX(), gridData.getGridY(), S1, gridData.getNodata_value());
contourLines = Contour.tracingContourLines(gridData.getGrid(), gridData.getGridX(), gridData.getGridY(), nc,
contourValues, gridData.getNodata_value(), borders, S1);
contourLines = Contour.smoothLines(contourLines);
int linesAll = contourLines.size();
int taskSize;
taskSize = (linesAll <= 25) ? 1
: (linesAll <= 50) ? 2
: (linesAll <= 100) ? 3
: (linesAll <= 200) ? 6
: (linesAll <= 300) ? 9
: (linesAll <= 400) ? 12 : 16;
int a = linesAll / taskSize;
int b = linesAll % taskSize;
ExecutorService pool = Executors.newFixedThreadPool(taskSize);
List<Future<List<wContour.Global.Polygon>>> futures = new ArrayList<>();
for (int i = 0; i < taskSize; i++) {
int num = a;
if (i == taskSize - 1 && b != 0) num = b;
int index = i * num;
List<PolyLine> lineList = new ArrayList<>();
for (int j = 0; j < num; j++) {
lineList.add(contourLines.get(index + j));
}
Callable c = new ContourCallable("task" + i, gridData, lineList, borders, contourValues);
Future<List<wContour.Global.Polygon>> f = pool.submit(c);
futures.add(f);
}
pool.shutdown();
while (true) { // 等待所有子线程执行完
if (pool.isTerminated()) {
break;
}
try {
Thread.sleep(20);
} catch (Exception e) {
System.err.println("绘制色斑图线程池出错:" + e.getMessage());
}
}
contourPolygons = new ArrayList<>();
try {
for (Future<List<wContour.Global.Polygon>> f : futures) {
contourPolygons.addAll(f.get());
}
} catch (Exception ex) {
System.err.println("获取线程结果出错:" + ex.getMessage());
}
if (clipXs == null && clipYs == null) {
clippedPolygons = contourPolygons;
} else {
for (int i = 0; i < clipXs.length; i++) {
clipPList.add(new PointD(clipXs[i], clipYs[i]));
}
clippedPolygons = Contour.clipPolygons(contourPolygons, clipPList);
}
return clippedPolygons;
}
static class ContourFeature implements Callable<Object> {
private String callableName;
private List<wContour.Global.Polygon> lineList;
private double[] contourValues;
private Color[] colors;
public ContourFeature(String callableName, List<Polygon> lineList, double[] contourValues, Color[] colors) {
this.callableName = callableName;
this.lineList = lineList;
this.contourValues = contourValues;
this.colors = colors;
}
@Override
public List<Feature> call() throws Exception {
System.out.println("<<<" + callableName + "任务启动");
Color color = null;
int index;
double value;
List<Feature> features = new ArrayList<Feature>();
List<com.hxgis.biz.contour.Point> points = null;
List<wContour.Global.PointD> pointdList = null;
com.hxgis.biz.contour.Polygon polygon = null;
for (int i = 0; i < lineList.size(); i++) {
value = lineList.get(i).LowValue;
index = indexOfArray(contourValues, value);
if (colors != null && colors.length > 1) {
color = colors[index + 1];
if (!lineList.get(i).IsHighCenter) {
color = colors[index];
}
}
points = new ArrayList<com.hxgis.biz.contour.Point>();
pointdList = lineList.get(i).OutLine.PointList;
for (wContour.Global.PointD pointD : pointdList) {
points.add(new Point(pointD.Y + "", pointD.X + ""));
}
polygon = new com.hxgis.biz.contour.Polygon(points);
Map<String, Object> properties = new HashMap<String, Object>();
if (color != null) {
properties.put("color", toHexEncoding(color));
}
properties.put("value", value + "");
Feature feature = new Feature();
feature.setGeometry(polygon);
feature.setProperties(properties);
features.add(feature);
}
System.out.println("<<<" + callableName + "任务结束");
return features;
}
}
/**
* 生成GeoJson对象
*
* @param contourPolygons 等值线多边形
* @param contourValues 等值线值 N
* @param colors 等值线色卡 N-1
* @return
*/
private static GeoJson genGeoJson(List<wContour.Global.Polygon> contourPolygons, double[] contourValues, Color[] colors) {
GeoJson json = new GeoJson();
List<Feature> features = new ArrayList<>();
int polygons = contourPolygons.size();
int taskSize = (polygons <= 25) ? 1
: (polygons <= 50) ? 2
: (polygons <= 100) ? 3
: (polygons <= 200) ? 6
: (polygons <= 300) ? 9
: (polygons <= 400) ? 12 : 16;
int a = polygons / taskSize;
int b = polygons % taskSize;
ExecutorService pool = Executors.newFixedThreadPool(taskSize);
List<Future<List<Feature>>> futures = new ArrayList<>();
for (int i = 0; i < taskSize; i++) {
int num = a;
if (i == taskSize - 1 && b != 0) num = b;
int indexNum = i * num;
List<wContour.Global.Polygon> lineList = new ArrayList<>();
for (int j = 0; j < num; j++) {
lineList.add(contourPolygons.get(indexNum + j));
}
Callable c = new ContourFeature("封装json线程" + i, lineList,contourValues,colors);
Future<List<Feature>> f = pool.submit(c);
futures.add(f);
}
pool.shutdown();
while (true) { // 等待所有子线程执行完
if (pool.isTerminated()) {
break;
}
try {
Thread.sleep(20);
} catch (Exception e) {
System.err.println("封装json线程池出错:" + e.getMessage());
}
}
try {
for (Future<List<Feature>> f : futures) {
features.addAll(f.get());
}
} catch (Exception ex) {
System.err.println("获取线程结果出错:" + ex.getMessage());
}
json.setFeatures(features);
return json;
}
private static String toHexEncoding(Color color) {
String R, G, B;
StringBuffer sb = new StringBuffer();
R = Integer.toHexString(color.getRed());
G = Integer.toHexString(color.getGreen());
B = Integer.toHexString(color.getBlue());
R = R.length() == 1 ? "0" + R : R;
G = G.length() == 1 ? "0" + G : G;
B = B.length() == 1 ? "0" + B : B;
sb.append("#");
sb.append(R);
sb.append(G);
sb.append(B);
return sb.toString();
}
private static int indexOfArray(double[] array, double value) {
int n = -1;
for (int i = 0; i < array.length; i++) {
if (array[i] == value) {
n = i;
break;
}
}
return n;
}
}