|
|
|
@ -1,19 +1,21 @@
|
|
|
|
|
package com.palnet.comn.utils; |
|
|
|
|
|
|
|
|
|
import java.io.BufferedReader; |
|
|
|
|
import java.io.File; |
|
|
|
|
import java.io.FileInputStream; |
|
|
|
|
import java.io.IOException; |
|
|
|
|
import java.io.InputStream; |
|
|
|
|
import java.io.InputStreamReader; |
|
|
|
|
import java.util.ArrayList; |
|
|
|
|
import java.util.List; |
|
|
|
|
import java.nio.charset.StandardCharsets; |
|
|
|
|
import java.util.*; |
|
|
|
|
import java.util.concurrent.Callable; |
|
|
|
|
import java.util.concurrent.ExecutionException; |
|
|
|
|
import java.util.concurrent.ExecutorService; |
|
|
|
|
import java.util.concurrent.Executors; |
|
|
|
|
import java.util.concurrent.Future; |
|
|
|
|
import java.util.regex.Pattern; |
|
|
|
|
|
|
|
|
|
import com.palnet.comn.code.ErrorCode; |
|
|
|
|
import com.palnet.comn.exception.CustomException; |
|
|
|
|
import lombok.Data; |
|
|
|
|
import org.json.simple.JSONArray; |
|
|
|
|
import org.json.simple.JSONObject; |
|
|
|
|
import org.json.simple.parser.JSONParser; |
|
|
|
@ -23,20 +25,17 @@ import org.locationtech.jts.geom.GeometryFactory;
|
|
|
|
|
import org.locationtech.jts.geom.Point; |
|
|
|
|
import org.locationtech.jts.geom.Polygon; |
|
|
|
|
import org.springframework.core.io.ClassPathResource; |
|
|
|
|
import org.springframework.core.io.support.PathMatchingResourcePatternResolver; |
|
|
|
|
import org.springframework.core.io.support.ResourcePatternResolver; |
|
|
|
|
import org.springframework.util.FileCopyUtils; |
|
|
|
|
|
|
|
|
|
import lombok.extern.slf4j.Slf4j; |
|
|
|
|
|
|
|
|
|
@Slf4j |
|
|
|
|
public class CoordUtils { |
|
|
|
|
|
|
|
|
|
private String basePath = "air/coordinateFolder/"; |
|
|
|
|
private final String basePath = "air/coordinateFolder/"; |
|
|
|
|
|
|
|
|
|
private static final CoordUtils INSTANCE = new CoordUtils(); |
|
|
|
|
|
|
|
|
|
private String baseFileName = "all_location.geojson"; |
|
|
|
|
private final String baseFileName = "all_location.geojson"; |
|
|
|
|
|
|
|
|
|
private List<JSONObject> allLocation; |
|
|
|
|
|
|
|
|
@ -89,7 +88,7 @@ public class CoordUtils {
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
} catch (Exception e) { |
|
|
|
|
e.printStackTrace(); |
|
|
|
|
log.error("", e); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
this.allLocation = result; |
|
|
|
@ -103,16 +102,14 @@ public class CoordUtils {
|
|
|
|
|
String path = basePath + coords + "/" + baseFileName; |
|
|
|
|
|
|
|
|
|
try(InputStream inputStream = new ClassPathResource(path).getInputStream(); |
|
|
|
|
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"), 8192)) { |
|
|
|
|
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8), 8192)) { |
|
|
|
|
|
|
|
|
|
JSONParser jsonParser = new JSONParser(); |
|
|
|
|
|
|
|
|
|
jsonObject = (JSONObject) jsonParser.parse(reader); |
|
|
|
|
|
|
|
|
|
}catch(Exception e) { |
|
|
|
|
|
|
|
|
|
e.getStackTrace(); |
|
|
|
|
|
|
|
|
|
log.error("", e); |
|
|
|
|
} |
|
|
|
|
return jsonObject; |
|
|
|
|
} |
|
|
|
@ -193,7 +190,7 @@ public class CoordUtils {
|
|
|
|
|
return result; |
|
|
|
|
|
|
|
|
|
} catch (Exception e) { |
|
|
|
|
e.printStackTrace(); |
|
|
|
|
log.error("", e); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -206,11 +203,11 @@ public class CoordUtils {
|
|
|
|
|
JSONObject obj = new JSONObject(); |
|
|
|
|
|
|
|
|
|
obj = parseGeoJson(polygon, coordinate); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(obj == null) return null; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return obj; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public JSONObject getCoordinateGis(Coordinate coordinate, String depth) throws IOException, ParseException { |
|
|
|
@ -254,91 +251,86 @@ public class CoordUtils {
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public JSONObject parseGeoJson(String path, Coordinate coordinate) throws IOException, ParseException { |
|
|
|
|
public JSONObject parseGeoJson(String path, Coordinate coordinate){ |
|
|
|
|
|
|
|
|
|
List<JSONObject> features = new ArrayList<JSONObject>(); |
|
|
|
|
|
|
|
|
|
Point point = null; |
|
|
|
|
|
|
|
|
|
try(InputStream inputStream = new ClassPathResource(path).getInputStream(); |
|
|
|
|
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"), 8192)) { |
|
|
|
|
|
|
|
|
|
JSONParser jsonParser = new JSONParser(); |
|
|
|
|
|
|
|
|
|
JSONObject jsonObject = (JSONObject) jsonParser.parse(reader); |
|
|
|
|
|
|
|
|
|
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"), 8192)) { |
|
|
|
|
|
|
|
|
|
point = geometryFactory.createPoint(coordinate); |
|
|
|
|
|
|
|
|
|
features = (List<JSONObject>) jsonObject.get("features"); |
|
|
|
|
|
|
|
|
|
}catch(Exception e) { |
|
|
|
|
|
|
|
|
|
e.getStackTrace(); |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
JSONParser jsonParser = new JSONParser(); |
|
|
|
|
|
|
|
|
|
JSONObject jsonObject = (JSONObject) jsonParser.parse(reader); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
point = geometryFactory.createPoint(coordinate); |
|
|
|
|
|
|
|
|
|
features = (List<JSONObject>) jsonObject.get("features"); |
|
|
|
|
|
|
|
|
|
}catch(Exception e) { |
|
|
|
|
log.error("", e); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return this.contains(features, point); |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public JSONObject contains(List<JSONObject> features, Point point) { |
|
|
|
|
|
|
|
|
|
JSONObject result = null; |
|
|
|
|
|
|
|
|
|
Double standard = 10000000.0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for(int i=0; i<features.size(); i++) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
JSONObject geometry = (JSONObject) features.get(i).get("geometry"); |
|
|
|
|
|
|
|
|
|
JSONObject properties = (JSONObject) features.get(i).get("properties"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
List<JSONArray> coordinates = (List<JSONArray>) geometry.get("coordinates"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for(int k = 0; k< coordinates.size(); k++) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
List<Coordinate> polygonPaths = new ArrayList<>(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for(Object coords : coordinates.get(k)) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for(int j = 0; j<((JSONArray)coords).size(); j++) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Object coord = ((JSONArray) coords).get(j); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Object x = ((JSONArray) coord).get(0); |
|
|
|
|
Object y = ((JSONArray) coord).get(1); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Double lon = y instanceof Double ? (Double) y : Double.valueOf((Long) y); |
|
|
|
|
Double lat = x instanceof Double ? (Double) x : Double.valueOf((Long) x); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Coordinate areaCoord = new Coordinate(lon, lat); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
polygonPaths.add(areaCoord); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
polygonPaths.add(polygonPaths.get(0)); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Polygon polygon = geometryFactory.createPolygon(polygonPaths.toArray(new Coordinate[] {})); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(polygon.contains(point)) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return properties; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}else { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Double distance = polygon.distance(point); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(standard > distance) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
standard = distance; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
result = properties; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -348,6 +340,249 @@ public class CoordUtils {
|
|
|
|
|
result.put("distance", standard); |
|
|
|
|
|
|
|
|
|
return result; |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 주소로 지역 바운더리 좌표 가져오기 |
|
|
|
|
* @param searchAdmCd DB에서 조회한 법정동 코드[10자리] |
|
|
|
|
* @param scope 지역 스코프, |
|
|
|
|
* @return 지역좌표 반환 |
|
|
|
|
*/ |
|
|
|
|
public List<LocationCoordinateModel> getCoordinateByAddress (String searchAdmCd, String scope){ |
|
|
|
|
|
|
|
|
|
String coordinateForderPath = this.getCodeForderPath(searchAdmCd, scope); |
|
|
|
|
String admCd = this.removeAdmCd(searchAdmCd, scope); |
|
|
|
|
|
|
|
|
|
List<LocationCoordinateModel> locationCoordinateModelList = new ArrayList<>(); |
|
|
|
|
|
|
|
|
|
try (InputStream inputStream = new ClassPathResource(coordinateForderPath).getInputStream(); |
|
|
|
|
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8), 8192);) { |
|
|
|
|
|
|
|
|
|
JSONParser jsonParser = new JSONParser(); |
|
|
|
|
JSONObject jsonObject = (JSONObject) jsonParser.parse(reader); |
|
|
|
|
List<JSONObject> features = (List<JSONObject>) jsonObject.get("features"); |
|
|
|
|
|
|
|
|
|
Optional<JSONObject> resultJsonObject = features.stream() |
|
|
|
|
.filter(feature -> { |
|
|
|
|
JSONObject properties = (JSONObject) feature.get("properties"); |
|
|
|
|
String cd = (String) properties.get("CD"); |
|
|
|
|
|
|
|
|
|
return cd.equals(admCd); |
|
|
|
|
}) |
|
|
|
|
.map(JSONObject::new) |
|
|
|
|
.findFirst(); |
|
|
|
|
|
|
|
|
|
JSONObject result = resultJsonObject.orElseThrow(() -> new CustomException(ErrorCode.DATA_NO)); |
|
|
|
|
JSONObject geometry = (JSONObject)result.get("geometry"); |
|
|
|
|
|
|
|
|
|
JSONArray coordinates = (JSONArray) geometry.get("coordinates"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for(int i = 0; i < coordinates.size(); i ++){ |
|
|
|
|
JSONArray arrayNode = (JSONArray)((JSONArray)coordinates.get(i)).get(0) ; |
|
|
|
|
|
|
|
|
|
List<Coordinate> coordinateList = new ArrayList<>(); |
|
|
|
|
|
|
|
|
|
for (Object o : arrayNode) { |
|
|
|
|
JSONArray node = (JSONArray) o; |
|
|
|
|
Coordinate coordimateModel = new Coordinate((Double) node.get(0), (Double) node.get(1)); |
|
|
|
|
coordinateList.add(coordimateModel); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
LocationCoordinateModel locationCoordinateModel = new LocationCoordinateModel(); |
|
|
|
|
locationCoordinateModel.setIndex(i); |
|
|
|
|
locationCoordinateModel.setCoordinateList(coordinateList); |
|
|
|
|
|
|
|
|
|
locationCoordinateModelList.add(locationCoordinateModel); |
|
|
|
|
} |
|
|
|
|
} catch (IOException | ParseException e) { |
|
|
|
|
log.error("", e); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return locationCoordinateModelList; |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 주소의 스코프 체크 기능. |
|
|
|
|
* @param address 스코프 체크할 주소 |
|
|
|
|
* @return 시/도: ctprvn, 시/군/구: sig, 읍/면/동: emd, 리: li |
|
|
|
|
*/ |
|
|
|
|
public String getScope(String address) { |
|
|
|
|
Map<String, String[]> patternMap = new HashMap<>(); |
|
|
|
|
patternMap.put("ctprvn", new String[]{ |
|
|
|
|
"^[^ ]+시$", |
|
|
|
|
"^[^ ]+도$" |
|
|
|
|
}); |
|
|
|
|
patternMap.put("sig", new String[]{ |
|
|
|
|
"^[^ ]+시 [^ ]+구$", |
|
|
|
|
"^[^ ]+시 [^ ]+군$", |
|
|
|
|
"^[^ ]+도 [^ ]+시$", |
|
|
|
|
"^[^ ]+도 [^ ]+군$", |
|
|
|
|
"^[^ ]+도 [^ ]+시 [^ ]+구$" |
|
|
|
|
}); |
|
|
|
|
patternMap.put("emd", new String[]{ |
|
|
|
|
"^[^ ]+시 [^ ]+구 [^ ]+동$", |
|
|
|
|
"^[^ ]+시 [^ ]+동$", |
|
|
|
|
"^[^ ]+시 [^ ]+읍$", |
|
|
|
|
"^[^ ]+시 [^ ]+면$", |
|
|
|
|
"^[^ ]+도 [^ ]+시 [^ ]+동$", |
|
|
|
|
"^[^ ]+도 [^ ]+시 [^ ]+읍$", |
|
|
|
|
"^[^ ]+도 [^ ]+시 [^ ]+면$", |
|
|
|
|
"^[^ ]+도 [^ ]+시 [^ ]+구 [^ ]+동$", |
|
|
|
|
"^[^ ]+도 [^ ]+시 [^ ]+구 [^ ]+읍$", |
|
|
|
|
"^[^ ]+도 [^ ]+시 [^ ]+구 [^ ]+면$", |
|
|
|
|
"^[^ ]+시 [^ ]+군 [^ ]+읍$", |
|
|
|
|
"^[^ ]+시 [^ ]+군 [^ ]+면$" |
|
|
|
|
}); |
|
|
|
|
patternMap.put("li", new String[]{ |
|
|
|
|
"^[^ ]+시 [^ ]+구 [^ ]+동 [^ ]+리$", |
|
|
|
|
"^[^ ]+시 [^ ]+동 [^ ]+리$", |
|
|
|
|
"^[^ ]+시 [^ ]+읍 [^ ]+리$", |
|
|
|
|
"^[^ ]+시 [^ ]+면 [^ ]+리$", |
|
|
|
|
"^[^ ]+도 [^ ]+시 [^ ]+동 [^ ]+리$", |
|
|
|
|
"^[^ ]+도 [^ ]+시 [^ ]+읍 [^ ]+리$", |
|
|
|
|
"^[^ ]+도 [^ ]+시 [^ ]+면 [^ ]+리$", |
|
|
|
|
"^[^ ]+도 [^ ]+시 [^ ]+구 [^ ]+동 [^ ]+리$", |
|
|
|
|
"^[^ ]+도 [^ ]+시 [^ ]+구 [^ ]+읍 [^ ]+리$", |
|
|
|
|
"^[^ ]+도 [^ ]+시 [^ ]+구 [^ ]+면 [^ ]+리$", |
|
|
|
|
"^[^ ]+시 [^ ]+군 [^ ]+읍 [^ ]+리$", |
|
|
|
|
"^[^ ]+시 [^ ]+군 [^ ]+면 [^ ]+리$" |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
for (Map.Entry<String, String[]> entry : patternMap.entrySet()) { |
|
|
|
|
for (String pattern : entry.getValue()) { |
|
|
|
|
if (Pattern.matches(pattern, address)) { |
|
|
|
|
return entry.getKey(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
throw new CustomException(ErrorCode.NON_VALID_PARAMETER); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 법정동코드와 스코프에 맞춰 조회할 좌표파일 경로 가져오는 기능 |
|
|
|
|
* @param cd 조회할 법정동코드 |
|
|
|
|
* @param scope 스코프 |
|
|
|
|
* @return 폴더경로 |
|
|
|
|
*/ |
|
|
|
|
private String getCodeForderPath(String cd, String scope){ |
|
|
|
|
|
|
|
|
|
if(cd.length() != 10) return null; |
|
|
|
|
|
|
|
|
|
Stack<String> forderPathStack = new Stack<>(); |
|
|
|
|
|
|
|
|
|
switch (scope) { |
|
|
|
|
case "li": |
|
|
|
|
forderPathStack.push(cd.substring(0, 8)); |
|
|
|
|
case "emd": |
|
|
|
|
forderPathStack.push(cd.substring(0, 5)); |
|
|
|
|
case "sig": |
|
|
|
|
forderPathStack.push(cd.substring(0, 2)); |
|
|
|
|
case "ctprvn": |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
StringBuilder forderPath = new StringBuilder(); |
|
|
|
|
forderPath.append(this.basePath); |
|
|
|
|
|
|
|
|
|
while(!forderPathStack.isEmpty()){ |
|
|
|
|
forderPath.append(forderPathStack.pop()); |
|
|
|
|
forderPath.append("/"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
forderPath.append(this.baseFileName); |
|
|
|
|
|
|
|
|
|
return forderPath.toString(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 법정동코드를 10자리에 맞춰 0을 추가[DB조회를 위함] |
|
|
|
|
* @param cd 10자리가 안되는 법정동코드 |
|
|
|
|
* @param scope 현재 법정동 코드의 스코프 |
|
|
|
|
* @return 10자리에 맞게 0이 추가된 법정동코드 |
|
|
|
|
*/ |
|
|
|
|
public String addAdmCd(String cd, String scope){ |
|
|
|
|
switch (scope) { |
|
|
|
|
case "ctprvn": |
|
|
|
|
|
|
|
|
|
if(cd.length() < 2) break; |
|
|
|
|
|
|
|
|
|
cd = cd.substring(0, 2); |
|
|
|
|
break; |
|
|
|
|
case "sig": |
|
|
|
|
|
|
|
|
|
if(cd.length() < 5) break; |
|
|
|
|
|
|
|
|
|
cd = cd.substring(0, 5); |
|
|
|
|
break; |
|
|
|
|
case "emd": |
|
|
|
|
|
|
|
|
|
if(cd.length() < 8) break; |
|
|
|
|
|
|
|
|
|
cd = cd.substring(0, 8); |
|
|
|
|
break; |
|
|
|
|
case "li": |
|
|
|
|
|
|
|
|
|
if(cd.length() < 10) break; |
|
|
|
|
|
|
|
|
|
cd = cd.substring(0, 10); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int length = cd.length(); |
|
|
|
|
int maxLength = 10; |
|
|
|
|
|
|
|
|
|
int difference = maxLength - length; |
|
|
|
|
|
|
|
|
|
StringBuilder sb = new StringBuilder(); |
|
|
|
|
sb.append(cd); |
|
|
|
|
|
|
|
|
|
for(int i = 0; i < difference; i++){ |
|
|
|
|
sb.append("0"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return sb.toString(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 스코프에 맞게 법정동코드 길이를 자르는 기능. |
|
|
|
|
* @param cd 잘라낼 법정동 코드 |
|
|
|
|
* @param scope 스코프 |
|
|
|
|
* @return 잘라진 법정동코드 |
|
|
|
|
*/ |
|
|
|
|
public String removeAdmCd(String cd, String scope){ |
|
|
|
|
|
|
|
|
|
if(cd.length() != 10) throw new CustomException(ErrorCode.NON_VALID_PARAMETER); |
|
|
|
|
|
|
|
|
|
String result = ""; |
|
|
|
|
|
|
|
|
|
switch (scope) { |
|
|
|
|
case "li": |
|
|
|
|
result = cd.substring(0, 10); |
|
|
|
|
break; |
|
|
|
|
case "emd": |
|
|
|
|
result = cd.substring(0, 8); |
|
|
|
|
break; |
|
|
|
|
case "sig": |
|
|
|
|
result = cd.substring(0, 5); |
|
|
|
|
break; |
|
|
|
|
case "ctprvn": |
|
|
|
|
result = cd.substring(0, 2); |
|
|
|
|
break; |
|
|
|
|
default: |
|
|
|
|
throw new CustomException(ErrorCode.NON_VALID_PARAMETER); |
|
|
|
|
} |
|
|
|
|
return result; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Data |
|
|
|
|
public static class LocationCoordinateModel { |
|
|
|
|
private Integer index; |
|
|
|
|
private List<Coordinate> coordinateList; |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|