SHP 파일은 GIS 공간 자료에서 유명한 표준 포맷 중에 하나 입니다.
이 파일이 중요한 점은 지도를 저장 할 수 있다고 간단히 생각하면 됩니다.
그런데 프로그램을 만들다 보면 이런 문제가 생길수 있습니다.
- 기존 지도 데이터를 신규로 교체해야 하는 경우
- 특정 영역에 있는 지도 데이터를 삭제 해야 하는 경우
- 특정 영역에 있는 지도 데이터를 비교 해야 하는 경우
등등의 여러가지 경우가 있을 수 있을 것 같은 데요.
그럴때 우리는 공간 연산 즉 지도 안의 데이터들을 비교 하여 원하는 데이터를 먼저 얻어 내야 하는 것이죠.
여기서는 특정 영역 안에 존재하는 지도 데이터와 이렇게 찾은 지도 데이터와 기존 데이터를 비교 하는 것 등등을 말할 수 있죠.
그리고 여기서 말하는 지도 데이터는 공간자료 즉 피처를 얘기 하고 있습니다.
이렇때 일반적으로 많이 쓰는 툴들이 존해 합니다. 상용도 있고, 프리도 있고, 오픈 소스도 있습니다.
오픈소스 GIS 연산이 필요 할 때, 자바에서는 geotools를 자주 애용(?) 하고 았습니다.
위의 글의 내용을 번역해 보면 다음과 같은 질문과 채택된 답면의 내용입니다.
GeoTools에서 두 개의 shapefile(레이어)을 비교하여 MapContent 객체의 피처(공간자료)들의 차이점 표현하기
GIS 기능을 구현하기 위해 GeoTools 라이브러리로 작업을 진행 중입니다. 저는 SHP 파일 두개를 가지고 있고 두 SHP 파일의 차이점을 포함하는 별도의 새 레이어를 생성하려고 합니다. 이 새 레이어는 두 개의 입력 shp 파일 중 하나에 있는 추가 피처를 보여 줘야 합니다.
화면에서 polygon2.shp와 polygon1.shp의 차이에 대한 새 레이어를 생성합니다.
GeoTools 라이브러리에 두 레이어의 shapefile에 대한 차이점을 가져 올 수 있는 특정 방법이 있을까요?
답변>
코멘트를 통해서 이야기 하였듯이, QGIS 코드를 이해 한다면 이 부분은 상당히 간단한 알고리즘입니다.
- 첫 번째 피처 컬렉션을 통해 순환한다.
- 현재 피처와 교차하는 두 번째 컬렉션의 지오메트리를 찾습니다.
- 이 피처들을 합치고(둘 이상인 경우) 첫 번째 피처에서 그 합집합을 빼줍니다(차이).
- 결과를 저장합니다.
public static SimpleFeatureCollection difference(SimpleFeatureCollection collA, SimpleFeatureCollection collB)
{
SimpleFeatureBuilder builder = new SimpleFeatureBuilder(collA.getSchema());
List<SimpleFeature> ret = new ArrayList<>();
FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2(GeoTools.getDefaultHints());
try (SimpleFeatureIterator itr = collA.features())
{
while (itr.hasNext())
{
SimpleFeature f = itr.next();
Geometry geom = (Geometry) f.getDefaultGeometry();
Filter filter = ff.intersects(ff.property(collB.getSchema().getGeometryDescriptor().getLocalName()),
ff.literal(geom));
SimpleFeatureCollection sub = collB.subCollection(filter);
if (!sub.isEmpty())
{
// union the geometries that overlap
Geometry result = null;
try (SimpleFeatureIterator itr2 = sub.features())
{
while (itr2.hasNext())
{
SimpleFeature f2 = itr2.next();
Geometry geom2 = (Geometry) f2.getDefaultGeometry();
if (result == null)
{
result = geom2;
} else {
result = result.union(geom2);
}
}
}
if (result.isValid() && geom.isValid()) {
// calc difference
Geometry g = geom.difference(result);
builder.addAll(f.getAttributes());
String geomName = collA.getSchema().getGeometryDescriptor().getLocalName();
builder.set(geomName, g);
SimpleFeature fout = builder.buildFeature(null);
ret.add(fout);
}
else
{
if (!result.isValid()) {
System.out.println("Invalid result");
System.out.println(result);
}
if (!geom.isValid()) {
System.out.println("Invalid geom");
System.out.println(geom);
}
}
}
else
{// no intersection
ret.add(f);
}
}
}
return DataUtilities.collection(ret);
}
실제로 GeoTools는 자신만의 인덱스 등을 생성할 필요가 없기 때문에 QGIS보다 훨씬 더 쉽습니다.
Natural Earth 지역과와 호수 레이어를 구분 해 보았습니다(인도는 무시 했는데, 잘못된 폴리곤이므로 수정할 수 없습니다).
코드는 오류가 약간 있어서 수정 하였습니다...
이상.
'프로그래밍 > GIS' 카테고리의 다른 글
톰캣 카카오 맵 API 사용하기 (0) | 2024.01.29 |
---|---|
JMapViewer - 오픈스트리트 지도뷰어 (1) | 2024.01.26 |
[C/C++] GIS 따라해보기 – gdal/GEOS SHP 파일 조작 (0) | 2023.01.01 |
당신이 알아두어야 할 GIS 프로그래밍 언어들 (0) | 2022.12.31 |
상용 및 오픈 소스 GIS 소프트웨어의 10 가지 차이점 (0) | 2022.12.30 |