Tạo đèn ngành trong QGIS?


24

Tôi đang sử dụng QGIS 2.18. Tôi cần tạo đèn khu vực cho mục đích điều hướng trên bản đồ.

Tôi có dữ liệu của ngành ánh sáng khi các trường đưa ra becon_id, mức độ bắt đầu, mức độ kết thúc và màu sắc trong một shapefile với hơn 500 phao, đèn hiệu và ngọn hải đăng cần được hiển thị trên bản đồ. Đối với mỗi đèn hiệu, có thể có nhiều hàng, mỗi hàng mô tả một khu vực ánh sáng (ví dụ: khu vực màu trắng)

Kết quả cuối cùng sẽ trông giống như dưới đây: Các thành phần ánh sáng có màu sắc phù hợp, với màu được đánh dấu là ký tự trong trường màu (RGW) và các đường chấm chấm từ phao / đèn hiệu / ngọn hải đăng từ 100m đến 1000m.

Điều này rất có thể sẽ được tạo ra như một biểu tượng dựa trên cai trị, nhưng tôi cần một số con trăn?

nhập mô tả hình ảnh ở đây

Dưới đây là một ví dụ về dữ liệu shapefile cho một ngọn hải đăng (tiếc là không phải ở trên) có một khu vực màu xanh lá cây từ 114 đến 154 độ, một khu vực màu trắng giữa 154 và 168 độ, một khu vực màu đỏ từ 168 đến 237 độ, một màu xanh lá cây khu vực nằm trong khoảng từ 237 đến 314 độ, khu vực màu trắng nằm trong khoảng từ 314 đến 320 độ, khu vực màu đỏ nằm trong khoảng từ 320 đến 337 độ (vì một số lý do, 0 không phải là phía bắc mà là phía nam):

ví dụ bảng shapefile



2
Xin vui lòng, bạn có thể tải lên một tập dữ liệu mẫu và chỉnh sửa câu hỏi của bạn bằng cách xây dựng chính xác kết quả mà bạn mong đợi là gì? Trong hình ảnh đính kèm tôi chỉ thấy một vũ trụ của các biểu tượng và màu sắc.
mgri

1
Dữ liệu ví dụ sẽ giúp ở đây. Bạn có một tính năng cho mỗi khu vực ánh sáng, hoặc một tính năng cho mỗi phao? Plugin Wedge Buffer có thể giúp ích ở đây, nhưng việc này dễ dàng như thế nào tùy thuộc vào cách dữ liệu của bạn được thiết lập.
Steven Kay

Xin chào @mgri và Steven, tôi đã thêm dữ liệu ví dụ và cố gắng làm cho câu hỏi rõ ràng hơn :), cảm ơn!
Benjamin Donner

1
@mgri các dòng không phải là một biến, nhưng các dòng nên được hiển thị tĩnh dưới dạng các dòng dài 900m giữa các thành phần ánh sáng như trong ảnh. Hệ thống tham chiếu dự kiến.
Benjamin Donner

Câu trả lời:


50

EDIT Tôi đã chỉnh sửa câu trả lời để quản lý các tình huống cụ thể (do các giá trị góc cụ thể) và không hiển thị các đường chấm chấm khi xác định góc tròn.


Tôi đề xuất một giải pháp bằng cách chỉ định kỳ về ký hiệu và ghi nhãn dựa trên quy tắc.

Trước khi bắt đầu, tôi muốn nhấn mạnh rằng tôi sẽ tập trung chú ý vào phần giải thích những điều tối thiểu cần làm để tái tạo kết quả mong muốn: điều này có nghĩa là một số thông số nhỏ khác (như kích thước, chiều rộng, v.v.) nên được điều chỉnh dễ dàng bởi bạn để phù hợp hơn với nhu cầu của bạn.

