I'm having some problem with my program. what I want to implement is a way to understand a point(x,y) in which quadrant is located.
The concept of a quadrant that I'm trying to implement is the following:
I have a rectangle, from which I have the coordinates of all the angles and the edges. given another point in the space, in the 2D space, I would like to know where is located between top,bottom, left and right.
Thank you in advance.
EDIT:
so far I've wrote this piece of code:
Point A=t.src; //center point of the first square
Point B=t.dest; //center point of the second square
int destHeight=t.destDim.height;
int destWidth=t.destDim.width;
int m = destHeight/destWidth;
int b = B.y -(m*B.x);
int d = B.y +(m*B.x);
if(A.y >= m*A.x +b){
if(A.y >= -m*A.x+d){
System.err.println("2 - Source on BOTTOM");
}else{ //A.y < -m*A.x+d
System.err.println("2 - Source on LEFT");
}
}else if(A.y < m*A.x + b){
if(A.y>= -m*A.x +d){
System.err.println("2 - Source on RIGHT");
}else{ //A.y < m*A.x + d
System.err.println("2 - Source on TOP");
}
}
The problem is that I still don't have the expected result. This is what I get:
Video demo of the problem
as you can see from the output console, it never pronts out that the source is on the left, it just transitions from top to bottom.
Let rectangle is zero-centered and has edge length a (horizontal) and b. (If it is not zero-centered, just subtract center coordinates from point ones). Then lines have simple equations
m = b / a
y = m * x //L1
y = -m * x //L2
Point in top quadrant lies above both lines, point in right quadrant lies above L2 but below L1 and so on.
For point coordinates (px, py):
mpx = m * px
if (py >= mpx) :
if (py >= -mpx) :
top
else:
left
else:
if (py >= -mpx) :
right
else:
bottom
Related
I am trying to map all circle cordinates to a flat surface using OpenGL fragment shader as shown in the picture. I know the radius and center point of the circle. So I am trying to use the below equation:
For a circle with origin (j, k) and radius r:
x(t) = r cos(t) + j
y(t) = r sin(t) + k
where you need to run this equation for t taking values within the range from 0 to 360, then you will get your x and y each on the boundary of the circle.
But I am facing below problem:
Angle values are in degrees. Can I use that directly in the fragment shader code as the OpenGL cordinates are from 0.0 to 1.0?
There are many approaches to map circle points to square and vice versa. For simplicity circle center is (0,0) and radius is 1.
Let coordinate in square are (x,y) and corresponding coordinate in circle is (u, v).
So to get circle point:
u = x * sqrt(1 - y^2/2)
v = y * sqrt(1 - x^2/2)
Inverse formula is more complex:
x = (sqrt(2 + u*u-v*v+2*u*sqrt(2)) - sqrt(2 + u*u-v*v - 2*u*sqrt(2))) / 2
y = (sqrt(2 - u*u+v*v+2*v*sqrt(2)) - sqrt(2 - u*u+v*v - 2*v*sqrt(2))) / 2
Note that you perhaps want to get point at the circle corresponding to needed square point, so need only the first formula pair
P.S. Perhaps I took formulas there years ago
If you need to walk through circle points with some step (while I doubt you really need this), you can scan Y-coordinates and get scanlines for X coordinates. Pseudocode:
for y = - R to R step d:
L = sqrt(R*R-y*y)
for x = -L to L step d:
getPoint(cx + x, cy + y)
I am trying to generate random points on a sphere that is filled with a cube.
Because I had no idea how to do that i started with 2d. (A circle filled with a quadrat.)
What I am trying to do: Generating random points inside the outer circle, but outside the green square.
Basically in the blue areas.
The square is located at (-1|-1),(1|-1),(1|1),(-1|1).
The circle has a radius of r = sqrt(2) and is centered at (0|0).
I already have scripts to:
generate a random point on a circle (uniformly):
float a = 2 * MathUtils.PI * MathUtils.random(1f); // angle between 0 and 2pi
float r = radius * Math.sqrt(MathUtils.random(0, 1f)
float x = r * MathUtils.cos(a);
float y = r * MathUtils.sin(a);
calculating the radius for a given angle to form a square:
float r = (1/Math.sqrt(2)) / MathUtils.cos(((a+45)%90-45)/180*MathUtils.PI);
with (1/Math.sqrt(2)) being half the side length of the square
Before anyone asks:
I know that I could just re-generate points which are inside the green square until I get one that is outside, but I don't want to do it this way.
I appreciate any help. Thank you :)
It is rather hard to generate points only in region of sphere outside the cube (caps and wedges), so rejecting method looks reasonable.
But you can diminish the number of useless points, generating points in the ring only in 2D case and in spherical shell in 3D case.
So pseudocode might look as
//2d
SquaredR = RandomUniformInRange(0.5, 1)
R = Sqrt(SquaredR)
//3d
CubedR = RandomUniformInRange(Pow(3, -3/2), 1)
R = Pow(CubedR, 1/3)
//generate point on the circle or on the sphere with radius R
if Abs(x) > Sqrt(2)/2 or Sqrt(3)/3 and so on - reject
Having R, you can generate point on the sphere using any approach from here
Here is rough sketch of the idea. You select one quadrant to sample, say, one on the right.
First, sample angles from -pi/4 to pi/4
float a = -MathUtils.PI/4.0f + MathUtils.PI/2.0 * MathUtils.random(0.f,1.f);
float c = MathUtils.cos(a);
float s = MathUtils.sin(a);
Second, find minimum radius. With ray going from (0,0) at angle a will intersect quadrant line at x=1 at minimum
float rmin = 1.0f / c;
float rmax = Math.sqrt(2.0f);
Sample from rmin to rmax = sqrt(2), taking into account that for plane you sample squared radius and then use sqrt(), and for 3d space you sample cubed radius and then use cbrt().
float r2 = rmin*rmin + (rmax*rmax-rmin*rmin)*MathUtils.random(0.f,1.f);
float r = Math.sqrt(r);
float x = r * c;
float y = r * s;
Now, we constructed (x,y) is a such way it is guaranteed to be in the right quadrant below circle and on the right of the x=1 line.
To cover all four quadrants just sample to which quadrant you will move the point
float q = MathUtils.random(0.f,1.f);
if (q < 0.25f) // top quadrant
return (y, x);
if (q < 0.5f) // left quadrant
return (-x, y);
if (q < 0.75f) // bottom quadrant
return (y, -x);
return (x,y); // right quadrant
Please bear with me - my Java is quite rusty, and I have no ways to test the code.
In 3D case you'll have to deal with two angles, cubed radius, eight octants instead of four quadrants, but general logic is the same
UPDATE
I was wrong, sampling like I propose would lead to non-uniform point distribution.
From PDF:
PDF(phi, r) = S_(-\pi/4)^\phi d\phi S_1/cos(\phi)^\sqrt(2) r dr
One could get that we have to make \phi sampling non-uniform. Unfortunately, from
U(0,1) to get to sampled \phi requires solving non-linear equation
\pi/2 (0.5*(\phi/\pi/4 + 1) - U(0,1)) = 0.5*(tan(phi) + 1) - U(0,1)
So algorithm would be:
Sample U(0,1)
Find appropriate \phi by solving equation above
Find lower R boundary
Sample R
Quick code (in Python, sorry) to plot this non-linear function
import numpy as np
import matplotlib.pyplot as plt
def f(phi, ksi):
c = 0.5 * np.pi
c_2 = 0.5 * c
left = c * (0.5 * (phi/c_2 + 1.0) - ksi)
rght = (0.5 * (np.tan(phi) + 1.0) - ksi)
return left - rght
nof_points = 41
phi = np.linspace(-0.25*np.pi, 0.25*np.pi, nof_points)
y0_00 = f(phi, 0.00)
y0_25 = f(phi, 0.25)
y0_50 = f(phi, 0.50)
y0_75 = f(phi, 0.75)
y0_99 = f(phi, 1.00)
plt.plot(phi, y0_00, 'ro', phi, y0_25, 'b+', phi, y0_50, 'gx', phi, y0_75, 'm.', phi, y0_99, 'y^')
plt.show()
and plotted functions for five values of U(0,1) (ksi in the code)
Sampling could be rearranged such that r sampling is non-linear, but it exhibits the same problem - need to solve non-linear equation with polynomial and trigonometric parts
UPDATE II
And just for the record, if you want to sample r first, then it has to be sampled from the solution of the non-linear equation:
r2 sec-1(r) - sqrt(r2 - 1) = U(0,1)*(\pi/2 - 1)
in the interval [1...sqrt(2)]
After solving it and finding sampled r, \phi could be sampled uniformly in the interval allowed by r: [-cos-1(1/r) ... +cos-1(1/r)]
I have a rectangle which when I hold down the mouse button I want that rectangle to move to that point following a strait line 1 pixel at a time.
This is my code so far (I put comments in it so you can understand)
float distanceX = finalX - x; //the number of pixels needed to get to destination on the X axis
float distanceY = finalY - y; // same as above but Y axis
float moveX = distanceX > 0 ? 1 : -1; // I only want it to move 1 pixel per render
float moveY = distanceY > 0 ? 1 : -1; // same as above
Array<Stuff> collidedX = new Array<Stuff>(); //saves collisions seperately for x and y
Array<Stuff> collidedY = new Array<Stuff>(); //because I want the square to move where the mouse is pointing even if it means only aligning one axis
for (Stuff s : collidables) {
if (overlapsT(s, x + moveX, y)) {
collidedX.add(s);
}
}
if (collidedX.size < 1) {
if (distanceX != 0)
x += moveX;
}
for (Stuff s : collidables) {
if (overlapsT(s, x, y + moveY)) {
collidedY.add(s);
}
}
if (collidedY.size < 1) {
if (distanceY != 0)
y += moveY;
}
right now the problem is it goes perfectly diagonal until it lines up with one of the axis and then moves up down left or right to the destination.
I don't want to move fractions of pixels. The way my custom physics engine works is each pixel matters, fractional pixels are no good so I am trying to figure out how to smooth the path or rather how to decide when to add 1 to x and then y.
Currently I can't comment, so I have to answer. I think the Bresenham's line algorithm will help you out. It's for drawing rasterize lines.
Bresenham
I've been thinking on some fast and brilliant pixel - perfect collision detection between a circle and any sprite. I need to get 2 points of collision to be able to calculate a normal vector out of them later. I managed to come up with some solution but the more scaling is done in my game, the more inaccurate and unprecise this collision is...It seems as if the code I posted below, was good and correct becouse I have been checking it already a few times and spent a few days reading it again and again... I also checked visually that the collision masks and areas of collision are calculated perfectly fine in the code below so the problem definitely doesn't lay there but in this method.
So I guess that the problem here is the loss of data in floating point arithmetic unless somebody finds a flaw in this method?
If however the problem is really with the float loss of data, what other solution would you recommend to find 2 points of collision between circle and any other sprite in pixel perfect? I really liked my solution becouse it was relatively fast
int xOffset1 = (int)colRectLeft; // left boundary of the collision area for the first sprite
int xOffset2 = (int)colCircleLeft; // left boundary of the collision area for the circle sprite
int yOffset1 = (int)colRectBottom; // bottom boundary of the collision area for the first sprite
int yOffset2 = (int)colCircleBottom; // bottom boundary of the collision area for the circle sprite
int width = (int)(colCircleRight - colCircleLeft); //width of the collision area - same for both sprites
int height = (int)(colCircleTop - colCircleBottom); // height of the collision area same for both sprites
// Pixel-perfect COLLISION DETECTION between circle and a sprite
// my custom vector classes - nothing special
Math2D.Vector_2 colRightPoint = new Math2D.Vector_2(-1, -1); // The right point of collision lying on the circle's circumference
Math2D.Vector_2 colLeftPoint = new Math2D.Vector_2(-1, -1); // the left point of collision lying on the circle's circumference
boolean colRightFound = false;
boolean colLeftFound = false;
// I'm going through y in the circle's area of collision
for (float y = yOffset2; y < yOffset2 + height; y += 1)
{
// from equation: (x-Sx)^2 + (y-Sy)^2 = r^2
// x1/2 = (+-)sqrt(r^2 - (y - Sy)^2) + Sx
//(Sx, Sy) is (circle's radius, circle's radius) becouse I want the points on the circle's circumference to have positive coordinates
float x1 = (float) (Math.sqrt(radius*radius - (y - radius)*(y - radius)) + radius); // the right pixel on the circumference
float x2 = (float) (-x1 + 2*radius); // the left pixel on the circumference
//first I check if the calculated x is inside of the previously calculated area of collision for both circle's area and a sprite's area
if (x1 >= xOffset2 &&
x1 <= xOffset2 + width &&
xOffset1 + x1 - xOffset2 < rectFrameW &&
yOffset1 + (int)y-yOffset2 < rectFrameH &&
yOffset1 + (int)y-yOffset2 > 0 &&
xOffset1 + x1 - xOffset2 > 0)
{
//I don't have to check if the point on the circle's circumference is opaque becouse it's always so just check if the same point translated to sprite's area of collision is opaque
boolean opaqueRectPixel = go.gameData.images.get(go.pic_nr)
.collision_mask[(int)((yOffset1 + (int)y-yOffset2)*rectFrameW +
(xOffset1 + x1 - xOffset2))];
if(opaqueRectPixel)
{
if(!colRightFound)
{
colRightPoint.x = (xOffset1 + x1 - xOffset2);
colRightPoint.y = (yOffset1 + (int)y - yOffset2);
colRightFound = true;
}
else if(!colLeftFound)
{
colLeftPoint.x = (xOffset1 + x1 - xOffset2);
colLeftPoint.y = (yOffset1 + (int)y - yOffset2);
}
}
}
//the same logic for the left point on the circle's circumference
if (x2 >= xOffset2 &&
x2 <= xOffset2 + width &&
xOffset1 + x2 - xOffset2 < rectFrameW &&
yOffset1 + (int)y-yOffset2 < rectFrameH &&
yOffset1 + (int)y-yOffset2 > 0 &&
xOffset1 + x2 - xOffset2 > 0)
{
boolean opaqueRectPixel = go.gameData.images.get(go.pic_nr)
.collision_mask[(int)((yOffset1 + (int)y-yOffset2)*rectFrameW +
(xOffset1 + x2 - xOffset2))];
if(opaqueRectPixel)
{
if(!colLeftFound)
{
colLeftPoint.x = (xOffset1 + x2 - xOffset2);
colLeftPoint.y = (yOffset1 + (int)y - yOffset2);
colLeftFound = true;
}
else if(!colRightFound)
{
colRightPoint.x = (xOffset1 + x2 - xOffset2);
colRightPoint.y = (yOffset1 + (int)y - yOffset2);
}
}
}
// if both points are already found, finish
if(colLeftFound && colRightFound)
break;
}
edit: Actually, what I'm doing in this method is finding points of intersection between circle and a sprite
edit: Ok, I'm uploading images to describe my algorithm a bit better. I really tried my best to explain it but if there's still something missing, let me know please!
Also I would accept any other good solutions to find intersection points between a circle and any sprite in pixel perfect, if you don't want to check my code :(... Eh, I'm always having problems with collisions...
If you absolutely want (or need) pixel perfect, your solution looks good.
don't forget to first make a rectangle-to-rectangle collision before testing a pixel perfect detection, to avoid unneeded processings.
If you want another accurate method which maybe more efficient, look for Separating Axis Theorem.
You can find more information about it here :
http://rocketmandevelopment.com/blog/separation-of-axis-theorem-for-collision-detection/
and here :
http://www.metanetsoftware.com/technique/tutorialA.html
The last one have nice interactive explanation and demonstration. Enjoy :)
...as I was not able to show the raster in the comments:
I did not mentally parse your code, however from the image I see that you try to detect borderline collisions. Putting round or diagonal (border)lines into a raster may cause occasions, where two crossing lines do not overlay each other - like this:
1 2
2 1
whereby 1 would be line 1 and 2 would be line 2.
However I still like the idea of checking border lines combined with rectangle pre-checks. If you would render an array of raster proved-closed line coordinates by sprites you could check them against each other. This could also be enriched by border line segmenting (such as North, East, West and South or a bit more fine grain - I guess there is an optimum). A diagonal proved-closed line in the check data set must represent something like this:
x _
x x
whereby the x represent the pixels of your line and the _ is an empty raster seat.
What is the logic that goes behind rotating an image via mouse movement. I know how to rotate using graphics2d.rotate...but having difficulty doing it with the mouse as the source for rotation. Here is basic steps:
get mouse x(dx) and mouse y(dy) distances from anchoring point( in this case that would be
the center of the image we want to rotate).
use this point in Math.arcTan2(dy,dx) to obtain the angle or rotation.
use the value from step to for Graphics2D.rotate method.
With that strategy, everytime i rotate the image, the image starts rotating from -pi and after 90 degrees of rotation it go goes back to -pi. I don't understand what I'm doing wrong here, it should be pretty basic.
Here is a part of the code :
// mouse dragged events get sent here.
public void mouseDragged( MouseEvent e ) {
int mx = e.getX( ), my = e.getY( );
// just checking if it falls within bounds of the image we
// want to rotate.
if( mx > speedKX || mx < speedKX + speedK.getWidth( ) || my > speedKY || my < speedKY + speedK.getHeight( )/2 )
{
theta += getTheta( e.getX( ), e.getY( ) );
}
}
As I understand you should look for the initial angle (when you clicked, the line between the anchor and your click) and the current angle (when you are dragging, same line). That angle (independent from the current distance to anchor point) will give you the rotation.
So you have to:
rotate(anglenow - angle0)
How to find it:
In both cases (initial click and mouse move event) you have to find angle between anchor and mouse point thinking the anchor as the origin.
I would use a method (getAngle(x1,y1,x2,y2). That method (except for race conditions like same x or same y, easily detectable) should calculate arctan(dy/dx).
Sign
But when you are dividing dy/dx it can be:
+ / + -> +
+ / - -> -
- / + -> -
- / - -> +
It is, four posibilities give you two kind of results. So, you have to look some condition to detect them.
I should review arctan doc or source to see what values it gives (between 0 and pi, or -pi/2 and +pi/2) and check then sign of the dx or the dy (depending on what range arctan returns) and use it to add/decrement pi to then resulting angle.
Then you'll get a getAngle method that return correctly the 360ยบ space.
Edit
Javadoc says:
Math.atan retuns the arc tangent of an angle, in the range of -pi/2 through pi/2.
So, assuming your angle of value 0 is for the X axis as I assumed, the range it returns is the right hemisphere. So you have to distiguish the right hemisphere from the left one.
If you calculate dx = xtarget - xorigin (as you did for the division) it will be positive if the correct hemisphere is the right one, and negative if it's not.
So if dy < 0 then you have to add pi to your resulting angle. It will be between -pi/2 and 3pi/2. You also can correct the result by passing all to (-pi,pi) range or (0,2pi) range.
Edit: pseudocode, please double check!
onmousedown {
startpoint = (x,y);
startangle = getAngle(origin, startpoint);
}
onmousemove {
currentpoint = (x,y);
currentangle = getAngle(origin, currentpoint);
originalimage.rotate(currentangle - startangle);
}
getAngle(origin, other) {
dy = other.y - origin.y;
dx = other.x - origin.x;
if (dx == 0) // special case
angle = dy >= 0? PI/2: -PI/2;
else
{
angle = Math.atan(dy/dx);
if (dx < 0) // hemisphere correction
angle += PI;
}
// all between 0 and 2PI
if (angle < 0) // between -PI/2 and 0
angle += 2*PI;
return angle;
}