osmc:Metodologia/Algoritmo SQL/Issues: mudanças entre as edições

m
m (solução por ST_Simplify)
 
(7 revisões intermediárias pelo mesmo usuário não estão sendo mostradas)
Linha 1: Linha 1:
Issues e discussões conceituais, antes de se partir para a implementação.
Issues e discussões conceituais, antes de se partir para a implementação. Ver também [[Discussão:DNGS/Decisões_soberanas#Issues]], relativas a decisões humanas, sem algoritmo previsto.


== Issue 01 - Uso ótimo do hInt64 ==
== Issue 01 - Uso ótimo do hInt64 ==
Linha 165: Linha 165:


<syntaxhighlight lang="sql">
<syntaxhighlight lang="sql">
DROP FUNCTION IF EXISTS st_transform_resilient
DROP FUNCTION IF EXISTS ST_Transform_Resilient
;
;
CREATE FUNCTION public.st_transform_resilient(
CREATE FUNCTION ST_Transform_Resilient(
   g geometry,
   g   geometry,     -- the input geometry
   srid integer,
   srid integer,     -- target SRID, to transform g
   size_fraction float DEFAULT 0.05,
   size_fraction float DEFAULT 0.05, -- 1/density. Density of points per charactDiam (or negative for absolute fraction).
   tolerance float DEFAULT 0 -- 0.00000005
   tolerance     float DEFAULT 0     -- E.g. on srid=4326 use 0.00000005.
) RETURNS public.geometry
                                    -- ZERO=0.000000001. Smallest=0.000000005. Start cell with 0.00000002.
    LANGUAGE sql IMMUTABLE
) RETURNS       geometry
  language SQL IMMUTABLE
AS $f$
AS $f$
  SELECT CASE
  SELECT CASE
       WHEN COALESCE(tolerance,0)>0 THEN -- ST_Simplify(celula) ou
       WHEN COALESCE(size_fraction,0.0)>0.0 AND COALESCE(tolerance,0)>0 THEN
        ST_SimplifyPreserveTopology(geom,tolerance) -- generico
          ST_SimplifyPreserveTopology(geom,tolerance) -- ST_Simplify enough for grid cells
       ELSE geom
       ELSE geom
       END
       END
  FROM (
  FROM (
  -- discuss ideal at https://gis.stackexchange.com/q/444441/7505
   SELECT CASE
   SELECT CASE
     WHEN size>0.0 THEN  ST_Transform(  ST_Segmentize(g,size)  , srid  )
     WHEN size>0.0 THEN  ST_Transform(  ST_Segmentize(g,size)  , srid  )
     ELSE  ST_Transform(g,srid)
     ELSE  ST_Transform(g,srid)
     END geom
     END geom, size
   FROM (
   FROM (
     SELECT CASE
     SELECT CASE
Linha 195: Linha 195:
  ) t2
  ) t2
$f$;
$f$;
COMMENT ON FUNCTION ST_Transform_Resilient IS
  'Avoid clothesline-effect. See problem/solution discussed at https://gis.stackexchange.com/q/444441/7505'
;
</syntaxhighlight>
</syntaxhighlight>
Migrar função para o git oficial!
== Issue 04 - Lib de grades  ==
Desenvolvendo em [[osmc:Metodologia/Algoritmo SQL/Issue04]].
== Issue 05 - Cálculo de dígitos base32 ==
Por imposição do [[Discrete National Grid Systems/pt|padrão DNGS]] temos <math>S_{L}=2^{Lmax-L}</math>. No caso do Brasil ''Lmax''=20, no caso de Camarões ''Lmax=18''. Já havíamos notado isso ao apresentar a [[osmc:Metodologia/Algoritmo_SQL/Lib#Core|Lib Core]].
No caso de geocódigo logístico, que requer cobertura municipal, supondo que o nível da grade adotada para cobertura seja ''Lcover'', podemos obter a aproximação ao metro por um múltiplo de 2.5, que é a quantidade de níveis que se sobe a cada 5 bits do dígito da base32. Partindo de  <math>1=2^{Lmax - Lcover - N \cdot 2.5}</math> obtemos por <math>log_2(1)=0</math> a fórmula <math>N= (Lmax-Lcover)/2.5</math>, onde ''N'' é o número de dígitos depois do primeiro para se chegar ao metro.  Num caso típico a cobertura municipal no Brasil (''Lmax''=20) é de nível ''L7.5'', resultando em ''N''=5, ou seja, com 6 dígitos teremos o metro. Para uma cobertura de resolução menor, ''L7'', o valor já não é exato, ''N''=5.2. O número de dígitos para chegar no metro portanto será <math>Ndig1m = 1+\lceil (Lmax-Lcover)/2.5 \rceil</math>.
<syntaxhighlight lang="sql" style="font-size: 80%;">
CREATE FUNCTION grid_br.logistic_Ndig1m(intlevel_cover int) RETURNS real[] AS $f$
    SELECT array[  Lcover, ceil(Ndig1m), ceil(Ndig1m)-Ndig1m,
          2^(Lmax-Lcover-ceil(Ndig1m)*2.5),
          CASE WHEN ceil(Ndig1m)-Ndig1m=0 THEN NULL ELSE 2^(Lmax-Lcover-floor(Ndig1m)*2.5) END  ]
    FROM (
      SELECT *, (Lmax-Lcover)/2.5 as Ndig1m
      FROM (SELECT 20 as Lmax, intlevel_cover/10.0 as Lcover) t1 
    ) t2
$f$ language SQL IMMUTABLE;
-- gerando a tabela do Brasil:
select x[1] as level_cover, x[2] as Ndigits_for_1m, round(x[4],2) as side_size,
      round(x[5],2) as size_before
from (
  select grid_br.logistic_Ndig1m(intLevel) as x
  from generate_series(40,90,5) t1(intLevel)
) t2;
</syntaxhighlight>
A escolha de nivel ''Lcover'' de cada município no caso do Brasil vai ter o seguinte perfil dado pela função <code>logistic_Ndig1m()</code>. Como o metro é a maior resolução significativa, é interesante não permitir resoluções finais inferiores a meio metro: por exemplo quando a cobertura ótima ''Lcover'' for 4 ou 4.5, usar no máximo 6 dígitos ao invés de 7, já que 2 metros e 1.4 metros são resoluções razoáveis para endereços. Idem ''Lcover''6.5 e 7 etc.
{| class="wikitable"
|+ Número de dígitos base32 para se chegar no metro, conforme ''Lcover'' do município
|-
|''Lcover'' || Ndigits for 1m || ''side_size'' || ''size_before''
|-
|        4 ||              7 ||      0.35 ||        2.00
|-
|      4.5 ||              7 ||      0.25 ||        1.41
|-
|        5 ||              6 ||      1.00 ||           
|-
|      5.5 ||              6 ||      0.71 ||        4.00
|-
|        6 ||              6 ||      0.50 ||        2.83
|-
|      6.5 ||              6 ||      0.35 ||        2.00
|-
|        7 ||              6 ||      0.25 ||        1.41
|-
|      7.5 ||              5 ||      1.00 ||           
|-
|        8 ||              5 ||      0.71 ||        4.00
|-
|      8.5 ||              5 ||      0.50 ||        2.83
|-
|        9 ||              5 ||      0.35 ||        2.00
|}
2 384

edições