선택 폴리곤, 포인트 정보 api 추가

This commit is contained in:
2026-02-24 12:17:20 +09:00
parent 190ba525d5
commit c93d40f3f3
5 changed files with 369 additions and 51 deletions

View File

@@ -2,7 +2,6 @@ package com.kamco.cd.kamcoback.changedetection;
import com.fasterxml.jackson.databind.JsonNode;
import com.kamco.cd.kamcoback.changedetection.dto.ChangeDetectionDto;
import com.kamco.cd.kamcoback.changedetection.dto.ChangeDetectionDto.ChangeDetectionMapDto;
import com.kamco.cd.kamcoback.changedetection.dto.ChangeDetectionDto.DetectSearchType;
import com.kamco.cd.kamcoback.changedetection.dto.ChangeDetectionDto.MapScaleType;
import com.kamco.cd.kamcoback.changedetection.service.ChangeDetectionService;
@@ -148,30 +147,43 @@ public class ChangeDetectionApiController {
changeDetectionService.getChangeDetectionPointList(type, scale, uuid, mapSheetNum));
}
@Operation(summary = "변화지도 uuid 조회", description = "변화지도 uuid 조회 API")
@GetMapping("/map")
public ApiResponseDto<UUID> getChangeDetection(
@Parameter(description = "기준년도", required = true) @RequestParam(defaultValue = "2022")
Integer stddYear,
@Parameter(description = "비교년도", required = true) @RequestParam(defaultValue = "2023")
Integer cprsnYear,
@Parameter(description = "변화탐지 객체 id 32자리") @RequestParam(defaultValue = "", required = false)
String cdObjectId,
@Parameter(description = "변화탐지 객체 ids 32자리")
@RequestParam(defaultValue = "", required = false)
List<String> cdObjectIds,
@Parameter(description = "변화탐지 회차별 id 32자리")
@RequestParam(defaultValue = "", required = false)
@Operation(summary = "선택 변화탐지 결과 Polygon", description = "선택 변화탐지 결과 Polygon")
@GetMapping("/selected/polygon")
public ApiResponseDto<ChangeDetectionDto.PolygonFeatureList> getCdPolygonList(
@Parameter(description = "회차 32자 uid", example = "98ABAA1FC4394F11885C302C19AE5E81")
@RequestParam
String chnDtctId,
@Parameter(description = "pnu") @RequestParam(defaultValue = "", required = false)
String pnu) {
ChangeDetectionMapDto req = new ChangeDetectionMapDto();
req.setCompareYyyy(stddYear);
req.setTargetYyyy(cprsnYear);
req.setCdObjectId(cdObjectId);
req.setCdObjectIds(cdObjectIds);
req.setChnDtctId(chnDtctId);
req.setPnu(pnu);
return ApiResponseDto.ok(changeDetectionService.getChangeDetectionUuid(req));
@Parameter(description = "polygon 32자 uid", example = "3B1A7E5F895A4D9698489540EE1BBE1E")
@RequestParam
String cdObjectId,
@Parameter(
description = "polygon 32자 uids",
example =
"3B1A7E5F895A4D9698489540EE1BBE1E,3B221A2AF9614647A0903A972D56C574,3B22686A7ACE44FC9CB20F1B4FA6DEFD,3B376D94A183479BB5FBE3D7166E6E1A")
@RequestParam
List<String> cdObjectIds,
@Parameter(description = "pnu") @RequestParam(required = false) String pnu) {
return ApiResponseDto.ok(
changeDetectionService.getPolygonListByCd(chnDtctId, cdObjectId, cdObjectIds, pnu));
}
@Operation(summary = "선택 변화탐지 결과 Point", description = "선택 변화탐지 결과 Point")
@GetMapping("/selected/point")
public ApiResponseDto<ChangeDetectionDto.PointFeatureList> getCdPointList(
@Parameter(description = "회차 32자 uid", example = "98ABAA1FC4394F11885C302C19AE5E81")
@RequestParam
String chnDtctId,
@Parameter(description = "polygon 32자 uid", example = "3B1A7E5F895A4D9698489540EE1BBE1E")
@RequestParam
String cdObjectId,
@Parameter(
description = "polygon 32자 uids",
example =
"3B1A7E5F895A4D9698489540EE1BBE1E,3B221A2AF9614647A0903A972D56C574,3B22686A7ACE44FC9CB20F1B4FA6DEFD,3B376D94A183479BB5FBE3D7166E6E1A")
@RequestParam
List<String> cdObjectIds,
@Parameter(description = "pnu") @RequestParam(required = false) String pnu) {
return ApiResponseDto.ok(
changeDetectionService.getPointListByCd(chnDtctId, cdObjectId, cdObjectIds, pnu));
}
}

