Rust 개발 환경 구성

VS.Code를 이용하므로 이 사이트에서 Rust 개발환경 구성을 참조하였음.

매우 간단한데 rustup-init.exe를 다운로드 받아 실행시키면 콘솔에서 설치가 진행됨. Rust 컴파일러와 Cargo 실행 파일 등이 최신 버전으로 설치가 되며 Path까지 잡아줌. 나중에 Uninstall은 어찌하라는 것인지… 그냥 폴더와 Path 잡힌 것만 제거하면 되는 것인가? VS.Code에서 확장은 rust-analyzer와 CodeLLDB를 설치해주면 됨. 각각 코드 하일라이팅 등의 기능 제공과 디버깅 기능을 제공함.

Rust 프로젝트를 하나 생성하기 위해서는 콘설에서 다음 코드를 실행하면 됨. 원하는 폴더에서 아래 명령을 실행하면 hello_world라는 폴더가 만들어지고 필요한 파일도 생성됨.

cargo new hello_world

VS.Code를 실행하고 hello_world 폴더를 열면 됨. 그리고 컴파일은 VS.Code의 Shell에서 다음 명령을 실행하면 됨. 아래 명령을 통해 실행 파일이 만들어짐.

cargo build

컴파일과 함께 실행을 동시에 하고 싶다면 다음 명령.

cargo run

