I'm trying to make a visualizer and I have to draw 4 vertexes while using math to make each vertex so they can react with the music. Rather than just typing all 4 of them out and plotting them I would like to use a nested for loop to do this. I was testing using a regular ellipse with the translate function in p5.js and the translate seems to be translating itself and not just changing the values to how I would want it.
for (var i = 1; i <= 2; i++)
{
for (var j = 1; j <= 2; j++)
{
translate(200 * i,200 * j);
ellipse(0,0,100)
}
}
translate does not set a translation, but concatenates the current transformation matrix with the new translation. Therefore you need to push the transformation matrix before appending the new translation and pop the matrix after drawing the geometry:
for (var i = 1; i <= 2; i++) {
for (var j = 1; j <= 2; j++) {
push()
translate(200 * i, 200 * j)
ellipse(0, 0, 100)
pop()
}
}
Related
a better explanation, is i have 2 arrays one that is listed in the statement of the nested loop and one that not and I'm trying to use the output or the middle of the nested loop to change but when i do this it doesn't change so i how would it change
function drawBricks() { // im using canvas and clear.rect so i have to be able to call on this over and over
for( i = 0; i < brickgrid.length; i++){ //brickgrid is my first 2d array
for( j = 0; j < brickgrid[i][j] ; j++){
x = (i * 120)+60;
y = (brickgrid[i][j] * 40)+40;
brickcentergrid[0].push(x); //brickcentergrid is my second 2d array witch is not changing when the code runs
ctx.beginPath();
ctx.fillRect(x, y, 80, 20); //the brick
ctx.closePath();
}
}
}
how would I change my code to allow the brickcentergrid to change or should I remake some of my code
this is my first post if you need some more info about my code ill post it in the comments
I think that you have a wrong condition on your inner for loop
try to change it with this
function drawBricks() { // im using canvas and clear.rect so i have to be able to call on this over and over
for( i = 0; i < brickgrid.length; i++){ //brickgrid is my first 2d array
for( j = 0; j < brickgrid[i].length ; j++){
x = (i * 120)+60;
y = (brickgrid[i][j] * 40)+40;
brickcentergrid[0].push(x); //brickcentergrid is my second 2d array witch is not changing when the code runs
ctx.beginPath();
ctx.fillRect(x, y, 80, 20); //the brick
ctx.closePath();
}
}
}
I'm trying to generate a grid of points on the canvas described by vectors in order to make a flow field. I generate the vectors in a nested loop, then push them to a list, and finally attempt to draw them. However, when I attempt to draw them the .x and .y attributes aren't recognised. I think this is because the list of vectors is empty/only has one entry in it and I can't work out why. Apologies if this is a simple problem - this is my first time using javascript and p5.js. My code is shown below, it should generate a uniform grid of points.
let width = 600;
let height = 600;
let points = [];
function setup() {
createCanvas(width, height);
background(30);
let density = 50;
let spacing = width / density;
for (var x = 0; x < width; x += spacing); {
for (var y = 0; y < height; y += spacing); {
var p = createVector(x, y)
points.push(p)
}
}
}
function draw() {
noStroke();
fill(255);
for (var i = 0; i < points.length; i++); {
circle(points[i].x, points[i].y, 1);
}
}
EDIT: My code is definitely generating one vector, but only one for some reason. So I believe the issue is the for loops not executing correctly.
Your for loop syntax is incorrect. There should not be a semicolon after the closing parenthesis and the opening curly brace:
// !
for (var i = 0; i < points.length; i++); {
circle(points[i].x, points[i].y, 1);
}
You will need to fix each of your for loops.
I'm trying to create a pattern script in Photoshop that duplicates an image horizontally and vertically over the whole canvas. But the issue is that across the x-axis it doubles its value every loop. If I remove the "j" loop, it works fine.
This pic will show you the issue I'm referring to https://imgur.com/a/0x9HhCS
var offset = parseInt(prompt("Type in the offset (spacing between pics) value here.\nDefault is 0px.", "0"));
for (var i = 0; i < width / (layerWidth + offset); i++) {
for (var j = 0; j < 3; j++) {
app.activeDocument.layers[i, j].duplicate()
app.activeDocument.layers[i, j].translate(i * (layerWidth + offset), j * (layerHeight + offset));
}
}
As volcanic mentioned, layers[i, j] isn't a valid way of accessing your layers. I'm not even sure why this works. You're supposed to select you original layer, make a copy and translate it. Something like this:
var width = activeDocument.width.as("px");
var height = activeDocument.height.as("px");
var layer = app.activeDocument.activeLayer;
var layerWidth = layer.bounds[2] - layer.bounds[0];
var layerHeight = layer.bounds[3] - layer.bounds[1];
var copy, i, j;
var offset = parseInt(prompt("Type in the offset (spacing between pics) value here.\nDefault is 0px.", "0"));
for (i = 0; i < width / (layerWidth + offset); i++)
{
for (j = 0; j < height / (layerHeight + offset); j++)
{
// in the each loop we select the original layer, make a copy and offset it to calculated values
app.activeDocument.activeLayer = layer;
copy = layer.duplicate();
copy.translate(i * (layerWidth + offset), j * (layerHeight + offset));
}
}
layer.remove(); // remove the original layer
Result:
the issue is related in how do you use offset:
Translate refers to the bounding rect of the layer.
If you have a 50px width image translated by 50px, the resulting layer width will be 100px.
Try to use only the offset, each iteration.
So, I am trying to create a N-Body Gravity simulation in JavaScript:
http://jsfiddle.net/4M94x/
var Circle = function(c, r, cor, cof) { // Fix CoR & CoF // Had to add code for JSFiddle link :P
this.c = c
this.r = r
this.m = r * r * Math.PI
this.v = new Vector()
this.cor = cor
this.cof = cof
}
The problem's that when you spawn (click) and put 2 balls (accidentally renamed "particles") next to each other they start to generate velocity and faster and faster push eachother.. How do I fix this, btw is my gravity implementation correct?
This is easy to explain: You are implementing Euler forward as solver for the ODE, and in mechanical systems the systematic error of Euler forward increases the energy. Euler backward decreases the energy, so a combination of alternating the explicit and implicit Euler methods would leave the energy a little more constant.
But then you can implement with the same or even less effort the second order symplectic methods which preserve energy and other physical invariants, either the (implicit) midpoint method or the Verlet-(Stoermer-Cromer-...-Newton-)method.
Or even higher order Runge-Kutta, which will also preserve the energy to a higher order, despite not being symplectic.
See Hairer on the Stoermer-Verlet-...-Newton method, postprint or preprint and the "Moving stars around" tutorial text using C++ or Ruby.
A note to the physics: All in all the implementation is very minimal and well readable. But the gravitational force is
g*m1*m2*(p2-p1)/norm(p2-p1)^3
as the negative gradient of
g*m1*m2/norm(p2-p1)
you are only using the square of the norm, where the force would be the negative gradient of the gravitational potential energy
g*m1*m2*ln(norm(p2-p1))
which is right for flatland physics, but not for a 2D section of 3D space.
Working code
with velocity Verlet and energy preservation:
Add a new field a=Vector() to the circle object and replace the kitchen sink which is the update() function with the following collection of dedicated functions
function compute_forces() {
for (var i = 0; i < particles.length; i++) {
var p = particles[i];
p.a.set(0);
for (var j = 0; j < i; j++) {
var p2 = particles[j];
var d = p.c.sub(p2.c);
var norm = Math.sqrt(100.0 + d.lengthSq());
var mag = gravity / (norm * norm * norm);
p.a.set(p.a.sub(d.mul(mag * p2.m)));
p2.a.set(p2.a.add(d.mul(mag * p.m)));
}
}
}
function do_collisions() {
for (var i = 0; i < particles.length; i++) {
var p = particles[i];
for (var j = 0; j < i; j++) {
var p2 = particles[j];
if (checkCCCol(p, p2)) {
resCCCol(p, p2);
}
}
}
}
function do_physics(dt) {
// do velocity Verlet
// with consistent state at interval half points
// x += 0.5*v*dt
for (var i1 = 0; i1 < particles.length; i1++) {
var p1 = particles[i1];
p1.c.set(p1.c.add(p1.v.mul(0.5 * dt)));
}
// a = A(x)
compute_forces();
// v += a*dt
for (var i2 = 0; i2 < particles.length; i2++) {
var p2 = particles[i2];
p2.v.set(p2.v.add(p2.a.mul(dt)));
}
// x += 0.5*v*dt
for (var i3 = 0; i3 < particles.length; i3++) {
var p3 = particles[i3];
p3.c.set(p3.c.add(p3.v.mul(0.5 * dt)));
}
do_collisions();
}
function update() {
for (var k = 0; k < 4; k++) {
do_physics(1.0 / 4);
}
render();
RAF(update);
}
See http://jsfiddle.net/4XVPH/
Altered example with particles coloured based on their mass(hopefully better displaying their interaction), one bug fixed, and some additional comments: http://jsfiddle.net/24mg6ctg/12/
I want to check if circles are colliding with each other.
I know I can do this by getting a distance between the two centers of the circles and subtracting the radius of each circle from that distance and seeing if 'distance' is > 1.
How can I do this efficiently though with say, 1000 circles? Maybe I can somehow get the nearest 20 circles or something like that and check these? I don't know how I would begin to go about that efficiently though either..
Any ideas?
Here is an example:
http://experiments.lionel.me/blocs/
Before you start calculating exact differences in distances, you can at least compare the x/y positions of the centers v.s. the radii. That information is implicitly available in the circle and requires just some simple comparisons and addition/subtraction.
That'll let you compare the simple distances in x/y between all the circle pairs, and throw away any that are obviously not collision candidates, e.g.
abs(x2 - x1) > (r2 + r1)
abs(y2 - y1) > (r2 + r1)
... if the distance in X or Y between the circle centers is greater than the sum of the radii, then they cannot be colliding.
Once you've whittled down the possible colliders, THEN you do the formal exact cartesian distance, which is where the 'heavy' multiplication/division stuff comes in.
Consider storing the coordinates of the circles' centers in a quad tree, then you would only need to check whether the circle intersects with other circles in that quadrant or adjacent quadrants.
The one caveat is that you need to sure the quad tree's leaf nodes have a minimal diameter of the radius of your largest circle, otherwise you will have to check more than just adjacent nodes for intersection.
http://en.wikipedia.org/wiki/Quadtree
If your circles are well scattered, then a simple optimization you can do is to store your circles sorted on the x or y axis, then you only need to check with circles who's x or y coordinate is within the radius of the circle.
The efficiency is going to be concerned with the speed of the algorithms you are using, for instance the speed of the square root algorithm that you calculate the distance with, and your data structures will determine the efficiency of memory, in addition to algorithms. Another way to speed up the calculations would be to reduce the precision of the distance calculations.
The best method to detect if the circles are colliding is, as you said, to store the circles' center coordinates and radius in variables and compute whether or not the distance between the centers is equivalent to 0 when the radii are subtracted.
I highly recommend Keith Peter's AdvancED ActionScript 3.0 Animation book, where you can find the concrete implementation of Quadtree algorithm in Actionscript.
Here are the basic steps:
First create a two dimensional grid and scatter all the balls randomly across the field.
private function createGrids():void {
_grids = new Array();
for (var i:int = 0; i< stage.stageWidth / GRID_SIZE; i++) {
_grids[i] = new Array();
for (var j:int = 0; j< stage.stageHeight / GRID_SIZE; j++) {
_grids[i][j] = new Array();
}
}
}
Assign balls to grid cells
private function assignBallsToGrid():void {
for (var i:int = 0; i< numBalls; i++) {
var ball:Ball = Ball(_balls[i]);
var xpos:int = Math.floor(ball.x / GRID_SIZE);
var ypos:int = Math.floor(ball.y / GRID_SIZE);
_grids[xpos][ypos].push(ball);
}
}
Check if two balls are colliding in a single cell, then check the balls in adjacent cells. As Charles Ma mentioned the only consideration here the grid cells dimension must be greater or equal to the largest ball diameter.
private function checkOneCell(x1:Number, y1:Number):void {
var _cell:Array = _grids[x1][y1] as Array;
for (var i:int = 0; i< _cell.length-1; i++) {
var ballA:Ball = _cell[i] as Ball;
for (var j:int = i+1; j< _cell.length; j++) {
var ballB:Ball = _cell[j] as Ball;
checkCollision(ballA, ballB);
}
}
}
private function checkTwoCell(x1:Number, y1:Number, x2:Number, y2:Number):void {
if (x2 < 0) { return }
if (x2 >= _grids.length) { return }
if (y2 >= _grids[x2].length) { return }
var _cell0:Array = _grids[x1][y1] as Array;
var _cell1:Array = _grids[x2][y2] as Array;
for (var i:int = 0; i< _cell0.length; i++) {
var ballA:Ball = _cell0[i] as Ball;
for (var j:int = 0; j< _cell1.length; j++) {
var ballB:Ball = _cell1[j] as Ball;
checkCollision(ballA, ballB);
}
}
}
private function checkCollision(ballA:Ball, ballB:Ball):void {
var dx:Number = ballB.x - ballA.x;
var dy:Number = ballB.y - ballA.y;
var dist:Number = Math.sqrt(dx*dx + dy*dy);
if (dist < ballB.radius + ballA.radius) {
// do something
}
}
Here is how it looks like the main method:
private function checkBallsCollision():void {
for (var i:int = 0; i< _grids.length; i++) {
for (var j:int = 0; j< _grids[i].length; j++) {
checkOneCell(i, j);
checkTwoCell(i, j, i+1, j);
checkTwoCell(i, j, i, j+1);
checkTwoCell(i, j, i-1, j);
checkTwoCell(i, j, i+1, j+1);
}
}
}
NOTE:
The code is written in Actionscript but can be implemented quite easily in Javascript.