Làm thế nào để tạo ra các nhà lãnh đạo năng động?


10

Tôi đang cố gắng tạo các dòng nhà lãnh đạo năng động bằng cách sử dụng chế độ xem PostGIS cùng với công cụ QGIS „Di chuyển Nhãn Nhãn.

CREATE VIEW leader_line AS
SELECT
gid,
ST_MakeLine(geom, ST_SetSRID(ST_MakePoint(xcord_label, ycord_label), SRID))::geometry(linestring, SRID) AS geom
FROM point
WHERE xcord_label IS NOT NULL;

Điều này hoạt động tốt cho tất cả các nhãn WHERE ST_X(geom) < xcord_labelnhưng tạo ra các đường dẫn tìm kiếm sai cho nhãn WHERE ST_X(geom) > xcord_label.

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

Có ai biết làm thế nào để có được dòng lãnh đạo được đặt đúng cho nhãn WHERE ST_X(geom) > xcord_label? Có cách nào để tham khảo tọa độ xmax của nhãn không?

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


1
Nhãn của bạn có tính theo điểm hoặc đơn vị bản đồ không? Nếu là đơn vị bản đồ, việc đoán chiều cao khá dễ dàng và do đó rút ngắn đường dẫn của bạn để bù lại)
Steven Kay

Kích thước nhãn là đơn vị bản đồ.
Biển âm lịch

Câu trả lời:


9

Bạn có thể sử dụng công cụ xác định vị trí góc phần tư của QGIS được xác định từ góc phương vị của dòng để đặt nhãn tốt hơn. Góc phần tư chỉ định 8 vị trí xung quanh một điểm:

[ 0=Above Left | 1=Above | 2=Above Right |
  3=Left       | 4=Over  | 5=Right       |
  6=Below Left | 7=Below | 8=Below Right ]

Đây là một ví dụ xung quanh đảo Null , tạo một bảng và hai khung nhìn.

CREATE TABLE points (
  gid serial PRIMARY KEY,
  geom geometry(Point, 4326),
  label_geom geometry(Point, 4326),
  label text
);

INSERT INTO points(geom, label_geom, label)
SELECT origin, pt, round(degrees(ST_Azimuth(origin, pt))) || ' degrees'
FROM (
  SELECT
    ST_SetSRID(ST_MakePoint(0, 0), 4326) AS origin,
    ST_SetSRID(ST_MakePoint(cos(radians(x)), sin(radians(x))), 4326) AS pt
  FROM generate_series(0, 350, 15) AS x
) AS f;

CREATE OR REPLACE VIEW point_labels AS
  SELECT gid, label_geom AS geom,
  CASE
    WHEN ST_Azimuth(geom, label_geom) ISNULL THEN 2 -- default if azimuth cannot be determined
    WHEN degrees(ST_Azimuth(geom, label_geom)) < 22.5 THEN 1 -- Above
    WHEN degrees(ST_Azimuth(geom, label_geom)) < 67.5 THEN 2 -- Above Right
    WHEN degrees(ST_Azimuth(geom, label_geom)) < 112.5 THEN 5 -- Right
    WHEN degrees(ST_Azimuth(geom, label_geom)) < 157.5 THEN 8 -- Below Right
    WHEN degrees(ST_Azimuth(geom, label_geom)) < 202.5 THEN 7 -- Below
    WHEN degrees(ST_Azimuth(geom, label_geom)) < 247.5 THEN 6 -- Below Left
    WHEN degrees(ST_Azimuth(geom, label_geom)) < 292.5 THEN 3 -- Left
    WHEN degrees(ST_Azimuth(geom, label_geom)) < 337.5 THEN 0 -- Above Left
    ELSE 1 -- >= 337.5 Above
  END AS quadrant, label
  FROM points;

CREATE OR REPLACE VIEW leader_line AS
  SELECT gid, ST_MakeLine(geom, label_geom)::geometry(LineString, 4326) AS geom, label
  FROM points;

Sau đó, trong QGIS, thêm:

  • points - geom
  • leader_line- geom- khóa chính cần phải làgid
  • point_labels- geom- khóa chính cần phải làgid

Quốc tế

Bây giờ cấu hình các thuộc tính lớp cho point_labels:

  • Thay đổi kiểu để điểm không được vẽ, ví dụ: thay đổi kích thước thành 0,0
  • Gắn nhãn lớp này với labelvà thay đổi vị trí thành "Offset from point", sửa đổi "Quadrant" để sử dụng trường thuộc tínhquadrant

góc phần tư

Chơi lô tô!

