Create triangle of ones in two-dimensional array - java

So I want to create array [64][64] of 0 in java and create triangle of ones here. I mean something like:
0001000
0010100
0100010
1111111
So I created class point:
public class Point {
public int x;
public int y;
Point(int x, int y)
{
this.x = x;
this.y = y;
}
}
And I'm creating in main new points objects in that way:
int amountOfPowers = 6;
Point a = new Point((int) (Math.pow(2, amountOfPowers))/2, 0);
Point b = new Point((int) Math.pow(2, amountOfPowers), (int) (Math.pow(2, amountOfPowers) * Math.sqrt(3.0) / 2));
Point c = new Point(0, (int) (Math.pow(2, amountOfPowers) * Math.sqrt(3.0) / 2));
So A is (0, 64), B is (64, 64) and C is (32, 55). Somebody has any idea how can I write all positions in array from 0,64 to 64,64 as 1? (something like [0][64] = 1, [1][64] = 1, ..., [64][64] = 1).
And also how can I create lines of ones from (0,64) to (32, 55) and from (32, 55) to (64, 64). Somebody have any idea how can I do this?
#edit
I tried to use it:
https://en.wikipedia.org/wiki/Line_drawing_algorithm
Here is my method:
static void drawLine(Point from, Point to) {
// https://en.wikipedia.org/wiki/Line_drawing_algorithm
int dx = to.x - from.x;
int dy = to.y - from.y;
for (int x = from.x; x < to.x; x++) {
int y = from.y + dx * (x - from.x) / dy;
System.out.println("X: " + x + " Y: " + y);
canvas[x][y] = 1;
}
}
I wrote this in main:
drawLine(a, b);
drawLine(b, c);
drawLine(c, a);
And here is my result :/ It's something wrong.
0000000000000000000000000000000000000000000000000000000100000000
0000000000000000000000000000000000000000000000000000000100000000
0000000000000000000000000000000000000000000000000000001000000000
0000000000000000000000000000000000000000000000000000001000000000
0000000000000000000000000000000000000000000000000000010000000000
0000000000000000000000000000000000000000000000000000010000000000
0000000000000000000000000000000000000000000000000000100000000000
0000000000000000000000000000000000000000000000000001000000000000
0000000000000000000000000000000000000000000000000001000000000000
0000000000000000000000000000000000000000000000000010000000000000
0000000000000000000000000000000000000000000000000010000000000000
0000000000000000000000000000000000000000000000000100000000000000
0000000000000000000000000000000000000000000000000100000000000000
0000000000000000000000000000000000000000000000001000000000000000
0000000000000000000000000000000000000000000000010000000000000000
0000000000000000000000000000000000000000000000010000000000000000
0000000000000000000000000000000000000000000000100000000000000000
0000000000000000000000000000000000000000000000100000000000000000
0000000000000000000000000000000000000000000001000000000000000000
0000000000000000000000000000000000000000000010000000000000000000
0000000000000000000000000000000000000000000010000000000000000000
0000000000000000000000000000000000000000000100000000000000000000
0000000000000000000000000000000000000000000100000000000000000000
0000000000000000000000000000000000000000001000000000000000000000
0000000000000000000000000000000000000000001000000000000000000000
0000000000000000000000000000000000000000010000000000000000000000
0000000000000000000000000000000000000000100000000000000000000000
0000000000000000000000000000000000000000100000000000000000000000
0000000000000000000000000000000000000001000000000000000000000000
0000000000000000000000000000000000000001000000000000000000000000
0000000000000000000000000000000000000010000000000000000000000000
0000000000000000000000000000000000000100000000000000000000000000
1000000000000000000000000000000000000000000000000000000000000000
1000000000000000000000000000000000000000000000000000000000000000
0100000000000000000000000000000000000000000000000000000000000000
0100000000000000000000000000000000000000000000000000000000000000
0010000000000000000000000000000000000000000000000000000000000000
0010000000000000000000000000000000000000000000000000000000000000
0001000000000000000000000000000000000000000000000000000000000000
0000100000000000000000000000000000000000000000000000000000000000
0000100000000000000000000000000000000000000000000000000000000000
0000010000000000000000000000000000000000000000000000000000000000
0000010000000000000000000000000000000000000000000000000000000000
0000001000000000000000000000000000000000000000000000000000000000
0000001000000000000000000000000000000000000000000000000000000000
0000000100000000000000000000000000000000000000000000000000000000
0000000010000000000000000000000000000000000000000000000000000000
0000000010000000000000000000000000000000000000000000000000000000
0000000001000000000000000000000000000000000000000000000000000000
0000000001000000000000000000000000000000000000000000000000000000
0000000000100000000000000000000000000000000000000000000000000000
0000000000010000000000000000000000000000000000000000000000000000
0000000000010000000000000000000000000000000000000000000000000000
0000000000001000000000000000000000000000000000000000000000000000
0000000000001000000000000000000000000000000000000000000000000000
0000000000000100000000000000000000000000000000000000000000000000
0000000000000100000000000000000000000000000000000000000000000000
0000000000000010000000000000000000000000000000000000000000000000
0000000000000001000000000000000000000000000000000000000000000000
0000000000000001000000000000000000000000000000000000000000000000
0000000000000000100000000000000000000000000000000000000000000000
0000000000000000100000000000000000000000000000000000000000000000
0000000000000000010000000000000000000000000000000000000000000000
0000000000000000001000000000000000000000000000000000000000000000
Anybody have idea how can I solve my problem? :/

