ダイナミックなリーダーラインを作成するには?


10

QGISの「ラベルの移動」ツールに加えて、PostGISビューを使用して動的な引出線を作成しようとしています。

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;

これはすべてのラベルで問題WHERE ST_X(geom) < xcord_labelなく機能しますが、ラベルの見栄えが悪くなりWHERE ST_X(geom) > xcord_labelます。

ここに画像の説明を入力してください ここに画像の説明を入力してください

誰かがラベルの引き出し線を正しく配置する方法を知っていますWHERE ST_X(geom) > xcord_labelか?ラベルのxmax座標を参照する方法はありますか?

ここに画像の説明を入力してください


1
ラベルはポイントまたはマップ単位ですか?それがマップ単位の場合、高さを推測するのはかなり簡単であり、それによってリーダーラインを短くして補正する必要があります)
Steven Kay

ラベルのサイズはマップ単位です。
月の海

回答:


9

ラインの方位角から決定されるQGISの象限配置指定子を使用して、より適切なラベルを配置できます。象限は、ポイントの周りに8つの位置を指定します。

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

ここでは、テーブルと2つのビューを作成するNull Islandの例を示します。

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;

次に、QGISで以下を追加します。

  • pointsgeom
  • leader_linegeom–主キーはgid
  • point_labelsgeom–主キーはgid

QGIS

次に、レイヤーのプロパティを設定しますpoint_labels

  • ポイントを描画しないようにスタイルを変更します。たとえば、サイズを0.0に変更します
  • このレイヤーにのラベルを付けlabel、配置を「オフセット」から「属性」フィールドを使用するように「象限」を変更して変更しますquadrant

四分円

ビンゴ!

ビンゴ

ST_Azimuthの動作は異なるため、geography型には少し異なるアプローチが必要であることに注意してください。


更新:pointsレイヤーに新しいポイントを追加すると、geomフィールドは通常どおりに更新されますが、そうでlabel_geomはありません。のデフォルト値にlabel_geom新しいポイントを入力するには、トリガーを作成する必要があります。ただし、トリガー関数を使用する場合は、quadrant指定子をpointsテーブルに格納して、point_labelsビューを無視できます。

たとえば、1つのテーブルと1つのビューを持つ少し異なる例から始めましょう。

-- 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();

最初の例から、INSERT INTO pointsand CREATE OR REPLACE VIEW leader_lineステートメントを再実行します。これらは変更する必要がないためです。ただし、leader_lineビューは無視してください。

次に、QGISで以下を追加します。

  • pointsgeom
  • pointslabel_geom
  • leader_linegeom–主キーはgid

次に、の最初の例pointslabel_geom同様に、with のレイヤープロパティを設定しますpoint_labelsquadrant指定子は、新規および移動ポイントを自動的に変更されますが、これらのみを使用して、編集内容を保存するたびに変更に気づくでしょう。


すばらしい作業ですが、1つのPostGISテーブルに2つのジオメトリ列を持つQGISに新しいポイントフィーチャを追加するにはどうすればよいですか?
ルナ海の

@Lunar Sea-おもしろいですが、テーブルごとに2つのエントリがあり、ジオメトリごとに1つですが、qgisではコンボからジオメトリフィールドを設定できませんか?インポートダイアログボックスで手動のSQLクエリを使用してみましたか(これは右端の列で、多くの場合表示されません...)?
スティーブンケイ

QGISには2つの「ポイント」レイヤーがgid | label_geom | labelありgid, geom, labelます(および)。
ルナ海の

@LunarSea 1つのテーブルと1つのビューを持つ2番目の例を作り直しました。テーブルには、のデフォルト値を決定するトリガー関数がありlabel_geomquadrant値も更新されるため、point_labelレイヤー/ビューは必要ありません。
マイクT

良い回避策マイク!移動した後label_geom、レイヤーの編集を保存し、キャンバスを更新して、ラベルの実際の位置を確認します。QGISの「ラベル移動」ツールで象限指定子を使用する方法がないのは残念です。
ルナ海の

1

わかりました。マップ単位なので、制限内でこれはかなり簡単なはずです。あなたはすでにラベルの高さを知っています。それがポイントである場合、それはスケールに依存します。

これは固定ラベルサイズを想定しているため、これがどの程度うまく機能するかは、ラベルの均一性と、プロポーショナルフォントまたは固定幅フォントを使用するかどうかによって決まります(固定幅の方が簡単です。ラベルの長さにラベルサイズを掛けると、ラベルの幅を取得します)。

残念ながら、これは実際にレンダリングされたラベルの境界を見つける方法についてのあなたの質問に答えません。

あなたには4つのケースがあります(NE、NW、SE、SW)。

私はあなたのテーブルがこのように見えると思います(お詫び、いくつかのフィールド名は異なります)

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;

次に、4つのポイント(すべて同一)を追加しますが、4つの象限に4つの主な使用例を表すラベルを付けます

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')

私はCRS 27700(左下に0,0、mにマップ単位)を使用しました。ラベルの幅は50、高さは30マップ単位と仮定しました。

-- 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);

アフィン変換

別の可能性は、すべての先行線を短くすることです。

  • ST_Translate(geom、-ST_X(geom)、-ST_Y(geom))を使用してラインを原点に移動し、geom_oを取得できます
  • ST_Scale(geom_o、0.8,0.8)を使用してgeom_o_scaledを取得します
  • 次に、ST_Translate(geom_o_scaled、ST_X(geom)、ST_Y(geom))を使用して元の位置に再変換します。

これは試したことはありませんが、うまくいくかもしれません。


ご不便をおかけして申し訳ありませんが、残念ながらリーダーラインはラベルとあまり一致していません。
月の海
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.