package com.smtaiserver.smtaiserver.gismap; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.dom4j.Document; import org.dom4j.Element; import org.dom4j.Node; import org.springframework.web.servlet.ModelAndView; import com.smtaiserver.smtaiserver.core.SMTAIServerApp; import com.smtaiserver.smtaiserver.core.SMTAIServerRequest; import com.smtaiserver.smtaiserver.database.SMTDatabase; import com.smtaiserver.smtaiserver.database.SMTDatabase.DBQueryNotify; import com.smtaiserver.smtaiserver.database.SMTDatabase.DBRecord; import com.smtaiserver.smtaiserver.database.SMTDatabase.DBRecords; import com.smtservlet.util.Json; import com.smtservlet.util.SMTJsonWriter; import com.smtservlet.util.SMTStatic; public class SMTGisMapLayerDef { protected static String _sqlTemplateHead = "WITH grid AS (\r\n" + " -- 将点映射到 100x100 的网格\r\n" + " SELECT\r\n" + " ST_SnapToGrid(shape, {grid}, {grid}) AS grid_geom,\r\n" + " shape,{column_names}\r\n" + " FROM(\r\n" ; protected static String _sqlTemplateTail = " ) T1 WHERE\r\n" + " shape && ST_TileEnvelope({zxy})\r\n" + "),\r\n" + "unique_points AS (\r\n" + " -- 从每个网格中选择一个点\r\n" + " SELECT\r\n" + " DISTINCT ON (grid_geom) shape, {column_names}\r\n" + " FROM\r\n" + " grid\r\n" + "),\r\n" + "mvtgeom AS(\r\n" + "SELECT\r\n" + " ST_AsMVTGeom(shape, ST_TileEnvelope({zxy}),\r\n" + " extent => {extent}) AS geom,\r\n" + " {column_names}\r\n" + "FROM\r\n" + " unique_points\r\n" + " where \r\n" + " shape && ST_TileEnvelope({zxy})\r\n" + ")\r\n" + "SELECT ST_AsMVT(mvtgeom.*)\r\n" + "FROM mvtgeom"; protected Double _maxRatio; protected Double _minRatio; protected String _icon; protected String _layerId; protected String _title; protected String _dsId; protected String _groupName; protected String _columnNames; protected List _listSqlxmlDrawSql = new ArrayList<>(); protected List _listSqlxmlSearchSql = new ArrayList<>(); protected int _gridBase = 0; protected Integer[] _grids = new Integer[] { 100 ,62 ,38 ,15 ,5 ,1 }; public SMTGisMapLayerDef(SMTDatabase db, DBRecord rec) throws Exception { _layerId = rec.getString("layer_id"); _title = rec.getString("layer_title"); _groupName = rec.getString("layer_group"); _minRatio = rec.getDouble("min_ratio"); _maxRatio = rec.getDouble("max_ratio"); String iconStr = rec.getString("layer_icon"); if(!SMTStatic.isNullOrEmpty(iconStr)) _icon = Json.read("{\"icon\":\"" + rec.getString("layer_icon") + "\"}").getJson("icon").asString(); Document doc = SMTStatic.convStrToXmlDoc("" + rec.getString("layer_sql_xml") + ""); Element xmlDrawSqlList = (Element) doc.selectSingleNode("ROOT/DRAW_SQL_LIST"); if(xmlDrawSqlList == null) throw new Exception("can't find DRAW_SQL_LIST"); Element xmlDrawZGrid = (Element)doc.selectSingleNode("ROOT/DRAW_Z_TO_GRID"); if(xmlDrawZGrid != null) { _gridBase = SMTStatic.toInt(SMTStatic.getXmlAttr(xmlDrawZGrid, "base", "0")); String[] values = xmlDrawZGrid.getText() .replace("\r", "") .replace("\n", "") .replace(" ", "") .replace("\t", "") .split(",") ; List listGrid = new ArrayList<>(); for(int i = 0; i < values.length; i ++) { if(SMTStatic.isNullOrEmpty(values[i])) continue; listGrid.add(Integer.parseInt(values[i])); } _grids = listGrid.toArray(new Integer[listGrid.size()]); } _dsId = SMTStatic.getXmlAttr(xmlDrawSqlList, "ds_id"); _columnNames = SMTStatic.getXmlAttr(xmlDrawSqlList, "columns"); for(Node nodeDrawSql : xmlDrawSqlList.selectNodes("DRAW_SQL")) { SMTMapLayerSqlXml sqlxmlDrawSql = new SMTMapLayerSqlXml((Element)nodeDrawSql); _listSqlxmlDrawSql.add(sqlxmlDrawSql); } StringBuilder sbSQL = new StringBuilder(); List sqlParams = new ArrayList<>(); sbSQL.append("SELECT min(st_xmin(shape)) l, min(st_ymin(shape)) t, max(st_xmax(shape)) r, max(st_ymax(shape)) b FROM (\n"); Map mapSqlXmlArgs = new HashMap<>(); mapSqlXmlArgs.put("cur_time", new Date()); for(int i = 0; i < _listSqlxmlDrawSql.size(); i ++) { if(i > 0) sbSQL.append("\r\nUNION ALL\r\n"); _listSqlxmlDrawSql.get(i).createSQL(mapSqlXmlArgs, sbSQL, sqlParams); } sbSQL.append(")T"); Element xmlSearchSQLList = (Element)doc.selectSingleNode("ROOT/SEARCH_SQL_LIST"); if(xmlSearchSQLList != null) { for(Node nodeSearchSQL : xmlSearchSQLList.selectNodes("SEARCH_SQL")) { SMTMapLayerSqlXml sqlxmlDrawSql = new SMTMapLayerSqlXml((Element)nodeSearchSQL); _listSqlxmlSearchSql.add(sqlxmlDrawSql); } } } public Double getMinRatio() { return _minRatio; } public Double getMaxRatio() { return _maxRatio; } public String getIcon() { return _icon; } public String getGroupName() { return _groupName; } public String getLayerId() { return _layerId; } public String getTitle() { return _title; } public ModelAndView queryVectorTileToResponse(SMTAIServerRequest tranReq, int z, int x, int y) throws Exception { SMTDatabase db = SMTAIServerApp.getApp().allocDatabase(); try { int gridZ = Math.max(z - _gridBase, 0); int grid = gridZ < _grids.length ? _grids[gridZ] : 1; StringBuilder sbSQL = new StringBuilder(); List sqlParams = new ArrayList<>(); sbSQL.append(_sqlTemplateHead); Map mapSqlXmlArgs = new HashMap<>(); mapSqlXmlArgs.put("cur_time", new Date()); for(int i = 0; i < _listSqlxmlDrawSql.size(); i ++) { if(i > 0) sbSQL.append("\r\nUNION ALL\r\n"); _listSqlxmlDrawSql.get(i).createSQL(mapSqlXmlArgs, sbSQL, sqlParams); } sbSQL.append(_sqlTemplateTail); String sql = sbSQL.toString() .replace("{zxy}", String.format("%d, %d, %d", z, x, y)) .replace("{extent}", "4096") .replace("{grid}", "" + grid) .replace("{column_names}", _columnNames); ; DBRecords recs = db.querySQL(sql, sqlParams.toArray(new Object[sqlParams.size()])); byte[] data = (byte[])recs.getRecord(0).getValue(0); return tranReq.returnDownloadByteArray(data, "a", "application/octet-stream"); } finally { db.close(); } } //SMTMapLayerSqlXml> _listSqlxmlSearchSql public void searchElement(SMTDatabase db, Date time, String searchText, int[] count, SMTJsonWriter jsonWr) throws Exception { Map mapArgs = new HashMap<>(); mapArgs.put("cur_time", time); mapArgs.put("search_str", searchText); for(SMTMapLayerSqlXml xmlSearchSQL : _listSqlxmlSearchSql) { StringBuilder sbSQL = new StringBuilder(); List sqlParams = new ArrayList<>(); xmlSearchSQL.createSQL(mapArgs, sbSQL, sqlParams); db.querySQLNotify(sbSQL.toString(), sqlParams.toArray(new Object[sqlParams.size()]), new DBQueryNotify() { @Override public boolean onNextRecord(DBRecord rec) throws Exception { jsonWr.beginMap(null); for(Entry entry : rec.getFieldMap().entrySet()) { jsonWr.addKeyValue(entry.getKey(), rec.getString(entry.getValue())); } jsonWr.endMap(); count[0] ++; if(count[0] >= count[1]) return false; return true; } }); } } }