If you will think about your arrays as a screen and about 1's as dark pixels and zeroes as white pixels than you have task of drawing a line on screen. In reality it is exactly the task that being actively performed in video card.
Algorithm is expressed here https://en.wikipedia.org/wiki/Line_drawing_algorithm
NB: in algorithm they use int's and due rounding issues you might be will have better results if you will swap coords and will iterate using y instead of x.

Related

Generate 2d world with vectors

I try to get started with a 2d map generator with vectors. Now I have some questions how should I go for it.
public float[] gen() {
float[] vec = new float[100];
float x = 0, y = 0;
float a = 20,
b = 10;
for (int i = 0; i < vec.length; i += 2) {
vec[i] = MathUtils.random(x, x + a);
vec[i+1] = MathUtils.random(y - b, y + b);
x = vec[i];
y = vec[i+1];
}
return vec;
}
Would this be a good way to get verctors from? var a, b could be changed for smooth land / hills.
I thought about a neverending map. But how could I only render the part of the player sees. I will work with box2d.
Generated world parts should be saved to a file. Should I save them as chunks like in Minecraft done? And what file fromat is reccoment (json)?
I just liked to get a little perpective to look forwart.
Answer for 2nd Q.
You have to have a Camera
if(x >=camera.project(new Vector3(camera.position.x - camera.viewportWidth - 25, 0, 0)).x) && x <= camera.project(new Vector3(camera.viewportWidth + camera.position.x + 25, 0, 0)).x)
and y the same or less laggy than this(every frame there is created new Vector3 object, so...)
Good luck!

Z-buffering algorithm not drawing 100% correctly

