2. O que é GeoJSON#

2.1 Conceitos Fundamentais#

GeoJSON é um formato aberto de codificação para representar estruturas de dados geográficos, baseado em JSON (JavaScript Object Notation).


2.2 Estrutura Básica#

Um arquivo GeoJSON válido contém obrigatoriamente um objeto FeatureCollection:

Exemplo de estrutura GeoJSON básica:

{
  "type": "FeatureCollection",
  "crs": {
    "type": "name",
    "properties": {
      "name": "EPSG:4674"
    }
  },
  "metadata": {
    "schema_version": "R0",
    "ano_programacao": 2026,
    "data_geracao": "2025-10-30T14:30:00-03:00"
  },
  "features": [
    {
      "type": "Feature",
      "geometry": {
        "type": "Point",
        "coordinates": [-47.0653, -23.5489]
      },
      "properties": {
        "id": 1,
        "detalhamento_servico": "Exemplo de feature"
      }
    }
  ]
}

Componentes principais:

ComponenteDescrição
typeSempre "FeatureCollection" para a coleção de features.
crsSistema de Referência de Coordenadas (obrigatório para ARTESP).
metadataMetadados de controle (específico da ARTESP).
featuresArray contendo as features (geometria + propriedades).

2.3 Tipos de Geometria#

O GeoJSON suporta os seguintes tipos geométricos:

2.3.1 Point (Ponto)#

Representa uma localização única no espaço.

Exemplo: [-47.0653, -23.5489]

2.3.2 LineString (Linha)#

Representa uma sequência conectada de pontos.

Exemplo de coordenadas: [ [-47.0653, -23.5489], [-47.0663, -23.5499] ]

Estrutura completa:

{
  "type": "Feature",
  "geometry": {
    "type": "LineString",
    "coordinates": [
      [-47.0653, -23.5489],
      [-47.0663, -23.5499],
      [-47.0673, -23.5509]
    ]
  },
  "properties": {
    "id": "pavimento-001",
    "detalhamento_servico": "Recuperação funcional do pavimento"
  }
}

Cálculo de Distância entre Pontos Consecutivos#

Para garantir a qualidade e precisão de geometrias LineString, é importante controlar a distância máxima entre pontos consecutivos.

Por que isso importa:

  • Distâncias muito grandes entre pontos (> 20m) podem resultar em linhas “retas” que não seguem o traçado real da rodovia
  • Distâncias muito pequenas (< 5m) geram vértices excessivos e comprometem a performance
  • O espaçamento adequado (~20m) garante representação fiel do trajeto com boa eficiência

Fórmula de Haversine (para coordenadas geográficas em graus):

a = sin²(Δlat/2) + cos(lat₁) × cos(lat₂) × sin²(Δlon/2)
c = 2 × atan2(√a, √(1−a))
d = R × c

Onde:

  • R = 6.371.000 m (raio médio da Terra)
  • Δlat = lat₂ - lat₁ (em radianos)
  • Δlon = lon₂ - lon₁ (em radianos)

Implementação em Python:

import math

def distancia_haversine(lon1, lat1, lon2, lat2):
    """
    Calcula a distância entre dois pontos usando a fórmula de Haversine.

    Parâmetros:
        lon1, lat1: Coordenadas do primeiro ponto (graus decimais)
        lon2, lat2: Coordenadas do segundo ponto (graus decimais)

    Retorna:
        Distância em metros
    """
    R = 6371000  # Raio da Terra em metros

    # Converter de graus para radianos
    lat1_rad = math.radians(lat1)
    lat2_rad = math.radians(lat2)
    delta_lat = math.radians(lat2 - lat1)
    delta_lon = math.radians(lon2 - lon1)

    # Fórmula de Haversine
    a = math.sin(delta_lat/2)**2 + \
        math.cos(lat1_rad) * math.cos(lat2_rad) * \
        math.sin(delta_lon/2)**2
    c = 2 * math.asin(math.sqrt(a))

    return R * c

# Exemplo de uso
ponto1 = (-47.0653, -23.5489)
ponto2 = (-47.0663, -23.5499)

dist_m = distancia_haversine(ponto1[0], ponto1[1], ponto2[0], ponto2[1])
print(f"Distância: {dist_m:.1f} m")
# Saída: Distância: 136.3 m

Validação da Distância Máxima:

