I'm trying to create a basic graph for my application, but I'm having a small issue with it. Presently, what happens is that my graph is generated as I'd hope, but when I go to graph my points inside of it, the points are always "off by 1", specifically, my point that should sit at spot 15 on the graph is displayed at 14. The same is true for all other points in my graph, as they are also displayed 1 lower than they should be. I tried to add 1 to cond, but that didn't seem to change any of the actual points as they're displayed, and simply shifted my labels on the y axis to start higher. Below is the code that I think is responsible, but if more is needed, simply ask and I shall post what's asked.
Note: This is for a class assignment where the purpose is to generate 2d graphics, so I can't use a graphing class specifically, although I know it be a far easier job to do so.
The code is below:
public class GraphicsView extends View {
ArrayList<Point> points = new ArrayList<Point>();
Path xPath = new Path();
Path yPath = new Path();
Path zPath = new Path();
Path drawGrid = new Path();
...
Integer xAxis;
Integer yAxis;
#Override
protected void onDraw(Canvas canvas) {
Integer counter = points.size();
Integer xCord;
super.onDraw(canvas);
yAxis = this.getHeight();
xAxis = this.getWidth();
canvas.drawColor(R.color.Background);
<Setting different paint objects to the right colors here>
xPath.moveTo(20, yAxis-20);
yPath.moveTo(20, yAxis-20);
zPath.moveTo(20, yAxis-20);
drawGrid.moveTo(22, yAxis-20);
drawGrid.lineTo(22, 0);
canvas.drawPath(drawGrid,grid);
drawGrid.moveTo(22, yAxis-20);
drawGrid.lineTo(xAxis, yAxis-22);
canvas.drawPath(drawGrid,grid);
//Left right Axis (X)
for (Integer ctr = counter; ctr > 0; ctr--) {
Integer value = counter- ctr + 1;
canvas.drawText(value.toString(), (xAxis-20)/ctr,yAxis-5, grid);
}
//Up down Axis (Y)
for (Integer ctr = 1; ctr < 22; ctr++) {
Integer value = ctr - 1;
canvas.drawText(value.toString(), 5, scale(yAxis, ctr), grid);
}
for (Point point : points)
{
xCord = ((xAxis -20) / counter);
xPath.lineTo(xCord, scale(yAxis,point.getxCord()));
xPath.addCircle(xCord, scale(yAxis, point.getxCord()), 2, Direction.CW);
yPath.lineTo(xCord, scale(yAxis, point.getyCord()));
yPath.addCircle(xCord, scale(yAxis,point.getyCord()), 2, Direction.CW);
zPath.lineTo(xCord, scale(yAxis, point.getzCord()));
zPath.addCircle(xCord, scale(yAxis, point.getzCord()), 2, Direction.CW);
canvas.drawPath(xPath, xPaint);
canvas.drawPath(yPath, yPaint);
canvas.drawPath(zPath, zPaint);
counter -= 1;
}
}
private Integer scale(Integer Axis, Integer cord) {
Integer point = 0;
point = (Axis - (((Axis-20)/21)) * cord);
return point;
}
}
To reiterate, what I'm looking for is a way to resolve it so that when a value is set to 15, it shows it as being along the 15 on the y axis. At present, it shows it as being beside 14.
Whenever you call point.getyCord() just add a + 1 to it.
point.getyCord() + 1
And can you confirm that when you are setting a y value it is actually going in as the desired value.
Your problem lies here:
for (Integer ctr = 1; ctr < 22; ctr++) {
Integer value = ctr - 1;
canvas.drawText(value.toString(), 5, scale(yAxis, ctr), grid);
Your Y axis starts with label 0, but it puts it at the 1 position, since value = ctr - 1. When you use the scale() function later on, you don't offset it by one.
Two methods to fix this:
Modify scale() to offset for you
private Integer scale(Integer Axis, Integer cord) {
Integer point = 0;
point = (Axis - (((Axis-20)/21)) * (cord + 1));
return point;
}
If you use this method, you should also get rid of the value variable you used when drawing the axis, since you can just use ctr for the string as well.
Offset your y coordinate every time
As Colin Gillespie said, you can just add 1 to point.getCord().
I prefer the first method, since it's cleaner, and you only ever have to offset it once, in that function. With the second method, any time you ever pass a coordinate to scale, you'll have to remember to offset it.
Related
I am trying to write a small program that has a given number of balls (in the example code below it's 3) travel back and forth across the screen at different speeds and phases (start offset).
This much has been achieved in the code. Although I want to be able to select the balls (one at a time) using a mouse click.
I have used the word "HIT!!!" to signify in the console that a ball has been clicked.
My problem is that when I run the code below, I only get a "HIT!" in the console when I click the top ball. That is when the first element y[0] matches with the click_Y variable. When I am sure (but obviously mistaken somehow) that there should be matches when I click in the vicinity of y[1] & y[2].
I'd really be grateful for any help with these. As it's gotten to the point where I am starting to stare blankly at the screen. Thanks.
int noCircles; // the number of items in the array (# of circles)
float[] y; // y-position of each circle (fixed)
float[] speed; // speed of each circle
float[] phase; // phase of each circle
float red = 120;
float green = 120;
float blue = 120;
float click_X;
float click_Y;
void setup() {
size(500, 500);
noCircles = 3;
// allocate space for each array
y = new float[noCircles];
speed = new float[noCircles];
phase = new float[noCircles];
// calculate the vertical gap between each circle based on the total number
// of circles
float gap = height / (noCircles + 1);
//setup an initial value for each item in the array
for (int i=0; i<noCircles; i++) {
y[i] = gap * (i + 1);
// y is constant for each so can be calculated once
speed[i] = random(10);
phase[i] = random(TWO_PI);
}
}
void draw() {
background(155);
for (int i=0; i<noCircles; i++) {
// calculate the x-position of each ball based on the speed, phase and
//current frame
float x = width/2 + sin(radians(frameCount*speed[i] ) + phase[i])* 200;
if (dist(x, y[i], click_X, click_Y) <= 20){
println("HIT!!!!!!!!!!!!!!!!!!");
}
ellipse(x, y[i], 20, 20);
click_X = 0;
click_Y = 0;
}
}
void mousePressed() {
println("You clicked******************************************");
click_X = mouseX;
click_Y = mouseY;
println("click_X =" + click_X);
println("click_Y =" + click_Y);
}
Problems like these are best solved by debugging your program. Start by tracing through the code by hand, then add print statements (more than you've already added), and if that doesn't work then don't be afraid to use the debugger.
You're using the click_X and click_Y variables to check the position of the mouse against the position of each ball. Trace through the for loop in your draw() function. What happens at the end of the first iteration?
You reset the values of click_X and click_Y. That's why you aren't detecting any hits on the other circles.
You could probably refactor your code to only reset those variables if something has been hit, but really, I would stop using them altogether.
I'm guessing that you're using those variables because you only want to check when the mouse is pressed? Just use the mousePressed variable for that. Then you can use the mouseX and mouseY variables directly.
Then your if statement would look like this:
if (mousePressed && dist(x, y[i], mouseX, mouseY) <= 20) {
println("HIT: " + i);
}
Also, using separate arrays like this is called parallel arrays, and is general a bad habit to get into. You should probably use classes instead.
I'm new to OpenCV, but with a bit of luck and a lot of time I was able to hack together some code that detects individual cells in a chessboard like so:
The image frame is being stored in a Mat and the corners are being stored in a MatOfPoint2f.
Code to show how I'm using the matrices to draw the cells individually:
private void draw(final Mat frame) {
for (int x = 0; x < BOARD_SIZE - 1; x++)
for (int y = 0; y < BOARD_SIZE - 1; y++) {
final int index = x + y * BOARD_SIZE;
final Point topLeft = cornerPoints.get(index);
final Point bottomLeft = cornerPoints.get(index + BOARD_SIZE);
final Point topRight = cornerPoints.get(index + 1);
final Point bottomRight = cornerPoints.get(index + 1 + BOARD_SIZE);
// left line
Imgproc.line(frame, topLeft, bottomLeft, DEBUG_COLOR);
// right line
Imgproc.line(frame, topRight, bottomRight, DEBUG_COLOR);
// top line
Imgproc.line(frame, topLeft, topRight, DEBUG_COLOR);
// bottom line
Imgproc.line(frame, bottomLeft, bottomRight, DEBUG_COLOR);
}
}
How would I use the four points (the corners of the cells) to get the RGB values of the pixels inside of the each quadrilateral?
Create a mask from your vertices. You can use fillPoly for that.
Then iterate over pixels. If pixel(x,y) is valid in your mask, read RGB else continue. Restrict pixel iteration range using your extreme vertices.
Masking works. If you have lots of polygons, or not too much RAM, a point-in-polygon test may be more efficient, especially if you can guarantee that your quadrilaterals are convex. See this reference
Update: this question is seeking guidance on how to get a set of neighbors for any given coordinate.
I created a 2d array that contains coordinates,
int[][] coordinates= { { -1, -1 }, { -1, 0 }, { -1, +1 },
{ 0, -1 }, { 0, +1 }, { +1, -1 }, { +1, 0 }, { +1, -1 } };
As you can tell, these are the neighbors for coordinates (0,0).
Now I am trying to implement a method that takes two parameters (int positionX, int positionY), and use the input parameters value coordiante(x,y) as the starting coordinate and find all the neighbors for this coordinate.
I am thinking about something like this:
int getNearCoordinates(int positionX, int positionY) {
for (int[] coordinate: coordinates) {
//I am not sure what to do after this
}
}
I am trying to use a loop to get the individual coordinate from the 2d array I created and I am stuck at here. How do I find a way to appropriately find positionX's and positionY's neighbor?
What are neighbours?
All orange points in diagram below are neighbours of Origin (0,0)
I'd recommend to
Use a dedicated class (Coordinate) instead of int[]. This makes your code easier to extend (3rd dimention, etc) or to change (using double instead of int, etc.). In the example you can see an imutable class - this hinders code to have side effects.
Use Collection instead of Array. This makes handling much easier (you can simply add and remove items)
Use java8-Streaming-API. It is lightning fast and makes your code better readable.
Additional ideas:
You could even make getNearCoordinates part of the Coordinate class. This would make new Coordinate(27,35).getNearCoordinates() available.
Instead of storing x and y in separate fields you could also use a Map<Axis, Integer>. This would make your code a little bit harder to understand - but would reduce duplicated code.
You could also generate the collection of directions by using two nested loops for (int x = -1; x <= 1; x++) for (int y = -1; y <= 1; y++) use(new Coordinate(x,y)). This would make your code cleaner, but might be harder to understand.
Example code:
import java.util.*;
import java.util.stream.Collectors;
public class Snippet {
// make a class to be more flexible
class Coordinate {
// final fields are making this an "imutable"
final int x;
final int y;
/** constructor to take coordinate values */
Coordinate(int x, int y) {
this.x = x;
this.y = y;
}
/** moves this coordinate by another coordinate */
Coordinate move(Coordinate vector) {
return new Coordinate(x + vector.x, y + vector.y);
}
}
/** using Collection instead of Array makes your live easier. Consider renaming this to "directions". */
Collection<Coordinate> coordinates = Arrays.asList(
new Coordinate( -1, -1 ), // left top
new Coordinate( -1, 0 ), // left middle
new Coordinate( -1, +1 ), // left bottom
new Coordinate( 0, -1 ), // top
new Coordinate( 0, +1 ), // bottom
new Coordinate( +1, -1 ), // right top
new Coordinate( +1, 0 ), // right middle
new Coordinate( +1, +1 ) // right bottom
);
/** #return a collection of eight nearest coordinates near origin */
Collection<Coordinate> getNearCoordinates(Coordinate origin) {
return
// turn collection into stream
coordinates.stream()
// move the origin into every direction
.map(origin::move)
// turn stream to collection
.collect(Collectors.toList());
}
}
Same behaviour without Java8-streaming API would look like this:
/** #return a collection of eight nearest coordinates near origin */
Collection<Coordinate> getNearCoordinates(Coordinate origin) {
Collection<Coordinate> neighbours = new ArrayList<>();
for (Coordinate direction : coordinates)
neighbours.add(origin.move(direction));
return neighbours;
}
Two points A(x1,y1), B(x2,y2) are neighbours if this expression is true:
Math.abs(x1-x2) <= 1 && Math.abs(y1-y2) <= 1
Here if both differences are equal to zero then A equals B.
This is not the best way to implement it (using int[] for points), the purpose of this answer is to show the algorithms.
If you are talking about an unbounded plane then you will always have 8 points, so you could implement it the following way:
// first point index, 2nd: 0 = x, 1 = y
public int[][] getNeighbours(int x, int y) {
int[][] ret = new int[8][2];
int count = 0;
for (int i = -1; i <= 1; i++)
for (int j = -1; j <= 1; j++) {
if (i == 0 && j == 0)
continue;
ret[count][0] = x + i;
ret[count++][1] = y + j;
}
return ret;
}
It gets more interesting if the plane is bounded, using an ArrayList this time:
public List<int[]> getNeighbours(int x, int y, int minX, int maxX, int minY, int maxY) {
List<int[]> ret = new ArrayList<int[]>(8); // default initial capacity is 100
for (int i = Math.max(x - 1, minX); i <= Math.min(x + 1, maxX); i++)
for (int j = Math.max(y - 1, minY); j <= Math.min(y + 1, maxY); j++) {
if (i == x && j == y)
continue;
ret.add(new int[] {i, j});
}
return ret;
}
The latter will work for any point, also outside of the plane or just at the border.
That depends on how you define a neighbour. The code below will test the coordinates and return true for the diagonal as well as horizontal and vertical neighbours.
if (Math.abs(coordinate[0] - positionX) <= 1 && Math.abs(coordinate[1] - positionY) <= 1)
{
System.out.println(Arrays.toString(coordinate));
}
make sure to import java.lang.Math
Printing of the coordinates is just an example of course, but may be useful for debugging.
It may seem obvious, but you could duplicate coordinates, and add the given coordinate's x and y values to those of each coordinate, fit example using a for loop.
I am currently making a program to procedurally generate 2d terrain maps, with different technics such as perlin noise, simplex, voronoi, fractal noise, etc. on a size-defined image to be able to use it in my games requiring a 2d terrain.
I've come across the "Modelling fake planets" section of http://paulbourke.net/fractals/noise and I need to make it on a 2d texture, and not on a 3d world like it is explained.
Now I'm trying to
create a line from point 'X' to point 'Y'
That line will define a zone with a boolean value for left or right of the line to be "darker".
Doing that for a number of iteration to create a texture.
Using the RGB value of the final image to change stuffs such as forests, lakes, etc.
this would work this way:
overrides with this method below,
http://img35.imageshack.us/img35/24/islf.png
I used my high school maths powers to create a code sample but it's not really working...
Questions:
How should i change it so it works instead of just being failing?
Is there a simpler way than using what i am using?
Java file:
if i need an example on how i will proceed, here it is:
package Generator;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.util.Random;
import VectorialStuffs.Vector2;
public class Linear
{
public static BufferedImage generateImage(Dimension dim, int iterations)
{
BufferedImage image = new BufferedImage(dim.width, dim.height, BufferedImage.TYPE_INT_ARGB);
//point X and point Y
Vector2 pointX;
Vector2 pointY;
//difference between those
Vector2 diff;
Vector2 side;
double slope;
//random
Random rand = new Random();
boolean direction; //the orientation of the dark zone. (left/right)
for (int i = 0; i < iterations; ++i)
{
pointX = new Vector2(0, 0);
pointY = new Vector2(0, 0);
direction = rand.nextBoolean();
System.out.println(direction);
side = new Vector2(0, 0); //there are 4 sides of the image.
while (side.x == side.y)
{
side.x = rand.nextInt(3); //0 - 1 - 2 - 3
side.y = rand.nextInt(3);
}
switch(side.x) //not the x coord, the X point! ;D
{
//x = random and y = 0
case 0:
pointX.x = rand.nextInt(dim.width);
pointX.y = 0;
break;
//x = max and y = random
case 2:
pointX.x = dim.width;
pointX.y = rand.nextInt(dim.height);
break;
//x = random and y = max
case 1:
pointX.x = rand.nextInt(dim.width);
pointX.y = dim.height;
break;
//x = 0 and y = random
case 3:
pointX.x = 0;
pointX.y = rand.nextInt(dim.height);
break;
}
switch(side.y) //not the y coord, the Y point! ;D
{
//x = random and y = 0
case 0:
pointY.x = rand.nextInt(dim.width);
pointY.y = 0;
break;
//x = max and y = random
case 2:
pointY.x = dim.width;
pointY.y = rand.nextInt(dim.height);
break;
//x = random and y = max
case 1:
pointY.x = rand.nextInt(dim.width);
pointY.y = dim.height;
break;
//x = 0 and y = random
case 3:
pointY.x = 0;
pointY.y = rand.nextInt(dim.height);
break;
}
diff = new Vector2((pointY.x - pointX.x), (pointY.y - pointX.y));
slope = diff.y / diff.x;
Graphics graph = image.getGraphics();
if (direction) //true = right | false = left
{
int start; //the start x coordinate, on the line then increases until reaching the end of the image
int end = dim.width;
graph.setColor(Color.red);
graph.fillRect(pointX.x - 8, pointX.y -8, 16, 16);
graph.setColor(Color.yellow);
graph.fillRect(pointY.x - 8, pointY.y -8, 16, 16);
for (int times = 0; times < dim.height; ++times) //horizontal drawer
{
System.out.println(times);
start = (int)((times-diff.y)/slope + diff.y); //this is where it goes wrong?
for (int value = start; value < end; ++value)
{
graph.setColor(new Color(rand.nextInt(255), rand.nextInt(255), rand.nextInt(255), 100));
graph.fillRect(value, times, 1, 1);
}
}
graph.dispose();
}
else
{
int start; //the start x coordinate, on the line then increases until reaching the end of the image
int end = dim.width;
graph.setColor(Color.red);
graph.fillRect(pointX.x - 8, pointX.y -8, 16, 16);
graph.setColor(Color.yellow);
graph.fillRect(pointY.x - 8, pointY.y -8, 16, 16);
for (int times = 0; times < dim.height; ++times) //horizontal drawer
{
System.out.println(times);
start = (int)((times-diff.y)/slope);
for (int value = end; value < start; --value)
{
graph.setColor(new Color(rand.nextInt(255), rand.nextInt(255), rand.nextInt(255), 100));
graph.fillRect(value, times, 1, 1);
}
}
graph.dispose();
}
}
return image;
}
}
Note:
In this case vector2 is just a class with X and Y, which can be accessed (this is probably going to be temporary).
Startup part to avoid you losing time:
terrainImage = Linear.generateImage(size, 1); //size being a Dimension. -> "new Dimension(256, 256)"
if (terrainImage != null)
{
Icon wIcon = new ImageIcon(terrainImage);
JOptionPane.showMessageDialog(null, "message", "title", JOptionPane.OK_OPTION, wIcon);
}
//edit
here is the code that needs improvement:
if (direction) //true = right | false = left
{
int start; //the start x coordinate, on the line then increases until reaching the end of the image
int end = dim.width;
graph.setColor(Color.red);
graph.fillRect(pointX.x - 8, pointX.y -8, 16, 16);
graph.setColor(Color.yellow);
graph.fillRect(pointY.x - 8, pointY.y -8, 16, 16);
for (int times = 0; times < dim.height; ++times) //horizontal drawer
{
System.out.println(times);
start = (int)((times-diff.y)/slope + diff.y); //this is where it goes wrong?
for (int value = start; value < end; ++value)
{
graph.setColor(new Color(rand.nextInt(255), rand.nextInt(255), rand.nextInt(255), 100));
graph.fillRect(value, times, 1, 1);
}
}
graph.dispose();
}
else
{
int start; //the start x coordinate, on the line then increases until reaching the end of the image
int end = dim.width;
graph.setColor(Color.red);
graph.fillRect(pointX.x - 8, pointX.y -8, 16, 16);
graph.setColor(Color.yellow);
graph.fillRect(pointY.x - 8, pointY.y -8, 16, 16);
for (int times = 0; times < dim.height; ++times) //horizontal drawer
{
System.out.println(times);
start = (int)((times-diff.y)/slope);
for (int value = end; value < start; --value)
{
graph.setColor(new Color(rand.nextInt(255), rand.nextInt(255), rand.nextInt(255), 100));
graph.fillRect(value, times, 1, 1);
}
}
graph.dispose();
}
i can't get it to work like i showed in the picture above, all it does is either nothing, or offset from the 2 points.
Also, sometimes it freezes for no reason, so idk what will happen if i make more iterations of this :/
The pattern generation element of your code should only take about 3 lines, including rotation, colour pattern modulation and all as a function of iterations of i.
I will try and be clear:
you don't need a bar/line to generate your maps, you need any pattern on one/2 axes that starts off half of the period of the map and that gets a smaller and smaller proportion of the map or a smaller and smaller period.
pattern:
A line is round(x); or round (x+y) or round(sin(x+y +translatebar)+barwidth)<--a real bar in middle not just on side //
you can do curvy and zigzag lines later and 2D lines using additions and multiplications of X and Y functions. That function is essentially just a single line where you can change it X value so that rotates.
Rotation:
instead of a functional X every time which make a vertical line, you need to use sinus and co sinus function to generate X and Y values.
4 example 30; rotation is : round( X * 0.866+ Y* 0.5)
Get the sine and cosine of a random values and it will give you random rotations of your pattern the handy thing is that you just make a random value of your loop iteration and send it to a sign cosine.
OK i ll write this in pseudocode it will be simpler:
var pattern = 0; // black canvas
for(var i=1; i=100; i++)
{
pattern += round((sin (X*sin(pseudorand(i)) + Y*cos(pseudorand(i)) + translation) + roundshift )*strength;
}
The above loop will generate thousands of map patterns by adding bars of different rotations.
Round = quantizes your sin(XY) function so it is just black and white / red grey.
Sin(XY) = a variable function to use as a pattern, quantized by round to 0/1 values... multiply and clamp that value in the same line so it doesnt exceed 1 or 0
roundshift = value inside round(sin) pattern that shifts the sin down or up inside the round value resulting in smaller or larger amouts of black/white ration of each iteration. its a multiple of i so it's a function of i, gets smaller every loop.
xsin(rnd i) ycos(rnd i) = rotates your pattern both rnd's are same number necessarily.
translate value = when you +/- a number to a Sin(x+translate). it moves bar backwards/forwards
in the end your pattern value will equals maxiumum 100, so devide by 100 so it's 0-1 or mult by 2.56 for 256, and use a color randomiser to make RGB random multiples of your pattern value.
The above loop obviously needs to run once for every pixel x y.
i dont know how to do the canvas array/texture addin pixels in JS, it should be easy.
The above code will give you great patterns and visual feedback of your errors so you should be able to refine it very nicely, only think i missed is clamp to 0-1 values of sin (-1 1)+ roundshift result.
so a bar is round(sin(xy)+translate), and you can use many many functions of xy added muptiplied sins to add together everything else instead bars, graph circles, squares, wiggles, ovals, rectangles etc.
there is a website all about patterns of this type, except for ordered angles and say 5-6 iterations, using dots bars triangles etc, he is Canadian and on deviant art as well, if there weren't so many TD pattern generated I could find his website!
Here is a website explaining the process of "pattern piling" it's overlaying many shapes in smaller and smaller iterations.
only difference is he uses ordered rotations to create symmetry, and you want random rotations to create chaos maps.
see all the pics of piled patterns in 2d, he has many examples on deviant art and his site, i learnt alot from this guy:
http://algorithmic-worlds.net/info/info.php?page=pilpat
here is more work of superimposed smaller and smaller patterns in symmetry rotations:
https://www.google.com/search?q=Samuel+Monnier&espv=210&es_sm=93&source=lnms&tbm=isch&sa=X&ei=It0AU9uTCOn20gXXv4G4Cw&ved=0CAkQ_AUoAQ&biw=1365&bih=911
same as this using random sin cos rotations.
I'm running an example from a Kinect library for Processing (http://www.shiffman.net/2010/11/14/kinect-and-processing/) and sometimes get a NullPointerException pointing to this line:
int rawDepth = depth[offset];
The depth array is created in this line:
int[] depth = kinect.getRawDepth();
I'm not exactly sure what a NullPointerException is, and much googling hasn't really helped. It seems odd to me that the code compiles 70% of the time and returns the error unpredictably. Could the hardware itself be affecting it?
Here's the whole example if it helps:
// Daniel Shiffman
// Kinect Point Cloud example
// http://www.shiffman.net
// https://github.com/shiffman/libfreenect/tree/master/wrappers/java/processing
import org.openkinect.*;
import org.openkinect.processing.*;
// Kinect Library object
Kinect kinect;
float a = 0;
// Size of kinect image
int w = 640;
int h = 480;
// We'll use a lookup table so that we don't have to repeat the math over and over
float[] depthLookUp = new float[2048];
void setup() {
size(800,600,P3D);
kinect = new Kinect(this);
kinect.start();
kinect.enableDepth(true);
// We don't need the grayscale image in this example
// so this makes it more efficient
kinect.processDepthImage(false);
// Lookup table for all possible depth values (0 - 2047)
for (int i = 0; i < depthLookUp.length; i++) {
depthLookUp[i] = rawDepthToMeters(i);
}
}
void draw() {
background(0);
fill(255);
textMode(SCREEN);
text("Kinect FR: " + (int)kinect.getDepthFPS() + "\nProcessing FR: " + (int)frameRate,10,16);
// Get the raw depth as array of integers
int[] depth = kinect.getRawDepth();
// We're just going to calculate and draw every 4th pixel (equivalent of 160x120)
int skip = 4;
// Translate and rotate
translate(width/2,height/2,-50);
rotateY(a);
for(int x=0; x<w; x+=skip) {
for(int y=0; y<h; y+=skip) {
int offset = x+y*w;
// Convert kinect data to world xyz coordinate
int rawDepth = depth[offset];
PVector v = depthToWorld(x,y,rawDepth);
stroke(255);
pushMatrix();
// Scale up by 200
float factor = 200;
translate(v.x*factor,v.y*factor,factor-v.z*factor);
// Draw a point
point(0,0);
popMatrix();
}
}
// Rotate
a += 0.015f;
}
// These functions come from: http://graphics.stanford.edu/~mdfisher/Kinect.html
float rawDepthToMeters(int depthValue) {
if (depthValue < 2047) {
return (float)(1.0 / ((double)(depthValue) * -0.0030711016 + 3.3309495161));
}
return 0.0f;
}
PVector depthToWorld(int x, int y, int depthValue) {
final double fx_d = 1.0 / 5.9421434211923247e+02;
final double fy_d = 1.0 / 5.9104053696870778e+02;
final double cx_d = 3.3930780975300314e+02;
final double cy_d = 2.4273913761751615e+02;
PVector result = new PVector();
double depth = depthLookUp[depthValue];//rawDepthToMeters(depthValue);
result.x = (float)((x - cx_d) * depth * fx_d);
result.y = (float)((y - cy_d) * depth * fy_d);
result.z = (float)(depth);
return result;
}
void stop() {
kinect.quit();
super.stop();
}
And here are the errors:
processing.app.debug.RunnerException: NullPointerException
at processing.app.Sketch.placeException(Sketch.java:1543)
at processing.app.debug.Runner.findException(Runner.java:583)
at processing.app.debug.Runner.reportException(Runner.java:558)
at processing.app.debug.Runner.exception(Runner.java:498)
at processing.app.debug.EventThread.exceptionEvent(EventThread.java:367)
at processing.app.debug.EventThread.handleEvent(EventThread.java:255)
at processing.app.debug.EventThread.run(EventThread.java:89)
Exception in thread "Animation Thread" java.lang.NullPointerException
at org.openkinect.processing.Kinect.enableDepth(Kinect.java:70)
at PointCloud.setup(PointCloud.java:48)
at processing.core.PApplet.handleDraw(PApplet.java:1583)
at processing.core.PApplet.run(PApplet.java:1503)
at java.lang.Thread.run(Thread.java:637)
You are getting a NullPointerException since the value of the depth array is null. You can see from the source code of the Kinect class, there is a chance of a null value being returned by the getRawDepth() method. It is likely that there is no image being displayed at the time.
The code can be found at:
https://github.com/shiffman/libfreenect/blob/master/wrappers/java/processing/KinectProcessing/src/org/openkinect/processing/Kinect.java
Your code should check if the depth array is null before trying to process it. For example...
int[] depth = kinect.getRawDepth();
if (depth == null) {
// do something here where you handle there being no image
} else {
// We're just going to calculate and draw every 4th pixel (equivalent of 160x120)
int skip = 4;
// Translate and rotate
translate(width/2,height/2,-50);
rotateY(a);
for(int x=0; x<w; x+=skip) {
for(int y=0; y<h; y+=skip) {
int offset = x+y*w;
// Convert kinect data to world xyz coordinate
int rawDepth = depth[offset];
PVector v = depthToWorld(x,y,rawDepth);
stroke(255);
pushMatrix();
// Scale up by 200
float factor = 200;
translate(v.x*factor,v.y*factor,factor-v.z*factor);
// Draw a point
point(0,0);
popMatrix();
}
}
// Rotate
a += 0.015f;
}
I would suggest using a Java Debugger so that you can see the state of the variables at the time the exception is thrown. Some people also like to use log statements to output the values of the variables at different points in the application.
You can then trace the problem back to a point where one of the values is not populated with a non-null value.
The null pointer is happening when offset > kinect.getRawDepth();
You have a lot of code here, I'm not going to look at it all. Why can you assume that offset is < kinect.getRawDepth()?
Edit:
On second though, #Asaph's comment is probably right.
Null Pointer exception happens when depth[offset] does not exist or has not been allocated. Check when depth[offset] is undefined and that is the cause of the nullpointer exception.
Check when kinect.getRawDepth(); is greater than offset.