I'm programming a software renderer in Java, and am trying to use Z-buffering for the depth calculation of each pixel. However, it appears to work inconsistently. For example, with the Utah teapot example model, the handle will draw perhaps half depending on how I rotate it.
My z-buffer algorithm:
for(int i = 0; i < m_triangles.size(); i++)
{
if(triangleIsBackfacing(m_triangles.get(i))) continue; //Backface culling
for(int y = minY(m_triangles.get(i)); y < maxY(m_triangles.get(i)); y++)
{
if((y + getHeight()/2 < 0) || (y + getHeight()/2 >= getHeight())) continue; //getHeight/2 and getWidth/2 is for moving the model to the centre of the screen
for(int x = minX(m_triangles.get(i)); x < maxX(m_triangles.get(i)); x++)
{
if((x + getWidth()/2 < 0) || (x + getWidth()/2 >= getWidth())) continue;
rayOrigin = new Point2D(x, y);
if(pointWithinTriangle(m_triangles.get(i), rayOrigin))
{
zDepth = zValueOfPoint(m_triangles.get(i), rayOrigin);
if(zDepth > zbuffer[x + getWidth()/2][y + getHeight()/2])
{
zbuffer[x + getWidth()/2][y + getHeight()/2] = zDepth;
colour[x + getWidth()/2][y + getHeight()/2] = m_triangles.get(i).getColour();
g2.setColor(m_triangles.get(i).getColour());
drawDot(g2, rayOrigin);
}
}
}
}
}
Method for calculating the z value of a point, given a triangle and the ray origin:
private double zValueOfPoint(Triangle triangle, Point2D rayOrigin)
{
Vector3D surfaceNormal = getNormal(triangle);
double A = surfaceNormal.x;
double B = surfaceNormal.y;
double C = surfaceNormal.z;
double d = -(A * triangle.getV1().x + B * triangle.getV1().y + C * triangle.getV1().z);
double rayZ = -(A * rayOrigin.x + B * rayOrigin.y + d) / C;
return rayZ;
}
Method for calculating if the ray origin is within a projected triangle:
private boolean pointWithinTriangle(Triangle triangle, Point2D rayOrigin)
{
Vector2D v0 = new Vector2D(triangle.getV3().projectPoint(modelViewer), triangle.getV1().projectPoint(modelViewer));
Vector2D v1 = new Vector2D(triangle.getV2().projectPoint(modelViewer), triangle.getV1().projectPoint(modelViewer));
Vector2D v2 = new Vector2D(rayOrigin, triangle.getV1().projectPoint(modelViewer));
double d00 = v0.dotProduct(v0);
double d01 = v0.dotProduct(v1);
double d02 = v0.dotProduct(v2);
double d11 = v1.dotProduct(v1);
double d12 = v1.dotProduct(v2);
double invDenom = 1.0 / (d00 * d11 - d01 * d01);
double u = (d11 * d02 - d01 * d12) * invDenom;
double v = (d00 * d12 - d01 * d02) * invDenom;
// Check if point is in triangle
if((u >= 0) && (v >= 0) && ((u + v) <= 1))
{
return true;
}
return false;
}
Method for calculating surface normal of a triangle:
private Vector3D getNormal(Triangle triangle)
{
Vector3D v1 = new Vector3D(triangle.getV1(), triangle.getV2());
Vector3D v2 = new Vector3D(triangle.getV3(), triangle.getV2());
return v1.crossProduct(v2);
}
Example of the incorrectly drawn teapot:
What am I doing wrong? I feel like it must be some small thing. Given that the triangles draw at all, I doubt it's the pointWithinTriangle method. Backface culling also appears to work correctly, so I doubt it's that. The most likely culprit to me is the zValueOfPoint method, but I don't know enough to know what's wrong with it.
My zValueOfPoint method was not working correctly. I'm unsure why :( however, I changed to a slightly different method of calculating the value of a point in a plane, found here: http://forum.devmaster.net/t/interpolation-on-a-3d-triangle-using-normals/20610/5
To make the answer here complete, we have the equation of a plane:
A * x + B * y + C * z + D = 0
Where A, B, and C are the surface normal x/y/z values, and D is -(Ax0 + By0 + Cz0).
x0, y0, and z0 are taken from one of the vertices of the triangle. x, y, and z are the coordinates of the point where the ray intersects the plane. x and y are known values (rayOrigin.x, rayOrigin.y) but z is the depth which we need to calculate. From the above equation we derive:
z = -A / C * x - B / C * y - D
Then, copied from the above link, we do:
"Note that for every step in the x-direction, z increments by -A / C, and likewise it increments by -B / C for every step in the y-direction.
So these are the gradients we're looking for to perform linear interpolation. In the plane equation (A, B, C) is the normal vector of the plane.
It can easily be computed with a cross product.
Now that we have the gradients, let's call them dz/dx (which is -A / C) and dz/dy (which is -B / C), we can easily compute z everywhere on the triangle.
We know the z value in all three vertex positions.
Let's call the one of the first vertex z0, and it's position coordinates (x0, y0). Then a generic z value of a point (x, y) can be computed as:"
z = z0 + dz/dx * (x - x0) + dz/dy * (y - y0)
This found the Z value correctly and fixed my code. The new zValueOfPoint method is:
private double zValueOfPoint(Triangle triangle, Point2D rayOrigin)
{
Vector3D surfaceNormal = getNormal(triangle);
double A = surfaceNormal.x;
double B = surfaceNormal.y;
double C = surfaceNormal.z;
double dzdx = -A / C;
double dzdy = -B / C;
double rayZ = triangle.getV1().z * modelViewer.getModelScale() + dzdx * (rayOrigin.x - triangle.getV1().projectPoint(modelViewer).x) + dzdy * (rayOrigin.y - triangle.getV1().projectPoint(modelViewer).y);
return rayZ;
}
We can optimize this by only calculating most of it once, and then adding dz/dx to get the z value for the next pixel, or dz/dy for the pixel below (with the y-axis going down). This means that we cut down on calculations per polygon significantly.
this must be really slow
so much redundant computations per iteration/pixel just to iterate its coordinates. You should compute the 3 projected vertexes and iterate between them instead look here:
triangle/convex polygon rasterization
I dislike your zValueOfPoint function
can not find any use of x,y coordinates from the main loops in it so how it can compute the Z value correctly ?
Or it just computes the average Z value per whole triangle ? or am I missing something? (not a JAVA coder myself) in anyway it seems that this is your main problem.
if you Z-value is wrongly computed then Z-Buffer can not work properly. To test that look at the depth buffer as image after rendering if it is not shaded teapot but some incoherent or constant mess instead then it is clear ...
Z buffer implementation
That looks OK
[Hints]
You have too much times terms like x + getWidth()/2 why not compute them just once to some variable? I know modern compilers should do it anyway but the code would be also more readable and shorter... at least for me

