QGIS의 가상 레이어를 사용하여 다각형 기능의 정점을 점으로 변환
폴리곤 레이어가 있고 폴리곤 레이어의 꼭지점에서 점을 만드는 가상 레이어를 사용하고 싶습니다. 문제는이를 수행하는 쿼리를 작성하는 방법입니다.
나는 도구를 알고 "Extract vertices"
있지만 내가 찾고있는 것은 아니다.
내가 시도한 것 :
select fid, nodes_to_points(p.geometry) as vertices from polygon as p
nodes_to_points()
QGIS 표현식이지만 문서에 다음과 같이 나와 있습니다 .
QGIS 표현식의 기능은 가상 레이어 쿼리에서도 사용할 수 있습니다.
그러나 (SQL) 쿼리 구문에 포함하는 방법에 대해서는 언급하지 않습니다. 업데이트 : 가상 레이어에서 모든 QGIS 표현식을 사용할 수있는 것은 아닌 것 같습니다. 사용할 수있는 기능 목록은 여기를 참조하십시오. QGIS의 가상 레이어에서 사용할 수있는 모든 기능 나열
SpatiaLite 4.2.0 SQL 함수 참조 목록 도 살펴 봤지만 각 정점에 대해 개별 점을 생성하는 함수를 찾을 수 없었습니다. 가장 가까운 곳은
ST_DissolvePoints()
다음과 같습니다.select fid, ST_DissolvePoints (p.geometry) as vertices from polygon as p
이렇게하면 정점의 시각적 효과가 생성되지만 개별 점이 아니라 다각형 당 단일 다중 점 기능이 생성됩니다.

답변
여기 내 솔루션 :
Requirements
- QGIS 3. x
- 고유 한 값 이있는
id
필드가 있는 (다중) 다각형 레이어
Features
- 하나의 쿼리
- 다중 다각형과 함께 작동
- 한 곳에서만 레이어 이름 구성
- 레이어
id
, 부품 번호, 링 번호 및 정점 번호 출력 - 마지막 중복 정점 삭제 (폴리곤에서 정점 시작 = 정점 끝)
- 열기 QGIS는 갈 Database > Database > DB Manager... > Virtual Layers
- 새로 열기 SQL Window
- 아래의 SQL 스크립트를 복사하고 lyr부분에서
polygons
실제 레이어 이름으로 바꾸십시오 (또는 QGIS에서 레이어 이름을 바꿉니다polygons
).
-- list parts
WITH RECURSIVE gs_part(id, part) AS (
SELECT conf_p.id, conf_p.start
FROM conf_p
UNION ALL
SELECT conf_p.id, part + 1
FROM gs_part gs, conf_p
WHERE
gs.id = conf_p.id
AND gs.part + 1 <= conf_p.stop
),
-- list interior rings
gs_ring(id, part, ring) AS (
SELECT conf_i.id, conf_i.part, conf_i.start
FROM conf_i
UNION ALL
SELECT conf_i.id, conf_i.part, ring + 1
FROM gs_ring gs, conf_i
WHERE
gs.id = conf_i.id
AND gs.part = conf_i.part
AND gs.ring + 1 <= conf_i.stop
),
-- list vertices
gs_vert(id, part, ring, vert) AS (
SELECT conf_v.id, conf_v.part, conf_v.ring, conf_v.start
FROM conf_v
UNION ALL
SELECT conf_v.id, conf_v.part, conf_v.ring, vert + 1
FROM gs_vert gs, conf_v
WHERE
gs.id = conf_v.id
AND gs.part = conf_v.part
AND gs.ring = conf_v.ring
AND gs.vert + 1 < conf_v.stop
),
--
parts AS (
SELECT lyr.id, gs_part.part, st_geometryn(lyr.geometry, gs_part.part) AS geometry
FROM gs_part, lyr
WHERE lyr.id = gs_part.id
),
--
rings AS (
SELECT
'interior' AS info,
parts.id,
parts.part,
gs_ring.ring,
interior_ring_n(parts.geometry, ring) AS geometry
FROM gs_ring, parts
WHERE
gs_ring.ring > 0
AND gs_ring.id = parts.id
AND gs_ring.part = parts.part
UNION ALL
SELECT
'exterior',
parts.id,
parts.part,
0,
exterior_ring(parts.geometry)
FROM parts
),
-- configuration
-- for parts
conf_p AS (
SELECT id, 1 AS start, st_numgeometries(geometry) AS stop
FROM lyr
),
-- for interior rings
conf_i AS (
SELECT id, part, 0 AS start, num_interior_rings(geometry) AS stop
FROM parts
),
-- for vertices
conf_v AS (
SELECT id, part, ring, 1 AS start, st_npoints(geometry) AS stop
FROM rings
),
-- for layer
lyr AS (
SELECT
'polygons' AS lyr_name, -- ## replace here with the 'layer name' ##
p.*
FROM polygons p -- ## replace here with the layer name ##
),
-- get layer crs
crs AS (
SELECT CAST(
SUBSTR(layer_property(lyr_name, 'crs'), 6, 15)
AS integer
) AS id
FROM lyr
LIMIT 1
)
SELECT
rings.info,
rings.id,
rings.part,
rings.ring,
gs_vert.vert AS vertex,
SetSRID(st_pointn(rings.geometry, gs_vert.vert), crs.id) AS geometry
FROM gs_vert, rings, crs
WHERE
gs_vert.id = rings.id
AND gs_vert.part = rings.part
AND gs_vert.ring = rings.ring
안타깝게도 ST_Dump()및 ST_DumpPoints()기능은 아직 Virtual Layer에서 구현되지 않았습니다. 따라서 다각형 피쳐의 정점을 추출하는 방법에 대한 해결 방법을 제공하고 있습니다.
이 솔루션은 여러 가지 기능, 즉 통합 NumInteriorRings(), ST_InteriorRingN(), ST_ExteriorRing(), ST_PointN(),와 ST_NPoints().
CROSS JOIN실제로 필요한 중복 인덱스 (내부 링 및 정점 용)를 생성 하는 절의 방대한 출력으로 인해 성능 및 복잡성 측면에서이 솔루션이 완벽하지 않다는 것을 알 수 있습니다 . 누군가 그것을 풀어내는 방법을 알고 있다면, 쿼리를 개선하거나 힌트를 제공하십시오.
라는 다각형 레이어가 있다고 가정 해 보겠습니다 'polygons'
. 아래 이미지를 참조하세요.

