commit d575ddfd746c9ecd7d9489339bd872fb0b4feff8 Author: Benjamin Kraft Date: Sun Mar 19 10:27:50 2023 +0100 Init diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c6ef218 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.idea + diff --git a/project.json b/project.json new file mode 100644 index 0000000..f706f6a --- /dev/null +++ b/project.json @@ -0,0 +1,6 @@ +{ + "display_name": "Cross product", + "info_text": "A 3D coordinates system which supported my presentation about the cross product in math class. Switch through states with arrow keys.", + "visible": false, + "tags": ["Tool", "Maths"] +} \ No newline at end of file diff --git a/public/data/scripts/Shape.js b/public/data/scripts/Shape.js new file mode 100644 index 0000000..c791e3e --- /dev/null +++ b/public/data/scripts/Shape.js @@ -0,0 +1,130 @@ +class Arrow { + + constructor(posX, posY, posZ, dirX, dirY, dirZ, c, sp){ + this.color = color(c); + this.visible = true; + this.sphere = sp; + this.pos = createVector(posX, posY, posZ); + this.dir = createVector(dirX, dirY, dirZ); + this.end = p5.Vector.add(this.pos, this.dir); + } + + static cross(a1, a2, c){ + let v = p5.Vector.cross(a1.dir, a2.dir); + return new Arrow(a1.pos.x, a1.pos.y, a1.pos.z, v.x, v.y, v.z, c); + } + + show(){ + this.pos.mult(scale); + this.dir.mult(scale); + this.end.mult(scale); + + stroke(this.color); + strokeWeight(4); + let endV = p5.Vector.add(this.pos, this.dir); + line(this.pos.y, -this.pos.z, this.pos.x, endV.y, -endV.z, endV.x); + if (this.sphere){ + push(); + translate(this.pos.y, -this.pos.z, this.pos.x); + noStroke(); + fill(220, 200, 180); + sphere(5); + pop(); + } + + this.pos.div(scale); + this.dir.div(scale); + this.end.div(scale); + } + +} + +class Quad { + + constructor(a1, a2, c){ + this.color = color(c); + this.visible = true; + this.a1 = a1; + this.a2 = a2; + } + + show(){ + this.a1.pos.mult(scale); + this.a2.dir.mult(scale); + this.a1.end.mult(scale); + this.a2.end.mult(scale); + + ambientLight(this.color); + strokeWeight(1); + beginShape(); + vertex(this.a1.pos.y, -this.a1.pos.z, this.a1.pos.x); + vertex(this.a1.end.y, -this.a1.end.z, this.a1.end.x); + vertex(this.a1.end.y + this.a2.dir.y, -this.a1.end.z - this.a2.dir.z, this.a1.end.x + this.a2.dir.x); + vertex(this.a2.end.y, -this.a2.end.z, this.a2.end.x); + endShape(); + + this.a1.pos.div(scale); + this.a2.dir.div(scale); + this.a1.end.div(scale); + this.a2.end.div(scale); + } + +} + +class Cuboid { + + constructor(a1, a2, a3, c, h){ + this.color = color(c); + this.visible = true; + this.showHeight = h; + this.a1 = a1; + this.a2 = a2; + this.a3 = a3; + } + + show(){ + this.a1.pos.mult(scale); + this.a2.pos.mult(scale); + this.a3.pos.mult(scale); + this.a1.dir.mult(scale); + this.a2.dir.mult(scale); + this.a3.dir.mult(scale); + this.a1.end.mult(scale); + this.a2.end.mult(scale); + this.a3.end.mult(scale); + + let endDown = p5.Vector.add(this.a1.end, this.a2.dir); + let endUp = p5.Vector.add(endDown, this.a3.dir); + let a1Up = p5.Vector.add(this.a1.end, this.a3.dir); + let a2Up = p5.Vector.add(this.a2.end, this.a3.dir); + stroke(this.color); + strokeWeight(4); + line(this.a2.end.y, -this.a2.end.z, this.a2.end.x, endDown.y, -endDown.z, endDown.x); + line(this.a1.end.y, -this.a1.end.z, this.a1.end.x, endDown.y, -endDown.z, endDown.x); + line(this.a3.end.y, -this.a3.end.z, this.a3.end.x, a1Up.y, -a1Up.z, a1Up.x); + line(this.a3.end.y, -this.a3.end.z, this.a3.end.x, a2Up.y, -a2Up.z, a2Up.x); + line(a1Up.y, -a1Up.z, a1Up.x, endUp.y, -endUp.z, endUp.x); + line(a2Up.y, -a2Up.z, a2Up.x, endUp.y, -endUp.z, endUp.x); + line(this.a1.end.y, -this.a1.end.z, this.a1.end.x, a1Up.y, -a1Up.z, a1Up.x); + line(this.a2.end.y, -this.a2.end.z, this.a2.end.x, a2Up.y, -a2Up.z, a2Up.x); + line(endDown.y, -endDown.z, endDown.x, endUp.y, -endUp.z, endUp.x); + + if (this.showHeight){ + stroke(255, 255, 0); + let hDir = p5.Vector.cross(this.a1.dir, this.a2.dir); + let hLength = p5.Vector.dot(this.a3.dir, hDir) / hDir.mag(); + hDir.setMag(hLength); + line(this.a3.end.y, -this.a3.end.z, this.a3.end.x, this.a3.end.y - hDir.y, -this.a3.end.z + hDir.z, this.a3.end.x - hDir.x); + } + + this.a1.pos.div(scale); + this.a2.pos.div(scale); + this.a3.pos.div(scale); + this.a1.dir.div(scale); + this.a2.dir.div(scale); + this.a3.dir.div(scale); + this.a1.end.div(scale); + this.a2.end.div(scale); + this.a3.end.div(scale); + } +} \ No newline at end of file diff --git a/public/data/scripts/events.js b/public/data/scripts/events.js new file mode 100644 index 0000000..eed60e8 --- /dev/null +++ b/public/data/scripts/events.js @@ -0,0 +1,51 @@ +function keyPressed(){ + switch(keyCode){ + case 68: //D + debug = !debug; + return false; + case 71: //G + grid = !grid; + return false; + case RIGHT_ARROW: + if (state < 16) state++; + break; + case LEFT_ARROW: + if (state > 0) state--; + break; + } + updater(); +} + +function keyReleased(){ + switch(keyCode){ + + } +} + +function mouseDragged(){ + +} + +function mousePressed(){ + +} + +function mouseReleased(){ + +} + +function mouseWheel(event){ + scale -= event.delta > 0 ? scale / 50 : -scale / 50; + return false; +} + +window.onresize = function(event){ + resizeCanvas($("#canvasHolder").width(), $("#canvasHolder").height()); +} + +function checkKeys(){ + if (keyIsDown(UP_ARROW) && !keyIsDown(DOWN_ARROW) && scale < 100) scale += scale / 50; + if (keyIsDown(DOWN_ARROW) && !keyIsDown(UP_ARROW) && scale > 10) scale -= scale / 50; + if (scale < 10) scale = 10; + if (scale > 100) scale = 100; +} \ No newline at end of file diff --git a/public/data/scripts/lib/benjo_library.js b/public/data/scripts/lib/benjo_library.js new file mode 100644 index 0000000..872bc43 --- /dev/null +++ b/public/data/scripts/lib/benjo_library.js @@ -0,0 +1,623 @@ +var TOP = 1; +var RIGHT = 2 +var BOTTOM = 3; +var LEFT = 4; +var TOP_RIGHT = 5; +var BOTTOM_RIGHT = 6; +var BOTTOM_LEFT = 7; +var TOP_LEFT = 8; + +var wWidth = window.innerWidth; +var wHeight = window.innerHeight; +var oldWHeight; +var oldWWidth; + +let frameRateArray = []; + +function updateVars(){ + oldWWidth = wWidth; + oldWHeight = wHeight; + wWidth = window.innerWidth; + wHeight = window.innerHeight; +} + +function collisionDetection(obj0, obj1){ + + var sp = strokePadding; + if (sp == null) sp = 0; + + if (obj0.isEllipse && obj1.isRectangle){ + + //Ball + var b = obj0; + + //Rectangle + var r = obj1; + + for (var i = 0; i < TWO_PI; i += PI / 32){ + + /* Check every borderpoint of the ball beginning + at the top in clock direction up to top again */ + + // Ball Center X + var bcx = b.x; + + // Ball Center Y + var bcy = b.y; + + // Ball Border X + var bbx = b.x + sin(i) * b.r; + + // Ball Border Y inverted because Y = 0 is the TOP of the screen + var bby = b.y - cos(i) * b.r; + + // Rectangle Width + var rW = r.width + 2 * sp; + + // Rectangle Height + var rH = r.height + 2 * sp; + + // Rectangle Border X + var rX = r.x - sp; + + // Rectangle Border Y + var rY = r.y - sp; + + // Objects touch + if (bbx > rX && bbx < rX + rW + && bby > rY && bby < rY + rH){ + + // STRAIGHT FACES // + + //Top/Bottom touch + if (bcx > rX && bcx < rX + rW){ + + //Top touch + if (b.v.y > 0) return {isTouching: true, location: TOP}; + + //Bottom touch + if (b.v.y < 0) return {isTouching: true, location: BOTTOM}; + } + + //Left/Right touch + if (bcy > rY && bcy < rY + rH){ + + //Left touch + if (b.v.x > 0) return {isTouching: true, location: LEFT}; + + //Right touch + if (b.v.x < 0) return {isTouching: true, location: RIGHT}; + + } + + // CORNERS // + + // BOTTOM Left/Right + if (i > 0 && i <= PI / 2) return {isTouching: true, location: BOTTOM_LEFT}; + + //LEFT Bottom/Top + if (i > PI / 2 && i <= PI) return {isTouching: true, location: TOP_LEFT}; + + //TOP Left/Right + if (i > PI && i <= PI + PI / 2) return {isTouching: true, location: TOP_RIGHT}; + + //RIGHT Bottom/Top + if (i > PI + PI / 2 && i <= TWO_PI) return {isTouching: true, location: BOTTOM_RIGHT}; + } + } + + } + + if (obj0.isEllipse && obj1.isEllipse){ + + //Ball 1 + var b1 = obj0; + + //Ball 2 + var b2 = obj1; + + //Balls are close to each other + if (b1.x + b1.r > b2.x - b2.r + && b1.x - b1.r < b2.x + b2.r + && b1.y + b1.r > b2.y - b2.r + && b1.y - b1.r < b2.y + b2.r){ + + var distance = sqrt(pow(b1.x - b2.x, 2) + pow(b1.y - b2.y, 2)); + + if (distance < b1.r + b2.r) return {isTouching: true}; + } + } + return {isTouching: false, location: 0}; +} + +function performCollision(obj0, obj1, collision){ + if (obj0.isEllipse){ + + var ball = obj0; + + //Ball collides with frameborder + if (obj1.isFrameborder){ + switch (collision.location){ + case BOTTOM: + ball.v.y *= -1; + break; + case LEFT: + case RIGHT: + ball.v.x *= -1; + break; + } + if (testMode && collision.location == TOP) ball.v.y *= -1; + ball.move(); + } + + //Ball collides with any brick + if (obj1.isBrick){ + switch (collision.location){ + case TOP: + case BOTTOM: + ball.v.y *= -1; + ball.move(); + return; + case LEFT: + case RIGHT: + ball.v.x *= -1; + ball.move(); + return; + case TOP_LEFT: + var cornerX = obj1.x; + var cornerY = obj1.y; + break; + case TOP_RIGHT: + var cornerX = obj1.x + obj1.width; + var cornerY = obj1.y; + break; + case BOTTOM_LEFT: + var cornerX = obj1.x; + var cornerY = obj1.y + obj1.height; + break; + case BOTTOM_RIGHT: + var cornerX = obj1.x + obj1.width; + var cornerY = obj1.y + obj1.height; + break; + } + + var nx = ball.x - cornerX; + var ny = ball.y - cornerY; + var length = sqrt(nx * nx + ny * ny); + nx /= length; + ny /= length; + + var projection = ball.v.x * nx + ball.v.y * ny; + ball.v.x = ball.v.x - 2 * projection * nx; + ball.v.y = ball.v.y - 2 * projection * ny; + + ball.move(); + + } + + //Ball collides with paddleboard + if (obj1.isPaddle){ + switch (collision.location){ + case TOP: + case TOP_LEFT: + case TOP_RIGHT: + ball.v.x = ball.calcVelocityX(obj1, ball.v.x); + ball.v.y = -ball.calcVelocityY(); + ball.move(); + return; + case LEFT: + case RIGHT: + ball.v.x *= -1; + ball.move(); + return; + case BOTTOM_LEFT: + var cornerX = obj1.x; + var cornerY = obj1.y + obj1.height; + break; + case BOTTOM_RIGHT: + var cornerX = obj1.x + obj1.width; + var cornerY = obj1.y + obj1.height; + break; + } + var nx = ball.x - cornerX; + var ny = ball.y - cornerY; + var length = sqrt(nx * nx + ny * ny); + nx /= length; + ny /= length; + + var projection = ball.v.x * nx + ball.v.y * ny; + ball.v.x = ball.v.x - 2 * projection * nx; + ball.v.y = ball.v.y - 2 * projection * ny; + + ball.move(); + } + + //Ball collides with other ball + if (obj1.isEllipse){ + + //Ball 1 + var b1 = obj0; + + //Ball 2 + var b2 = obj1; + + //Set mass equal to radius of each ball + b1.mass = b1.r; + b2.mass = b2.r; + + //Colliding angle of ball 1 to ball 2 using arc tan of both x and y differences + var collisionAngle = atan2((b2.y - b1.y), (b2.x - b1.x)); + + //Converting directions of velocity vector of balls into angles + var d1 = atan2(b1.v.y, b1.v.x); + var d2 = atan2(b2.v.y, b2.v.x); + + //Ignoring mass effects new velocites are simply magnitude multiplied with value of angle differences + var newXspeed1 = b1.v.mag * cos(d1 - collisionAngle); + var newYspeed1 = b1.v.mag * sin(d1 - collisionAngle); + var newXspeed2 = b2.v.mag * cos(d2 - collisionAngle); + var newYspeed2 = b2.v.mag * sin(d2 - collisionAngle); + + //According to the principle of linear momentum, kinetic energy stays the same after collision, so velocities are now related to masses + var finalXspeed1 = ((b1.mass - b2.mass) * newXspeed1 + b2.mass * 2 * newXspeed2) / (b1.mass + b2.mass); + var finalYspeed1 = newYspeed1; + var finalXspeed2 = (b1.mass * 2 * newXspeed1 + (b2.mass - b1.mass) * newXspeed2) / (b1.mass + b2.mass); + var finalYspeed2 = newYspeed2; + + //Values of collisionAngle + var cosAngle = cos(collisionAngle); + var sinAngle = sin(collisionAngle); + + //To also keep velocites relative to pure collisionAngle, subtract sin*x from cos*x and add sin*y to cos*y because coordSystem has y = 0 on the top + var u1x = cosAngle * finalXspeed1 - sinAngle * finalYspeed1; + var u1y = sinAngle * finalXspeed1 + cosAngle * finalYspeed1; + var u2x = cosAngle * finalXspeed2 - sinAngle * finalYspeed2; + var u2y = sinAngle * finalXspeed2 + cosAngle * finalYspeed2; + + //Set new velocities to both balls + b1.v.x = u1x; + b1.v.y = u1y; + b2.v.x = u2x; + b2.v.y = u2y; + + //Update magnitude + b1.v.mag = sqrt(pow(b1.v.x, 2) + pow(b1.v.y, 2)); + b2.v.mag = sqrt(pow(b2.v.x, 2) + pow(b2.v.y, 2)); + + + //Move balls one vx/vy forward to avoid double inverting collision detection + b1.x += b1.v.x; + b1.y += b1.v.y; + b2.x += b2.v.x; + b2.y += b2.v.y; + } + } +} + + + +function toTimeString(time, hoursWanted){ + + var time = floor(time / 10); + + var hs = String(floor(time % 100)); + var fs = String(floor((time / 100) % 60)); + + if (hoursWanted){ + var min = String(floor(((time / 100) / 60) % 60)); + var hr = String(floor(((time / 100) / 60) / 60)); + + if (hs.length < 2) hs = "0" + hs; + if (fs.length < 2) fs = "0" + fs; + if (min.length < 2) min = "0" + min; + if (hr.length < 2) hr = "0" + hr; + + var timeString = hr + ":" + min + ":" + fs + ":" + hs; + } else { + var min = String(floor(((time / 100) / 60) % 60)); + + if (hs.length < 2) hs = "0" + hs; + if (fs.length < 2) fs = "0" + fs; + if (min.length < 2) min = "0" + min; + + var timeString = min + ":" + fs + ":" + hs; + } + + + + return timeString; +} + + +function setCookie(name, value, years){ + var expires = ""; + if (years){ + var date = new Date(); + date.setTime(date.getTime() + (years * 365 * 24 * 60 * 60 * 1000)); + expires = "; expires=" + date.toUTCString(); + } + document.cookie = name + "=" + value + expires + "; path=/"; +} + +function getCookie(name){ + var nameEQ = name + "="; + var ca = document.cookie.split(';'); + for (var i = 0; i < ca.length; i++){ + var c = ca[i]; + while (c.charAt(0) == ' ') c = c.substring(1, c.length); + if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length); + } + return null; +} + +function deleteCookies(){ + for (var i = 0; i < arguments.length; i++) setCookie(arguments[i], "", -1); +} + +function deleteAllCookies(){ + var cookies = document.cookie.split(";"); + for (var i = 0; i < cookies.length; i++) deleteCookies(cookies[i].split("=")[0]); +} + +Array.prototype.shuffle = function(){ + let currentIndex = this.length, temporaryValue, randomIndex; + while (0 != currentIndex){ + randomIndex = floor(random() * currentIndex); + currentIndex -= 1; + temporaryValue = this[currentIndex]; + this[currentIndex] = this[randomIndex]; + this[randomIndex] = temporaryValue; + } +} + +Array.prototype.clone = function(){ + return this.slice(0); +}; + +Array.prototype.partitiate = function(dimensions){ + if (dimensions == 0) return this; + let parts = []; + while(this.length) parts.push(this.splice(0, round(pow(this.length, 1 / (1 + 1 / dimensions)))).partitiate(dimensions - 1)); + return parts; +} + +function debugInformation(){ + let x = viewPort.x, + y = viewPort.y; + textSize(12); + textStyle(NORMAL); + stroke(255); + strokeWeight(1); + fill(255); + text("FPS : " + round(frameRate()), 10 + x, 10 + textAscent("FPS : ") + y); + text("MouseX : " + round(mouseX + x), 10 + x, 10 + textAscent("FPS : ") + 10 + textAscent("MouseX : ") + y); + text("MouseY : " + round(mouseY + y), 10 + x, 10 + textAscent("FPS : ") + 10 + textAscent("MouseX : ") + 10 + textAscent("MouseY : ") + y); +} + + + +function ColorPicker(editor) { + this.movingObject = ""; + + this.updateFromHSV = function(){ + this.h = 1 - $("#hue_picker").position().top / $("#hue").height(); + this.s = ($("#sb_picker").position().left + 8) / $("#saturation").width(); + this.v = 1 - ($("#sb_picker").position().top + 8) / $("#value").height(); + + this.r = HSVtoRGB(this.h, this.s, this.v).r; + this.g = HSVtoRGB(this.h, this.s, this.v).g; + this.b = HSVtoRGB(this.h, this.s, this.v).b; + + this.hex = RGBtoHEX(this.r, this.g, this.b); + + this.updateInterface(); + } + + this.updateFromRGB = function(){ + this.r = $($(".color_picker_rgb")[0]).val(); + this.g = $($(".color_picker_rgb")[1]).val(); + this.b = $($(".color_picker_rgb")[2]).val(); + + this.h = RGBtoHSV(this.r, this.g, this.b).h; + this.s = RGBtoHSV(this.r, this.g, this.b).s; + this.v = RGBtoHSV(this.r, this.g, this.b).v; + + this.hex = RGBtoHEX(this.r, this.g, this.b); + + this.updateFromHEX(null, true); + + this.updateInterface(); + } + + this.updateFromHEX = function(input, otf){ + if (!otf){ //Not on the fly + if ($(input).val().isValidHEX()) this.hex = $(input).val(); + else { + alert("Error!"); + return; + } + } + + this.r = HEXtoRGB(this.hex).r; + this.g = HEXtoRGB(this.hex).g; + this.b = HEXtoRGB(this.hex).b; + + this.h = RGBtoHSV(this.r, this.g, this.b).h; + this.s = RGBtoHSV(this.r, this.g, this.b).s; + this.v = RGBtoHSV(this.r, this.g, this.b).v; + + this.updateInterface(); + } + + this.updateInterface = function(){ + var o = Math.round((this.r * 299 + (this.g * 587) + (this.b * 114)) / 1000); //https://www.nbdtech.com/Blog/archive/2008/04/27/Calculating-the-Perceived-Brightness-of-a-Color.aspx + this.fontColor = (o > 125) ? "#000" : "#FFF"; + + $($(".color_picker_rgb")[0]).val(this.r); + $($(".color_picker_rgb")[1]).val(this.g); + $($(".color_picker_rgb")[2]).val(this.b); + + $("#color_picker_hex").val(this.hex); + + $("#hue_picker").css("top", (1 - this.h) * $("#hue").height()); + $("#sb_picker").css({ + "left": this.s * $("#saturation").width() - 8, + "top": (1 - this.v) * $("#value").height() - 8 + }); + + var sRGB = HSVtoRGB(this.h, 1, 1); + var saturationBackground = "linear-gradient(to right, #FFF 0%, rgb(" + + sRGB.r + "," + + sRGB.g + "," + + sRGB.b + ") 100%)"; + + $("#saturation").css("background", saturationBackground); + + /*$($(".color_picker_rgb")[0]).css({ + "background-color": "rgb(" + this.r + ", 0, 0)" + }); + $($(".color_picker_rgb")[1]).css({ + "background-color": "rgb(0, " + this.g + ", 0)" + }); + $($(".color_picker_rgb")[2]).css({ + "background-color": "rgb(0, 0, " + this.b + ")" + });*/ + //Fancy but overloaded + + $("#color_picker_hex").css({ + "background-color": this.hex, + "color": this.fontColor + }); + } + + this.mousePressed = function(){ + var x = winMouseX - $("#saturation").offset().left; + var y = winMouseY - $("#value").offset().top; + if (x > 0 && x < $("#saturation").width() && y > 0 && y < $("#value").height()){ + this.movingObject = "sb"; + } + if (x > $("#saturation").width() + 6 && x < $("#saturation").width() + 6 + $("#hue").width() && y > 0 && y < $("#hue").height()){ + this.movingObject = "hue"; + } + this.mouseDragged(); + } + + this.mouseDragged = function(){ + if (this.movingObject == "hue"){ + var objH = $("#hue"); + var picker = $("#hue_picker"); + var h = winMouseY - objH.offset().top; + if (h > 0 && h < objH.height()){ + picker.css("top", h - 1); + } else if (h > objH.height()){ + picker.css("top", objH.height() - 1); + } else if (h < 0){ + picker.css("top", -1); + } + } + + if (this.movingObject == "sb"){ + var objS = $("#saturation"); + var objV = $("#value"); + var picker = $("#sb_picker"); + var s = winMouseX - objS.offset().left; + var v = winMouseY - objV.offset().top; + if (s > 0 && s < objS.width()){ + picker.css("left", s - 8); + } else if (s < 0){ + picker.css("left", -8); + } else if (s < objS.width()){ + picker.css("left", objS.width() - 8); + } + if (v > 0 && v < objV.height()){ + picker.css("top", v - 8); + } else if (v < 0){ + picker.css("top", -8); + } else if (v > objV.height()){ + picker.css("top", objV.height() - 8); + } + } + + this.updateFromHSV(); + } + + this.mouseReleased = function(){ + this.movingObject = ""; + } + + this.getColor = function(){ + return this.hex; + } +} + +//www.stackoverflow.com --> +function RGBtoHEX(r, g, b) { + var rgb = b | (g << 8) | (r << 16); + return '#' + (0x1000000 + rgb).toString(16).slice(1); +} + +function HEXtoRGB(hex) { + var shorthandRegex = /^#?([a-fA-F\d])([a-fA-F\d])([a-fA-F\d])$/i; + hex = hex.replace(shorthandRegex, function(m, r, g, b) { + return r + r + g + g + b + b; + }); + var result = /^#?([a-fA-F\d]{2})([a-fA-F\d]{2})([a-fA-F\d]{2})$/i.exec(hex); + return result ? { + r: parseInt(result[1], 16), + g: parseInt(result[2], 16), + b: parseInt(result[3], 16) + } : null; +} + +function HSVtoRGB(h, s, v) { + var r, g, b, i, f, p, q, t; + if (arguments.length === 1) { + s = h.s, v = h.v, h = h.h; + } + i = Math.floor(h * 6); + f = h * 6 - i; + p = v * (1 - s); + q = v * (1 - f * s); + t = v * (1 - (1 - f) * s); + switch (i % 6) { + case 0: r = v, g = t, b = p; break; + case 1: r = q, g = v, b = p; break; + case 2: r = p, g = v, b = t; break; + case 3: r = p, g = q, b = v; break; + case 4: r = t, g = p, b = v; break; + case 5: r = v, g = p, b = q; break; + } + return { + r: Math.round(r * 255), + g: Math.round(g * 255), + b: Math.round(b * 255) + }; +} + +function RGBtoHSV(r, g, b) { + if (arguments.length === 1) { + g = r.g, b = r.b, r = r.r; + } + var max = Math.max(r, g, b), min = Math.min(r, g, b), + d = max - min, + h, + s = (max === 0 ? 0 : d / max), + v = max / 255; + + switch (max) { + case min: h = 0; break; + case r: h = (g - b) + d * (g < b ? 6: 0); h /= 6 * d; break; + case g: h = (b - r) + d * 2; h /= 6 * d; break; + case b: h = (r - g) + d * 4; h /= 6 * d; break; + } + + return { + h: h, + s: s, + v: v + }; +} + +String.prototype.isValidHEX = function(){ + return /(^#[0-9A-Fa-f]{6}$)|(^#[0-9A-Fa-f]{3}$)/i.test(this); +} \ No newline at end of file diff --git a/public/data/scripts/sketch.js b/public/data/scripts/sketch.js new file mode 100644 index 0000000..89b296c --- /dev/null +++ b/public/data/scripts/sketch.js @@ -0,0 +1,267 @@ +//p5 X --> Y +//p5 Y --> -Z +//p5 Z --> X + +//line(y1, -z1, x1, y2, -z2, x2) + +let debug = false, + viewPort = {x: 0, y: 0, z: 0}, + arrows = [], + quads = [], + cuboids = [], + state = 0, + scale = 25, + grid = true; + +let oldMouse = {x: 0, y: 0}, + rotation = {x: 0, y: 0}; + + +function setup() { + setFrameRate(60); + let c = createCanvas($("#canvasHolder").width(), $("#canvasHolder").height(), WEBGL); + c.parent("canvasHolder"); + $("#cheatInput").css("display", "none"); +} + +function draw() { + background(20); + translate(-50, 50, 0); + rotateX(-PI / 16); + rotateY(-PI / 8); + myOrbitControl(); + checkKeys(); + drawCoordSystem(); + for (let a of arrows) a.show(); + for (let q of quads) q.show(); + for (let c of cuboids) c.show(); +} + +let vectorA1 = () => new Arrow(2, 2, 2, 4, 0, 0, "#FFF", true); +let vectorB1 = () => new Arrow(2, 2, 2, 0, 6, 0, "#FFF"); +let vectorC1 = () => new Arrow(2, 2, 2, 3, 0, 5, "#FFF"); +let vectorA2 = () => new Arrow(2, 2, 2, 2, 3, -2, "#FFF", true); +let vectorB2 = () => new Arrow(2, 2, 2, 0, 3, 2, "#FFF"); +let vectorC2 = () => new Arrow(2, 2, 2, 3, -1, 6, "#FFF"); +let createCuboid = (a1, a2, a3, h) => new Cuboid(a1, a2, a3, color(100, 255, 255), h); +let createQuad = (a1, a2) => new Quad(a1, a2, color(255, 200, 100)); +let crossVector = (a1, a2) => Arrow.cross(a1, a2, "#FE9"); + +function drawCoordSystem(){ + + strokeWeight(5); + + let strong = 10, + weak = 150; + + let longLength = 300; + let shortLength = longLength / 3; + + let long = longLength - longLength % scale; + let short = shortLength - shortLength % scale; + + //X + stroke(strong, strong, 255); //strong + line(0, 0, long, 0, 0, 0); + stroke(weak, weak, 255); //weak + line(0, 0, 0, 0, 0, -short); + + //Y + stroke(255, strong, strong); //strong + line(long, 0, 0, 0, 0, 0); + stroke(255, weak, weak); //weak + line(0, 0, 0, -short, 0, 0); + + //Z + stroke(strong, 255, strong); //strong + line(0, -long, 0, 0, 0, 0); + stroke(weak, 255, weak); //weak + line(0, 0, 0, 0, short, 0); + + if (grid){ + strokeWeight(1); + + //Multiple for XY + stroke("rgba(255, " + weak + ", 255, 0.3)"); + for (let y = -short; y <= longLength; y += scale) line(y, 0, long, y, 0, -short); + for (let x = -short; x <= longLength; x += scale) line(long, 0, x, -short, 0, x); + + //Multiple for XZ + stroke("rgba(" + weak + ", 255, 255, 0.3)"); + for (let z = -short; z <= longLength; z += scale) line(0, -z, long, 0, -z, -short); + for (let x = -short; x <= longLength; x += scale) line(0, -long, x, 0, short, x); + + //Multiple for YZ + stroke("rgba(255, 255, " + weak + ", 0.3)"); + for (let y = -short; y <= longLength; y += scale) line(y, -long, 0, y, short, 0); + for (let z = -short; z <= longLength; z += scale) line(long, -z, 0, -short, -z, 0); + } + +} + +function myOrbitControl(){ + if (mouseIsPressed){ + rotation.x -= map(mouseY - oldMouse.y, 0, height, 0, PI); + rotation.y += map(mouseX - oldMouse.x, 0, width, 0, PI); + } + rotateX(rotation.x); + rotateY(rotation.y); + oldMouse.x = mouseX; + oldMouse.y = mouseY; +} + +function html(name, vector, first, second){ + if (name == null){ + $("#info").html(""); + return; + } + let dir = vector.dir; + $("#info").append("
"); + $("#info fieldset").last().attr({ + "class": "holder", + "id": name + }); + $("#" + name + " table tr:eq(0) td:eq(0)").html(""); + $("#" + name + " table tr:eq(0) td:eq(0)").css({"text-align": "left", "-moz-transform": "translate(-2px, 30px) scale(1, 1)"}); + $("#" + name + " table tr:eq(0) td:eq(1) span").html("("); + $("#" + name + " table tr:eq(0) td:eq(2)").html(dir.x); + $("#" + name + " table tr:eq(0) td:eq(3) span").html(")"); + $("#" + name + " table tr:eq(0) td:eq(1), #" + name + " table tr:eq(0) td:eq(3)").attr({ + "style": "font-size: 70px", + "rowspan": "3" + }); + $("#" + name + " table tr:eq(1) td:eq(0)").html(name + " = "); + $("#" + name + " table tr:eq(1) td:eq(1)").html(dir.y); + $("#" + name + " table tr:eq(2) td:eq(1)").html(dir.z); + + if (first){ + $("#" + name + " table tr:eq(0) td:eq(5), #" + name + " table tr:eq(0) td:eq(7)").html(""); + $("#" + name + " table tr:eq(0) td:eq(5), #" + name + " table tr:eq(0) td:eq(7)").css("-moz-transform", "translateY(30px)"); + $("#" + name + " table tr:eq(1) td:eq(2)").html(" = "); + $("#" + name + " table tr:eq(1) td:eq(3)").html(first); + $("#" + name + " table tr:eq(1) td:eq(4)").html("×"); + $("#" + name + " table tr:eq(1) td:eq(5)").html(second); + } +} + +function updater(){ + arrows = []; + quads = []; + cuboids = []; + html(null); + switch(state){ + case 1: + arrows.push(vectorA1()); + html("a", vectorA1()); + break; + case 2: + arrows.push(vectorA1()); + arrows.push(vectorB1()); + html("a", vectorA1()); + html("b", vectorB1()); + break; + case 3: + arrows.push(vectorA1()); + arrows.push(vectorB1()); + arrows.push(crossVector(vectorA1(), vectorB1())); + html("a", vectorA1()); + html("b", vectorB1()); + html("x", crossVector(vectorA1(), vectorB1()), "a", "b"); + break; + case 4: + arrows.push(vectorA1()); + arrows.push(vectorB1()); + arrows.push(crossVector(vectorA1(), vectorB1())); + quads.push(createQuad(vectorA1(), vectorB1())); + html("a", vectorA1()); + html("b", vectorB1()); + html("x", crossVector(vectorA1(), vectorB1()), "a", "b"); + break; + case 5: + arrows.push(vectorA1()); + arrows.push(vectorB1()); + html("a", vectorA1()); + html("b", vectorB1()); + break; + case 6: + arrows.push(vectorA1()); + arrows.push(vectorB1()); + arrows.push(vectorC1()); + html("a", vectorA1()); + html("b", vectorB1()); + html("c", vectorC1()); + break; + case 7: + arrows.push(vectorA1()); + arrows.push(vectorB1()); + arrows.push(vectorC1()); + cuboids.push(createCuboid(vectorA1(), vectorB1(), vectorC1(), true)); + html("a", vectorA1()); + html("b", vectorB1()); + html("c", vectorC1()); + break; + case 8: + arrows.push(vectorA1()); + arrows.push(vectorB1()); + arrows.push(vectorC1()); + arrows.push(crossVector(vectorA1(), vectorB1())); + cuboids.push(createCuboid(vectorA1(), vectorB1(), vectorC1(), true)); + quads.push(createQuad(vectorA1(), vectorB1())); + html("a", vectorA1()); + html("b", vectorB1()); + html("c", vectorC1()); + html("x", crossVector(vectorA1(), vectorB1()), "a", "b"); + break; + case 9: + break; + case 10: + arrows.push(vectorA2()); + html("a", vectorA2()); + break; + case 11: + arrows.push(vectorA2()); + arrows.push(vectorB2()); + html("a", vectorA2()); + html("b", vectorB2()); + break; + case 12: + arrows.push(vectorA2()); + arrows.push(vectorB2()); + arrows.push(vectorC2()); + html("a", vectorA2()); + html("b", vectorB2()); + html("c", vectorC2()); + break; + case 13: + quads.push(createQuad(vectorA2(), vectorB2())); + arrows.push(vectorA2()); + arrows.push(vectorB2()); + arrows.push(vectorC2()); + html("a", vectorA2()); + html("b", vectorB2()); + html("c", vectorC2()); + break; + case 14: + cuboids.push(createCuboid(vectorA2(), vectorB2(), vectorC2(), false)); + quads.push(createQuad(vectorA2(), vectorB2())); + arrows.push(vectorA2()); + arrows.push(vectorB2()); + arrows.push(vectorC2()); + html("a", vectorA2()); + html("b", vectorB2()); + html("c", vectorC2()); + break; + case 15: + cuboids.push(createCuboid(vectorA2(), vectorB2(), vectorC2(), false)); + quads.push(createQuad(vectorA2(), vectorB2())); + arrows.push(crossVector(vectorA2(), vectorB2())); + arrows.push(vectorA2()); + arrows.push(vectorB2()); + arrows.push(vectorC2()); + html("a", vectorA2()); + html("b", vectorB2()); + html("c", vectorC2()); + html("x", crossVector(vectorA2(), vectorB2()), "a", "b"); + break; + } +} \ No newline at end of file diff --git a/public/data/styles/._color_picker.css b/public/data/styles/._color_picker.css new file mode 100644 index 0000000..89a8b4d Binary files /dev/null and b/public/data/styles/._color_picker.css differ diff --git a/public/data/styles/TitilliumWeb-Light.ttf b/public/data/styles/TitilliumWeb-Light.ttf new file mode 100644 index 0000000..2685cbe Binary files /dev/null and b/public/data/styles/TitilliumWeb-Light.ttf differ diff --git a/public/data/styles/color_picker.css b/public/data/styles/color_picker.css new file mode 100644 index 0000000..a5b510e --- /dev/null +++ b/public/data/styles/color_picker.css @@ -0,0 +1,88 @@ +#color_picker{ + width: 300px; + height: 25%; + margin: 20px; + margin-top: 50px; + border: 5px solid #000; + background-color: #000; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + position: relative; +} +#color_picker_numeric{ + width: 80%; + padding: 5%; + margin: 5%; + background-color: #888; + border-radius: 10px; + overflow: hidden; +} +.color_picker_rgb{ + float: left; + width: 22%; + height: 35px; + font-size: 25px; + color: #000; +} +.color_picker_rgb:nth-child(1){ + margin-right: 10%; + margin-left: 3%; + background-color: #F00; + +} +.color_picker_rgb:nth-child(2){ + background-color: #0F0; +} +.color_picker_rgb:nth-child(3){ + margin-left: 10%; + background-color: #00F; + color: #FFF; +} +#color_picker_hex{ + width: 50%; + height: 30px; + font-size: 25px; + margin: 10% 25% 0 25%; +} +#saturation{ + position: relative; + width: calc(100% - 33px); + height: 100%; + background: linear-gradient(to right, #FFF 0%, #F00 100%); + float: left; + margin-right: 6px; +} +#value { + width: 100%; + height: 100%; + background: linear-gradient(to top, #000 0%, rgba(255,255,255,0) 100%); +} +#sb_picker{ + border: 2px solid; + border-color: #FFF; + position: absolute; + width: 14px; + height: 14px; + border-radius: 10px; + bottom: 50px; + left: 50px; + box-sizing: border-box; + z-index: 10; +} +#hue { + width: 27px; + height: 100%; + position: relative; + float: left; + background: linear-gradient(to bottom, #F00 0%, #F0F 17%, #00F 34%, #0FF 50%, #0F0 67%, #FF0 84%, #F00 100%); +} +#hue_picker { + position: absolute; + background: #000; + border-bottom: 1px solid #000; + top: 0; + width: 27px; + height: 2px; +} \ No newline at end of file diff --git a/public/index.html b/public/index.html new file mode 100644 index 0000000..513f68f --- /dev/null +++ b/public/index.html @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + Das Vektorprodukt + + +
+
+
+ + + \ No newline at end of file diff --git a/public/styles.css b/public/styles.css new file mode 100644 index 0000000..c79f67c --- /dev/null +++ b/public/styles.css @@ -0,0 +1,87 @@ +a:link, a:hover, a:active, a:visited{color: #000;} + +html, body{margin: 0; padding: 0; height: 100%; width: 100%; background-color: #AAA;} + +canvas{margin: 0; padding: 0; display: block;} + +button:hover{cursor: pointer;} + +#canvasHolder{ + position: absolute; + display: block; + width: calc(100% - 340px - 10px); + margin: auto; + right: 0px; + top: 0px; + bottom: 0px; +} + +@font-face { + font-family: 'TitilliumWeb'; + src: url('data/styles/TitilliumWeb-Light.ttf'); +} + +body{ + font-family: 'TitilliumWeb'; + cursor: none; + -moz-user-select: none; + -webkit-user-select: none; +} + +#info{ + background-color: #222; + position: absolute; + display: block; + width: 340px; + margin: auto; + left: 0px; + top: 0px; + bottom: 0px; + overflow: hidden; +} + +#border{ + position: absolute; + display: block; + width: 10px; + top: 0; + bottom: 0; + left: 340px; + background-color: #444; +} + +.holder{ + background-color: rgb(10, 20, 20); + position: relative; + width: 314px; + margin: 5px; + padding: 3px; + padding-top: 0px; + border: 5px solid #444; + border-radius: 5px; + color: #ddd; + font-size: 35px; +} + +p{margin-top: 5px; margin-bottom: 5px;} +legend{font-size: 30px;} + +.holder span{ + display: inline-block; + -moz-transform: scale(1,2); +} + +.holder td{ + text-align: center; + padding: 0px; +} + +#cheatInput{ + position: absolute; + margin: 0px; + padding: 0px; + bottom: 0; + right: 0; + left: 0; + width: 384px; +} \ No newline at end of file diff --git a/public/thumbnail.png b/public/thumbnail.png new file mode 100644 index 0000000..6c407da Binary files /dev/null and b/public/thumbnail.png differ