I'm new to WebGL and was trying to draw a circle with triangle_fan.
I set up the variables
var pi = 3.14159;
var x = 2*pi/100;
var y = 2*pi/100;
var r = 0.05;
points = [ vec2(0.4, 0.8) ]; //establish origin
And then drew the circle using this for loop.
for(var i = 0.4; i < 100; i++){
points.push(vec2(r*Math.cos(x*i), r*Math.sin(y*i)));
points.push(vec2(r*Math.cos(x*(i+1)), r*Math.sin(y*(i+1))));
}
The issue is that I am actually pushing in the second point again when i increases which I don't want to do.
Also, the image below is that is drawn :/
I don't have enough reputation to comment on mlkn's answer, but I think there was one piece he was missing. Here's how I ended up using his example
vec2 center = vec2(cX, cY);
points.push(center);
for (i = 0; i <= 200; i++){
points.push(center + vec2(
r*Math.cos(i*2*Math.PI/200),
r*Math.sin(i*2*Math.PI/200)
));
}
Otherwise, if the 200 supplied in the start of the loop is a fraction of the 200 given in the calculation (r*Math.cos(i*2*Math.PI/200)), then only a fraction of the circle will be drawn. Also, without adding in the i to the calculation in the loop, the points are all the same value, resulting in a line.
Using triangle fan you don't need to duplicate vertices. WebGL will form ABC, ACD and ADE triangles from [A,B,C,D,E] array with TRIANGLE_FAN mode.
Also, you don't take into account center of your sphere. And i can't get why i = 0.4.
Here is corrected version of your code:
vec2 center = vec2(cX, cY);
points.push(center);
for (i = 0; i <= 100; i++){
points.push(center + vec2(
r*Math.cos(i * 2 * Math.PI / 200),
r*Math.sin(i * 2 * Math.PI / 200)
));
}
Also if you want to draw a sphere you could often draw one triangle or gl.point and discard pixels which are out of circle in fragment shader.
Both the Ramil and Nicks answer helped me lot, i would like to add a point here.
For some one who might be confused why almost every circle generation deals with this step
i*2*Math.PI/200 --->(i*2*Math.PI/someNumber)
and the loop goes from 0 to 200---> again 0 to someNumber ,Here is how it works,since a complete circle spans from 0 to 2*Math.PI and to draw a circle by points we might want more points or the circle points will be having some gaps between them along the edge,We divide this into intervals by some number effectively giving more points to plot.Say we need to divide the interval from 0 to 2*PI into 800 points we do this by
const totalPoints=800;
for (let i = 0; i <= totalPoints; i++) {
const angle= 2 * Math.PI * i / totalPoints;
const x = startX + radius * Math.cos(angle);
const y = startY + radius * Math.sin(angle);
vertices.push(x, y);
}
Since the loop goes from 0 to 800 the last value will be equal to 2*Math.PI*800/800 giving the last value of the interval [0,2*PI]
Related
I'm attempting to write code that will generate fractals according to the Chaos game
In particular, I'm trying to debug the faulty generation/rendering of this fractal:
I'm doing this with Javascript in a Canvas element. The relevant Javascript is below:
canvas = document.getElementById('myCanvas');
context = canvas.getContext('2d');
//constants
border = 10 //cardinal distance between vertices and nearest edge(s)
class Point{
constructor(_x, _y){
this.x = _x;
this.y = _y;
}
}
vertices = []
secondLastVertex = 0;
lastVertex = 0;
//vertices in clockwise order (for ease of checking adjacency)
vertices.push(new Point(canvas.width / 2, border)); //top
vertices.push(new Point(canvas.width - border, canvas.height * Math.tan(36 * Math.PI / 180) / 2)); //upper right
vertices.push(new Point(canvas.width * Math.cos(36 * Math.PI / 180), canvas.height - border)); //lower right
vertices.push(new Point(canvas.width * (1 - (Math.cos(36 * Math.PI / 180))), canvas.height - border)); //lower left
vertices.push(new Point(border, canvas.height * Math.tan(36 * Math.PI / 180) / 2)); //upper left
//move half distance towards random vertex but it can't neighbor the last one IF the last two were the same
function updatePoint(){
//pick a random vertex
v = Math.floor(Math.random() * vertices.length);
if(lastVertex == secondLastVertex)
//while randomly selected vertex is adjacent to the last approached vertex
while((v == (lastVertex - 1) % 5) || (v == (lastVertex + 1) % 5))
//pick another random vertex
v = Math.floor(Math.random() * vertices.length);
//cycle the last two vertices
secondLastVertex = lastVertex;
lastVertex = v;
//move half way towards the chosen vertex
point.x = (vertices[v].x + point.x) / 2;
point.y = (vertices[v].y + point.y) / 2;
}
//starting point (doesn't matter where)
point = new Point(canvas.width / 2, canvas.height / 2);
for (var i = 0; i < 1000000; i++){
//get point's next location
updatePoint();
//draw the point
context.fillRect(Math.round(point.x), Math.round(point.y), 1, 1);
}
The rendering that is produced looks like this:
So far I haven't been able to determine what is causing the rendering to be so skewed and wrong. One possibility is that I've misunderstood the rules that generate this fractal (i.e. "move half the distance from the current position towards a random vertex that is not adjacent to the last vertex IF the last two vertices were the same")
Another is that I have some bug in how I'm drawing fractals. But the same code with rule/starting-vertex modifications is able to draw things like the Sierpinkski triangle/carpet and even other pentagonal fractals apparently perfectly. Though one other pentagonal fractal ended up with some weird skewing and "lower right fourth of each self-similar substructure" weirdness.
I tried making some slight modifications to how I interpreted the rules (e.g. "next vertex can't be adjacent OR EQUAL TO previous vertex if last two vertices were the same") but nothing like that helped. I also tried not rounding the coordinates of the target point before plotting it, but though this slightly changed the character/sharpness of the details, it didn't change any larger scale features of the plot.
My issue as kindly pointed out by ggorlen, was that I wasn't comparing vertices for adjacency correctly. I mistakenly thought Javascript evaluated something like (-1 % 5) as 4, rather than -1.
To fix this, I add 4 to the index instead of subtracting 1, before modding it against 5 (the number of vertices)
This completely fixed the render. (in not just this case but other cases I'd been testing with different fractals)
I have one circle, which grows and shrinks by manipulating the radius in a loop.
While growing and shrinking, I draw a point on that circle. And within the same loop, increasing the angle for a next point.
The setup is like this:
let radius = 0;
let circleAngle = 0;
let radiusAngle = 0;
let speed = 0.02;
let radiusSpeed = 4;
let circleSpeed = 2;
And in the loop:
radius = Math.cos(radiusAngle) * 100;
// creating new point for line
let pointOnCircle = {
x: midX + Math.cos(circleAngle) * radius,
y: midY + Math.sin(circleAngle) * radius
};
circleAngle += speed * circleSpeed;
radiusAngle += speed * radiusSpeed;
This produces some kind of flower / pattern to be drawn.
After unknown rotations, the drawing line connects to the point from where it started, closing the path perfectly.
Now I would like to know how many rotations must occure, before the line is back to it's beginning.
A working example can be found here:
http://codepen.io/anon/pen/RGKOjP
The console logs the current rotations of both the circle and the line.
Full cycle is over, when both radius and point returns to the starting point. So
speed * circleSpeed * K = 360 * N
speed * radiusSpeed * K = 360 * M
Here K is unknown number of turns, N and M are integer numbers.
Divide the first equation by the second
circleSpeed / radiusSpeed = N / M
If speed values are integers, divide them by LCM to get minimal valid N and M values, if they are rational, multiply them to get integer proportion.
For your example minimal integers N=1,M=2, so we can get
K = 360 * 1 / (0.02 * 2) = 9000 loop turns
I was working on a fun project that implicates creating "imperfect" circles by drawing them with lines and animate their points to generate a pleasing effect.
The points should alternate between moving away and closer to the center of the circle, to illustrate:
I think I was able to accomplish that, the problem is when I try to render it in a canvas half the render jitters like crazy, you can see it in this demo.
You can see how it renders for me in this video. If you pay close attention the bottom right half of the render runs smoothly while the top left just..doesn't.
This is how I create the points:
for (var i = 0; i < q; i++) {
var a = toRad(aDiv * i);
var e = rand(this.e, 1);
var x = Math.cos(a) * (this.r * e) + this.x;
var y = Math.sin(a) * (this.r * e) + this.y;
this.points.push({
x: x,
y: y,
initX: x,
initY: y,
reverseX: false,
reverseY: false,
finalX: x + 5 * Math.cos(a),
finalY: y + 5 * Math.sin(a)
});
}
Each point in the imperfect circle is calculated using an angle and a random distance that it's not particularly relevant (it relies on a few parameters).
I think it's starts to mess up when I assign the final values (finalX,finalY), the animation is supposed to alternate between those and their initial values, but only half of the render accomplishes it.
Is the math wrong? Is the code wrong? Or is it just that my computer can't handle the rendering?
I can't figure it out, thanks in advance!
Is the math wrong? Is the code wrong? Or is it just that my computer can't handle the rendering?
I Think that your animation function has not care about the elapsed time. Simply the animation occurs very fast. The number of requestAnimationFrame callbacks is usually 60 times per second, So Happens just what is expected to happen.
I made some fixes in this fiddle. This animate function take care about timestamp. Also I made a gradient in the animation to alternate between their final and initial positions smoothly.
ImperfectCircle.prototype.animate = function (timestamp) {
var factor = 4;
var stepTime = 400;
for (var i = 0, l = this.points.length; i < l; i++) {
var point = this.points[i];
var direction = Math.floor(timestamp/stepTime)%2;
var stepProgress = timestamp % stepTime * 100 / stepTime;
stepProgress = (direction == 0 ? stepProgress: 100 -stepProgress);
point.x = point.initX + (Math.cos(point.angle) * stepProgress/100 * factor);
point.y = point.initY + (Math.sin(point.angle) * stepProgress/100 * factor);
}
}
Step by Step:
based on comments
// 1. Calculates the steps as int: Math.floor(timestamp/stepTime)
// 2. Modulo to know if even step or odd step: %2
var direction = Math.floor(timestamp/stepTime)%2;
// 1. Calculates the step progress: timestamp % stepTime
// 2. Convert it to a percentage: * 100 / stepTime
var stepProgress = timestamp % stepTime * 100 / stepTime;
// if odd invert the percentage.
stepProgress = (direction == 0 ? stepProgress: 100 -stepProgress);
// recompute position based on step percentage
// factor is for fine adjustment.
point.x = point.initX + (Math.cos(point.angle) * stepProgress/100 * factor);
point.y = point.initY + (Math.sin(point.angle) * stepProgress/100 * factor);
I've written a loop in JavaScript that will render rings of concentric hexagons around a central hexagon on the HTML canvas.
I start with the innermost ring, draw the hex at 3 o'clock, then continue around in a circle until all hexes are rendered. Then I move on to the next ring and repeat.
When you draw hexagons this way (instead of tiling them using solely x and y offsets) any hexagon that is not divisible by 60 is not the same distance to the center hex as those that are divisible by 60 (because these hexes comprise the flat edges, not the vertices, of the larger hex).
The problem I'm having is these hexes (those not divisible by 60 degrees) are rendering in a slightly off position. I'm not sure if it is a floating point math problem, the problem with my algorithm, the problem with my rusty trig, or just plain stupidity. I'm betting 3 out of 4. To cut to the chase, look at the line if (alpha % 60 !== 0) in the code below.
As a point of information, I decided to draw the grid this way because I needed an easy way to map the coordinates of each hex into a data structure, with each hex being identified by its ring # and ID# within that ring. If there is a better way to do it I'm all ears, however, I'd still like to know why my rendering is off.
Here is my very amateur code, so bear with me.
<script type="text/javascript">
window.addEventListener('load', eventWindowLoaded, false);
function eventWindowLoaded() {
canvasApp();
}
function canvasApp(){
var xOrigin;
var yOrigin;
var scaleFactor = 30;
var theCanvas = document.getElementById("canvas");
var context;
if (canvas.getContext) {
context = theCanvas.getContext("2d");
window.addEventListener('resize', resizeCanvas, false);
window.addEventListener('orientationchange', resizeCanvas, false);
resizeCanvas();
}
drawScreen();
function resizeCanvas() {
var imgData = context.getImageData(0,0, theCanvas.width, theCanvas.height);
theCanvas.width = window.innerWidth;
theCanvas.height = window.innerHeight;
context.putImageData(imgData,0,0);
xOrigin = theCanvas.width / 2;
yOrigin = theCanvas.height / 2;
}
function drawScreen() {
var rings = 3;
var alpha = 0;
var modifier = 1;
context.clearRect(0, 0, theCanvas.width, theCanvas.height);
drawHex(0,0);
for (var i = 1; i<=rings; i++) {
for (var j = 1; j<=i*6; j++) {
if (alpha % 60 !== 0) {
var h = modifier * scaleFactor / Math.cos(dtr(360 / (6 * i)));
drawHex(h * (Math.cos(dtr(alpha))), h * Math.sin(dtr(alpha)));
}
else {
drawHex(2 * scaleFactor * i * Math.cos(dtr(alpha)), 2 * scaleFactor * i * Math.sin(dtr(alpha)));
}
alpha += 360 / (i*6);
}
modifier+=2;
}
}
function drawHex(xOff, yOff) {
context.fillStyle = '#aaaaaa';
context.strokeStyle = 'black';
context.lineWidth = 2;
context.lineCap = 'square';
context.beginPath();
context.moveTo(xOrigin+xOff-scaleFactor,yOrigin+yOff-Math.tan(dtr(30))*scaleFactor);
context.lineTo(xOrigin+xOff,yOrigin+yOff-scaleFactor/Math.cos(dtr(30)));
context.lineTo(xOrigin+xOff+scaleFactor,yOrigin+yOff-Math.tan(dtr(30))*scaleFactor);
context.lineTo(xOrigin+xOff+scaleFactor,yOrigin+yOff+Math.tan(dtr(30))*scaleFactor);
context.lineTo(xOrigin+xOff,yOrigin+yOff+scaleFactor/Math.cos(dtr(30)));
context.lineTo(xOrigin+xOff-scaleFactor,yOrigin+yOff+Math.tan(dtr(30))*scaleFactor);
context.closePath();
context.stroke();
}
function dtr(ang) {
return ang * Math.PI / 180;
}
function rtd(ang) {
return ang * 180 / Math.PI;
}
}
</script>
Man it took me longer than I'd like to admit to find the pattern for the hexagonal circles. I'm too tired right now to explain since I think I'll need to make some assisting illustrations in order to explain it.
In short, each "circle" of hexagonal shapes is itself hexagonal. The number of hexagonal shapes along one edge is the same as the number of the steps from the center.
var c = document.getElementById("canvas");
var ctx = c.getContext("2d");
c.width = 500;
c.height = 500;
var hexRadius = 20;
var innerCircleRadius = hexRadius/2*Math.sqrt(3);
var TO_RADIANS = Math.PI/180;
function drawHex(x,y) {
var r = hexRadius;
ctx.beginPath();
ctx.moveTo(x,y-r);
for (var i = 0; i<=6; i++) {
ctx.lineTo(x+Math.cos((i*60-90)*TO_RADIANS)*r,y+Math.sin((i*60-90)*TO_RADIANS)*r);
}
ctx.closePath();
ctx.stroke();
}
drawHexCircle(250,250,4);
function drawHexCircle(x,y,circles) {
var rc = innerCircleRadius;
drawHex(250,250); //center
for (var i = 1; i<=circles; i++) {
for (var j = 0; j<6; j++) {
var currentX = x+Math.cos((j*60)*TO_RADIANS)*rc*2*i;
var currentY = y+Math.sin((j*60)*TO_RADIANS)*rc*2*i;
drawHex(currentX,currentY);
for (var k = 1; k<i; k++) {
var newX = currentX + Math.cos((j*60+120)*TO_RADIANS)*rc*2*k;
var newY = currentY + Math.sin((j*60+120)*TO_RADIANS)*rc*2*k;
drawHex(newX,newY);
}
}
}
}
canvas {
border: 1px solid black;
}
<canvas id="canvas"></canvas>
I think you're trying to use radial coordinates for something that isn't a circle.
As you noted correctly, the (centers of) the vertex hexagons are indeed laid out in a circle and you can use basic radial positioning to lay them out. However, the non-vertex ones are not laid out on an arc of that circle, but on a chord of it (the line connecting two vertex hexagons). So your algorithm, which tries to use a constant h (radius) value for these hexagons, will not lay them out correctly.
You can try interpolating the non-vertex hexagons from the vertex hexagons: the position of of the Kth (out of N) non-vertex hexagon H between vertex hexagons VH1 and VH2 is:
Pos(H) = Pos(VH1) + (K / (N + 1)) * (Pos(VH2)-Pos(VH1))
e.g. in a ring with 4 hexagons per edge (i.e. 2 non-vertex hexagons), look at the line of hexagons between the 3 o'clock and the 5 o'clock: the 3 o'clock is at 0% along that line, the one after that is at 1/3 of the way, the next is at 2/3 of the way, and the 5 o'clock is at 100% of the way. Alternatively you can think of each hexagon along that line as "advancing" by a predetermined vector in the direction between the two vertices until you reach the end of the line.
So basically your algorithm could go through the 6 primary vertex hexagons, each time interpolating the hexagons from the current vertex hexagon to the next. Thus you should probably have three nested loops: one for rings, one for angles on a ring (always six steps), and one for interpolating hexagons along a given angle (number of steps according to ring number).
Is there a way to translate into javascript a piece of code that will allow me to show map pins around a point taking in consideration a radius ?
var data=[
{long:3,lat:2},
{long:5,lat:2},
{long:2,lat:3}
];
aCoord={long:1,lat:2};
for(var i=0;i<data.length;i++){
if (data[i] is 30 kms far from aCoord)
myMap.addPin(data[i]);
}
myMap.autozoom();
Thank you,
Regards
I came up with this example so you have an idea on how to calculate the points. You'll need to figure out how to do any necessary conversions for lat/lon.
/**
* Returns coordinates for N points around a circle with a given radius from
* the center.
*
* center: array [x, y]
* radius: int
* num_points: int
*/
function get_points_on_circle(center, radius, num_points) {
if (!num_points) num_points = 10;
var interval = Math.PI * 2 / num_points;
points = [];
i = -1;
while (++i < num_points) {
var theta = interval * i,
point = [Math.cos(theta) * radius + center[0], Math.sin(theta) * radius + center[1]];
points.push(point);
}
return points;
}
// Sample usage
var center = [250, 250],
radius = 100,
num_points = 10;
var points = get_points_on_circle(center, radius, num_points);
Test it out (uses Raphael for plotting)
If you are interested in learning a little about the logic:
A radian is a unit of measure for angles. There are a total of 2*PI radians in a circle. Using that fact, you can calculate the angle interval of any number of points on a circle by performing 2*PI/num_points.
When you know the angle interval, you can calculate the angle (theta) of a point on a circle. Once you have theta (the angle), you have polar coordinates (radius,angle). For that to be of any use to us in this problem, you need to convert the polar coordinates into Cartesian coordinates (x,y). You can do that by using the following formulas:
x = cos(theta) * radius
y = sin(theta) * radius
That's pretty much it in a nutshell.