Hexagonal Grid (Flat Top) Distance Calculation

I have been working on creating a hexagonal (flat top) grid for a simulation I am working on. I have attempted to work out the distance between the hexagons, from a specified target hexagon.
The solution I have works for most of the time, apart from every odd column from the target hexagon north of the target is shifted up by 1. I know that sounds confusing but I have attached an image to explain what I mean:
As you guys can see, the bottom half of the grid below the target hexagon and every other column above the target Hexagon is correct. I cannot understand why :S
Here is an explanation of the Axial & Cube Co-ords.
http://www.redblobgames.com/grids/hexagons/#coordinates
Here is the code responsible for converting the Axial Co-ords to Cube Co-ords.
public void setQR(int theQ, int theR){
this.q = theQ;
this.r = theR;
this.x = this.q;
this.z = this.r - (this.q - (this.q&1)) /2;
this.y = -(this.x + this.z);
}
And heres the code for working out distance.
FYI, the Hexagons are created from a CentrePoint (CPx, CPy).
private double distance = 0;
public double workOutDistance(Hexagon hexagon, HexagonFood target){
double targetX = target.getCPX();
double targetY = target.getCPY();
double hexagonX = hexagon.getCPX();
double hexagonY = hexagon.getCPY();
double deltaX = (targetX-hexagonX)*-1;
double deltaY = (targetY-hexagonY)*-1;
double deltaXRadius = (deltaX/(SimField.hexSize)/1.5);
double deltaYApothem = (deltaY/(SimField.hexSize/1.155)/2);
hexagon.setQR((int)deltaXRadius, (int)deltaYApothem);
ArrayList<Integer> coords = new ArrayList<>();
coords.add(
Math.abs(hexagon.getX() - target.getX())
);
coords.add(
Math.abs(hexagon.getZ() - target.getZ())
);
coords.add(
Math.abs(hexagon.getY() - target.getY())
);
System.out.println(coords);
distance = Collections.max(coords);
return distance;
}
Can anyone please tell me why this is happening ? Would be greatly appreciated.
EDIT:
After changing Int to Double as suggested by Tim, I get this.
http://i.stack.imgur.com/javZb.png
**
SOLUTION
**
after experimenting with the answers given, This small tweak solves the problem.
changing this..
public void setQR(int theQ, int theR){
this.q = theQ;
this.r = theR;
this.x = this.q;
this.z = this.r - (this.q - (this.q&1)) /2;
this.y = -(this.x + this.z);
}
to this..
public void setQR(int theQ, int theR){
this.q = theQ;
this.r = theR;
this.x = this.q;
if (this.r>0){
this.z = this.r - (this.q - (this.q&1))/2;
}
else {
this.z = this.r - (this.q + (this.q&1))/2;
}
this.y = -(this.x + this.z);
}
You're casting a double to an int when calling setQR(); are you sure that's doing what you expect? Doubles use floating point math, so the number you'd expect to be 2.0 might actually be 1.999999989, which would then be rounded down to 1 when cast to an int.
I'm also skeptical of the line that reads this.z = this.r - (this.q - (this.q&1)) /2;. You're adding 1 when the number is odd, which seems to be the failure case you're experiencing; I'd make sure that line is doing what you're expecting, too.
If you're not stepping through this with a debugger and examining the values, you're doing it wrong.
You could also take an entirely different approach to this problem. You know the X/Y (cartesian) coordinates of your two hexagons, which means you can get each hexagon's cubic coordinates relative to the origin of your hexagonal space. The distance between the two hexagons is simply the sum of the absolute values of the differences between the two hexagons' X, Y and Z cubic coordinates. (That is, dist = |h2.X - h1.X| + |h2.Y - h1.Y| + |h2.Z - h1.Z|) So rather than trying to compute the vector between the two centerpoints and then convert that into cubic coordinates, you could just compute the distance directly in cubic coordinates (just like you would if these were squares in cartesian coordinates)...
Even if you take this approach, though, I'd strongly recommend that you debug what's going on with your original approach. Even if you end up throwing away the code, the exercise of debugging will probably teach you valuable lessons that you'll be able to apply in the future.
Note to readers: "cubic" coordinates aren't 3-dimensional cartesian coordinates, they're a hexagon-specific coordinate system for which a link was provided by the OP.
The fact that the computation (that is, the conversion from offset- to cube coordinates, and the computation of the distance in cube coordinates) seems to be correct suggests that Tim was right with his assumption about the floating point errors.
You should try to change the line
hexagon.setQR((int)deltaXRadius, (int)deltaYApothem);
from your original code to something like
hexagon.setQR((int)Math.round(deltaXRadius), (int)Math.round(deltaYApothem));
Which could solve the issue in this case.
If not ... or... in any case, here's a small example, basically doing the same as you did, but as a MVCE...
import java.awt.Point;
public class HexagonsTest
{
public static void main(String[] args)
{
// Above and below
test(8,6, 8,5, 1);
test(8,6, 8,7, 1);
// Left
test(8,6, 7,5, 1);
test(8,6, 7,6, 1);
// Right
test(8,6, 9,5, 1);
test(8,6, 9,6, 1);
// The first one that was wrong:
test(8,6, 7,4, 2);
}
private static void test(int x0, int y0, int x1, int y1, int expected)
{
int distance = computeStepsDistance(x0, y0, x1, y1);
System.out.println(
"Distance of (" + x0 + "," + y0 + ") to " +
"(" + x1 + "," + y1 + ") is " + distance +
", expected " + expected);
}
private static int computeStepsDistance(int x0, int y0, int x1, int y1)
{
Point cp0 = convertOffsetToCubeCoordinates(x0, y0, null);
Point cp1 = convertOffsetToCubeCoordinates(x1, y1, null);
int cx0 = cp0.x;
int cy0 = cp0.y;
int cz0 = -cx0-cy0;
int cx1 = cp1.x;
int cy1 = cp1.y;
int cz1 = -cx1-cy1;
int dx = Math.abs(cx0 - cx1);
int dy = Math.abs(cy0 - cy1);
int dz = Math.abs(cz0 - cz1);
return Math.max(dx, Math.max(dy, dz));
}
private static Point convertOffsetToCubeCoordinates(
int ox, int oy, Point p)
{
int cx = ox;
int cz = oy - (ox - (ox&1)) / 2;
int cy = -cx-cz;
if (p == null)
{
p = new Point();
}
p.x = cx;
p.y = cy;
return p;
}
}

