From 2ed2791528ce56b8f0eb1d7ab34e188cc3f3c951 Mon Sep 17 00:00:00 2001 From: bluesaxman Date: Tue, 8 Feb 2022 17:10:24 -0700 Subject: [PATCH] More math added to math.js bluepixle currently broken as I'm in the middle of cleaning --- libs/bluemath.js | 116 +++++++--- libs/bluepixle.js | 536 ++++++++++++---------------------------------- 2 files changed, 224 insertions(+), 428 deletions(-) diff --git a/libs/bluemath.js b/libs/bluemath.js index ec2ac63..00e7246 100644 --- a/libs/bluemath.js +++ b/libs/bluemath.js @@ -12,32 +12,62 @@ function rad2deg (rad) { class vector { constructor(dimentions=[0]) { var me = this; - this.d = Array.isArray(dimentions) ? dimentions.map(d => !isNaN(d)) : [0]; + this.d = Array.isArray(dimentions) ? dimentions.map(d => !isNaN(d) ? d : 0) : [0]; if (me.d.length == 2) { - this.getRadAngle = function (vec) { - vec = vec instanceof vector ? vec : new vector([0,0]); - var xydims = vec.d.length == 2 ? vec.d : [...me.d.map((d,i) => vec[i] ? vec[i] : 0)]; - return Math.atan2(xydims[1] - me.d[1], xydims[0] - me.d[0]); + this.getRadAngle = function (from) { + from = from instanceof vector ? from : new vector([0,0]); + return Math.atan2(me.d[1] - from.d[1], me.d[0] - from.d[0]); } - this.getDegAngle = function (vec) { - return rad2deg(me.getRadAngle(vec)); + this.getDegAngle = function (from) { + return rad2deg(me.getRadAngle(from)); } this.resize = function (newLength) { var angle = me.getDegAngle(); var soh = Math.sin(angle) * newLength; var cah = Math.cos(angle) * newLength; - me.d = [cah,soh]; + return new vector([cah,soh]); + } + + this.rotate = function (rad) { + var theta = me.getRadAngle() + rad; + var amp = me.getDistance(); + return new vector([Math.cos(theta)*amp,Math.sin(theta)*amp]); + } + + this.reflect = function (surfaceVector) { + var theta = (2 * (surfaceVector.getDegAngle() + 90)) - me.getDegAngle(); + var amp = me.getDistance(); + return new vector([Math.cos(theta)*amp,Math.sin(theta)*amp]); } + this.getPerp = function () { + return me.rotate(deg2rad(90)); + } + + this.slope = function () { + return me.d[1] / me.d[0]; + } + + this.yIntercept = function () { + if (Math.abs(me.slope()) != Infinity) { + return -(me.slope()*me.d[0])+me.d[1]; + } else { + return me.d[0]; + } + } + + this.xIntercept = function () { + return -me.yIntercept()/me.slope(); + } } } add(vec=new vector([...this.d.map(d => 0)])) { vec = vec instanceof vector ? vec : new vector([0]); - var longest = vec.d.length > this.d.length ? vec.d : this.d; + var longest = vec.d.length >= this.d.length ? vec.d : this.d; var shortest = vec.d.length < this.d.length ? vec.d : this.d; return new vector([...longest.map(function (value,index) { var small = shortest[index]; @@ -46,8 +76,8 @@ class vector { } mult(vec=new vector([...this.d.map(d => 1)])) { - vec = vec instanceof vector ? vec : new vector([0]); - var longest = vec.d.length > this.d.length ? vec.d : this.d; + vec = vec instanceof vector ? vec : new vector([...this.d.map(d => 1)]); + var longest = vec.d.length >= this.d.length ? vec.d : this.d; var shortest = vec.d.length < this.d.length ? vec.d : this.d; return new vector([...longest.map(function (value,index) { var small = shortest[index]; @@ -68,11 +98,59 @@ class vector { origin = origin instanceof vector ? origin : new vector([...this.d.map(d => 0)]); return Math.sqrt(this.d.map(function (value, index) { var ori = !isNaN(origin.d[index]) ? origin.d[index] : 0; - return Math.pow(ori - value, 2); + return Math.pow(Math.abs(ori - value), 2); }).reduce((a,b) => a + b)); } } +class lineSeg { + constructor (pointA,pointB) { + this.pointA = pointA; + this.pointB = pointB; + } + + intersect(line) { + if (line instanceof lineSeg) { + var x1 = this.pointA.d[0]; + var x2 = this.pointB.d[0]; + var x3 = line.pointA.d[0]; + var x4 = line.pointB.d[0]; + + var y1 = this.pointA.d[1]; + var y2 = this.pointB.d[1]; + var y3 = line.pointA.d[1]; + var y4 = line.pointB.d[1]; + + var deltaAX = x1 - x2; + var deltaBX = x3 - x4; + var deltaAY = y1 - y2; + var deltaBY = y3 - y4; + + // I don't know wtf to call these + var ground = deltaAX*deltaBY-deltaAY*deltaBX; + var Across = x1*y2 - y1*x2; + var Bcross = x3*y4 - y3*x4; + + var x = (Across*deltaBX-deltaAX*Bcross)/ground; + var y = (Across*deltaBY-deltaAY*Bcross)/ground; + + if ( + (new bound([x1],[x2])).inbounds([x]) && + (new bound([x3],[x4])).inbounds([x]) && + (new bound([y1],[y2])).inbounds([y]) && + (new bound([y3],[y4])).inbounds([y])) { + return new vector([x,y]); + } else { + return false; + } + + } else { + throw new TypeError("must check against line"); + } + } + +} + function rad2vec (rad) { var x = Math.cos(rad); var y = Math.sin(rad); @@ -83,19 +161,6 @@ function deg2vec (deg) { //abstraction, really just for sanity return rad2vec(deg2rad(deg)); } -function getAngle(ax,ay,bx,by) { - var deltaX = bx - ax; - var deltaY = by - ay; - return rad2deg(Math.atan2(deltaY,deltaX)); -} - -function reflect(inAngle,surfaceAngle) { - var normal = surfaceAngle+90; - var theta1 = normal - inAngle; - var theta2 = normal + theta1; - return theta2; -} - class bound { constructor (min=[-Infinity],max=[Infinity]) { // Insure both inputs are arrays with valid numbers @@ -238,4 +303,3 @@ class matrix { } } } - diff --git a/libs/bluepixle.js b/libs/bluepixle.js index 9bed14e..6944f54 100644 --- a/libs/bluepixle.js +++ b/libs/bluepixle.js @@ -2,37 +2,145 @@ // This library is to help make using canvas tags easier // requires bluemath.js -function drift(object) { - if (object instanceof container) { - object.direction = "number" == typeof object.direction ? - object.direction : Math.floor(Math.random()*360); - object.speed = "number" == typeof object.speed ? object.speed : 1; - object.move(object.direction,object.speed); - } else { - return new TypeError("must provide a container object"); +class shape { + constructor(type,coordinates,dimentions,rotation,fColor,bColor,bStyle,extraObject) { + this.type = "string" == typeof type ? (["rect","elipse","image"].includes(type) ? type : "rect") : "rect"; + this.coordinates = coordinates instanceof vector ? coordinates : new vector([0,0]); + this.dimentions = dimentions instanceof vector ? dimentions : new vector([1,1]); + this.rotation = rotation instanceof vector ? rotation : new vector([0,1]); + this.fColor = "string" == typeof fColor ? fColor : undefined; + this.bColor = "string" == typeof bColor ? bColor : undefined; + this.bStyle = "number" == typeof bStyle ? bStyle : undefined; + this.extraObject = "object" == typeof extraObject ? extraObject : {}; + if ("image" == this.type) { + this.imageData = + this.extraObject.imageData instanceof ImageData ? + this.extraObject.imageData : + new ImageData( + new Uint8ClampedArray([ + 255,0,0,255, + 0,0,0,0, + 255,0,0,255, + 0,0,0,0, + 255,0,0,255, + 0,0,0,0, + 255,0,0,255, + 0,0,0,0, + 255,0,0,255 + ]),3,3); + this.image = createImageBitmap(this.imageData); + } + + } + + render(ctx,position,rotation) { + // Save current defaults + var local = {}; + local.fillStyle = "string" == typeof ctx.fillStyle ? ctx.fillStyle : undefined; + local.strokeStyle = "string" == ctx.strokeStyle ? ctx.strokeStyle : undefined; + local.lineWidth = "number" == ctx.lineWidth ? ctx.lineWidth : undefined; + local.imageSmoothingEnabled = ctx.imageSmoothingEnabled; + // calculate origin and rotation + var origin = this.coordinates.add(position instanceof vector ? position : new vector([0,0])); + var origRot = this.rotation.getRadAngle() + (rotation instanceof vector ? rotation : new vector([0,1])).getRadAngle(); + var center = origin.add(this.dimentions.mag(0.5)); + // Rotate + ctx.translate(center.d[0],center.d[1]); + ctx.rotate(origRot); + ctx.translate(-center.d[0],-center.d[1]); + // Draw + ctx.fillStyle = this.fcolor; + ctx.strokeStyle = this.bColor; + ctx.lineWidth = this.bStyle; + if("rect" == this.type) { + ctx.fillRect(origin.d[0],origin.d[1],this.dimentions.d[0],this.dimentions.d[1]); + ctx.strokeRect(origin.d[0],origin.d[1],this.dimentions.d[0],this.dimentions.d[1]); + } else if ("elipse" == this.type) { + ctx.beginPath(); + ctx.ellipse(center.d[0],center.d[1],dimentions.d[0]/2,dimentions.d[1]/2,0,0,360); + ctx.stroke(); + ctx.fill(); + } else if ("image" == this.type) { + this.image.then(function (image) { + ctx.imageSmoothingEnabled = false; + ctx.drawImage(image,origin.d[0],origin.d[0],this.dimentions.d[0],this.dimentions.d[1]); + }); + } + // restore context defaults + ctx.setTransform(1,0,0,1,0,0); + ctx.fillStyle = local.fillStyle; + ctx.strokeStyle = local.strokeStyle; + ctx.lineWidth = local.lineWidth; + ctx.imageSmoothingEnabled = local.imageSmoothingEnabled; + } + + grow (amp) { + this.dimentions = this.dimentions.amp(amp); } } -function bounce(object, surface, impactTime) { - object.direction = reflect(object.direction,surface.direction-90); - object.speed = object.speed; -} - -function valueBetween (value,low,high) { - var Tlow = low <= high ? low : high; - var Thigh = high >= low ? high : low; - if ( (value >= Tlow) & (value <= Thigh) ) { - return true; - } else { - return false; +class container { + constructor(coordinates,dimentions,rotation) { + this.coordinates = coordinates instanceof vector ? coordinates : new vector([0,0]); + this.size = dimentions instanceof vector ? dimentions : new vector([1,1]); + this.rotation = rotation instanceof vector ? rotation : new vector([0,1]); + this.movementVector = new vector([0,0]); + this.shapes = []; + this.containers = []; } -} -function pointInside (x,y,top,right,bottom,left) { - if ( valueBetween(x,left,right) & valueBetween(y,top,bottom) ) { - return true; - } else { - return false; + addShape(myShape) { + if (myShape instanceof shape) { + this.shapes.push(myShape); + } else { + throw new TypeError("addShape Method must be given a shape object"); + } + } + + addContainer(myContainer) { + if (myContainer instanceof container) { + this.containers.push(container); + } else { + throw new TypeError("addContainer Method must be given a container object"); + } + } + + move(delta) { + delta = !isNaN(delta) ? delta : 0; + this.coordinates = this.coordinates.add(this.movementVector.mag(delta)); + } + + renderContainer(ctx,position,rotation) { + position = position instanceof vector ? position : new vector([0,0]); + rotation = rotation instanceof vector ? rotation : new vector([0,1]); + var refPos = this.coordinates.add(position); + var refRot = this.rotation.add(rotation); + if (this.shapes.length) { + this.shapes.forEach(shape => shape.render(ctx,refPos,refRot)); + } + if (this.containers.length) { + this.containers.forEach(container => container.renderContainer(ctx,refPos,refRot)); + } + } + + grow(amp) { + amp = !isNaN(amp) ? amp : 1; + this.position.mag(amp); + if (this.shapes.length) { + this.shapes.forEach(shape => shape.grow(amp)); + } + if (this.containers.length) { + this.containers.forEach( container => container.grow(amp)); + } + } + + bounce(surface) { + this.movementVector = this.movementVector.reflect(surface); + } + + overlap(otherContainer, callbackFunction) { +///////////////////////////////// work starts here + this. } } @@ -103,44 +211,6 @@ function chase (source,target,max,minDis,acc) { } } -function rect (ctx,xOrigin,yOrigin,width,height,fill,stroke,outlineWidth) { -// Save current defaults - var local = {}; - local.fillStyle = "string" == typeof ctx.fillStyle ? ctx.fillStyle : undefined; - local.strokeStyle = "string" == ctx.strokeStyle ? ctx.strokeStyle : undefined; - local.lineWidth = "number" == ctx.lineWidth ? ctx.lineWidth : undefined; -// Check inputs - ctx.fillStyle = "string" == typeof fill ? fill : local.fillStyle; - ctx.strokeStyle = "string" == typeof stroke ? stroke : "rgba(0,0,0,0)"; - ctx.lineWidth = "number" == typeof outlineWidth ? outlineWidth : 1; - ctx.fillRect(xOrigin,yOrigin,width,height); - ctx.strokeRect(xOrigin,yOrigin,width,height); -// restore context defaults - ctx.fillStyle = local.fillStyle; - ctx.strokeStyle = local.strokeStyle; - ctx.lineWidth = local.lineWidth; -} - -function elip (ctx,xOrigin,yOrigin,width,height,fill,stroke,outlineWidth) { -// Save current defaults - var local = {}; - local.fillStyle = ctx.fillStyle; - local.strokeStyle = ctx.strokeStyle; - local.lineWidth = ctx.lineWidth; -// Check inputs - ctx.fillStyle = "string" == typeof fill ? fill : local.fillStyle; - ctx.strokeStyle = "string" == typeof stroke ? stroke : "rgba(0,0,0,0)"; - ctx.lineWidth = "number" == typeof outlineWidth ? outlineWidth : 1; - ctx.beginPath(); - ctx.ellipse(xOrigin,yOrigin,width,height,0,0,360); - ctx.stroke(); - ctx.fill(); -// restore context defaults - ctx.fillStyle = local.fillStyle; - ctx.strokeStyle = local.strokeStyle; - ctx.lineWidth = local.lineWidth; -} - function drawPixel (ctx, x, y, r, g, b, a) { // Always validate your input if (false == ctx instanceof CanvasRenderingContext2D) { @@ -160,344 +230,6 @@ function drawPixel (ctx, x, y, r, g, b, a) { ctx.putImageData(new ImageData(new Uint8ClampedArray([r,g,b,a]),1,1),x,y); } -class lineSeg { - constructor(x1,y1,x2,y2) { - this.pointA = new point(x1,y1); - this.pointB = new point(x2,y2); - this.center = new point((x1+x2)/2,(y1+y2)/2); - this.length = Math.sqrt( - Math.pow(Math.abs(x2-x1),2) - +Math.pow(Math.abs(y2-y1),2) - ); - this.angle = getAngle(x1,y1,x2,y2); - } - - adjustA(length) { - length = "number" == typeof length ? length : 0; - var vecC2A = new vector(getAngle( - this.center.x, - this.center.y, - this.pointA.x, - this.pointA.y), - this.length/2); - vecC2A.adjustMag(length); - this.pointA = vecC2A.executeVector(this.center.x,this.center.y); - this.center.setCoords( - (this.pointA.x+this.pointB.x)/2, - (this.pointA.y+this.pointB.y)/2); - this.length += length; - } - - adjustB(length) { - length = "number" == typeof length ? length : 0; - var vecC2B = new vector( - getAngle( - this.center.x, - this.center.y, - this.pointB.x, - this.pointB.y), - this.length/2); - vecC2B.adjustMag(length); - this.pointB = vecC2B.executeVector(this.center.x,this.center.y); - this.center.setCoords( - (this.pointA.x+this.pointB.x)/2, - (this.pointA.y+this.pointB.y)/2); - this.length += length; - } - - adjustCenter(length) { - adjustA(length/2); - adjustB(length/2); - } - - rotateA(deg) { - var abVec = new vector( - getAngle( - this.pointA.x, - this.pointA.y, - this.pointB.x, - this.pointB.y), - this.length); - abVec.adjustDir(deg); - this.pointB = abVec.executeVector(this.pointA.x,this.pointA.y); - this.center.setCoords( - (this.pointA.x+this.pointB.x)/2, - (this.pointA.y+this.pointB.y)/2); - } - - rotateB(deg) { - var baVec = new vector( - getAngle( - this.pointB.x, - this.pointB.y, - this.pointA.x, - this.pointA.y), - this.length); - baVec.adjustDir(deg); - this.pointA = baVec.executeVector(this.pointB.x,this.pointB.y); - this.center.setCoords( - (this.pointA.x+this.pointB.x)/2, - (this.pointA.y+this.pointB.y)/2); - } - - rotateCenter(deg) { - var vecC2A = new vector( - getAngle( - this.center.x, - this.center.y, - this.pointA.x, - this.pointA.y), - this.length/2); - var vecC2B = new vector( - getAngle( - this.center.x, - this.center.y, - this.pointB.x, - this.pointB.y), - this.length/2); - vecC2A.adjust(deg); - vecC2B.adjust(deg); - this.pointA = vecC2A.executeVector(this.center.x,this.center.y); - this.pointB = vecC2B.executeVector(this.center.x,this.center.y); - } - - getPerp() { - this.rotateCenter(90); - var newline = new lineSeg( - this.pointA.x, - this.pointA.y, - this.pointB.x, - this.pointB.y); - this.rotateCenter(-90); - return newline; - } - - slope() { - var deltaX = this.pointB.x - this.pointA.x; - var deltaY = this.pointB.y - this.pointA.y; - return deltaY / deltaX; - } - - xIntercept() { - return -this.yIntercept()/this.slope(); - } - - yIntercept() { - var slope = this.slope(); - if (Math.abs(slope) != Infinity) { - return -(slope*this.pointA.x)+this.pointA.y; - } else { - return this.pointA.x; - } - } - - intersect(line) { - if (line instanceof lineSeg) { - var x1 = this.pointA.x; - var x2 = this.pointB.x; - var x3 = line.pointA.x; - var x4 = line.pointB.x; - - var y1 = this.pointA.y; - var y2 = this.pointB.y; - var y3 = line.pointA.y; - var y4 = line.pointB.y; - - var deltaAX = x1 - x2; - var deltaBX = x3 - x4; - var deltaAY = y1 - y2; - var deltaBY = y3 - y4; - - // I don't know wtf to call these - var ground = deltaAX*deltaBY-deltaAY*deltaBX; - var Across = x1*y2 - y1*x2; - var Bcross = x3*y4 - y3*x4; - - var x = (Across*deltaBX-deltaAX*Bcross)/ground; - var y = (Across*deltaBY-deltaAY*Bcross)/ground; - - if ( - valueBetween(x,this.pointA.x,this.pointB.x) && - valueBetween(x,line.pointA.x,line.pointB.x) && - valueBetween(y,this.pointA.y,this.pointB.y) && - valueBetween(y,line.pointA.y,line.pointB.y)) { - return new point(x,y); - } else { - return false; - } - - } else { - throw new TypeError("must check against line"); - } - } - -} - -class shape { - constructor(type,x,y,sizeX,sizeY,fColor,bColor,bStyle,extraObject) { - this.type = "string" == typeof type ? type : "rect"; - this.x = "number" == typeof x ? x : 0; - this.y = "number" == typeof y ? y : 0; - this.sizeX = "number" == typeof sizeX ? sizeX : 1; - this.sizeY = "number" == typeof sizeY ? sizeY : 1; - this.fColor = "string" == typeof fColor ? fColor : undefined; - this.bColor = "string" == typeof bColor ? bColor : undefined; - this.bStyle = "number" == typeof bStyle ? bStyle : undefined; - this.extraObject = "object" == typeof extraObject ? extraObject : {}; - - if ("rect" == this.type) { - this.render = function (ctx,xPos,yPos) { - rect( - ctx, - this.x+xPos, - this.y+yPos, - this.sizeX, - this.sizeY, - this.fColor, - this.bColor, - this.bStyle); - } - } else if ("elipse" == this.type) { - this.render = function (ctx,xPos,yPos) { - var centerX = this.x+xPos+(this.sizeX/2); - var centerY = this.y+yPos+(this.sizeY/2); - elip( - ctx, - centerX, - centerY, - (this.sizeX/2), - (this.sizeY/2), - this.fColor, - this.bColor, - this.bStyle); - } - } else if ("image" == this.type) { - this.imageData = - this.extraObject.imageData instanceof ImageData ? - this.extraObject.imageData : - new ImageData( - new Uint8ClampedArray([ - 255,0,0,255, - 0,0,0,0, - 255,0,0,255, - 0,0,0,0, - 255,0,0,255, - 0,0,0,0, - 255,0,0,255, - 0,0,0,0, - 255,0,0,255 - ]),3,3); - this.image = createImageBitmap(this.imageData); - this.render = function (ctx,xPos,yPos) { - var x = this.x; - var y = this.y; - var sizeX = this.sizeX; - var sizeY = this.sizeY; - var contextBlur = ctx.imageSmoothingEnabled; - this.image.then(function (image) { - ctx.imageSmoothingEnabled = false; - ctx.drawImage(image,x+xPos,y+yPos,sizeX,sizeY); - ctx.imageSmoothingEnabled = contextBlur; - }); - } - } else { - console.log("no valid type defined for shape, defalting to 'rect'"); - this.render = function (ctx,xPos,yPos) { - rect( - ctx, - this.x+xPos, - this.y+yPos, - this.sizeX, - this.sizeY, - this.fColor, - this.bColor, - this.bStyle); - } - } - } - - grow (amp) { - this.sizeX+=amp; - this.sizeY+=amp; - } -} - -class container { - constructor(x,y,height,width,speed,direction) { - this.x = x; - this.y = y; - this.sizeY = height; - this.sizeX = width; - this.speed = "number" == typeof speed ? speed : 0; - this.direction = "number" == typeof direction ? direction : 0; - // Vectors are the future - this.netMovementVector = new vector( - this.direction, - this.speed); - } - - setShape(myShape) { - if (myShape instanceof shape) { - this.shape = myShape; - } else { - throw new TypeError("addShape Method must be given a shape object"); - } - } - - nestContainer() { - this.containerArray = []; - this.addShape = function (newShape) { - if (newShape instanceof shape) { - var containerIndex = this.containerArray.push( - new container(0,0,this.sizeY,this.sizeX)); - this.containerArray[containerIndex-1].setShape(newShape); - return this.containerArray[containerIndex-1]; - } else { - throw new TypeError("addShape Method must be given a shape object"); - } - }; - if (this.shape instanceof shape) { this.addShape(me.shape); } - this.shape = undefined; - this.setShape = undefined; - } - - move(direction,amplitude) { - this.direction = direction; - this.speed = amplitude; - var theta = deg2rad(direction); - this.x += Math.cos(theta) * amplitude; - this.y += Math.sin(theta) * amplitude; - } - - renderContainer(ctx,xPos,yPos) { - var refX = this.x + ("number" == typeof xPos ? xPos : 0); - var refY = this.y + ("number" == typeof yPos ? yPos : 0); - if ("object" == typeof this.shape) { - this.shape.render(ctx,refX,refY); - } else if ("object" == typeof this.containerArray) { - this.containerArray.forEach( - function (container) { - container.renderContainer(ctx,refX,refY); - }); - } else { - console.log("Container is empty!!!"); - } - } - - grow(amp) { - amp = "number"== typeof amp ? amp : 1; - this.x -= amp; - this.y -= amp; - if ("object" == typeof this.shape) { - this.shape.grow(amp); - } else if ("object" == typeof this.containerArray) { - this.containerArray.forEach( - function (container) { container.grow(amp); }); - } - } - -} - class frameBuffer { constructor(ctx, height, width) { this.ctx = ctx;