View File

@@ -2,7 +2,6 @@ package com.kamco.cd.kamcoback.changedetection.service;
import com.fasterxml.jackson.databind.JsonNode;
import com.kamco.cd.kamcoback.changedetection.dto.ChangeDetectionDto;
import com.kamco.cd.kamcoback.changedetection.dto.ChangeDetectionDto.ChangeDetectionMapDto;
import com.kamco.cd.kamcoback.changedetection.dto.ChangeDetectionDto.DetectSearchType;
import com.kamco.cd.kamcoback.changedetection.dto.ChangeDetectionDto.MapScaleType;
import com.kamco.cd.kamcoback.postgres.core.ChangeDetectionCoreService;
@@ -91,7 +90,31 @@ public class ChangeDetectionService {
}
}
public UUID getChangeDetectionUuid(ChangeDetectionMapDto req) {
return changeDetectionCoreService.getChangeDetectionUuid(req);
/**
* 선택 폴리곤 정보 조회
*
* @param chnDtctId
* @param cdObjectId
* @param cdObjectIds
* @param pnu
* @return
*/
public ChangeDetectionDto.PolygonFeatureList getPolygonListByCd(
String chnDtctId, String cdObjectId, List<String> cdObjectIds, String pnu) {
return changeDetectionCoreService.getPolygonListByCd(chnDtctId, cdObjectId, cdObjectIds);
}
/**
* 선택 Point 조회
*
* @param chnDtctId
* @param cdObjectId
* @param cdObjectIds
* @param pnu
* @return
*/
public ChangeDetectionDto.PointFeatureList getPointListByCd(
String chnDtctId, String cdObjectId, List<String> cdObjectIds, String pnu) {
return changeDetectionCoreService.getPointListByCd(chnDtctId, cdObjectId, cdObjectIds);
}
}

View File

@@ -4,11 +4,9 @@ import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.kamco.cd.kamcoback.changedetection.dto.ChangeDetectionDto;
import com.kamco.cd.kamcoback.changedetection.dto.ChangeDetectionDto.ChangeDetectionMapDto;
import com.kamco.cd.kamcoback.changedetection.dto.ChangeDetectionDto.MapScaleType;
import com.kamco.cd.kamcoback.changedetection.dto.ChangeDetectionDto.MapSheetList;
import com.kamco.cd.kamcoback.common.enums.DetectionClassification;
import com.kamco.cd.kamcoback.common.exception.CustomApiException;
import com.kamco.cd.kamcoback.postgres.entity.MapSheetAnalDataInferenceGeomEntity;
import com.kamco.cd.kamcoback.postgres.repository.changedetection.ChangeDetectionRepository;
import java.util.List;
@@ -17,7 +15,6 @@ import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.Point;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
@Service
@@ -100,9 +97,53 @@ public class ChangeDetectionCoreService {
return changeDetectionRepository.getChangeDetectionMapSheet50kList(uuid);
}
public UUID getChangeDetectionUuid(ChangeDetectionMapDto req) {
return changeDetectionRepository
.getChangeDetectionUuid(req)
.orElseThrow(() -> new CustomApiException("NOT_FOUND_DATA", HttpStatus.NOT_FOUND));
/**
* 선택 폴리곤 조회 by object id
*
* @param chnDtctId 회차 uid 32자
* @param cdObjectId geo object uid 32자
* @param cdObjectIds geo object uids 32자
* @return
*/
public ChangeDetectionDto.PolygonFeatureList getPolygonListByCd(
String chnDtctId, String cdObjectId, List<String> cdObjectIds) {
return changeDetectionRepository.getPolygonListByCd(chnDtctId, cdObjectId, cdObjectIds);
}
/**
* 선택 Point 조회 by object id
*
* @param chnDtctId 회차 uid 32자
* @param cdObjectId geo object uid 32자
* @param cdObjectIds geo object uids 32자
* @return
*/
public ChangeDetectionDto.PointFeatureList getPointListByCd(
String chnDtctId, String cdObjectId, List<String> cdObjectIds) {
return changeDetectionRepository.getPointListByCd(chnDtctId, cdObjectId, cdObjectIds);
}
/**
* 선택 polygon 조회 by pnu
*
* @param chnDtctId 회차 uid 32자
* @param pnu Pnu
* @return
*/
public ChangeDetectionDto.PolygonFeatureList getSelectedChangeDetectionPolygonListByPnu(
String chnDtctId, String pnu) {
return changeDetectionRepository.getSelectedChangeDetectionPolygonListByPnu(chnDtctId, pnu);
}
/**
* 선택 point 조회 by pnu
*
* @param chnDtctId 회차 uid 32자
* @param pnu Pnu
* @return
*/
public ChangeDetectionDto.PointFeatureList getSelectedChangeDetectionPointListByPnu(
String chnDtctId, String pnu) {
return changeDetectionRepository.getSelectedChangeDetectionPointListByPnu(chnDtctId, pnu);
}
}

