I'm currently writting a 3D implementation of the boids algorithm in P5.js but I'm having trouble orienting my boids according to their direction (velocity). Rotations are limited to RotateX(), RotateY() and RotateZ(). The simplest solution that I feel should work goes along these lines :
push();
translate(this.pos);
rotateZ(createVector(this.vel.x, this.vel.y).heading());
rotateY(createVector(this.vel.x, this.vel.z).heading());
beginShape();
// Draw Boid Vertices..
endShape();
pop();
But it doesn't.
I've written a much smaller version of the program which contains only the orientation for randomly generated particles that go in a single direction. It is available here directly on the p5js website : https://editor.p5js.org/itsKaspar/sketches/JvypSPGGh
There is a default orbit control so you can zoom and drag the mouse to check the orientation of the particles.
Thanks so much, I've been stuck on this for half a day now
From your demo, the z component is flipped, and you can test this from only trying one of the rotations at a time. Second, chaining rotations in 3D this way will usually not do what you want, as rotating will change the "up" or "right" vector of the coordinate system attached to a certain object. For example, rotating about the up (-y for p5) vector, or the yaw angle, will rotate the right vector. The second rotation then needs to be about the rotated right vector (now pitch), so you can't just use rotateX/Y/Z as they are still in world space instead of object space. Note that I'm completely ignoring roll in this solution, but if you look at the boids from the front and top angles, it should be aligned with the velocities
var right = p5.Vector(this.vel.x, 0, this.vel.z);
rotate(atan(this.vel.y/ this.vel.x), right);
rotateY(atan2(-this.vel.z, this.vel.x));
I have been developing a program which includes some sort of genetic algorithm. For my program, let's say there is a population of 200 units, and each unit can be in 5 different states. Inititlly, they all start at state 0, and they can randomly jump to states 1 to 4, and influence other units to jump as well. This way, the more units are on state 2, the more units will jump to state 2 and so on. I have these units moving randomly inside my canvas, bouncing off the walls when they hit them.
The one thing I want to do now is visualize the evolution on a chart, and for that I would like to have the canvas with the units jumping states on one side and the chart next to it, dynamically representing the percentage of units in state 0, 1, 2... simultaneously. I will presumably have no problem in coding the chart, however I cannot find a way of displaying it outside the canvas or without altering it.
Just in case, I am programming in Atom and have mostly used p5 libraries.
Any ideas??
You have 2 options:
Make a second canvas (Like enhzflep said), but this might be complicated for you, becuase you will not have access to P5.js drawing tools on that second canvas, look at this:
(On your first canvas)
fill(255,0,0)
rect(50,50,50,50);
To make and draw to a second canvas:
const canvas = document.createElement('canvas');
document.body.appendChild(canvas);
//deal with positioning, scaling, and other stuff (comment if you need help with that)
...
const c = canvas.getContext('2d');
c.fillStyle = "rgb(255,0,0)";
c.fillRect(50,50,50,50);
(See, lots of effort)
Or, you can just use your first canvas, and partition a section off that is dedicated to the graph
createCanvas(600 + graphWidth, 600);
//Wherever your bouncing off walls code is
//for the right side of the screen
if(this.x > width - graphWidth){
bounce();
}
//that leaves you a graphWidth by 600 rectangle for you to draw you graph
The second option is much easier to read and will save you some headaches (I would use that).
we are making a small Snake Browser game Using Easejs.
Now we want to use PNGs for the Snake Parts and not only a colour:
this.shape.graphics.beginFill("#e54d42");
this.shape.graphics.drawRect(this.x*this.grid.cell_width, this.y*this.grid.cell_height, this.grid.cell_width, this.grid.cell_height);
this.shape.graphics.endFill();
Does anyone know how to do it? Shall we use beginBitmapFill or how we have to do it?
Bitmap fill might do what you want, but you will need to consider the coordinates of the shape.
Here is a quick sample: http://jsfiddle.net/lannymcnie/ogy1qmxn/1/
shape.graphics.clear()
.beginBitmapFill(img)
.drawRect(0,0,800,600);
Note that my shape starts at [0,0]. If you start your shape at different coordinates, the bitmap will be cropped differently because it draws from [0,0] by default. Here is an example where the x/y coordinate of the bitmap is offset: http://jsfiddle.net/lannymcnie/ogy1qmxn/2/
You can fix this by either drawing at [0,0] and actually moving the shape, por using a matrix when you draw your shape.
var matrix = new createjs.Matrix2D();
matrix.translate(this.x*this.grid.cell_width, this.y*this.grid.cell_height);
shape.graphics.beginBitmapFill(img, "repeat", matrix);
Hope that helps!
I am building a tool which will ultimately leverage the Google Maps API v3 to build up an area on a map constructed of squares of a fixed edge length (e.g. 10 metres) on a fixed “grid” system (e.g., co-ordinates spaced out every 0.0001 latlong units starting at earth’s 0,0 point).
I have written code where users can click on an area on the map and the code draws an outline and fill of the square where it's found. Users can click on other adjacent locations to that square to build up a larger and larger “blocky” polygon, and can click on individual squares to delete them. I have tested all this myself in both HTML5 canvas/JavaScript as well as the Google Maps API.
Now I want to write code that removes any internal edges/vertices so that it only draws the outermost boundaries of this polygon so that it is actually drawn as one large polygon, rather than a collection of squares. Think of it this way: even though we know countries like Australia, USA etc., are comprised of a number of states, when we draw the border around the country we are not usually interested in the borders of all the states and can delete those lines in between and just draw the outer boundary. This is the same thing I want to accomplish, just using a grid of squares rather than complex polygons.
My current code is here:
https://jsfiddle.net/wyxcvmdf/14/
HTML:
<canvas id="myCanvas" width="500" height="250" style="border:1px solid #000000;"></canvas>
<!--etc.-->
JavaScript:
// don't forget to set load type in jsfiddle to no wrap in <body>
// define the global variable and some helper variables to make the code shorter
var gv = {};
gv.o = function(id) {
return document.getElementById(id)
};
gv.i = 'innerHTML';
// etc.
A couple of explanatory notes about my code:
• The “origin point” for every square is the vertex at the bottom left corner of that square. No particular reason for this.
• The “drawing direction” in terms of how HTML5 canvas draws the outline is counter-clockwise from the origin point. Again, no particular reason for this.
• You can’t “click” to add squares yet as it’s just a proof of concept, so you add squares by entering the x and y co-ordinates in the relevant text entry boxes
The use cases/tests required to prove my code which I have thought of are:
Square added to polygon with 1 duplicate vertex (working)
Square added to polygon with 2 and 3 duplicate vertices in all cases: adjacent edges, non-adjacent edges, non-sequential vertices (currently working for first case only)
Square added to polygon with 4 duplicate vertices in all cases: plugging a hole, plugging part of a hole, joining multiple polygons (currently working for first case only)
Square removed from polygon with 1 duplicate vertex in cases described above (not developed yet, but should effectively be “reverse” of addition code)
Square removed from polygon with 2 and 3 duplicate vertices in cases described above (not developed yet, but should effectively be “reverse” of addition code)
Square removed from polygon with 4 duplicate vertices in cases described above (not developed yet, but should effectively be “reverse” of addition code)
Square addition/removal on outside of polygon with multiple inner borders, i.e., holes (not developed yet, may be tricky)
Square addition/removal on inside of polygon with multiple inner borders, i.e., holes (not developed yet, may be tricky)
Note 1: My use of “squares”, “edge” etc., instead of "polygons", etc., is just for simplicity of explanation.
Note 2: I have performed quite a bit of research on similar problems and possible solutions but haven’t really found anything which will meet my needs. The research I’ve done is on:
Travelling Salesman Problem. However, this is not about optimising a path – it is about making sure a path is “drawable” and hence heading in one direction. Overlapping vertices are totally fine as long as the resulting shape looks like what a user would expect it to.
Convex hull algorithm. Not really applicable as the hull could be convex, concave or even non-contiguous! Also, I think that by simplifying to a grid system I have removed the problem of having many scattered vertices where you need to determine how far they are from a centre point, use trigonometry etc.
Concave hull solutions. This gets closer to solving my problem, however what I have seen is that there are many plug-ins for commercial tools (e.g. ArcGIS) to do this, but no generic code (irrespective of programming language) which covers all of my use cases.
Tile-based games. You would think that any tile-based game which requires drawing boundaries around tiles (e.g. A player’s territory in a real-time strategy game) would have solved this problem, but not from what I can see.
You say "draw" rather than calculate the outside vertices, so ...
You can use clipping plus compositing to "hollow out" your set of squares.
Assume you have determined that these squares are inside your desired boundary (either partially or fully inside):
var aInside=[ {x:60,y:60},{x:80,y:60},{x:40,y:60},{x:60,y:40},{x:60,y:80} ];
An illustration of squares that are inside your desired boundary.
Then, to draw just the boundary of the set of squares, you can:
Stroke (not fill) each of your inside squares: context.rect
Restrict futher drawing to the stroked rects: context.clip
Cause all new drawing to erase existing pixels: context.globalCompositeOperation = 'destination-out'
Fill the entire canvas with a solid color: context.fillRect(0,0,canvas.width,canvas.height).
The trick: Stroking a rectangle actually draws a stroke half-inside & half-outside the rectangle, so step#4 will erase the inside of the set of rectangles but (importantly!) will leave the half outside stroke.
So you end up with this:
Here's example code and a Demo:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var aInside=[ {x:60,y:60},{x:80,y:60},{x:40,y:60},{x:60,y:40},{x:60,y:80} ];
// stroke all inside squares
ctx.save();
ctx.beginPath();
for(var i=0;i<aInside.length;i++){
var s=aInside[i];
ctx.rect(s.x,s.y,20,20);
}
ctx.stroke();
// clip to cause all new drawing to be inside the stroked squares
ctx.clip();
// set compositing to use new drawings to "erase" existing drawings
ctx.globalCompositeOperation='destination-out';
// Fill (===erase!) the entire canvas
// Clipping causes only the clipping area to be erased
// so the inside of the rects set is "hollowed out"
ctx.fillRect(0,0,canvas.width,canvas.height);
ctx.restore();
body{ background-color: ivory; }
#canvas{border:1px solid red; }
<canvas id="canvas" width=150 height=150></canvas>
An Algorithmic Note: If you want a set of the surviving vertices rather than a drawing, you can modify the Marching Squares Algorithm to return only the inflection points. Those inflection points are the vertices of your outside boundary.
This method addresses only drawing/appearance - it does not produce any new polygons. But it allow you to use a collection of polygons (any shape, here rectangles) and merge them visually to produce a merged outline. I base this answer on one of my earlier answers, but modified and adopted to fit the scenario here:
Draw all the rectangles as solids
Re-draw them offset around all edges and corners extruded to the thickness you want
Redraw the original rectangles but with global composite mode set to destination-outand centered on top
There are a few steps, but it works pretty fast.
A couple of notes:
If you have an existing background it would be necessary to use an off-screen canvas as a temporary stage. Not shown here, though the steps would be the same except that you would do these steps on the off-screen context and at the end you would copy the content from the off-screen canvas on top of the existing content of your display canvas.
If you have a lot of rectangles it can be optimized by drawing each single rectangle to a separate off-screen canvas without redrawing anything else. Then you just use this off-screen canvas as a source when you do the extrusion process shown below (see link above for example, just replace image with off-screen canvas itself as source).
It can be further optimized by checking if a rectangle is embedded and if so remove it from the collection.
Demo
var ctx = c.getContext("2d"),
rw = 50, rh = 50, // some demo size
rectangles = []; // rectangle collection
function render(ctx) {
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
ctx.fillStyle = "#a00";
ctx.globalCompositeOperation = "source-over"; // draw using standard mode3
// we will draw the same rects on top of each other eight times
// this will extrude the edge so we can in the next step punch a
// hole in the drawing and leave only the extrusion -
// offset array (x,y) pairs
var i, d = 2, // d = number of pixels to offset
offsets = [-d, -d, 0, -d, d, -d, d, 0, d, d, 0, d, -d, d, -d, 0];
for(i = 0; i < offsets.length; i += 2) {
ctx.setTransform(1,0,0,1, offsets[i], offsets[i+1]);
drawRects()
}
// punch hole in the center
ctx.setTransform(1,0,0,1,0,0); // reset transformatons
ctx.globalCompositeOperation = "destination-out"; // "erase" mode
drawRects(); // draw a final time, wo/ extrusion
function drawRects() {
ctx.beginPath();
rectangles.forEach(function(r) {
ctx.rect(r.x, r.y, r.w, r.h)
}); // loop through collection and draw
ctx.fill()
}
}
// demo stuff --
c.onclick = function(e) {
var r = this.getBoundingClientRect(), // for demo, get mouse position
x = e.clientX - r.left,
y = e.clientY - r.top;
// add rectangle to list
rectangles.push({ // generate a rect. from center
x: x - rw*0.5,
y: y - rh*0.5,
w: rw,
h: rh
});
render(ctx); // the key process
};
canvas {border:1px solid #000}
Click on the canvas below to place rectangles:<br>
<canvas width=600 height=600 id=c></canvas>
I've been trying to draw an asymmetrical ellipse using HTML5 Javascript,
My first try was using the arc and the scale but I was only able to generate symmetrical ellipses using that,
So my second try was using bezier curves. Which had as main problem that I don't understand how they work...
In the end, I ended up with something like this:
http://jsfiddle.net/eLEUD/4/
It works, but I have the modifiers hardcoded in there, as soon as you change the points, it stops working. I have no idea how to calculate them though...
Who can help me further?
The bezierCurveTo function actually draws the last three nodes of a Cubic Bezier Curve
Cubic bezier curves require 4 points to be drawn:
P1: the starting point of the curve.
P2: the first point the curve heads towards but does not touch.
P3: the sencond point the curve heads towards but does not touch.
P4: the end point of the curve.
Given that, the code looks like this (assuming P1,P2,P3,P4 are point structures):
//move to the first part of the curve
context.moveTo(P1.x, P1.y);
//draw the curve.
context.bezierCurveTo(P2.x, P2.y,
P3.x, P3.y,
P4.x, P4.y);
The bezierCurveTo function treats the whatever point the canvas context is sitting at as the first anchor point.
As for drawing your egg shape, you're just going to have to fiddle with it until you're happy with whatever shape you're looking for.
I hope that helps.
EDIT
It seems like maybe you're trying to draw an egg shape inside the diamond shape... so I've updated your fiddle to do that. See the green egg shape here:
http://jsfiddle.net/blesh/zVWrH/1/
What I did is calculate the other points around the diamond: northeast, north-by-northeast, etc. and used those as anchor points.
I hope that helps.