Computing area of a polygon in Java - java

I have a class called SimplePolygon that creates a polygon with coordinates provided by the user. I am trying to define a method to compute the area of the polygon. It's an assignment and course instructor wants us to use the following formula to compute the area.
I can use either formula. I chose the right one.
My code gives me the wrong area. I don't know what's wrong.
public class SimplePolygon implements Polygon {
protected int n; // number of vertices of the polygon
protected Point2D.Double[] vertices; // vertices[0..n-1] around the polygon
public double area() throws NonSimplePolygonException {
try
{
if(isSimple()==false)
throw new NonSimplePolygonException();
else
{
double sum = 0;
for(int i = 0; i < vertices.length - 1; i++)
if(i == 0)
sum += vertices[i].x * (vertices[i+1].y - vertices[vertices.length - 1].y);
else
sum += vertices[i].x * (vertices[i+1].y - vertices[i-1].y);
double area = 0.5 * Math.abs(sum);
return area;
}
}
catch(NonSimplePolygonException e)
{
System.out.println("The Polygon is not simple.");
}
return 0.0;
}
The following is a tester code. The polygon is a rectangle with area 2, but the output is 2.5
Point2D.Double a = new Point2D.Double(1,1);
Point2D.Double b = new Point2D.Double(3,1);
Point2D.Double c = new Point2D.Double(3,2);
Point2D.Double d = new Point2D.Double(1,2);
SimplePolygon poly = new SimplePolygon(4);
poly.vertices[0] = a;
poly.vertices[1] = b;
poly.vertices[2] = c;
poly.vertices[3] = d;
System.out.println(poly.area());

Now that you've fixed the trivial boundary case, you're missing another boundary and your loop is wrong. Corrected code with debug:
public double area()
{
double sum = 0;
for (int i = 0; i < vertices.length ; i++)
{
if (i == 0)
{
System.out.println(vertices[i].x + "x" + (vertices[i + 1].y + "-" + vertices[vertices.length - 1].y));
sum += vertices[i].x * (vertices[i + 1].y - vertices[vertices.length - 1].y);
}
else if (i == vertices.length - 1)
{
System.out.println(vertices[i].x + "x" + (vertices[0].y + "-" + vertices[i - 1].y));
sum += vertices[i].x * (vertices[0].y - vertices[i - 1].y);
}
else
{
System.out.println(vertices[i].x + "x" + (vertices[i + 1].y + "-" + vertices[i - 1].y));
sum += vertices[i].x * (vertices[i + 1].y - vertices[i - 1].y);
}
}
double area = 0.5 * Math.abs(sum);
return area;
}

There is one missing term from the sum: vertices[n-1].x * (vertices[0].y - vertices[n-2].y).
Before the edit of the question there was also a problem with the first term:
Furthermore, if i==0 the term should be vertices[i].x * (vertices[i+1].y - vertices[n-1].y).
Assuming that n is equal to vertices.length.
The simplest way to code the loop is probably:
n = vertices.length;
sum =0;
for (int i = 0; i < n; i++) {
sum += vertices[i].x * (vertices[(i + 1) % n].y - vertices[(i + n - 1) % n].y);
}

I found another way,
Add first element again into polygon array
So that we can avoid "Out of bound" case as well as many If conditions.
Here is my solution:
public class PolygonArea {
public static void main(String[] args) {
PolygonArea p = new PolygonArea();
System.out.println(p.calculateArea());
}
Point[] points = new Point[5];
public double calculateArea() {
points[0] = new Point("A", 4, 10);
points[1] = new Point("B", 9, 7);
points[2] = new Point("C", 11, 2);
points[3] = new Point("D", 2, 2);
/** Add first entry again to polygon */
points[4] = new Point("A", 4, 10);
double sum = 0.0;
for (int i = 0; i < points.length - 1; ++i) {
sum += (points[i].X * points[i + 1].Y) - (points[i + 1].X * points[i].Y);
}
return Math.abs(sum / 2);
}
class Point {
final String _ID;
final int X;
final int Y;
public Point(String id, int x, int y) {
_ID = id;
X = x;
Y = y;
}
}
}

Related

Rotate 2D array by alpha degrees

I wrote a function which takes two parameters:
JPG image as 3D array
rotation degrees given by alpha
My approach was:
public static int[][] rotate(int[][] img, double alpha) {
double rad = Math.toRadians(alpha);
double sin = Math.sin(rad);
double cos = Math.cos(rad);
int height = img.length;
int width = img[0].length;
int[][] rotate = new int[height][width];
for(int i = 0; i < height; i++) {
for(int j = height - i - 1; j < width; j++) {
if(j < height && i < width) {
double i_new = Math.floor(cos * (img[i].length - i) - sin * (img[j].length - j)) + i;
double j_new = Math.floor(sin * (img[i].length - i) + cos * (img[j].length - j)) + j;
rotate[i][j] = img[(int)j_new][(int)i_new];
}
}
}
return rotate;
}
While fixing the index range, the output is a black image. What am I missing?
After a while I got to a solution.
Caution: Its not using any special pre-defined libraries.
The global function which run`s over the matrice:
public static int[][] rotate(int[][] img, double alpha) {
double rad = Math.toRadians(alpha); //construct of the relevant angles
double sin = Math.sin(rad);
double cos = Math.cos(rad);
int height = img.length;
int width = img[0].length;
int[][] rotate = new int[height][width];
int a = height / 2; //we will use the area of a and b to compare coordinates by the formula given
int b = width / 2;
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
double i_new = Math.floor(cos * (i - a) - sin * (j - b)) + a; // following the conversion function
double j_new = Math.floor(sin * (i - a) + cos * (j - b)) + b;
if (i_new >= rotate.length || i_new < 0 || j_new >= rotate[0].length || j_new < rotate[0][0]) { // if out of scope of the conversion --> print none
System.out.print(""); //mainly cause 'continue' statements are not necessary in java and JS
} else {
rotate[(int) i_new][(int) j_new] = img[i][j]; //convert
}
}
}
return rotate;
}
The global function which rotates each 2D matrice:
public static int[][][] rotate_alpha(int[][][] img, double alpha) {
int height = img[0].length;
int width = img[0][0].length;
int[][][] rotated = new int[3][height][width];
for (int k = 0; k < 3; k++) {
rotated[k] = rotate(img[k], alpha);
}
return rotated;
}
Hope this topic is solved by now, and stands by all the standards of the clean code.

There is a "lag" or "delay" when it comes to changing many ImageIcons inside JLabels. How to avoid?

I am currently working on a 2D-simulator game that takes place in a Perlin noise-generated terrain that is shown on a 41x23 grid. The player (as of the moment, at the center but not yet given an overlaying icon) can move using the arrow keys, but doing so will keep the player static but move the map accordingly. However, when I move, the JFrame lags like hell. Some JLabel instances change their ImageIcons slower than others, creating huge latency and un-"playability". I have tried replacing the inefficient function update with four functions that "efficiently" move the player faster - but the lag or delay remains. I have also reformatted and refactored the function, to no avail. So, I am stuck.
For more info, I am using 32x32 icons that represent the structures and the domain, and the JFrame is 1280x720 in size. I am confident that this is not due to hardware, as the program runs with other memory- or core- consuming programs. Is there any way to solve the lag or delay?
Main Class
import java.awt.EventQueue;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.awt.image.RescaleOp;
import javax.swing.JPanel;
import java.awt.Color;
import java.awt.GridBagLayout;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
public class Main {
private JFrame frame;
public static ImageIcon water = new ImageIcon(new ImageIcon(Main.class.getResource("/textures/terrain/water.png")).getImage().getScaledInstance(32, 32, Image.SCALE_DEFAULT));
public static ImageIcon sand = new ImageIcon(new ImageIcon(Main.class.getResource("/textures/terrain/sand.png")).getImage().getScaledInstance(32, 32, Image.SCALE_DEFAULT));
public static ImageIcon grass = new ImageIcon(new ImageIcon(Main.class.getResource("/textures/terrain/grass.png")).getImage().getScaledInstance(32, 32, Image.SCALE_DEFAULT));
public static ImageIcon stone = new ImageIcon(new ImageIcon(Main.class.getResource("/textures/terrain/stone.png")).getImage().getScaledInstance(32, 32, Image.SCALE_DEFAULT));
public static ImageIcon ice = new ImageIcon(new ImageIcon(Main.class.getResource("/textures/terrain/ice.png")).getImage().getScaledInstance(32, 32, Image.SCALE_DEFAULT));
public static ImageIcon oak = new ImageIcon(new ImageIcon(Main.class.getResource("/textures/structure/oak.png")).getImage().getScaledInstance(32, 32, Image.SCALE_DEFAULT));
public static ImageIcon nullstructure = new ImageIcon(new ImageIcon(Main.class.getResource("/textures/structure/nullstructure.png")).getImage().getScaledInstance(32, 32, Image.SCALE_DEFAULT));
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Main window = new Main();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
* #throws InterruptedException
*/
public Main() throws InterruptedException {
initialize();
}
/**
* Initialize the contents of the frame.
* #throws InterruptedException
*/
private void initialize() throws InterruptedException {
frame = new JFrame();
frame.setResizable(false);
frame.setBounds(0, 0, 1280, 720);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
Coordinate playerPos = new Coordinate(0,0);
JLabel[][] terrainArray = new JLabel[41][23];
JLabel[][] structureArray = new JLabel[41][23];
JLayeredPane layeredPane = new JLayeredPane();
layeredPane.setBounds(0, 0, 1280, 720);
frame.getContentPane().add(layeredPane);
layeredPane.setLayout(null);
JPanel terrainGrid = new JPanel();
terrainGrid.setBounds(0, 0, 1280, 720);
layeredPane.add(terrainGrid);
GridBagLayout gbl_terrainGrid = new GridBagLayout();
gbl_terrainGrid.columnWidths = new int[]{0};
gbl_terrainGrid.rowHeights = new int[]{0};
gbl_terrainGrid.columnWeights = new double[]{Double.MIN_VALUE};
gbl_terrainGrid.rowWeights = new double[]{Double.MIN_VALUE};
terrainGrid.setLayout(gbl_terrainGrid);
JPanel structureGrid = new JPanel();
layeredPane.setLayer(structureGrid, Integer.valueOf(1));
structureGrid.setBounds(0, 0, 1280, 720);
structureGrid.setBackground(new Color(0,0,0,0));
structureGrid.setOpaque(false);
layeredPane.add(structureGrid);
GridBagLayout gbl_structureGrid = new GridBagLayout();
gbl_structureGrid.columnWidths = new int[]{0};
gbl_structureGrid.rowHeights = new int[]{0};
gbl_structureGrid.columnWeights = new double[]{Double.MIN_VALUE};
gbl_structureGrid.rowWeights = new double[]{Double.MIN_VALUE};
structureGrid.setLayout(gbl_structureGrid);
Coordinate[][] map = new Coordinate[Coordinate.MAP_SIZE][Coordinate.MAP_SIZE];
for(int i = 0; i < Coordinate.MAP_SIZE; i++) {
for(int j = 0; j < Coordinate.MAP_SIZE; j++) {
map[i][j] = new Coordinate(i - ((Coordinate.MAP_SIZE - 1)/2) , j - ((Coordinate.MAP_SIZE - 1)/2));
}
}
for(int i = 0; i < 41; i++) {
for(int j = 0; j < 23; j++) {
terrainArray[i][j] = new JLabel("");
structureArray[i][j] = new JLabel("");
structureArray[i][j].setIcon(Main.nullstructure);
terrainArray[i][j].setIcon(findEntry(map, new Coordinate(playerPos.getX() - 20 + i, playerPos.getZ() - 11 + j)).returnTerrainIcon());
structureArray[i][j].setIcon(findEntry(map, new Coordinate(playerPos.getX() - 20 + i, playerPos.getZ() - 11 + j)).returnStructureIcon());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = i; gbc.gridy = j;
terrainGrid.add(terrainArray[i][j], gbc);
structureGrid.add(structureArray[i][j],gbc);
}
}
frame.addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent e) {
switch(e.getKeyCode()) {
case KeyEvent.VK_UP:
playerPos.setZ(playerPos.getZ() - 1);
moveUP(terrainArray, structureArray, map, playerPos);
break;
case KeyEvent.VK_DOWN:
playerPos.setZ(playerPos.getZ() + 1);
moveDOWN(terrainArray, structureArray, map, playerPos);
break;
case KeyEvent.VK_RIGHT:
playerPos.setX(playerPos.getX() + 1);
moveRIGHT(terrainArray, structureArray, map, playerPos);
break;
case KeyEvent.VK_LEFT:
playerPos.setX(playerPos.getX() - 1);
moveLEFT(terrainArray, structureArray, map, playerPos);
break;
}
}
});
}
public void moveUP(JLabel[][] terrainArray, JLabel[][] structureArray, Coordinate[][] map, Coordinate playerPos) {
for(int x = 0; x < 41; x++) {
for(int z = 22; z > 0; z--) { //23 - 1
terrainArray[x][z].setIcon(terrainArray[x][z-1].getIcon());
structureArray[x][z].setIcon(structureArray[x][z-1].getIcon());
}
terrainArray[x][0].setIcon(findEntry(map, new Coordinate(playerPos.getX() - 20 + x, playerPos.getZ() - 11)).returnTerrainIcon());
structureArray[x][0].setIcon(findEntry(map, new Coordinate(playerPos.getX() - 20 + x, playerPos.getZ() - 11)).returnStructureIcon());
}
}
public void moveDOWN(JLabel[][] terrainArray, JLabel[][] structureArray, Coordinate[][] map, Coordinate playerPos) {
for(int x = 0; x < 41; x++) {
for(int z = 0; z < 22; z++) { //23 - 1
terrainArray[x][z].setIcon(terrainArray[x][z+1].getIcon());
structureArray[x][z].setIcon(structureArray[x][z+1].getIcon());
}
terrainArray[x][22].setIcon(findEntry(map, new Coordinate(playerPos.getX() - 20 + x, playerPos.getZ() + 11)).returnTerrainIcon());
structureArray[x][22].setIcon(findEntry(map, new Coordinate(playerPos.getX() - 20 + x, playerPos.getZ() + 11)).returnStructureIcon());
}
}
public void moveLEFT(JLabel[][] terrainArray, JLabel[][] structureArray, Coordinate[][] map, Coordinate playerPos) {
for(int z = 0; z < 23; z++) {
for(int x = 40; x > 0; x--) {
terrainArray[x][z].setIcon(terrainArray[x-1][z].getIcon());
structureArray[x][z].setIcon(structureArray[x-1][z].getIcon());
}
terrainArray[0][z].setIcon(findEntry(map, new Coordinate(playerPos.getX() - 20, playerPos.getZ() - 11 + z)).returnTerrainIcon());
structureArray[0][z].setIcon(findEntry(map, new Coordinate(playerPos.getX() - 20, playerPos.getZ() - 11 + z)).returnStructureIcon());
}
}
public void moveRIGHT(JLabel[][] terrainArray, JLabel[][] structureArray, Coordinate[][] map, Coordinate playerPos) {
for(int z = 0; z < 23; z++) {
for(int x = 0; x < 40; x++) {
terrainArray[x][z].setIcon(terrainArray[x+1][z].getIcon());
structureArray[x][z].setIcon(structureArray[x+1][z].getIcon());
}
terrainArray[40][z].setIcon(findEntry(map, new Coordinate(playerPos.getX() + 20, playerPos.getZ() - 11 + z)).returnTerrainIcon());
structureArray[40][z].setIcon(findEntry(map, new Coordinate(playerPos.getX() + 20, playerPos.getZ() - 11 + z)).returnStructureIcon());
}
}
public static ImageIcon brightenImage(ImageIcon input, float brightness, float offset) {
BufferedImage bI = new BufferedImage(input.getImage().getWidth(null), input.getImage().getHeight(null), BufferedImage.TYPE_INT_RGB);
Graphics2D bIgr = bI.createGraphics();
bIgr.drawImage(input.getImage(), 0, 0, null);
bIgr.dispose();
BufferedImage bO = new BufferedImage(input.getImage().getWidth(null), input.getImage().getHeight(null), BufferedImage.TYPE_INT_RGB);
RescaleOp rop = new RescaleOp(brightness, offset, null);
bO = rop.filter(bI, null);
ImageIcon output = new ImageIcon(bO);
return output;
}
// public void update(JLabel[][] terrainArray, JLabel[][] structureArray, Coordinate[][] map, Coordinate playerPos) {
// for(int i = 0; i < 41; i++) {
// for(int j = 0; j < 23; j++) {
// terrainArray[i][j].setIcon(findEntry(map, new Coordinate(playerPos.getX() - 20 + i, playerPos.getZ() - 11 + j)).returnTerrainIcon());
// structureArray[i][j].setIcon(findEntry(map, new Coordinate(playerPos.getX() - 20 + i, playerPos.getZ() - 11 + j)).returnStructureIcon());
// }
// }
// }
public Coordinate findEntry(Coordinate[][] map, Coordinate pos) {
Coordinate entry = null;
for(int x = 0; x < Coordinate.MAP_SIZE; x++) {
for(int z = 0; z < Coordinate.MAP_SIZE; z++) {
if(pos.getX() == map[x][z].getX() && pos.getZ() == map[x][z].getZ()) {
entry = map[x][z];
}
}
}
return entry;
}
}
Coordinate Class
import javax.swing.ImageIcon;
public class Coordinate {
private int x, z;
private int alt;
public static final int MAP_SIZE = 199;
private ImageIcon str = Main.nullstructure;
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getZ() {
return z;
}
public void setZ(int z) {
this.z = z;
}
public int getAlt() {
return alt;
}
public void setAlt(int alt) {
this.alt = alt;
}
public Coordinate(int x0, int z0) {
this.x = x0;
this.z = z0;
int a = (int) Noise.mapTo(-1 * Math.sqrt(0.5), Math.sqrt(0.5), 0, 100, Noise.noise(x*0.1, z*0.1));
int b = (int) Noise.mapTo(-1 * Math.sqrt(0.5), Math.sqrt(0.5), 0, 100, Noise.noise(x*0.05, z*0.05));
int c = (int) Noise.mapTo(-1 * Math.sqrt(0.5), Math.sqrt(0.5), 0, 100, Noise.noise(x*0.01, z*0.01));
this.alt = (int) ((0.55*c) + (0.25*b) + (0.20*a));
if(Math.random() < 0.05 && alt >= 52 && alt < 70) {
str = Main.oak;
}
}
public ImageIcon returnTerrainIcon() {
if(alt >= 0 && alt < 50) {
return Main.water;
}
else if(alt >= 50 && alt < 52) {
return Main.brightenImage(Main.sand, (float) ((float) 0.95 + ((alt - 50) * 0.025)), (float) 0.36);
}
else if(alt >= 52 && alt < 70) {
return Main.brightenImage(Main.grass, (float) ((float) 0.85 + ((alt - 52) * 0.025)), (float) 0.36);
}
else if(alt >= 80 && alt < 90) {
return Main.brightenImage(Main.stone, (float) ((float) 0.65 + ((alt - 70) * 0.05)), (float) 0.36);
}
else {
return Main.ice;
}
}
public ImageIcon returnStructureIcon() {
return str;
}
}
Perlin (Not original)
import java.util.Random;
//<pre>
// Copyright 2001 Ken Perlin
// Courtesy of https://mrl.cs.nyu.edu/~perlin/experiments/packing/render/Noise.java
/**
Computes Perlin Noise for one, two, and three dimensions.<p>
The result is a continuous function that interpolates a smooth path
along a series random points. The function is consitent, so given
the same parameters, it will always return the same value.
#see ImprovedNoise
*/
public final class Noise {
/**
Initialization seed used to start the random number generator.
*/
static Random randseed = new Random();
public static int seed = (int) Math.floor(randseed.nextInt());
private static final int P = 8;
private static final int B = 1 << P;
private static final int M = B - 1;
private static final int NP = 8;
private static final int N = 1 << NP;
private static int p[] = new int[B + B + 2];
private static double g2[][] = new double[B + B + 2][2];
private static double g1[] = new double[B + B + 2];
private static double[][] points = new double[32][3];
static {
init();
}
private static double lerp(double t, double a, double b) {
return a + t * (b - a);
}
private static double s_curve(double t) {
return t * t * (3 - t - t);
}
/**
Computes noise function for one dimension at x.
#param x 1 dimensional parameter
#return the noise value at x
*/
public static double noise(double x) {
int bx0, bx1;
double rx0, rx1, sx, t, u, v;
t = x + N;
bx0 = ((int) t) & M;
bx1 = (bx0 + 1) & M;
rx0 = t - (int) t;
rx1 = rx0 - 1;
sx = s_curve(rx0);
u = rx0 * g1[p[bx0]];
v = rx1 * g1[p[bx1]];
return lerp(sx, u, v);
}
/**
Computes noise function for two dimensions at the point (x,y).
#param x x dimension parameter
#param y y dimension parameter
#return the value of noise at the point (x,y)
*/
public static double noise(double x, double y) {
int bx0, bx1, by0, by1, b00, b10, b01, b11;
double rx0, rx1, ry0, ry1, sx, sy, a, b, t, u, v, q[];
int i, j;
t = x + N;
bx0 = ((int) t) & M;
bx1 = (bx0 + 1) & M;
rx0 = t - (int) t;
rx1 = rx0 - 1;
t = y + N;
by0 = ((int) t) & M;
by1 = (by0 + 1) & M;
ry0 = t - (int) t;
ry1 = ry0 - 1;
i = p[bx0];
j = p[bx1];
b00 = p[i + by0];
b10 = p[j + by0];
b01 = p[i + by1];
b11 = p[j + by1];
sx = s_curve(rx0);
sy = s_curve(ry0);
q = g2[b00];
u = rx0 * q[0] + ry0 * q[1];
q = g2[b10];
v = rx1 * q[0] + ry0 * q[1];
a = lerp(sx, u, v);
q = g2[b01];
u = rx0 * q[0] + ry1 * q[1];
q = g2[b11];
v = rx1 * q[0] + ry1 * q[1];
b = lerp(sx, u, v);
return lerp(sy, a, b);
}
/**
Computes noise function for three dimensions at the point (x,y,z).
#param x x dimension parameter
#param y y dimension parameter
#param z z dimension parameter
#return the noise value at the point (x, y, z)
*/
static public double noise(double x, double y, double z) {
int bx, by, bz, b0, b1, b00, b10, b01, b11;
double rx0, rx1, ry0, ry1, rz, sx, sy, sz, a, b, c, d, u, v, q[];
bx = (int) Math.IEEEremainder(Math.floor(x), B);
if (bx < 0)
bx += B;
rx0 = x - Math.floor(x);
rx1 = rx0 - 1;
by = (int) Math.IEEEremainder(Math.floor(y), B);
if (by < 0)
by += B;
ry0 = y - Math.floor(y);
ry1 = ry0 - 1;
bz = (int) Math.IEEEremainder(Math.floor(z), B);
if (bz < 0)
bz += B;
rz = z - Math.floor(z);
//if (bx < 0 || bx >= B + B + 2)
//System.out.println(bx);
b0 = p[bx];
bx++;
b1 = p[bx];
b00 = p[b0 + by];
b10 = p[b1 + by];
by++;
b01 = p[b0 + by];
b11 = p[b1 + by];
sx = s_curve(rx0);
sy = s_curve(ry0);
sz = s_curve(rz);
q = G(b00 + bz);
u = rx0 * q[0] + ry0 * q[1] + rz * q[2];
q = G(b10 + bz);
v = rx1 * q[0] + ry0 * q[1] + rz * q[2];
a = lerp(sx, u, v);
q = G(b01 + bz);
u = rx0 * q[0] + ry1 * q[1] + rz * q[2];
q = G(b11 + bz);
v = rx1 * q[0] + ry1 * q[1] + rz * q[2];
b = lerp(sx, u, v);
c = lerp(sy, a, b);
bz++;
rz--;
q = G(b00 + bz);
u = rx0 * q[0] + ry0 * q[1] + rz * q[2];
q = G(b10 + bz);
v = rx1 * q[0] + ry0 * q[1] + rz * q[2];
a = lerp(sx, u, v);
q = G(b01 + bz);
u = rx0 * q[0] + ry1 * q[1] + rz * q[2];
q = G(b11 + bz);
v = rx1 * q[0] + ry1 * q[1] + rz * q[2];
b = lerp(sx, u, v);
d = lerp(sy, a, b);
return lerp(sz, c, d);
}
private static double[] G(int i) {
return points[i % 32];
}
private static void init() {
int i, j, k;
double u, v, w, U, V, W, Hi, Lo;
java.util.Random r = new java.util.Random(seed);
for (i = 0; i < B; i++) {
p[i] = i;
g1[i] = 2 * r.nextDouble() - 1;
do {
u = 2 * r.nextDouble() - 1;
v = 2 * r.nextDouble() - 1;
} while (u * u + v * v > 1 || Math.abs(u) > 2.5 * Math.abs(v) || Math.abs(v) > 2.5 * Math.abs(u) || Math.abs(Math.abs(u) - Math.abs(v)) < .4);
g2[i][0] = u;
g2[i][1] = v;
normalize2(g2[i]);
do {
u = 2 * r.nextDouble() - 1;
v = 2 * r.nextDouble() - 1;
w = 2 * r.nextDouble() - 1;
U = Math.abs(u);
V = Math.abs(v);
W = Math.abs(w);
Lo = Math.min(U, Math.min(V, W));
Hi = Math.max(U, Math.max(V, W));
} while (u * u + v * v + w * w > 1 || Hi > 4 * Lo || Math.min(Math.abs(U - V), Math.min(Math.abs(U - W), Math.abs(V - W))) < .2);
}
while (--i > 0) {
k = p[i];
j = (int) (r.nextLong() & M);
p[i] = p[j];
p[j] = k;
}
for (i = 0; i < B + 2; i++) {
p[B + i] = p[i];
g1[B + i] = g1[i];
for (j = 0; j < 2; j++) {
g2[B + i][j] = g2[i][j];
}
}
points[3][0] = points[3][1] = points[3][2] = Math.sqrt(1. / 3);
double r2 = Math.sqrt(1. / 2);
double s = Math.sqrt(2 + r2 + r2);
for (i = 0; i < 3; i++)
for (j = 0; j < 3; j++)
points[i][j] = (i == j ? 1 + r2 + r2 : r2) / s;
for (i = 0; i <= 1; i++)
for (j = 0; j <= 1; j++)
for (k = 0; k <= 1; k++) {
int n = i + j * 2 + k * 4;
if (n > 0)
for (int m = 0; m < 4; m++) {
points[4 * n + m][0] = (i == 0 ? 1 : -1) * points[m][0];
points[4 * n + m][1] = (j == 0 ? 1 : -1) * points[m][1];
points[4 * n + m][2] = (k == 0 ? 1 : -1) * points[m][2];
}
}
}
private static void normalize2(double v[]) {
double s;
s = Math.sqrt(v[0] * v[0] + v[1] * v[1]);
v[0] = v[0] / s;
v[1] = v[1] / s;
}
public static double mapTo(double a1, double a2, double b1, double b2, double x) {
return b1 + ((x-a1)*(b2-b1))/(a2-a1);
}
}
The icons and resources to be used are in this Github code (repository, I guess, I am new to Github):
https://github.com/rubiksRepository/Perlin.git
I would appreciate any help given. Thanks!
So far, Raildex's suggestion is working. The compilation of the map into a single buffered image has reduced the lag tremendously and made the game "playable". For additions in the code, I have made a texture class that supports the textures used; and a MapField whose object has fields that have the compiled BufferImage.
import java.awt.image.BufferedImage;
public class MapField {
private BufferedImage terrain;
private BufferedImage structure;
public MapField(Coordinate[][] map) {
BufferedImage[] colsT = new BufferedImage[Coordinate.MAP_SIZE];
BufferedImage[] colsS = new BufferedImage[Coordinate.MAP_SIZE];
for(int z = 0; z < Coordinate.MAP_SIZE; z++) {
colsT[z] = Texture.mergeTeU(map[z]);
colsS[z] = Texture.mergeStU(map[z]);
}
terrain = Texture.mergeH(colsT);
structure = Texture.mergeH(colsS);
}
public BufferedImage getTerrain() {
return terrain;
}
public void setTerrain(BufferedImage terrain) {
this.terrain = terrain;
}
public BufferedImage getStructure() {
return structure;
}
public void setStructure(BufferedImage structure) {
this.structure = structure;
}
}
Also in the Texture class, there are methods that can be used to merge rows and columns of BufferedImages, using a Graphics2D drawing process:
public static BufferedImage toBI(ImageIcon input) {
BufferedImage output = new BufferedImage(input.getImage().getWidth(null), input.getImage().getHeight(null), BufferedImage.TYPE_INT_ARGB);
Graphics2D outputGr = output.createGraphics();
outputGr.drawImage(input.getImage(), 0, 0, null);
outputGr.dispose();
return output;
}
public static BufferedImage mergeH(BufferedImage[] x) {
int i = 0;
BufferedImage rowOutput = new BufferedImage(x[0].getWidth() * x.length, x[0].getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D rowOutputG = rowOutput.createGraphics();
for(BufferedImage xBI : x) {
rowOutputG.drawImage(xBI, i * x[0].getWidth(), 0, null);
i++;
}
rowOutputG.dispose();
return rowOutput;
}
public static BufferedImage mergeTeH(Coordinate[] x) {
BufferedImage[] xIcons = new BufferedImage[x.length];
for(int i = 0; i < x.length; i++) {
xIcons[i] = Texture.toBI(x[i].returnTerrainIcon());
}
return mergeH(xIcons);
}
public static BufferedImage mergeStH(Coordinate[] x) {
BufferedImage[] xIcons = new BufferedImage[x.length];
for(int i = 0; i < x.length; i++) {
xIcons[i] = Texture.toBI(x[i].returnStructureIcon());
}
return mergeH(xIcons);
}
public static BufferedImage mergeU(BufferedImage[] x) {
int i = 0;
BufferedImage colOutput = new BufferedImage(x[0].getWidth(), x[0].getHeight() * x.length, BufferedImage.TYPE_INT_ARGB);
Graphics2D colOutputG = colOutput.createGraphics();
for(BufferedImage xBI : x) {
colOutputG.drawImage(xBI, 0, i * x[0].getHeight(), null);
i++;
}
colOutputG.dispose();
return colOutput;
}
public static BufferedImage mergeTeU(Coordinate[] x) {
BufferedImage[] xIcons = new BufferedImage[x.length];
for(int i = 0; i < x.length; i++) {
xIcons[i] = Texture.toBI(x[i].returnTerrainIcon());
}
return mergeU(xIcons);
}
public static BufferedImage mergeStU(Coordinate[] x) {
BufferedImage[] xIcons = new BufferedImage[x.length];
for(int i = 0; i < x.length; i++) {
xIcons[i] = Texture.toBI(x[i].returnStructureIcon());
}
return mergeU(xIcons);
}
So the bottomline is: for scroll-based maps, you can compile the textures corresponding to the map to improve playability (FPS or lag reduction). For interaction with the game, editing the BufferedImage at a pixel range via turning it to transparency or changing textures can help, at least for me. Not really great in answering the general gist since I am addressing my case only (trying to emulate this solution on others though) and the scroll-base map is on a case-to-case basis, but I hope my solution helps.

Recursive Division Maze Java

I'm having problems with completing the algorithm based on this link.
After building a wall I choose the upper or left part of the maze and it seems to create itself only to the point where it needs to break the recursion and enter another divide method call. I'm not sure if I understand the values needed to be passed to the last call of the divide method correctly.
public void divide(int x, int y, int width, int hight) {
if (width< 2 || hight< 2) ;
else {
boolean horizontal = chooseOrientation(width,hight);
if (horizontal) {
int randomNumber = r.nextInt(hight - 1);
wallY = randomNumber + y;
for (int i = x; i < width; i++) {
fields[wallY][i].setHorizontalWall();
}
fields[wallY][r.nextInt(width- 1)].deleteHorizontalWall();
hight = wallY - y + 1;
divide(x, y, width, hight);
}
else {
int randomNumber = r.nextInt(width- 1);
WallX = randomNumber + x;
for (int i = y; i < hight; i++) {
fields[i][WallX].setVerticalWall();
}
fields[r.nextInt(hight - 1) + y][WallX].deleteVerticalWall();
width = WallX - x + 1;
}
if(horizontal){
hight = y + hight + WallY-1;
y = WallY + 1;
}
else {
width = WallX - 1 + width + x;
x = WallX + 1;
}
divide(x, y, width, hight);
}
}
In the "recursive-division" algorithm you start with a full 2-dimensional grid graph and you then start removing edges (= building "walls") alternating in horizontal and vertical "stripes". In every "stripe" only a single edge ("door") is left.
A graph-based version of this algorithm can be found here:
https://github.com/armin-reichert/mazes
https://github.com/armin-reichert/mazes/blob/master/mazes-algorithms/src/main/java/de/amr/maze/alg/others/RecursiveDivision.java

Java 2D Polygon - Polygon Collision Detection

Recently I have been using the Polygon class to create asteroids as well as bullets and a spaceship. I am currently trying to create the collision detection for the program however it appears that the collision detection only works around 1/5 of the time (no pattern appears as to why it works).
Here's the code..
Creating the Polygon:
void renderPoly() {
int j;
int s = sides;
double r, angle;
int x, y;
for (j = 0; j < s; j++) {
angle = 2 * Math.PI / s * j;
r = MIN_ROCK_SIZE + (int) (Math.random() * (MAX_ROCK_SIZE - MIN_ROCK_SIZE));
x = (int) (r * Math.cos(angle));
y = (int) (r * -Math.sin(angle));
cOM[0] += x;
cOM[1] += y;
pointData[j][0] = x;
pointData[j][1] = y;
}
cOM[0] /= asteroidShape.npoints;
cOM[1] /= asteroidShape.npoints;
for (int i = 0; i < asteroidShape.npoints; i++) {
pointData[i][0] += cOM[0];
pointData[i][1] += cOM[1];
}
}
rotating and moving the polygon:
void move() {
int x, y, i;
//change rotation
theta += rotVel;
//change x
asteroidData[0] += deltaX;
//change y
asteroidData[1] += deltaY;
for (i = 0; i < asteroidShape.npoints; i++) {
x = (int) (pointData[i][0] * Math.cos(theta) - pointData[i][1] * Math.sin(theta) );
y = (int) (pointData[i][0] * Math.sin(theta) + pointData[i][1] * Math.cos(theta) );
asteroidShape.xpoints[i] = x + asteroidData[0];
asteroidShape.ypoints[i] = y + asteroidData[1];
asteroidShape.invalidate();
}
}
check if touching bullet:
boolean hitBullet(Bullet b) {
this.asteroidShape.invalidate();
for (int i = 0; i < b.bulletShape.npoints; i++)
if (this.asteroidShape.contains(b.bulletShape.xpoints[i], b.bulletShape.ypoints[i]) )
return true;
for (int j = 0; j < this.asteroidShape.npoints; j++)
if (b.bulletShape.contains(this.asteroidShape.xpoints[j], this.asteroidShape.ypoints[j]) )
return true;
return false;
}
(the ship method is the same except the constructor requires a ship object)
as well as the loop that calls it in the 'game' class:
for (int i = 0; i < aArray.length-1; i++) {
if (aArray[i] != null) {
for (int j = 0; j < bArray.length-1; j++) {
if (bArray[j] != null) {
if (aArray[i].hitBullet(bArray[j])) {
aArray[i] = null;
bArray[j] = null;
i = aArray.length-1;
j = bArray.length-1;
}
}
else {
i = aArray.length-1;
j = bArray.length-1;
}
}
}
else {
i = aArray.length-1;
}
}
I have been looking around at alternative solutions such as the Separating Axis Theorem however I do have convex polygons at times and since this method (.contains()) already exists I would like to use it.
Any help would be appreciated, thanks!
The easy way to solve this that I've found is to convert Shapes (in your case Polygon(2D?)) into Areas. You can use Area.intersect(Area) to see if two Areas have collided

Estimating Area Between Shapes

In my class, we are given the task as follows:
For this assignment you will attempt to make a program for computing the overlapping area of a set of shapes, implementing Monte Carlo integration, as discussed in class.
Make AreaEstimator.java, a program that estimates the area of overlap of an arbitrary number of circles and triangles using randomized estimation. The program's arguments will be the number of randomly-generated points to be used in this trial, followed by the coordinates of the points that define the shapes. For example,
java AreaEstimator 1000000 circle 2.0 2.0 1.0 triangle 1.0 1.0 2.5 3.0 2.0 -3.0 circle 2.5 1.0 3.0
would generate one million random points to estimate the overlap of a triangle whose vertices are ( 1.0, 1.0 ), ( 2.5, 3.0 ), ( 2.0, -3.0 ), with two circles whose centers are at ( 2.0, 2.0 ) and ( 2.5, 1.0 ), and whose radii are 1.0 and 3.0, respectively.
Here is my code for the Circle class:
public class Circle {
private double xcenter;
private double ycenter;
private double radius;
private double xcmax;
private double xcmin;
private double ycmax;
private double ycmin;
public Circle ( double xcenter, double ycenter, double radius){
if(radius <= 0){
throw new IllegalArgumentException();
}
this.xcenter = xcenter;
this.ycenter = ycenter;
this.radius = radius;
}
public void maxAndMinCircle (){ //find the minimun and maximum for the plane according to this circle
xcmax = (this.xcenter + this.radius);
ycmax = (this.ycenter + this.radius);
xcmin = (this.xcenter - this.radius);
ycmin = (this.ycenter - this.radius);
}
public double getXCMax (){
return xcmax;
}
public double getYCMax () {
return ycmax;
}
public double getXCMin() {
return xcmin;
}
public double getYCMin(){
return ycmin;
}
public boolean outsideCircle(double randX, double randY){ // find if the random point passed thru is in this circle
double distance = Math.sqrt((randX-this.xcenter)*(randX-this.xcenter) + (randY-this.ycenter) * (randY - this.ycenter));
return distance >= radius;
}}
The Triangle Class:
public class Triangle {
private double cornerx1;
private double cornery1;
private double cornerx2;
private double cornery2;
private double cornerx3;
private double cornery3;
private double xtmax;
private double xtmin;
private double ytmax;
private double ytmin;
private Double[] corners;
public Triangle (double cornerx1, double cornery1, double cornerx2, double cornery2, double cornerx3, double cornery3){
corners = new Double [6];
corners[0] = cornerx1;
corners[1] = cornery1;
corners[2] = cornerx2;
corners[3] = cornery2;
corners[4] = cornerx3;
corners[5] = cornery3;
}
public void maxAndMinTriangle (){ // find the minimum and maximum of the plane according to this triangle
xtmax = corners[0];
for(int i=1;i < corners.length;i += 2){
if(corners[i] > xtmax){
xtmax = corners[i];
}
}
xtmin = corners[0];
for(int i=1;i < corners.length;i += 2){
if(corners[i] < xtmin){
xtmin = corners[i];
}
}
ytmax = corners[1];
for(int i=1;i < corners.length;i += 2){
if(corners[i] > ytmax){
ytmax = corners[i];
}
}
ytmin = corners[1];
for(int i=1;i < corners.length;i += 2){
if(corners[i] < ytmin){
ytmin = corners[i];
}
}
}
public double getXTMax (){
return xtmax;
}
public double getYTMax () {
return ytmax;
}
public double getXTMin() {
return xtmin;
}
public double getYTMin(){
return ytmin;
}
//public static boolean isLeft (double x1, double y1, double x2, double y2, double x3, double y3){
//return ( 0 <= ( ( x2 - x1 ) * ( y - y1) )- (( y2 - y1) * ( x - x1)));
//}
public boolean isLeft1 (double randX, double randY){ // find if this point is to the left of the first line
return ( 0 <= ( ( corners[2] - corners[0] ) * ( randY - corners[1]) )- (( corners[3] - corners[1]) * ( randX - corners[0])));
}
public boolean isLeft2 (double randX, double randY){ // find if this point is to the left of the second line
return ( 0 <= ( ( corners[4] - corners[0]) * ( randY - corners[1]) )- (( corners[5] - corners[1]) * ( randX - corners[0])));
}
public boolean isLeft3 (double randX, double randY){ // find if this point is to the left of the third line
return ( 0 <= ( ( corners[4] - corners[2] ) * ( randY - corners[3]) )- (( corners[5] - corners[3]) * ( randX - corners[2])));
}
public boolean outsideTriangle ( double randX, double randY ){ // find if this point is inside of the triangle
int counter = 0;
if (isLeft1(randX,randY)){
counter++;
}
if (isLeft2(randX,randY)){
counter++;
}
if (isLeft3(randX,randY)){
counter++;
}
return counter == 2; // must be to the left of exactly 2 of the lines
}}
And then the AreaEstimator class:
public class AreaEstimator{
public static double[] maxAndMinValues (Circle[] circles,Triangle[] triangles){
// find maximum and minimum values according to all of the triangles and circles
double xmax = -100;
double ymax = -100;
double xmin = 100;
double ymin = 100;
for (int l=0; l < circles.length; l++){
if (xmax < circles[l].getXCMax()){
xmax = circles[l].getXCMax();
}
if (ymax < circles[l].getYCMax()){
ymax = circles[l].getYCMax();
}
if (xmin > circles[l].getXCMin()){
xmin = circles[l].getXCMin();
}
if (ymin > circles[l].getYCMin()){
ymin = circles[l].getYCMin();
}
}
for ( int m = 0; m < triangles.length; m++){
if(xmax < triangles[m].getXTMax()){
xmax = triangles[m].getXTMax();
}
if(ymax < triangles[m].getYTMax()){
ymax = triangles[m].getYTMax();
}
if(xmin > triangles[m].getXTMin()){
xmin = triangles[m].getXTMin();
}
if(ymin > triangles[m].getYTMin()){
ymin = triangles[m].getYTMin();
}
}
double[] result = new double [4];
result[0] = xmax;
result[1] = ymax;
result[2] = xmin;
result[3] = ymin;
return result;
}
public static void main (String[] args) {
double numThrows = Integer.parseInt(args[0]); // initialize amount of throws
if (numThrows <= 0){
throw new IllegalArgumentException();
}
int countCircles = 0; // find the amount of circles given
for ( int i = 1; i<args.length; i++){
if(args[i].equals("circle")){
countCircles++;
}
}
Circle[] circles = new Circle [countCircles];
for ( int i = 1; i<args.length; i++){
if (args[i].equals("circle")){
for ( int k = 0; k< countCircles; k++){
double xcenter = Double.parseDouble(args[i+1]);
double ycenter = Double.parseDouble(args[i+2]);
double radius = Double.parseDouble(args[i+3]);
circles[k] = new Circle (xcenter, ycenter, radius); //values associated with this circle
circles[k].maxAndMinCircle();//max and min value of the circle itself
}
}
}
int countTriangles = 0; // find the amount of the triangles given
for ( int i = 1; i < args.length; i++){
if(args[i].equals("triangle")){
countTriangles++;
}
}
Triangle[] triangles = new Triangle [countTriangles];
for ( int i = 1; i<args.length; i++){
if (args[i].equals("triangle")){
for ( int p = 0; p< countTriangles; p++){
double cornerx1 = Double.parseDouble(args[i+1]);
double cornery1 = Double.parseDouble(args[i+2]);
double cornerx2 = Double.parseDouble(args[i+3]);
double cornery2 = Double.parseDouble(args[i+4]);
double cornerx3 = Double.parseDouble(args[i+5]);
double cornery3 = Double.parseDouble(args[i+6]);
triangles[p] = new Triangle (cornerx1, cornery1, cornerx2, cornery2, cornerx3, cornery3);
//values associated with this triangle
triangles[p].maxAndMinTriangle(); //max and min value of the triangle itself
}
}
}
boolean dartsInOverlap = true;
double countInOverlap = 0; // initialize amount of darts in the overlapping shape
double[]result = maxAndMinValues(circles,triangles);
for(int i= 0;i < numThrows;i++){
double randX= (Math.random() * (result[0]-result[2]) + result[2]) ; // generate a random x value
double randY= (Math.random() * (result[1]-result[3])+ result[3]); // generate a random y value
for ( int h = 0; h < circles.length && dartsInOverlap; h++){
if (circles[h].outsideCircle(randX, randY)){
dartsInOverlap = false; // if the point is outside of the circle, it returns false
}
}
for ( int q = 0; q < triangles.length && dartsInOverlap; q++){
if (triangles[q].outsideTriangle(randX, randY)){
dartsInOverlap = false; // if the point is outside of the triangle, it returns false
}
}
if (dartsInOverlap){
countInOverlap++; // counts up the amount of points in the overlapping shape
}
dartsInOverlap = true;
}
System.out.println("This many darts were in the overlap between the shapes:" + countInOverlap);
// counts up the amount of points in the overlapping shape
System.out.println("The estimated overlapped areas is" + (result[0]-result[2])*(result[1]-result[3]) *(countInOverlap/numThrows));
//finds estimated area
}}
My code has worked for a few test cases, if in the command line there is only a circle and triangle entered, or only a sole circle. A triangle by itself or any other combination will give me answers far from the desired area estimation. I have looked and reviewed my code, and it all seems logical. So, where in my code could the problem persist? Any help would be appreciated.
There is at least a typo in maxAndMinTriangle. You wrote a 1 where you need a 0
xtmax = corners[0];
for(int i=1;i < corners.length;i += 2){
...
xtmin = corners[0];
for(int i=1;i < corners.length;i += 2){
it should be
xtmax = corners[0];
for(int i=0;i < corners.length;i += 2){
...
xtmin = corners[0];
for(int i=0;i < corners.length;i += 2){

Categories