хорошо ... так как это в единицах карты, это должно быть довольно просто, в пределах ограничений. Вы уже знаете высоту этикетки. Если бы это было в пунктах, это будет зависеть от масштаба.
Это предполагает фиксированный размер метки, поэтому насколько хорошо это работает, зависит от того, насколько однородны ваши метки, и от того, используете ли вы шрифт пропорциональной или фиксированной ширины (фиксированная ширина проще - умножьте длину метки на размер метки, чтобы получить ширину метки).
К сожалению, это не ответит на ваш вопрос о том, как на самом деле найти границы метки как предоставленные .
у вас есть 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 слева внизу, единицы измерения карты в м). Я принял ширину метки 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
- используйте ST_Scale (geom_o, 0.8,0.8), чтобы получить geom_o_scaled
- затем повторите перевод с помощью ST_Translate (geom_o_scaled, ST_X (geom), ST_Y (geom)) обратно в исходное положение.
Это может работать лучше, хотя я не пробовал.