|
@@ -0,0 +1,344 @@
|
|
|
+package com.zjugis.ysgzybz.utils.geocomm;
|
|
|
+
|
|
|
+import com.vividsolutions.jts.geom.*;
|
|
|
+import com.vividsolutions.jts.io.ParseException;
|
|
|
+import com.vividsolutions.jts.operation.IsSimpleOp;
|
|
|
+
|
|
|
+import com.zjugis.ysgzybz.utils.GisUtils;
|
|
|
+import org.apache.commons.lang3.StringUtils;
|
|
|
+import org.geotools.geometry.jts.JTSFactoryFinder;
|
|
|
+
|
|
|
+import java.io.*;
|
|
|
+import java.util.*;
|
|
|
+
|
|
|
+public class TxtReader {
|
|
|
+
|
|
|
+ private GeometryFactory geometryFactory;
|
|
|
+ private BufferedReader reader;
|
|
|
+
|
|
|
+ private ParseResult parseResult;
|
|
|
+
|
|
|
+ public final static double AERA_MISTAKE = 0.01;
|
|
|
+
|
|
|
+ public TxtReader(File file) throws Exception {
|
|
|
+ this(new BufferedReader(new InputStreamReader(new FileInputStream(file), "gbk")));
|
|
|
+ }
|
|
|
+
|
|
|
+ public TxtReader(InputStream inputStream) throws Exception {
|
|
|
+ this(new BufferedReader(new InputStreamReader(inputStream, "gbk")));
|
|
|
+ }
|
|
|
+
|
|
|
+ public TxtReader(BufferedReader reader) {
|
|
|
+ this.reader = reader;
|
|
|
+ geometryFactory = JTSFactoryFinder.getGeometryFactory();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 将 1,1,3339023.0372,40513893.3519解析为(3339023.0372,40513893.3519)
|
|
|
+ *
|
|
|
+ * @param line
|
|
|
+ * @return
|
|
|
+ * @throws Exception
|
|
|
+ */
|
|
|
+ private Coordinate getCoordinate(String line) throws Exception {
|
|
|
+ String[] split = line.split(",");
|
|
|
+ if (split.length != 4) {
|
|
|
+ throw new ParseException("文件格式错误!");
|
|
|
+ }
|
|
|
+ double y = Double.parseDouble(split[2]);
|
|
|
+ double x = Double.parseDouble(split[3]);
|
|
|
+ Coordinate coordinate = new Coordinate(x, y);
|
|
|
+
|
|
|
+ return coordinate;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 读取一个LinearRing
|
|
|
+ *
|
|
|
+ * @param lineList
|
|
|
+ * @return
|
|
|
+ * @throws Exception
|
|
|
+ */
|
|
|
+ private LinearRing getLinearRing(List<String> lineList) throws Exception {
|
|
|
+ List<Coordinate> coordinateList = new ArrayList<>();
|
|
|
+ for (String s : lineList) {
|
|
|
+ Coordinate coordinate = getCoordinate(s);
|
|
|
+ coordinateList.add(coordinate);
|
|
|
+ }
|
|
|
+ return geometryFactory.createLinearRing(coordinateList.toArray(new Coordinate[coordinateList.size()]));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 读取一个Polygon
|
|
|
+ *
|
|
|
+ * @param lineList
|
|
|
+ * @return
|
|
|
+ * @throws Exception
|
|
|
+ */
|
|
|
+ private Polygon getPolygon(List<String> lineList) throws Exception {
|
|
|
+ Map<String, List<String>> map = new HashMap<>();
|
|
|
+ for (String s : lineList) {
|
|
|
+ String[] split = s.split(",");
|
|
|
+ String qh = split[1];
|
|
|
+ if (!map.containsKey(qh)) {
|
|
|
+ map.put(qh, new ArrayList<>());
|
|
|
+ }
|
|
|
+ map.get(qh).add(s);
|
|
|
+ }
|
|
|
+ List<String> shellList = map.get("1");
|
|
|
+ LinearRing shell = getLinearRing(shellList);
|
|
|
+
|
|
|
+ List<LinearRing> holes = new ArrayList<>();
|
|
|
+ for (String s : map.keySet()) {
|
|
|
+ if (!"1".equals(s)) {
|
|
|
+ List<String> list = map.get(s);
|
|
|
+ LinearRing linearRing = getLinearRing(list);
|
|
|
+ holes.add(linearRing);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return geometryFactory.createPolygon(shell, holes.toArray(new LinearRing[holes.size()]));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 读取MultiPolygon
|
|
|
+ *
|
|
|
+ * @return
|
|
|
+ * @throws Exception
|
|
|
+ */
|
|
|
+ private MultiPolygon getMultiPolygon() throws Exception {
|
|
|
+ List<JzdDk> jzdDkList = new ArrayList<>();
|
|
|
+ List<JzdZb> jzdZbList = new ArrayList<>();
|
|
|
+ parseResult.setJzdDkList(jzdDkList);
|
|
|
+ parseResult.setJzdZbList(jzdZbList);
|
|
|
+ String s = reader.readLine();
|
|
|
+ List<String> lineList = null;
|
|
|
+ List<Polygon> polygonList = new ArrayList<>();
|
|
|
+ while (s != null) {
|
|
|
+ if (s.endsWith(GisConstant.FILE_AT)) {
|
|
|
+ JzdDk jzdDk = getJzdDk(s);
|
|
|
+
|
|
|
+ validateJzdDk(jzdDk);
|
|
|
+ double dkmj = jzdDk.getDkmj();
|
|
|
+ String dkbh = jzdDk.getDkbh();
|
|
|
+ jzdDkList.add(jzdDk);
|
|
|
+ lineList = new ArrayList<>();
|
|
|
+ s = reader.readLine();
|
|
|
+ int order = 1;
|
|
|
+ JzdZb preJzdZb = null;
|
|
|
+ while (s != null && !s.endsWith(GisConstant.FILE_AT)) {
|
|
|
+ lineList.add(s);
|
|
|
+ JzdZb jzdZb = getJzdZb(s, jzdDk, order++, preJzdZb);
|
|
|
+ jzdZbList.add(jzdZb);
|
|
|
+ s = reader.readLine();
|
|
|
+ preJzdZb = jzdZb;
|
|
|
+ }
|
|
|
+ if (lineList.size() > 0) {
|
|
|
+ Polygon polygon = getPolygon(lineList);
|
|
|
+ polygonList.add(polygon);
|
|
|
+ MultiPolygon multiPolygon = geometryFactory.createMultiPolygon(new Polygon[]{polygon});
|
|
|
+ double area = multiPolygon.getArea() / 10000;
|
|
|
+
|
|
|
+ if (dkmj - area > 1e-4) {
|
|
|
+ String formatErrorMsg = String.format("地块编号:【%s】填写的地块面积:【%.4f】实际面积:【%.4f】,误差大于0", dkbh, dkmj, area);
|
|
|
+ parseResult.getErrorList().add(formatErrorMsg);
|
|
|
+ }
|
|
|
+
|
|
|
+ jzdDk.setGeometry(multiPolygon);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return geometryFactory.createMultiPolygon(polygonList.toArray(new Polygon[polygonList.size()]));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 就仅校验一个
|
|
|
+ *
|
|
|
+ * @param dk
|
|
|
+ */
|
|
|
+ private void validateJzdDk(JzdDk dk) throws ParseException {
|
|
|
+ if (dk.getJzds() == 0) {
|
|
|
+ throw new ParseException("界址点数必须大于0");
|
|
|
+ }
|
|
|
+ if (dk.getDkmj() == 0) {
|
|
|
+ throw new ParseException("地块面积必须大于0");
|
|
|
+ }
|
|
|
+ if (StringUtils.isEmpty(dk.getDkbh())) {
|
|
|
+ throw new ParseException("地块编号不能为空");
|
|
|
+ }
|
|
|
+ if (StringUtils.isEmpty(dk.getDkmc())) {
|
|
|
+ throw new ParseException("地块名称不能为空");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 将11,0,1,杭州地铁4号线浦沿站(二期),,,,,@解析为JzdDk
|
|
|
+ *
|
|
|
+ * @param line
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private JzdDk getJzdDk(String line) {
|
|
|
+ JzdDk jzddk = new JzdDk();
|
|
|
+ jzddk.setId(UUID.randomUUID().toString());
|
|
|
+ jzddk.setJzdsxGuid(UUID.randomUUID().toString());
|
|
|
+// 界址点数,地块面积,地块编号,地块名称,记录图形属性(点、线、面),图幅号,地块用途,地类编码,@
|
|
|
+// 66,1.5397,1,浦乐单元BJ0704-M1-08地块(原浦乐单元M1-29地块),面,,,,@
|
|
|
+ String[] group = line.split(",");
|
|
|
+ jzddk.setJzds(Integer.parseInt(group[0]));
|
|
|
+ jzddk.setDkmj(Double.parseDouble(group[1]));
|
|
|
+ jzddk.setDkbh(group[2]);//报提示
|
|
|
+ jzddk.setDkmc(group[3]);//报提示
|
|
|
+ jzddk.setTfh(group[5]);
|
|
|
+ jzddk.setDkyt(group[6]);
|
|
|
+ jzddk.setCreateDate(new Date());
|
|
|
+ jzddk.setUpdateDate(new Date());
|
|
|
+ return jzddk;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 将1,1,3339023.0372,40513893.3519解析为JzdZb
|
|
|
+ *
|
|
|
+ * @param line
|
|
|
+ * @param jzdDk
|
|
|
+ * @param order
|
|
|
+ * @param preJzdzb
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private JzdZb getJzdZb(String line, JzdDk jzdDk, int order, JzdZb preJzdzb) {
|
|
|
+ JzdZb jzdzb = new JzdZb();
|
|
|
+ jzdzb.setId(UUID.randomUUID().toString());
|
|
|
+ jzdzb.setJzdGuid(UUID.randomUUID().toString());
|
|
|
+ String[] split = line.split(",");
|
|
|
+ double y = Double.parseDouble(split[2]);
|
|
|
+ double x = Double.parseDouble(split[3]);
|
|
|
+ jzdzb.setXzb(x);
|
|
|
+ jzdzb.setYzb(y);
|
|
|
+ jzdzb.setQh(split[1]);
|
|
|
+ String jzdh = split[0];
|
|
|
+ if (jzdh.startsWith("J")) {
|
|
|
+ jzdh = jzdh.substring(1);
|
|
|
+ }
|
|
|
+ jzdzb.setJzdh(jzdh);
|
|
|
+ jzdzb.setJzdsxGuid(jzdDk.getJzdsxGuid());
|
|
|
+ jzdzb.setDkbh(jzdDk.getDkbh());
|
|
|
+ jzdzb.setJzdorder(order);
|
|
|
+
|
|
|
+ //反算边长
|
|
|
+ if (preJzdzb != null) {
|
|
|
+ double xzb = preJzdzb.getXzb();
|
|
|
+ double yzb = preJzdzb.getYzb();
|
|
|
+ jzdzb.setFsbc(GisUtils.calculateDistance(xzb, yzb, jzdzb.getXzb(), jzdzb.getYzb()));
|
|
|
+ }
|
|
|
+ jzdzb.setCreateDate(new Date());
|
|
|
+ jzdzb.setUpdate_date(new Date());
|
|
|
+ return jzdzb;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据文件头解析地块属性信息
|
|
|
+ *
|
|
|
+ * @param map
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private JzdSx getJzdsx(Map<String, String> map) {
|
|
|
+ JzdSx jzdsx = new JzdSx();
|
|
|
+ jzdsx.setId(UUID.randomUUID().toString());
|
|
|
+ jzdsx.setZbGuid(UUID.randomUUID().toString());
|
|
|
+ if (map.containsKey(GisConstant.ZBX)) {
|
|
|
+ jzdsx.setZbx(map.get(GisConstant.ZBX));
|
|
|
+ }
|
|
|
+ if (map.containsKey(GisConstant.JDFD)) {
|
|
|
+ jzdsx.setJdfd(map.get(GisConstant.JDFD));
|
|
|
+ }
|
|
|
+ if (map.containsKey(GisConstant.TYLX)) {
|
|
|
+ jzdsx.setTylx(map.get(GisConstant.TYLX));
|
|
|
+ }
|
|
|
+ if (map.containsKey(GisConstant.JLDW)) {
|
|
|
+ jzdsx.setJldw(map.get(GisConstant.JLDW));
|
|
|
+ }
|
|
|
+ if (map.containsKey(GisConstant.DH)) {
|
|
|
+ jzdsx.setDh(map.get(GisConstant.DH));
|
|
|
+ }
|
|
|
+ if (map.containsKey(GisConstant.JD)) {
|
|
|
+ double jd = Double.parseDouble(map.get(GisConstant.JD));
|
|
|
+ jzdsx.setJd(jd);
|
|
|
+ }
|
|
|
+ jzdsx.setCreateDate(new Date());
|
|
|
+ jzdsx.setUpdateDate(new Date());
|
|
|
+ return jzdsx;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 入口
|
|
|
+ *
|
|
|
+ * @return
|
|
|
+ * @throws Exception
|
|
|
+ */
|
|
|
+ public ParseResult read() throws Exception {
|
|
|
+ parseResult = new ParseResult();
|
|
|
+ //读取到[地块坐标]这一行
|
|
|
+ String s = reader.readLine();
|
|
|
+
|
|
|
+ if (!GisConstant.FILE_ATTRIBUTE.equals(s)) {
|
|
|
+ throw new ParseException("请确认文件编码是否为ANSI格式,请查看帮助文档!");
|
|
|
+ }
|
|
|
+
|
|
|
+ Map<String, String> sxMap = new HashMap<>();
|
|
|
+ while (s != null && !GisConstant.FILE_HEAD.equals(s)) {
|
|
|
+ String[] propGroup = s.split(GisConstant.EQUAL);
|
|
|
+ if (propGroup.length == 2 && !sxMap.containsKey(propGroup[0])) {
|
|
|
+ sxMap.put(propGroup[0], propGroup[1]);
|
|
|
+ }
|
|
|
+ s = reader.readLine();
|
|
|
+ }
|
|
|
+ JzdSx jzdsx = getJzdsx(sxMap);
|
|
|
+ if (!GisConstant.CGCS2000.equals(jzdsx.getZbx())) {
|
|
|
+ throw new ParseException("坐标系必须为2000国家大地坐标系,请查看帮助文档!");
|
|
|
+ }
|
|
|
+
|
|
|
+ parseResult.setJzdSx(jzdsx);
|
|
|
+ MultiPolygon multiPolygon = getMultiPolygon();
|
|
|
+ if (!multiPolygon.isValid()) {
|
|
|
+// parseResult.getErrorList().add("图形存在拓扑错误");
|
|
|
+ throw new ParseException("图形存在拓扑错误");
|
|
|
+ }
|
|
|
+ IsSimpleOp isSimple = new IsSimpleOp(multiPolygon);
|
|
|
+
|
|
|
+ // 如果geometry自相交,isSimple.isSimple()将返回false
|
|
|
+ if (!isSimple.isSimple()) {
|
|
|
+// parseResult.getErrorList().add("图形自相交");
|
|
|
+ throw new ParseException("图形自相交");
|
|
|
+ }
|
|
|
+ parseResult.setGeometry(multiPolygon);
|
|
|
+ return parseResult;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * dkmj和geometry的面积误差超过1%,则视为不合法
|
|
|
+ *
|
|
|
+ * @param dkmj
|
|
|
+ * @param geometry
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private boolean validDkmj(double dkmj, Geometry geometry) {
|
|
|
+ double area = geometry.getArea();
|
|
|
+ return Math.abs((area - dkmj * 10000) / area) < TxtReader.AERA_MISTAKE;
|
|
|
+ }
|
|
|
+
|
|
|
+// public static void main(String[] args) throws Exception {
|
|
|
+// String filePath = "D:\\Users\\Desktop\\杭州地铁.txt";
|
|
|
+// //校验坐标系
|
|
|
+//
|
|
|
+// TxtReader parseTxtExtend = new TxtReader(new File(filePath));
|
|
|
+// ParseResult result = parseTxtExtend.read();
|
|
|
+//// System.out.println(result.getJzdSx());
|
|
|
+//// System.out.println(result.getJzdDkList());
|
|
|
+//// System.out.println(result.getJzdZbList());
|
|
|
+//
|
|
|
+// TxtWriter writer = new TxtWriter();
|
|
|
+// String writer1 = writer.writer(result);
|
|
|
+// System.out.println(writer1);
|
|
|
+// }
|
|
|
+
|
|
|
+}
|