about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--quadtree.go51
-rw-r--r--quadtree_test.go1603
2 files changed, 1635 insertions, 19 deletions
diff --git a/quadtree.go b/quadtree.go
index 07bbe73..8d74804 100644
--- a/quadtree.go
+++ b/quadtree.go
@@ -5,6 +5,7 @@ import (
 	"io/ioutil"
 	"log"
 	"math"
+	"os"
 	"os/exec"
 )
 
@@ -42,7 +43,7 @@ func NewNode(bounadry BoundingBox) *Node {
 }
 
 // Subdivide the tree
-func (n *Node) subdivide() {
+func (n *Node) Subdivide() {
 
 	// define new values defining the new BoundaryBoxes
 	newBoundaryWidth := n.Boundry.Width / 2
@@ -89,7 +90,7 @@ func (n *Node) Insert(star Star2D) error {
 
 		// if the node does not all ready have child nodes, subdivide it
 		if n.Subtrees == ([4]*Node{}) {
-			n.subdivide()
+			n.Subdivide()
 		}
 
 		// Insert the blocking star into it's subtree
@@ -205,40 +206,51 @@ func (n Node) GetAllStars() []Star2D {
 	return listOfNodes
 }
 
-// CalcCenterOfMass calculates the center of mass for every node in the treee
-func (n *Node) CalcCenterOfMass() Vec2 {
-	fmt.Printf("[CalcCenterOfMass] %v\n", n.Boundry.Width)
+// CalcCenterOfMass calculates the center of mass for every node in the tree
+func (n *Node) calcCenterOfMass() Vec2 {
 
-	if n.Boundry.Width < 10 {
-		return Vec2{}
-	}
+	nominatorX := 0.0
+	denominatorX := 0.0
+
+	nominatorY := 0.0
+	denominatorY := 0.0
 
 	// if the subtrees are not empty
 	if n.Subtrees != ([4]*Node{}) {
+		for _, star := range n.Subtrees {
+			fmt.Println(star)
+		}
 		for i := 0; i < len(n.Subtrees); i++ {
-			// get the center of mass for the subtree
-			subtreeCenterOfMassX := n.Subtrees[i].CalcCenterOfMass().X
-			subtreeCenterOfMassY := n.Subtrees[i].CalcCenterOfMass().Y
-
-			// get the totalmass of the subtree
-			subtreeTotalMass := n.Subtrees[i].TotalMass
+			nominatorX += n.Subtrees[i].calcCenterOfMass().X * n.Subtrees[i].TotalMass
+			denominatorX += n.Subtrees[i].TotalMass
 
-			// calculate the center of mass of both
-			n.CenterOfMass.X = subtreeCenterOfMassX * subtreeTotalMass
-			n.CenterOfMass.Y = subtreeCenterOfMassY * subtreeTotalMass
+			nominatorY += n.Subtrees[i].calcCenterOfMass().Y * n.Subtrees[i].TotalMass
+			denominatorY += n.Subtrees[i].TotalMass
 		}
 	}
 
 	if n.Star != (Star2D{}) {
 		n.CenterOfMass = n.Star.C
+		fmt.Println(n.Star)
 	}
 
-	n.CenterOfMass.X = n.CenterOfMass.X / n.TotalMass
-	n.CenterOfMass.Y = n.CenterOfMass.Y / n.TotalMass
+	comX := nominatorX / denominatorX
+	comY := nominatorY / denominatorY
+	fmt.Printf("nomX: %f \t denomX: %f\n", nominatorX, denominatorX)
+	fmt.Printf("nomY: %f \t denomY: %f\n", nominatorY, denominatorY)
+
+	n.CenterOfMass = Vec2{comX, comY}
 
 	return n.CenterOfMass
 }
 
+func (n *Node) CalcCenterOfMass() Vec2 {
+	tree := n.GenForestTree(n)
+	fmt.Println(tree)
+	centerOfMass := n.calcCenterOfMass()
+	return centerOfMass
+}
+
 // CalcTotalMass calculates the total mass for every node in the tree
 func (n *Node) CalcTotalMass() float64 {
 
@@ -260,6 +272,7 @@ func (n *Node) CalcTotalMass() float64 {
 // CalcAllForces calculates the force acting in between the given star and all the other stars using the given theta.
 // It gets all the other stars from the root node it is called on
 func (n Node) CalcAllForces(star Star2D, theta float64) Vec2 {
+	log.SetOutput(os.Stderr)
 
 	// initialize a variable storing the overall force
 	var localForce Vec2 = Vec2{}
diff --git a/quadtree_test.go b/quadtree_test.go
new file mode 100644
index 0000000..76ee7c4
--- /dev/null
+++ b/quadtree_test.go
@@ -0,0 +1,1603 @@
+package structs
+
+import (
+	"fmt"
+	"reflect"
+	"testing"
+)
+
+// The example below creates a new root node at (0, 0) with the given width.
+// The width given in this case is 100.
+func ExampleNewRoot() {
+	root := NewRoot(100)
+	fmt.Printf("%v\n", root)
+	// Output: &{{{0 0} 100} {0 0} 0 0 {{0 0} {0 0} 0} [<nil> <nil> <nil> <nil>]}
+}
+
+func TestNewRoot(t *testing.T) {
+	type args struct {
+		BoundingBoxWidth float64
+	}
+	tests := []struct {
+		name string
+		args args
+		want *Node
+	}{
+		{
+			name: "New root at (0, 0) with a width of 100",
+			args: args{
+				BoundingBoxWidth: 100,
+			},
+			want: &Node{
+				Boundry: BoundingBox{
+					Center: Vec2{
+						X: 0,
+						Y: 0,
+					},
+					Width: 100,
+				},
+				CenterOfMass: Vec2{
+					X: 0,
+					Y: 0,
+				},
+				TotalMass: 0,
+				Depth:     0,
+				Star: Star2D{
+					C: Vec2{
+						X: 0,
+						Y: 0,
+					},
+					V: Vec2{
+						X: 0,
+						Y: 0,
+					},
+					M: 0,
+				},
+				Subtrees: [4]*Node{},
+			},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if got := NewRoot(tt.args.BoundingBoxWidth); !reflect.DeepEqual(got, tt.want) {
+				t.Errorf("NewRoot() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+// The example below creates a new node using the given bounding box
+func ExampleNewNode() {
+	newNode := NewNode(BoundingBox{
+		Center: Vec2{
+			X: 25,
+			Y: 25,
+		},
+		Width: 50,
+	})
+	fmt.Printf("%v\n", newNode)
+	// Output: &{{{25 25} 50} {0 0} 0 0 {{0 0} {0 0} 0} [<nil> <nil> <nil> <nil>]}
+}
+
+func TestNewNode(t *testing.T) {
+	type args struct {
+		bounadry BoundingBox
+	}
+	tests := []struct {
+		name string
+		args args
+		want *Node
+	}{
+		{
+			name: "Return a new node",
+			args: args{
+				bounadry: BoundingBox{
+					Center: Vec2{
+						X: 3,
+						Y: 15,
+					},
+					Width: 100,
+				},
+			},
+			want: &Node{
+				Boundry: BoundingBox{
+					Center: Vec2{
+						X: 3,
+						Y: 15,
+					},
+					Width: 100,
+				},
+				CenterOfMass: Vec2{
+					X: 0,
+					Y: 0,
+				},
+				TotalMass: 0,
+				Depth:     0,
+				Star: Star2D{
+					C: Vec2{
+						X: 0,
+						Y: 0,
+					},
+					V: Vec2{
+						X: 0,
+						Y: 0,
+					},
+					M: 0,
+				},
+				Subtrees: [4]*Node{},
+			},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if got := NewNode(tt.args.bounadry); !reflect.DeepEqual(got, tt.want) {
+				t.Errorf("NewNode() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+// The example below subdivides the node it is called on.
+// The function inserts four pointers pointing to other nodes into the subtree array representing the quadrants.
+//
+// The Code below prints the four subtrees that where generated:
+func ExampleNode_Subdivide() {
+	root := NewRoot(100)
+	root.Subdivide()
+	for i := 0; i < 4; i++ {
+		fmt.Printf("%v\n", root.Subtrees[i])
+	}
+	// Output:
+	// &{{{-25 25} 50} {0 0} 0 0 {{0 0} {0 0} 0} [<nil> <nil> <nil> <nil>]}
+	// &{{{25 25} 50} {0 0} 0 0 {{0 0} {0 0} 0} [<nil> <nil> <nil> <nil>]}
+	// &{{{-25 -25} 50} {0 0} 0 0 {{0 0} {0 0} 0} [<nil> <nil> <nil> <nil>]}
+	// &{{{25 -25} 50} {0 0} 0 0 {{0 0} {0 0} 0} [<nil> <nil> <nil> <nil>]}
+}
+
+func TestNode_Subdivide(t *testing.T) {
+	type fields struct {
+		Boundry      BoundingBox
+		CenterOfMass Vec2
+		TotalMass    float64
+		Depth        int
+		Star         Star2D
+		Subtrees     [4]*Node
+	}
+	tests := []struct {
+		name   string
+		fields fields
+	}{
+		{
+			name: "Subdivide a tree from [100] to [[50][50][50][50]]",
+			fields: fields{
+				Boundry: BoundingBox{
+					Center: Vec2{
+						X: 0,
+						Y: 0,
+					},
+					Width: 100,
+				},
+				CenterOfMass: Vec2{
+					X: 0,
+					Y: 0,
+				},
+				TotalMass: 0,
+				Depth:     0,
+				Star: Star2D{
+					C: Vec2{
+						X: 0,
+						Y: 0,
+					},
+					V: Vec2{
+						X: 0,
+						Y: 0,
+					},
+					M: 0,
+				},
+				Subtrees: [4]*Node{
+					{
+						Boundry: BoundingBox{
+							Center: Vec2{
+								X: -25,
+								Y: 25,
+							},
+							Width: 50,
+						},
+						CenterOfMass: Vec2{
+							X: 0,
+							Y: 0,
+						},
+						TotalMass: 0,
+						Depth:     0,
+						Star: Star2D{
+							C: Vec2{
+								X: 0,
+								Y: 0,
+							},
+							V: Vec2{
+								X: 0,
+								Y: 0,
+							},
+							M: 0,
+						},
+						Subtrees: [4]*Node{},
+					},
+					{
+						Boundry: BoundingBox{
+							Center: Vec2{
+								X: 25,
+								Y: 25,
+							},
+							Width: 50,
+						},
+						CenterOfMass: Vec2{
+							X: 0,
+							Y: 0,
+						},
+						TotalMass: 0,
+						Depth:     0,
+						Star: Star2D{
+							C: Vec2{
+								X: 0,
+								Y: 0,
+							},
+							V: Vec2{
+								X: 0,
+								Y: 0,
+							},
+							M: 0,
+						},
+						Subtrees: [4]*Node{},
+					},
+					{
+						Boundry: BoundingBox{
+							Center: Vec2{
+								X: -25,
+								Y: -25,
+							},
+							Width: 50,
+						},
+						CenterOfMass: Vec2{
+							X: 0,
+							Y: 0,
+						},
+						TotalMass: 0,
+						Depth:     0,
+						Star: Star2D{
+							C: Vec2{
+								X: 0,
+								Y: 0,
+							},
+							V: Vec2{
+								X: 0,
+								Y: 0,
+							},
+							M: 0,
+						},
+						Subtrees: [4]*Node{},
+					},
+					{
+						Boundry: BoundingBox{
+							Center: Vec2{
+								X: 25,
+								Y: -25,
+							},
+							Width: 50,
+						},
+						CenterOfMass: Vec2{
+							X: 0,
+							Y: 0,
+						},
+						TotalMass: 0,
+						Depth:     0,
+						Star: Star2D{
+							C: Vec2{
+								X: 0,
+								Y: 0,
+							},
+							V: Vec2{
+								X: 0,
+								Y: 0,
+							},
+							M: 0,
+						},
+						Subtrees: [4]*Node{},
+					},
+				},
+			},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			n := &Node{
+				Boundry:      tt.fields.Boundry,
+				CenterOfMass: tt.fields.CenterOfMass,
+				TotalMass:    tt.fields.TotalMass,
+				Depth:        tt.fields.Depth,
+				Star:         tt.fields.Star,
+				Subtrees:     tt.fields.Subtrees,
+			}
+			n.Subdivide()
+		})
+	}
+}
+
+// Insert a star into a tree.
+// If the star cannot be inserted (e.g. recursion depth too deep), Insert() returns an error
+func ExampleNode_Insert() {
+
+	// Initialize a tree and a star
+	root := NewRoot(100)
+	star := Star2D{
+		C: Vec2{
+			X: 12,
+			Y: 34,
+		},
+		V: Vec2{
+			X: 0,
+			Y: 0,
+		},
+		M: 0,
+	}
+
+	// insert the star into the tree
+	err := root.Insert(star)
+
+	// handle potential errors
+	if err != nil {
+		panic(err)
+	}
+
+	fmt.Printf("%v", root)
+
+	// Output:
+	// Direct insert of (12.000000, 34.000000)
+	// &{{{0 0} 100} {0 0} 0 0 {{12 34} {0 0} 0} [<nil> <nil> <nil> <nil>]}
+}
+
+// Insert two stars that are very close to each other into the tree.
+// A problem arises: the tree has to be subdivided so often, that the insert function
+// raises a recursion depth error
+func ExampleNode_Insert_error() {
+
+	// Initialize a tree and two
+	root := NewRoot(100)
+	star1 := Star2D{
+		C: Vec2{
+			X: 5,
+			Y: 5,
+		},
+		V: Vec2{
+			X: 0,
+			Y: 0,
+		},
+		M: 0,
+	}
+	star2 := Star2D{
+		C: Vec2{
+			X: 5.000000000000001,
+			Y: 5.000000000000001,
+		},
+		V: Vec2{
+			X: 0,
+			Y: 0,
+		},
+		M: 0,
+	}
+
+	// insert the first star into the tree
+	err := root.Insert(star1)
+	// handle potential errors
+	if err != nil {
+		panic(err)
+	}
+
+	// insert the second star into the tree
+	err = root.Insert(star2)
+	// handle potential errors
+	if err != nil {
+		panic(err)
+	}
+
+	// Output:
+	// Direct insert of (5.000000, 5.000000)
+	// Direct insert of (5.000000, 5.000000)
+	// Direct insert of (5.000000, 5.000000)
+	// Direct insert of (5.000000, 5.000000)
+	// Direct insert of (5.000000, 5.000000)
+	// Direct insert of (5.000000, 5.000000)
+	// Direct insert of (5.000000, 5.000000)
+	// Direct insert of (5.000000, 5.000000)
+	// Direct insert of (5.000000, 5.000000)
+	// Direct insert of (5.000000, 5.000000)
+	// Direct insert of (5.000000, 5.000000)
+	// Direct insert of (5.000000, 5.000000)
+	// Direct insert of (5.000000, 5.000000)
+	// Direct insert of (5.000000, 5.000000)
+	// Direct insert of (5.000000, 5.000000)
+	// Direct insert of (5.000000, 5.000000)
+	// Direct insert of (5.000000, 5.000000)
+	// Direct insert of (5.000000, 5.000000)
+	// Direct insert of (5.000000, 5.000000)
+	// Direct insert of (5.000000, 5.000000)
+	// Direct insert of (5.000000, 5.000000)
+	// Direct insert of (5.000000, 5.000000)
+	// Direct insert of (5.000000, 5.000000)
+	// Direct insert of (5.000000, 5.000000)
+	// Direct insert of (5.000000, 5.000000)
+	// Direct insert of (5.000000, 5.000000)
+	// Direct insert of (5.000000, 5.000000)
+	// Direct insert of (5.000000, 5.000000)
+	// Direct insert of (5.000000, 5.000000)
+	// Direct insert of (5.000000, 5.000000)
+	// Direct insert of (5.000000, 5.000000)
+	// Direct insert of (5.000000, 5.000000)
+	// Direct insert of (5.000000, 5.000000)
+	// Direct insert of (5.000000, 5.000000)
+	// Direct insert of (5.000000, 5.000000)
+	// Direct insert of (5.000000, 5.000000)
+	// Direct insert of (5.000000, 5.000000)
+	// Direct insert of (5.000000, 5.000000)
+	// Direct insert of (5.000000, 5.000000)
+	// Direct insert of (5.000000, 5.000000)
+	// Direct insert of (5.000000, 5.000000)
+	// Direct insert of (5.000000, 5.000000)
+	// Direct insert of (5.000000, 5.000000)
+	// Direct insert of (5.000000, 5.000000)
+	// Direct insert of (5.000000, 5.000000)
+	// Direct insert of (5.000000, 5.000000)
+	// Direct insert of (5.000000, 5.000000)
+	// Direct insert of (5.000000, 5.000000)
+	// Direct insert of (5.000000, 5.000000)
+	// Direct insert of (5.000000, 5.000000)
+	// Could not insert star (5.000000, 5.000000) (recursion limit reached)
+	//
+	// Could not insert star (5.000000, 5.000000) (recursion limit reached)
+}
+
+func TestNode_Insert(t *testing.T) {
+	type fields struct {
+		Boundry      BoundingBox
+		CenterOfMass Vec2
+		TotalMass    float64
+		Depth        int
+		Star         Star2D
+		Subtrees     [4]*Node
+	}
+	type args struct {
+		star Star2D
+	}
+	tests := []struct {
+		name    string
+		fields  fields
+		args    args
+		wantErr bool
+	}{
+		{
+			name: "Inserting a single star into a previously empty galaxy",
+			fields: fields{
+				Boundry: BoundingBox{
+					Center: Vec2{
+						X: 0,
+						Y: 0,
+					},
+					Width: 100,
+				},
+				CenterOfMass: Vec2{
+					X: 0,
+					Y: 0,
+				},
+				TotalMass: 0,
+				Depth:     0,
+				Star: Star2D{
+					C: Vec2{
+						X: 0,
+						Y: 0,
+					},
+					V: Vec2{
+						X: 0,
+						Y: 0,
+					},
+					M: 0,
+				},
+				Subtrees: [4]*Node{},
+			},
+			args: args{
+				star: Star2D{
+					C: Vec2{
+						X: 0,
+						Y: 0,
+					},
+					V: Vec2{
+						X: 0,
+						Y: 0,
+					},
+					M: 0,
+				},
+			},
+			wantErr: false,
+		},
+		{
+			name: "Inserting a single star into a galaxy all ready containing a star",
+			fields: fields{
+				Boundry: BoundingBox{
+					Center: Vec2{
+						X: 0,
+						Y: 0,
+					},
+					Width: 100,
+				},
+				CenterOfMass: Vec2{
+					X: 0,
+					Y: 0,
+				},
+				TotalMass: 0,
+				Depth:     0,
+				Star: Star2D{
+					C: Vec2{
+						X: 2,
+						Y: 3,
+					},
+					V: Vec2{
+						X: 0,
+						Y: 0,
+					},
+					M: 0,
+				},
+				Subtrees: [4]*Node{},
+			},
+			args: args{
+				star: Star2D{
+					C: Vec2{
+						X: 10,
+						Y: 20,
+					},
+					V: Vec2{
+						X: 0,
+						Y: 0,
+					},
+					M: 0,
+				},
+			},
+			wantErr: false,
+		},
+		{
+			name: "Inserting a single star onto the boundary limit",
+			fields: fields{
+				Boundry: BoundingBox{
+					Center: Vec2{
+						X: 0,
+						Y: 0,
+					},
+					Width: 100,
+				},
+				CenterOfMass: Vec2{
+					X: 0,
+					Y: 0,
+				},
+				TotalMass: 0,
+				Depth:     0,
+				Star: Star2D{
+					C: Vec2{
+						X: 10,
+						Y: 20,
+					},
+					V: Vec2{
+						X: 0,
+						Y: 0,
+					},
+					M: 0,
+				},
+				Subtrees: [4]*Node{},
+			},
+			args: args{
+				star: Star2D{
+					C: Vec2{
+						X: 25,
+						Y: 25,
+					},
+					V: Vec2{
+						X: 0,
+						Y: 0,
+					},
+					M: 20,
+				},
+			},
+			wantErr: false,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			n := &Node{
+				Boundry:      tt.fields.Boundry,
+				CenterOfMass: tt.fields.CenterOfMass,
+				TotalMass:    tt.fields.TotalMass,
+				Depth:        tt.fields.Depth,
+				Star:         tt.fields.Star,
+				Subtrees:     tt.fields.Subtrees,
+			}
+			if err := n.Insert(tt.args.star); (err != nil) != tt.wantErr {
+				t.Errorf("Node.Insert() error = %v, wantErr %v", err, tt.wantErr)
+			}
+		})
+	}
+}
+
+// Generate a tree using the LaTeX forest tree notation
+// This is a minimal example using only a root node
+func ExampleNode_GenForestTree() { // Create a new root
+	root := NewRoot(100)
+	root.Star = Star2D{
+		C: Vec2{
+			X: 10,
+			Y: 20,
+		},
+		V: Vec2{
+			X: 0,
+			Y: 0,
+		},
+		M: 20,
+	}
+
+	// generate the tree
+	forestTree := root.GenForestTree(root)
+	fmt.Println(forestTree)
+	// Output:
+	// [10 20[][][][]]
+}
+
+// Generate a tree using the LaTeX forest tree notation.
+// This is an example displaying a bigger tree.
+func ExampleNode_GenForestTree_deepTree() {
+	// Create a new root
+	root := NewRoot(100)
+
+	// Subdivide the root multiple times
+	root.Subdivide()
+	root.Subtrees[1].Subdivide()
+
+	// Insert a star into the tree
+	root.Subtrees[1].Star = Star2D{
+		C: Vec2{
+			X: 20,
+			Y: 30,
+		},
+		V: Vec2{
+			X: 0,
+			Y: 0,
+		},
+		M: 20,
+	}
+
+	// Generate the tree
+	forestTree := root.GenForestTree(root)
+	fmt.Println(forestTree)
+	// Output:
+	// [[[][][][]][20 30[[][][][]][[][][][]][[][][][]][[][][][]]][[][][][]][[][][][]]]
+}
+
+func TestNode_GenForestTree(t *testing.T) {
+	type fields struct {
+		Boundry      BoundingBox
+		CenterOfMass Vec2
+		TotalMass    float64
+		Depth        int
+		Star         Star2D
+		Subtrees     [4]*Node
+	}
+	type args struct {
+		node *Node
+	}
+	tests := []struct {
+		name   string
+		fields fields
+		args   args
+		want   string
+	}{
+		{
+			name: "Create a forest from a single node with four subnodes",
+			fields: fields{
+				Boundry: BoundingBox{
+					Center: Vec2{
+						X: 0,
+						Y: 0,
+					},
+					Width: 100,
+				},
+				CenterOfMass: Vec2{
+					X: 0,
+					Y: 0,
+				},
+				TotalMass: 0,
+				Depth:     0,
+				Star: Star2D{
+					C: Vec2{
+						X: 0,
+						Y: 0,
+					},
+					V: Vec2{
+						X: 0,
+						Y: 0,
+					},
+					M: 0,
+				},
+				Subtrees: [4]*Node{},
+			},
+			args: args{
+				node: &Node{
+					Boundry: BoundingBox{
+						Center: Vec2{
+							X: 0,
+							Y: 0,
+						},
+						Width: 100,
+					},
+					CenterOfMass: Vec2{
+						X: 0,
+						Y: 0,
+					},
+					TotalMass: 0,
+					Depth:     0,
+					Star: Star2D{
+						C: Vec2{
+							X: 0,
+							Y: 0,
+						},
+						V: Vec2{
+							X: 0,
+							Y: 0,
+						},
+						M: 0,
+					},
+					Subtrees: [4]*Node{},
+				},
+			},
+			want: "[[][][][]]",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			n := Node{
+				Boundry:      tt.fields.Boundry,
+				CenterOfMass: tt.fields.CenterOfMass,
+				TotalMass:    tt.fields.TotalMass,
+				Depth:        tt.fields.Depth,
+				Star:         tt.fields.Star,
+				Subtrees:     tt.fields.Subtrees,
+			}
+			if got := n.GenForestTree(tt.args.node); got != tt.want {
+				t.Errorf("Node.GenForestTree() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+// Draws the tree to a pdf using lualatex for building the pdf.
+// (Luatex is used, because pdflatex apparently cannot handle such deep recursion depths)
+func ExampleNode_DrawTreeLaTeX() {
+	// create a new root node
+	root := NewRoot(100)
+
+	// write the LaTeX to out.tex and build the tex using luatex
+	root.DrawTreeLaTeX("out.tex")
+	// Output:
+}
+
+func TestNode_DrawTreeLaTeX(t *testing.T) {
+	type fields struct {
+		Boundry      BoundingBox
+		CenterOfMass Vec2
+		TotalMass    float64
+		Depth        int
+		Star         Star2D
+		Subtrees     [4]*Node
+	}
+	type args struct {
+		outpath string
+	}
+	tests := []struct {
+		name   string
+		fields fields
+		args   args
+	}{
+		{
+			name: "Draw a tree using latex",
+			fields: fields{
+				Boundry: BoundingBox{
+					Center: Vec2{
+						X: 0,
+						Y: 0,
+					},
+					Width: 0,
+				},
+				CenterOfMass: Vec2{
+					X: 0,
+					Y: 0,
+				},
+				TotalMass: 0,
+				Depth:     0,
+				Star: Star2D{
+					C: Vec2{
+						X: 0,
+						Y: 0,
+					},
+					V: Vec2{
+						X: 0,
+						Y: 0,
+					},
+					M: 0,
+				},
+				Subtrees: [4]*Node{},
+			},
+			args: args{
+				outpath: "tree.tex",
+			},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			n := Node{
+				Boundry:      tt.fields.Boundry,
+				CenterOfMass: tt.fields.CenterOfMass,
+				TotalMass:    tt.fields.TotalMass,
+				Depth:        tt.fields.Depth,
+				Star:         tt.fields.Star,
+				Subtrees:     tt.fields.Subtrees,
+			}
+			n.DrawTreeLaTeX(tt.args.outpath)
+		})
+	}
+}
+
+// GetAllStars gets all the stars from a selected tree.
+// In the example below, an empty node is generated, subdivided and two stars are inserted into it.
+// Then, a list of all stars (the two that were previously inserted) gets generated and printed.
+func ExampleNode_GetAllStars() {
+	// Define a new root node
+	root := NewRoot(100)
+
+	// Subdivide the root
+	root.Subdivide()
+
+	// Insert two stars into the tree
+	root.Subtrees[1].Star = Star2D{
+		C: Vec2{
+			X: 10,
+			Y: 20,
+		},
+		V: Vec2{
+			X: 0,
+			Y: 0,
+		},
+		M: 0,
+	}
+	root.Subtrees[3].Star = Star2D{
+		C: Vec2{
+			X: 30,
+			Y: 40,
+		},
+		V: Vec2{
+			X: 0,
+			Y: 0,
+		},
+		M: 0,
+	}
+
+	// Get the stars from the tree
+	starsList := root.GetAllStars()
+
+	// Print all the stars in the list
+	for _, star := range starsList {
+		fmt.Println(star)
+	}
+	// Output:
+	// {{10 20} {0 0} 0}
+	// {{30 40} {0 0} 0}
+}
+
+func TestNode_GetAllStars(t *testing.T) {
+	type fields struct {
+		Boundry      BoundingBox
+		CenterOfMass Vec2
+		TotalMass    float64
+		Depth        int
+		Star         Star2D
+		Subtrees     [4]*Node
+	}
+	tests := []struct {
+		name   string
+		fields fields
+		want   []Star2D
+	}{
+		{
+			name: "",
+			fields: fields{
+				Boundry: BoundingBox{
+					Center: Vec2{
+						X: 0,
+						Y: 0,
+					},
+					Width: 0,
+				},
+				CenterOfMass: Vec2{
+					X: 0,
+					Y: 0,
+				},
+				TotalMass: 0,
+				Depth:     0,
+				Star: Star2D{
+					C: Vec2{
+						X: 0,
+						Y: 0,
+					},
+					V: Vec2{
+						X: 0,
+						Y: 0,
+					},
+					M: 0,
+				},
+				Subtrees: [4]*Node{
+					{
+						Boundry: BoundingBox{
+							Center: Vec2{
+								X: -25,
+								Y: 25,
+							},
+							Width: 50,
+						},
+						CenterOfMass: Vec2{
+							X: 0,
+							Y: 0,
+						},
+						TotalMass: 0,
+						Depth:     0,
+						Star: Star2D{
+							C: Vec2{
+								X: 10,
+								Y: 20,
+							},
+							V: Vec2{
+								X: 0,
+								Y: 0,
+							},
+							M: 0,
+						},
+						Subtrees: [4]*Node{},
+					},
+					{
+						Boundry: BoundingBox{
+							Center: Vec2{
+								X: 25,
+								Y: 25,
+							},
+							Width: 50,
+						},
+						CenterOfMass: Vec2{
+							X: 0,
+							Y: 0,
+						},
+						TotalMass: 0,
+						Depth:     0,
+						Star: Star2D{
+							C: Vec2{
+								X: 30,
+								Y: 40,
+							},
+							V: Vec2{
+								X: 0,
+								Y: 0,
+							},
+							M: 0,
+						},
+						Subtrees: [4]*Node{},
+					},
+					{
+						Boundry: BoundingBox{
+							Center: Vec2{
+								X: -25,
+								Y: -25,
+							},
+							Width: 50,
+						},
+						CenterOfMass: Vec2{
+							X: 0,
+							Y: 0,
+						},
+						TotalMass: 0,
+						Depth:     0,
+						Star: Star2D{
+							C: Vec2{
+								X: 50,
+								Y: 60,
+							},
+							V: Vec2{
+								X: 0,
+								Y: 0,
+							},
+							M: 0,
+						},
+						Subtrees: [4]*Node{},
+					},
+					{
+						Boundry: BoundingBox{
+							Center: Vec2{
+								X: 25,
+								Y: -25,
+							},
+							Width: 50,
+						},
+						CenterOfMass: Vec2{
+							X: 0,
+							Y: 0,
+						},
+						TotalMass: 0,
+						Depth:     0,
+						Star: Star2D{
+							C: Vec2{
+								X: 70,
+								Y: 80,
+							},
+							V: Vec2{
+								X: 0,
+								Y: 0,
+							},
+							M: 0,
+						},
+						Subtrees: [4]*Node{},
+					},
+				},
+			},
+			want: []Star2D{
+				{
+					C: Vec2{
+						X: 10,
+						Y: 20,
+					},
+					V: Vec2{
+						X: 0,
+						Y: 0,
+					},
+					M: 0,
+				},
+				{
+					C: Vec2{
+						X: 30,
+						Y: 40,
+					},
+					V: Vec2{
+						X: 0,
+						Y: 0,
+					},
+					M: 0,
+				},
+				{
+					C: Vec2{
+						X: 50,
+						Y: 60,
+					},
+					V: Vec2{
+						X: 0,
+						Y: 0,
+					},
+					M: 0,
+				},
+				{
+					C: Vec2{
+						X: 70,
+						Y: 80,
+					},
+					V: Vec2{
+						X: 0,
+						Y: 0,
+					},
+					M: 0,
+				},
+			},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			n := Node{
+				Boundry:      tt.fields.Boundry,
+				CenterOfMass: tt.fields.CenterOfMass,
+				TotalMass:    tt.fields.TotalMass,
+				Depth:        tt.fields.Depth,
+				Star:         tt.fields.Star,
+				Subtrees:     tt.fields.Subtrees,
+			}
+			if got := n.GetAllStars(); !reflect.DeepEqual(got, tt.want) {
+				t.Errorf("Node.GetAllStars() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+// CalcCenterOfMass calculates the center of mass of the node it is called on.
+// In the example below, the Tree contains two stars with equal mass (10): (20, 30) and (-20, -30).
+func ExampleNode_CalcCenterOfMass() {
+	root := NewRoot(100)
+
+	root.Subdivide()
+
+	star1 := NewStar2D(Vec2{0, 0}, Vec2{0, 0}, 10)
+	star2 := NewStar2D(Vec2{3, 3}, Vec2{0, 0}, 10)
+
+	// Insert the stars into the tree
+	// There will be no error handling here, we'll assume that everything goes right..
+	_ = root.Insert(star1)
+	_ = root.Insert(star2)
+
+	root.CalcTotalMass()
+
+	centerOfMass := root.CalcCenterOfMass()
+	fmt.Println(centerOfMass)
+	// Output:
+}
+
+func TestNode_CalcCenterOfMass(t *testing.T) {
+	type fields struct {
+		Boundry      BoundingBox
+		CenterOfMass Vec2
+		TotalMass    float64
+		Depth        int
+		Star         Star2D
+		Subtrees     [4]*Node
+	}
+	tests := []struct {
+		name   string
+		fields fields
+		want   Vec2
+	}{
+		{
+			name: "Center of mass inbetween ",
+			fields: fields{
+				Boundry: BoundingBox{
+					Center: Vec2{
+						X: 0,
+						Y: 0,
+					},
+					Width: 0,
+				},
+				CenterOfMass: Vec2{
+					X: 0,
+					Y: 0,
+				},
+				TotalMass: 0,
+				Depth:     0,
+				Star: Star2D{
+					C: Vec2{
+						X: 0,
+						Y: 0,
+					},
+					V: Vec2{
+						X: 0,
+						Y: 0,
+					},
+					M: 0,
+				},
+				Subtrees: [4]*Node{
+					{
+						Boundry: BoundingBox{
+							Center: Vec2{
+								X: -25,
+								Y: 25,
+							},
+							Width: 50,
+						},
+						CenterOfMass: Vec2{
+							X: 0,
+							Y: 0,
+						},
+						TotalMass: 0,
+						Depth:     0,
+						Star: Star2D{
+							C: Vec2{
+								X: 10,
+								Y: 20,
+							},
+							V: Vec2{
+								X: 0,
+								Y: 0,
+							},
+							M: 0,
+						},
+						Subtrees: [4]*Node{},
+					},
+					{
+						Boundry: BoundingBox{
+							Center: Vec2{
+								X: 25,
+								Y: 25,
+							},
+							Width: 50,
+						},
+						CenterOfMass: Vec2{
+							X: 0,
+							Y: 0,
+						},
+						TotalMass: 0,
+						Depth:     0,
+						Star: Star2D{
+							C: Vec2{
+								X: 30,
+								Y: 40,
+							},
+							V: Vec2{
+								X: 0,
+								Y: 0,
+							},
+							M: 0,
+						},
+						Subtrees: [4]*Node{},
+					},
+					{
+						Boundry: BoundingBox{
+							Center: Vec2{
+								X: -25,
+								Y: -25,
+							},
+							Width: 50,
+						},
+						CenterOfMass: Vec2{
+							X: 0,
+							Y: 0,
+						},
+						TotalMass: 0,
+						Depth:     0,
+						Star: Star2D{
+							C: Vec2{
+								X: 50,
+								Y: 60,
+							},
+							V: Vec2{
+								X: 0,
+								Y: 0,
+							},
+							M: 0,
+						},
+						Subtrees: [4]*Node{},
+					},
+					{
+						Boundry: BoundingBox{
+							Center: Vec2{
+								X: 25,
+								Y: -25,
+							},
+							Width: 50,
+						},
+						CenterOfMass: Vec2{
+							X: 0,
+							Y: 0,
+						},
+						TotalMass: 0,
+						Depth:     0,
+						Star: Star2D{
+							C: Vec2{
+								X: 70,
+								Y: 80,
+							},
+							V: Vec2{
+								X: 0,
+								Y: 0,
+							},
+							M: 0,
+						},
+						Subtrees: [4]*Node{},
+					},
+				},
+			},
+			want: Vec2{
+				X: 0,
+				Y: 0,
+			},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			n := &Node{
+				Boundry:      tt.fields.Boundry,
+				CenterOfMass: tt.fields.CenterOfMass,
+				TotalMass:    tt.fields.TotalMass,
+				Depth:        tt.fields.Depth,
+				Star:         tt.fields.Star,
+				Subtrees:     tt.fields.Subtrees,
+			}
+			if got := n.CalcCenterOfMass(); !reflect.DeepEqual(got, tt.want) {
+				t.Errorf("Node.CalcCenterOfMass() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+//
+func ExampleNode_CalcTotalMass() {
+
+}
+
+func TestNode_CalcTotalMass(t *testing.T) {
+	type fields struct {
+		Boundry      BoundingBox
+		CenterOfMass Vec2
+		TotalMass    float64
+		Depth        int
+		Star         Star2D
+		Subtrees     [4]*Node
+	}
+	tests := []struct {
+		name   string
+		fields fields
+		want   float64
+	}{
+		{
+			name: "Calculating the total mass two stars",
+			fields: fields{
+				Boundry: BoundingBox{
+					Center: Vec2{
+						X: 0,
+						Y: 0,
+					},
+					Width: 0,
+				},
+				CenterOfMass: Vec2{
+					X: 0,
+					Y: 0,
+				},
+				TotalMass: 0,
+				Depth:     0,
+				Star: Star2D{
+					C: Vec2{
+						X: 0,
+						Y: 0,
+					},
+					V: Vec2{
+						X: 0,
+						Y: 0,
+					},
+					M: 0,
+				},
+				Subtrees: [4]*Node{
+					{
+						Boundry: BoundingBox{
+							Center: Vec2{
+								X: -25,
+								Y: 25,
+							},
+							Width: 50,
+						},
+						CenterOfMass: Vec2{
+							X: 0,
+							Y: 0,
+						},
+						TotalMass: 0,
+						Depth:     0,
+						Star: Star2D{
+							C: Vec2{
+								X: 10,
+								Y: 20,
+							},
+							V: Vec2{
+								X: 0,
+								Y: 0,
+							},
+							M: 42,
+						},
+						Subtrees: [4]*Node{},
+					},
+					{
+						Boundry: BoundingBox{
+							Center: Vec2{
+								X: 25,
+								Y: 25,
+							},
+							Width: 50,
+						},
+						CenterOfMass: Vec2{
+							X: 0,
+							Y: 0,
+						},
+						TotalMass: 0,
+						Depth:     0,
+						Star: Star2D{
+							C: Vec2{
+								X: 0,
+								Y: 0,
+							},
+							V: Vec2{
+								X: 0,
+								Y: 0,
+							},
+							M: 0,
+						},
+						Subtrees: [4]*Node{},
+					},
+					{
+						Boundry: BoundingBox{
+							Center: Vec2{
+								X: -25,
+								Y: -25,
+							},
+							Width: 50,
+						},
+						CenterOfMass: Vec2{
+							X: 0,
+							Y: 0,
+						},
+						TotalMass: 0,
+						Depth:     0,
+						Star: Star2D{
+							C: Vec2{
+								X: 30,
+								Y: 40,
+							},
+							V: Vec2{
+								X: 0,
+								Y: 0,
+							},
+							M: 24,
+						},
+						Subtrees: [4]*Node{},
+					},
+					{
+						Boundry: BoundingBox{
+							Center: Vec2{
+								X: 25,
+								Y: -25,
+							},
+							Width: 50,
+						},
+						CenterOfMass: Vec2{
+							X: 0,
+							Y: 0,
+						},
+						TotalMass: 0,
+						Depth:     0,
+						Star: Star2D{
+							C: Vec2{
+								X: 0,
+								Y: 0,
+							},
+							V: Vec2{
+								X: 0,
+								Y: 0,
+							},
+							M: 0,
+						},
+						Subtrees: [4]*Node{},
+					},
+				},
+			},
+			want: 66,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			n := &Node{
+				Boundry:      tt.fields.Boundry,
+				CenterOfMass: tt.fields.CenterOfMass,
+				TotalMass:    tt.fields.TotalMass,
+				Depth:        tt.fields.Depth,
+				Star:         tt.fields.Star,
+				Subtrees:     tt.fields.Subtrees,
+			}
+			if got := n.CalcTotalMass(); got != tt.want {
+				t.Errorf("Node.CalcTotalMass() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+//
+func ExampleNode_CalcAllForces() {
+
+}
+
+func TestNode_CalcAllForces(t *testing.T) {
+	type fields struct {
+		Boundry      BoundingBox
+		CenterOfMass Vec2
+		TotalMass    float64
+		Depth        int
+		Star         Star2D
+		Subtrees     [4]*Node
+	}
+	type args struct {
+		star  Star2D
+		theta float64
+	}
+	tests := []struct {
+		name   string
+		fields fields
+		args   args
+		want   Vec2
+	}{
+		{
+			name: "single star",
+			fields: fields{
+				Boundry: BoundingBox{
+					Center: Vec2{
+						X: 0,
+						Y: 0,
+					},
+					Width: 0,
+				},
+				CenterOfMass: Vec2{
+					X: 0,
+					Y: 0,
+				},
+				TotalMass: 0,
+				Depth:     0,
+				Star: Star2D{
+					C: Vec2{
+						X: 0,
+						Y: 0,
+					},
+					V: Vec2{
+						X: 0,
+						Y: 0,
+					},
+					M: 0,
+				},
+				Subtrees: [4]*Node{},
+			},
+			args: args{
+				star: Star2D{
+					C: Vec2{
+						X: 0,
+						Y: 0,
+					},
+					V: Vec2{
+						X: 0,
+						Y: 0,
+					},
+					M: 0,
+				},
+				theta: 0,
+			},
+			want: Vec2{
+				X: 0,
+				Y: 0,
+			},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			n := Node{
+				Boundry:      tt.fields.Boundry,
+				CenterOfMass: tt.fields.CenterOfMass,
+				TotalMass:    tt.fields.TotalMass,
+				Depth:        tt.fields.Depth,
+				Star:         tt.fields.Star,
+				Subtrees:     tt.fields.Subtrees,
+			}
+			if got := n.CalcAllForces(tt.args.star, tt.args.theta); !reflect.DeepEqual(got, tt.want) {
+				t.Errorf("Node.CalcAllForces() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+//
+func ExampleCalcForce() {
+
+}
+
+func TestCalcForce(t *testing.T) {
+	type args struct {
+		s1 Star2D
+		s2 Star2D
+	}
+	tests := []struct {
+		name string
+		args args
+		want Vec2
+	}{
+		// TODO: Add test cases.
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if got := CalcForce(tt.args.s1, tt.args.s2); !reflect.DeepEqual(got, tt.want) {
+				t.Errorf("CalcForce() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}