I've been struggling with this one for a couple of days now. I am trying to figure out how to make the arcs in this code rotate. I think the problem is that they are in a nested loop with random variables but I'm not sure how to fix that and still make it work.
I know I need to increase or decrease the start/stop angles in unison but to make them rotate but I need to figure out how to get static arcs once they are drawn first (i think).
Any ideas would be greatly appreciated.
let data;
let index = 0;
function preload() {
// data = loadJSON("palettes.json");
data = {
palettes: [
["#69d2e7", "#a7dbd8", "#e0e4cc", "#f38630", "#fa6900"]
]
}
}
function setup() {
createCanvas(windowWidth, windowHeight);
index = floor(random(data.palettes.length));
arcNumber = round(random(1, 3))
}
function draw() {
angleMode(DEGREES)
let palette = data.palettes[index];
let combBorderHeight = 0.2 * height
let combBorderWidth = 0.2 * width
let borderHeight = 0.1 * height
let borderWidth = 0.1 * width
stroke(palette[0])
background(palette[0])
for (let x = 0; x < 7; x++) {
for (let y = 0; y < 7; y++) {
if ((x % 2 == 0 && y % 2 == 0) || (x % 2 == 1 && y % 2 == 1)) {
fill(palette[1])
} else {
fill(palette[2])
}
rect((x + borderWidth + (x * (width - combBorderWidth) / 7)), (y + borderHeight + (y * (height - combBorderHeight) / 7)), (width - combBorderWidth) / 7, (height - combBorderWidth) / 7)
let arcNumber;
arcNumber = round(random(1, 3))
for (let i = 0; i < arcNumber; i++) {
let arcRand1 = random(10, random(0.4, 0.8) * (height - combBorderHeight) / 7)
let arcStart1 = random(0, 320)
let arcStop1 = random(arcStart1 + 40, 360)
let arcPalette = [palette[0], palette[3], palette[4]]
stroke(arcPalette[i])
push()
strokeCap(SQUARE)
strokeWeight(random(1, 10))
noFill()
arc((x + borderWidth + (x * (width - combBorderWidth) / 7) + 0.5 * (width - combBorderWidth) / 7), (y + borderHeight + (y * (height - combBorderHeight) / 7) + 0.5 * (height - combBorderHeight) / 7), arcRand1, arcRand1, arcStart1, arcStop1, OPEN, 50)
noLoop()
pop()
stroke(palette[0])
}
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.2/p5.js" integrity="sha512-+tu0+vUXyZX+S51npa//IN6znNTLZsBoy8mXn9WzHxfBqYMy6gOzzfTK0VqZf9O171RY9AJviHDokCnvEq8+1A==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
If you remove the noLoop() function things will start to rotate randomly. You may want to store all those rotation variables in a 3D array that corresponds to each square (x,y) and arc(i).
let data;
let index = 0;
var my_size = 2;
var delta_angle = 0.1
var offset_angle = 0;
function preload() {
// data = loadJSON("palettes.json");
data = {
palettes: [
["#69d2e7", "#a7dbd8", "#e0e4cc", "#f38630", "#fa6900"]
]
}
}
function setup() {
createCanvas(windowWidth, windowHeight);
index = floor(random(data.palettes.length));
arcNumber = round(random(1, 3))
}
function draw() {
angleMode(DEGREES)
let palette = data.palettes[index];
let combBorderHeight = 0.2 * height
let combBorderWidth = 0.2 * width
let borderHeight = 0.1 * height
let borderWidth = 0.1 * width
stroke(palette[0])
background(palette[0])
offset_angle += delta_angle;
for (let x = 0; x < my_size; x++) {
for (let y = 0; y < my_size; y++) {
if ((x % 2 == 0 && y % 2 == 0) || (x % 2 == 1 && y % 2 == 1)) {
fill(palette[1])
} else {
fill(palette[2])
}
rect((x + borderWidth + (x * (width - combBorderWidth) / my_size)), (y + borderHeight + (y * (height - combBorderHeight) / my_size)), (width - combBorderWidth) / my_size, (height - combBorderWidth) / my_size)
let arcNumber;
arcNumber = round(random(1, 3))
for (let i = 0; i < arcNumber; i++) {
let arcRand1 = random(10, random(0.4, 0.8) * (height - combBorderHeight) / my_size)
let arcStart1 = random(0, 320)
let arcStop1 = random(arcStart1 + 40, 360)
let arcPalette = [palette[0], palette[3], palette[4]]
stroke(arcPalette[i])
push()
strokeCap(SQUARE)
strokeWeight(random(1, 10))
noFill()
arc((x + borderWidth + (x * (width - combBorderWidth) / my_size) + 0.5 * (width - combBorderWidth) / my_size), (y + borderHeight + (y * (height - combBorderHeight) / my_size) + 0.5 * (height - combBorderHeight) / my_size), arcRand1, arcRand1, arcStart1 + offset_angle, arcStop1 + offset_angle, OPEN, 50)
// noLoop()
pop()
stroke(palette[0])
}
}
}
}
function windowResized() {
resizeCanvas(windowWidth, windowHeight);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.2/p5.js" integrity="sha512-+tu0+vUXyZX+S51npa//IN6znNTLZsBoy8mXn9WzHxfBqYMy6gOzzfTK0VqZf9O171RY9AJviHDokCnvEq8+1A==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
Related
Im noob with p5j and i need help from someone please! :-(
On the website i must upload it , they not allow the external links.
and i need to change the "let url" to a png/jpg local link ( not external link ).
i dont know what the solution is ( maybe something similar with: "loadImage" or something.... please help me :-) )
Thank you so much and have a blessed week!
Here is the code:
//let url = "https://coolors.co/3a2e39-1e555c-f4d8cd-edb183-f15152";
let url = "https://blog.logrocket.com/wp-content/uploads/2022/03/Creating-animations-p5-js.png";
let palette;
let font;
function preload() {
font = loadFont("https://openprocessing.org/sketch/1359269/files/Happy Monsters.ttf");
}
function setup() {
createCanvas(1112, 834);
colorMode(HSB, 360, 100, 100, 100);
angleMode(DEGREES);
palette = createPalette(url);
background(10);
}
function draw() {
//background(0, 0, 90);
let offset = 100//width / 100;
let margin = 0; //offset / 5;
let cells = 1//int(random(2, 8));
let d = (width - offset * 2 - margin * (cells - 1)) / cells;
for (let j = 0; j < cells; j++) {
for (let i = 0; i < cells; i++) {
let x = offset + i * (d + margin) + d / 2;
let y = offset + j * (d + margin) + d / 2;
drawFancyShape(x, y, d, palette.concat());
}
}
frameRate(0.5);
noLoop();
}
function drawFancyShape(x, y, d, colors, char = String.fromCodePoint(65 + int(random(26)))) {
let g = createGraphics(d, d);
let g2 = createGraphics(d, d);
colors = shuffle(colors);
let c0 = colors[0];
colors.splice(0, 1);
let ratio = 0.2;
let xStep, yStep;
for (let y = 0; y < g.height; y += yStep) {
yStep = random(ratio, 1 - ratio) * g.height / 2;
if (y + yStep > g.height) yStep = g.height - y;
if (g.height - y - yStep < g.height / 100) yStep = g.height - y;
for (let x = 0; x < g.width; x += xStep) {
xStep = random(ratio, 1 - ratio) * g.width / 2;
if (x + xStep > g.width) xStep = g.width - x;
if (g.width - x - xStep < g.width / 100) xStep = g.width - x;
let r = [];
for (let i = 0; i < 4; i++) {
r.push(int(random(5)) * max(xStep, yStep) / 4);
}
g.rectMode(CENTER);
g.fill(random(colors));
g.noStroke();
g.rect(x + xStep / 2, y + yStep / 2, xStep - 2, yStep - 2, r[0], r[1], r[2], r[3]);
}
}
g2.textSize(g.width * 0.6);
g2.textAlign(CENTER, CENTER);
g2.textFont(font)
g2.textStyle(BOLD);
g2.fill(c0);
// g2.stroke(0);
g2.text(char, g.width / 2, g.height / 2 - g.height / 8);
let g_tmp = g.get();
let g2_tmp = g2.get();
g_tmp.mask(g2_tmp);
// g_tmp.mask(g2_tmp);
drawingContext.shadowColor = color(0, 0, 0, 33);
drawingContext.shadowBlur = d / 10;
push();
translate(x, y);
imageMode(CENTER);
// image(g, 0, 0);
let scl = 1.1;
image(g2, 0, 0, g2.width * scl, g2.height * scl);
image(g_tmp, 0, 0, g_tmp.width * scl, g_tmp.height * scl);
pop();
}
function createPalette(_url) {
let slash_index = _url.lastIndexOf('/');
let pallate_str = _url.slice(slash_index + 1);
let arr = pallate_str.split('-');
for (let i = 0; i < arr.length; i++) {
arr[i] = color('#' + arr[i]);
}
return arr;
}
// save jpg
let lapse = 0; // mouse timer
function mousePressed(){
// prevents mouse press from registering twice
if (millis() - lapse > 400){
save("img_" + month() + '-' + day() + '_' + hour() + '-' + minute() + '-' + second() + ".jpg");
lapse = millis();
}
}
I am trying to make a raycasting game. Everything is rendered correctly except when the ray is facing up (angle > PI) or facing right(angle > 0.5PI and < 1.5PI) lines are drawn on walls. I am not sure what is causing it to happen but I know that the lines are not affected by the rotation of the player only by the players position. I tried rounding the rays position but that did not help.
I don't have enough reputation to post images.
Right and up ray walls.
(https://i.imgur.com/DKlfzM3.png)
The walls up close.
(https://i.imgur.com/orP89sT.png)
Left and down ray walls.
(https://i.imgur.com/YVggx51.png)
Code:
let rayX, rayY, rayAngle, rayDeltaX, rayDeltaY
for (let i = 0; i < this.screen.width; i ++) {
rayAngle = this.angle - this.fov / 2 + i * (this.fov / this.screen.width)
if (rayAngle < 0) {
rayAngle += Math.PI * 2
}
else if (rayAngle > Math.PI * 2) {
rayAngle -= Math.PI * 2
}
rayX = this.x
rayY = this.y
let stepY
if (rayAngle > Math.PI) {
stepY = -this.tileSize
rayY = Math.floor(rayY / this.tileSize) * this.tileSize - 1
}
else {
stepY = this.tileSize
rayY = Math.floor(rayY / this.tileSize) * this.tileSize + this.tileSize
}
rayX = this.x + (rayY - this.y) / Math.tan(rayAngle)
rayDeltaY = stepY
rayDeltaX = stepY / Math.tan(rayAngle)
while(true) {
if (this.Map.map[Math.floor(rayY / this.tileSize) * this.Map.width + Math.floor(rayX / this.tileSize)] == '#') {
break
}
rayX += rayDeltaX
rayY += rayDeltaY
}
let rayHorizontalX = rayX
let rayHorizontalY = rayY
let rayDistanceHorizontal = Math.sqrt((this.x - rayHorizontalX) ** 2 + (this.y - rayHorizontalY) ** 2)
rayX = this.x
rayY = this.y
let stepX
if (rayAngle > 0.5 * Math.PI && rayAngle < 1.5 * Math.PI) {
stepX = -this.tileSize
rayX = Math.floor(rayX / this.tileSize) * this.tileSize - 1
}
else {
stepX = this.tileSize
rayX = Math.floor(rayX / this.tileSize) * this.tileSize + this.tileSize
}
rayY = this.y + (rayX - this.x) * Math.tan(rayAngle)
rayDeltaY = stepX * Math.tan(rayAngle)
rayDeltaX = stepX
while(true) {
if (this.Map.map[Math.floor(rayY / this.tileSize) * this.Map.width + Math.floor(rayX / this.tileSize)] == '#') {
break
}
rayX += rayDeltaX
rayY += rayDeltaY
}
let rayVerticalX = rayX
let rayVerticalY = rayY
let rayDistanceVertical = Math.sqrt((this.x - rayVerticalX) ** 2 + (this.y - rayVerticalY) ** 2)
let rayFinalDistance
if (rayDistanceHorizontal < rayDistanceVertical) {
rayFinalDistance = rayDistanceHorizontal
ctx.fillStyle = 'darkblue'
}
else {
rayFinalDistance = rayDistanceVertical
ctx.fillStyle = 'blue'
}
let rayCorrectedDistance = rayFinalDistance * Math.cos(rayAngle - this.angle)
let lineHeight = this.tileSize * (this.screen.width / 2 / Math.tan(this.fov / 2)) / rayCorrectedDistance
let lineBottom = this.projectionPlane.centerY + lineHeight * 0.5
let lineTop = this.projectionPlane.height - lineBottom
ctx.fillRect(i, lineTop, 1, lineHeight)
}
Any help would be appreciated.
I fixed the problem. When the ray was facing up or right I was substracting 1 from the rounded position of the ray to get the first intersection. Substracting a smaller number like 0.001 fixed it.
Basically, I am trying to make an interactive background where wherever the mouse hovers or goes to, the lines in this background flows or follows the mouse in that certain direction. Is there anyway I could do this by using HTML/CSS/JavaScript? Here is the code. CSS is on the top, JS on the bottom.
//CSS
canvas {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
//JS
// Init Context
let c = document.createElement('canvas').getContext('2d')
let postctx = document.body.appendChild(document.createElement('canvas')).getContext('2d')
let canvas = c.canvas
let vertices = []
// Effect Properties
let vertexCount = 7000
let vertexSize = 2
let oceanWidth = 204
let oceanHeight = -80
let gridSize = 32;
let waveSize = 16;
let perspective = 500;
// Common variables
let depth = (vertexCount / oceanWidth * gridSize)
let frame = 0
let { sin, cos, tan, PI } = Math
// Render loop
let loop = () => {
let rad = sin(frame / 100) * PI / 20
let rad2 = sin(frame / 50) * PI / 10
frame++
if (postctx.canvas.width !== postctx.canvas.offsetWidth || postctx.canvas.height !== postctx.canvas.offsetHeight) {
postctx.canvas.width = canvas.width = postctx.canvas.offsetWidth
postctx.canvas.height = canvas.height = postctx.canvas.offsetHeight
}
c.fillStyle = `hsl(200deg, 100%, 2%)`
c.fillRect(0, 0, canvas.width, canvas.height)
c.save()
c.translate(canvas.width / 2, canvas.height / 2)
c.beginPath()
vertices.forEach((vertex, i) => {
let ni = i + oceanWidth
let x = vertex[0] - frame % (gridSize * 2)
let z = vertex[2] - frame * 2 % gridSize + (i % 2 === 0 ? gridSize / 2 : 0)
let wave = (cos(frame / 45 + x / 50) - sin(frame / 20 + z / 50) + sin(frame / 30 + z*x / 10000))
let y = vertex[1] + wave * waveSize
let a = Math.max(0, 1 - (Math.sqrt(x ** 2 + z ** 2)) / depth)
let tx, ty, tz
y -= oceanHeight
// Transformation variables
tx = x
ty = y
tz = z
// Rotation Y
tx = x * cos(rad) + z * sin(rad)
tz = -x * sin(rad) + z * cos(rad)
x = tx
y = ty
z = tz
// Rotation Z
tx = x * cos(rad) - y * sin(rad)
ty = x * sin(rad) + y * cos(rad)
x = tx;
y = ty;
z = tz;
// Rotation X
ty = y * cos(rad2) - z * sin(rad2)
tz = y * sin(rad2) + z * cos(rad2)
x = tx;
y = ty;
z = tz;
x /= z / perspective
y /= z / perspective
if (a < 0.01) return
if (z < 0) return
c.globalAlpha = a
c.fillStyle = `hsl(${180 + wave * 20}deg, 100%, 50%)`
c.fillRect(x - a * vertexSize / 2, y - a * vertexSize / 2, a * vertexSize, a * vertexSize)
c.globalAlpha = 1
})
c.restore()
// Post-processing
postctx.drawImage(canvas, 0, 0)
postctx.globalCompositeOperation = "screen"
postctx.filter = 'blur(16px)'
postctx.drawImage(canvas, 0, 0)
postctx.filter = 'blur(0)'
postctx.globalCompositeOperation = "source-over"
requestAnimationFrame(loop)
}
// Generating dots
for (let i = 0; i < vertexCount; i++) {
let x = i % oceanWidth
let y = 0
let z = i / oceanWidth >> 0
let offset = oceanWidth / 2
vertices.push([(-offset + x) * gridSize, y * gridSize, z * gridSize])
}
loop()
I've written a drawing app that turns drawings into Fourier series, but it's doing a weird thing where it spirals inwards. For some reason, all the constants of the series are similar in size (something that I believe is incorrect, but I could be wrong). Here's my code:
var states = ["START", "DRAWING", "CIRCLES"];
var currentState = states[0];
var graph = [];
var constants = [];
// Half because ranging from -50 to 50
var halfNumCircles = 50;
var time = 0;
var deltaTime = 0.01;
// INITIAL SETUP
function setup() {
createCanvas(window.innerWidth, window.innerHeight);
angleMode(DEGREES);
frameRate(30);
cursor(CROSS);
}
// DRAWING LOOP
function draw() {
background(255);
// Axes
stroke(100);
line(width / 2, 0, width / 2, height);
line(0, height / 2, width, height / 2);
// Drawing
stroke(0);
if (currentState == states[1]) {
// Add mousepos to graph
graph.push([mouseX - width / 2, mouseY - height / 2]);
// Draw graph
for (let i = 0; i < graph.length - 1; i++) {
line(graph[i][0] + width / 2, graph[i][1] + height / 2,
graph[i + 1][0] + width / 2, graph[i + 1][1] + height / 2);
}
}
// Circles
stroke(0);
if (currentState == states[2]) {
// Starting at origin, draw lines to each boundary between circles
var points = [[0, 0]];
// For each constant, add a point
for (let i = 0; i < 2 * halfNumCircles + 1; i++) {
// n is 0,1,-1,2,-2...
var n = 0;
if (i % 2 == 0) {
n = -i / 2;
} else {
n = i / 2;
}
var pointX = constants[i][0] * cos(n * 2 * Math.PI * time) -
constants[i][1] * sin(n * 2 * Math.PI * time);
var pointY = constants[i][0] * sin(n * 2 * Math.PI * time) +
constants[i][1] * cos(n * 2 * Math.PI * time);
// Add new arrow to the last one
points.push([points[points.length - 1][0] + pointX, points[points.length - 1][1] + pointY]);
}
// Draw lines between points
for (let i = 0; i < points.length - 1; i++) {
line(points[i][0] + width / 2, points[i][1] + height / 2,
points[i + 1][0] + width / 2, points[i + 1][1] + height / 2)
}
// Increment time
time = (time + deltaTime);
}
}
// FOURIER SERIES OF FUNCTION
function getConstants(graph) {
// Returns array with constants
// Note that constants are complex numbers
// Set constants to 0, to be added to in the next loop
var constants = []
for (let i = 0; i < 2 * halfNumCircles + 1; i++) {
constants.push([0, 0]);
}
// For each constant
for (let c = -halfNumCircles; c <= halfNumCircles; c++) {
var deltaT = 1.0 / graph.length;
// Loop through the graph: sum of f(t)*e^{-c*2pi*i*t}*deltaT from 0 <= t <= 1
for (let i = 0; i < graph.length; i++) {
// Effective points on graph
var a = graph[i][0];
var b = graph[i][1];
var t = i / graph.length;
// Complex multiplication f(t)*e^{-c*2pi*i*t}
var xChange = a * cos(-c * 2 * Math.PI * t) - b * sin(-c * 2 * Math.PI * t);
var yChange = a * sin(-c * 2 * Math.PI * t) + b * cos(-c * 2 * Math.PI * t);
constants[c + halfNumCircles][0] += xChange * deltaT;
constants[c + halfNumCircles][1] += yChange * deltaT;
}
}
// Reorder from [...-2, -1, 0, 1, 2...] to [0, 1, -1, 2, -2...]
var orderedConstants = []
for (let i = 0; i < 2 * halfNumCircles + 1; i++) {
orderedConstants.push([0, 0]);
}
for (let i = 0; i < 2 * halfNumCircles + 1; i++) {
if (i % 2 == 0) {
orderedConstants[i] = constants[halfNumCircles - i / 2];
} else {
orderedConstants[i] = constants[halfNumCircles + (i + 1) / 2];
}
}
return orderedConstants;
}
// STATE CHANGING EVENTS
function mousePressed() {
// When clicked from start, start drawing
// When clicked from circles, reset
if (currentState == states[0]) {
currentState = states[1];
} else if (currentState == states[2]) {
currentState = states[0];
graph = [[]];
}
}
function mouseReleased() {
// When released, stop drawing, start circles
if (currentState == states[1]) {
currentState = states[2];
time = 0;
// Add first element of graph to the end, creating a loop
graph.push(graph[0]);
// Computationally intensive step
constants = getConstants(graph);
}
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Circle Drawing</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.6.0/p5.js" type="text/javascript"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.6.0/addons/p5.dom.js" type="text/javascript"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.6.0/addons/p5.sound.js" type="text/javascript"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjs/5.2.3/math.js" type="text/javascript"></script>
<script src="circles.js" type="text/javascript"></script>
<style media="screen">
body {
padding: 0;
margin: 0;
}
</style>
</head>
<body>
</body>
</html>
I can't seem to find the bug. I figured it could have something to do with the scale of the input, but that wouldn't' make sense since the units are arbitrary in this case. Please let me know if you have any idea what I've done wrong. Thanks for your help!
The unit of deltaTime is milliseconds. The sample period is far too large.
Divide the time by 1000.0 to get the time in seconds:
var times_s = time/1000.0;
var pointX = constants[i][0] * cos(n * 2 * Math.PI * times_s) -
constants[i][1] * sin(n * 2 * Math.PI * times_s);
var pointY = constants[i][0] * sin(n * 2 * Math.PI * times_s) +
constants[i][1] * cos(n * 2 * Math.PI * times_s);
var states = ["START", "DRAWING", "CIRCLES"];
var currentState = states[0];
var graph = [];
var constants = [];
// Half because ranging from -50 to 50
var halfNumCircles = 50;
var time = 0;
var deltaTime = 0.01;
// INITIAL SETUP
function setup() {
createCanvas(window.innerWidth, window.innerHeight);
angleMode(DEGREES);
frameRate(30);
cursor(CROSS);
}
// DRAWING LOOP
function draw() {
background(255);
// Axes
stroke(100);
line(width / 2, 0, width / 2, height);
line(0, height / 2, width, height / 2);
// Drawing
stroke(0);
if (currentState == states[1]) {
// Add mousepos to graph
graph.push([mouseX - width / 2, mouseY - height / 2]);
// Draw graph
for (let i = 0; i < graph.length - 1; i++) {
line(graph[i][0] + width / 2, graph[i][1] + height / 2,
graph[i + 1][0] + width / 2, graph[i + 1][1] + height / 2);
}
}
// Circles
stroke(0);
if (currentState == states[2]) {
// Starting at origin, draw lines to each boundary between circles
var points = [[0, 0]];
// For each constant, add a point
for (let i = 0; i < 2 * halfNumCircles + 1; i++) {
// n is 0,1,-1,2,-2...
var n = 0;
if (i % 2 == 0) {
n = -i / 2;
} else {
n = i / 2;
}
var times_s = time/1000.0;
var pointX = constants[i][0] * cos(n * 2 * Math.PI * times_s) -
constants[i][1] * sin(n * 2 * Math.PI * times_s);
var pointY = constants[i][0] * sin(n * 2 * Math.PI * times_s) +
constants[i][1] * cos(n * 2 * Math.PI * times_s);
// Add new arrow to the last one
points.push([points[points.length - 1][0] + pointX, points[points.length - 1][1] + pointY]);
}
// Draw lines between points
for (let i = 0; i < points.length - 1; i++) {
line(points[i][0] + width / 2, points[i][1] + height / 2,
points[i + 1][0] + width / 2, points[i + 1][1] + height / 2)
}
// Increment time
time = (time + deltaTime);
}
}
// FOURIER SERIES OF FUNCTION
function getConstants(graph) {
// Returns array with constants
// Note that constants are complex numbers
// Set constants to 0, to be added to in the next loop
var constants = []
for (let i = 0; i < 2 * halfNumCircles + 1; i++) {
constants.push([0, 0]);
}
// For each constant
for (let c = -halfNumCircles; c <= halfNumCircles; c++) {
var deltaT = 1.0 / graph.length;
// Loop through the graph: sum of f(t)*e^{-c*2pi*i*t}*deltaT from 0 <= t <= 1
for (let i = 0; i < graph.length; i++) {
// Effective points on graph
var a = graph[i][0];
var b = graph[i][1];
var t = i / graph.length;
// Complex multiplication f(t)*e^{-c*2pi*i*t}
var xChange = a * cos(-c * 2 * Math.PI * t) - b * sin(-c * 2 * Math.PI * t);
var yChange = a * sin(-c * 2 * Math.PI * t) + b * cos(-c * 2 * Math.PI * t);
constants[c + halfNumCircles][0] += xChange * deltaT;
constants[c + halfNumCircles][1] += yChange * deltaT;
}
}
// Reorder from [...-2, -1, 0, 1, 2...] to [0, 1, -1, 2, -2...]
var orderedConstants = []
for (let i = 0; i < 2 * halfNumCircles + 1; i++) {
orderedConstants.push([0, 0]);
}
for (let i = 0; i < 2 * halfNumCircles + 1; i++) {
if (i % 2 == 0) {
orderedConstants[i] = constants[halfNumCircles - i / 2];
} else {
orderedConstants[i] = constants[halfNumCircles + (i + 1) / 2];
}
}
return orderedConstants;
}
// STATE CHANGING EVENTS
function mousePressed() {
// When clicked from start, start drawing
// When clicked from circles, reset
if (currentState == states[0]) {
currentState = states[1];
} else if (currentState == states[2]) {
currentState = states[0];
graph = [[]];
}
}
function mouseReleased() {
// When released, stop drawing, start circles
if (currentState == states[1]) {
currentState = states[2];
time = 0;
// Add first element of graph to the end, creating a loop
graph.push(graph[0]);
// Computationally intensive step
constants = getConstants(graph);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/p5.js"></script>
I am trying to create a simulation for experimenting with the Brownian motion. The idea is to make numerous particles (points) each moving randomly and colliding with each other, while conserving the total energy. That, I did succeed programming.
Now the problematic part is to make these point-like particles collide with a big circle and program the collision correctly. The difference is I made the particles move towards a totally random angle after their collision with each other, but when they collide with the circle, their previous path and speed, together with the circle's path and speed determines the result. So what I tried to do is to convert to a coordinate system attached to the center of the circle, calculate the collision point of every particle, which entered into the circle in the previous step, then calculate the angle in which they arrived. Now then the momentum of the particle is decomposed into two components: the tangential component remains the same, while the radial component changes according to the laws of collisions. This affects the motion of the circle as well. After calculating all the collisions, we move back to the original reference system, and draw all the objects.
The code can be found below, and it seems to be broken. I guess I was mistaken when calculating with the angles, because some particles can be shown arriving to the circle at one point, then "exiting" through the other side of it. I just lost track in following it all. I'm a complete newbie to programming, so be... um... gentle, please. :) Another strange thing is that the circle trends to move to a direction it started to move early, which is not what it supposed to do.
The mass of the particles are given, the mass of the circle is calculated with it's radius.
You can find the simulation on this website:
http://sixy.uw.hu/brown
It is not finished yet, but the start button works fine. :)
The part of the code I'm asking about is here: (shall I give you the whole code?)
function animateParticles() {
if ($('N').value != particleCount || $('S').value != circle.R) {
reset();
}
switch (activeGraph) {
case '#graph':
chartOptions.title.text = 'Távolság';
chartOptions.axisY.title = 'd [px]';
break;
if (Date.now() > lastAnim + 22) {
context.clearRect(0, 0, canvas.width, canvas.height);
// Particles step and collide
for (var i in particle) {
// Particle steps
{
particle[i].x += particle[i].vx;
particle[i].y += particle[i].vy;
}
// If not in the circle
if ((circle.x - particle[i].x) * (circle.x - particle[i].x) + (circle.y - particle[i].y) * (circle.y - particle[i].y) > circle.R * circle.R) {
// Collides with some of the rest of the particles
for (var j = 1; j <= $('N').value; j += Math.ceil(particleCount / (Math.random() * 50 + 50))) {
// If that's not in the circle as well
if ((circle.x - particle[j].x) * (circle.x - particle[j].x) + (circle.y - particle[j].y) * (circle.y - particle[j].y) > circle.R * circle.R) {
// If not himself
if (j != i) {
if (particle[i].coll == 0) {
// Collide
if (Math.pow((particle[i].x - particle[j].x), 2) + Math.pow((particle[i].y - particle[j].y), 2) <= 4) {
var tkpx = (particle[i].vx + particle[j].vx) / 2;
var tkpy = (particle[i].vy + particle[j].vy) / 2;
var fi = Math.random() * 2 * Math.PI;
var index;
var ix = particle[i].vx;
var iy = particle[i].vy;
particle[i].vx = Math.sqrt(Math.pow((ix - tkpx), 2) + Math.pow((iy - tkpy), 2)) * Math.cos(fi) + tkpx;
particle[i].vy = Math.sqrt(Math.pow((ix - tkpx), 2) + Math.pow((iy - tkpy), 2)) * Math.sin(fi) + tkpy;
particle[j].vx = -Math.sqrt(Math.pow((ix - tkpx), 2) + Math.pow((iy - tkpy), 2)) * Math.cos(fi) + tkpx;
particle[j].vy = -Math.sqrt(Math.pow((ix - tkpx), 2) + Math.pow((iy - tkpy), 2)) * Math.sin(fi) + tkpy;
}
}
}
if (particle[i].coll >= 1) {
particle[i].coll -= 1;
}
}
}
}
// Collision with the walls
{
if (particle[i].x >= canvas.width) {
var temp;
temp = particle[i].x - canvas.width;
particle[i].x = canvas.width - temp;
particle[i].vx *= -1
}
if (particle[i].x <= 0) {
var temp;
temp = -particle[i].x;
particle[i].x = temp;
particle[i].vx *= -1;
}
if (particle[i].y >= canvas.height) {
var temp;
temp = particle[i].y - canvas.height;
particle[i].y = canvas.height - temp;
particle[i].vy *= -1;
}
if (particle[i].y <= 0) {
var temp;
temp = -particle[i].y;
particle[i].y = temp;
particle[i].vy *= -1;
}
}
}
//console.log(circle);
// Circle steps and collides with particles
var cu = 0;
var cv = 0;
for (var i in particle) {
if ((circle.x - particle[i].x) * (circle.x - particle[i].x) + (circle.y - particle[i].y) * (circle.y - particle[i].y) < circle.R * circle.R) {
var pu;
var pv;
var px;
var py;
var px0;
var py0;
var t;
var t2;
var Tx;
var Ty;
var fi;
var p;
var q;
var cuu;
var cvv;
px = particle[i].x - circle.x;
py = particle[i].y - circle.y;
pu = particle[i].vx - circle.vx;
pv = particle[i].vy - circle.vy;
px0 = px - particle[i].vx;
py0 = py - particle[i].vy;
// Calculating the meeting point of the collision
t = (-(px0 * pu + py0 * pv) - Math.sqrt(circle.R * circle.R * (pu * pu + pv * pv) - Math.pow(px0 * pv - py0 * pu, 2))) / (pu * pu + pv * pv);
t2 = ((px - px0) * (px - px0) + (py - py0) * (py - py0)) / Math.sqrt(pu * pu + pv * pv) - t;
Tx = px0 + t * pu;
Ty = py0 + t * pv;
//console.log("TX: ", Tx);
//console.log("TY: ", Ty);
// Calculating the angle
{
if (Tx > 0 && Ty >= 0) {
fi = 2 * Math.PI - Math.atan(Ty / Tx);
}
else if (Tx < 0 && Ty >= 0) {
fi = Math.PI - Math.atan(Ty / Tx);
}
else if (Tx < 0 && Ty < 0) {
fi = Math.PI / 2 + Math.atan(Ty / Tx);
}
else if (Tx > 0 && Ty < 0) {
fi = -Math.atan(Ty / Tx);
}
else if (Tx = 0 && Ty >= 0) {
fi = 3 / 2 * Math.PI;
}
else if (Tx = 0 && Ty < 0) {
fi = Math.PI / 2;
}
}
//console.log("FI:", fi);
p = pu * Math.cos(fi) + pv * Math.sin(fi);
q = -pu * Math.sin(fi) + pv * Math.cos(fi);
cuu = 2 * q / (circle.M + 1);
cvv = 0;
q *= (1 - circle.M) / (1 + circle.M);
cu += cuu * Math.cos(-fi) + cvv * Math.sin(-fi);
cv += -cuu * Math.sin(-fi) + cvv * Math.cos(-fi);
//console.log("CU: ", cu);
//console.log("CV: ", cv);
pu = p * Math.cos(-fi) + q * Math.sin(-fi);
pv = -p * Math.sin(-fi) + q * Math.cos(-fi);
px = Tx + t2 * pu;
py = Ty + t2 * pv;
particle[i].x = px + circle.x;
particle[i].y = py + circle.y;
particle[i].vx = pu + circle.vx;
particle[i].vy = pv + circle.vy;
}
}
// Moving circle
{
circle.vx += cu;
circle.vy += cv;
circle.x += circle.vx;
circle.y += circle.vy;
for (var i in particle) {
while ((circle.x - particle[i].x) * (circle.x - particle[i].x) + (circle.y - particle[i].y) * (circle.y - particle[i].y) < circle.R * circle.R) {
particle[i].x += circle.vx / Math.abs(circle.vx);
particle[i].y += circle.vy / Math.abs(circle.vy);
}
}
circlePath.push({x: circle.x, y: circle.y});
if (Date.now() > lastDraw + 500) {
items.push({
y: Math.sqrt((circle.x - canvas.width / 2) * (circle.x - canvas.width / 2) + (circle.y - canvas.height / 2) * (circle.y - canvas.height / 2)),
x: (items.length + 1) / 2
});
drawChart(activeGraph);
lastDraw = Date.now();
}
}
//console.log(circle);
drawCircle();
for (var i in particle) drawParticle(particle[i]);
lastAnim = Date.now();
}
animation = window.requestAnimationFrame(animateParticles);
}