I want to distribute n points evenly on a circle circumference in quadrants I and IV only.
As parameters, I have the numbers of point n, the center of circle coordiantes cx and cy and the radius r.
I can distribute the points over the whole circumference like using this formula below, but I am looking for the formula to spread them only in quadrants I and IV
var n = 5;
var cx = 1;
var cy = 1;
var r = 2;
//I store each point's coordinates in this array below
var coordinates = [];
for (var i=0; i < n; i++) {
//defining point's angle with the center of the circle in radiant
//this angle distribute the points evenly over all 4 quadrants
var angle = ((360/n) * i) * (Math.PI/180);
//calculating the point's coordinates on the circle circumference
var pointX = cx + r * Math.cos(angle);
var pointY = cx + r * Math.sin(angle);
//storing the point's coordinates
coordinates.push([pointX, pointY]);
}
Here would be the steps I'd take to solve this:
find the angle betw. each point var incrementBy = 180 / n
start angle will be 270º and end angle will be 90º
iterate through via
code
var increment = 180 / n
var startAngle = 270
for (var i = 0; i < n; i++)
{
var angle = startAngle + increment * i
var rads = angle * Math.pi / 180
var tx = cx + r * Math.cos(rads)
var ty = cy + r * Math.sin(rads)
coords.push([tx, ty])
}
note
I didn't bother to convert for traditional quadrants (vs JS's y-axis moving downwards). If that is needed then, after your calculations, just invert the ty value. I also didn't bother to reduce the angle value when it exceeds 360º when you're incrementing back into Quad I.
like this?
var n = 5;
var r = 2;
var cx = 1;
var cy = 1;
var coordinates = [];
for(var i=0; i<n; ++i){
var a = (i+.5) / n * Math.PI;
coordinates.push([
cx + Math.sin(a) * r,
cy - Math.cos(a) * r
]);
}
Here is the way to equally distribute objects
var boxes = []
let count = 10;
for (let i = 0; i < count; i++) {
let size = 0.8;
let radius = 3;
let box = new THREE.Mesh(new THREE.BoxGeometry( size, size, size ),new THREE.MeshPhysicalMaterial(0x333333))
let gap = 0.5;
let angle = i * ((Math.PI * 2) / count);
let x = radius * Math.cos(angle);
let y = 0;
let z = radius * Math.sin(angle);
box.position.set(x,y,z);
boxes.push(box);`enter code here`
scene.add(box)
}
here is how it looks for 10 blocks
here is how it looks for 5 blocks
var n = 5;
var cx = 1;
var cy = 1;
var r = 2;
//I store each point's coordinates in this array below
var coordinates = [];
for (var i=0; i < n; i++) {
//defining the angle of the point with the center of the circle in radiant
var angle = ((360/n) * i) * (Math.PI/180);
//calculating the coordinates of the point on the circle circumference
var pointX = cx + r * Math.cos(angle);
var pointY = cx + r * Math.sin(angle);
// Here, we are going to use a boolean expression to determine if
// [pointX, pointY] is within quadrant 1 or 4.
// We can start with this boolean equation:
// (pointX >= cx && pointY >= cy) || (pointX >= cx && pointY <= cy)
// But this problem can be simplified to only pointX >= cx
if(pointX >= cx){
//storing the point's coordinates
coordinates.push([pointX, pointY]);
}
}
Related
I am using p5.js to create a sphere
What I am interested in is getting the points coordinates of the shapes used to modelize the sphere.
Is it possible to do so?
Basically, I would like to get the series of points used to draw the triangles that modelize the sphere.
You can use the spherical coordinates (two angles and radius) to cartesian coordinates (x,y,z) conversion formula to compute points on a sphere:
(Image source: wikipedia)
If you think of the two angles as latitude(lat), longitude(lon) angles on our globe and a constant radius, in the JS you can look at this formula as:
var x = radius * cos(lat) * sin(lon);
var y = radius * sin(lat) * sin(lon);
var z = radius * cos(lon);
Here's a basic sketch to illustrate the idea:
var radius = 120;
var latDetail = 0.243;
var lonDetail = 0.15;
function setup() {
createCanvas(300, 300, WEBGL);
strokeWeight(9);
}
function draw() {
background(255);
orbitControl();
beginShape(POINTS);
// iterate through lat, lon angles (in radians)
for(var lat = 0; lat <= PI; lat += latDetail){
for(var lon = 0; lon <= TWO_PI; lon += lonDetail){
// for each sperical coordinate (lat, lon angles, radius)
// convert to cartesian (x, y, z)
var x = radius * cos(lat) * sin(lon);
var y = radius * sin(lat) * sin(lon);
var z = radius * cos(lon);
// render each point
vertex(x, y, z);
}
}
endShape();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.1/p5.min.js"></script>
Have a play with the latDetail, lonDetail variables which define how dense/sparse the sphere's parallels/meridians will be.
Having a quick look online for UV Spheres, Daniel Sieger's Generating Spheres article is neat!
Even though the code is c++, the syntax is similar enough to understand:
// generate vertices per stack / slice
for (int i = 0; i < n_stacks - 1; i++)
{
auto phi = M_PI * double(i + 1) / double(n_stacks);
for (int j = 0; j < n_slices; j++)
{
auto theta = 2.0 * M_PI * double(j) / double(n_slices);
auto x = std::sin(phi) * std::cos(theta);
auto y = std::cos(phi);
auto z = std::sin(phi) * std::sin(theta);
mesh.add_vertex(Point(x, y, z));
}
}
Pretty much the same formula (withouth the radius scalar) and a counter to for the number of segments on each angle (instead of an angle increment).
Here's a p5.js port:
var radius = 120;
var uSegments = 12;
var vSegments = 12;
// sliders
var uSegmentsSlider;
var vSegmentsSlider;
function setup() {
createCanvas(300, 300, WEBGL);
strokeWeight(9);
uSegmentsSlider = createSlider(3, 36, 12, 1);
vSegmentsSlider = createSlider(3, 36, 12, 1);
uSegmentsSlider.position(10, 10);
vSegmentsSlider.position(10, 30);
createP('U').position(145, -3);
createP('V').position(145, 17);
}
function draw() {
// read slider values
uSegments = uSegmentsSlider.value();
vSegments = vSegmentsSlider.value();
background(255);
orbitControl();
beginShape(POINTS);
// iterate through u, v segments
for(var u = 0; u < uSegments; u++){
var phi = PI * (u + 1) / uSegments;
for(var v = 0; v < vSegments; v++){
var theta = TWO_PI * v / vSegments;
// for each sperical coordinate (lat, lon angles, radius)
// convert to cartesian (x, y, z)
var x = radius * cos(theta) * sin(phi);
var y = radius * sin(theta) * sin(phi);
var z = radius * cos(phi);
// render each point
vertex(x, y, z);
}
}
endShape();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.1/p5.min.js"></script>
Update Turns out p5.Vector.fromAngles() does this for you.
e.g.
// iterate through u, v segments
for(var u = 0; u < uSegments; u++){
var phi = PI * (u + 1) / uSegments;
for(var v = 0; v < vSegments; v++){
var theta = TWO_PI * v / vSegments;
// for each sperical coordinate (lat, lon angles, radius)
// convert to cartesian (x, y, z)
let p = p5.Vector.fromAngles(phi, theta, radius);
// render each point
vertex(p.x, p.y, p.z);
}
}
The above isn't great because it's allocating a new p5.Vector on each call (not recommended in draw()), but hopefully the idea is illustrated and you can pre-calculate the points in setup() then simply render in draw()
I have an array of items that I would like to place on concentric circles. See diagram. I am having trouble with the math.
I can calculate the "steps" variable (each item is 40x40 so the steps are the circumference divided by the width plus margin). And I can calculate the points given the radius and the steps, but I don't know how to calculate the radius as a function of the current item index.
for(var i = 0; i < items.length; i++) {
var radius = functionOf(i)??;
var steps = Math.floor((2*radius*Math.PI)/60);
var x = Math.floor(0 + radius * Math.cos(2 * Math.PI * index / steps));
var y = Math.floor(0 + radius * Math.sin(2 * Math.PI * index / steps));
//draw item at x,y
}
Thoughts on how to calculate radius as a function of i?
You can calculate radius for every item using sum of arithmetic progression (for equidistant circles number of items form that progression), but there is simpler and faster approach - change radius after circle filling (pseudocode)
var radius = 0;
var i = 0;
while (i < items.length) {
var steps = Math.floor((2*radius*Math.PI)/60);
for(var index = 0; index < steps; index++) {
var x = Math.floor(0 + radius * Math.cos(2 * Math.PI * index / steps));
var y = Math.floor(0 + radius * Math.sin(2 * Math.PI * index / steps));
//draw item at x,y
i++;
if (i == items.length)
break;
}
radius = radius + 60; //start next circle
}
About arithmetic progression:
for progression with the first item a0 and difference d the sum of first n members is
S = n * (2 * a0 + d * (n - 1)) / 2
so to find what circle some index S belongs to, we have to solve quadratic inequality (find max integer x to fulfill the condition)
x^2 * d + x * (2 * a0 - d) - 2 * S <= 0
checked solution in Delphi:
function GetCircle(a0, d, i: Integer): Integer;
var
Discr: Double;
begin
Discr := (2 * a0 - d) * (2 * a0 - d) + 8 * i * d;
if Discr < 0 then
Exit(0);
Result := Floor((d - 2 * a0 + Sqrt(Discr)) / (2 * d));
end;
for case a0=1, d=6 (your picture differs a bit - progression is not exact) it gives
i=0: 0
i=1..7: 1
i=8..20: 2
i=21..39: 3
and so on
This means:
0th item is at the circle with radius 0
3rd item at the circle with radius 1 * R
11th item at the circle with radius 2 * R
...
Given your sample image, an easy approach is to add 6 elements for every outer circle, so that we have the sequence: 1, 6, 12, 18...
Then the radius of each circle can be enlarged by a constant amount, bigger then the element size:
// center of the circles
var centerx = 350;
var centery = 350;
// start drawing the central (first) element
if ( items.length > 0 ) {
// draw item at centerx, centery
}
var k = 1;
var i = 1;
while ( i < items.length ) {
// number of elements on this circle
var steps = k * 6;
// angular distance between elements
var angle_range = 2 * Math.PI / steps;
// every circle is bigger then the previuos of the same amount
var radius = k * 60;
var j = 0;
while ( j < steps && i < items.length ) {
var angle = j * angle_range;
var x = Math.round(centerx + radius * Math.cos(angle));
var y = Math.round(centery + radius * Math.sin(angle));
//draw item at x,y
i++;
j++;
}
k++;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<title>Circles</title>
<link href="stile.css"/>
</head>
<body>
<canvas id="myCanvas" width="700" height="700" style="border:1px solid #000000;">
</canvas>
<script>
// dummy draw function
function draw_item( itm, cntx, x, y) {
cntx.fillStyle = "#0022FF";
cntx.fillRect(x - 20, y - 20, 40, 40);
cntx.font = "14px Arial";
cntx.fillStyle = "#FFFFFF";
cntx.fillText(itm, x - 7, y + 5);
}
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
// dummy array
var items = [];
for ( var i = 0; i < 91; i++ ) {
items.push(i);
}
// center of the circles
var centerx = 350;
var centery = 350;
// start drawing the central (first) element
if ( items.length > 0 ) {
draw_item(items[0], ctx, centerx, centery);
}
var k = 1;
var i = 1;
while ( i < items.length ) {
// number of elements on this circle
var steps = k * 6;
// angular distance between elements
var angle_range = 2 * Math.PI / steps;
// every circle is bigger then the previuos of the same amount
var radius = k * 60;
var j = 0;
while ( j < steps && i < items.length ) {
var angle = j * angle_range;
var x = Math.round(centerx + radius * Math.cos(angle));
var y = Math.round(centery + radius * Math.sin(angle));
//draw item at x,y
draw_item(items[i], ctx, x, y);
i++;
j++;
}
k++;
}
</script>
</body>
</html>
I'm looking for a function to arrange some elements around a circle.
result should be something like :
Here's some code that should help you:
var numElements = 4,
angle = 0
step = (2*Math.PI) / numElements;
for(var i = 0; i < numElements.length; i++) {
var x = container_width/2 + radius * Math.cos(angle);
var y = container_height/2 + radius * Math.sin(angle);
angle += step;
}
It is not complete but should give you a good start.
Update: Here's something that actually works:
var radius = 200; // radius of the circle
var fields = $('.field'),
container = $('#container'),
width = container.width(),
height = container.height(),
angle = 0,
step = (2*Math.PI) / fields.length;
fields.each(function() {
var x = Math.round(width/2 + radius * Math.cos(angle) - $(this).width()/2),
y = Math.round(height/2 + radius * Math.sin(angle) - $(this).height()/2);
$(this).css({
left: x + 'px',
top: y + 'px'
});
angle += step;
});
Demo: http://jsfiddle.net/ThiefMaster/LPh33/
Here's an improved version where you can change the element count.
For an element around a centre at (x, y), distance r, the element's centre should be positioned at:
(x + r cos(2kπ/n), y + r sin(2kπ/n))
where n is the number of elements, and k is the "number" of the element you're currently positioning (between 1 and n inclusive).
I've combined ThiefMaster's fiddle with the jQuery pointAt plugin:
Demo: http://jsfiddle.net/BananaAcid/nytN6/
the code is somewhat like above.
might be interesting to some of you.
Arrange Elements In Circle (Javascript)
function arrangeElementsInCircle (elements, x, y, r) {
for (var i = 0; i < elements.length; i++) {
elements[i].scaleX = 1 / elements.length
elements[i].scaleY = 1 / elements.length
elements[i].x = (x + r * Math.cos((2 * Math.PI) * i/elements.length))
elements[i].y = (y + r * Math.sin((2 * Math.PI) * i/store.length))
}
}
Where x,y is point co-ordinates and elements is array of elements to be placed and r is radius.
Javascript only version of thiefmaster's answer
function distributeFields(deg){
deg = deg || 0;
var radius = 200;
var fields = document.querySelectorAll('.field'), //using queryselector instead of $ to select items
container = document.querySelector('#container'),
width = container.offsetWidth, //offsetWidth gives the width of the container
height = container.offsetHeight,
angle = deg || Math.PI * 3.5,
step = (2 * Math.PI) / fields.length;
console.log(width, height)
//using forEach loop on a NodeList instead of a Jquery .each,
//so we can now use "field" as an iterator instead of $(this)
fields.forEach((field)=>{
var x = Math.round(width / 2 + radius * Math.cos(angle) - field.offsetWidth/2);
var y = Math.round(height / 2 + radius * Math.sin(angle) - field.offsetHeight/2);
console.log(x, y)
field.style.left = x + 'px'; //adding inline style to the document (field)
field.style.top= y + 'px';
angle += step;
})
}
distributeFields();
I want to plot a range of points on the lower left section (6 to 9 o'clock) of the perimeter of a circle. However, the starting point of rendering X,Y coordinates always begins at 3 o'clock.
!https://dl.dropboxusercontent.com/u/55849501/plotting-xy.png
Here is the rendering portion of my code:
var items = 5;
for(var i = 0; i < items; i++) {
var x = 96 + 100 * Math.cos(0.665 * Math.PI * i / items);
var y = 96 + 100 * Math.sin(0.665 * Math.PI * i / items);
$("#center").append("<div class='point' style='left:"+ x +"px;top:"+ y +"px'></div>");
}
And here is a jsfiddle of the code in action: http://jsfiddle.net/jE26S/198/
In summary:
I want the points to render starting at the 6 o'clock position instead of the 3 o'clock position.
What you are really doing here is interpolating between two values of theta. In your case, you want to start at Pi/2 and end at Pi. I took the liberty of re-writing your snippet using this interpolation paradigm. Also, you can adjust how far you want the dots/items away from the circle using outerCircleRadius.
var items = 5;
var startTheta = .5 * Math.PI;
var endTheta = 1 * Math.PI;
var outerCircleRadius = 112;
var cx = 90;
var cy = 90;
for(var i = 0; i < items; i++) {
var theta = startTheta + (endTheta - startTheta) * i / (items - 1)
var x = cx + outerCircleRadius * Math.cos(theta);
var y = cy + outerCircleRadius * Math.sin(theta);
$("#center").append("<div class='point' style='left:"+ x +"px;top:"+ y +"px'></div>");
}
Something like this?
var x = 86 + 100 * Math.cos(0.665 * Math.PI * (items-1+i-0.5) / items);
var y = 96 + 100 * Math.sin(0.665 * Math.PI * (items-1+i-0.5) / items);
Everything in Richard Shurtz's answer, except for the "items - 1" in the first line in the loop.
This worked for any number of items:
var items = 5;
var startTheta = .5 * Math.PI;
var endTheta = 1 * Math.PI;
var outerCircleRadius = 112;
var cx = 90;
var cy = 90;
for(var i = 0; i < items; i++) {
var theta = startTheta + (endTheta - startTheta) * i / items
var x = cx + outerCircleRadius * Math.cos(theta);
var y = cy + outerCircleRadius * Math.sin(theta);
$("#center").append("<div class='point' style='left:"+ x +"px;top:"+ y +"px'></div>");
}
I'm creating a Canvas animation, and have managed to position x number of circles in a circular path. Here's a simplified version of the code I'm using:
var total = circles.length,
i = 0,
radius = 500,
angle = 0,
step = (2*Math.PI) / total;
for( i; i < total; i++ ) {
var circle = circles[i].children[0],
cRadius = circle[i].r,
x = Math.round(winWidth/2 + radius * Math.cos( angle ) - cRadius),
y = Math.round(winHeight/2 + radius * Math.sin( angle ) - cRadius);
circle.x = x;
circle.y = y;
angle += step;
}
Which results in this:
What I am trying to achieve is for all the circles to be next to each other with no gap between them (except the first and last). The circles sizes (radius) are generated randomly and shouldn't adjust to fit the circular path:
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
I expect there to be a gap between the first and last circle.
I'm struggling to get my head around this so any help would be much appreciated :)
Cheers!
Main creation loop :
• take a current radius
• compute the angles it cover ( = atan2(smallRadius/bigRadius) )
• move base angle by this latest angle.
http://jsfiddle.net/dj2v7mbw/9/
function CircledCircle(x, y, radius, margin, subCircleCount, subRadiusMin, subRadiusMax) {
this.x = x;
this.y = y;
this.radius = radius;
this.subCircleCount = subCircleCount;
var circles = this.circles = [];
// build top sub-circles
var halfCount = Math.floor(subCircleCount / 2);
var totalAngle = addCircles(halfCount);
// re-center top circles
var correction = totalAngle / 2 + Math.PI / 2;
for (var i = 0; i < halfCount; i++) this.circles[i].angle -= correction;
// build bottom sub-circles
totalAngle = addCircles(subCircleCount - halfCount);
// re-center bottom circles
var correction = totalAngle / 2 - Math.PI / 2;
for (var i = halfCount; i < subCircleCount; i++) this.circles[i].angle -= correction;
// -- draw this C
this.draw = function (angleShift) {
for (var i = 0; i < this.circles.length; i++) drawDistantCircle(this.circles[i], angleShift);
}
//
function drawDistantCircle(c, angleShift) {
angleShift = angleShift || 0;
var thisX = x + radius * Math.cos(c.angle + angleShift);
var thisY = y + radius * Math.sin(c.angle + angleShift);
ctx.beginPath();
ctx.arc(thisX, thisY, c.r, 0, 2 * Math.PI);
ctx.fillStyle = 'hsl(' + (c.index * 15) + ',75%, 75%)';
ctx.fill();
ctx.stroke();
}
//
function addCircles(cnt) {
var currAngle = 0;
for (var i = 0; i < cnt; i++) {
var thisRadius = getRandomInt(subRadiusMin, subRadiusMax);
var thisAngle = Math.atan2(2 * thisRadius + margin, radius);
var thisCircle = new subCircle(thisRadius, currAngle + thisAngle / 2, i);
currAngle += thisAngle;
circles.push(thisCircle);
}
return currAngle;
}
}
with
function subCircle(radius, angle, index) {
this.r = radius;
this.angle = angle;
this.index = index;
}
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
use with
var myCircles = new CircledCircle(winWidth / 2, winHeight / 2, 350, 2, 24, 5, 50);
myCircles.draw();
animate with :
var angleShift = 0;
function draw() {
requestAnimationFrame(draw);
ctx.clearRect(0, 0, winWidth, winHeight);
myCircles.draw(angleShift);
angleShift += 0.010;
}
draw();
It's something like this, but you're gonna have to figure out the last circle's size:
http://jsfiddle.net/rudiedirkx/ufvf62yf/2/
The main logic:
var firstStep = 0, rad = 0, step = 0;
firstStep = step = stepSize();
for ( var i=0; i<30; i++ ) {
draw.radCircle(rad, step);
rad += step;
step = stepSize();
rad += step;
}
stepSize() creates a random rad between Math.PI/48 and Math.PI/48 + Math.PI/36 (no special reason, but it looked good). You can fix that to be the right sizes.
draw.radCircle(rad, step) creates a circle at position rad of size step (also in rad).
step is added twice per iteration: once to step from current circle's center to its edge and once to find the next circle's center
firstStep is important because you have to know where to stop drawing (because the first circle crosses into negative angle)
I haven't figured out how to make the last circle the perfect size yet =)
There's also a bit of magic in draw.radCircle():
var r = rRad * Math.PI/3 * 200 * .95;
The 200 is obviously the big circle's radius
The 95% is because the circle's edge length is slightly longer than the (straight) radius of every circle
I have no idea why Math.PI/3 is that... I figured it had to be Math.PI/2, which is 1 rad, but that didn't work at all. 1/3 for some reason does..... Explain that!
If you want to animate these circle sizes and keep them aligned, you'll have a hard time. They're all random now. In an animation, only the very first iteration can be random, and the rest is a big mess of cache and math =)