다음 쿼리로
-- generating the second series required to extract all vertices from polygons' contours
WITH RECURSIVE generate_series2(vert) AS (
SELECT 1
UNION ALL
SELECT vert + 1
FROM generate_series2, max_num_points_per_feature
WHERE vert + 1 <= stop2
),
-- finding max number of vertices in all features
max_num_points_per_feature AS (
SELECT MAX(st_npoints(geom1)) AS stop2
FROM inter_outer_contours
),
-- union of geometries of both outer and inner contours, represented as polylines
inter_outer_contours AS (
-- interior rings from all polygons
WITH interior AS (
-- generating the first series required to extract all interior rings
WITH RECURSIVE generate_series1(ring) AS (
SELECT 1
UNION ALL
SELECT ring + 1
FROM generate_series1, max_num_rings_per_polys
WHERE ring + 1 <= stop1
),
-- finding max number of interior rings within all polygons
max_num_rings_per_polys AS (
SELECT MAX(numrings) AS stop1
FROM num_rings_per_poly
),
-- finding how many interior rings each polygon has
num_rings_per_poly AS (
SELECT id, NumInteriorRings(geometry) AS numrings
FROM "polygons"
GROUP BY id
)
-- query to extract all interior rings from all polygons
SELECT p.id AS origin, -- a field represents the original polygon id
'interior' AS info, -- a text field represents the interior attribute
interior_ring_n(geometry, ring) AS geom1 -- setting geometry for a polyline
FROM "polygons" AS p
CROSS JOIN generate_series1
WHERE geom1 IS NOT NULL -- no null geometries accepted, needed because of the cross join
),
-- exterior rings from all polygons
exterior AS (
SELECT p.id AS origin, -- a field represents the original polygon id
'exterior' AS info, -- a text field represents the exterior attribute
st_exteriorring(geometry) AS geom1 -- setting geometry for a polyline
FROM "polygons" AS p
)
-- a union between interior and exterior rings from all polygons
SELECT *
FROM interior
UNION
SELECT *
FROM exterior
)
-- query to achieve all vertices from all polygons
SELECT ioc.origin,
ioc.info,
gs2.vert, -- a field represents the vertice index
st_pointn(ioc.geom1, gs2.vert) AS geom2 -- setting geometry for a point
FROM inter_outer_contours AS ioc
JOIN generate_series2 AS gs2
WHERE geom2 IS NOT NULL -- no null geometries accepted, needed because of the cross join
모든 정점을 얻을 수 있습니다

결과는 "Extract vertices" 지리 알고리즘 의 출력과 일치합니다 .
설명 :
- 위의 쿼리에서 네 번 문자열을 실제 다각형 레이어 이름으로 변경 하는 것을 잊지 마십시오
"polygons"
할 것:
- 설명 섹션 확장
- 다중 다각형으로 시도
- 새 필드 추가
"id"
참조 :
- 가상 계층에서 RECURSIVE 사용