Skip to content

Instantly share code, notes, and snippets.

@isuvorov
Last active February 1, 2017 16:35
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 isuvorov/c8df35607d2d6ebd4bab1956715a7f82 to your computer and use it in GitHub Desktop.
Save isuvorov/c8df35607d2d6ebd4bab1956715a7f82 to your computer and use it in GitHub Desktop.
/* eslint-disable */
import _ from 'lodash'
export const R = 6371
export function deg2rad(deg) {
return deg * (Math.PI / 180)
}
export function getDistance(point1, point2) {
const vector = {
lat: deg2rad(point2.lat - point1.lat),
lng: deg2rad(point2.lng - point1.lng),
}
const a =
Math.sin(vector.lat / 2) * Math.sin(vector.lat / 2) +
Math.cos(deg2rad(point1.lat)) * Math.cos(deg2rad(point2.lat)) *
Math.sin(vector.lng / 2) * Math.sin(vector.lng / 2)
;
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
const d = R * c; // Distance in km
// console.log('point1, point2', point1, point2, d);
return d;
}
// @TODO replace 1 km
export function showOnlyUsers(params) {
return params.distance < 1
}
export function getCellSize(params) {
const { distance, grid } = params
let size = 4
if (grid) {
return { dlat: grid, dlng: grid }
}
// @TODO replace function
if (distance < 1) {
size = 1 / 1024
} else if (distance < 2) {
size = 1 / 512
} else if (distance < 5) {
size = 1 / 256
} else if (distance < 10) {
size = 1 / 128
} else if (distance < 20) {
size = 1 / 64
} else if (distance < 40) {
size = 1 / 32
} else if (distance < 90) {
size = 1 / 16
} else if (distance < 250) {
size = 1 / 8
} else if (distance < 500) {
size = 1 / 4
} else if (distance < 1000) {
size = 1 / 2
} else if (distance < 2000) {
size = 1
} else if (distance < 4000) {
size = 2
}
size *= 2
// console.log({ size })
return { dlat: size, dlng: size }
}
export function getClusterByLatLng(params) {
const { dlat, dlng, lat, lng } = params
const cluster = {
lat: Math.floor(lat / dlat) * dlat,
lng: Math.floor(lng / dlng) * dlng,
}
cluster.id = cluster.lat + '_' + cluster.lng
// console.log({ dlat, dlng, lat, lng, id: cluster.id} );
return cluster
}
export function getBestUserFromCluster(users) {
// console.log('getBestUserFromCluster', users.map(u => u.distance), _.minBy(users, (user) => user.distance).distance);
return _.minBy(users, (user) => user.distance)
}
export default (users, params) => {
const {lat, lng, distance, limit = 12} = params
// @TODO replace 10 users
if (users.length < 10 || showOnlyUsers(params)) {
return users
}
/// if 10
// if (showOnlyUsers(params)) {
// return users
// }
const { dlat, dlng } = getCellSize(params)
// console.log({dlat, dlng});
const usersWithClusters = users.map(user => {
const cluster = getClusterByLatLng({dlat, dlng, lat: user.lat, lng: user.lng})
return {
cluster,
distance: getDistance(cluster, user),
...user.toJSON(),
};
})
const clusters = _.groupBy(usersWithClusters, 'cluster.id')
const clusterWithUsers = _.map(clusters, users => {
const user = getBestUserFromCluster(users) // пока сделаем по _.min(users, 'distance') , потом подумаем
// user.lat = user.cluster.lat
// user.lng = user.cluster.lng
return {
type: 'cluster',
user,
users,
lng: user.cluster.lng,
lat: user.cluster.lat,
}
})
// @TODO мониторинг результата => 5-9
// console.log(JSON.stringify({...params, ...{ dlat, dlng }, users: users.length, clusterWithUsers: clusterWithUsers.length}, null, 4))
return clusterWithUsers
}
//
// Игорь Суворов, [25.12.16 23:39]
// 0 - 10 z = 1
// 10 - 40 z = 2
// 40 - 250 z = 3
// 250 - 1000 z = 4
// 1000 - 4000 z = 5
//
// Игорь Суворов, [25.12.16 23:39]
// перевод distance в масштаб
//
// Игорь Суворов, [25.12.16 23:40]
// при z = 5 , кваждрат "кластеризации" 2х2 кластера
//
// Игорь Суворов, [25.12.16 23:41]
// z = 5, 2 г
// z = 4, 1/2 г
// z = 3, 1/8 г
// z = 2, 1/32 г
// z = 1, 1/128 г
//
//
// if (showOnlyUsers()) { // if distance < 10km
// return users
// }
//
// const { dlat, dlng } = getCellSize(lat, lng, distance, count) // получаем размер кластерной сетки в зависимости от того,
// // 1) на какной дистанции смотрим
// // 2) сколько нам нужно кластеров
// // 3) размерность в градусах для этого участка земли (компенсируем отношение грудусов к километрам на полюсах)
//
//
// const usersWithClusters = users.map(user => {
//
// const cluster = getClusterByLatLng({dlat, dlng, ...user}) // получаем ближайший кластер для юзера ( в том квадрате в котором находится юзер )
//
//
//
// const clusterId = cluster.lat + '_' + cluster.lng
//
//
//
// return {
//
// cluster,
// clusterId,
// distance: getDistance(cluster, user),
//
// ...user
// }
// })
//
// // группируем пользователей по принадлежности кластерам
// const clusters = _.groupBy(usersWithClusters, 'clusterId')
//
//
// return _.map(clusters, users => {
//
// const user = getSuperUserFromCluster(users) // пока сделаем по _.min(users, 'distance') , потом подумаем
//
//
// return {
// user: user,
// count: users.count,
// lng: user.lng, // пока центр кластера пусть будет центр юзера, потом попробуем еще {lng : user.cluster.lng}
// lat: user.lat,
// }
//
// })
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment