डायनेमिक लीडर लाइन कैसे बनाएं?


10

मैं QGIS Label मूव लेबल ”टूल के अलावा 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
अंक या मानचित्र इकाइयों में आपके लेबल हैं? यदि यह मानचित्र इकाइयाँ हैं, तो ऊँचाई का अनुमान लगाना काफी आसान होना चाहिए, और इस तरह क्षतिपूर्ति करने के लिए आपकी लीडर लाइन को छोटा करना होगा)
स्टीवन के

लेबल का आकार मानचित्र इकाइयों में है।
चंद्र सागर

जवाबों:


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 ]

यहाँ नल द्वीप के चारों ओर एक उदाहरण है , जिससे एक तालिका और दो दृश्य बनते हैं।

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 में, जोड़ें:

  • points - geom
  • leader_line- geom- प्राथमिक कुंजी होना आवश्यक हैgid
  • point_labels- geom- प्राथमिक कुंजी होना आवश्यक हैgid

QGIS

अब इसके लिए परत गुणों को कॉन्फ़िगर करें point_labels:

  • शैली बदलें ताकि बिंदु आकर्षित न हो, उदाहरण के लिए, आकार को 0.0 में बदलें
  • इस लेयर को लेबल करें label, और प्लेसमेंट को "पॉइंट से ऑफ़सेट" में बदलें, विशेषता फ़ील्ड का उपयोग करने के लिए "क्वाड्रंट" को संशोधित करेंquadrant

वृत्त का चतुर्थ भाग

बिंगो!

बिंगो

ध्यान दें कि geographyप्रकारों के लिए थोड़ा अलग दृष्टिकोण आवश्यक है , क्योंकि ST_Azimuth भिन्न व्यवहार करता है।


अद्यतन: जब नए बिंदुओं को pointsपरत में जोड़ते हैं , तो geomफ़ील्ड को हमेशा की तरह अपडेट किया जाता है, लेकिन label_geomऐसा नहीं है। label_geomनए बिंदुओं के साथ एक डिफ़ॉल्ट मान को पॉप्युलेट करने के लिए , एक ट्रिगर बनाने की आवश्यकता होती है । लेकिन अगर एक ट्रिगर फ़ंक्शन का उपयोग किया जाता है, तो quadrantविनिर्देश pointsतालिका में संग्रहीत किया जा सकता है और point_labelsदृश्य को अनदेखा किया जा सकता है:

उदाहरण के लिए, आइए एक तालिका और एक दृश्य के साथ फिर से एक अलग उदाहरण के साथ शुरू करें:

-- 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 pointsऔर CREATE OR REPLACE VIEW leader_lineबयान करें, क्योंकि इनमें संशोधन की आवश्यकता नहीं है। लेकिन leader_lineदृश्य को अनदेखा करें ।

फिर QGIS में, जोड़ें:

  • points - geom
  • points - label_geom
  • leader_line- geom- प्राथमिक कुंजी होना आवश्यक हैgid

अब के लिए परत प्रॉपर्टी कॉन्फ़िगर pointsसाथ label_geomके रूप में पहला उदाहरण के लिए किया था point_labelsquadrantविनिर्देशक नए और चले गए अंक के लिए स्वचालित रूप से संशोधित किया जाएगा, लेकिन आप केवल इन हर बार आप अपने संपादन बचाने में परिवर्तन देखेंगे।


महान काम है, लेकिन एक पोस्टजीआईएस तालिका में दो ज्यामिति कॉलम वाले क्यूजीआईएस में एक नई बिंदु सुविधा कैसे जोड़ें?
चंद्र सागर

@ चंद्र सागर - दिलचस्प है, क्या आपको तालिका के लिए दो प्रविष्टियां मिलती हैं, एक प्रति ज्यामिति, लेकिन क्यूजी आपको कॉम्बो से ज्यामिति क्षेत्र निर्धारित करने की अनुमति नहीं देता है? क्या आपने आयात संवाद बॉक्स में एक मैनुअल sql क्वेरी का उपयोग करने की कोशिश की है (यह सबसे सही कॉलम है, और अक्सर दृश्य से छिपा हुआ है ...)?
स्टीवन के

QGIS ( gid | label_geom | labelऔर gid, geom, label) में दो 'पॉइंट' लेयर्स हैं ।
चंद्र सागर 19

@LunarSea मैंने एक दूसरा उदाहरण पुन: प्रकाशित किया जिसमें एक तालिका और एक दृश्य है। तालिका में इसके लिए डिफ़ॉल्ट मान निर्धारित करने के लिए ट्रिगर फ़ंक्शन हैं label_geom, और मान को भी अपडेट करता quadrantहै, इसलिए point_labelपरत / दृश्य की अब आवश्यकता नहीं है।
माइक टी।

अच्छा समाधान माइक! ले जाने के बाद, label_geomमैं लेयर एडिट को सेव करने और कैनवास को लेबल की वास्तविक स्थिति देखने के लिए रिफ्रेश करता हूं। यह अफ़सोस की बात है कि QGIS "मूव लेबल" टूल के साथ एक क्वाड्रंट स्पेसिफायर का उपयोग करने का कोई तरीका नहीं है।
चंद्र सागर

1

ठीक है .. जैसा कि मानचित्र इकाइयों में है, यह सीमाओं के भीतर काफी सीधा-आगे होना चाहिए। आप पहले से ही लेबल की ऊंचाई जानते हैं। अगर यह अंक में होता तो यह पैमाना निर्भर होता।

यह एक निश्चित लेबल आकार मानता है, इसलिए यह कितना अच्छा काम करता है यह इस बात पर निर्भर करता है कि आपके लेबल कितने समान हैं, और आप आनुपातिक या निश्चित-चौड़ाई वाले फ़ॉन्ट का उपयोग करते हैं या नहीं (निश्चित चौड़ाई आसान है - लेबल आकार द्वारा लेबल की लंबाई गुणा करें लेबल चौड़ाई प्राप्त करें)।

अफसोस की बात है कि यह आपके सवाल का जवाब नहीं देता है कि वास्तव में लेबल की सीमाओं को कैसे प्रदान किया जाए

आपके पास 4 मामले हैं (एनई, एनडब्ल्यू, एसई, एसडब्ल्यू)।

मुझे लगता है कि आपकी तालिका इस तरह दिखती है (माफी, कुछ क्षेत्र के नाम अलग हैं)

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

ट्रान्सफ़ॉर्मेशन ट्रांसफ़ॉर्मेशन

एक और संभावना 80% कहने के लिए सभी प्रमुख लाइनों को छोटा करना है।

  • आप लाइन को स्थानांतरित करने के लिए ST_Translate (geom, -ST_X (geom), - ST_Y (geom) का उपयोग कर सकते हैं ताकि geom_o प्राप्त कर सकें
  • geom_o_scaled प्राप्त करने के लिए ST_Scale (geom_o, 0.8,0.8) का उपयोग करें
  • उसके बाद मूल स्थिति में वापस ST_Translate (geom_o_scaled, ST_X (geom), ST_Y (geom)) का उपयोग करके पुन: प्रारंभ करें।

यह बेहतर काम कर सकता है, हालांकि मैंने इसकी कोशिश नहीं की है।


अपने पुतलों के लिए धन्यवाद, दुर्भाग्य से नेता लाइनें लेबल से बहुत मेल नहीं खाती हैं।
चंद्र सागर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.