I'm trying to maintain and then use a transformation matrix for a computer graphics program. It's a 3x3 matrix that stores scale, rotate, and translate information for (x,y) points.
My program can handle any individual case... i.e. if I only scale or only rotate it works fine. However, it does not seem to work when combining scale and rotate, and I think that has to do with how I combine rotation and scale in the code. The matrix is called transformation and is of type float. The following methods clear, rotate, scale, and translate (in that order) the matrix.
public void clearTransform()
{
transformation[0][0] = 1;transformation[0][1] = 0;transformation[0][2] = 0;
transformation[1][0] = 0;transformation[1][1] = 1;transformation[1][2] = 0;
transformation[2][0] = 0;transformation[2][1] = 0;transformation[2][2] = 1;
}
public void rotate (float degrees)
{
double r = degrees * (Math.PI/180);
float sin = (float)Math.sin(r);
float cos = (float)Math.cos(r);
transformation[0][0] *= cos;
transformation[1][1] *= cos;
if(transformation[0][1] == 0)
transformation[0][1] = -sin;
else
transformation[0][1] *= -sin;
if(transformation[1][0] == 0)
transformation[1][0] = sin;
else
transformation[1][0] *= sin;
}
public void scale (float x, float y)
{
transformation[0][0] *= x;
transformation[1][1] *= y;
}
public void translate (float x, float y)
{
transformation[0][2] += x;
transformation[1][2] += y;
}
For scale, the matrix hold info like this:
(Sx, 0, 0)
(0, Sy, 0)
(0, 0, 1)
for rotation, like this:
(cos(theta), -sin(theta), 0)
(sin(theta), cos(theta), 0)
(0, 0, 1)
for translation, this:
(1, 0, Tx)
(0, 1, Ty)
(0, 0, 1)
I don't think I'm correctly combining scale and rotate. Here is where I actually apply the transformation:
public float[] transformX(float[] x, float[] y, int n) {
float[] newX = new float[n];
for(int i = 0; i < n; i ++) {
newX[i] = (x[i] * transformation[0][0]) + (y[i] * transformation[0][1]) + transformation[0][2];
}
return newX;
}
public float[] transformY(float[] x, float[] y, int n) {
float[] newY = new float[n];
for(int i = 0; i < n; i ++) {
newY[i] = (x[i] * transformation[1][0]) + (y[i] * transformation[1][1]) + transformation[1][2];
}
return newY;
}
Where x and y are the pre-transformed point arrays, and n is the number of points
Thank you for any help!
I think the correct transformation should be:
Related
I'm trying to visualize Mandelbrot's set with processing, and it's the first time I do something like this. My approach is pretty simple.
I have a function Z, which is literally just the set's main function (f(z)=z^2+c) and i do a loop for each pixel of the screen, every time i repeat the process of using Z() and using the result as the new z parameter in the function Z()
For some reason what shows up on the screen is only a diagonal line, and i have no idea of why that is.
Here's the full code:
void draw() {
int max_iterations = 100, infinity_treshold = 16;
for (int y = 0; y < 360; y++) {
for (int x = 0; x < 480; x++) {
float z = 0; // the result of the function, (y)
float real = map(x,0,480,-2,2); // map "scales" the coordinate as if the pixel 0 was -2 and the pixel 480 was 2
float imaginary = map(y,0,360,-2,2); // same thing with the height
int func_iterations = 0; // how many times the process of the equation has been excecuted
while (func_iterations < max_iterations) {
z = Z(z, real+imaginary);
if (abs(z) > infinity_treshold) break;
func_iterations++;
}
if (func_iterations == max_iterations) rect(x,y,1,1);
}
}
noLoop();
}
private float Z(float z, float c) {
return pow(z,2)+c;
}
The formula z = z^2 +c is meant to operate with Complex numbers. I recommend to use PVector to represent a complex number. e.g.:
private PVector Z(PVector z, PVector c) {
return new PVector(z.x * z.x - z.y * z.y + c.x, 2.0 * z.x * z.y + c.y);
}
See the example:
void setup() {
size(400, 400);
}
void draw() {
background(255);
int max_iterations = 100;
float infinity_treshold = 16.0;
for (int y = 0; y < width; y++) {
for (int x = 0; x < height; x++) {
float real = map(x, 0, width, -2.5, 1.5);
float imaginary = map(y, 0, height, -2, 2);
PVector c = new PVector(real, imaginary);
PVector z = new PVector(0, 0);
int func_iterations = 0;
while (func_iterations < max_iterations) {
z = Z(z, c);
if (z.magSq() > infinity_treshold)
break;
func_iterations++;
}
if (func_iterations == max_iterations) {
point(x, y);
}
}
}
noLoop();
}
private PVector Z(PVector z, PVector c) {
return new PVector(z.x * z.x - z.y * z.y + c.x, 2.0 * z.x * z.y + c.y);
}
See also
wikipedia - Mandelbrot set
Mandelbrot.java
You've declared z as float so it's a real number, it should be complex. I'm not familiar with processing, does it even have a complex number data type?
Another problem is at Z(z, real+imaginary) Real and imaginary are both floats, so real numbers, so their sum is a real number. You need to construct a complex number from the real and imaginary parts.
I appear to have hit a wall in my most recent project involving wave/ripple generation over an image. I made one that works with basic colors on a grid that works perfectly; heck, I even added shades to the colors depending on the height of the wave.
However, my overall goal was to make this effect work over an image like you would see here. I was following an algorithm that people are calling the Hugo Elias method (though idk if he truly came up with the design). His tutorial can be found here!
When following that tutorial I found his pseudo code challenging to follow. I mean the concept for the most part makes sense until I hit the height map portion over an image. The problem being the x and y offsets throw an ArrayIndexOutOfBoundsException due to him adding the offset to the corresponding x or y. If the wave is too big (i.e. in my case 512) it throws an error; yet, if it is too small you can't see it.
Any ideas or fixes to my attempted implementation of his algorithm?
So I can't really make a compile-able version that is small and shows the issue, but I will give the three methods I'm using in the algorithm. Also keep in mind that the buffer1 and buffer2 are the height maps for the wave (current and previous) and imgArray is a bufferedImage represented by a int[img.getWidth() * img.getHeight()] full of ARGB values.
Anyways here you go:
public class WaveRippleAlgorithmOnImage extends JPanel implements Runnable, MouseListener, MouseMotionListener
{
private int[] buffer1;
private int[] buffer2;
private int[] imgArray;
private int[] movedImgArray;
private static double dampening = 0.96;
private BufferedImage img;
public WaveRippleAlgorithmOnImage(BufferedImage img)
{
this.img = img;
imgArray = new int[img.getHeight()*img.getWidth()];
movedImgArray = new int[img.getHeight()*img.getWidth()];
imgArray = img.getRGB(0, 0,
img.getWidth(), img.getHeight(),
null, 0, img.getWidth());
//OLD CODE
/*for(int y = 0; y < img.getHeight(); y++)
{
for(int x = 0; x < img.getWidth(); x++)
{
imgArray[y][x] = temp[0 + (y-0)*img.getWidth() + (x-0)];
}
}*/
buffer1 = new int[img.getHeight()*img.getWidth()];
buffer2 = new int[img.getHeight()*img.getWidth()];
buffer1[buffer1.length/2] = (img.getWidth() <= img.getHeight() ? img.getWidth() / 3 : img.getHeight() / 3);
//buffer1[25][25] = 10;
back = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_ARGB);
this.addMouseListener(this);
this.addMouseMotionListener(this);
}
//<editor-fold defaultstate="collapsed" desc="Used Methods">
#Override
public void run()
{
while(true)
{
this.update();
this.repaint();
this.swap();
}
}
//Called from Thread to update movedImgArray prior to being drawn.
private void update()
{
//This is my attempt of trying to convert his code to java.
for (int i=img.getWidth(); i < imgArray.length - 1; i++)
{
if(i % img.getWidth() == 0 || i >= imgArray.length - img.getWidth())
continue;
buffer2[i] = (
((buffer1[i-1]+
buffer1[i+1]+
buffer1[i-img.getWidth()]+
buffer1[i+img.getWidth()]) >> 1)) - buffer2[i];
buffer2[i] -= (buffer2[i] >> 5);
}
//Still my version of his code, because of the int[] instead of int[][].
for (int y = 1; y < img.getHeight() - 2; y++)
{
for(int x = 1; x < img.getWidth() - 2; x++)
{
int xOffset = buffer1[((y)*img.getWidth()) + (x-1)] - buffer1[((y)*img.getWidth()) + (x+1)];
int yOffset = buffer1[((y-1)*img.getWidth()) + (x)] - buffer1[((y+1)*img.getWidth()) + (x)];
int shading = xOffset;
//Here is where the error occurs (after a click or wave started), because yOffset becomes -512; which in turn gets
//multiplied by y... Not good... -_-
movedImgArray[(y*img.getWidth()) + x] = imgArray[((y+yOffset)*img.getWidth()) + (x+xOffset)] + shading;
}
}
//This is my OLD code that kidna worked...
//I threw in here to show you how I was doing it before I switched to images.
/*
for(int y = 1; y < img.getHeight() - 1; y++)
{
for(int x = 1; x < img.getWidth() - 1; x++)
{
//buffer2[y][x] = ((buffer1[y][x-1] +
//buffer1[y][x+1] +
//buffer1[y+1][x] +
//buffer1[y-1][x]) / 4) - buffer2[y][x];
buffer2[y][x] = ((buffer1[y][x-1] +
buffer1[y][x+1] +
buffer1[y+1][x] +
buffer1[y-1][x] +
buffer1[y + 1][x-1] +
buffer1[y + 1][x+1] +
buffer1[y - 1][x - 1] +
buffer1[y - 1][x + 1]) / 4) - buffer2[y][x];
buffer2[y][x] = (int)(buffer2[y][x] * dampening);
}
}*/
}
//Swaps buffers
private void swap()
{
int[] temp;
temp = buffer2;
buffer2 = buffer1;
buffer1 = temp;
}
//This creates a wave upon clicking. It also is where that 512 is coming from.
//512 was about right in my OLD code shown above, but helps to cause the Exeception now.
#Override
public void mouseClicked(MouseEvent e)
{
if(e.getX() > 0 && e.getY() > 0 && e.getX() < img.getWidth() && e.getY() < img.getHeight())
buffer2[((e.getY())*img.getWidth()) + (e.getX())] = 512;
}
private BufferedImage back;
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
back.setRGB(0, 0, img.getWidth(), img.getHeight(), movedImgArray, 0, img.getWidth());
g.drawImage(back, 0, 0, null);
}
}
P.S. Here are two images of the old code working.
Looking at my original pseudocode, I assume the Array Out Of Bounds error is happening when you try to look up the texture based on the offset. The problem happens because the refraction in the water is allowing us to see outside of the texture.
for every pixel (x,y) in the buffer
Xoffset = buffer(x-1, y) - buffer(x+1, y)
Yoffset = buffer(x, y-1) - buffer(x, y+1)
Shading = Xoffset
t = texture(x+Xoffset, y+Yoffset) // Array out of bounds?
p = t + Shading
plot pixel at (x,y) with colour p
end loop
The way to fix this is simply to either clamp the texture coordinates, or let them wrap. Also, if you find that the amount of refraction is too much, you can reduce it by bit-shifting the Xoffset and Yoffset values a little bit.
int clamp(int x, int min, int max)
{
if (x < min) return min;
if (x > max) return max;
return x;
}
int wrap(int x, int min, int max)
{
while (x<min)
x += (1+max-min);
while (x>max)
x -= (1+max-min);
return x;
}
for every pixel (x,y) in the buffer
Xoffset = buffer(x-1, y) - buffer(x+1, y)
Yoffset = buffer(x, y-1) - buffer(x, y+1)
Shading = Xoffset
Xoffset >>= 1 // Halve the amount of refraction
Yoffset >>= 1 // if you want.
Xcoordinate = clamp(x+Xoffset, 0, Xmax) // Use clamp() or wrap() here
Ycoordinate = clamp(y+Yoffset, 0, Ymax) //
t = texture(Xcoordinate, Ycoordinate)
p = t + Shading
plot pixel at (x,y) with colour p
end loop
I am calculating distance of point from a line. But I am getting wrong distance. Following is my piece of code which is gettting distance from line.
float px,py,something,u;
px=x2-x1;
py=y2-y1;
something = px*px + py*py;
u = ((x - x1) * px + (y - y1) * py) /(something);
if( u > 1)
{
u = 1;
// MinDist=0;
}
else if (u < 0)
{
u = 0;
//MinDist=0;
}
float xx = x1 + u * px;
float yy = y1 + u * py;
float dx = xx - x;
float dy = yy - y;
float dist= (float)Math.sqrt((double)dx*dx +(double) dy*dy);
Dist is giving wrong answer.
From: http://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line#Vector_formulation
distance(x=a+tn, p) = ||(a-p)-((a-p).n)n||
Where:
a = (x1, y1) //First point on line
n = |(x2-x1, y2-y1)| //Normalised direction vector
p = (x, y) //Query point
So, not going to do it all, but make functions and give meaningful names to help you follow the formular:
float[] a = new float[]{x1, y1};
float[] n = new float[]{x2-x1, y2-y1};
normalize(n);
float[] p = new float[]{x, y};
float[] aMinusP = subtract(a, p);
float aMinusPDotn = dot(aMinusP, n);
// vec2a.vec2b
float dot(float[] vec2a, float[] vec2b)
{
return vec2a[0]*vec2b[0] + vec2a[1]*vec2b[1];
}
// ||vec2||
float len(float[] vec2)
{
return (float)Math.Sqrt(dot(vec2, vec2));
}
// vec2/||vec2||
void normalize(float[] vec2)
{
float length = len(vec2);
vec2[0] /= length;
vec2[1] /= length;
}
// vec2a - vec2b
float[] subtract(float[] vec2a, float[] vec2b)
{
return new float[]{vec2a[0]-vec2b[0],vec2a[1]-vec2b[1]};
}
I'm working on the physics for my GTA2-like game so I can learn more about game physics.
The collision detection and resolution are working great.
I'm now just unsure how to compute the point of contact when I hit a wall.
Here is my OBB class:
public class OBB2D
{
private Vector2D projVec = new Vector2D();
private static Vector2D projAVec = new Vector2D();
private static Vector2D projBVec = new Vector2D();
private static Vector2D tempNormal = new Vector2D();
private Vector2D deltaVec = new Vector2D();
// Corners of the box, where 0 is the lower left.
private Vector2D corner[] = new Vector2D[4];
private Vector2D center = new Vector2D();
private Vector2D extents = new Vector2D();
private RectF boundingRect = new RectF();
private float angle;
//Two edges of the box extended away from corner[0].
private Vector2D axis[] = new Vector2D[2];
private double origin[] = new double[2];
public OBB2D(float centerx, float centery, float w, float h, float angle)
{
for(int i = 0; i < corner.length; ++i)
{
corner[i] = new Vector2D();
}
for(int i = 0; i < axis.length; ++i)
{
axis[i] = new Vector2D();
}
set(centerx,centery,w,h,angle);
}
public OBB2D(float left, float top, float width, float height)
{
for(int i = 0; i < corner.length; ++i)
{
corner[i] = new Vector2D();
}
for(int i = 0; i < axis.length; ++i)
{
axis[i] = new Vector2D();
}
set(left + (width / 2), top + (height / 2),width,height,0.0f);
}
public void set(float centerx,float centery,float w, float h,float angle)
{
float vxx = (float)Math.cos(angle);
float vxy = (float)Math.sin(angle);
float vyx = (float)-Math.sin(angle);
float vyy = (float)Math.cos(angle);
vxx *= w / 2;
vxy *= (w / 2);
vyx *= (h / 2);
vyy *= (h / 2);
corner[0].x = centerx - vxx - vyx;
corner[0].y = centery - vxy - vyy;
corner[1].x = centerx + vxx - vyx;
corner[1].y = centery + vxy - vyy;
corner[2].x = centerx + vxx + vyx;
corner[2].y = centery + vxy + vyy;
corner[3].x = centerx - vxx + vyx;
corner[3].y = centery - vxy + vyy;
this.center.x = centerx;
this.center.y = centery;
this.angle = angle;
computeAxes();
extents.x = w / 2;
extents.y = h / 2;
computeBoundingRect();
}
//Updates the axes after the corners move. Assumes the
//corners actually form a rectangle.
private void computeAxes()
{
axis[0].x = corner[1].x - corner[0].x;
axis[0].y = corner[1].y - corner[0].y;
axis[1].x = corner[3].x - corner[0].x;
axis[1].y = corner[3].y - corner[0].y;
// Make the length of each axis 1/edge length so we know any
// dot product must be less than 1 to fall within the edge.
for (int a = 0; a < axis.length; ++a)
{
float l = axis[a].length();
float ll = l * l;
axis[a].x = axis[a].x / ll;
axis[a].y = axis[a].y / ll;
origin[a] = corner[0].dot(axis[a]);
}
}
public void computeBoundingRect()
{
boundingRect.left = JMath.min(JMath.min(corner[0].x, corner[3].x), JMath.min(corner[1].x, corner[2].x));
boundingRect.top = JMath.min(JMath.min(corner[0].y, corner[1].y),JMath.min(corner[2].y, corner[3].y));
boundingRect.right = JMath.max(JMath.max(corner[1].x, corner[2].x), JMath.max(corner[0].x, corner[3].x));
boundingRect.bottom = JMath.max(JMath.max(corner[2].y, corner[3].y),JMath.max(corner[0].y, corner[1].y));
}
public void set(RectF rect)
{
set(rect.centerX(),rect.centerY(),rect.width(),rect.height(),0.0f);
}
// Returns true if other overlaps one dimension of this.
private boolean overlaps1Way(OBB2D other)
{
for (int a = 0; a < axis.length; ++a) {
double t = other.corner[0].dot(axis[a]);
// Find the extent of box 2 on axis a
double tMin = t;
double tMax = t;
for (int c = 1; c < corner.length; ++c) {
t = other.corner[c].dot(axis[a]);
if (t < tMin) {
tMin = t;
} else if (t > tMax) {
tMax = t;
}
}
// We have to subtract off the origin
// See if [tMin, tMax] intersects [0, 1]
if ((tMin > 1 + origin[a]) || (tMax < origin[a])) {
// There was no intersection along this dimension;
// the boxes cannot possibly overlap.
return false;
}
}
// There was no dimension along which there is no intersection.
// Therefore the boxes overlap.
return true;
}
public void moveTo(float centerx, float centery)
{
float cx,cy;
cx = center.x;
cy = center.y;
deltaVec.x = centerx - cx;
deltaVec.y = centery - cy;
for (int c = 0; c < 4; ++c)
{
corner[c].x += deltaVec.x;
corner[c].y += deltaVec.y;
}
boundingRect.left += deltaVec.x;
boundingRect.top += deltaVec.y;
boundingRect.right += deltaVec.x;
boundingRect.bottom += deltaVec.y;
this.center.x = centerx;
this.center.y = centery;
computeAxes();
}
// Returns true if the intersection of the boxes is non-empty.
public boolean overlaps(OBB2D other)
{
if(right() < other.left())
{
return false;
}
if(bottom() < other.top())
{
return false;
}
if(left() > other.right())
{
return false;
}
if(top() > other.bottom())
{
return false;
}
if(other.getAngle() == 0.0f && getAngle() == 0.0f)
{
return true;
}
return overlaps1Way(other) && other.overlaps1Way(this);
}
public Vector2D getCenter()
{
return center;
}
public float getWidth()
{
return extents.x * 2;
}
public float getHeight()
{
return extents.y * 2;
}
public void setAngle(float angle)
{
set(center.x,center.y,getWidth(),getHeight(),angle);
}
public float getAngle()
{
return angle;
}
public void setSize(float w,float h)
{
set(center.x,center.y,w,h,angle);
}
public float left()
{
return boundingRect.left;
}
public float right()
{
return boundingRect.right;
}
public float bottom()
{
return boundingRect.bottom;
}
public float top()
{
return boundingRect.top;
}
public RectF getBoundingRect()
{
return boundingRect;
}
public boolean overlaps(float left, float top, float right, float bottom)
{
if(right() < left)
{
return false;
}
if(bottom() < top)
{
return false;
}
if(left() > right)
{
return false;
}
if(top() > bottom)
{
return false;
}
return true;
}
public static float distance(float ax, float ay,float bx, float by)
{
if (ax < bx)
return bx - ay;
else
return ax - by;
}
public Vector2D project(float ax, float ay)
{
projVec.x = Float.MAX_VALUE;
projVec.y = Float.MIN_VALUE;
for (int i = 0; i < corner.length; ++i)
{
float dot = Vector2D.dot(corner[i].x,corner[i].y,ax,ay);
projVec.x = JMath.min(dot, projVec.x);
projVec.y = JMath.max(dot, projVec.y);
}
return projVec;
}
public Vector2D getCorner(int c)
{
return corner[c];
}
public int getNumCorners()
{
return corner.length;
}
public static float collisionResponse(OBB2D a, OBB2D b, Vector2D outNormal)
{
float depth = Float.MAX_VALUE;
for (int i = 0; i < a.getNumCorners() + b.getNumCorners(); ++i)
{
Vector2D edgeA;
Vector2D edgeB;
if(i >= a.getNumCorners())
{
edgeA = b.getCorner((i + b.getNumCorners() - 1) % b.getNumCorners());
edgeB = b.getCorner(i % b.getNumCorners());
}
else
{
edgeA = a.getCorner((i + a.getNumCorners() - 1) % a.getNumCorners());
edgeB = a.getCorner(i % a.getNumCorners());
}
tempNormal.x = edgeB.x -edgeA.x;
tempNormal.y = edgeB.y - edgeA.y;
tempNormal.normalize();
projAVec.equals(a.project(tempNormal.x,tempNormal.y));
projBVec.equals(b.project(tempNormal.x,tempNormal.y));
float distance = OBB2D.distance(projAVec.x, projAVec.y,projBVec.x,projBVec.y);
if (distance > 0.0f)
{
return 0.0f;
}
else
{
float d = Math.abs(distance);
if (d < depth)
{
depth = d;
outNormal.equals(tempNormal);
}
}
}
float dx,dy;
dx = b.getCenter().x - a.getCenter().x;
dy = b.getCenter().y - a.getCenter().y;
float dot = Vector2D.dot(dx,dy,outNormal.x,outNormal.y);
if(dot > 0)
{
outNormal.x = -outNormal.x;
outNormal.y = -outNormal.y;
}
return depth;
}
public Vector2D getMoveDeltaVec()
{
return deltaVec;
}
};
I'm now just unsure how to compute the point of contact when I hit a
wall.
You can represent a wall with a simple plane.
The OBB-vs-plane intersection test is the simplest separating axis test of them all:
If two convex objects don't intersect, then there is a plane where
the projection of these two objects will not intersect.
A box intersects plane only if the plane normal forms a separating axis. Compute the projection of the box center and the projected radius (4 dot products and a few adds) and you're good to go (you also get penetration depth for free).
The condition looks as follows:
|d| <= a1|n*A1| + a2|n*A2| + a3|n*A3|
Here:
d distance from the center of the box to the plane.
a1...a3 the extents of the box from the center.
n normal of the plane
A1...A3 the x,y,z-axis of the box
Some pseudocode:
//Test if OBB b intersects plane p
int TestOBBPlane(OBB b, Plane p)
{
// Compute the projection interval radius of b onto L(t) = b.c + t * p.n
float r = b.e[0]*Abs(Dot(p.n, b.u[0])) +
b.e[1]*Abs(Dot(p.n, b.u[1])) +
b.e[2]*Abs(Dot(p.n, b.u[2]));
// Compute distance of box center from plane
float s = Dot(p.n, b.c) – p.d;
// Intersection occurs when distance s falls within [-r,+r] interval
return Abs(s) <= r;
}
The OBB-vs-OBB intersection test is more complicated.
Let us refer to this great tutorial:
In this case we no longer have corresponding separating lines that are
perpendicular to the separating axes. Instead, we have separating
planes that separate the bounding volumes (and they are perpendicular
to their corresponding separating axes).
In 3D space, each OBB only has 3 unique planes extended by its faces,
and the separating planes are parallel to these faces. We are
interested in the separating planes parallel to the faces, but in 3D
space, the faces are not the only concern. We are also interested in
the edges. The separating planes of interest are parallel to the faces
of the boxes, and the separating axes of interest are perpendicular to
the separating planes. Hence the separating axes of interest are
perpendicular to the 3 unique faces of each box. Notice these 6
separating axes of interest correspond to the 6 local (XYZ) axes of
the two boxes.
So there are 9 separating axes to consider for edges collision in
addition to the 6 separating axes we already have found for the faces
collision. This makes the total number of possible separating axes to
consider at 15.
Here are the 15 possible separating axes (L) you will need to test:
CASE 1: L = Ax
CASE 2: L = Ay
CASE 3: L = Az
CASE 4: L = Bx
CASE 5: L = By
CASE 6: L = Bz
CASE 7: L = Ax x Bx
CASE 8: L = Ax x By
CASE 9: L = Ax x Bz
CASE 10: L = Ay x Bx
CASE 11: L = Ay x By
CASE 12: L = Ay x Bz
CASE 13: L = Az x Bx
CASE 14: L = Az x By
CASE 15: L = Az x Bz
Here:
Ax unit vector representing the x-axis of A
Ay unit vector representing the y-axis of A
Az unit vector representing the z-axis of A
Bx unit vector representing the x-axis of B
By unit vector representing the y-axis of B
Bz unit vector representing the z-axis of B
Now you can see the algorithm behind the OBB-OBB intersection test.
Let's jump to the source code:
2D OBB-OBB: http://www.flipcode.com/archives/2D_OBB_Intersection.shtml
3D OBB-OBB: http://www.geometrictools.com/LibMathematics/Intersection/Intersection.html
P.S: This link http://www.realtimerendering.com/intersections.html will be useful to those, who wish to go beyond planes and boxes.
I am trying to write a program like bouncingBall. but i generated N obstacles in the screen. Each time the ball touch the obstacle, the obstacle disappears and shows up at another random place. i am trying to use 2 dimension array to store the random-gernerated obstacles' point (x,y).
Right now if I input N>50, it gives me outofbound.
But what i want is to store point from (0,0) to (50,50)..what should I do achieve this with 2-dimentional array?
Thanks!
import java.util.ArrayList;
public class BouncingBall {
public static void main(String[] args) {
if (args.length < 1) {
System.out.println("Usage: java BouncingBall N");
System.exit(0);
}
int N = Integer.parseInt(args[0]);
if (N > 2500) {
System.out.println("Usage: java BouncingBall N<=2500");
System.exit(0);
}
double[][] myArray = new double[50][50];
// set the scale of the coordinate system
StdDraw.setXscale(-1.0, 1.0);
StdDraw.setYscale(-1.0, 1.0);
// initial values
double rx = 0.480, ry = 0.860; // position
double vx = 0.015, vy = 0.023; // velocity
double radius = 0.02; // radius
double x;
double y;
double a[] = new double[2];
StdDraw.setPenColor(StdDraw.WHITE);
StdDraw.filledSquare(0, 0, 1.0);
StdDraw.setPenColor(StdDraw.BLACK);
for(int i=0; i <= N; i++){
x = 2.0*(double)Math.random()-1.0;
y = 2.0*(double)Math.random()-1.0;
for (int t=0;t <50;t++){
for (int j=0;j <50;j++){
myArray[t][j]= x;
myArray[j][t]= y;
}
}
StdDraw.filledSquare(x, y, 0.02);
}
// main animation loop
while (true) {
// bounce off wall according to law of elastic collision
if (Math.abs(rx + vx) > 1.0 - radius) vx = -vx;
if (Math.abs(ry + vy) > 1.0 - radius) vy = -vy;
// clear the background
StdDraw.setPenColor(StdDraw.WHITE);
StdDraw.filledSquare(0, 0, 1.0);
StdDraw.clear();
StdDraw.setPenColor(StdDraw.BLACK);
for(int t=0; t <= N; t++){
for (int j=0;j <50;j++){
x = myArray[t][j];
y = myArray[j][t];
}
if ((Math.abs(rx + vx) > x - radius)||(Math.abs(ry + vy) > y - radius))
{ //if the ball touch the square
vx = -vx;
vy = -vy;
if (args.length == 2 && args[1].equals("-d")){
x = 2.0*(double)Math.random()-1.0; //new random x
y = 2.0*(double)Math.random()-1.0; //new random y
}else{
;
}
StdDraw.filledSquare(x, y, 0.02);
}
else{
StdDraw.filledSquare(x, y, 0.02); //if not touched, keep it.
}
}
rx = rx + vx;
ry = ry + vy;
StdDraw.filledCircle(rx, ry, radius);
// display and pause for 20 ms
StdDraw.show(20);
}
}
}
Imagine that the user inputs -1 for N, then x and y won't get a value because the loops bodies won't run.
Simple workaround: assign a default value to x and y (0 for example)
double x = 0;
double y = 0;
You need to initialize both x and y:
double x = 0;
double y = 0;
Your ArrayIndexOutOfBoundsException is occurring because you only define the array to be 50x50
double[][] myArray = new double[50][50];
yet access an index greater than that using t:
x = myArray[t][j];
you have to initialize your local variables, local variables dont get default values
int double x=0.0;
int double y=0.0;
would solve the compiler error.
if N>50
for (int t=0;t <50;t++){
for (int j=0;j <50;j++){
myArray[t][j]= x; // ArrayIndexOutOfBound Exection occurs here
myArray[j][t]= y;
}
}