물론 VS.Code에서도 그냥 실행이 가능하고 라인 단위 디버깅도 가능함. (단, launch.json 파일 생성이 필요하고 앞서 언급한 CodeLLDB 확장 기능 설치가 필요함.

pyQGIS를 이용한 벡터 데이터 처리 5 : 피쳐 선택하고 저장하기

가장 먼저 피쳐의 ID 값으로 선택하는 코드입니다.

QgsProject.instance().removeAllMapLayers()
layer = QgsVectorLayer("D:/__Data__/세종특별자치시_36000/TL_SPRD_MANAGE.shp", "TL_SPRD_MANAGE", "ogr")
QgsProject.instance().addMapLayers([layer])

selectid = [0, 1, 2, 3, 4]
layer.select(selectid)

아래는 선택된 피쳐를 순회하는 코드입니다.

QgsProject.instance().removeAllMapLayers()
layer = QgsVectorLayer("D:/__Data__/세종특별자치시_36000/TL_SPRD_MANAGE.shp", "TL_SPRD_MANAGE", "ogr")
QgsProject.instance().addMapLayers([layer])

selectid = [0, 1, 2, 3, 4]
layer.select(selectid)
QgsProject.instance().removeAllMapLayers()
layer = QgsVectorLayer("D:/__Data__/세종특별자치시_36000/TL_SPRD_MANAGE.shp", "TL_SPRD_MANAGE", "ogr")
QgsProject.instance().addMapLayers([layer])

selectid = [0, 1, 2, 3, 4]
layer.select(selectid)

selection = layer.selectedFeatures()
for feat in selection:
    print(feat['RN'])

다음은 SQL의 Where 조건 형태의 조건으로 피쳐를 선택하고 선택된 피쳐만을 새로운 SHP 파일로 저장하는 코드입니다.

QgsProject.instance().removeAllMapLayers()

layer = QgsVectorLayer("D:/__Data__/세종특별자치시_36000/TL_SPRD_MANAGE.shp", "TL_SPRD_MANAGE", "ogr")
QgsProject.instance().addMapLayers([layer])
layer.selectByExpression('"RN" like \'%로\'')

fn = "D:/__Data__/aa.shp"
writer = QgsVectorFileWriter.writeAsVectorFormat(layer, fn, 
    "utf-8", 
    driverName="ESRI ShapeFile", 
    onlySelected=True
)

print("DONE")

newLayer = QgsVectorLayer(fn, "aa")
QgsProject.instance().addMapLayers([newLayer])

다음은 사각형 영역을 지정해서 이 영역과 교차하는 피쳐를 선택하는 코드입니다.

QgsProject.instance().removeAllMapLayers()
layer = QgsVectorLayer("D:/__Data__/세종특별자치시_36000/TL_SPRD_MANAGE.shp", "TL_SPRD_MANAGE", "ogr")
QgsProject.instance().addMapLayers([layer])

areaOfInterest = QgsRectangle(982413, 1835226, 987413, 1840226)
request = QgsFeatureRequest().setFilterRect(areaOfInterest)

selected = []

for feature in layer.getFeatures(request):
    selected.append(feature.id())
    
layer.select(selected)

pyQGIS를 이용한 벡터 데이터 처리 4 : 스타일 심벌 및 라벨 지정하기

추가한 벡터 레이어에 대한 그리기 스타일을 심벌이라고 하는데, 이 심벌은 매우 다양합니다. 먼저 전체 도형을 하나의 심벌로 지정하는 코드는 다음과 같습니다.

QgsProject.instance().removeAllMapLayers()

layer = QgsVectorLayer("D:/__Data__/세종특별자치시_36000/TL_SPRD_MANAGE.shp", "TL_SPRD_MANAGE", "ogr")
QgsProject.instance().addMapLayers([layer])

symbol = QgsLineSymbol.createSimple({"line_style":"solid", "color": "red", "width": "0.5"})
layer.renderer().setSymbol(symbol)
layer.triggerRepaint()

선 스타일은 Solid이고 색상은 red, 굵기는 0.5로 지정했으며 결과는 다음과 같습니다.

다음은 특정 필드의 값에 대한 범위에 따라 심벌을 다르게 설정하는 코드입니다.

QgsProject.instance().removeAllMapLayers()

layer = QgsVectorLayer("D:/__Data__/세종특별자치시_36000/TL_SPRD_MANAGE.shp", "TL_SPRD_MANAGE", "ogr")
QgsProject.instance().addMapLayers([layer])

for field in layer.fields():
    print(field.name())
    
field = "ROAD_BT"

def createRendererRange(layer, label, minV, maxV, color, opacity, width):
    color = QColor(color)
    symbol = QgsSymbol.defaultSymbol(layer.geometryType())
    symbol.setColor(color)
    symbol.setOpacity(1)
    symbol.setWidth(width)
    range = QgsRendererRange(minV, maxV, symbol, label)
    return range

rangeList = [
    createRendererRange(layer, "Group1", 0.0, 10, "#aaaaaa", 1, 0.2),
    createRendererRange(layer, "Group2", 10, 20, "#00ff00", 0.5, 0.5),
    createRendererRange(layer, "Group3", 20, 30, "#ffff00", 1, 0.5),
    createRendererRange(layer, "Group4", 30, 50, "#ff0000", 0.5, 0.5)
]

groupRenderer = QgsGraduatedSymbolRenderer("", rangeList)
groupRenderer.setMode(QgsGraduatedSymbolRenderer.EqualInterval)
groupRenderer.setClassAttribute(field)
layer.setRenderer(groupRenderer)

ROAD_BT에 대한 필드값을 4개의 구간에 대해 다른 심벌을 지정하고 있으며 그 결과는 다음과 같습니다.

다음은 라벨을 설정하는 코드입니다.

text_format = QgsTextFormat()
text_format.setFont(QFont("Arial"))
text_format.setSize(12)
text_format.setColor(QColor("white"))
buffer_settings = QgsTextBufferSettings()
buffer_settings.setEnabled(True)
buffer_settings.setSize(1)
buffer_settings.setColor(QColor("gray"))
text_format.setBuffer(buffer_settings)

layer_settings = QgsPalLayerSettings()
layer_settings.setFormat(text_format)
layer_settings.fieldName = "name"
layer_settings.placement = QgsPalLayerSettings.Line

label_settings = QgsVectorLayerSimpleLabeling(layer_settings)
layer.setLabelsEnabled(True)
layer.setLabeling(label_settings)
layer.triggerRepaint()

실행 결과는 다음과 같습니다.

pyQGIS를 이용한 벡터 데이터 처리 3 : 속성 및 좌표 얻기

벡터 데이터는 피쳐(Feature)라는 항목들로 구성되며 피쳐는 속성과 좌표로 정의됩니다. 벡터 데이터를 구성하는 피쳐에 대한 속성과 좌표를 얻는 코드를 살펴보겠습니다.

먼저 벡터 데이터의 속성값에 대한 필드 정보는 얻는 코드입니다.

QgsProject.instance().removeAllMapLayers()
layer = QgsVectorLayer("D:/__Data__/세종특별자치시_36000/TL_SPRD_MANAGE.shp", "TL_SPRD_MANAGE", "ogr")
QgsProject.instance().addMapLayers([layer])

for field in layer.fields():
    print(field.name(), field.typeName(), field.length(), field.precision())

실행 결과는 다음과 같습니다.

그리고 모든 피쳐의 각 필드의 값을 얻어오는 코드는 다음과 같습니다.

QgsProject.instance().removeAllMapLayers()

layer = QgsVectorLayer("D:/__Data__/세종특별자치시_36000/TL_SPRD_MANAGE.shp", "TL_SPRD_MANAGE")
QgsProject.instance().addMapLayers([layer])

fieldNames = []
for field in layer.fields():
    fieldNames.append(field.name())

fc = layer.featureCount()
for i in range(0, fc):
    print("\nFID: ", i)
    feature = layer.getFeature(i)
    for fn in fieldNames:
        print(fn, feature[fn])
    
    if i == 5: break

먼저 필드명을 배열에 저장해 두고 각 피쳐에 대해 필드명으로 그 필드값을 얻어올 수 있습니다. 필드명이 아닌 필드의 인덱스 번호로도 필드값을 얻을 수 있습니다. 필드의 인덱스의 시작은 0입니다. 위의 코드에 대한 실행결과는 다음과 같습니다.

다음은 피쳐의 좌표를 얻어오는 코드입니다.

QgsProject.instance().removeAllMapLayers()

layer = QgsVectorLayer("D:/__Data__/세종특별자치시_36000/TL_SPRD_MANAGE.shp", "TL_SPRD_MANAGE")
QgsProject.instance().addMapLayers([layer])

fc = layer.featureCount()
for i in range(0, fc):
    feature = layer.getFeature(i)
    geometry = feature.geometry()
    # print(geometry.asWkt())
    geomSingleType = QgsWkbTypes.isSingleType(geometry.wkbType())
    
    if geometry.type() == QgsWkbTypes.LineGeometry:
        if geomSingleType:
            polyline = geometry.asPolyline()
            print("line:", geom)
        else:
            polyline = geometry.asMultiPolyline()
            print("multiline:", geom)
    
    if i == 5: break

실행결과는 다음과 같습니다.

지오메트리의 좌표를 뽑아내기 위해서는 Multi 여부를 확인해서 형변환(asPolyline, asMultiPolyline 등)이 필요하며 형변환된 객체에 지오메트리의 구성 좌표가 QgsPointXY 타입의 객체들이 배열로 저장됩니다.