Coverage using network of streets

Tracing a path through a streets’ network from a starting point to calculate the coverage along the network, it’s likely that this distance does not coincide with a network’s node. It will end at an intermediate point of the final section.

This article presents a way to get coverage from a starting point until it reaches a maximum distance along the streets’ network. The main contribution is the calculation of the last partial segment of every path.

Specifically, this article focuses on how to resolve the problem in obtaining full and partial sections that conform the traveled distance along the network, using the ‘pgr_withPointsDD’ function from the ‘pgrouting’ library. Starting from a node that is outside the graph and is not any of the network nodes.

In order to use the code in this article, you should install the extension ‘pgrouting’ of PostgresSQL, that allows you to analyze networks. More information on (http: //docs.pgrouting. org) and (http://pgrouting.org).

ATTENTION: Next steps will modify the PostgresSQL database. Be careful, otherwise you may harm existing databases.

  • Download database here.
  • Create new database and name it ‘db_temp’.
  • Restore downloaded database.

Once done, you must have 3 entities:

  • “orig_network” (Streets’ network)
  • “origin” (Starting point)
  • “orig_network_vertices_pgr” (network nodes)

In order to understand this process, below is an example based on an orthogonal and symmetrical streets’ network. But can be used in any network you have.

Below is network ‘pep’, every section measures 100 meters, from node to node and the starting point ‘origin’ is painted in red, as you can see in Figure 1.

fig1

Fig 1. Orthogonal network, 100 meters from node to node.

Procedure of calculating coverage using ‘pgrouting’.

In order to calculate a 500 meters coverage from red dot, you must follow the instructions:

  • Duplicate the network and rename it as ‘network’..
  • Create a table named ‘poi_tmp’, which will contain the geometries of the starting points.
  • Modify ‘poi_tmp’ table, adding the fields(x,y,edge_id,side,fraction, newPoint).
DO $$
#variable_conflict use_variable
DECLARE dist_var INT;
BEGIN
dist_var:=500;DROP TABLE IF EXISTS "network";
CREATE TABLE IF NOT EXISTS "network" as (SELECT * FROM "orig_network");
drop table if exists poi_tmp;
CREATE TABLE if not exists poi_tmp as (SELECT ST_Centroid(tmp."geom") the_geom,tmp."id" as pid from (SELECT * FROM "origin") tmp);
ALTER TABLE poi_tmp ADD COLUMN     x FLOAT;
ALTER TABLE poi_tmp ADD COLUMN     y FLOAT;
ALTER TABLE poi_tmp ADD COLUMN     edge_id BIGINT;
ALTER TABLE poi_tmp ADD COLUMN     side CHAR;
ALTER TABLE poi_tmp ADD COLUMN     fraction FLOAT;
ALTER TABLE poi_tmp ADD COLUMN     newPoint geometry;
  • Update the ‘edge_id’ field with the nearest section identifier.
  • Update the ‘fraction’ field with the nearest section fraction.
UPDATE "poi_tmp" set "edge_id"=nearest_section."tram_id" from (SELECT distinct on(Poi.pid) Poi.pid As Punt_id,Sg.id as Tram_id, ST_Distance(Sg.the_geom,Poi.the_geom) as dist FROM "network" as Sg,"poi_tmp" AS Poi ORDER BY Poi.pid, ST_Distance(Sg.the_geom,Poi.the_geom), Sg.id) nearest_section where "poi_tmp"."pid"=nearest_section."punt_id";
UPDATE "poi_tmp" SET fraction = ST_LineLocatePoint(e.the_geom, "poi_tmp".the_geom),newPoint = ST_LineInterpolatePoint(e.the_geom, ST_LineLocatePoint(e.the_geom, "poi_tmp".the_geom)) FROM "network" AS e WHERE "poi_tmp"."edge_id" = e.id;
  • Create ‘tbl_final_nodes_tmp’ table that will contain the ‘id’, aggregate costs and the starting node.
  • Create ‘geo_final_nodes_tmp’ table that will contain the ‘tbl_final_nodes_tmp’ and their geometries.
DROP FUNCTION IF EXISTS coverage();
DROP TABLE IF EXISTS tbl_final_nodes_tmp;
CREATE TABLE IF NOT EXISTS tbl_final_nodes_tmp AS(SELECT node,agg_cost,start_vid FROM pgr_withPointsDD('SELECT id, source, target, cost, reverse_cost FROM "network" ORDER BY "network".id','SELECT pid, edge_id, fraction, side from "poi_tmp"',array(select "pid"*(-1) from "poi_tmp"),dist_var,driving_side := 'b',details := false));
DROP table if exists geo_final_nodes_tmp;
CREATE TABLE IF NOT EXISTS geo_final_nodes_tmp as (select "orig_network_vertices_pgr".*,"tbl_final_nodes_tmp"."agg_cost", "tbl_final_nodes_tmp"."start_vid", dist_var from "orig_network_vertices_pgr","tbl_final_nodes_tmp" where "orig_network_vertices_pgr"."id" ="tbl_final_nodes_tmp"."node" order by "tbl_final_nodes_tmp"."start_vid" desc,"tbl_final_nodes_tmp"."agg_cost");

After executing the previous code, you will obtaing the picture showed in Figure 2. The blue dot shows the projection of the starting point upon the nearest section, and this will be the starting point of every path calculated.

fig2

Fig 2. Nodes conforming the coverage.

The ‘pgr_withPointsDD’ function, returns the nodes that conform the 500m coverage, but if you want to know where exactly finishes the coverage, you can’t.

In order to resolve this problem, continue reading:

  • Create ‘final_sections_tmp’ table that will contain every section that will conform the coverage, including the final sections, but, as you may imagine, only a fraction of the every final section is valid.
DROP table IF EXISTS final_sections_tmp;
CREATE TABLE IF NOT EXISTS final_sections_tmp as (select "network"."id","network"."the_geom","geo_final_nodes_tmp"."id" as node,"geo_final_nodes_tmp"."agg_cost" as coste,(dist_var  "geo_final_nodes_tmp"."agg_cost") as falta,"geo_final_nodes_tmp"."start_vid" as id_punt,  (select case when (dist_var-"geo_final_nodes_tmp"."agg_cost") / ST_Length("network"."the_geom")<=1 then (dist_var-"geo_final_nodes_tmp"."agg_cost") / ST_Length("network"."the_geom") when (dist_var-      "geo_final_nodes_tmp"."agg_cost") / ST_Length("network"."the_geom")>1 then (1) end) as      fraccio from "network","geo_final_nodes_tmp" where ST_DWithin("geo_final_nodes_tmp"."the_geom", "network"."the_geom",1)=TRUE);

You can see the result of executing the previous code in Figure 3.

fig3

Fig 3. Section conforming part of the 500m coverage.

In order to obtain the fractions of the final sections that complete the 500m coverage, below is a function written in ‘PL/pgSQL’, that does the necessary modifications.

  • Create ‘Coverage’ function.
  • Create ‘fraction_sections_raw’ table, that will contain complete and fractioned sections that conform the 500m coverage.
CREATE OR REPLACE FUNCTION coverage() RETURNS SETOF final_sections_tmp AS
$BODY$
DECLARE
r final_sections_tmp%rowtype;
m final_sections_tmp%rowtype;
BEGIN
DROP TABLE IF EXISTS fraction_sections_raw;
CREATE TABLE fraction_sections_raw (the_geom geometry, punt_id bigint,id_tram bigint,fraccio FLOAT,node bigint,fraccio_inicial FLOAT,cost_invers FLOAT,cost_directe FLOAT,target bigint,radi_inic FLOAT);
FOR r IN SELECT "final_sections_tmp".* FROM "final_sections_tmp" WHERE "final_sections_tmp"."id" not in (select "edge_id" from "poi_tmp")
LOOP
insert into fraction_sections_raw VALUES(ST_Line_Substring((r."the_geom"),case when (select ST_Line_Locate_Point((r."the_geom"),(select "geo_final_nodes_tmp"."the_geom" from "geo_final_nodes_tmp" where "geo_final_nodes_tmp"."id"=r."node" and "geo_final_nodes_tmp"."start_vid"=r."id_punt")))<0.001 then 0 else 1-r."fraccio"
END,
case when (select ST_Line_Locate_Point((r."the_geom"),(select "geo_final_nodes_tmp"."the_geom" from "geo_final_nodes_tmp" where "geo_final_nodes_tmp"."id"=r."node" and "geo_final_nodes_tmp"."start_vid"=r."id_punt")))<0.001 then r."fraccio" else 1
END),r."id_punt"*(-1),r."id",0,r."node",0,0,0,0);
RETURN NEXT r;
END LOOP;
FOR m IN SELECT "final_sections_tmp".* FROM "final_sections_tmp" WHERE "final_sections_tmp"."id" in (select "edge_id" from "poi_tmp")
LOOP
insert into fraction_sections_raw VALUES(m."the_geom",m."id_punt"*(-1),m."id",0,m."node",0,0,0);
RETURN NEXT m;
END LOOP;
RETURN;
END
$BODY$
LANGUAGE 'plpgsql' ;
PERFORM "the_geom" FROM coverage();

After that, is necessary to modify the ‘fraction_sections_raw’ table, in order to obtain the complete 500m coverage.

  • Update ‘fraccio_inicial’ table with the calculated value.
  • Update ‘cost_directe’ and ‘cost_invers’ fields with corresponding values.
  • Update ‘fraccio’ field with the calculated values.
  • Modify the geometry using the calulated ‘fraccio’ field.
update "fraction_sections_raw" set "fraccio_inicial"="poi_tmp"."fraction" from "poi_tmp" where "id_tram"="edge_id";
update "fraction_sections_raw" set "cost_directe"="network"."cost", "target"="network"."target", "cost_invers"="network"."reverse_cost" from "network" where "id_tram"="id";
UPDATE "fraction_sections_raw" SET "fraccio"=((case when ("fraction_sections_raw"."fraccio_inicial" * ST_Length("fraction_sections_raw"."the_geom"))>dist_var then (dist_var/ST_Length("fraction_sections_raw"."the_geom")) else "fraction_sections_raw"."fraccio_inicial" end)+(case when ((1-"fraction_sections_raw"."fraccio_inicial") * ST_Length("fraction_sections_raw"."the_geom"))>dist_var then (dist_var/ST_Length("fraction_sections_raw"."the_geom")) else (1-"fraction_sections_raw"."fraccio_inicial") end));
update "fraction_sections_raw" set "the_geom"=final."the_geom"from(select distinct(ST_Line_Substring((m."the_geom"),(case when (select ST_Line_Locate_Point((m."the_geom"), (select "the_geom" from "geo_final_nodes_tmp" where "geo_final_nodes_tmp"."id"=m."node" and "geo_final_nodes_tmp"."start_vid" = m."punt_id"*-1)))<0.01 then 0 else 1-m."fraccio" END),(case when (select ST_Line_Locate_Point((m."the_geom") , (select "the_geom" from "geo_final_nodes_tmp" where "geo_final_nodes_tmp"."id"=m."node" and "geo_final_nodes_tmp"."start_vid" = m."punt_id"*-1)))<0.01 then m."fraccio" else 1 END)))  the_geom,m."id_tram"from "fraction_sections_raw" m where m."id_tram" in (select "edge_id" from "poi_tmp")) final where final."id_tram" ="fraction_sections_raw"."id_tram";
insert into "fraction_sections_raw" (select SX."the_geom",PI."pid" as punt_id,SX."id"as id_tram,999 as fraccio,SX."source" as node,PI."fraction" as fraccio_inicial , SX."cost",SX."reverse_cost" from "network" SX inner join (Select "edge_id","pid","fraction" from "poi_tmp") PI on SX."id"=PI."edge_id");
UPDATE "fraction_sections_raw" set "the_geom"=final."the_geom" from (select ST_Line_Substring((SXI."the_geom"),(case when (FT."fraccio_inicial" - (dist_var/ST_Length(SXI."the_geom")))>0 then (FT."fraccio_inicial"-(dist_var/ST_Length(SXI."the_geom"))) else 0 end),(case when (FT."fraccio_inicial" + (dist_var/ST_Length(SXI."the_geom")))<1 then (FT."fraccio_inicial"+(dist_var/ST_Length(SXI."the_geom"))) else 1 end)) as the_geom, FT."punt_id", FT."id_tram", FT."fraccio" from "fraction_sections_raw"FT inner join (select SX."the_geom" as the_geom, SX."id" as tram_xarxa from "orig_network" SX, "poi_tmp" PI where SX."id"=PI."edge_id") SXI on FT."id_tram"=SXI.tram_xarxa where FT."fraccio"=999) final where "fraction_sections_raw"."punt_id"=final."punt_id" and "fraction_sections_raw"."fraccio"=999;
  • Create ‘fractions_sections_tmp’ table that will contain every section that conform the 500m coverage.
  • Create ‘driving_distance’ table that will contain the union of every section.
DROP TABLE IF EXISTS fraction_sections_tmp;
CREATE TABLE fraction_sections_tmp AS (select distinct(the_geom),punt_id,radi_inic from fraction_sections_raw);
DROP TABLE IF EXISTS driving_distance;
CREATE TABLE IF NOT EXISTS driving_distance AS (Select ST_Union(TOT.the_geom) the_geom, TOT."punt_id" from (select the_geom,punt_id,radi_inic from fraction_sections_tmp) TOT group by TOT."punt_id");
END $$;

Once executed the previous code, you should have the same as you can see in the Figure 4.

fig4

Fig 4.  Final 500m coverage.

In Figure 4 you can see the final sections cutted where the 500m path finishes. You can compare with Figure 3 and see the differences.

Conclusions

As a final conclusion, we created a function that obtains the coverage through a network , from a given starting point and a given distance or cost function. Improving the result obtained using the functions of the ‘pgrouting’ library.

 

The designed function is applicable to any routing function in which starts from initial points, that can be outside of the network, to obtain the desired coverage.

The code can be downloaded here.

Manual d’ús de l’usuari: Cerca de trajectes a entitats

Aquest document explica el funcionament del mòdul de ‘Cerca de Trajectes a Entitats’ per a QGIS. Aquest mòdul permet obtenir els trajectes o camins entre una adreça qualsevol de Mataró entrada per l’usuari i les N entitats més properes (també escollides per l’usuari). El cost pot estar en funció de la distància o el temps. Els desplaçaments obtinguts es mostren de forma ordenada de menys a més cost en forma de taula i de capa. Per a poder utilitzar-lo, el primer que s’ha de fer és executar el programa QGIS i un cop inicialitzat aquest, cal pitjar la icona següent CTE2o anar a Complementos -> CCU -> Cerca de Trajectes a Entitats i s’obrirà una finestra com la que podem veure a continuació a la figura 1.

CTE1

Figura 1: Imatge de l’estat inicial del mòdul CTE

Aquest mòdul es pot dividir bàsicament en tres parts diferenciades: origen (1) , destí (2), connexió i botons (3).

1. Connexió i altres botons

La primera part a mostrar inclou els botons de funcionament del mòdul (d’esquerra a dreta):

  • Connexió: pestanya desplegable on es mostren totes les connexions.
  • Botó ‘Inici’: aquest botó inicia el procés de consulta del mòdul.
  • Botó ‘Sortir’: aquest botó tanca el mòdul.

CTE5

Figura 2: Connexió i botons

2. Origen

En aquesta part del mòdul l’usuari troba les eines per escollir el punt d’inici, més concretament l’adreça. Seguidament es descriuran les seves parts, començant per la part superior:

CTE3

Figura 3: Origen

El primer element que trobem és una camp de text per cerca el nom del carrer a on es troba l’origen. Inicialment, en el gran requadre inferior, s’hi llisten tots els noms de carrers i a mesura que es va introduint un nom, la llista es va actualitzant automàticament amb els noms que s’assemblen al nom que introdueix l’usuari fins a trobar el desitjat. Una vegada, s’ha trobat el carrer, cal fer doble clic en el nom perquè quedi ben especificat en el camp de text.

Posteriorment, s’ha d’escriure el número del portal que desitgem, juntament amb la lletra. En el cas de la lletra no és necessari escollir-ne una.

Per acabar, a la dreta del camp de text per introduir el nom hi ha un botó amb una creu (X) que permet esborrar el contingut del camp de text.

3. Destí

En aquesta part del mòdul, l’usuari pot escollir la capa de destí i les diferents característiques dels camins: cost, número de camins i aproximació en cas de no existir l’adreça desitjada.

Començant per la part superior, el primer que trobem és una pestanya desplegable on es mostren les diferents capes de punts que poden ser destí. Just a sota hi trobem els modes de cerca. El primer que trobem són dos botons, de color verd i vermell respectivament.

El botó “Més proper” escull l’adreça amb el número de portal més proper a la adreça que s’ha seleccionat, independentment de si és parell o senar, i sempre que l’adreça escollida per l’usuari no existeixi.

En canvi, el botó “Més proper Parell/Senar” escull el portal amb el número senar o parell en funció de quin dels dos tipus sigui el número que s’hagi escollit prèviament, i sobretot que no existeixi.

A la dreta d’aquests dos botons, hi ha una spin box que permet escollir el nombre de camins desitjats, en un rang de 1 a 10 camins. En el cas que el nombre de camins sigui superior al nombre d’entitats d’una capa, el número de camins serà tants com entitats tingui la capa escollida.

Després trobem una pestanya desplegable on es pot triar el cost dels camins: distància o temps. En el cas d’escollir la opció de temps, hi ha un check box que permet incloure en el cost el cost de nusos.

A sota hi ha un gran requadre que s’utilitza per mostrar els resultats de la cerca que s’ha realitzat. La taula que es mostra té dos columnes: la primera mostra el nom de l’entitat de destí i la segona mostra el cost: si és distància en metres i si és en temps en minuts.

Entre la opció del cost i el requadre de resultats hi ha un espai buit que un cop s’ha fet la consulta hi apareix l’adreça de l’origen.

CTE4

Figura 4: Secció de destí

Manual d’ús de l’usuari: Mapes descriptius de població

Aquest document explica el funcionament del plugin de ‘Mapes descriptius de població’ per a QGIS.  Per a poder utilitzar-lo, el primer que s’ha de fer és executar el programa QGIS i un cop inicialitzat aquest, cal pitjar la icona següent 101o anar a Complementos -> CCU -> Mapes descriptius de població i s’obrirà una finestra com la que podem veure a continuació a la figura 1, que és molt semblant a la interfície del plugin de la Taula Resum amb algunes diferències descrites en els apartats 1 i 4.
1054 quines capes volem treballar: illes, parcel·les, seccions, barris o districtes postals.

103

Fig 2. Mètode de treball

  1. A la part superior central, hi ha una pestanya desplegable amb les connexions disponibles (ja configurades prèviament) per a realitzar les operacions. Allà n’escollim una i seguidament la barra que hi ha just a sota n’indicarà l’estat.

104

Fig 3. Connexió i progrés

  1. A la zona lateral dreta hi podem trobar el selector de filtres que volem utilitzar per crear la consulta. Només cal pitjar el filtre que vulguem aplicar per poder-lo emprar. Just a sota hi trobem dos botons més: INICI i SORTIR. ‘Inici’ arrenca el procés de representació del mapa i en el cas que hi hagi algun error en la configuració dels paràmetres per a la construcció d’aquestes, el procés s’interromp i ens apareix un missatge amb l’error. I el botó sortir, tanca el plugin.

105

Fig 4. Opcions i ordres principals

  1. Finalment, a la part central, tenim requadre amb dos pestanyes amb les opcions: configuració de la capa de sortida i els filtres.

106
Fig 5. Pestanyes

Per una banda, a la pestanya de ‘Filtres’ podem trobar-hi un requadre amb cinc pestanyes per poder configurar els paràmetres de cada  filtre. Recordem que el filtre es defineix en aquesta pestanya però s’activa pel botó lateral de la figura 4. , s’han de fer les dues coses.

Seguidament els detallarem:

  • El primer que apareix és l’edat. En aquesta pestanya s’ha d’introduir en primer lloc una data segons la qual es vulgui fer l’estudi, per exemple 1 de maig de 2016. Després hem de posar el marge d’edat que volem definir en els camps edat mínima i edat màxima. Si volem fer una taula per les escoles bressol, cal posar 0 i 2 anys en els dos camps respectivament. Seleccionant la opció criteri restrictiu cercarem els nens que encara no hagin fet els 2 anys. En canvi seleccionant el criteri no restrictiu cercarem tots els nens que encara no han fet els tres anys.

107
Fig 6. Filtre per edat

  • El segon criteri que apareix és el gènere. Podem decidir que la nostra cerca sigui en funció d’homes o de dones.

108
Fig 7. Génere

  • A continuació tenim els estudis: podem fer un filtratge segons els estudis que la persona hagi declarat tenir en el padró.

109
Fig 8. Estudis

  • Un altre punt molt important seria l’origen no confondre amb nacionalitat.

Una cosa és el país d’origen, és a dir, on ha nascut la persona en qüestió i l’altre la nacionalitat. La segona és quelcom més complex d’explicar, ja que està subjecte als conceptes de “ius sanguini” i “ius soli”. En el primer cas, quelcom comú als països europeus, africans i la Xina, els nen/a tenen automàtica la nacionalitat d’origen dels pares. Això comporta, per exemple, que un nen/a nascuda de pares marroquins a Mataró tingui nacionalitat marroquina. En el segon cas, si neixes en un país de dret de “ius soli”, obtens la automàticament la nacionalitat del país on neixes. Aquesta és la situació de la majoria de països llatinoamericans.

Llavors, en aquesta finestra podem filtrar la nostre cerca segons diferents criteris:

  1. Pel país d’origen
  2. Per la zona del país d’origen
  3. Per que el seu país d’origen pertanyi a la unió europea.

110

Fig 9. Origen

  • Per últim la nacionalitat, que té els mateixos criteris de filtratge que en l’apartat anterior.

111

Fig 10 . Nacionalitat

Per altra banda, a la pestanya de ‘Configuració de la sortida’ hi trobem diferents opcions per a la visualització dels resultats obtinguts.

112

Fig 11. Configuració de la sortida

Seguidament s’explicaran detalladament de què consta cada element:

  1. En primer lloc escollim la opció amb la qual volem que es faci el càlcul. Podem escollir entre tres opcions:
    • Habitants absoluts: retorna el número absolut dels habitants afectats pel filtre que hem escollit.
    • Habitants relatius: retorna el percentatge d’habitants afectats pel filtre entre el número total de persones que viuen en l’entitat que hem escollit per fer la cerca.
    • Densitat: retorna la densitat de població que està afectada pel filtre en Habitants/km2.
  1. En segon lloc escollim entre dues opcions pel color de la capa de sortida: un color únic per a tota la capa on en podem en podem regular la transparència, o bé un degradat de colors per indicar el major o menor nombre de persones afectades, on podem escollir-ne el número de intervals i el mode del temàtic que vol dir la forma en que es defineix cada rang, igual nombre de incidències , igual amplada de l’interval etc.
  1. En tercer i últim lloc tenim la possibilitat d’afegir etiquetes i modificar-ne algunes de les seves propietats com ara la mida i el color de la lletra i també la visualització en escala. Els valors de l’escala de visualització tenen un valor per defecte per a cada tipus d’entitat, però es poden modificar sense cap mena de problema.

Una vegada aplicats els filtres a la cerca per qualsevol dels criteris explicats anteriorment i configurats els paràmetres de sortida, només cal pitjar el botó “INICI”.

 

Cobertura mitjançant graf de carrers

Al traçar una trajectòria a traves d’un graf de trams de carrer de manera que a partir d’un punt inicial es calculi fins allà on arriba una distancia determinada seguint el graf, és molt probable que aquesta distancia no coincideixi amb un nus concret sinó que estigui en un punt intermedi d’un segment.

En aquest article es presenta una forma d’obtenir la cobertura a partir d’un punt inicial fins que s’arriba a una distancia màxima seguint l’arbre del graf de trams de carrer, la contribució principal és el càlcul del darrer segment parcial en totes les trajectòries.

Concretament, en aquest article s’explica de quina manera s’ha resolt el problema que representa obtenir els trams complerts i parcials que conformen el càlcul d’una distància recorreguda pel graf de carrers, mitjançant la funció ‘pgr_withPointsDD’ del pgrouting des de punts exteriors al graf, es a dir, que no formen part dels nodes de la xarxa.

Per poder utilitzar el codi d’aquest article s’ha de tenir instal·lat en el PostgresSQL l’extensió ‘pgrouting’ que ens permet fer anàlisi de xarxes, per mes informació visiteu la pagina web (http://docs.pgrouting.org) i (http://pgrouting.org).

ATENCIO: Els següents passos modificaran la base de dades PostgresSQL, cal anar amb molt de compte ja que podeu inutilitzar bases de dades ja existents.

  • Descarregar la base de dades PostgresSQL, feu clic aquí.
  • Crear base de dades nova amb nom ‘db_temp’.
  • Restaurar la base de dades descarregada.

Un cop restaurada la base de dades PostgresSQL, s’ha de tenir 3 entitats:

  • “orig_network” (xarxa de carrers)
  • “origin” (punt d’inici)
  • “orig_network_vertices_pgr” (nodes de la xarxa de carrers)

Per entendre millor el procediment s’ha plantejat un exemple concret basat en un graf de trams de carrer totalment simètric i ortogonal, però seria aplicable a qualsevol graf.

Es parteix d’una xarxa ortogonal de carrers (“orig_network”) de 2.000 x 2.000 metres, amb trams de carrers de 100m de node a node i el punt inicial (“origin”) representat en vermell, tal i com es pot veure en la figura 1.

fig1

Fig 1. Xarxa ortogonal de carrers de 100m.

Procediment pel càlcul de cobertura mitjançant pgrouting.

Per calcular una cobertura de 500m des del punt vermell seguirem les següents passes:

  • Fer un duplicat de la xarxa al qual anomenarem ‘network’.
  • Crear una taula anomenada ‘poi_tmp’ on tindrà totes les geometries dels punts inicials, en el nostre cas només tindrà un valor.
  • Modificar la taula ‘poi_tmp’ afegint els camps (x,y,edge_id,side,fraction, newPoint);
DO $$
#variable_conflict use_variable
DECLARE dist_var INT;
BEGIN
dist_var:=500;DROP TABLE IF EXISTS "network";
CREATE TABLE IF NOT EXISTS "network" as (SELECT * FROM "orig_network");
drop table if exists poi_tmp;
CREATE TABLE if not exists poi_tmp as (SELECT ST_Centroid(tmp."geom") the_geom,tmp."id" as pid from (SELECT * FROM "origin") tmp);
ALTER TABLE poi_tmp ADD COLUMN     x FLOAT;
ALTER TABLE poi_tmp ADD COLUMN     y FLOAT;
ALTER TABLE poi_tmp ADD COLUMN     edge_id BIGINT;
ALTER TABLE poi_tmp ADD COLUMN     side CHAR;
ALTER TABLE poi_tmp ADD COLUMN     fraction FLOAT;
ALTER TABLE poi_tmp ADD COLUMN     newPoint geometry;
  • Actualitzar el camp ‘edge_id’ amb l’identificador del tram més proper.
  • Actualitzar el camp ‘fraction’ amb la fracció corresponent del tram abans trobat.
UPDATE "poi_tmp" set "edge_id"=nearest_section."tram_id" from (SELECT distinct on(Poi.pid) Poi.pid As Punt_id,Sg.id as Tram_id, ST_Distance(Sg.the_geom,Poi.the_geom) as dist FROM "network" as Sg,"poi_tmp" AS Poi ORDER BY Poi.pid, ST_Distance(Sg.the_geom,Poi.the_geom), Sg.id) nearest_section where "poi_tmp"."pid"=nearest_section."punt_id";
UPDATE "poi_tmp" SET fraction = ST_LineLocatePoint(e.the_geom, "poi_tmp".the_geom),newPoint = ST_LineInterpolatePoint(e.the_geom, ST_LineLocatePoint(e.the_geom, "poi_tmp".the_geom)) FROM "network" AS e WHERE "poi_tmp"."edge_id" = e.id;
  • Crear la taula ‘tbl_final_nodes_tmp’ que contindrà les ‘id’, els costos agregats i el node de partida de tots els nodes pels quals passa la funció ‘pgr_withPointsDD’.
  • Crear la taula ‘geo_final_nodes_tmp’ que contindrà els nodes anteriors amb la geometria corresponent.
DROP FUNCTION IF EXISTS coverage();
DROP TABLE IF EXISTS tbl_final_nodes_tmp;
CREATE TABLE IF NOT EXISTS tbl_final_nodes_tmp AS(SELECT node,agg_cost,start_vid FROM pgr_withPointsDD('SELECT id, source, target, cost, reverse_cost FROM "network" ORDER BY "network".id','SELECT pid, edge_id, fraction, side from "poi_tmp"',array(select "pid"*(-1) from "poi_tmp"),dist_var,driving_side := 'b',details := false));
DROP table if exists geo_final_nodes_tmp;
CREATE TABLE IF NOT EXISTS geo_final_nodes_tmp as (select "orig_network_vertices_pgr".*,"tbl_final_nodes_tmp"."agg_cost", "tbl_final_nodes_tmp"."start_vid", dist_var from "orig_network_vertices_pgr","tbl_final_nodes_tmp" where "orig_network_vertices_pgr"."id" ="tbl_final_nodes_tmp"."node" order by "tbl_final_nodes_tmp"."start_vid" desc,"tbl_final_nodes_tmp"."agg_cost");

Després d’executar el codi anterior obtenim la imatge mostrada a la figura 2. El punt blau indica la projecció del punt de partida sobre el tram més proper, que serà d’on començaran tots els camins.

fig2

Fig 2. Nodes que queden dins de la cobertura.

El que ens retorna la funció ‘pgr_withPointsDD’ son els nodes que queden dins de la cobertura, però si volem saber els trams que composen la cobertura de 500 metres, veurem que no sabem quins son els trams finals de la cobertura que quedarien incomplerts.

Per tal de resoldre aquest problema, s’ha de fer el següent:

  • Crear la taula ‘final_sections_tmp’ on tindrem tots els trams que formen part de la cobertura , inclosos els trams finals dels quals només és vàlida una fracció del mateix.
DROP table IF EXISTS final_sections_tmp;
CREATE TABLE IF NOT EXISTS final_sections_tmp as (select "network"."id","network"."the_geom","geo_final_nodes_tmp"."id" as node,"geo_final_nodes_tmp"."agg_cost" as coste,(dist_var  "geo_final_nodes_tmp"."agg_cost") as falta,"geo_final_nodes_tmp"."start_vid" as id_punt,  (select case when (dist_var-"geo_final_nodes_tmp"."agg_cost") / ST_Length("network"."the_geom")<=1 then (dist_var-"geo_final_nodes_tmp"."agg_cost") / ST_Length("network"."the_geom") when (dist_var-      "geo_final_nodes_tmp"."agg_cost") / ST_Length("network"."the_geom")>1 then (1) end) as      fraccio from "network","geo_final_nodes_tmp" where ST_DWithin("geo_final_nodes_tmp"."the_geom", "network"."the_geom",1)=TRUE);

En la figura 3 es mostra el resultat d’executar el codi anterior.

fig3

Fig 3. Trams que formen part de la cobertura de 500 metres.

Per tal d’obtenir les fraccions del trams finals que completen la cobertura de 500 metres, s’ha creat una funció en ‘PL/pgSQL’, la qual realitza les modificacions necessàries.

  • Crear la funció ‘Coverage’ que realitzarà el procés.
  • Crear la taula ‘fraction_sections_raw’ que contindrà el trams (complerts i fraccions) que composen la cobertura de 500 metres.
CREATE OR REPLACE FUNCTION coverage() RETURNS SETOF final_sections_tmp AS
$BODY$
DECLARE
r final_sections_tmp%rowtype;
m final_sections_tmp%rowtype;
BEGIN
DROP TABLE IF EXISTS fraction_sections_raw;
CREATE TABLE fraction_sections_raw (the_geom geometry, punt_id bigint,id_tram bigint,fraccio FLOAT,node bigint,fraccio_inicial FLOAT,cost_invers FLOAT,cost_directe FLOAT,target bigint,radi_inic FLOAT);
FOR r IN SELECT "final_sections_tmp".* FROM "final_sections_tmp" WHERE "final_sections_tmp"."id" not in (select "edge_id" from "poi_tmp")
LOOP
insert into fraction_sections_raw VALUES(ST_Line_Substring((r."the_geom"),case when (select ST_Line_Locate_Point((r."the_geom"),(select "geo_final_nodes_tmp"."the_geom" from "geo_final_nodes_tmp" where "geo_final_nodes_tmp"."id"=r."node" and "geo_final_nodes_tmp"."start_vid"=r."id_punt")))<0.001 then 0 else 1-r."fraccio"
END,
case when (select ST_Line_Locate_Point((r."the_geom"),(select "geo_final_nodes_tmp"."the_geom" from "geo_final_nodes_tmp" where "geo_final_nodes_tmp"."id"=r."node" and "geo_final_nodes_tmp"."start_vid"=r."id_punt")))<0.001 then r."fraccio" else 1
END),r."id_punt"*(-1),r."id",0,r."node",0,0,0,0);
RETURN NEXT r;
END LOOP;
FOR m IN SELECT "final_sections_tmp".* FROM "final_sections_tmp" WHERE "final_sections_tmp"."id" in (select "edge_id" from "poi_tmp")
LOOP
insert into fraction_sections_raw VALUES(m."the_geom",m."id_punt"*(-1),m."id",0,m."node",0,0,0);
RETURN NEXT m;
END LOOP;
RETURN;
END
$BODY$
LANGUAGE 'plpgsql' ;
PERFORM "the_geom" FROM coverage();

Tot seguit es modifica la taula ‘fraction_sections_raw’ per tal d’obtenir els trams finals que corresponen a la cobertura de 500 metres.

  • Actualitzar ‘fraccio_inicial’ amb el valor que li pertoca.
  • Actualizar ‘’cost_directe’, ‘cost_invers’ amb els valors corresponents.
  • Actualitzar ‘fraccio’ amb el valors calculats dels trams finals.
  • Modificar la geometria segons el camp ‘fraccio’ calculat.
update "fraction_sections_raw" set "fraccio_inicial"="poi_tmp"."fraction" from "poi_tmp" where "id_tram"="edge_id";
update "fraction_sections_raw" set "cost_directe"="network"."cost", "target"="network"."target", "cost_invers"="network"."reverse_cost" from "network" where "id_tram"="id";
UPDATE "fraction_sections_raw" SET "fraccio"=((case when ("fraction_sections_raw"."fraccio_inicial" * ST_Length("fraction_sections_raw"."the_geom"))>dist_var then (dist_var/ST_Length("fraction_sections_raw"."the_geom")) else "fraction_sections_raw"."fraccio_inicial" end)+(case when ((1-"fraction_sections_raw"."fraccio_inicial") * ST_Length("fraction_sections_raw"."the_geom"))>dist_var then (dist_var/ST_Length("fraction_sections_raw"."the_geom")) else (1-"fraction_sections_raw"."fraccio_inicial") end));
update "fraction_sections_raw" set "the_geom"=final."the_geom"from(select distinct(ST_Line_Substring((m."the_geom"),(case when (select ST_Line_Locate_Point((m."the_geom"), (select "the_geom" from "geo_final_nodes_tmp" where "geo_final_nodes_tmp"."id"=m."node" and "geo_final_nodes_tmp"."start_vid" = m."punt_id"*-1)))<0.01 then 0 else 1-m."fraccio" END),(case when (select ST_Line_Locate_Point((m."the_geom") , (select "the_geom" from "geo_final_nodes_tmp" where "geo_final_nodes_tmp"."id"=m."node" and "geo_final_nodes_tmp"."start_vid" = m."punt_id"*-1)))<0.01 then m."fraccio" else 1 END)))  the_geom,m."id_tram"from "fraction_sections_raw" m where m."id_tram" in (select "edge_id" from "poi_tmp")) final where final."id_tram" ="fraction_sections_raw"."id_tram";
insert into "fraction_sections_raw" (select SX."the_geom",PI."pid" as punt_id,SX."id"as id_tram,999 as fraccio,SX."source" as node,PI."fraction" as fraccio_inicial , SX."cost",SX."reverse_cost" from "network" SX inner join (Select "edge_id","pid","fraction" from "poi_tmp") PI on SX."id"=PI."edge_id");
UPDATE "fraction_sections_raw" set "the_geom"=final."the_geom" from (select ST_Line_Substring((SXI."the_geom"),(case when (FT."fraccio_inicial" - (dist_var/ST_Length(SXI."the_geom")))>0 then (FT."fraccio_inicial"-(dist_var/ST_Length(SXI."the_geom"))) else 0 end),(case when (FT."fraccio_inicial" + (dist_var/ST_Length(SXI."the_geom")))<1 then (FT."fraccio_inicial"+(dist_var/ST_Length(SXI."the_geom"))) else 1 end)) as the_geom, FT."punt_id", FT."id_tram", FT."fraccio" from "fraction_sections_raw"FT inner join (select SX."the_geom" as the_geom, SX."id" as tram_xarxa from "orig_network" SX, "poi_tmp" PI where SX."id"=PI."edge_id") SXI on FT."id_tram"=SXI.tram_xarxa where FT."fraccio"=999) final where "fraction_sections_raw"."punt_id"=final."punt_id" and "fraction_sections_raw"."fraccio"=999;
  • Crear la taula ‘fractions_sections_tmp’ que contindrà els trams sense duplicats de la cobertura de 500m.
  • Crear la taula ‘driving_distance’ que contindrà la unió de tots els trams.
DROP TABLE IF EXISTS fraction_sections_tmp;
CREATE TABLE fraction_sections_tmp AS (select distinct(the_geom),punt_id,radi_inic from fraction_sections_raw);
DROP TABLE IF EXISTS driving_distance;
CREATE TABLE IF NOT EXISTS driving_distance AS (Select ST_Union(TOT.the_geom) the_geom, TOT."punt_id" from (select the_geom,punt_id,radi_inic from fraction_sections_tmp) TOT group by TOT."punt_id");
END $$;

Un cop executat tot el codi el resultat és el que es mostra en la figura 4.

fig4

Fig 4. Cobertura final de 500 metres.

En aquesta figura es poden veure els segments finals dels trajectes a partir del punt projectat amb la seva autèntica dimensió, implicant per tant només un fragment del tram sencer correspondent, es pot comparar amb la figura 3 per veure la diferència de resultats.

Conclusions

Com a conclusió finals del article, podem dir que s’ha creat una funció per obtenir la cobertura a partir d’un punt amb distància o funció  de cost constant a partir d’un punt d’inici projectat sobre del graf, donant un resultat exacte.

Millorant, així, el resultat que es podria obtenir només amb les funcions pròpies de la llibreria del ‘pgrouting’.

La funció dissenyada es aplicable a qualsevol funció de rutatge en la que es parteixi d’uns punts inicials, que formin, o no, part del graf, i obtenir la cobertura desitjada.

El codi sencer es pot descarregar del següent enllaç.

Manual d’ús del mòdul ‘Zones d’influència adaptatives’

Aquest document explica el funcionament del plugin de ‘Zones d’influència adaptatives’ per a QGIS.  Per a poder utilitzar-lo, el primer que s’ha de fer és executar el programa QGIS i un cop inicialitzat aquest, cal pitjar la icona següent1

o anar a Complements -> CCU -> Zones d’influència adaptatives i s’obrirà una finestra com la que podem veure a continuació a la imatge.

2

Aquest mòdul el que fa és ajustar la zona d’influència de cada entitat proveïdora d’un servei a la població a la capacitat de cada centre (que s’ha de fixar en la BD prèviament), tenint en compte la densitat de la problació ‘target’ del seu entorn. Aquesta zona d’influència pot ser circular o seguint el Graf de Trams de Carrer.

A continuació es detallaran els diferents components del plugin i quina és la seva funció:

  1. A la part superior, hi ha un barra on s’hi indica l’estat de la connexió i una pestanya desplegable amb les connexions disponibles (ja configurades prèviament) per a realitzar les operacions. Allà n’escollim una.3
  2. En aquesta part escollirem la capa de punts a partir de la qual volem fer la zona d’influència i el color que tindrà.4
  3. Just a sota trobarem tres botons que ens permetran escollir la capa sobre la que volem treballar: Illes, parcel·les o portals.5
  4. En aquesta secció cal introduir un número de iteracions que volem que es realitzin.6
    Hem de tenir present que el programa fa el recalcul del següent radi (o distància) a partir del nombre de persones trobades prèviament dins de la zona i això ho pot fer una vegada (cas de una iteració) o unes quantes, poguent anar refinant l’ajust, però amb augment del temps de càlcul.
  1. En l’apartat de cobertura caldrà dir el percentatge de població sobre el qual volem fer l’estudi. També marcarem el checkBox en el cas que vulguem que es mostri la població no afectada per la zona d’influència. Una vegada realitzada la operació, ens apareixerà el nombre d’habitants no coberts en el requadre blanc, a la part inferior.7
  2. Aquí cal introduir el radi inicial a partir del qual treballarem amb les entitats puntuals. Es una radi inicial mitjà a partir del qual i segons la capacitat de cada centre s’assigna el radi inicial particular de cada un.8
  3. En aquest apartat es pot escollir zones d’influència de graf si se selecciona l’opció ‘fer servir trams’. En cas contrari, les zones d’influència són circulars. En cas de fer servir trams, podem fer que es vegi el dibuix del graf marcan el checkBox corresponent. També es pot modificar el radi de la zona d’influència canviant el valor en el textBox.9
  4. En el cas que la opció de ‘fer servir trams’ estigui habilitada, cal escollir un graf sobre la qual treballar, mitjançant la pestanya desplegable. També podem escollir el color de l’àrea d’influència i modificar el traç amb la pestanya desplegable inferior.10
  5. En últim lloc, a la part inferior de la finestra podem trobar la versió de la plugin amb la que estem treballant i dos botons: ‘INICI’ per començar el processament de les dades i ‘SORTIR’ per tancar el plugin.11

 

Manual de preparació de l’entorn d’usuari QGIS

En aquesta secció s’expliquen els passos a seguir per instal·lar el programa QGIS en el nostre entorn. El primer pas a seguir és anar al lloc web de QGIS (www.qgis.org) i dirigir-se a l’apartat de descàrregues (http://qgis.org/es/site/forusers/download.html). Allà es podran trobar dues versions del programa: la versió més recent i la de llarg termini. Qualsevol de les dues és perfectament vàlida, tot i que si l’usuari del programa treballa per una empresa o institució pública, recomanem la versió de llarg termini. Un cop escollida la versió, només cal descarregar-la.27

Un cop descarregada, cal instal·lar-la en el nostre equip. Només cal que fem doble clic a l’arxiu que hem descarregat prèviament. Llavors s’executarà l’instal·lador i només cal seguir els passos que ens indica. Un cop completat aquest procés, ja podrem executar el QGIS.

Per poder instal·lar els plugins que s’utilitzen per tractar les dades cal anar a Complementos à Administrar e instalar complementos… i ens apareixerà una finestra com la següent:28 Anem a la pestanya de configuració.29

Marcarem la opció de “comprovar actualitzacions a l’inici”, que es troba a la part superior, i posteriorment escollirem la periodicitat de l’acció amb les diferents opcions del desplegable que podem trobar just a sota.
També és necessari afegir el repositori on es troben els plugins necessaris per treballar. Cal prémer el botó Añadir…, que es troba a la part inferior, i ens apareixerà la finestra que es mostra a continuació.30

En el camp de nom cal afegir un nom com per exemple “Plugins CCU Tecnocampus” i en el camp de la URL cal posar http://geoportalccu.tecnocampus.cat/plugins.xml. Un cop fet, acceptem i tornem a l’apartat de Todos. A la part superior hi podrem trobar un barra de cerca on buscarem els plugins necessaris: TaulaResum, Activitats Econòmiques i ZI-GTC.

Un cop els trobem, pitgem sobre ells i finalment només caldrà instal·lar-los en el nostre equip.31

Aleshores només cal tancar la finestra i afegir les connexions a la base de dades per a poder treballar amb el QGIS. Per últim només ens farà falta configurar la connexió amb la base de dades. Per poder-ho fer cal seguir els següents passos:

Primer cal cercar a la barra d’eines en el lateral esquerra de la nostra pantalla una icona com aquesta 32Un cop ho haguem fet, ens apareixerà una finestra com la de la figura 1. En allà cal prémer el botó “Nueva”, tal i com està senyalitzat a la mateixa figura. Posteriorment ens ha d’aparèixer una finestra com la de la figura 2. En allà cal introduir els camps necessaris per configurar la connexió: usuari, nom de la base de dades, servidor i contrasenya. Una vegada fet, només es necessari prémer el botó Acceptar de les dues finestres mencionades prèviament i ja tindríem l’entorn preparat per treballar.

33Figura 134

Figura 2

Manual d’ús del mòdul ‘ZI-GTC’

Aquest post explica el funcionament del plugin de ‘ZI-GTC’ per a QGIS.  Per a poder utilitzar-lo, el primer que s’ha de fer és executar el programa QGIS i un cop inicialitzat aquest, cal pitjar la icona següent17 o anar a Complementos -> CCU -> Càlcul de població afectada i s’obrirà una finestra com la que podem veure a continuació a la imatge.18_2

A continuació es detallaran els diferents components del plugin i quina és la seva funció:

  1. Comencem per la part superior, on hi trobem una pestanya desplegable i un requadre. A la pestanya s’escull la connexió amb la que volem treballar, i que prèviament hem configurat en el QGIS. En el requadre indica l’estat de la connexió.19
  2. En segon lloc, trobem una pestanya desplegable on hi podem seleccionar la entitat puntual sobre la qual volem treballar.20
  3. Just a sota, podem trobar una altra pestanya desplegable. En aquesta ocasió tindrem la possibilitat d’escollir la xarxa de carrers sobre la qual volem treballar. Per poder utilitzar la capa, cal que disposem d’accés a una taula auxiliar amb els vèrtex. Cada vegada que seleccionem una capa de graf, el plugin s’encarrega de comprovar que la capa auxiliar hi sigui. En el cas que no hi sigui, un missatge apareixerà per tal d’informar de la situació a l’usuari.21
  1. En quart lloc, hi ha el menú per seleccionar el mètode de treball: primer trobem un desplegable per treballar sobre la distància o el temps. Just a dreta hi trobem dos checkBox que només s’activen quan en el desplegable hi ha escollida la opció de ‘Temps’ i que s’utilitzen per indicar si volem utilitzar el cost invers i el de nusos. Després hi ha un camp per omplir text on l’indicarem amb un número la distància o el temps amb la que volem fer el buffer, i en últim lloc hi ha una pestanya desplegable on hi podrem escollir el camp de la taula de la xarxa de carrers que s’utilitzarà com a camp de distància o temps, segons s’hagi escollit.22
  1. Just després del mètode de treball, hi trobem les opcions d’aparença del graf. Primer hi ha un checkBox que habilita el botó amb el qual s’escull el color i una pestanya on s’escull el gruix del traç. A més a més, hi ha un camp on hi podem indicar el radi en metres de la zona d’influència de l’entorn del graf.23
  1. Seguidament hi ha una pestanya on podem escriure el títol de la llegenda. En el moment en què escollim una entitat puntual, aquest camp s’actualitzarà automàticament per “<nom de la entitat>”. Tot i això, el títol pot ser el que nosaltres vulguem.24
  1. Després d’això, trobarem l’apartat on seleccionarem el mètode per treballar amb la població. Primer trobarem un checkBox on indicarem si volem treballar amb la població. En cas afirmatiu, ens apareixerà el menú amb les opcions just a sota. En aquest menú hi apareixen 3 botons on indicarem si volem treballar amb les illes, parcel·les o portals. En la part inferior hi ha una etiqueta blanca on hi apareix el percentatge d’habitants afectats per la zona d’influència del càlcul, un cop realitzat. A la dreta hi ha un checkBox on hi indicarem si volem que es mostri la població exclosa.25
  2. Finalment, a la part inferior de la finestra hi ha dos botons: el de ‘SORTIR’ i el de processar o ‘INICI’. El de SORTIR serveix per tancar la pestanya. El botó ‘INICI’ serveix per processar la consulta que li hem indicat amb els elements que acabem de veure. Segons les opcions que li haguem indicat, ens apareixerà un resultat o un altre. En el cas que alguna de les dades o la connexió no sigui correcta, el programa advertirà de la incidència a l’usuari. Un cop aquesta sigui resolta, l’usuari podrà executar el programa amb normalitat.26

Manual d’ús del mòdul ‘Activitats econòmiques’

Aquest post explica el funcionament del plugin de ‘Activitat Econòmica’ per a QGIS.  Per a poder utilitzar-lo, el primer que s’ha de fer és executar el programa QGIS i un cop inicialitzat aquest, cal pitjar la icona següent  1 o anar a Complementos -> CCU -> Epígrafs i s’obrirà una finestra com la que podem veure a continuació a la imatge.
2
Aquest mòdul disposa de dues pestanyes principals: ‘Llista d’Activitats Econòmiques’ i ‘Altres operacions’. Començarem per la primera, que és la que apareix a la figura anterior:

  1. En primer lloc trobem 2 botons on podem escollir el mètode de treball, ja sigui amb parcel·les o número de policia.3
  2. A la dreta hi ha una pestanya desplegable on hi podrem escollir les connexions que prèviament haurem configurat en el QGIS.4
  3. Una vegada ens haguem connectat, en el requadre gran central ens apareixerà una llista amb totes les activitats econòmiques, on les podem trobar de dues maneres: per nom i per número d’epígraf. 5Ho podem escollir per mitjà de les dues pestanyes que podem trobar a la part superior del requadre.6Per tal de facilitar la feina, podem fer una cerca de l’epígraf desitjat per mitjà de la pestanya de cerca.7A mesura que anem seleccionant activitats econòmiques, ens apareixerà una barra superior temporal de color blau on hi podrem trobar informació referent als elements: número d’elements seleccionats tan en la llista d’epígraf per número com la de descripció. A l’esquerra d’aquesta informació ens apareixerà un botó, que si el pitgem, ens farà aparèixer una finestra on hi hauran llistat tots elements seleccionats.8A més a més, cada llista disposa d’un botó per poder des seleccionar tots els elements de la llista que haguem seleccionat prèviament.16
  1. A la part inferior de la finestra hi ha una etiqueta que ens indica l’estat de la connexió. Just a la dreta hi podem trobar dos botons: el botó ‘INICI’ processa les dades que li hem introduït i fa els càlculs pertinents per tal d’obtenir els resultats desitjats. En el moment en que s’estiguin realitzant la operació, l’etiqueta de la connexió ho indicarà. En canvi, el botó ‘SORTIR’ tanca el mòdul.9

Ara canviem a la pestanya de ‘Altres operacions’.10

Cal dir que segons les opcions que triem en la pestanya anterior, es mostraran o s’ocultaran diferents opcions. Tot seguit explicarem quines són:

  1. La opció de càlcul de radi consisteix en un camp on hi introduirem el valor de la variable K que correspon a la longitud del diàmetre del punt de l’entitat sobre la qual estem treballant. Per tant, com més gran sigui K, més gran serà el punt. Just al costat hi ha un botó per indicar el color del punt. Quan el cliquem se’ns obra un diàleg amb una paleta de colors per escollir. Cal afegir també que aquesta opció només és visible quan la opció de treballar amb números de policia de l’altre pestanya està activa.11
  1. En segon lloc hi trobem el camp on hi introduïm el títol de la llegenda que li volem donar a la entitat nova. Sempre hi ha un títol per defecte però podem posar el que sigui necessari. Aquesta opció sempre és visible.12
  2. Just a la dreta de les dues opcions anterior, hi trobem la de ‘Dibuixar zones d’influència’. A la part superior hi ha un checkBox que marcarem en el cas que vulguem veure les zones d’influència. En cas afirmatiu, just a sota apareixerà un submenú i es farà visible la opció de l’apartat 4, que posteriorment explicarem. Començant per la part superior i baixant, primer trobem un camp on hi podem indicar el radi o distància en metres de la zona d’influència segons si volem que aquesta sigui circula o de graf. Seguidament hi ha un botó per indicar el color, tal i com el que hem vist a l’apartat del càlcul del radi (1). Per complementar el color, també en podem indicar la transparència a la barra graduada. Si li indiquem que volem un 0% de transparència ens mostrarà una capa totalment opaca. Altrament, si li indiquem que volem un 100% de transparència, ens mostrarà la capa totalment transparent. En última posició hi trobem dos botons que serveixen per indicar si volem que la zona d’influència sigui circular o de graf. En el cas que sigui de graf, apareixerà la opció de l’apartat 5, que posteriorment explicarem.13
  3. La opció 4 és la de ‘Població’. Aquí indicarem si la zona d’influència volem que estigui relacionada amb la població. Per fer-ho cal marcar la opció del checkBox que trobem en primer lloc. Llavors trobem un desplegable on triarem el color del degradat per indicar les illes de població exclosa. El color tindrà més intensitat en funció de si en aquella illa hi ha més o menys població exclosa. En últim lloc hi trobem un altre checkBox que servirà per indicar volem que es mostri la zona d’influència o no.14
  4. Per acabar explicarem un submenú que es fa visible quan indiquem que volem la zona d’influència en forma de graf, explicat a l’apartat 3. En aquesta part tenim la possibilitat de escollir si fer el graf en funció de la distància o del temps a la pestanya desplegable que hi ha a la part superior. En el cas que s’esculli la opció del temps, dos checkBox apareixeran. Aquests ens permetran escollir el cost que volem utilitzar: cost de nusos o cost invers. Després podrem veure un camp on li indicarem el radi que volem que tingui el graf de la zona d’influència i també tindrem la possibilitat d’escollir el color. Finalment, trobem un checkBox on indicarem si volem pintar en el mapa l’esquelet del graf de la zona d’influència.15

Manual d’ús del mòdul ‘TaulaResum’

Aquest document explica el funcionament del plugin de ‘Taula Resum’ per a QGIS.  Per a poder utilitzar-lo, el primer que s’ha de fer és executar el programa QGIS i un cop inicialitzat aquest, cal pitjar la icona de la figura 1 o anar a Complementos -> CCU -> Taula Resum i s’obrirà una finestra com la que podem veure a la figura 2.

icona figura 1

inici figura 2

A continuació es detallaran els diferents components del plugin i quina és la seva funció:

  1. A la part superior esquerra, hi ha un rectangle on hi indicarem sobre quines capes volem treballar: illes, parcel·les, portals o totes tres alhora.met-treb
  2. A la part superior central, hi ha una pestanya desplegable amb les connexions disponibles (ja configurades prèviament) per a realitzar les operacions. Allà n’escollim una i seguidament la barra que hi ha just a sota n’indicarà l’estat.connexio
  3. A la zona lateral dreta hi podem trobar el selector de filtres que volem utilitzar per crear les taules. Només cal pitjar el filtre que vulguem aplicar per poder-lo emprar. Just a sota hi trobem dos botons més: crear taula i sortir. Crear taula inicia el procés de creació de taules i en el cas que hi hagi algun error en la configuració dels paràmetres per a la construcció d’aquestes, el procés s’interromp i ens apareix un missatge amb l’error. I el botó sortir, tanca el plugin.filtres
  4. Finalment, a la part central, tenim requadre amb cinc pestanyes amb les opcions per poder configurar els paràmetres de cada filtre. Seguidament els detallarem:
    • El primer que apareix és l’edat. En aquesta pestanya s’ha d’introduir en primer lloc una data segons la qual es vulgui fer l’estudi, per exemple 1 de maig de 2016. Després hem de posar el marge d’edat que volem definir en els camps edat mínima i edat màxima. Si volem fer una taula per les escoles bressol, cal posar 0 i 2 anys en els dos camps respectivament. Seleccionant la opció criteri restrictiu cercarem els nens que encara no hagin fet els 2 anys. En canvi seleccionant el criteri no restrictiu cercarem tots els nens que encara no han fet els tres anys.

pest

    • El segon criteri que apareix és el gènere. Podem decidir que la nostra cerca sigui en funció d’homes o de dones.

pest2

    • A continuació tenim els estudis: podem fer un filtratge segons els estudis que la persona hagi declarat tenir en el padró.

pest3

  • Un altre punt molt important seria l’origen no confondre amb nacionalitat. Una cosa és el país d’origen, és a dir, on ha nascut la persona en qüestió i l’altre la nacionalitat. La segona és quelcom més complex d’explicar, ja que està subjecte als conceptes de “ius sanguini” i “ius soli”. En el primer cas, quelcom comú als països europeus, africans i la Xina, els nen/a tenen automàtica la nacionalitat d’origen dels pares. Això comporta, per exemple, que un nen/a nascuda de pares marroquins a Mataró tingui nacionalitat marroquina. En el segon cas, si neixes en un país de dret de “ius soli”, obtens la automàticament la nacionalitat del país on neixes. Aquesta és la situació de la majoria de països llatinoamericans. Llavors, en aquesta finestra podem filtrar la nostre cerca segons diferents criteris:
    1. Pel país d’origen
    2. Per la zona del país d’origen
    3. Per que el seu país d’origen pertanyi a la unió europea.

pest4

    • Per últim la nacionalitat, que té els mateixos criteris de filtratge que en l’apartat anterior.

pest5

Una vegada aplicats els filtres a la cerca per qualsevol dels criteris explicats anteriorment, ja podem crear la teva taula resum, seleccionant tots els botons dels filtres sobre els quals volem fer la cerca i posteriorment pitjant al botó “crear taula”.

Creació del plugin ‘Taula Resum’

Introducció

En aquest post es podrà llegir els passos que cal seguir per a construir el plugin ‘Taula Resum’ per a QGIS.

En el plugin ‘TaulaResum’ cal destacar el canvi de filosofia que s’ha produït amb el canvi de GeoMedia, el qual treballa amb bases de dades locals, al QGIS. En canvi amb aquest últim hem passat a treballar amb un topologia client-servidor, que permet que tots els usuaris que disposin de les credencials podran accedir a les bases de dades sempre que vulguin i des de qualsevol lloc. I només el cal tenir el mòdul QGIS amb el mòdul instal·lat i podran treballar.

Sempre que fem referència a qualsevol element de l’entorn de programació o QGIS, aquest és explicat en el post sobre ‘com preparar l’entorn’.

Procés de creació

Disseny de la interfície

El primer que vam fer va ser la creació de la interfície del plugin. Un cop hem creada l’estructura del plugin amb el ‘Plugin Builder’, vam obrir l’arxiu amb format *.ui amb el Qt Designer i començarem amb la creació. Primer va caldre posar les pestanyes més exteriors (QTab Widget) i dimensionar-lo de manera adequada. Al voltant, vam afegir els elements que ajudaran a escollir els filtres, els mètodes de treball, l’elecció de la connexió i els botons per crear la taula i sortir. Un costum que tenim és el de posar una etiqueta amb la versió de la plugin, ja que ajuda a la identificació de quines són les funcions que pot tenir un plugin. Els plugins poden patir diferents actualitzacions i les funcions poden variar. En el cas de que hi hagi un error en una versió que no és la més recent, l’etiqueta facilita la detecció de l’error i es pot corregir ràpidament. El resultat de tot això es pot veure a la figura 1.

p1
Figura 1

Un vegada fet, vam afegir els elements de dintre les cinc pestanyes dels filtres. Finalment, el que vàrem fer és donar-li un nom que ajudi a la identificació de cada element interactiu de la interfície. Aquest serà el nom que utilitzarem per poder-hi interactuar dins el codi principal que controlarà el plugin. A la figura 2 es pot veure com quedaria la finestra amb la pestanya principal omplerta.

p2
Figura 2

Recomanem que siguin el més explícits possible ja que es podran evitar errades i també ajudaran a facilitar la comprensió del codi, com per exemple ‘ComboConnexio’ en referencia a la pestanya desplegable on s’hi indicarà la connexió que volem escollir.

Interacció amb les Bases de Dades

Per a poder realitzar qualsevol acció sobre la base de dades cal primer saber el nom d’usuari, nom de la base de dades, servidor i contrasenya. És recomanable guardar aquestes dades en variables globals i aconseguirem accedir-hi des de qualsevol funció en qualsevol moment. També cal fer l’import de la llibreria psycopg2 (import psycopg2) al principi del codi.

Per establir la connexió hem utilitzat el codi següent:

#Connexio
nomBD = nomBD1.encode('ascii','ignore')
usuari = usuari1.encode('ascii','ignore')
servidor = host1.encode('ascii','ignore')
contrasenya = contra1.encode('ascii','ignore')
try:
  estructura="dbname='"+nomBD+"' user='"+usuari
  +"' host='"+servidor+"' password='" + contrasenya + "'"
  conn = psycopg2.connect(estructura)
  cur = conn.cursor()
  cur.execute(Sentencia_sql)
  resultat = cur.fetchall()
  conn.close()

Utilitzarem la comanda execute(<sentencia SQL>) per realitzar la consulta. Per poder passar els resultats i per poder-los tractar utilitzarem la comanda fetchall() que retorna una matriu amb tots ells. És important tancar la connexió un cop haguem fet les consultes necessàries.

En el cas que ens ocupa, hi ha tres pestanyes del grup de pestanyes principals que necessiten llegir dades de la BD i exposar-les en els seus respectius camps. Com per exemple en la pestanya ‘Estudis’ hi ha un requadre amb una llista (QListWidget) on cal llistar-hi tots els estudis que hi pot haver i que tenim emmagatzemats a la taula del Padró. El que busquem nosaltres és una consulta que ens retorni els diferents tipus d’estudi que hi ha i ho hem resolt amb la sentencia SQL següent:

select distinct("HABNIVINS"),"NINDESCRI" from "public"."Padro" order by 2;

El camp “HABNIVINS” és l’identificador de l’estudi i el “NINDESCRI” és el nom de l’estudi que apareixerà al requadre de la llista. L’identificador de l’estudi el vincularem a l’estudi per mitjà del ToolTip(), que posteriorment ens facilitarà la construcció de la consulta que l’usuari desitja.

Connexió dels botons

Per poder vincular i recollir els estats dels elements de la interfície cal fer els següents passos. Primer de tot cal fer from TaulaResum_dialog import TaulaResumDialog per tal de poder vincular el fitxer de la interfície amb el codi.

Aleshores, a la funció init(), que ja ve creada pel Plugin Builder, hi posem les següents comandes:

self.dlg = TaulaResumDialog()
self.dlg.btoNACIONALITAT.toggled.connect(self.on_click_MarcarBotoNACIONALITAT)
self.dlg.comboConnexions.currentIndexChanged.connect(self.on_Change_ComboConn)

El primer inicialitza el diàleg amb el què hem d’interaccionar. Les altres dos activen les seves funcions respectives cada vegada que el valor que tinguin variï. Segons el tipus d’element que sigui, es pot canviar l’aparença o carregar elements per pantalla.

Cada element de la interfície ha de tenir una funció vinculada a ell per tal de que el codi sigui capaç de veure en quin estat està.

Programació dels efectes dels botons

Cada vegada que l’usuari interaccioni amb un dels elements de la interfície es produirà un efecte. En aquest apartat s’introduirà un exemple d’aquest tipus de comportament. Per l’exemple utilitzarem el codi següent:

def on_click_MarcarBotoEDAT(self, clicked):
if clicked:
  self.dlg.btoEDAT.setStyleSheet('background-color: #7fff7f')
  self.dlg.GrupPestanyes.setCurrentIndex(0)
else:
  self.dlg.btoEDAT.setStyleSheet('background-color:rgb(227,227,227)')

Aquesta funció es dedica a controlar l’aspecte del botó del filtre d’Edat. Si és clicat, canvia de color de fons i mostra la pestanya del filtre d’edat per tal que l’usuari esculli els paràmetres que vol analitzar. Altrament, li torna a posar el color de desactivat.

A més a més, cal tenir en compte que els elements de la interfície tenen memòria i que un cop els hi canviem l’estat, creem la taula i tanquem el plugin, una vegada el tornem a obrir, conserven el seu estat anterior. Això fa necessària una funció que posi aquests elements en el seu estat inicial cada vegada el que el plugin s’obri i s’utilitzi.

En el nostre cas, la majoria d’elements de la interfície tenen efectes molt senzills com el que hem explicat fa un moment però hi ha un botó que realitza una funció més complexa: crear la taula resum. Aquesta funció recull totes les dades que l’usuari ha introduït sobre els filtres que desitja analitzar, comprova que no hi hagi cap error o que falti alguna dada, es connecta amb la base de dades i escriu el resultat en fitxers de text .csv per a que l’usuari els pugui utilitzar sempre que vulgui.

Un altre punt important és el control d’errors. Cada cop que es produeixi un resultat no esperat s’ha controlar i avisar a l’usuari del que ha passat i indicar-li els passos per corregir l’errada. En el nostre cas, els errors més comuns es produeixen a l’hora de crear les consultes: l’usuari no introdueix correctament les dades de la consulta. Però també pot ser que la connexió no estigui disponible o que l’usuari no tingui els permisos adequats de lectura.

Quan es tracta d’un error relacionat amb la connexió s’adverteix a l’usuari per mitjà d’una etiqueta que n’indica l’estat. En el cas de tenir problemes amb la consulta, apareixen finestres amb el missatge d’error.

Prova del plugin

Una vegada hem programat totes les funcions, cal comprovar que els resultats són els esperats. Per fer-ho, cal que utilitzem el GeoMedia amb el plugin que s’utilitzava anteriorment i comprovar que si posem les mateixes variables d’entrada obtenim el mateix resultat.

Cal que el procés sigui exhaustiu perquè cal revisar cadascuna de les funcions que s’han implementat. S’han de fer totes les combinacions possibles i comprovar que el número de resultats ha sigut igual. En el cas que no ho sigui, s’han de comparar els codis i veure el punt on difereixen.