Skip to content

Instantly share code, notes, and snippets.

@jucie
Created December 7, 2019 08:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jucie/82b58ab48f8c0c99d522def5d480deb2 to your computer and use it in GitHub Desktop.
Save jucie/82b58ab48f8c0c99d522def5d480deb2 to your computer and use it in GitHub Desktop.
geomedian c++
// Este programa le a imagem PNG de um mapa e encontra o ponto em que
// o territorio se divide igualmente entre Norte e Sul, Leste e Oeste.
// A lib PNG++ usa uma funcao que o Windows nao tem, entao quebramos o galho com uma macro.
// https://stackoverflow.com/questions/11718915/alternative-api-of-strerror-r-for-windows-os
#define strerror_r(errno,buf,len) strerror_s(buf,len,errno)
#include <png.hpp> // e' a biblioteca que sabe ler, gravar e manipular imagens em formato PNG.
// Esta e' a classe da lib PNG++ que representa uma imagem. Vamos chama-la apenas de Imagem.
typedef png::image< png::rgb_pixel > Imagem;
const png::rgb_pixel pontoPreto; // e' um pontinho na cor preta.
// compara um pixel com outro pra ver se a cor bate. Retorna true se bater.
bool operator==(const png::rgb_pixel& lhs, const png::rgb_pixel& rhs) {
return lhs.blue == rhs.blue && lhs.green == rhs.green && lhs.red == rhs.red;
}
// compara um pixel com outro pra ver se a cor bate. Retorna true se NAO bater.
bool operator!=(const png::rgb_pixel& lhs, const png::rgb_pixel& rhs) {
return !operator==(lhs, rhs);
}
// fazLinhaHorizontal traca uma linha da esquerda para a direita na posicao y.
void fazLinhaHorizontal(Imagem& img, size_t y) {
for (size_t x = 0; x < img.get_width(); x++) { // varre da esquerda para a direita
img.set_pixel(x, y, pontoPreto); // marca um pontinho
}
}
// fazLinhaVertical traca uma linha de cima para baixo na coluna x.
void fazLinhaVertical(Imagem& img, size_t x) {
for (size_t y = 0; y < img.get_height(); y++) { // varre de cima para baixo
img.set_pixel(x, y, pontoPreto); // marca um pontinho
}
}
// calculaArea retorna a quantidade de pixels dentro do territorio que nos interessa.
size_t calculaArea(Imagem& img) {
png::rgb_pixel fundo = img.get_pixel(0,0); // pega cor do cantinho
size_t cnt = 0; // vamos contar
for (size_t y = 0; y < img.get_height(); y++) { // varre de cima para baixo
for (size_t x = 0; x < img.get_width(); x++) { // varre da esquerda para a direita
if (img.get_pixel(x, y) != fundo) { // estamos dentro do territorio?
cnt++; // area que nos interessa tem mais um pixel
}
}
}
return cnt; // quantos pixels tem no territorio
}
// divideNorteSul faz uma linha horizontal dividindo o Norte do Sul.
// area indica em que posicao deve ser tracada a linha horizontal.
void divideNorteSul(Imagem& img, size_t area) {
png::rgb_pixel fundo = img.get_pixel(0,0); // pega cor do cantinho
size_t cnt = 0; // vamos contar
for (size_t y = 0; y < img.get_height(); y++) { // varre de cima para baixo
for (size_t x = 0; x < img.get_width(); x++) { // varre da esquerda para a direita
if (img.get_pixel(x, y) != fundo) { // estamos dentro do territorio?
cnt++; // area que nos interessa tem mais um pixel
if (cnt == area) { // chegamos na linha onde devemos marcar?
fazLinhaHorizontal(img, y); // entao marca essa linha
return; // e cai fora
}
}
}
}
}
// divideLesteOeste faz uma linha vertical dividindo o Leste do Oeste.
// area indica em que posicao deve ser tracada a linha vertical.
void divideLesteOeste(Imagem& img, size_t area) {
png::rgb_pixel fundo = img.get_pixel(0,0); // pega cor do cantinho
size_t cnt = 0; // vamos contar
for (size_t x = 0; x < img.get_width(); x++) { // varre da esquerda para a direita
for (size_t y = 0; y < img.get_height(); y++) { // varre de cima para baixo
if (img.get_pixel(x, y) != fundo) { // estamos dentro do territorio?
cnt++; // area que nos interessa tem mais um pixel
if (cnt == area) { // chegamos na coluna onde devemos marcar?
fazLinhaVertical(img, x); // entao marca essa coluna
return; // e cai fora
}
}
}
}
}
// fazACruz acha o ponto no mapa onde a area se divide igualmente entre Norte/Sul e Leste/Oeste.
void fazACruz(Imagem& img) {
size_t area = calculaArea(img); // primeiro obtemos a area total do territorio
size_t metade = area / 2; // vamos dividir essa area ao meio
divideNorteSul(img, metade); // tracamos uma linha dividindo entre Norte e Sul
divideLesteOeste(img, metade); // depois tracamos outra dividindo entre Leste e Oeste
}
int main() {
Imagem img("input.png"); // le a imagem original do arquivo de entrada
fazACruz(img); // marca a divisao
img.write("output.png"); // grava a imagem marcada no arquivo de saida
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment