Skip to content

Commit

Permalink
Add cluster class
Browse files Browse the repository at this point in the history
  • Loading branch information
tryuan99 committed Jan 3, 2025
1 parent db86939 commit d5c865b
Show file tree
Hide file tree
Showing 5 changed files with 182 additions and 0 deletions.
8 changes: 8 additions & 0 deletions Assets/Scripts/Algorithms.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

75 changes: 75 additions & 0 deletions Assets/Scripts/Algorithms/Cluster.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

// The cluster class represents a collection of points with a defined centroid.
public class Cluster {
// Centroid of the cluster.
private Vector3 centroid = Vector3.zero;

// List of points in the cluster.
private List<Vector3> points = new List<Vector3>();

// Get the list of points.
public IReadOnlyList<Vector3> Points {
get { return points; }
}

// Return the size of the cluster.
public int Size() {
return points.Count;
}

// Check whether the cluster is empty.
public bool IsEmpty() {
return Size() == 0;
}

// Calculate the radius of the cluster.
public float Radius() {
if (IsEmpty()) {
return 0;
}

Vector3 centroid = Centroid();
return points.Max(point => Vector3.Distance(centroid, point));
}

// Calculate the centroid of the cluster.
public Vector3 Centroid() {
if (IsEmpty()) {
return Vector3.zero;
}

Vector3 centroid = Vector3.zero;
foreach (var point in points) {
centroid += point;
}
centroid /= points.Count;
return centroid;
}

// Recenter the cluster's centroid to be the mean of all points in the cluster.
public void Recenter() {
centroid = Centroid();
}

// Add a point to the cluster.
// This function does not update the centroid of the cluster.
public void AddPoint(in Vector3 point) {
points.Add(point);
}

// Add multiple points to the cluster.
// This function does not update the centroid of the cluster.
public void AddPoints(in IReadOnlyList<Vector3> otherPoints) {
points.AddRange(otherPoints);
}

// Merge another cluster into this one.
// This function does not update the centroid of the cluster.
public void Merge(in Cluster cluster) {
AddPoints(cluster.Points);
}
}
2 changes: 2 additions & 0 deletions Assets/Scripts/Algorithms/Cluster.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

95 changes: 95 additions & 0 deletions Assets/Tests/EditMode/ClusterTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
using System.Collections;
using System.Collections.Generic;

public class ClusterTest {
public static Cluster GenerateCluster(in IReadOnlyList<Vector3> points) {
Cluster cluster = new Cluster();
cluster.AddPoints(points);
cluster.Recenter();
return cluster;
}

[Test]
public void TestSize() {
const int size = 10;
List<Vector3> points = new List<Vector3>();
for (int i = 0; i < size; ++i) {
points.Add(new Vector3(0, i, 0));
}
Cluster cluster = GenerateCluster(points);
Assert.AreEqual(cluster.Size(), size);
}

[Test]
public void TestIsEmpty() {
Cluster emptyCluster = new Cluster();
Assert.IsTrue(emptyCluster.IsEmpty());

Cluster cluster = new Cluster();
cluster.AddPoint(new Vector3(1, -1, 0));
Assert.IsFalse(cluster.IsEmpty());
}

[Test]
public void TestRadius() {
const float radius = 5;
List<Vector3> points = new List<Vector3> {
new Vector3(0, radius, 0),
new Vector3(0, -radius, 0),
};
Cluster cluster = GenerateCluster(points);
Assert.AreEqual(cluster.Radius(), radius);
}

[Test]
public void TestCentroid() {
const float radius = 3;
List<Vector3> points = new List<Vector3>();
for (int i = -1; i <= 1; ++i) {
for (int j = -1; j <= 1; ++j) {
points.Add(new Vector3(i, j, 0));
}
}
Cluster cluster = GenerateCluster(points);
Assert.AreEqual(cluster.Centroid(), Vector3.zero);
}

[Test]
public void TestRecenter() {
const float radius = 3;
List<Vector3> points = new List<Vector3>();
for (int i = -1; i <= 1; ++i) {
for (int j = -1; j <= 1; ++j) {
points.Add(new Vector3(i, j, 0));
}
}
Cluster cluster = GenerateCluster(points);
cluster.AddPoint(new Vector3(10, -10, 0));
cluster.Recenter();
Assert.AreEqual(cluster.Centroid(), new Vector3(1, -1, 0));
}

[Test]
public void TestMerge() {
const int size = 10;
List<Vector3> points1 = new List<Vector3>();
List<Vector3> points2 = new List<Vector3>();
for (int i = 0; i < size; ++i) {
points1.Add(new Vector3(0, i, 0));
points2.Add(new Vector3(i, 0, 0));
}
Cluster cluster1 = GenerateCluster(points1);
Cluster cluster2 = GenerateCluster(points2);
int size1 = cluster1.Size();
int size2 = cluster2.Size();
Vector3 centroid1 = cluster1.Centroid();
Vector3 centroid2 = cluster2.Centroid();
cluster1.Merge(cluster2);
cluster1.Recenter();
Assert.AreEqual(cluster1.Size(), size1 + size2);
Assert.AreEqual(cluster1.Centroid(), (centroid1 + centroid2) / 2);
}
}
2 changes: 2 additions & 0 deletions Assets/Tests/EditMode/ClusterTest.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit d5c865b

Please sign in to comment.