Hơn nữa, giải pháp này chỉ hoạt động nếu bạn cho rằng 0mức độ là Bắc thay vì Nam (thay vào đó 0là Nam, thay vào đó, nó sẽ đủ để tổng 180giá trị mỗi khi xuất hiện '90' trong các công thức xử lý các góc, ví dụ như cos(radians(90))sẽ trở thành cos(radians(180 + 90))). Tôi thích làm điều này chỉ vì mục đích đưa ra một giải pháp tổng quát hơn.


Tạo kiểu

Chúng tôi sẽ kết xuất các điểm bằng một Single symbolvà bằng cách lặp lại một Simple Markervà ba Geometry generatorlớp biểu tượng:

nhập mô tả hình ảnh ở đây

Trong phần giải thích thêm, tôi sẽ làm theo thứ tự tương tự của các biểu tượng trong hình trên.

1) Điểm đánh dấu đơn giản

Tôi đã chọn một biểu tượng mặc định của một ngôi sao đen (đây là phần dễ dàng hơn trong hướng dẫn này), có kích thước 3 mm và chiều rộng 0,4 mm.

2) Máy phát điện hình học số 1

Thêm một lớp biểu tượng mới và chọn Geometry generatorloại:

nhập mô tả hình ảnh ở đây

Chèn biểu thức này vào Expressiontrường:

CASE
WHEN abs( "ALKUKULMA" - "LOPPUKULMA") < 360
THEN
make_line(
 $geometry,
 make_point(
  $x + 1000*cos(radians(90 - "ALKUKULMA")),
  $y + 1000*sin(radians(90 - "ALKUKULMA"))
  )
)
END

Chúng tôi vừa xác định dòng đầu tiên hướng đến điểm bắt đầu của ngành ánh sáng. Đường này dài 1000 m và nó chỉ được tạo khi góc mở của ánh sáng khu vực không phải là góc tròn (điều này xảy ra để tránh rằng đường đó sẽ phá vỡ cả một vòng tròn).

3) Máy phát điện hình học số 2

Tương tự như trên, nhưng trong bước này, bạn cần sử dụng biểu thức này:

CASE
WHEN abs( "ALKUKULMA" - "LOPPUKULMA") < 360
THEN
make_line(
 $geometry,
 make_point(
  $x + 1000*cos(radians(90 - "LOPPUKULMA")),
  $y + 1000*sin(radians(90 - "LOPPUKULMA"))
  )
)
END

Chúng tôi vừa xác định dòng đầu tiên hướng đến điểm mà ngành ánh sáng kết thúc tại. Đường này dài 1000 m và nó chỉ được tạo khi góc mở của ánh sáng khu vực không phải là góc tròn (điều này xảy ra để tránh rằng đường đó sẽ phá vỡ cả một vòng tròn).

4) Máy phát điện hình học số 3

Chèn biểu thức này vào Expressiontrường:

CASE

WHEN abs("ALKUKULMA" - "LOPPUKULMA") <= 180 AND "ALKUKULMA" >= "LOPPUKULMA"
THEN
difference(
 boundary(
  buffer(
   $geometry, 900)
   ),
  make_polygon(
   geom_from_wkt(
    geom_to_wkt(
     make_line(
      $geometry,
      make_point($x + 2000*cos(radians(90 - "ALKUKULMA" )), $y + 2000*sin(radians((90 - "ALKUKULMA" )))),
      make_point($x + 2000*cos(radians(90 - ("LOPPUKULMA" + "ALKUKULMA")/2 )), $y + 2000*sin(radians((90 - ("LOPPUKULMA" + "ALKUKULMA")/2 )))),
      make_point($x + 2000*cos(radians(90 - "LOPPUKULMA")), $y + 2000*sin(radians((90 - "LOPPUKULMA")))),
      $geometry)
   )  
  )
 )
)