Trying to create an Htree using Recursion in Java, unable to get it to do more than one corner

I'm currently taking a class in Java and our professor is having us write a program using recursion to build an "Htree" which is just an H with smaller H's on every corner of the first, and down as many levels as the user specifies. So far I have it recursively creating the FIRST corner, but I can't seem to figure out how to change it so it will do all four corners. Here is my code:
package assignment3;
public class Htree {
public static void main(String[] args) {
int SIZE = 512;
// Output and entry take place in the console window
Turtle.create(SIZE, SIZE);
int xCenter = SIZE / 2;
int yCenter = SIZE / 2;
int x = 4;
recursive(xCenter, yCenter, x);
}
private static void recursive(int xCenter, int yCenter, int x) {
int x2 = x - 1;
if (x2 < 0) {
return;
}
int left = xCenter - xCenter / 2;
int right = xCenter + xCenter / 2;
int top = yCenter - yCenter / 2;
int bottom = yCenter + yCenter / 2;
int middle = yCenter;
Turtle.fly(right, middle);
Turtle.go(left, middle);
Turtle.fly(right, top);
Turtle.go(right, bottom);
Turtle.fly(left, top);
Turtle.go(left, bottom);
recursive(left, top, x2);
System.out.println("Done");
}
}
And it's supposed to look something like this:
Any tips would be appreciated.
Your code like
int left = xCenter - xCenter / 2;
int right = xCenter + xCenter / 2;
is problematic. Suppose the X centers for second-level H's should be at x=2 and x=6. For the lefthand H you compute left=1, right=3, so it would be 2 units wide. But for the righthand H you compute left=3, right=9, so it is 6 units wide. Conclusion: your recursive routine needs another parameter, to specify width, and you would use formulas like left=xCenter-wide/2, right=xCenter+wide/2.
Here is pseudocode for an easy way to do the four different recursive calls (with drawH(xCenter, yCenter, wide, deep) used in place of your recursive(left, top, x2); function):
p = q = 1
for i in {1..4}:
drawH(xCenter+p*size/xratio, yCenter+q*size/yratio, wide/2, deep-1)
q = p*q; p = -p;
Correction and note, May 2016: The last line of pseudocode, q = p*q; p = -p;, produces (p, q) pairs {(1, 1), (-1, 1), (1, -1), (-1, -1)} for the four bars of the H.