Chơi lô tô

Lưu ý rằng một cách tiếp cận hơi khác nhau là bắt buộc đối với geographycác loại, vì ST_Azimuth hành xử khác nhau.


Cập nhật: Khi thêm điểm mới vào pointslớp, geomtrường được cập nhật như bình thường, nhưng label_geomkhông phải. Để điền một giá trị mặc định label_geomvới các điểm mới, cần phải kích hoạt một bộ kích hoạt . Nhưng nếu một chức năng kích hoạt được sử dụng, bộ quadrantxác định có thể được lưu trữ trong pointsbảng và point_labelschế độ xem có thể bị bỏ qua:

Ví dụ: hãy bắt đầu lại với một ví dụ hơi khác với một bảng và một khung nhìn:

-- DROP TABLE points CASCADE;
CREATE TABLE points (
  gid serial PRIMARY KEY,
  geom geometry(Point, 4326),
  label_geom geometry(Point, 4326),
  quadrant integer,
  label text
);

CREATE FUNCTION label_geom_tg_fn() RETURNS trigger AS
$BODY$
DECLARE
  azimuth float8;
BEGIN
  -- Set a default label_geom
  IF NEW.label_geom ISNULL THEN
    NEW.label_geom := NEW.geom;
  END IF;
  -- Determine quadrant
  azimuth := degrees(ST_Azimuth(NEW.geom, NEW.label_geom));
  NEW.quadrant := CASE
    WHEN azimuth ISNULL THEN 2 -- azimuth cannot be determined, so put Above Right
    WHEN azimuth < 22.5 THEN 1 -- Above
    WHEN azimuth < 67.5 THEN 2 -- Above Right
    WHEN azimuth < 112.5 THEN 5 -- Right
    WHEN azimuth < 157.5 THEN 8 -- Below Right
    WHEN azimuth < 202.5 THEN 7 -- Below
    WHEN azimuth < 247.5 THEN 6 -- Below Left
    WHEN azimuth < 292.5 THEN 3 -- Left
    WHEN azimuth < 337.5 THEN 0 -- Above Left
    ELSE 1 END;-- >= 337.5 Above
  RETURN NEW;
END;$BODY$ LANGUAGE plpgsql;

CREATE TRIGGER label_geom_tg BEFORE INSERT OR UPDATE
   ON points FOR EACH ROW
   EXECUTE PROCEDURE label_geom_tg_fn();

Từ ví dụ đầu tiên, làm lại các câu lệnh INSERT INTO pointsCREATE OR REPLACE VIEW leader_linevì chúng không yêu cầu sửa đổi. Nhưng bỏ qua leader_linequan điểm.

Sau đó, trong QGIS, thêm:

  • points - geom
  • points - label_geom
  • leader_line- geom- khóa chính cần phải làgid

Bây giờ cấu hình các thuộc tính lớp cho pointsvới label_geomví dụ đầu tiên đã làm point_labels. Trình quadrantxác định sẽ được sửa đổi tự động cho các điểm mới và di chuyển, nhưng bạn sẽ chỉ nhận thấy những thay đổi này mỗi khi bạn lưu các chỉnh sửa của mình.


Công việc tuyệt vời, nhưng làm thế nào để thêm một tính năng điểm mới trong QGIS có hai cột hình học trong một bảng PostGIS?
Biển âm lịch

@Lunar Sea - thật thú vị, bạn có nhận được hai mục nhập cho bảng không, một mục nhập cho mỗi hình học, nhưng qgis không cho phép bạn đặt trường hình học từ kết hợp? Bạn đã thử sử dụng truy vấn sql thủ công trong hộp thoại nhập (đó là cột ngoài cùng bên phải và thường bị ẩn khỏi tầm nhìn ...)?
Steven Kay

Tôi có hai lớp 'điểm' trong QGIS ( gid | label_geom | labelgid, geom, label).
Biển âm lịch

@LunarSea Tôi đã làm lại một ví dụ thứ hai có một bảng và một khung nhìn. Bảng có các hàm kích hoạt để xác định giá trị mặc định cho label_geomvà cũng cập nhật quadrantgiá trị, do đó, point_labellớp / khung nhìn không còn cần thiết nữa.
Mike T

Cách giải quyết tốt đẹp Mike! Sau khi di chuyển, label_geomtôi phải lưu chỉnh sửa lớp và làm mới khung vẽ để xem vị trí thực của nhãn. Thật đáng tiếc khi không có cách nào sử dụng một công cụ xác định góc phần tư với công cụ "Di chuyển nhãn" của QGIS.
Âm lịch