WHEN abs("ALKUKULMA" - "LOPPUKULMA") <= 180 AND "ALKUKULMA" <= "LOPPUKULMA"
THEN
intersection(
 boundary(
  buffer(
   $geometry, 900)
   ),
  make_polygon(
   geom_from_wkt(
    geom_to_wkt(
     make_line(
      $geometry,
      make_point($x + 2000*cos(radians(90 - "ALKUKULMA" )), $y + 2000*sin(radians((90 - "ALKUKULMA" )))),
      make_point($x + 2000*cos(radians(90 - ("LOPPUKULMA" + "ALKUKULMA")/2 )), $y + 2000*sin(radians((90 - ("LOPPUKULMA" + "ALKUKULMA")/2 )))),
      make_point($x + 2000*cos(radians(90 - "LOPPUKULMA")), $y + 2000*sin(radians((90 - "LOPPUKULMA")))),
      $geometry)
   )  
  )
 )
)

WHEN abs("ALKUKULMA" - "LOPPUKULMA") > 180 AND "ALKUKULMA" >= "LOPPUKULMA"
THEN
intersection(
 boundary(
  buffer(
   $geometry, 900)
   ),
  make_polygon(
   geom_from_wkt(
    geom_to_wkt(
     make_line(
      $geometry,
      make_point($x + 2000*cos(radians(90 - "ALKUKULMA" )), $y + 2000*sin(radians((90 - "ALKUKULMA" )))),
      make_point($x - 2000*cos(radians(90 - ("LOPPUKULMA" + "ALKUKULMA")/2 )), $y - 2000*sin(radians((90 - ("LOPPUKULMA" + "ALKUKULMA")/2 )))),
      make_point($x + 2000*cos(radians(90 - "LOPPUKULMA")), $y + 2000*sin(radians((90 - "LOPPUKULMA")))),
      $geometry)
   )  
  )
 )
)

WHEN abs("ALKUKULMA" - "LOPPUKULMA") > 180 AND "ALKUKULMA" <= "LOPPUKULMA"
THEN
difference(
 boundary(
  buffer(
   $geometry, 900)
   ),
  make_polygon(
   geom_from_wkt(
    geom_to_wkt(
     make_line(
      $geometry,
      make_point($x + 2000*cos(radians(90 - "ALKUKULMA" )), $y + 2000*sin(radians((90 - "ALKUKULMA" )))),
      make_point($x - 2000*cos(radians(90 - ("LOPPUKULMA" + "ALKUKULMA")/2 )), $y - 2000*sin(radians((90 - ("LOPPUKULMA" + "ALKUKULMA")/2 )))),
      make_point($x + 2000*cos(radians(90 - "LOPPUKULMA")), $y + 2000*sin(radians((90 - "LOPPUKULMA")))),
      $geometry)
   )  
  )
 )
)


END

Chúng tôi vừa xác định cung giữa điểm bắt đầu và điểm kết thúc của ngành ánh sáng (xin lưu ý rằng đó 2000là một giá trị tùy ý vì tôi đang cố gắng tạo một đa giác để giao với ranh giới của vòng tròn có bán kính 900 m).

Hơn nữa, chúng ta cần đặt màu được lưu trữ trong "VARIS"trường. Để làm điều này, chúng ta cần chỉ định nó với một biểu thức tùy chỉnh. Thực hiện theo mũi tên trong hình dưới đây:

nhập mô tả hình ảnh ở đây

và sau đó nhập biểu thức này sau khi nhấp vào Edit...nút:

CASE
WHEN  "VARIS" = 'vi' THEN color_rgb(51,160,44)
WHEN "VARIS" = 'v' THEN color_rgb(255,255,255)
WHEN "VARIS" = 'p' THEN color_rgb(227,26,28)
END

Xin lưu ý rằng, đối với lớp biểu tượng này, tôi đã tạo hai dòng: dòng trên xác định màu sẽ sử dụng (thực tế tôi đặt biểu thức tùy chỉnh cho lớp này), trong khi lớp dưới hữu ích để xác định đường viền màu đen (nó sẽ có chiều rộng lớn hơn đường kẻ trên). Cũng cần nhớ để thiết lập Flatnhư Cap stylecho cả hai dòng để tránh bất kỳ màu sắc chồng chéo.


