Blender Modeling Tip : “방망이 깍던 노인”

모델링 잘하는 분의 영상을 보고 모델링 연습 중인데.. 그 사람의 영상을 보면서 “이 정도면 된거 같은데?”라고 생각 중에 아직 영상의 반절 밖에 지나지 않았다. 시작했던 것이니 끝까지 봐야지 싶어 보던차에 “이 사람은 이걸 어떻게 알고 이렇게 한거지..?”라는 생각이 든다. 이건 배운게 아니고 오랜 경험을 통해 느끼고 스스로 터득한 것 같다라는 생각이 든다. 마지막까지 따라하며 아까보다 아주 조금 더 나은 결과물을 보고 미세해서 눈에 보이지 않는 것들이 더욱 눈이 들어오는 것 같다. 문득 중학교인가 고등학교 때인가 교과서에서 봤던 “방망이 깍던 노인”이라는 수필이 생각났다. AI 시대에 프롬프트로 제대로 지시만 내려주면 3차원 모델도 만들어 주는 시대다. 이런 시대에 방망이 깍던 노인처럼 꼭 이렇게 모델링을 해야 하나 싶기도 하다. 모르겠다… 여튼 아래는 그 결과

FingerEyes-Xr에서 JSTS를 사용한 쓰는 코드 정리

FingerEyes-Xr은 JS 기반의 맵엔진이고 JSTS는 JS 기반의 지오메트리 연산 라이브러리입니다.

웹브라우저에서 공간 데이터에 대한 처리를 수행하는 경우에 JSTS를 사용하면 매우 좋은데요. 오래전부터 1.9버전을 사용하고 있었는데 오늘 보니 JSTS가 2.9.3 버전까지 올라왔군요.

JSTS에 대한 코드만을 뽑아 정리하기가 버겨워…. 대충 언급하여 정리해 봅니다. 아래 코드의 목적은 중첩되는 공간 데이터에 대한 헥사곤 도형을 생성해 주는 것입니다.

#run() {
  const selectLayers = this.#dialog.content.querySelector(".input-layer")
  const radius = parseFloat(this.#dialog.content.querySelector(".radius").value)
  const layerName = selectLayers.value
  const layer = app.map.layers().layer(layerName)
  const mbrLayer = layer.MBR()

  // MBR의 좌표계를 배경지도에 대한 좌표계로 변경함
  const proj = layer.EPSG() === -1 ? null : proj4(layer.proj4Name(), 'EPSG:' + layer.EPSG());
  const [minX, minY] = proj ? proj.forward([mbrLayer.minX, mbrLayer.minY]) : [mbrLayer.minX, mbrLayer.minY];
  let [maxX, maxY] = proj ? proj.forward([mbrLayer.maxX, mbrLayer.maxY]) : [mbrLayer.maxX, mbrLayer.maxY];
  maxX += radius*2
  maxY += radius*2

  const xStep = radius + radius/2
  const yStep = radius * Math.sin(60*(Math.PI/180)) * 2
  const gl = new Xr.layers.GraphicLayer("gl")
  app.map.layers().add(gl)

  const cntRows = layer.totalRowsCount();
  const wktReader = new jsts.io.WKTReader()

  for(let y=minY; y<maxY; y+=yStep) {
    for(let cx=minX; cx<maxX; cx+=xStep) {  
      ...
      const pts = [[ /* Hexagon 도형 구성 좌표 만드는 코드 */ ]]

      const psd = new Xr.data.PolygonShapeData(pts)
      const pgr = new Xr.data.PolygonGraphicRow(count, psd)

      const geomHexa = wktReader.read(psd.toWKT(false))   
      let intersected = false
      for(let i=0; i<cntRows; i++) {
        const shapeRow = layer.getShapeByFID(i)
        const geom = wktReader.read(shapeRow.shapeData().toWKT(true))   
        if(geom.intersects(geomHexa)) {
          intersected = true
          break
        }
      }
  
      if(intersected) gl.rowSet().add(pgr)
    }
  }

  app.map.update()
}

JSTS에 대한 주요 코드는 21번, 31/35번, 36번인데요. 각각 jsts.io.WKTReader 객체 준비, WKT로부터 JSTS를 위한 지오메트리 객체를 생성, 중첩 여부 확인 코드입니다. 참고로 위의 코드는 다음과 같은 결과를 만들어 냅니다.

Blender Modeling Tip : 빠르게 면 채우기

위의 그림을 보면 뚫린 곳이 있는데 먼저 2개의 정점이 선택된 상태입니다. 이 상태에서 F키를 입력하면 면이 채워(Fill)집니다. F키를 연속으로 누르면 자동으로 인접한 면이 채워집니다. 아래는 그 결과입니다.

Blender Modeling Tip : N-Gon 만 선택하기

면을 선택하는 것이므로 편집 모드에서 Face 선택 모드로 하고 [Select]-[Select All By Trait]-[Faces By Sides]를 실행합니다. 4개보다 더 많은 정점으로 구성된 면인 N-Gon을 선택해야 하므로 Number of Vertices를 4로, Type을 Greater Than으로 선택하면 N-Gon만이 선택됩니다.