1

được rồi .. vì nó trong các đơn vị bản đồ nên điều này khá đơn giản, trong giới hạn. Bạn đã biết chiều cao của nhãn. Nếu nó ở điểm thì nó sẽ phụ thuộc vào quy mô.

Điều này giả định kích thước nhãn cố định, do đó, mức độ hoạt động của nó phụ thuộc vào mức độ đồng nhất của nhãn của bạn và bạn có sử dụng phông chữ theo tỷ lệ hoặc chiều rộng cố định hay không (chiều rộng cố định dễ dàng hơn - nhân chiều dài của nhãn với kích thước nhãn lấy chiều rộng nhãn).

Đáng buồn thay, điều này không trả lời câu hỏi của bạn về cách thực sự tìm thấy giới hạn của nhãn như được hiển thị .

bạn có 4 trường hợp (NE, NW, SE, SW).

tôi giả sử bảng của bạn trông như thế này (xin lỗi, một số tên trường là khác nhau)

CREATE TABLE points
(
  uniq int PRIMARY KEY,
  geom geometry(Point,27700),
  label_x int,
  label_y int,
  labeltext character varying(100)
);
ALTER TABLE points
  OWNER TO user;
GRANT ALL ON TABLE points TO user;
GRANT SELECT ON TABLE points TO public;

Tiếp theo, thêm 4 điểm (tất cả giống hệt nhau) nhưng có nhãn trong 4 góc phần tư để thể hiện 4 trường hợp sử dụng chính

insert into points values 
(1,ST_SetSRID(ST_Point(1000,1000),27700),750,750,'123');

insert into points values(2,ST_SetSRID(ST_Point(1000,1000),27700),1250,1250,'456')

insert into points values 
(3,ST_SetSRID(ST_Point(1000,1000),27700),750,1250,'456')

insert into points values 
(4,ST_SetSRID(ST_Point(1000,1000),27700),1250,750,'789')

Tôi đã sử dụng CRS 27700 (0,0 ở phía dưới bên trái, đơn vị bản đồ tính bằng m) Tôi đã giả sử một nhãn có chiều rộng 50, chiều cao 30 đơn vị bản đồ.

-- SW use case
CREATE OR REPLACE VIEW leader_line_sw AS
SELECT
uniq,
ST_MakeLine(geom, ST_SetSRID(ST_MakePoint(label_x+50, label_y+30), 27700))::geometry(linestring, 27700) AS geom
FROM points
WHERE label_x IS NOT NULL AND 
label_y<=ST_Y(geom) and label_x<=ST_X(geom);

-- SE use case
CREATE OR REPLACE VIEW leader_line_se AS
SELECT
uniq,
ST_MakeLine(geom, ST_SetSRID(ST_MakePoint(label_x, label_y-30), 27700))::geometry(linestring, 27700) AS geom
FROM points
WHERE label_x IS NOT NULL AND 
label_y<=ST_Y(geom) and label_x>ST_X(geom);


-- NE use case
CREATE OR REPLACE VIEW leader_line_ne AS
SELECT
uniq,
ST_MakeLine(geom, ST_SetSRID(ST_MakePoint(label_x, label_y), 27700))::geometry(linestring, 27700) AS geom
FROM points
WHERE label_x IS NOT NULL AND 
label_y>ST_Y(geom) and label_x>ST_X(geom);

-- NW use case
CREATE OR REPLACE VIEW leader_line_nw2 AS
SELECT
uniq,
ST_MakeLine(geom, ST_SetSRID(ST_MakePoint(label_x+50, label_y), 27700))::geometry(linestring, 27700) AS geom
FROM points
WHERE label_x IS NOT NULL AND 
label_y>ST_Y(geom) and label_x<=ST_X(geom);

Biến đổi affine

Một khả năng khác là rút ngắn tất cả các dòng hàng đầu, để nói 80%.

  • Bạn có thể sử dụng ST_Translate (geom, -ST_X (geom), - ST_Y (geom)) để di chuyển dòng đến gốc để lấy geom_o
  • sử dụng ST_Scale (geom_o, 0.8,0.8) để nhận geom_o_scaled
  • sau đó truyền lại bằng ST_Translate (geom_o_scaled, ST_X (geom), ST_Y (geom)) trở lại vị trí ban đầu.

Điều này có thể hoạt động tốt hơn, mặc dù tôi đã không thử nó.


Cảm ơn bạn vì hiệu ứng của bạn, thật không may, các dòng lãnh đạo không khớp với nhãn rất tốt.
Biển âm lịch
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.