View File

@@ -1,11 +1,9 @@
package com.kamco.cd.kamcoback.postgres.repository.changedetection;
import com.kamco.cd.kamcoback.changedetection.dto.ChangeDetectionDto;
import com.kamco.cd.kamcoback.changedetection.dto.ChangeDetectionDto.ChangeDetectionMapDto;
import com.kamco.cd.kamcoback.changedetection.dto.ChangeDetectionDto.MapScaleType;
import com.kamco.cd.kamcoback.changedetection.dto.ChangeDetectionDto.MapSheetList;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
public interface ChangeDetectionRepositoryCustom {
@@ -31,5 +29,15 @@ public interface ChangeDetectionRepositoryCustom {
List<MapSheetList> getChangeDetectionMapSheet50kList(UUID uuid);
Optional<UUID> getChangeDetectionUuid(ChangeDetectionMapDto req);
ChangeDetectionDto.PolygonFeatureList getPolygonListByCd(
String chnDtctId, String cdObjectId, List<String> cdObjectIds);
ChangeDetectionDto.PointFeatureList getPointListByCd(
String chnDtctId, String cdObjectId, List<String> cdObjectIds);
ChangeDetectionDto.PolygonFeatureList getSelectedChangeDetectionPolygonListByPnu(
String chnDtctId, String pnu);
ChangeDetectionDto.PointFeatureList getSelectedChangeDetectionPointListByPnu(
String chnDtctId, String pnu);
}

View File

@@ -8,15 +8,17 @@ import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetAnalDataInferenceG
import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetAnalInferenceEntity.mapSheetAnalInferenceEntity;
import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetAnalSttcEntity.mapSheetAnalSttcEntity;
import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetLearnEntity.mapSheetLearnEntity;
import static com.kamco.cd.kamcoback.postgres.entity.QPnuEntity.pnuEntity;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.kamco.cd.kamcoback.changedetection.dto.ChangeDetectionDto;
import com.kamco.cd.kamcoback.changedetection.dto.ChangeDetectionDto.ChangeDetectionMapDto;
import com.kamco.cd.kamcoback.changedetection.dto.ChangeDetectionDto.DetectSearchType;
import com.kamco.cd.kamcoback.changedetection.dto.ChangeDetectionDto.MapScaleType;
import com.kamco.cd.kamcoback.changedetection.dto.ChangeDetectionDto.MapSheetList;
import com.kamco.cd.kamcoback.changedetection.dto.ChangeDetectionDto.PointFeatureList;
import com.kamco.cd.kamcoback.changedetection.dto.ChangeDetectionDto.PolygonFeatureList;
import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.Status;
import com.kamco.cd.kamcoback.postgres.entity.MapSheetAnalDataInferenceGeomEntity;
import com.kamco.cd.kamcoback.postgres.entity.QMapSheetAnalDataInferenceEntity;
@@ -32,7 +34,6 @@ import com.querydsl.jpa.JPAExpressions;
import com.querydsl.jpa.impl.JPAQueryFactory;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;
import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport;
@@ -378,22 +379,255 @@ public class ChangeDetectionRepositoryImpl extends QuerydslRepositorySupport
}
@Override
public Optional<UUID> getChangeDetectionUuid(ChangeDetectionMapDto req) {
public PolygonFeatureList getPolygonListByCd(
String chnDtctId, String cdObjectId, List<String> cdObjectIds) {
BooleanBuilder builder = new BooleanBuilder();
builder.and(mapSheetAnalInferenceEntity.stage.isNotNull());
builder.and(mapSheetAnalInferenceEntity.compareYyyy.eq(req.getCompareYyyy()));
builder.and(mapSheetAnalInferenceEntity.targetYyyy.eq(req.getTargetYyyy()));
builder.and(mapSheetLearnEntity.uid.eq(chnDtctId));
builder.and(
mapSheetAnalDataInferenceGeomEntity
.resultUid
.eq(chnDtctId)
.or(mapSheetAnalDataInferenceGeomEntity.resultUid.in(cdObjectIds)));
return Optional.ofNullable(
List<ChangeDetectionDto.PolygonQueryData> list =
queryFactory
.select(mapSheetAnalInferenceEntity.uuid)
.from(mapSheetAnalInferenceEntity)
.select(
Projections.constructor(
ChangeDetectionDto.PolygonQueryData.class,
Expressions.stringTemplate("{0}", "Feature"),
Expressions.stringTemplate(
"ST_AsGeoJSON({0})", mapSheetAnalDataInferenceGeomEntity.geom),
mapSheetAnalDataInferenceGeomEntity.geoUid,
mapSheetAnalDataInferenceGeomEntity.area,
mapSheetAnalDataInferenceGeomEntity.compareYyyy,
mapSheetAnalDataInferenceGeomEntity.classBeforeProb,
mapSheetAnalDataInferenceGeomEntity.classBeforeCd.toUpperCase(),
mapSheetAnalDataInferenceGeomEntity.targetYyyy,
mapSheetAnalDataInferenceGeomEntity.classAfterProb,
mapSheetAnalDataInferenceGeomEntity.classAfterCd.toUpperCase(),
mapSheetAnalDataInferenceGeomEntity.cdProb))
.from(mapSheetAnalDataInferenceGeomEntity)
.innerJoin(mapSheetAnalDataInferenceEntity)
.on(mapSheetAnalDataInferenceGeomEntity.dataUid.eq(mapSheetAnalDataInferenceEntity.id))
.innerJoin(mapSheetAnalInferenceEntity)
.on(mapSheetAnalInferenceEntity.id.eq(mapSheetAnalDataInferenceEntity.analUid))
.innerJoin(mapSheetLearnEntity)
.on(mapSheetLearnEntity.id.eq(mapSheetAnalInferenceEntity.learnId))
.where(builder)
.groupBy(mapSheetAnalInferenceEntity.uuid, mapSheetAnalInferenceEntity.stage)
.orderBy(mapSheetAnalInferenceEntity.stage.desc())
.limit(1)
.fetchOne());
.orderBy(mapSheetAnalDataInferenceGeomEntity.mapSheetNum.asc())
.fetch();
ObjectMapper mapper = new ObjectMapper();
List<ChangeDetectionDto.PolygonFeature> result =
list.stream()
.map(
data -> {
String geoJson = data.getGeometry();
JsonNode jsonNode;
try {
jsonNode = mapper.readTree(geoJson);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
ChangeDetectionDto.PolygonProperties properties =
new ChangeDetectionDto.PolygonProperties(
data.getGeoUid(),
data.getArea(),
data.getBeforeYear(),
data.getBeforeConfidence(),
data.getBeforeClass(),
data.getAfterYear(),
data.getAfterConfidence(),
data.getAfterClass(),
data.getCdProb());
return new ChangeDetectionDto.PolygonFeature(
data.getType(), jsonNode, properties);
})
.collect(Collectors.toList());
ChangeDetectionDto.PolygonFeatureList polygonList = new ChangeDetectionDto.PolygonFeatureList();
polygonList.setType("FeatureCollection");
polygonList.setFeatures(result);
return polygonList;
}
@Override
public PointFeatureList getPointListByCd(
String chnDtctId, String cdObjectId, List<String> cdObjectIds) {
BooleanBuilder builder = new BooleanBuilder();
builder.and(mapSheetLearnEntity.uid.eq(chnDtctId));
builder.and(
mapSheetAnalDataInferenceGeomEntity
.resultUid
.eq(chnDtctId)
.or(mapSheetAnalDataInferenceGeomEntity.resultUid.in(cdObjectIds)));
List<ChangeDetectionDto.PointQueryData> list =
queryFactory
.select(
Projections.constructor(
ChangeDetectionDto.PointQueryData.class,
Expressions.stringTemplate("{0}", "Feature"),
Expressions.stringTemplate(
"ST_AsGeoJSON({0})",
mapSheetAnalDataInferenceGeomEntity.geomCenter), // point
Projections.constructor(
ChangeDetectionDto.PointProperties.class,
mapSheetAnalDataInferenceGeomEntity.geoUid,
mapSheetAnalDataInferenceGeomEntity.classAfterCd.toUpperCase())))
.from(mapSheetAnalDataInferenceGeomEntity)
.innerJoin(mapSheetAnalDataInferenceEntity)
.on(mapSheetAnalDataInferenceGeomEntity.dataUid.eq(mapSheetAnalDataInferenceEntity.id))
.innerJoin(mapSheetAnalInferenceEntity)
.on(mapSheetAnalInferenceEntity.id.eq(mapSheetAnalDataInferenceEntity.analUid))
.innerJoin(mapSheetLearnEntity)
.on(mapSheetLearnEntity.id.eq(mapSheetAnalInferenceEntity.learnId))
.where(builder)
.fetch();
ObjectMapper mapper = new ObjectMapper();
List<ChangeDetectionDto.PointFeature> result =
list.stream()
.map(
data -> {
String geoJson = data.getGeometry();
JsonNode jsonNode;
try {
jsonNode = mapper.readTree(geoJson);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
return new ChangeDetectionDto.PointFeature(
data.getType(), jsonNode, data.getProperties());
})
.collect(Collectors.toList());
return new ChangeDetectionDto.PointFeatureList("FeatureCollection", result);
}
@Override
public PolygonFeatureList getSelectedChangeDetectionPolygonListByPnu(
String chnDtctId, String pnu) {
BooleanBuilder builder = new BooleanBuilder();
builder.and(mapSheetLearnEntity.uid.eq(chnDtctId));
builder.and(pnuEntity.pnu.eq(pnu));
List<ChangeDetectionDto.PolygonQueryData> list =
queryFactory
.select(
Projections.constructor(
ChangeDetectionDto.PolygonQueryData.class,
Expressions.stringTemplate("{0}", "Feature"),
Expressions.stringTemplate(
"ST_AsGeoJSON({0})", mapSheetAnalDataInferenceGeomEntity.geom),
mapSheetAnalDataInferenceGeomEntity.geoUid,
mapSheetAnalDataInferenceGeomEntity.area,
mapSheetAnalDataInferenceGeomEntity.compareYyyy,
mapSheetAnalDataInferenceGeomEntity.classBeforeProb,
mapSheetAnalDataInferenceGeomEntity.classBeforeCd.toUpperCase(),
mapSheetAnalDataInferenceGeomEntity.targetYyyy,
mapSheetAnalDataInferenceGeomEntity.classAfterProb,
mapSheetAnalDataInferenceGeomEntity.classAfterCd.toUpperCase(),
mapSheetAnalDataInferenceGeomEntity.cdProb))
.from(mapSheetAnalDataInferenceGeomEntity)
.innerJoin(mapSheetAnalDataInferenceEntity)
.on(mapSheetAnalDataInferenceGeomEntity.dataUid.eq(mapSheetAnalDataInferenceEntity.id))
.innerJoin(mapSheetAnalInferenceEntity)
.on(mapSheetAnalInferenceEntity.id.eq(mapSheetAnalDataInferenceEntity.analUid))
.innerJoin(mapSheetLearnEntity)
.on(mapSheetLearnEntity.id.eq(mapSheetAnalInferenceEntity.learnId))
.innerJoin(pnuEntity.geo, mapSheetAnalDataInferenceGeomEntity)
.where(builder)
.orderBy(mapSheetAnalDataInferenceGeomEntity.mapSheetNum.asc())
.fetch();
ObjectMapper mapper = new ObjectMapper();
List<ChangeDetectionDto.PolygonFeature> result =
list.stream()
.map(
data -> {
String geoJson = data.getGeometry();
JsonNode jsonNode;
try {
jsonNode = mapper.readTree(geoJson);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
ChangeDetectionDto.PolygonProperties properties =
new ChangeDetectionDto.PolygonProperties(
data.getGeoUid(),
data.getArea(),
data.getBeforeYear(),
data.getBeforeConfidence(),
data.getBeforeClass(),
data.getAfterYear(),
data.getAfterConfidence(),
data.getAfterClass(),
data.getCdProb());
return new ChangeDetectionDto.PolygonFeature(
data.getType(), jsonNode, properties);
})
.collect(Collectors.toList());
ChangeDetectionDto.PolygonFeatureList polygonList = new ChangeDetectionDto.PolygonFeatureList();
polygonList.setType("FeatureCollection");
polygonList.setFeatures(result);
return polygonList;
}
@Override
public PointFeatureList getSelectedChangeDetectionPointListByPnu(String chnDtctId, String pnu) {
BooleanBuilder builder = new BooleanBuilder();
builder.and(mapSheetLearnEntity.uid.eq(chnDtctId));
builder.and(pnuEntity.pnu.eq(pnu));
List<ChangeDetectionDto.PointQueryData> list =
queryFactory
.select(
Projections.constructor(
ChangeDetectionDto.PointQueryData.class,
Expressions.stringTemplate("{0}", "Feature"),
Expressions.stringTemplate(
"ST_AsGeoJSON({0})",
mapSheetAnalDataInferenceGeomEntity.geomCenter), // point
Projections.constructor(
ChangeDetectionDto.PointProperties.class,
mapSheetAnalDataInferenceGeomEntity.geoUid,
mapSheetAnalDataInferenceGeomEntity.classAfterCd.toUpperCase())))
.from(mapSheetAnalDataInferenceGeomEntity)
.innerJoin(mapSheetAnalDataInferenceEntity)
.on(mapSheetAnalDataInferenceGeomEntity.dataUid.eq(mapSheetAnalDataInferenceEntity.id))
.innerJoin(mapSheetAnalInferenceEntity)
.on(mapSheetAnalInferenceEntity.id.eq(mapSheetAnalDataInferenceEntity.analUid))
.innerJoin(mapSheetLearnEntity)
.on(mapSheetLearnEntity.id.eq(mapSheetAnalInferenceEntity.learnId))
.innerJoin(pnuEntity.geo, mapSheetAnalDataInferenceGeomEntity)
.where(builder)
.fetch();
ObjectMapper mapper = new ObjectMapper();
List<ChangeDetectionDto.PointFeature> result =
list.stream()
.map(
data -> {
String geoJson = data.getGeometry();
JsonNode jsonNode;
try {
jsonNode = mapper.readTree(geoJson);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
return new ChangeDetectionDto.PointFeature(
data.getType(), jsonNode, data.getProperties());
})
.collect(Collectors.toList());
return new ChangeDetectionDto.PointFeatureList("FeatureCollection", result);
}
}