Java: Rotate Point around another by specified degree value

I am trying to rotate a 2D Point in java around another with a specified degree value, in this case simply around Point (0, 0) at 90 degrees.
Method:
public void rotateAround(Point center, double angle) {
x = center.x + (Math.cos(Math.toRadians(angle)) * (x - center.x) - Math.sin(Math.toRadians(angle)) * (y - center.y));
y = center.y + (Math.sin(Math.toRadians(angle)) * (x - center.x) + Math.cos(Math.toRadians(angle)) * (y - center.y));
}
Expected for (3, 0): X = 0, Y = -3
Returned for (3, 0): X = 1.8369701987210297E-16, Y = 1.8369701987210297E-16
Expected for (0, -10): X = -10, Y = 0
Returned for (0, -10): X = 10.0, Y = 10.0
Is something wrong with the method itself? I ported the function from (Rotating A Point In 2D In Lua - GPWiki) to Java.
EDIT:
Did some performance tests. I wouldn't have thought so, but the vector solution won, so I'll use this one.
If you have access to java.awt, this is just
double[] pt = {x, y};
AffineTransform.getRotateInstance(Math.toRadians(angle), center.x, center.y)
.transform(pt, 0, pt, 0, 1); // specifying to use this double[] to hold coords
double newX = pt[0];
double newY = pt[1];
You're mutating the X value of center before performing the calculation on the Y value. Use a temporary point instead.
Additionally, that function takes three parameters. Why does yours only take two?

Categories

Resources