diff --git a/http/server/server.http b/http/server/server.http index 8c82e829..4baf3002 100644 --- a/http/server/server.http +++ b/http/server/server.http @@ -38,8 +38,8 @@ // 김항소-관제과 // const loginInfo = { - // userId: "GMPATC2", - // userPswd: "GMPATC12!@" + // userId: "GMPOPS", + // userPswd: "GMPOPS12!@" // } diff --git a/pav-server/src/main/java/com/palnet/comn/utils/AirAreaUtils.java b/pav-server/src/main/java/com/palnet/comn/utils/AirAreaUtils.java index 8ba0d6b0..4974280e 100644 --- a/pav-server/src/main/java/com/palnet/comn/utils/AirAreaUtils.java +++ b/pav-server/src/main/java/com/palnet/comn/utils/AirAreaUtils.java @@ -7,6 +7,7 @@ import lombok.extern.slf4j.Slf4j; import org.geotools.geojson.feature.FeatureJSON; import org.geotools.geojson.geom.GeometryJSON; import org.geotools.geometry.jts.JTS; +import org.geotools.geometry.jts.JTSFactoryFinder; import org.geotools.referencing.CRS; import org.geotools.referencing.GeodeticCalculator; import org.json.simple.JSONArray; @@ -20,7 +21,9 @@ import org.locationtech.proj4j.BasicCoordinateTransform; import org.locationtech.proj4j.CRSFactory; import org.locationtech.proj4j.ProjCoordinate; import org.opengis.feature.simple.SimpleFeature; +import org.opengis.referencing.FactoryException; import org.opengis.referencing.crs.CoordinateReferenceSystem; +import org.opengis.referencing.operation.MathTransform; import org.opengis.referencing.operation.TransformException; import org.springframework.cache.annotation.Cacheable; import org.springframework.core.io.Resource; @@ -41,6 +44,7 @@ import java.util.stream.Collectors; @Slf4j public class AirAreaUtils { + private final int PERIMETER_OF_EARTH = 40075 * 1000; // 지구 둘레(m) private final String RESOURCE_BASE_PATH = "air/airspace/"; private final String COMMON_PATH = "common/"; private final String CUSTOM_PATH = "custom/"; @@ -93,7 +97,7 @@ public class AirAreaUtils { /** - * 초기화 + * 초기화 */ private void init() { airAreaMap = new HashMap<>(); @@ -663,9 +667,15 @@ public class AirAreaUtils { return originalGeometry; // Return the original geometry if type is not handled } + public static List swapCoordinates(List originalCoordinates) { + return originalCoordinates.stream().map(coordinate -> new Coordinate(coordinate.y, coordinate.x)).collect(Collectors.toList()); + + } + // ---------------------- AreaUtils ---------------------- // TODO 버퍼 생성시 임의로 좌표변환을 해야만 하는지 확인 ex) espg:4326 -> espg:5181 -> espg:4326 + /** * 좌표계 변환 * @@ -685,7 +695,7 @@ public class AirAreaUtils { List result = new ArrayList<>(); - for(Coordinate coord : coordList) { + for (Coordinate coord : coordList) { ProjCoordinate projCoordinate = new ProjCoordinate(coord.getX(), coord.getY()); ProjCoordinate projTrasform = transform.transform(projCoordinate, new ProjCoordinate()); @@ -706,7 +716,7 @@ public class AirAreaUtils { */ public List buffer(List coordList, double bufferZone) { - LineString line = geometryFactory.createLineString(coordList.toArray(new Coordinate[] {})); + LineString line = geometryFactory.createLineString(coordList.toArray(new Coordinate[]{})); Geometry geometry = geometryFactory.createGeometry(line); // buffer @@ -726,6 +736,7 @@ public class AirAreaUtils { } // TODO 곡률로 구성된 원 생성방법 확인(타원이 아닌) + /** * 타원 생성 * @@ -740,9 +751,9 @@ public class AirAreaUtils { double lat = CircleCoord.y; double diameterInMeters = BufferZone; - shapeFactory.setCentre(new Coordinate(lng , lat)); + shapeFactory.setCentre(new Coordinate(lng, lat)); shapeFactory.setHeight((diameterInMeters * 2) / 111320d); - shapeFactory.setWidth((diameterInMeters * 2) / (40075000 * Math.cos(Math.toRadians(lat)) / 360)); + shapeFactory.setWidth((diameterInMeters * 2) / (PERIMETER_OF_EARTH * Math.cos(Math.toRadians(lat)) / 360)); shapeFactory.setNumPoints(64); final Polygon circle = shapeFactory.createCircle(); @@ -756,43 +767,86 @@ public class AirAreaUtils { return coordList; } + /* + // 라인 버퍼 생성 샘플 + public static void main(String[] args) throws FactoryException, TransformException { + // EPSG:4326 좌표계 정의 + CoordinateReferenceSystem crs4326 = CRS.decode("EPSG:4326"); + // EPSG:3857 좌표계 정의 (투영 좌표계) +// CoordinateReferenceSystem crs3857 = CRS.decode("EPSG:3857"); + CoordinateReferenceSystem crs3857 = CRS.decode("EPSG:5181"); - public static void main(String[] args) { - AirAreaUtils utils = AirAreaUtils.getInstance(); - log.info("utils: {}", utils); - -// AirAreaUtils utils2 = AirAreaUtils.getInstance(); -// log.info("utils2: {}", utils2); -// log.info("utils == utils2: {}", utils == utils2); -// -// List list = List.of(1, 2, 3, 4, 5); -// boolean b = list.stream().anyMatch(i -> i == 3); -// log.info("b:: {}", b); -// List list2 = new ArrayList<>(); -// boolean b2 = list2.stream().anyMatch(i -> i == 3); -// log.info("b2:: {}", b2); - - Map> airMap = utils.getAirAreaMap(); - airMap.forEach((k, v) -> { - log.info("{} - {}", k, v.size()); - }); - - List beforeCoordinates = List.of( - new Coordinate(126.0, 37.0), - new Coordinate(126.0, 38.0), - new Coordinate(127.0, 38.0), + // 좌표 변환기 설정 + MathTransform transformTo3857 = CRS.findMathTransform(crs4326, crs3857); + MathTransform transformTo4326 = CRS.findMathTransform(crs3857, crs4326); + + // GeometryFactory 생성 + GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory(); + + // LineString 좌표 정의 (EPSG:4326) + Coordinate[] coordinates = new Coordinate[]{ new Coordinate(127.0, 37.0), - new Coordinate(126.0, 37.0) - ); + new Coordinate(127.1, 37.1), + new Coordinate(127.2, 37.2) + }; + List coordinates1 = AirAreaUtils.swapCoordinates(Arrays.asList(coordinates)); + LineString lineString = geometryFactory.createLineString(coordinates1.toArray(new Coordinate[0])); + + // LineString을 EPSG:3857로 변환 + LineString transformedLineString = (LineString) JTS.transform(lineString, transformTo3857); + + // 거리 (단위: 미터) + double distance = 1000; // 1km + + // Buffer를 사용하여 LineString을 둘러싼 Polygon 생성 (EPSG:3857) + Polygon bufferedPolygon = (Polygon) transformedLineString.buffer(distance); + + // Buffered Polygon을 EPSG:4326로 변환 + Polygon finalPolygon = (Polygon) JTS.transform(bufferedPolygon, transformTo4326); + List finalCoordinates = Arrays.stream(finalPolygon.getCoordinates()).map(coordinate -> new de.micromata.opengis.kml.v_2_2_0.Coordinate(coordinate.y, coordinate.x)).collect(Collectors.toList()); + + // 결과 출력 + KmlUtils.KmlRq bufferRq = KmlUtils.KmlRq.builder() + .name("test") + .type(KmlUtils.TYPE.POLYGON) + .coordinates(finalCoordinates) + .build(); + KmlUtils.KmlRq lineRq = KmlUtils.KmlRq.builder() + .name("test") + .type(KmlUtils.TYPE.LINESTRING) + .coordinates(Arrays.stream(coordinates).map(coordinate -> new de.micromata.opengis.kml.v_2_2_0.Coordinate(coordinate.x, coordinate.y)).collect(Collectors.toList())) + .build(); + String str = KmlUtils.createKmlPolygons(List.of(bufferRq, lineRq)); + System.out.println(str); + + } + */ - List transCoordList = utils.transform(beforeCoordinates, "EPSG:4326", "EPSG:5181"); - List bufferList = utils.buffer(transCoordList, 50); // buffer 영역 생성 + public static Coordinate transformCoordinate(Coordinate sourceCoord, String sourceCRSCode, String targetCRSCode) throws Exception { + // 소스와 타겟 CRS 정의 + CoordinateReferenceSystem sourceCRS = CRS.decode(sourceCRSCode); + CoordinateReferenceSystem targetCRS = CRS.decode(targetCRSCode); - List transBufferList = utils.transform(bufferList, "EPSG:5181", "EPSG:4326"); // buffer 영역 좌표계 변환 - log.info("transBufferList: {}", transBufferList); + // MathTransform 객체 생성 + MathTransform transform = CRS.findMathTransform(sourceCRS, targetCRS); + + // 좌표 변환 + return JTS.transform(sourceCoord, null, transform); + } + public static void main(String[] args) { + try { + Coordinate sourceCoord = new Coordinate(37.111, 127.1133); + Coordinate transformedCoord = transformCoordinate(sourceCoord, "EPSG:4326", "EPSG:5181"); + System.out.println("Transformed Coordinate1: " + transformedCoord); + Coordinate transformedCoord2 = transformCoordinate(transformedCoord, "EPSG:5181", "EPSG:4326"); + System.out.println("Transformed Coordinate2: " + transformedCoord2); + } catch (Exception e) { + e.printStackTrace(); + } } + } diff --git a/pav-server/src/main/java/com/palnet/comn/utils/AirspaceUtils.java b/pav-server/src/main/java/com/palnet/comn/utils/AirspaceUtils.java index abb30bf8..bc8e8cb4 100644 --- a/pav-server/src/main/java/com/palnet/comn/utils/AirspaceUtils.java +++ b/pav-server/src/main/java/com/palnet/comn/utils/AirspaceUtils.java @@ -494,4 +494,5 @@ public class AirspaceUtils { return originalGeometry; // Return the original geometry if type is not handled } + } diff --git a/pav-server/src/main/java/com/palnet/comn/utils/KmlUtils.java b/pav-server/src/main/java/com/palnet/comn/utils/KmlUtils.java index e605e664..b213a054 100644 --- a/pav-server/src/main/java/com/palnet/comn/utils/KmlUtils.java +++ b/pav-server/src/main/java/com/palnet/comn/utils/KmlUtils.java @@ -5,39 +5,86 @@ import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; import java.io.StringWriter; import java.util.ArrayList; import java.util.List; +@Slf4j public class KmlUtils { final static Kml kml = new Kml(); public static String createKmlPolygons(List rqList) { // validation - if(rqList == null || rqList.isEmpty()) { + if (rqList == null || rqList.isEmpty()) { return null; } // document Document doc = kml.createAndSetDocument().withName("kml-export"); - Style style = doc.createAndAddStyle().withId("styled001"); - style.createAndSetLineStyle().withColor("ff0000ff").withWidth(2.0); - style.createAndSetPolyStyle().withColor("7f00ff00"); + + Style polygonStyle = doc.createAndAddStyle().withId("polygon-style-001"); + polygonStyle.createAndSetLineStyle().withColor("ff0000ff").withWidth(2.0); + polygonStyle.createAndSetPolyStyle().withColor("7f00ff00"); + log.info(">>> polygonStyle: {}", polygonStyle.getId()); + + Style lineStyle = doc.createAndAddStyle().withId("line-style-001"); + lineStyle.createAndSetLineStyle().withColor("ff0000ff").withWidth(2.0); + lineStyle.createAndSetPolyStyle().withColor("7f00ff00"); + log.info(">>> lineStyle: {}", lineStyle.getId()); + // folder Folder folder = doc.createAndAddFolder().withName("kml-folder"); rqList.forEach(rq -> { + + List coordinates = rq.getCoordinates(); + if (coordinates != null && !coordinates.isEmpty() && rq.getType() == null) { + if (coordinates.size() == 1) { + rq.setType(TYPE.POINT); + } else { + Coordinate firstCoordinate = coordinates.get(0); + Coordinate lastCoordinate = coordinates.get(coordinates.size() - 1); + if (firstCoordinate.equals(lastCoordinate)) { + rq.setType(TYPE.POLYGON); + } else { + rq.setType(TYPE.LINESTRING); + } + } + } + + // placemark - polygon - Placemark placemark = folder.createAndAddPlacemark() - .withName(rq.getName()) - .withVisibility(true) - .withStyleUrl("#styled001"); - LinearRing linearRing = placemark.createAndSetPolygon() - .createAndSetOuterBoundaryIs() - .createAndSetLinearRing() - .withCoordinates(rq.getCoordinates()); + if (TYPE.POLYGON == rq.getType()) { + + Placemark placemark = folder.createAndAddPlacemark() + .withName(rq.getName()) + .withVisibility(true) + .withStyleUrl("#" + polygonStyle.getId()); + + Polygon polygon = placemark.createAndSetPolygon(); + + polygon.createAndSetOuterBoundaryIs() + .createAndSetLinearRing() + .withCoordinates(rq.getCoordinates()); + + } else if (TYPE.LINESTRING == rq.getType()) { + + Placemark placemark = folder.createAndAddPlacemark() + .withName(rq.getName()) + .withVisibility(true) + .withStyleUrl("#" + lineStyle.getId()); + + LineString lineString = placemark.createAndSetLineString() + .withTessellate(true) + .withCoordinates(rq.getCoordinates()); + + } else if (TYPE.POINT == rq.getType()) { + // TODO + } + }); @@ -52,30 +99,35 @@ public class KmlUtils { @Builder public static class KmlRq { private String name; + private TYPE type; @Builder.Default private List coordinates = new ArrayList<>(); } + public enum TYPE { + POLYGON, LINESTRING, POINT + } + public static void main(String[] args) { KmlRq rq1 = KmlRq.builder() .name("test1") .coordinates(List.of( - new Coordinate(126.73229515507134,37.622273460242354), - new Coordinate(126.73329515507134,37.622273460242354), - new Coordinate(126.73329515507134,37.622373460242354), - new Coordinate(126.73229515507134,37.622373460242354), - new Coordinate(126.73229515507134,37.622273460242354) + new Coordinate(126.73229515507134, 37.622273460242354), + new Coordinate(126.73329515507134, 37.622273460242354), + new Coordinate(126.73329515507134, 37.622373460242354), + new Coordinate(126.73229515507134, 37.622373460242354), + new Coordinate(126.73229515507134, 37.622273460242354) )) .build(); KmlRq rq2 = KmlRq.builder() .name("test2") .coordinates(List.of( - new Coordinate(126.74229515507134,37.632273460242354), - new Coordinate(126.74329515507134,37.632273460242354), - new Coordinate(126.74329515507134,37.632373460242354), - new Coordinate(126.74229515507134,37.632373460242354), - new Coordinate(126.74229515507134,37.632273460242354) + new Coordinate(126.74229515507134, 37.632273460242354), + new Coordinate(126.74329515507134, 37.632273460242354), + new Coordinate(126.74329515507134, 37.632373460242354), + new Coordinate(126.74229515507134, 37.632373460242354), + new Coordinate(126.74229515507134, 37.632273460242354) )) .build(); String str = createKmlPolygons(List.of(rq1, rq2));