about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Dockerfile10
-rw-r--r--docker-compose.yml7
-rw-r--r--main.go196
-rw-r--r--webgl/index.html177
4 files changed, 390 insertions, 0 deletions
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..2396314
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,10 @@
+FROM golang:latest
+
+WORKDIR /home
+
+COPY main.go /home/main.go
+
+RUN ["go", "get", "github.com/gorilla/mux"]
+RUN ["go", "get", "git.darknebu.la/GalaxySimulator/structs"]
+
+ENTRYPOINT ["go", "run", "/home/main.go"]
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..06f2545
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,7 @@
+version: '3'
+
+services:
+  db:
+    build: .
+    ports:
+      - "8015:80"
diff --git a/main.go b/main.go
new file mode 100644
index 0000000..04368e7
--- /dev/null
+++ b/main.go
@@ -0,0 +1,196 @@
+package main
+
+import (
+	"encoding/json"
+	"fmt"
+	"log"
+	"net/http"
+	"strconv"
+
+	"github.com/gorilla/mux"
+
+	"git.darknebu.la/GalaxySimulator/structs"
+)
+
+var (
+	treeArray []structs.Quadtree
+)
+
+// Get a subtree by searching a given element and returning its children recursively
+func getSubtreeHandler(w http.ResponseWriter, r *http.Request) {
+	// set the content type to json (looks fancy in firefox :D)
+	w.Header().Set("Content-Type", "application/json")
+
+	// parse the mux variables
+	vars := mux.Vars(r)
+	getIndex, strconvErr := strconv.ParseInt(vars["treeindex"], 10, 0)
+	if strconvErr != nil {
+		panic(strconvErr)
+	}
+	log.Println(getIndex)
+
+	// Convert the data to json
+	jsonData, jsonMarshalerError := json.Marshal(treeArray[getIndex])
+	if jsonMarshalerError != nil {
+		panic(jsonMarshalerError)
+	}
+
+	// print the jsonData to the ResponseWriter
+	_, printTreeErr := fmt.Fprintf(w, "%v\n", string(jsonData))
+	if printTreeErr != nil {
+		panic(printTreeErr)
+	}
+	log.Printf("The getSubtree endpoint was accessed.\n")
+}
+
+// newTreeHandler creates a new tree and adds ot the the treeArray
+func newTreeHandler(w http.ResponseWriter, r *http.Request) {
+	// set the content type to json (looks fancy in firefox :D)
+	w.Header().Set("Content-Type", "application/json")
+
+	// get the star by parsing http-post parameters
+	errParseForm := r.ParseForm() // parse the POST form
+	if errParseForm != nil {      // handle errors
+		panic(errParseForm)
+	}
+
+	// default values
+	x := 0.0
+	y := 0.0
+	width := 0.0
+
+	// values from the user
+	xTmp, _ := strconv.ParseFloat(r.Form.Get("x"), 64)     // x
+	yTmp, _ := strconv.ParseFloat(r.Form.Get("y"), 64)     // y
+	widthTmp, _ := strconv.ParseFloat(r.Form.Get("w"), 64) // bounding box width
+
+	// assign the values
+	if xTmp != 0 {
+		x = xTmp
+	}
+	if yTmp != 0 {
+		y = yTmp
+	}
+	if widthTmp != 0 {
+		width = widthTmp
+	}
+
+	// generate a new tree and add it to the treeArray
+	newTree := structs.NewQuadtree(structs.BoundingBox{
+		Center: structs.Vec2{
+			X: x,
+			Y: y,
+		},
+		Width: width,
+	})
+
+	log.Println(newTree.Boundary)
+
+	treeArray = append(treeArray, *newTree)
+
+	// convert the tree to json format
+	jsonData, jsonMarshalErr := json.Marshal(newTree)
+	if jsonMarshalErr != nil {
+		panic(jsonMarshalErr)
+	}
+
+	// return the new tree as json
+	_, _ = fmt.Fprintf(w, "%v", string(jsonData))
+
+	log.Printf("The newTree endpoint was accessed.\n")
+}
+
+// printAllHandler prints all the trees in the treeArray
+func printAllHandler(w http.ResponseWriter, r *http.Request) { // set the content type to json (looks fancy in firefox :D)
+	w.Header().Set("Content-Type", "application/json")
+
+	// Convert the data to json
+	jsonData, jsonMarshalerError := json.Marshal(treeArray)
+	if jsonMarshalerError != nil {
+		panic(jsonMarshalerError)
+	}
+
+	// print the jsonData to the ResponseWriter
+	_, printTreeErr := fmt.Fprintf(w, "%v\n", string(jsonData))
+	if printTreeErr != nil {
+		panic(printTreeErr)
+	}
+
+	log.Printf("The printAll endpoint was accessed.\n")
+}
+
+// this insert handler inserts a given star using http queries
+func insertHandler(w http.ResponseWriter, r *http.Request) {
+	// get the tree id in which the star should be inserted
+	vars := mux.Vars(r)
+	treeindex, _ := strconv.ParseInt(vars["treeindex"], 10, 0)
+	_, _ = fmt.Fprintln(w, treeindex)
+
+	// get the star by parsing http-post parameters
+	errParseForm := r.ParseForm() // parse the POST form
+	if errParseForm != nil {      // handle errors
+		panic(errParseForm)
+	}
+
+	// parse the values from the post parameters
+	x, _ := strconv.ParseFloat(r.Form.Get("x"), 64)
+	y, _ := strconv.ParseFloat(r.Form.Get("y"), 64)
+	vx, _ := strconv.ParseFloat(r.Form.Get("vx"), 64)
+	vy, _ := strconv.ParseFloat(r.Form.Get("vy"), 64)
+	m, _ := strconv.ParseFloat(r.Form.Get("m"), 64)
+
+	log.Println("------------------------------------------------------------------------------------------------")
+	log.Printf("[---] Inserting x: %f\ty: %f", x, y)
+
+	// build the star that should be inserted
+	newStar := structs.Star2D{
+		C: structs.Vec2{
+			X: x,
+			Y: y,
+		},
+		V: structs.Vec2{
+			X: vx,
+			Y: vy,
+		},
+		M: m,
+	}
+
+	treeArray[treeindex].Insert(newStar)
+}
+
+// Simple index Handler
+// TODO: Display some kind of help
+// TODO: Insert an api-documentation
+func indexHandler(w http.ResponseWriter, r *http.Request) {
+	var _, _ = fmt.Fprintf(w, "Hello from the db-container!")
+	log.Printf("The indexHandler was accessed.")
+	var _, _ = fmt.Fprintln(w, "Insert a star using > $ curl --data \"x=250&y=250&vx=0.1&vy=0.2&m=3\" http://localhost:8123/insert/0")
+}
+
+func drawTreeHandler(w http.ResponseWriter, r *http.Request) {
+	log.Println("The drawTreeHandler was accessed.")
+
+	vars := mux.Vars(r)
+	treeindex, _ := strconv.ParseInt(vars["treeindex"], 10, 0)
+	log.Println(treeindex)
+
+	if treeArray[treeindex] != (structs.Quadtree{}) {
+		log.Println(treeArray[treeindex])
+		treeArray[treeindex].Draw("/public/quadtree.png")
+	}
+
+	http.ServeFile(w, r, "/public/quadtree.png")
+}
+
+func main() {
+	router := mux.NewRouter()
+
+	router.HandleFunc("/", indexHandler).Methods("GET")
+	router.HandleFunc("/get/{treeindex}", getSubtreeHandler).Methods("GET")
+	router.HandleFunc("/new", newTreeHandler).Methods("POST")
+	router.HandleFunc("/insert/{treeindex}", insertHandler).Methods("POST")
+	router.HandleFunc("/printall", printAllHandler).Methods("GET")
+	router.HandleFunc("/drawtree/{treeindex}", drawTreeHandler).Methods("GET")
+
+	log.Fatal(http.ListenAndServe(":8015", router))
+}
diff --git a/webgl/index.html b/webgl/index.html
new file mode 100644
index 0000000..875b3d8
--- /dev/null
+++ b/webgl/index.html
@@ -0,0 +1,177 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<script src="https://d3js.org/d3.v4.min.js"></script>
+<script src="https://unpkg.com/d3-3d/build/d3-3d.min.js"></script>
+<body>
+<svg width="960" height="500"></svg>
+<style type="text/css">
+    button {
+        position: absolute;
+        right: 10px;
+        top: 10px;
+    }
+</style>
+<button>update</button>
+<script>
+    var origin = [480, 300], j = 10, scale = 20, scatter = [], yLine = [], xGrid = [], beta = 0, alpha = 0, key = function(d){ return d.id; }, startAngle = Math.PI/4;
+    var svg    = d3.select('svg').call(d3.drag().on('drag', dragged).on('start', dragStart).on('end', dragEnd)).append('g');
+    var color  = d3.scaleOrdinal(d3.schemeCategory20);
+    var mx, my, mouseX, mouseY;
+
+    var grid3d = d3._3d()
+        .shape('GRID', 20)
+        .origin(origin)
+        .rotateY( startAngle)
+        .rotateX(-startAngle)
+        .scale(scale);
+
+    var point3d = d3._3d()
+        .x(function(d){ return d.x; })
+        .y(function(d){ return d.y; })
+        .z(function(d){ return d.z; })
+        .origin(origin)
+        .rotateY( startAngle)
+        .rotateX(-startAngle)
+        .scale(scale);
+
+    var yScale3d = d3._3d()
+        .shape('LINE_STRIP')
+        .origin(origin)
+        .rotateY( startAngle)
+        .rotateX(-startAngle)
+        .scale(scale);
+
+    function processData(data, tt){
+
+        /* ----------- GRID ----------- */
+
+        var xGrid = svg.selectAll('path.grid').data(data[0], key);
+
+        xGrid
+            .enter()
+            .append('path')
+            .attr('class', '_3d grid')
+            .merge(xGrid)
+            .attr('stroke', 'black')
+            .attr('stroke-width', 0.3)
+            .attr('fill', function(d){ return d.ccw ? 'lightgrey' : '#717171'; })
+            .attr('fill-opacity', 0.9)
+            .attr('d', grid3d.draw);
+
+        xGrid.exit().remove();
+
+        /* ----------- POINTS ----------- */
+
+        var points = svg.selectAll('circle').data(data[1], key);
+
+        points
+            .enter()
+            .append('circle')
+            .attr('class', '_3d')
+            .attr('opacity', 0)
+            .attr('cx', posPointX)
+            .attr('cy', posPointY)
+            .merge(points)
+            .transition().duration(tt)
+            .attr('r', 3)
+            .attr('stroke', function(d){ return d3.color(color(d.id)).darker(3); })
+            .attr('fill', function(d){ return color(d.id); })
+            .attr('opacity', 1)
+            .attr('cx', posPointX)
+            .attr('cy', posPointY);
+
+        points.exit().remove();
+
+        /* ----------- y-Scale ----------- */
+
+        var yScale = svg.selectAll('path.yScale').data(data[2]);
+
+        yScale
+            .enter()
+            .append('path')
+            .attr('class', '_3d yScale')
+            .merge(yScale)
+            .attr('stroke', 'black')
+            .attr('stroke-width', .5)
+            .attr('d', yScale3d.draw);
+
+        yScale.exit().remove();
+
+        /* ----------- y-Scale Text ----------- */
+
+        var yText = svg.selectAll('text.yText').data(data[2][0]);
+
+        yText
+            .enter()
+            .append('text')
+            .attr('class', '_3d yText')
+            .attr('dx', '.3em')
+            .merge(yText)
+            .each(function(d){
+                d.centroid = {x: d.rotated.x, y: d.rotated.y, z: d.rotated.z};
+            })
+            .attr('x', function(d){ return d.projected.x; })
+            .attr('y', function(d){ return d.projected.y; })
+            .text(function(d){ return d[1] <= 0 ? d[1] : ''; });
+
+        yText.exit().remove();
+
+        d3.selectAll('._3d').sort(d3._3d().sort);
+    }
+
+    function posPointX(d){
+        return d.projected.x;
+    }
+
+    function posPointY(d){
+        return d.projected.y;
+    }
+
+    function init(){
+        var count = 0;
+        xGrid = [], scatter = [], yLine = [];
+        for(var z = -j; z < j; z++){
+            for(var x = -j; x < j; x++){
+                xGrid.push([x, 1, z]);
+                scatter.push({x: x, y: d3.randomUniform(0, -10)(), z: z, id: 'point_' + count++});
+            }
+        }
+
+        d3.range(-1, 11, 1).forEach(function(d){ yLine.push([-j, -d, -j]); });
+
+        var data = [
+            grid3d(xGrid),
+            point3d(scatter),
+            yScale3d([yLine])
+        ];
+        processData(data, 1000);
+    }
+
+    function dragStart(){
+        mx = d3.event.x;
+        my = d3.event.y;
+    }
+
+    function dragged(){
+        mouseX = mouseX || 0;
+        mouseY = mouseY || 0;
+        beta   = (d3.event.x - mx + mouseX) * Math.PI / 230 ;
+        alpha  = (d3.event.y - my + mouseY) * Math.PI / 230  * (-1);
+        var data = [
+            grid3d.rotateY(beta + startAngle).rotateX(alpha - startAngle)(xGrid),
+            point3d.rotateY(beta + startAngle).rotateX(alpha - startAngle)(scatter),
+            yScale3d.rotateY(beta + startAngle).rotateX(alpha - startAngle)([yLine]),
+        ];
+        processData(data, 0);
+    }
+
+    function dragEnd(){
+        mouseX = d3.event.x - mx + mouseX;
+        mouseY = d3.event.y - my + mouseY;
+    }
+
+    d3.selectAll('button').on('click', init);
+
+    init();
+</script>
+</body>