10 votos

¿Cómo crear líneas de liderazgo dinámicas?

Estoy tratando de crear líneas de liderazgo dinámicas utilizando una vista de PostGIS además de la herramienta "Mover etiqueta" de QGIS.

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;

Esto funciona bien para todas las etiquetas WHERE ST_X(geom) < xcord_label pero crea líneas guía de aspecto erróneo para las etiquetas WHERE ST_X(geom) > xcord_label .

enter image description here enter image description here

¿Alguien sabe cómo conseguir que las líneas guía de las etiquetas estén bien colocadas? WHERE ST_X(geom) > xcord_label ? ¿Hay alguna forma de referirse a la coordenada xmax de las etiquetas?

enter image description here

1 votos

Si se trata de unidades cartográficas, debería ser bastante fácil adivinar la altura y, por lo tanto, acortar la línea de referencia para compensar.)

0 votos

El tamaño de la etiqueta está en unidades de mapa.

9voto

hernan43 Puntos 566

Puede utilizar la función de QGIS cuadrante especificador de colocación determinado a partir del acimut de la línea para colocar una etiqueta mejor. El cuadrante especifica 8 posiciones alrededor de un punto:

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

He aquí un ejemplo en torno a Isla Nula creando una tabla y dos vistas.

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;

A continuación, en QGIS, añada:

  • points - geom
  • leader_line - geom - la clave primaria debe ser gid
  • point_labels - geom - la clave primaria debe ser gid

QGIS

Ahora configure las propiedades de la capa para point_labels :

  • Cambiar el estilo para que el punto no se dibuje, por ejemplo, cambiar el tamaño a 0.0
  • Etiquete esta capa con label y cambiar la colocación a "Desplazamiento del punto", modificando el "Cuadrante" para utilizar el campo de atributos quadrant

quadrant

¡Bingo!

Bingo

Tenga en cuenta que se requiere un enfoque ligeramente diferente para geography tipos, ya que ST_Azimuth se comporta de manera diferente.


Actualización: Al añadir nuevos puntos al points capa, el geom se actualiza como siempre, pero el campo label_geom no lo es. Para rellenar un valor por defecto de label_geom con nuevos puntos, un es necesario crear un disparador . Pero si se utiliza una función de activación, el quadrant puede ser almacenado en el points mesa y el point_labels vista puede ser ignorada:

Por ejemplo, empecemos de nuevo con un ejemplo ligeramente diferente con una tabla y una vista:

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

El del primer ejemplo, volver a hacer el INSERT INTO points et CREATE OR REPLACE VIEW leader_line de las declaraciones, ya que éstas no necesitan ser modificadas. Sin embargo, no hay que tener en cuenta el leader_line vista.

A continuación, en QGIS, añada:

  • points - geom
  • points - label_geom
  • leader_line - geom - la clave primaria debe ser gid

Ahora configure las propiedades de la capa para points con label_geom como lo hizo el primer ejemplo para point_labels . El quadrant se modificará automáticamente para los puntos nuevos y movidos, pero sólo notará estos cambios cada vez que guarde sus ediciones.

0 votos

Gran trabajo, pero ¿cómo añadir una nueva característica de punto en QGIS teniendo dos columnas de geometría en una tabla PostGIS?

0 votos

@Lunar Sea - interesante, ¿obtienes dos entradas para la tabla, una por geometría, pero qgis no te deja establecer el campo de la geometría desde el combo? ¿Has probado a usar una consulta sql manual en el cuadro de diálogo de importación (es la columna más a la derecha, y a menudo está oculta fuera de la vista...)?

0 votos

Tengo dos capas de "puntos" en QGIS ( gid | label_geom | label et gid, geom, label ).

1voto

Mat Puntos 196

Vale como está en unidades de mapa esto debería ser bastante sencillo, dentro de las limitaciones. Ya sabes la altura de la etiqueta. Si estuviera en puntos dependería de la escala.

Esto supone un tamaño de etiqueta fijo, por lo que su funcionamiento depende de la uniformidad de sus etiquetas y de si utiliza una fuente proporcional o de ancho fijo (el ancho fijo es más fácil: multiplique la longitud de la etiqueta por el tamaño de la misma para obtener su ancho).

Lamentablemente, esto no responde a su pregunta sobre cómo encontrar los límites de la etiqueta como se hace .

tienes 4 casos (NE,NW,SE,SW).

Supongo que su tabla tiene el siguiente aspecto (disculpas, algunos nombres de campos son diferentes)

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;

A continuación, añada 4 puntos (todos idénticos) pero con etiquetas en los 4 cuadrantes para representar los 4 casos de uso principales

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

He utilizado el CRS 27700 (0,0 en la parte inferior izquierda, unidades del mapa en m) He asumido una etiqueta de ancho 50, altura 30 unidades de mapa.

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

Transformaciones afines

Otra posibilidad es acortar todas las líneas de dirección, por ejemplo al 80%.

  • Puedes usar ST_Translate(geom,-ST_X(geom),-ST_Y(geom)) para mover la línea al origen y obtener geom_o
  • utilice ST_Scale(geom_o,0.8,0.8) para obtener geom_o_scaled
  • luego retranslada usando ST_Translate(geom_o_scaled,ST_X(geom),ST_Y(geom)) de vuelta a la posición original.

Esto podría funcionar mejor, aunque no lo he probado.

0 votos

Gracias por sus esfuerzos, lamentablemente las líneas de dirección no coinciden muy bien con las etiquetas.

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X