diff options
-rw-r--r-- | Dockerfile | 10 | ||||
-rw-r--r-- | docker-compose.yml | 7 | ||||
-rw-r--r-- | main.go | 196 | ||||
-rw-r--r-- | webgl/index.html | 177 |
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> |