def validar_distancias_linestring(coordinates, max_distancia_m=20.0):
    """
    Valida se todos os segmentos de uma LineString respeitam a distância máxima.

    Parâmetros:
        coordinates: Lista de coordenadas [[lon, lat], ...]
        max_distancia_m: Distância máxima permitida entre pontos consecutivos (metros)
                        Default: 20m (recomendado para trechos rodoviários)

    Retorna:
        (bool, list): (é_válido, lista_de_erros)
    """
    erros = []

    for i in range(len(coordinates) - 1):
        lon1, lat1 = coordinates[i]
        lon2, lat2 = coordinates[i + 1]

        dist = distancia_haversine(lon1, lat1, lon2, lat2)

        if dist > max_distancia_m:
            erros.append({
                'segmento': f"{i}{i+1}",
                'ponto1': [lon1, lat1],
                'ponto2': [lon2, lat2],
                'distancia_m': round(dist, 1)
            })

    return len(erros) == 0, erros

# Exemplo de validação
linestring = [
    [-47.0653, -23.5489],
    [-47.0655, -23.5491],  # Distância ~31m - EXCEDE o limite de 20m
    [-47.0800, -23.5600]   # Distância ~18km - MUITO ACIMA do limite
]

valido, erros = validar_distancias_linestring(linestring, max_distancia_m=20.0)

if not valido:
    print("⚠️ Segmentos com distância excessiva encontrados:")
    for erro in erros:
        print(f"  Segmento {erro['segmento']}: {erro['distancia_m']:.1f} m")

📏 Recomendações de Distância:

Tipo de GeometriaDistância Máxima RecomendadaObservações
Trechos rodoviários gerais20 mPadrão recomendado - equilíbrio entre precisão e performance
Trechos rodoviários retos50-100 mPode ser relaxado em trechos retilíneos longos
Trechos com curvas suaves20-30 mMantém fidelidade ao traçado
Trechos com curvas acentuadas10-15 mNecessário para representar curvas complexas
Áreas urbanas/dispositivos5-10 mMaior detalhamento em interseções e alças

⚠️ Alertas:

  • O padrão de 20 metros oferece boa precisão sem gerar vértices excessivos
  • Evite vértices excessivos (> 1000 pontos por LineString) para não comprometer performance
  • Para trechos muito longos (> 50 km), considere dividir em múltiplas features
  • Use ferramentas GIS para simplificar geometrias quando apropriado
  • Distâncias inferiores a 5m raramente agregam precisão significativa

2.3.3 Polygon (Polígono)#

Representa uma área fechada.

Exemplo: [ [ [-47.06, -23.54], [-47.07, -23.54], [-47.07, -23.55], [-47.06, -23.55], [-47.06, -23.54] ] ]

2.3.4 MultiPoint (Múltiplos Pontos)#

Representa um conjunto de pontos discretos não conectados entre si.

Uso típico: Localização de múltiplos itens similares distribuídos ao longo de um trecho (sensores, tachões, placas de sinalização).

Exemplo de coordenadas:

[
  [-47.0653, -23.5489],
  [-47.0663, -23.5499],
  [-47.0673, -23.5509]
]

Estrutura completa:

{
  "type": "Feature",
  "geometry": {
    "type": "MultiPoint",
    "coordinates": [
      [-47.0653, -23.5489],
      [-47.0663, -23.5499],
      [-47.0673, -23.5509]
    ]
  },
  "properties": {
    "id": "sensor-001",
    "detalhamento_servico": "Instalação de sensores de tráfego"
  }
}

2.3.5 Diferença entre MultiPoint e LineString#

Embora ambos os tipos usem arrays de coordenadas, possuem diferenças fundamentais:

AspectoMultiPointLineString
ConectividadePontos independentes (não conectados)Pontos conectados sequencialmente
Ordem dos pontosOrdem não implica continuidade espacialOrdem define o trajeto da linha
Interpretação visualConjunto de marcadores discretosLinha contínua
Uso típicoItens múltiplos e discretosTrechos lineares contínuos
Distância entre pontosIrrelevanteDeve ser calculada (veja abaixo)

📌 Exemplo Prático:

MultiPoint - Instalação de 5 radares ao longo da SP-280:

  • Radar no km 100
  • Radar no km 115
  • Radar no km 130
  • Radar no km 145
  • Radar no km 160

→ Não há relação de continuidade entre os radares. São itens independentes.

LineString - Recuperação de pavimento do km 100 ao km 110 da SP-280:

  • Ponto inicial: km 100
  • Pontos intermediários: km 102, km 104, km 106, km 108
  • Ponto final: km 110

→ Há continuidade espacial. O serviço cobre toda a extensão entre os pontos.

⚠️ Regra de Decisão:

  • Use MultiPoint quando os itens são discretos e independentes
  • Use LineString quando há continuidade espacial entre os pontos