[Java]geotools 에서 SHP 파일 비교

2022. 8. 23. 18:51프로그래밍/GIS

728x90

SHP 파일은 GIS 공간 자료에서 유명한 표준 포맷 중에 하나 입니다. 

이 파일이 중요한 점은 지도를 저장 할 수 있다고 간단히 생각하면 됩니다.

 

그런데 프로그램을 만들다 보면 이런 문제가 생길수 있습니다.

  • 기존 지도 데이터를 신규로 교체해야 하는 경우
  • 특정 영역에 있는 지도 데이터를 삭제 해야 하는 경우
  • 특정 영역에 있는 지도 데이터를 비교 해야 하는 경우

등등의 여러가지 경우가 있을 수 있을 것 같은 데요.

그럴때 우리는 공간 연산 즉 지도 안의 데이터들을 비교 하여 원하는 데이터를 먼저 얻어 내야 하는 것이죠.

여기서는 특정 영역 안에 존재하는 지도 데이터와 이렇게 찾은 지도 데이터와 기존 데이터를 비교 하는 것 등등을 말할 수 있죠.

그리고 여기서 말하는 지도 데이터는 공간자료 즉 피처를 얘기 하고 있습니다.

 

이렇때 일반적으로 많이 쓰는 툴들이 존해 합니다. 상용도 있고, 프리도 있고, 오픈 소스도 있습니다.

오픈소스 GIS 연산이 필요 할 때, 자바에서는 geotools를 자주 애용(?) 하고 았습니다.

 

위의 글의 내용을 번역해 보면 다음과 같은 질문과 채택된 답면의 내용입니다.


 

GeoTools에서 두 개의 shapefile(레이어)을 비교하여 MapContent 객체의 피처(공간자료)들의 차이점 표현하기

 

 

Comparing two shapefiles(layers) and display the differences in features in MapContent object in GeoTools

I am working with GeoTools libraries to implement GIS features. Here, I have two different shapefiles and I want to generate a new separate layer containing the differences between the two shape fi...

gis.stackexchange.com

 

GIS 기능을 구현하기 위해 GeoTools 라이브러리로 작업을 진행 중입니다. 저는 SHP 파일 두개를 가지고 있고 두 SHP 파일의 차이점을 포함하는 별도의 새 레이어를 생성하려고 합니다. 이 새 레이어는 두 개의 입력 shp 파일 중 하나에 있는 추가 피처를 보여 줘야 합니다.


화면에서 polygon2.shp와 polygon1.shp의 차이에 대한 새 레이어를 생성합니다.
GeoTools 라이브러리에 두 레이어의 shapefile에 대한 차이점을 가져 올 수 있는 특정 방법이 있을까요?

답변>
코멘트를 통해서 이야기 하였듯이, QGIS 코드를 이해 한다면 이 부분은 상당히 간단한 알고리즘입니다.

  1. 첫 번째 피처 컬렉션을 통해 순환한다.
  2. 현재 피처와 교차하는 두 번째 컬렉션의 지오메트리를 찾습니다.
  3. 이 피처들을 합치고(둘 이상인 경우) 첫 번째 피처에서 그 합집합을 빼줍니다(차이).
  4. 결과를 저장합니다.
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 지역과와 호수 레이어를 구분 해 보았습니다(인도는 무시 했는데, 잘못된 폴리곤이므로 수정할 수 없습니다).

 

Comparing two shapefiles(layers) and display the differences in features in MapContent object in GeoTools

I am working with GeoTools libraries to implement GIS features. Here, I have two different shapefiles and I want to generate a new separate layer containing the differences between the two shape fi...

gis.stackexchange.com


코드는 오류가 약간 있어서 수정 하였습니다...

이상.

 

728x90