일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- android studio
- macos
- ffmpeg
- golang
- kubectl
- service
- 행정구역분류
- namespace
- HLS
- dart
- aws
- deployment
- Android
- configmap
- Pod
- Windows10
- spring cloud config
- docker
- nginx-media-server
- wireshark
- VSCode
- Shell script
- Kubernetes
- Python
- aws cli
- Java
- ebpf
- RTMP
- Sysinternals
- Flutter
- Today
- Total
woonizzooni
대한민국 행정동 경계 좌표 추출 #3 - java > GeoJSON 본문
이전 게시물 참고.
1. QGiS이용
2. python이용
이번에는 java코드로 shapefile에서 GeoJson형식으로 좌표 추출 시도.
o 빌드 & 실행 환경 구성
geotools를 이용할 건데, 우선 아래 내용 참고해서 실행 환경 구성.
https://docs.geotools.org/latest/userguide/tutorial/quickstart/
현재 편의상 eclipse, maven을 활용해본다. 아래는 내 pom.xml설정 상태.
<dependencies>
...
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-shapefile</artifactId>
<version>${geotools.version}</version>
</dependency>
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-swing</artifactId>
<version>${geotools.version}</version>
</dependency>
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-opengis</artifactId>
<version>${geotools.version}</version>
</dependency>
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-geojson</artifactId>
<version>${geotools.version}</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>maven2-repository.dev.java.net</id>
<name>Java.net repository</name>
<url>http://download.java.net/maven/2</url>
</repository>
<repository>
<id>osgeo</id>
<name>Open Source Geospatial Foundation Repository</name>
<url>http://download.osgeo.org/webdav/geotools/</url>
</repository>
<repository>
<snapshots>
<enabled>true</enabled>
</snapshots>
<id>boundless</id>
<name>Boundless Maven Repository</name>
<url>http://repo.boundlessgeo.com/main</url>
</repository>
</repositories>
o 코드 작성
- geotools 중 'GeoJSON Plugin' 사용. 다만 이 플러그인이 'Unsupported'로 분류되어 있음을 기억해두고..
private static String filename = "E:\\Z_SOP_BND_ADM_DONG_PG\\Z_SOP_BND_ADM_DONG_PG.shp";
public static void main(String[] args) {
try {
File shpfile = new File(filename);
// DataStore & FeatureSource 접근 방법 1
/*
ShapefileDataStore dataStore = new ShapefileDataStore(shpFile.toURI().toURL());
dataStore.setCharset(Charset.forName("euc-kr"));
SimpleFeatureSource featureSource = dataStore.getFeatureSource();
*/
// DataStore & DataSource 접근 방법 2
Map<String, String> params = new HashMap<String, String>();
params.put("url", shpfile.toURI().toString());
params.put("charset", "euc-kr");
DataStore dataStore = DataStoreFinder.getDataStore(params);
String[] typeNames = dataStore.getTypeNames();
SimpleFeatureSource featureSource = dataStore.getFeatureSource(typeNames[0]);
// featureCollection 접근 & geojson 인코딩
SimpleFeatureCollection featureCollection = featureSource.getFeatures();
FeatureJSON featureJson = new FeatureJSON();
StringWriter writer = new StringWriter();
featureJson.writeFeatureCollection(featureCollection, writer);
// json 출력
//String geoJson = writer.toString();
//System.out.println(geoJson);
String geoJsonFile = "E:\\Z_SOP_BND_ADM_DONG_PG\\Z_SOP_BND_ADM_DONG_PG.geojson";
FileWriter fw = new FileWriter(geoJsonFile);
fw.write(writer.toString());
fw.flush();
fw.close();
} catch (Throwable e) {
}
}
- 정보 가공이 필요할 경우 대략 아래 클래스를 참고해서 수정해보면 되겠다.
아래는 geometry와 feature properties의 파라미터 추가 & 위치 변경 예.
org.geotools.geojson.feature.FeatureJSON.class
class FeatureCollectionEncoder
class FeatureEncoder
public void writeFeatureCollection(FeatureCollection features, Object output) throws IOException {
Map<String, Object> obj = new LinkedHashMap<String, Object>();
// type : FeatureCollection
obj.put("type", "FeatureCollection");
// crs : {}
if (features.getSchema().getGeometryDescriptor() != null) {
final ReferencedEnvelope bounds = features.getBounds();
final CoordinateReferenceSystem crs = (bounds != null) ? bounds.getCoordinateReferenceSystem() : null;
if (!isStandardCRS(crs)) {
obj.put("crs", createCRS(crs));
}
}
// features : []
obj.put("features", new FeatureCollectionEncoder(features, gjson));
GeoJSONUtil.encode(obj, output);
}
Map<String, Object> createCRS(CoordinateReferenceSystem crs) throws IOException {
Map<String, Object> obj = new LinkedHashMap<String, Object>();
obj.put("type", "name");
Map<String, Object> props = new LinkedHashMap<String, Object>();
if (crs == null) {
props.put("name", "EPSG:4326");
} else {
try {
String identifier = CRS.lookupIdentifier(crs, true);
props.put("name", identifier);
} catch (FactoryException e) {
throw (IOException) new IOException("Error looking up crs identifier").initCause(e);
}
}
obj.put("properties", props);
return obj;
}
class FeatureEncoder implements JSONAware {
SimpleFeatureType featureType;
SimpleFeature feature;
int featureSeq = 0;
public FeatureEncoder(SimpleFeature feature) {
this(feature.getType());
this.feature = feature;
}
public FeatureEncoder(SimpleFeatureType featureType) {
this.featureType = featureType;
}
public String toJSONString(SimpleFeature feature) {
StringBuilder sb = new StringBuilder();
sb.append("{");
// type ----------------------------
entry("type", "Feature", sb);
sb.append(",");
// properties ----------------------------
int gindex =
featureType.getGeometryDescriptor() != null
? featureType.indexOf(
featureType.getGeometryDescriptor().getLocalName())
: -1;
string("properties", sb).append(":").append("{");
string("objectid", sb).append(":").append(Integer.toString(++this.featureSeq)).append(",");
boolean attributesWritten = false;
for (int i = 0; i < featureType.getAttributeCount(); i++) {
AttributeDescriptor ad = featureType.getDescriptor(i);
// skip the default geometry, it's already encoded
if (i == gindex) {
continue;
}
Object value = feature.getAttribute(i);
if (value == null) {
// skip
continue;
}
attributesWritten = true;
// handle special types separately, everything else as a string or literal
if (value instanceof Envelope) {
array(ad.getLocalName(), gjson.toString((Envelope) value), sb);
} else if (value instanceof BoundingBox) {
array(ad.getLocalName(), gjson.toString((BoundingBox) value), sb);
} else if (value instanceof Geometry) {
string(ad.getLocalName(), sb)
.append(":")
.append(gjson.toString((Geometry) value));
} else {
// ad.getLocalName().toLowerCase()
// base_year : 기준년도
// adm_dr_cd : 행정동코드
// adm_dr_nm : 행정동명
entry(ad.getLocalName().toLowerCase(), value, sb);
}
sb.append(",");
}
if (attributesWritten) {
sb.setLength(sb.length() - 1);
}
sb.append("},");
// geometry : 공간정보 (Polygon, MultiPolygon) ----------------------------
if (feature.getDefaultGeometry() != null) {
string("geometry", sb)
.append(":")
.append(gjson.toString((Geometry) feature.getDefaultGeometry()));
}
sb.append("}");
return sb.toString();
}
public String toJSONString() {
return toJSONString(feature);
}
}
org.geotools.geojson.geom.GeometryJSON.class
.createPoint() : Polygon, MultiPolygon등 geometry 유형별
static class CoordinateSequenceEncoder.class : coordinates 인코더
org.geotools.geojson.geom.GeometryJSON.class
.toString(geometry)
.write()
.create(geometry)
.createPolygon(), createMultiPolygon()...
.toList(GeometryCollectino)
CoordinateSequenceEncoder.class <-- geometry 인코딩부
org.geotools.geojson.GeoJSONUtil.class
.encode()
o 결과
- 음.. 일단 이상한건(?) 사직동이 QGiS툴, java에서는 MultiPolygon으로, python으로는 Polygon으로 인식된다. -_-
{
"type": "FeatureCollection",
"crs": {
"type": "name",
"properties": {
"name": "CRS:84"
}
},
"features": [
{
"type": "Feature",
"properties": {
"objectid": 1,
"base_year": "2018",
"adm_dr_cd": "1101053",
"adm_dr_nm": "사직동"
},
"geometry": {
"type": "MultiPolygon",
"coordinates": [
[
[
[
126.9689,
37.5781
],
[
126.969,
37.5779
],
[
126.9692,
37.5779
],
[
126.9692,
37.578
],
[
126.9692,
37.578
],
[
126.9692,
이제 '이 내용' 에 위 geometry만 DB에 넣으면
시도/시군구/법정동/행정동 기준의 geocoding, reverse geocoding API 구현을 위한
백데이터를 마련했다고 볼 수 있겠다. 아직 안해봤으니 일단 대충만이라도.... 흠.
[참고]
GeoTools
https://github.com/geotools/geotools
https://docs.geotools.org/latest/javadocs/
User Guide
https://docs.geotools.org/latest/userguide/
Data - DataStore plugins: Shaperfile Plugin > Connection Parameters, Reading DBF
https://docs.geotools.org/stable/userguide/library/data/
Main - Contents : FeatureCollection
https://docs.geotools.org/latest/userguide/library/main/
Unsupported Module
https://docs.geotools.org/latest/userguide/unsupported/
'Programming > Java' 카테고리의 다른 글
Java Decompiler 종류 (0) | 2019.08.25 |
---|---|
IPv4 네트워크 접두어 길이 구하기 = CIDR Prefix Length 구하기 (0) | 2019.06.13 |
java tip : 파일을 가장 빨리 읽는 방법 / 효과적인 방법 (0) | 2019.06.13 |
Java 버전별 내용 참고 (0) | 2019.06.13 |