Dán nhãn

1) Đặt nhãn

Đi tới Layer Properties> Labelsvà, như thường lệ, đi theo mũi tên màu đỏ:

nhập mô tả hình ảnh ở đây

và sau đó gõ biểu thức này:

CASE
WHEN "VARIS" = 'vi' THEN 'G'
WHEN "VARIS" = 'v' THEN 'W'
WHEN "VARIS" = 'p' THEN 'R'
END

Chúng tôi vừa xác định quy tắc màu bằng cách sử dụng giá trị được lưu trữ trong "VARIS"trường.

2) Đặt vị trí cho nhãn

Chọn Placementtùy chọn trong LabelsMenu và chọn Offset from point.

Sau đó, với tham chiếu đến hình ảnh dưới đây:

nhập mô tả hình ảnh ở đây

theo mũi tên màu đỏ và gõ biểu thức này:

CASE
WHEN "ALKUKULMA" > "LOPPUKULMA"
THEN
concat(
 -1000*cos(radians(90 - ("ALKUKULMA" + "LOPPUKULMA")/2)),
  ',',
  1000*sin(radians(90 - ("ALKUKULMA" + "LOPPUKULMA")/2))
)
WHEN "ALKUKULMA" <= "LOPPUKULMA"
THEN
concat(
 1000*cos(radians(90 - ("ALKUKULMA" + "LOPPUKULMA")/2)),
  ',',
  -1000*sin(radians(90 - ("ALKUKULMA" + "LOPPUKULMA")/2))
)
END

Sau đó, làm theo mũi tên màu xanh lá cây và gõ biểu thức này:

CASE
WHEN "ALKUKULMA" >= "LOPPUKULMA"
THEN
180-(("ALKUKULMA" + "LOPPUKULMA")/2)
WHEN "ALKUKULMA" < "LOPPUKULMA"
THEN
- (("ALKUKULMA" + "LOPPUKULMA")/2)
END

Kết quả cuối cùng

Nếu bạn thực hiện đúng các nhiệm vụ trước đó, bạn sẽ có thể nhận được kết quả này:

nhập mô tả hình ảnh ở đây

Tiền thưởng

Vì các tham số nhỏ có quá nhiều để được bao phủ hoàn toàn trong câu trả lời này, tôi đã đính kèm kiểu ở đây : bạn có thể mở mã này bằng bất kỳ trình soạn thảo văn bản nào và lưu nó dưới dạng tệp Kiểu lớp của QGIS (nghĩa là có .qmlphần mở rộng).

Kiểu trên được tạo bằng cách sử dụng QGIS 2.18.4 (nó phải có cùng tên của shapefile bạn đang sử dụng).


3
Trông thật tuyệt, thực sự cho bạn thấy sức mạnh của trình tạo hình học. Là nó chậm để kết xuất?
HeikkiVesanto

2
@Vesanto Tôi đã thử nghiệm nó trên một điểm có sáu tính năng (tức là sáu đèn ngành) và nó được hiển thị ngay lập tức. Tôi nghĩ rằng nó cũng phải nhanh khi xử lý hàng trăm tính năng vì không có cuộc gọi nào đến nhà cung cấp hoặc thứ gì đó tương tự, mà chỉ có một vài thao tác toán học và hình học như Văn bản cũng biết.
mgri

2
Các câu hỏi / câu trả lời như thế này thực sự cho thấy khả năng đa dạng của QGIS!
Joseph

1
@mgri bạn là Master, một giải pháp tuyệt vời và một lời giải thích tuyệt vời liên quan đến rất nhiều công việc, CẢM ƠN BẠN !!
Benjamin Donner

1
@mgri một ngọn núi trong khu vực này nên được đặt theo tên của bạn, cảm ơn bạn !! Tôi đã thử nghiệm một chút và không có vấn đề với các giải pháp bổ sung của bạn đã được tìm thấy :)!
Benjamin Donner
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.