Plotas para plotar para que não se sobreponham se tiverem as mesmas coordenadas
-
27-09-2019 - |
Pergunta
Eu tenho uma função que leva longitude e latitude e a converte em x e y para serem plotadas. A conversão para X e Y está funcionando bem e não é com isso que tenho o problema.
Quero garantir que dois pontos não sejam plotados no mesmo lugar. Em um conjunto de resultados, existem cerca de 30 um no outro (porque eles têm a mesma latitude e longitude), esse número pode ser muito maior.
No momento, estou tentando conseguir isso movendo pontos para a esquerda, direita, superior ou inferior do ponto para fazer um quadrado. Uma vez que um quadrado composto de pontos foi atraído, depois passando para a próxima linha e desenhando outro quadrado de pontos ao redor da praça anterior.
O código é JavaScript, mas é muito genérico, então acho que é um pouco irrelevante.
Meu código é o seguinte:
var prevLong, prevLat, rand = 1, line = 1, spread = 8, i = 0;
function plot_points(long, lat){
// CODE HERE TO CONVERT long and lat into x and y
// System to not overlap the points
if((prevLat == lat) && (prevLong == long)) {
if(rand==1) {
x += spread*line;
} else if(rand==2) {
x -= spread*line;
} else if(rand==3) {
y += spread*line;
} else if(rand==4) {
y -= spread*line;
} else if(rand==5) {
x += spread*line;
y += spread*line;
} else if(rand==6) {
x -= spread*line;
y -= spread*line;
} else if(rand==7) {
x += spread*line;
y -= spread*line;
} else if(rand==8) {
x -= spread*line;
y += spread*line;
// x = double
} else if(rand==9) {
x += spread*line;
y += spread;
} else if(rand==10) {
x += spread;
y += spread*line;
} else if(rand==11) {
x -= spread*line;
y -= spread;
} else if(rand==12) {
x -= spread;
y -= spread*line;
} else if(rand==13) {
x += spread*line;
y -= spread;
} else if(rand==14) {
x += spread;
y -= spread*line;
} else if(rand==15) {
x += spread*line;
y -= spread;
} else if(rand==16) {
x += spread;
y -= spread*line;
} else if(rand==17) {
x -= spread*line;
y += spread;
} else if(rand==18) {
x -= spread;
y += spread*line;
} else if(rand==19) {
x -= spread*line;
y += spread;
} else if(rand==20) {
x -= spread;
y += spread*line;
}
if(rand == 20) {rand = 1; line++; } else { rand++; }
i++
} else {
line = 1;
i = 0;
}
prevLat = latitude;
prevLong = longitude;
return [x,y];
}
Esta é a saída:
Não está funcionando corretamente e nem sei se estou abordando o problema de maneira correta.
Alguém já teve que fazer isso antes? Que método você sugeriria?
Solução
Comece agrupando suas coordenadas. Sua conversão longa, lat -> x, y pode não ser necessária até a última etapa. Um método é criar um mapa de hash, onde você armazena cada posição longa/lat e uma contagem para cada posição.
Em seguida, você converte cada posição longa e LAT em AX, coordenada e usa a contagem para decidir como renderizar os pontos centrados em torno da posição X, Y, mas com um tamanho de acordo com o número de pontos.
Um algoritmo de trabalho para render um quadrado é:
var count = 30; // example
result = [];
var width = count/Math.sqrt(count);
width = Math.floor(width);
height = Math.floor(count/width);
var remain = count % width;
var i,j;
for(i = 0; i < width; i++)
for(j = 0; j < height; j++)
result.push([x-Math.floor(width/2)+i, y-Math.floor(height/2)+j];
for(i = 0; i < remain; i++)
result.push([x-Math.floor(width/2)+i, y-Math.floor(height/2)+j];
A entrada é contagem de pontos, x, y coordenada central, a saída é uma matriz de pontos para renderizar.
A última linha são os pontos restantes, por exemplo, um quadrado de 15 pontos renderiza:
OOOO
OOOO
OOOO
OOO
Outras dicas
Usando a solução de Ernelli como exemplo, consegui fazer a trama funcionar corretamente. Parece um pouco longo, mas funciona e não é lento.
A solução de Ernelli tem um erro no segundo para o loop:
for(j = 0; i < height; i++)
Deveria estar:
for(j = 0; j < height; j++)
De qualquer forma, este é o meu código que estou usando e está funcionando. PoTaRray é uma variedade de todos os elementos a serem plotados:
var countArray = new Array();
// Go through every point and group same co-ordinates together
for (var i = pointArray.length-1; i > -1; i--) {
if(pointArray[i] != undefined)
{
var found = 0;
// Check if this point is already in array
for (var j = countArray.length-1; j > -1; j--)
{
if(countArray[j] != undefined)
{
if((pointArray[i].getBBox().x == countArray[j]["x"]) && (pointArray[i].getBBox().y == countArray[j]["y"]))
{
countArray[j]["points"].push(pointArray[i]);
found = 1;
}
}
}
// The point is not in the array, so add it
if(found != 1)
{
var index = countArray.length;
countArray[index] = new Array();
countArray[index]["x"] = pointArray[i].getBBox().x;
countArray[index]["y"] = pointArray[i].getBBox().y;
countArray[index]["points"] = new Array();
countArray[index]["points"].push(pointArray[i]);
}
}
}
// For each co-ordinate
for (var j = countArray.length-1; j > -1; j--)
{
if(countArray[j] != undefined)
{
// If there is more than one point
if(countArray[j]["points"].length > 1) {
// Calculate the square points
var count = countArray[j]["points"].length;
var x = countArray[j]["x"];
var y = countArray[j]["x"];
result = [];
var width = count/Math.sqrt(count);
width = Math.floor(width);
height = Math.floor(count/width);
var remain = count % width;
var i2,j2, xx, yy;
var space = 8;
for(i2 = 0; i2 < width*space; i2+=space)
{
for(j2 = 0; j2 < height*space; j2+=space)
{
result.push([(Math.floor(width/2)+i2), (Math.floor(height/2)+j2)]);
}
}
for(i2 = 0; i2 < remain*space; i2+=space)
{
result.push([(Math.floor(width/2)+i2), (Math.floor(height/2)+j2)]);
}
// Go through each point and then translate it to it's new position
for (var jj = countArray[j]["points"].length-1; jj > -1; jj--)
{
if(countArray[j]["points"][jj] != undefined)
{
if(result[jj] != undefined)
{
countArray[j]["points"][jj].translate(result[jj][0]-((width*8)/2), result[jj][1]-((height*8)/2))
}
}
}
} // End if count more than 1
} // End if undefined
}
Observe que isso usa muitos Raphael.js funções (como getBbox e tradução)