I am trying to draw some ellipses like if they were in the perimeter of an imaginary circle.I have done my logic, I do not see where it fails. Basically what I do is move the starting point where I want, then get locations using trigonometry, given that the angle and the hypotenuse are kwown. See the code:
// Curve for 5 number
translate(width/6*3-30, width/6*4);
for(int alpha = 0; alpha < 120; alpha = alpha +5){
int radius = (int)random(30)+20;
int xpos = (int)cos(alpha)*350; int ypos= (int)sin(alpha)*350;
ellipse(xpos,ypos,radius,radius);}
}
cos() and sin() are expecting radians. Try sin(radians(alpha))
Also perhaps you should make xpos and ypos floats...
Related
I'm using Wikipedia's spherical coordinate system article to create a sphere made out of particles in Three.js. Based on this article, I created a small Polarizer class that takes in polar coordinates with setPolar(rho, theta, phi) and it returns its corresponding x, y, z
Here's the setPolar() function:
// Rho: radius
// theta θ: polar angle on Y axis
// phi φ: azimuthal angle on Z axis
Polarizer.prototype.setPolar = function(rho, theta, phi){
// Limit values to zero
this.rho = Math.max(0, rho);
this.theta = Math.max(0, theta);
this.phi = Math.max(0, phi);
// Calculate x,y,z
this.x = this.rho * Math.sin(this.theta) * Math.sin(this.phi);
this.y = this.rho * Math.cos(this.theta);
this.z = this.rho * Math.sin(this.theta) * Math.cos(this.phi);
return this;
}
I'm using it to position my particles as follows:
var tempPolarizer = new Polarizer();
for(var i = 0; i < geometry.vertices.length; i++){
tempPolarizer.setPolar(
50, // Radius of 50
Math.random() * Math.PI, // Theta ranges from 0 - PI
Math.random() * 2 * Math.PI // Phi ranges from 0 - 2PI
);
// Set new vertex positions
geometry.vertices[i].set(
tempPolarizer.x,
tempPolarizer.y,
tempPolarizer.z
);
}
It works wonderfully, except that I'm getting high particle densities, or "pinching" at the poles:
I'm stumped as to how to avoid this from happening. I thought of passing a weighted random number to the latitude, but I'm hoping to animate the particles without the longitude also slowing down and bunching up at the poles.
Is there a different formula to generate a sphere where the poles don't get as much weight? Should I be using quaternions instead?
For random uniform sampling
use random point in unit cube , handle it as vector and set its length to radius of your sphere. For example something like this in C++:
x = 2.0*Random()-1.0;
y = 2.0*Random()-1.0;
z = 2.0*Random()-1.0;
m=r/sqrt(x*x+y*y+z*z);
x*=m;
y*=m;
z*=m;
where Random return number in <0.0,1.0>. For more info see:
Procedural generation of stars with skybox
For uniform non-random sampling
see related QAs:
Sphere triangulation by mesh subdivision
Make a sphere with equidistant vertices
In order to avoid high density at the poles, I had to lower the likelihood of theta (latitude) landing close to 0 and PI. My input of
Math.random() * Math.PI, for theta gives an equal likelihood to all values (orange).
Math.acos((Math.random() * 2) - 1) perfectly weights the output to make 0 and PI less likely along the sphere's surface (yellow)
Now I can't even tell where the poles are!
I wanna to produce a Pie Chart on a Hexagon. There are probably several solutions for this. In the picture are my Hexagon and two Ideas:
My Hexagon (6 vertices, 4 faces)
How it should look at the end (without the gray lines)
Math: Can I get some informations from the object to dynamically calculate new vertices (from the center to each point) to add colored faces?
Clipping: On a sphere a Pie-Chart is easy, maybe I can clip the THREE Object (WITHOUT SVG.js!) so I just see the Hexagon with the clipped Chart?
Well the whole clipping thing in three.js is already solved here : Object Overflow Clipping Three JS, with a fiddle that shows it works and all.
So I'll go for the "vertices" option, or rather, a function that, given a list of values gives back a list of polygons, one for each value, that are portions of the hexagon, such that
they all have the centre point as a vertex
the angle they have at that point is proportional to the value
they form a partition the hexagon
Let us suppose the hexagon is inscribed in a circle of radius R, and defined by the vertices :
{(R sqrt(3)/2, R/2), (0,R), (-R sqrt(3)/2, R/2), (-R sqrt(3)/2, -R/2), (0,-R), (R sqrt(3)/2, -R/2)}
This comes easily from the values cos(Pi/6), sin(Pi/6) and various symmetries.
Getting the angles at the centre for each polygon is pretty simple, since it is the same as for a circle. Now we need to know the position of the points that are on the hexagon.
Note that if you use the symmetries of the coordinate axes, there are only two cases : [0,Pi/6] and [Pi/6,Pi/2], and you then get your result by mirroring. If you use the rotational symmetry by Pi/3, you only have one case : [-Pi/6,Pi/6], and you get the result by rotation.
Using rotational symmetry
Thus for every point, you can consider it's angle to be between [-Pi/6,Pi/6]. Any point on the hexagon in that part has x=R sqrt(3)/2, which simplifies the problem a lot : we only have to find it's y value.
Now we assumed that we know the polar coordinate angle for our point, since it is the same as for a circle. Let us call it beta, and alpha its value in [-Pi/6,Pi/6] (modulo Pi/3). We don't know at what distance d it is from the centre, and thus we have the following system :
Which is trivially solved since cos is never 0 in the range [-Pi/6,Pi/6].
Thus d=R sqrt(3)/( 2 cos(alpha) ), and y=d sin(alpha)
So now we know
the angle from the centre beta
it's distance d from the centre, thanks to rotational symmetry
So our point is (d cos(beta), d sin(beta))
Code
Yeah, I got curious, so I ended up coding it. Sorry if you wanted to play with it yourself. It's working, and pretty ugly in the end (at least with this dataset), see the jsfiddle : http://jsfiddle.net/vb7on8vo/5/
var R = 100;
var hexagon = [{x:R*Math.sqrt(3)/2, y:R/2}, {x:0, y:R}, {x:-R*Math.sqrt(3)/2, y:R/2}, {x:-R*Math.sqrt(3)/2, y:-R/2}, {x:0, y:-R}, {x:R*Math.sqrt(3)/2, y:-R/2}];
var hex_angles = [Math.PI / 6, Math.PI / 2, 5*Math.PI / 6, 7*Math.PI / 6, 3*Math.PI / 2, 11*Math.PI / 6];
function regions(values)
{
var i, total = 0, regions = [];
for(i=0; i<values.length; i++)
total += values[i];
// first (0 rad) and last (2Pi rad) points are always at x=R Math.sqrt(3)/2, y=0
var prev_point = {x:hexagon[0].x, y:0}, last_angle = 0;
for(i=0; i<values.length; i++)
{
var j, theta, p = [{x:0,y:0}, prev_point], beta = last_angle + values[i] * 2 * Math.PI / total;
for( j=0; j<hexagon.length; j++)
{
theta = hex_angles[j];
if( theta <= last_angle )
continue;
else if( theta >= beta )
break;
else
p.push( hexagon[j] );
}
var alpha = beta - (Math.PI * (j % 6) / 3); // segment 6 is segment 0
var d = hexagon[0].x / Math.cos(alpha);
var point = {x:d*Math.cos(beta), y:d*Math.sin(beta)};
p.push( point );
regions.push(p.slice(0));
last_angle = beta;
prev_point = {x:point.x, y:point.y};
}
return regions;
}
I would like to draw a textured circle in Direct3D which looks like a real 3D sphere. For this purpose, I took a texture of a billard ball and tried to write a pixel shader in HLSL, which maps it onto a simple pre-transformed quad in such a way that it looks like a 3-dimensional sphere (apart from the lighting, of course).
This is what I've got so far:
struct PS_INPUT
{
float2 Texture : TEXCOORD0;
};
struct PS_OUTPUT
{
float4 Color : COLOR0;
};
sampler2D Tex0;
// main function
PS_OUTPUT ps_main( PS_INPUT In )
{
// default color for points outside the sphere (alpha=0, i.e. invisible)
PS_OUTPUT Out;
Out.Color = float4(0, 0, 0, 0);
float pi = acos(-1);
// map texel coordinates to [-1, 1]
float x = 2.0 * (In.Texture.x - 0.5);
float y = 2.0 * (In.Texture.y - 0.5);
float r = sqrt(x * x + y * y);
// if the texel is not inside the sphere
if(r > 1.0f)
return Out;
// 3D position on the front half of the sphere
float p[3] = {x, y, sqrt(1 - x*x + y*y)};
// calculate UV mapping
float u = 0.5 + atan2(p[2], p[0]) / (2.0*pi);
float v = 0.5 - asin(p[1]) / pi;
// do some simple antialiasing
float alpha = saturate((1-r) * 32); // scale by half quad width
Out.Color = tex2D(Tex0, float2(u, v));
Out.Color.a = alpha;
return Out;
}
The texture coordinates of my quad range from 0 to 1, so I first map them to [-1, 1]. After that I followed the formula in this article to calculate the correct texture coordinates for the current point.
At first, the outcome looked ok, but I'd like to be able to rotate this illusion of a sphere arbitrarily. So I gradually increased u in the hope of rotating the sphere around the vertical axis. This is the result:
As you can see, the imprint of the ball looks unnaturally deformed when it reaches the edge. Can anyone see any reason for this? And additionally, how could I implement rotations around an arbitrary axis?
Thanks in advance!
I finally found the mistake by myself: The calculation of the z value which corresponds to the current point (x, y) on the front half of the sphere was wrong. It must of course be:
That's all, it works as exspected now. Furthermore, I figured out how to rotate the sphere. You just have to rotate the point p before calculating u and v by multiplying it with a 3D rotation matrix like this one for example.
The result looks like the following:
If anyone has any advice as to how I could smooth the texture a litte bit, please leave a comment.
I'm trying to write a spraypaint type program but I have forgotten all my maths.
I need some sort of probability equation to pick pixels near where the user clicks. So the probability should be high near the center and then decrease as the distance from the center gets higher and once you reach a certain distance the probability should be zero.
Also the probability at the center should be a smooth curve (if you know what I mean)
I'm not sure which language you're coding in, so here's some pseudo-code. I will assume you know the corresponding syntax in the language you're coding in.
// Parameters:
// Radius is the radius of the brush in pixels
// Strength is a double ranging 0.0 to 1.0 and multiplies the probability of a pixel being painted
function spraypaint(int radius, double strength) {
strength = (strength * 2) - 1; //Change strength from 0.0->1.0 to -1.0->1.0 for logical application
// For each pixel within the square...
for(int x = -radius; x < radius; x++) {
for(int y = -radius; y < radius; y++) {
double distance = sqrt(x*x + y*y); // Get distance from center pixel
double angle = 90*(distance/radius); // Get angle of "bell curve"
double probability = sine(angle); // Determine probability of filling in this pixel
// Apply additional probability based on strength parameter
if(strength >= 0.0)
probability += ((1-probability) * strength);
else
probability += probability * strength;
if(distance > radius) {
continue; // Skip this pixel if it's out of the circle's radius
}
if(random(0.0 to 1.0) < probability) { // If we random a decimal lower than our probability
setPixel(mouse.x + x, mouse.y + y, "Black"); // Draw this pixel
}
}
}
}
The basic idea is:
Iterate through each pixel and...
1. Find its distance from the center pixel (The clicked pixel).
2. Get distance/radius (0.0 to 1.0) and find the corresponding sine, creating a
smooth probability curve.
3. Apply the supplied strength to the probability.
4. Pull a random double 0.0 to 1.0 and draw the pixel if it's within our probability.
I have two vectors in a game. One vector is the player, one vector is an object. I also have a vector that specifies the direction the player if facing. The direction vector has no z part. It is a point that has a magnitude of 1 placed somewhere around the origin.
I want to calculate the angle between the direction the soldier is currently facing and the object, so I can correctly pan some audio (stereo only).
The diagram below describes my problem. I want to calculate the angle between the two dashed lines. One dashed line connects the player and the object, and the other is a line representing the direction the player is facing from the point the player is at.
At the moment, I am doing this (assume player, object and direction are all vectors with 3 points, x, y and z):
Vector3d v1 = direction;
Vector3d v2 = object - player;
v1.normalise();
v2.normalise();
float angle = acos(dotProduct(v1, v2));
But it seems to give me incorrect results. Any advice?
Test of code:
Vector3d soldier = Vector3d(1.f, 1.f, 0.f);
Vector3d object = Vector3d(1.f, -1.f, 0.f);
Vector3d dir = Vector3d(1.f, 0.f, 0.f);
Vector3d v1 = dir;
Vector3d v2 = object - soldier;
long steps = 360;
for (long step = 0; step < steps; step++) {
float rad = (float)step * (M_PI / 180.f);
v1.x = cosf(rad);
v1.y = sinf(rad);
v1.normalise();
float dx = dotProduct(v2, v1);
float dy = dotProduct(v2, soldier);
float vangle = atan2(dx, dy);
}
You shoud always use atan2 when computing angular deltas, and then normalize.
The reason is that for example acos is a function with domain -1...1; even normalizing if the input absolute value (because of approximations) gets bigger than 1 the function will fail even if it's clear that in such a case you would have liked an angle of 0 or PI instead. Also acos cannot measure the full range -PI..PI and you'd need to use explicitly sign tests to find the correct quadrant.
Instead atan2 only singularity is at (0, 0) (where of course it doesn't make sense to compute an angle) and its codomain is the full circle -PI...PI.
Here is an example in C++
// Absolute angle 1
double a1 = atan2(object.y - player.y, object.x - player.x);
// Absolute angle 2
double a2 = atan2(direction.y, direction.x);
// Relative angle
double rel_angle = a1 - a2;
// Normalize to -PI .. +PI
rel_angle -= floor((rel_angle + PI)/(2*PI)) * (2*PI) - PI;
In the case of a general 3d orientation you need two orthogonal directions, e.g. the vector of where the nose is pointing to and the vector to where your right ear is.
In that case the formulas are just slightly more complex, but simpler if you have the dot product handy:
// I'm assuming that '*' is defined as the dot product
// between two vectors: x1*x2 + y1*y2 + z1*z2
double dx = (object - player) * nose_direction;
double dy = (object - player) * right_ear_direction;
double angle = atan2(dx, dy); // Already in -PI ... PI range
In 3D space, you also need to compute the axis:
Vector3d axis = normalise(crossProduct(normalise(v1), normalise(v2)));