|
|
@ -1,32 +1,25 @@ |
|
|
|
package com.palnet.comn.utils; |
|
|
|
package com.palnet.comn.utils; |
|
|
|
|
|
|
|
|
|
|
|
import java.io.BufferedReader; |
|
|
|
|
|
|
|
import java.io.IOException; |
|
|
|
|
|
|
|
import java.io.InputStream; |
|
|
|
|
|
|
|
import java.io.InputStreamReader; |
|
|
|
|
|
|
|
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.code.ErrorCode; |
|
|
|
import com.palnet.comn.exception.CustomException; |
|
|
|
import com.palnet.comn.exception.CustomException; |
|
|
|
import lombok.Data; |
|
|
|
import lombok.Data; |
|
|
|
|
|
|
|
import lombok.extern.slf4j.Slf4j; |
|
|
|
import org.json.simple.JSONArray; |
|
|
|
import org.json.simple.JSONArray; |
|
|
|
import org.json.simple.JSONObject; |
|
|
|
import org.json.simple.JSONObject; |
|
|
|
import org.json.simple.parser.JSONParser; |
|
|
|
import org.json.simple.parser.JSONParser; |
|
|
|
import org.json.simple.parser.ParseException; |
|
|
|
import org.json.simple.parser.ParseException; |
|
|
|
import org.locationtech.jts.geom.Coordinate; |
|
|
|
import org.locationtech.jts.geom.*; |
|
|
|
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.ClassPathResource; |
|
|
|
|
|
|
|
|
|
|
|
import lombok.extern.slf4j.Slf4j; |
|
|
|
import java.io.BufferedReader; |
|
|
|
|
|
|
|
import java.io.IOException; |
|
|
|
|
|
|
|
import java.io.InputStream; |
|
|
|
|
|
|
|
import java.io.InputStreamReader; |
|
|
|
|
|
|
|
import java.nio.charset.StandardCharsets; |
|
|
|
|
|
|
|
import java.util.*; |
|
|
|
|
|
|
|
import java.util.concurrent.*; |
|
|
|
|
|
|
|
import java.util.regex.Pattern; |
|
|
|
|
|
|
|
import java.util.stream.Collectors; |
|
|
|
|
|
|
|
|
|
|
|
@Slf4j |
|
|
|
@Slf4j |
|
|
|
public class CoordUtils { |
|
|
|
public class CoordUtils { |
|
|
@ -240,6 +233,7 @@ public class CoordUtils { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public JSONObject parseGeoJson(JSONObject obj, Coordinate coordinate) throws IOException, ParseException { |
|
|
|
public JSONObject parseGeoJson(JSONObject obj, Coordinate coordinate) throws IOException, ParseException { |
|
|
|
|
|
|
|
|
|
|
|
Point point = geometryFactory.createPoint(coordinate); |
|
|
|
Point point = geometryFactory.createPoint(coordinate); |
|
|
@ -277,6 +271,7 @@ public class CoordUtils { |
|
|
|
return this.contains(features, point); |
|
|
|
return this.contains(features, point); |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public JSONObject contains(List<JSONObject> features, Point point) { |
|
|
|
public JSONObject contains(List<JSONObject> features, Point point) { |
|
|
|
|
|
|
|
|
|
|
|
JSONObject result = null; |
|
|
|
JSONObject result = null; |
|
|
@ -344,6 +339,7 @@ public class CoordUtils { |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* 주소로 지역 바운더리 좌표 가져오기 |
|
|
|
* 주소로 지역 바운더리 좌표 가져오기 |
|
|
|
|
|
|
|
* |
|
|
|
* @param searchAdmCd DB에서 조회한 법정동 코드[10자리] |
|
|
|
* @param searchAdmCd DB에서 조회한 법정동 코드[10자리] |
|
|
|
* @param scope 지역 스코프, |
|
|
|
* @param scope 지역 스코프, |
|
|
|
* @return 지역좌표 반환 |
|
|
|
* @return 지역좌표 반환 |
|
|
@ -404,9 +400,9 @@ public class CoordUtils { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* 주소의 스코프 체크 기능. |
|
|
|
* 주소의 스코프 체크 기능. |
|
|
|
|
|
|
|
* |
|
|
|
* @param address 스코프 체크할 주소 |
|
|
|
* @param address 스코프 체크할 주소 |
|
|
|
* @return 시/도: ctprvn, 시/군/구: sig, 읍/면/동: emd, 리: li |
|
|
|
* @return 시/도: ctprvn, 시/군/구: sig, 읍/면/동: emd, 리: li |
|
|
|
*/ |
|
|
|
*/ |
|
|
@ -465,6 +461,7 @@ public class CoordUtils { |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* 법정동코드와 스코프에 맞춰 조회할 좌표파일 경로 가져오는 기능 |
|
|
|
* 법정동코드와 스코프에 맞춰 조회할 좌표파일 경로 가져오는 기능 |
|
|
|
|
|
|
|
* |
|
|
|
* @param cd 조회할 법정동코드 |
|
|
|
* @param cd 조회할 법정동코드 |
|
|
|
* @param scope 스코프 |
|
|
|
* @param scope 스코프 |
|
|
|
* @return 폴더경로 |
|
|
|
* @return 폴더경로 |
|
|
@ -500,6 +497,7 @@ public class CoordUtils { |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* 법정동코드를 10자리에 맞춰 0을 추가[DB조회를 위함] |
|
|
|
* 법정동코드를 10자리에 맞춰 0을 추가[DB조회를 위함] |
|
|
|
|
|
|
|
* |
|
|
|
* @param cd 10자리가 안되는 법정동코드 |
|
|
|
* @param cd 10자리가 안되는 법정동코드 |
|
|
|
* @param scope 현재 법정동 코드의 스코프 |
|
|
|
* @param scope 현재 법정동 코드의 스코프 |
|
|
|
* @return 10자리에 맞게 0이 추가된 법정동코드 |
|
|
|
* @return 10자리에 맞게 0이 추가된 법정동코드 |
|
|
@ -549,6 +547,7 @@ public class CoordUtils { |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* 스코프에 맞게 법정동코드 길이를 자르는 기능. |
|
|
|
* 스코프에 맞게 법정동코드 길이를 자르는 기능. |
|
|
|
|
|
|
|
* |
|
|
|
* @param cd 잘라낼 법정동 코드 |
|
|
|
* @param cd 잘라낼 법정동 코드 |
|
|
|
* @param scope 스코프 |
|
|
|
* @param scope 스코프 |
|
|
|
* @return 잘라진 법정동코드 |
|
|
|
* @return 잘라진 법정동코드 |
|
|
@ -585,4 +584,151 @@ public class CoordUtils { |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public List<JSONObject> getPlace(List<Coordinate> coords) { |
|
|
|
|
|
|
|
Geometry target = geometryFactory.createPolygon(coords.toArray(new Coordinate[]{})); |
|
|
|
|
|
|
|
List<JSONObject> result = new ArrayList<>(); |
|
|
|
|
|
|
|
List<JSONObject> firstIntersectList = new ArrayList<>(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (JSONObject location : this.allLocation) { |
|
|
|
|
|
|
|
List<JSONObject> features = (List<JSONObject>) location.get("features"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
List<JSONObject> intersects = this.intersects(features, target); |
|
|
|
|
|
|
|
firstIntersectList.addAll(intersects); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
boolean isIntersect = firstIntersectList.stream().anyMatch(properties -> properties.get("distance") == null); |
|
|
|
|
|
|
|
if (isIntersect) { |
|
|
|
|
|
|
|
firstIntersectList = firstIntersectList.stream().filter(properties -> properties.get("distance") == null).collect(Collectors.toList()); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
JSONObject jsonObject = firstIntersectList.stream().min(Comparator.comparingDouble(properties -> (Double) properties.get("distance"))).orElse(null); |
|
|
|
|
|
|
|
if (jsonObject != null) { |
|
|
|
|
|
|
|
firstIntersectList = new ArrayList<>(); |
|
|
|
|
|
|
|
firstIntersectList.add(jsonObject); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (firstIntersectList.isEmpty()) { |
|
|
|
|
|
|
|
return result; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (JSONObject properties : firstIntersectList) { |
|
|
|
|
|
|
|
List<JSONObject> subPropertiesList = getSubPropertiesByFile(properties, target); |
|
|
|
|
|
|
|
if(!subPropertiesList.isEmpty()) { |
|
|
|
|
|
|
|
result.addAll(subPropertiesList); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return result; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private List<JSONObject> getSubPropertiesByFile(JSONObject properties, Geometry target) { |
|
|
|
|
|
|
|
String depth = properties.get("CD").toString(); |
|
|
|
|
|
|
|
final String address = properties.get("KOR_NM").toString(); |
|
|
|
|
|
|
|
String path = basePath + depth.substring(0, 2) + "/" + depth + "/"; |
|
|
|
|
|
|
|
String filename = path + baseFileName; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ClassPathResource classPathResource = new ClassPathResource(filename); |
|
|
|
|
|
|
|
List<JSONObject> result = new ArrayList<>(); |
|
|
|
|
|
|
|
if (!classPathResource.exists()) { |
|
|
|
|
|
|
|
return result; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
List<JSONObject> features = new ArrayList<>(); |
|
|
|
|
|
|
|
try (InputStream inputStream = new ClassPathResource(filename).getInputStream(); |
|
|
|
|
|
|
|
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"), 8192)) { |
|
|
|
|
|
|
|
JSONParser jsonParser = new JSONParser(); |
|
|
|
|
|
|
|
JSONObject jsonObject = (JSONObject) jsonParser.parse(reader); |
|
|
|
|
|
|
|
features = (List<JSONObject>) jsonObject.get("features"); |
|
|
|
|
|
|
|
} catch (Exception e) { |
|
|
|
|
|
|
|
log.error("", e); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
result = this.intersects(features, target); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
boolean isIntersect = result.stream().anyMatch(p -> p.get("distance") == null); |
|
|
|
|
|
|
|
if (isIntersect) { |
|
|
|
|
|
|
|
result = result.stream().filter(p -> p.get("distance") == null).collect(Collectors.toList()); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
JSONObject jsonObject = result.stream().min(Comparator.comparingDouble(p -> (Double) p.get("distance"))).orElse(null); |
|
|
|
|
|
|
|
if (jsonObject != null) { |
|
|
|
|
|
|
|
result = new ArrayList<>(); |
|
|
|
|
|
|
|
result.add(jsonObject); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
result.forEach(subProperties -> subProperties.put("address", address + " " + subProperties.get("KOR_NM"))); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (JSONObject subProperties : result) { |
|
|
|
|
|
|
|
List<JSONObject> subSubPropertiesList = getSubPropertiesByFile(subProperties, target); |
|
|
|
|
|
|
|
if(!subSubPropertiesList.isEmpty()) { |
|
|
|
|
|
|
|
result.addAll(subSubPropertiesList); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return result; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private List<JSONObject> intersects(List<JSONObject> features, Geometry target) { |
|
|
|
|
|
|
|
List<JSONObject> intersectRs = new ArrayList<>(); |
|
|
|
|
|
|
|
JSONObject isNotInstersectRs = null; |
|
|
|
|
|
|
|
double distance = Double.MAX_VALUE; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (JSONObject feature : features) { |
|
|
|
|
|
|
|
JSONObject properties = (JSONObject) feature.get("properties"); |
|
|
|
|
|
|
|
JSONObject geometry = (JSONObject) feature.get("geometry"); |
|
|
|
|
|
|
|
List<JSONArray> coordinates = (List<JSONArray>) geometry.get("coordinates"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
List<Polygon> polygons = new ArrayList<>(); |
|
|
|
|
|
|
|
for (JSONArray coordinate : coordinates) { |
|
|
|
|
|
|
|
List<Coordinate> polygonPaths = new ArrayList<>(); |
|
|
|
|
|
|
|
for (Object coords1 : coordinate) { |
|
|
|
|
|
|
|
for (int j = 0; j < ((JSONArray) coords1).size(); j++) { |
|
|
|
|
|
|
|
Object coord = ((JSONArray) coords1).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.isEmpty()) { |
|
|
|
|
|
|
|
polygons.add(polygon); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
MultiPolygon multiPolygon = null; |
|
|
|
|
|
|
|
if (!polygons.isEmpty()) { |
|
|
|
|
|
|
|
multiPolygon = geometryFactory.createMultiPolygon(polygons.toArray(new Polygon[]{})); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (multiPolygon != null) { |
|
|
|
|
|
|
|
boolean isIntersects = multiPolygon.intersects(target); |
|
|
|
|
|
|
|
if (isIntersects) { |
|
|
|
|
|
|
|
intersectRs.add(properties); |
|
|
|
|
|
|
|
isNotInstersectRs = null; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
if (intersectRs.isEmpty()) { |
|
|
|
|
|
|
|
double targetDistance = multiPolygon.distance(target); |
|
|
|
|
|
|
|
if (targetDistance < distance) { |
|
|
|
|
|
|
|
distance = targetDistance; |
|
|
|
|
|
|
|
properties.put("distance", distance); |
|
|
|
|
|
|
|
isNotInstersectRs = properties; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
log.debug("multiPolygon is null"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (intersectRs.isEmpty() && isNotInstersectRs != null) { |
|
|
|
|
|
|
|
intersectRs.add(isNotInstersectRs); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return intersectRs; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|