package main
import (
"fmt"
"math"
)
type Point struct {
X, Y, T float64
}
func (p Point) DistanceTo(other Point) float64 {
dx := p.X - other.X
dy := p.Y - other.Y
dt := p.T - other.T
return math.Sqrt(dx*dx + dy*dy + dt*dt)
}
type Cluster struct {
Points []Point
}
func DBSCAN(points []Point, epsilon float64, minPts int) []Cluster {
var clusters []Cluster
var visited = make(map[Point]bool)
for _, point := range points {
if visited[point] {
continue
}
visited[point] = true
neighbours := getNeighbours(points, point, epsilon)
if len(neighbours) < minPts {
continue
}
var clusterPoints []Point
expandCluster(&clusterPoints, points, visited, point, neighbours, epsilon, minPts)
clusters = append(clusters, Cluster{Points: clusterPoints})
}
return clusters
}
func getNeighbours(points []Point, point Point, epsilon float64) []Point {
var neighbours []Point
for _, other := range points {
if point.DistanceTo(other) <= epsilon {
neighbours = append(neighbours, other)
}
}
return neighbours
}
func expandCluster(cluster *[]Point, points []Point, visited map[Point]bool, point Point, neighbours []Point, epsilon float64, minPts int) {
*cluster = append(*cluster, point)
for _, neighbour := range neighbours {
if !visited[neighbour] {
visited[neighbour] = true
neighbourNeighbours := getNeighbours(points, neighbour, epsilon)
if len(neighbourNeighbours) >= minPts {
expandCluster(cluster, points, visited, neighbour, neighbourNeighbours, epsilon, minPts)
}
}
var isInCluster bool
for _, c := range *cluster {
if c == neighbour {
isInCluster = true
break
}
}
if !isInCluster {
*cluster = append(*cluster, neighbour)
}
}
}
func main() {
points := []Point{
{X: 1, Y: 2, T: 0},
{X: 1.5, Y: 1.8, T: 1},
{X: 5, Y: 8, T: 2},
{X: 8, Y: 8, T: 3},
{X: 1, Y: 0.6, T: 4},
{X: 9, Y: 11, T: 5},
{X: 8, Y: 2, T: 6},
{X: 10, Y: 2, T: 7},
{X: 9, Y: 3, T: 8},
}
epsilon := 3.0
minPts := 2
clusters := DBSCAN(points, epsilon, minPts)
for i, cluster := range clusters {
fmt.Printf("Cluster %d:\n", i+1)
for _, point := range cluster.Points {
fmt.Printf(" (%.2f, %.2f, %.2f)\n", point.X, point.Y, point.T)
}
}
}