I'm trying to draw parallel equidistant lines inside a circle. I've got to the stage that if i connect points from their opposite angles on the circumference I get parallel lines... but they're not equidistant...
Here's some code:
var num_lines = 8;
var num_points = num_lines * 2;
var start_angle = 100;
var points = [];
var radius = 200;
ctx.strokeCircle(w/2, h/2, radius, radius); // shorthand for ctx.arc( x, y, 5, 0, Math.PI * 2, true );
for (var i = 0; i < num_points; i++) {
var angle = 360/num_points * i;
ctx.fillStyle = "red";
if (i %2 == 0 ) ctx.fillStyle = "blue";
var x = w/2 + Math.cos(angle) * radius/2;
var y = h/2 + Math.sin(angle) * radius/2;
ctx.circle(x, y, 10, 10); // shorthand for ctx.arc( x, y, 5, 0, Math.PI * 2, true );
points.push({x: x, y: y});
}
for (var i = 0; i < num_lines; i++) {
ctx.line(points[i].x, points[i].y, points[points.length-i-1].x, points[points.length-i-1].y)
}
Use Pythagoras' theorem.
The ...
y: vertical position of the line relative to the center
x: horizontal distance of its endpoints from the center
r: radius of the circle
... must satisfy y^2 + x^2 = r^2.
Code:
var radius = 200;
var num_lines = 8;
// vertical spacing
var delta_y = (2.0 * radius) / (num_lines + 1);
ctx.strokeCircle(w/2, h/2, radius, radius);
for (var i = 0; i < num_lines; i++)
{
// applying pythagoras
var y = delta_y * (i + 1) - radius / 2;
var x = Math.sqrt(radius * radius - y * y);
// calculating endpoints
var left_x = w / 2 - x;
var right_x = w / 2 + x;
var end_y = h / 2 + y;
ctx.fillStyle = (i % 2 == 0) ? "blue" : "red";
ctx.circle(left_x, end_y, 10, 10);
ctx.circle(right_x, end_y, 10, 10);
ctx.line(left_x, end_y, right_x, end_y);
}
EDIT: rotation
To rotate a vector by angle a clockwise:
x' = x * cos(a) + y * sin(a)
y' = y * cos(a) - x * sin(a)
Code:
var radius = 200;
var num_lines = 50;
var angle = 60;
// temporary variables
var delta_y = (2.0 * radius) / (num_lines);
var cos_a = Math.cos(angle * Math.PI / 180.0);
var sin_a = Math.sin(angle * Math.PI / 180.0);
ctx.strokeCircle(w / 2, h / 2, radius * 2, radius * 2);
for (var i = 0; i < num_lines; i++)
{
// applying pythagoras
var y = delta_y * i - radius;
var x = Math.sqrt(radius * radius - y * y);
// rotating the displacement vector
var left_x = y * sin_a + x * cos_a;
var right_x = y * sin_a - x * cos_a;
var left_y = y * cos_a - x * sin_a;
var right_y = y * cos_a + x * sin_a;
ctx.fillStyle = (i % 2 == 0) ? "blue" : "red";
ctx.line(w / 2 + left_x , h / 2 + left_y ,
w / 2 + right_x, h / 2 + right_y);
}
got it to work like so... wondering how I can rotate the lines at an angle (mathematically, not using ctx.translate and ctx.rotate ):
var radius = 200;
var num_lines = 50;
// vertical spacing
var delta_y = (2.0 * radius) / (num_lines);
ctx.strokeCircle(w/2, h/2, radius * 2, radius * 2);
for (var i = 0; i < num_lines; i++)
{
// applying pythagoras
var y = delta_y * (i) - radius;
var x = Math.sqrt(radius * radius - y * y);
// calculating endpoints
var left_x = w / 2 - x;
var right_x = w / 2 + x;
var end_y = h / 2 + y;
ctx.fillStyle = (i % 2 == 0) ? "blue" : "red";
ctx.line(left_x, end_y, right_x, end_y);
}
Related
There is a simple JS code that renders a very basic Mandelbrot fractal.
let canvas = document.getElementsByTagName("canvas")[0],
canvasWidth = canvas.width,
canvasHeight = canvas.height,
ctx = canvas.getContext("2d");
const maxIterations = 100,
magnificationFactor = 200,
panX = 2,
panY = 1.25;
let drawPoint = (x, y, color) => {
var pointSize = 1;
ctx.fillStyle = color;
ctx.beginPath();
ctx.arc(x, y, pointSize, 0, Math.PI * 2, true);
ctx.fill();
}
let mandelbrot = (c, z = 0) => z ^ 2 + c;
let BelongsToMandelbrotSet = (x, y) => {
let realComponentOfResult = x,
imaginaryComponentOfResult = y;
for (let i = 0; i < maxIterations; i++) {
let tempRealComponent = realComponentOfResult * realComponentOfResult - imaginaryComponentOfResult * imaginaryComponentOfResult + x,
tempImaginaryComponent = 2 * realComponentOfResult * imaginaryComponentOfResult + y;
realComponentOfResult = tempRealComponent;
imaginaryComponentOfResult = tempImaginaryComponent;
}
if (realComponentOfResult * imaginaryComponentOfResult < 5)
return true;
return false;
}
for (let x = 0; x < canvasWidth; x++) {
for (let y = 0; y < canvasHeight; y++) {
let belongsToSet =
BelongsToMandelbrotSet(x / magnificationFactor - panX,
y / magnificationFactor - panY);
if (belongsToSet)
drawPoint(x, y, '#000')
}
}
body {
margin: 0;
}
<canvas width="800" height="800"></canvas>
The task is to rotate this fractal by the random angle along its axis.
And it shouldn't be a canvas rotation or its image data, but I have to tweak the initial fractal formula to do that.
For example, if the angle is 45 degrees or PI / 4 in radians, the output should look like
I have tried to play with x = center.x + 500 * Math.cos(theta), y = center.y + 500 * Math.sin(theta) without any success.
You can try to transform the coordinates right in the main loop, where you do scaling and translation:
let x1 = x * Math.cos(theta) - y * Math.sin(theta)
let y1 = x * Math.sin(theta) + y * Math.cos(theta)
let belongsToSet = BelongsToMandelbrotSet(x1/magnificationFactor - panX, ...
...drawPoint(x, y, '#000')
To further simplify this, create an affine transformation matrix for all kinds of transforms and apply it once.
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()
When rotating a custom shape using translate(width/2,height/2); rotate(angle)),
it moves the shape in the bottom left corner. I tried making translate values negative, it fixed it but then the origin was at 0,0. I have used pop(); push() and beginShape(); endShape with no success.
var points = [];
var r;
var lines = 30;
function setup() {
createCanvas(window.innerWidth, window.windowHeight);
angleMode(DEGREES);
// get the points of the corners of the hexagon
r = Math.min(width, height) * 0.4;
var angle = 60;
for (var i = 1; i < 7; i++) {
var tempX = r * sin((angle * i + 30) % 360) + width / 2;
var tempY = r * cos((angle * i + 30) % 360) + height / 2;
points.push([tempX, tempY]);
}
background(0);
stroke(0, 0, 255);
rectMode(CENTER);
}
function draw() {
background(0);
// draw the lines of ...
push();
translate(width/2, height/2);
rotate(frameCount * 0.75);
beginShape();
for (var i = 0; i < points.length; i++) {
// ... the hexagon perimeter
line(points[i][0], points[i][1], points[(i + 1) % 6][0], points[(i + 1) % 6][1]);
var tempAngle = 240 + i * 60;
var tempX = r * 1.1545 * sin(tempAngle) + points[i][0];
var tempY = r * 1.1545 * cos(tempAngle) + points[i][1];
for (var j = 0; j < lines + 1; j++) {
// ... the lines inside the hexagon
var tempAngle2 = tempAngle = (30 / lines * j) + 210 + i * 60;
var distance = r / cos(30 / lines * j);
var tempX2 = distance * sin(tempAngle2) + points[i][0];
var tempY2 = distance * cos(tempAngle2) + points[i][1];;
line(points[i][0], points[i][1], tempX2, tempY2);
}
endShape();
}
pop();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.6.1/p5.js"></script>
I think the problem is that you are defining your points for your shape with an x/y offset. By removing the width / 2 & height / 2 from your point definitions it centers your shape.
var points = [];
var r;
var lines = 30;
function setup() {
createCanvas(window.innerWidth, window.windowHeight);
angleMode(DEGREES);
// get the points of the corners of the hexagon
r = Math.min(width, height) * 0.4;
var angle = 60;
for (var i = 1; i < 7; i++) {
var tempX = r * sin((angle * i + 30) % 360)
var tempY = r * cos((angle * i + 30) % 360)
points.push([tempX, tempY]);
}
background(0);
stroke(0, 0, 255);
//rectMode(CENTER);
}
function draw() {
background(0);
// draw the lines of ...
push();
translate(width/2, height/2);
rotate(frameCount * 0.75);
beginShape();
for (var i = 0; i < points.length; i++) {
// ... the hexagon perimeter
line(points[i][0], points[i][1], points[(i + 1) % 6][0], points[(i + 1) % 6][1]);
var tempAngle = 240 + i * 60;
var tempX = r * 1.1545 * sin(tempAngle) + points[i][0];
var tempY = r * 1.1545 * cos(tempAngle) + points[i][1];
for (var j = 0; j < lines + 1; j++) {
// ... the lines inside the hexagon
var tempAngle2 = tempAngle = (30 / lines * j) + 210 + i * 60;
var distance = r / cos(30 / lines * j);
var tempX2 = distance * sin(tempAngle2) + points[i][0];
var tempY2 = distance * cos(tempAngle2) + points[i][1];;
line(points[i][0], points[i][1], tempX2, tempY2);
}
endShape();
}
pop();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.6.1/p5.js"></script>
I wanted a random x/ y coordinate on the area of an intersection of two circles
My problem now is that i got the heavy part done, and it does work in the browser with Canvas for demonstration. But only on 2D Coordinates. Im using Google Maps, and i wanted to input two Circles with the Lat Lng positions and a radius. The result should have been the Lat/ Lang which i calculated on 2D.
But my mathematics end on real world coordinates..
so circle1.x and .y would be .lat and .lng for example.
/******************************************************************
Generate New Coord From Intersect
Generate random position point on cntersect area of two circles.
*******************************************************************/
var circle1 = {x : 0, y : 0, radius : 10};
var circle2 = {x : 0, y : 0, radius : 10};
var ctx;
var p2 = {x : 0, y : 0};
var p3 = {x : 0, y : 0};
var t3 = {x : 0, y : 0};
var t6 = {x : 0, y : 0};
var t7 = {x : 0, y : 0};
function GenerateNewCoordFromIntersect(circle1, circle2) {
var c = document.getElementById('canvasID');
c.width = 500;
c.height = 500;
ctx = c.getContext('2d');
drawCircle(circle1.x,circle1.y,circle1.radius,"red");
drawCircle(circle2.x,circle2.y,circle2.radius,"blue");
var distance = Math.sqrt(Math.pow(circle2.x-circle1.x,2) + Math.pow(circle2.y-circle1.y,2));
// then there are no solutions, the circles are separate.
if (distance > circle1.radius + circle2.radius ) {
return;
}
// then there are no solutions because one circle is contained within the other.
if (distance < circle1.radius - circle2.radius ) {
return;
}
// then the circles are coincident and there are an infinite number of solutions.
if (distance == 0 && circle1.radius == circle2.radius) {
return;
}
// random if take sector of circle 1 or 2
if (Math.random() > 0.5) {
var newcircle1 = JSON.parse(JSON.stringify(circle1));
var newcircle2 = JSON.parse(JSON.stringify(circle2));
circle1 = newcircle2;
circle2 = newcircle1;
}
// calc a
a = ((Math.pow(circle1.radius,2) - Math.pow(circle2.radius,2) + Math.pow(distance,2))) / (2 * distance);
// calc height
h = Math.sqrt(Math.pow(circle1.radius,2) - Math.pow(a,2));
// calc middle point of intersect
p2.x = circle1.x + a * (circle2.x - circle1.x) / distance;
p2.y = circle1.y + a * (circle2.y - circle1.y) / distance;
// calc upper radius intersect point
p3.x = p2.x + h * (circle2.y - circle1.y) / distance;
p3.y = p2.y - h * (circle2.x - circle1.x) / distance;
// random height for random point position
var randNumber = Math.random() / 2 + Math.random() * 0.5;
var radiusOfH = (h*2);
var randh = (randNumber) * radiusOfH - h;
// calc random Hypotenuse
var hypDistance = Math.abs(Math.sqrt(Math.pow(a,2) + Math.pow(randh,2)));
var randomHyp = (circle1.radius - hypDistance) + hypDistance;
// random point on line of middlepoint
t3.x = p2.x + ((randh) * (circle2.y - circle1.y)) / distance;
t3.y = p2.y - (randh) * (circle2.x - circle1.x) / distance;
// angle calc
var winkel = Math.atan(randh / a);
var newA = Math.cos(winkel) * randomHyp; //(randomHyp);
var newH = Math.sin(winkel) * randomHyp;//newA ;
t6.x = circle1.x + newA * (circle2.x - circle1.x) / distance;
t6.y = circle1.y + newA * (circle2.y - circle1.y) / distance;
t7.x = t6.x + newH * (circle2.y - circle1.y) / distance;
t7.y = t6.y - newH * (circle2.x - circle1.x) / distance;
randNumber = Math.random();
var xDist = (t7.x - t3.x) * (randNumber);
var yDist = (t7.y - t3.y) * (randNumber);
var rx = t3.x + xDist;
var ry = t3.y + yDist;
drawCircle(rx,ry,2,"blue");
}
function drawCircle(x, y, r, fill) {
ctx.beginPath();
ctx.arc(x,y,r,0,2*Math.PI);
ctx.strokeStyle = fill;
ctx.stroke();
}
You need to know the map projection that it's used to convert between lat/long coordinates to a x/y coordinates of a 2d plane.
You can find specific information for the Google Maps API here.
I have a flat image that I want to transform so it looks like a projection on an elliptic cylinder.
I've found the great script from Blindman67 for a regular cylinder at https://stackoverflow.com/a/40999097/4273683
However I don't understand, how to change the script to get an elliptic result. Any idea?
Thanks a lot for help.
var createImage=function(w,h){var i=document.createElement("canvas");i.width=w;i.height=h;i.ctx=i.getContext("2d");return i;}
var canvas = createImage(400,400);
var ctx = canvas.ctx;
document.body.appendChild(canvas)
ctx.clearRect(0,0,500,500)
var image = createImage(400,200);
image.ctx.font = "60px arial";
image.ctx.textAlign = "center";
image.ctx.fillStyle = "#7F5";
image.ctx.fillRect(0,0,image.width,image.height)
image.ctx.fillStyle = "white";
image.ctx.fillText("Wrap around",200,60)
image.ctx.fillText("Some images",200,140)
function draw(ang,tilt, perspective){
var step = 1/(Math.max(image.width,400));
for(var i = 0; i < 1; i += step){
var a = i * Math.PI;
var a1 = (i+ step*2) * Math.PI ;
var ix = i * image.width*1.2;
var iw = step * image.width*1.2;
a += ang * Math.PI * 2;
a1 += ang * Math.PI * 2;
a = Math.PI -a;
a1 = Math.PI -a1;
var x = canvas.width * 0.5;
var y = canvas.height * 0.1;
var x1 = x + Math.cos(a1) * 110;
var y1 = y + Math.sin(a) * tilt;
x += Math.cos(a) * 110;
y += Math.sin(a) * tilt;
var s = Math.sin(a);
var s1 = Math.sin(a1);
if(s > 0 || s1 > 0){
ctx.drawImage(image,ix,0,iw,image.height,x1,y- s * perspective*0.5,x-x1,200 + s * perspective)
}
}
}
var w = canvas.width;
var h = canvas.height;
// main update function
function update(timer){
ctx.setTransform(1,0,0,1,0,0); // reset transform
ctx.globalAlpha = 1; // reset alpha
ctx.fillStyle = "black"
ctx.fillRect(0,0,w,h);
draw(timer / 2000, 40,30)
requestAnimationFrame(update);
}
requestAnimationFrame(update);