# CEP Distribuição Otimizador **Descubra as melhores cidades para instalar centros de distribuição (CDs) a partir da lista de CEPs dos seus pedidos.** Você sobe um CSV com os CEPs (e, opcionalmente, o volume de cada pedido) e a ferramenta responde, em segundos, **em quais cidades ficam os melhores CDs** para reduzir a distância — e, por consequência, tempo e custo de frete — até os seus clientes. Tudo roda **localmente, de graça e offline**: o geocoding de CEP → cidade é feito por uma base embarcada, sem depender de milhares de chamadas a APIs externas. ![Exemplo de mapa de centros de distribuição](examples/mapa_exemplo.png) ## O que ele faz - 📍 **Geocoding offline** de CEP → município (lat/long reais), instantâneo e escalável para centenas de milhares de pedidos. - 🏢 **Recomenda cidades reais** para CDs, escolhendo as que minimizam a distância total ponderada pela demanda (heurística gulosa de *k-median* / p-median). - 📈 **Curva "quantos CDs?"** — mostra o retorno decrescente de abrir 1, 2, 3… centros e sugere um número razoável. - ⚖️ **Ponderação por volume** — se o CSV tiver quantidade/peso/faturamento por linha, a recomendação é puxada pela demanda de verdade. - 🗺️ **Mapas** — PNG estático (offline, contornos reais do Brasil) + HTML interativo (Leaflet/OpenStreetMap) para apresentar. ## Instalação ```bash git clone https://github.com/artificialguybr/cep-distribuicao-otimizador.git cd cep-distribuicao-otimizador npm install npm run build ``` > Requer Node.js 18+ (usa `fetch` nativo). O pacote `canvas` compila bibliotecas nativas na instalação. ## Uso rápido ```bash # Recomendar as melhores cidades para CDs (número sugerido automaticamente) node dist/cli.js centers examples/pedidos_exemplo.csv -o mapa # Forçar exatamente 3 centros e gerar os mapas node dist/cli.js centers examples/pedidos_exemplo.csv -n 3 -o mapa ``` Isso gera `mapa.png` (estático) e `mapa.html` (interativo), além de imprimir a curva de retorno e a lista de cidades recomendadas. ## Formato do arquivo de entrada CSV (ou Excel) com **pelo menos uma coluna de CEP**. Uma linha por pedido: ```csv cep,pedido,peso 01310-100,PED001,3 20040-000,PED002,1 40020-000,PED003,5 ``` Colunas reconhecidas (aceita variações de nome/caixa): | Coluna | Aliases aceitos | Obrigatória? | |---|---|---| | CEP | `cep`, `CEP`, `zip`, `zipcode`, `codigo_postal` | **Sim** | | Peso/volume | `peso`, `weight`, `quantidade`, `qtd`, `volume`, `pedidos`, `faturamento`, `receita` | Não (padrão 1 por linha) | | Coordenadas | `lat`/`latitude` e `lng`/`longitude` | Não (usa se você já tiver) | | Identificação | `pedido`/`id`, `cliente`/`nome` | Não | **Como preparar os dados:** exporte do seu ERP/e-commerce a lista de pedidos com o CEP de entrega. Se quiser que cidades com mais demanda pesem mais, inclua uma coluna de volume/quantidade/faturamento — senão cada pedido conta como 1. ## Comandos ### `centers ` — recomenda cidades para CDs (principal) ```bash node dist/cli.js centers pedidos.csv [opções] ``` | Opção | Descrição | |---|---| | `-n, --centers ` | Número de CDs. Se omitido, sugere pela curva de retorno. | | `-m, --max ` | Máximo de centros avaliados na curva (padrão: 10). | | `-o, --output ` | Gera `.png` e `.html`. | | `--offline` | Não usa o fallback ViaCEP (100% offline; pode pular CEPs raros). | Saída de exemplo: ``` 📈 How many distribution centers? (diminishing returns) k | avg km/delivery | improvement vs 1 center 1 | 753.6 km | 0% 2 | 455.1 km | 40% ... 7 | 178.3 km | 76% ← suggested 🏢 Recommended cities for distribution centers: 1. Guarulhos/SP (-23.4538, -46.5333) serves 257 orders across 8 cities, weight 773 avg distance to its demand: 96.6 km ... ``` ### `cep ` — consulta um CEP (via ViaCEP) ```bash node dist/cli.js cep 01310-100 ``` ### `process ` — clusteriza e otimiza rotas Agrupa entregas em clusters (K-means com distância haversine) e otimiza a rota interna de cada um (vizinho mais próximo + 2-opt), com estimativa de custo por combustível. ```bash node dist/cli.js process pedidos.csv -c 5 -f 6.50 -k 8 --format xlsx -o resultado.xlsx ``` | Opção | Descrição | |---|---| | `-c, --clusters ` | Número de clusters (padrão: 5) | | `-f, --fuel ` | Preço do combustível por litro (padrão: 6.5) | | `-k, --consumption ` | Consumo do veículo (padrão: 8) | | `--format ` | `csv`, `json` ou `xlsx` | ## Como funciona ### Geocoding (offline) 1. O CEP é resolvido para o **município** por busca binária numa tabela embarcada de **faixas de CEP → cidade** (`data/cep_ranges.csv`). 2. A cidade é cruzada com os **centróides municipais do IBGE** (`data/municipios.csv`) para obter lat/long reais. 3. Se o CSV já trouxer `lat`/`lng`, esses valores têm prioridade (precisão de rua). 4. Para os poucos CEPs fora das faixas (~0,2%), há um **fallback opcional via ViaCEP** (desligável com `--offline`). CEPs que não resolvem são **descartados** — nenhuma coordenada é inventada. ### Recomendação de centros As entregas são agregadas por cidade (com seus pesos) e a ferramenta escolhe, entre as cidades onde você tem demanda, as **k** que **minimizam a distância total ponderada** de cada cidade ao centro mais próximo — a heurística gulosa clássica de *facility location* (k-median). A curva de retorno decrescente ajuda a decidir **quantos** CDs valem a pena. ## Precisão e limitações (importante) - **Resolução por município**, não por rua. É a granularidade certa para *escolher cidades de CD*; não use para roteirização porta a porta sem fornecer lat/long próprios. - **Distância em linha reta (haversine) ≠ R$ de frete.** É um ótimo *proxy direcional* de custo/tempo, mas o frete real (Correios/transportadora) tem componente fixo, faixas de peso e saltos por zona/estado. Para R$ exato, seria necessário plugar uma tabela de frete. - **CDs escolhidos entre cidades com demanda.** Um CD "no meio do caminho" numa cidade sem pedidos não é considerado (mantém a resposta interpretável). - **Demanda intra-metrópole colapsa** para o centróide do município (ex.: toda a Grande São Paulo vira o ponto de São Paulo). - **Resultados determinísticos**: mesma entrada → mesma recomendação. ## Fontes de dados - Centróides de municípios: [kelvins/municipios-brasileiros](https://github.com/kelvins/municipios-brasileiros) (dados públicos do IBGE). - Faixas de CEP por município: base pública dos Correios (gist [tamnil](https://gist.github.com/tamnil/792a6a66f6df9fc028041587cfca0c3d)). - Contornos dos estados: GeoJSON de [click_that_hood](https://github.com/codeforgermany/click_that_hood). - Fallback de consulta de CEP: [ViaCEP](https://viacep.com.br/). ## Estrutura do projeto ``` data/ ├── municipios.csv # cidade → lat/long (IBGE) ├── cep_ranges.csv # faixa de CEP → cidade └── brazil-states.geojson # contornos dos estados (mapa PNG) src/ ├── cli.ts # entry point ├── commands/ # cep, process, cluster, route, centers ├── services/ │ ├── geocoder.ts # geocoding offline (CEP → município) │ ├── viacep.ts # cliente ViaCEP + enriquecimento │ ├── facility.ts # k-median ponderado + curva de retorno │ ├── clustering.ts # K-means (haversine, semente fixa) │ ├── routing.ts # vizinho mais próximo + 2-opt │ ├── map.ts # mapa PNG (canvas + GeoJSON) │ └── mapHtml.ts # mapa HTML interativo (Leaflet) ├── utils/ # csv, geo (haversine, RNG semeado) └── types/ # tipos TypeScript ``` ## Licença MIT