LIBGDX: How do I draw a filled polygon with the shaperenderer? - java

I have defined a shape using an array of vertices:
float[] points = new float[]{50,60,50,70,60,70, 60,60,50,60};
And I am drawing this here:
shapeRenderer.polygon(floatNew);
This just gives an outline of the shape.
How do I fill it with colour?
Thanks

Currently, ShapeRenderer supports polygon drawing (by line) but not filling.
This code is clipping the polygon on triangles, and then drawing each triangle separately.
Edit ShapeRenderer.java like this:
EarClippingTriangulator ear = new EarClippingTriangulator();
public void polygon(float[] vertices, int offset, int count)
{
if (shapeType != ShapeType.Filled && shapeType != ShapeType.Line)
throw new GdxRuntimeException("Must call begin(ShapeType.Filled) or begin(ShapeType.Line)");
if (count < 6)
throw new IllegalArgumentException("Polygons must contain at least 3 points.");
if (count % 2 != 0)
throw new IllegalArgumentException("Polygons must have an even number of vertices.");
check(shapeType, null, count);
final float firstX = vertices[0];
final float firstY = vertices[1];
if (shapeType == ShapeType.Line)
{
for (int i = offset, n = offset + count; i < n; i += 2)
{
final float x1 = vertices[i];
final float y1 = vertices[i + 1];
final float x2;
final float y2;
if (i + 2 >= count)
{
x2 = firstX;
y2 = firstY;
} else
{
x2 = vertices[i + 2];
y2 = vertices[i + 3];
}
renderer.color(color);
renderer.vertex(x1, y1, 0);
renderer.color(color);
renderer.vertex(x2, y2, 0);
}
} else
{
ShortArray arrRes = ear.computeTriangles(vertices);
for (int i = 0; i < arrRes.size - 2; i = i + 3)
{
float x1 = vertices[arrRes.get(i) * 2];
float y1 = vertices[(arrRes.get(i) * 2) + 1];
float x2 = vertices[(arrRes.get(i + 1)) * 2];
float y2 = vertices[(arrRes.get(i + 1) * 2) + 1];
float x3 = vertices[arrRes.get(i + 2) * 2];
float y3 = vertices[(arrRes.get(i + 2) * 2) + 1];
this.triangle(x1, y1, x2, y2, x3, y3);
}
}
}

You cant draw a filled Polygon with the shaperender yet. take a look at this from the bugtracker
You can also read that in the API.
public void polygon(float[] vertices)
Draws a polygon in the x/y plane. The vertices must contain at least 3
points (6 floats x,y). The ShapeRenderer.ShapeType passed to begin has
to be ShapeRenderer.ShapeType.Line.
API ShapeRender
Sure if its with ShapeType.Line you just get the outlines.
You need to draw it yourself with Triangles in that case. It should be possible to fill at least Triangles.
Maybe take a look at this from Stackoverflow: drawing-filled-polygon-with-libgdx

Edit your ShapeRenderer.java class replacing polygon() method with the following code:
public void polygon(float[] vertices, int offset, int count) {
if (currType != ShapeType.Filled && currType != ShapeType.Line)
throw new GdxRuntimeException(
"Must call begin(ShapeType.Filled) or begin(ShapeType.Line)");
if (count < 6)
throw new IllegalArgumentException(
"Polygons must contain at least 3 points.");
if (count % 2 != 0)
throw new IllegalArgumentException(
"Polygons must have an even number of vertices.");
checkDirty();
checkFlush(count);
final float firstX = vertices[0];
final float firstY = vertices[1];
if (currType == ShapeType.Line) {
for (int i = offset, n = offset + count; i < n; i += 2) {
final float x1 = vertices[i];
final float y1 = vertices[i + 1];
final float x2;
final float y2;
if (i + 2 >= count) {
x2 = firstX;
y2 = firstY;
} else {
x2 = vertices[i + 2];
y2 = vertices[i + 3];
}
renderer.color(color);
renderer.vertex(x1, y1, 0);
renderer.color(color);
renderer.vertex(x2, y2, 0);
}
} else {
for (int i = offset, n = offset + count; i < n; i += 4) {
final float x1 = vertices[i];
final float y1 = vertices[i + 1];
if (i + 2 >= count) {
break;
}
final float x2 = vertices[i + 2];
final float y2 = vertices[i + 3];
final float x3;
final float y3;
if (i + 4 >= count) {
x3 = firstX;
y3 = firstY;
} else {
x3 = vertices[i + 4];
y3 = vertices[i + 5];
}
renderer.color(color);
renderer.vertex(x1, y1, 0);
renderer.color(color);
renderer.vertex(x2, y2, 0);
renderer.color(color);
renderer.vertex(x3, y3, 0);
}
}
}
Usage:
gdx_shape_renderer.begin(ShapeType.Filled);
gdx_shape_renderer.setColor(fill_r, fill_g, fill_b, fill_a);
gdx_shape_renderer.polygon(vertices);
gdx_shape_renderer.end();
gdx_shape_renderer.begin(ShapeType.Line);
gdx_shape_renderer.setColor(border_r, border_g, border_b, border_a);
gdx_shape_renderer.polygon(vertices);
gdx_shape_renderer.end();

Related

How to optimize my drawing routine to rasterize triangles to the screen in Java

I'm currently programming a 3D software renderer where I am rasterizing triangles based on a function to take x and y coordinates to draw 3 lines to draw a triangle that works just fine. However, my code to interpolate through the triangle to fill it with the color of a BufferedImage is very costly and eats at the performance of my application. I was informed that instantiating a new Color object and using the drawLine() method to draw a pixel to the screen is very costly on the CPU. Is there any alternative to this drawing routine such as holding all possible RGB's/pixels on the screen in an array and calling from that to draw to the screen to limit the number of pixels drawn?
public static void drawTriangle(Graphics2D g2, double x1, double y1, double x2, double y2, double x3, double y3)
{
g2.setStroke(new BasicStroke(2));
g2.draw(new Line2D.Double(x1, y1, x2, y2));
g2.draw(new Line2D.Double(x2, y2, x3, y3));
g2.draw(new Line2D.Double(x3, y3, x1, y1));
}
public static void texturedTriangle(Graphics2D g2, int x1, int y1, double u1, double v1, int x2, int y2, double
u2, double v2, int x3, int y3, double u3, double v3, BufferedImage img, double visibility, boolean fog)
{
if(y2 < y1)
{
int temp = y1;
y1 = y2;
y2 = temp;
int tempx = x1;
x1 = x2;
x2 = tempx;
double tempu = u1;
u1 = u2;
u2 = tempu;
double tempv = v1;
v1 = v2;
v2 = tempv;
}
if(y3 < y1)
{
int temp = y1;
y1 = y3;
y3 = temp;
int tempx = x1;
x1 = x3;
x3 = tempx;
double tempu = u1;
u1 = u3;
u3 = tempu;
double tempv = v1;
v1 = v3;
v3 = tempv;
}
if(y3 < y2)
{
int temp = y2;
y2 = y3;
y3 = temp;
int tempx = x2;
x2 = x3;
x3 = tempx;
double tempu = u2;
u2 = u3;
u3 = tempu;
double tempv = v2;
v2 = v3;
v3 = tempv;
}
int dy1 = y2 - y1;
int dx1 = x2 - x1;
double dv1 = v2 - v1;
double du1 = u2 - u1;
int dy2 = y3 - y1;
int dx2 = x3 - x1;
double dv2 = v3 - v1;
double du2 = u3 - u1;
double tex_u, tex_v;
double dax_step = 0, dbx_step = 0, du1_step = 0, dv1_step = 0, du2_step = 0, dv2_step = 0;
if (dy1 != 0) dax_step = dx1 / (float)Math.abs(dy1);
if (dy2 != 0) dbx_step = dx2 / (float)Math.abs(dy2);
if (dy1 != 0) du1_step = du1 / (float)Math.abs(dy1);
if (dy1 != 0) dv1_step = dv1 / (float)Math.abs(dy1);
if (dy2 != 0) du2_step = du2 / (float)Math.abs(dy2);
if (dy2 != 0) dv2_step = dv2 / (float)Math.abs(dy2);
if(dy1 != 0)
{
for(int i = y1; i <= y2; i++)
{
int ax = (int)(x1 + (i - y1) * dax_step);
int bx = (int)(x1 + (i - y1) * dbx_step);
double tex_su = u1 + (float)(i - y1) * du1_step;
double tex_sv = v1 + (float)(i - y1) * dv1_step;
double tex_eu = u1 + (float)(i - y1) * du2_step;
double tex_ev = v1 + (float)(i - y1) * dv2_step;
if(ax > bx)
{
int temp = ax;
ax = bx;
bx = temp;
double temps = tex_su;
tex_su = tex_eu;
tex_eu = temps;
double tempv = tex_sv;
tex_sv = tex_ev;
tex_ev = tempv;
}
tex_u = tex_su;
tex_v = tex_sv;
double tstep = 1.0 / (float)(bx-ax);
double t = 0.0;
for(int j = ax; j < bx; j++)
{
tex_u = (1.0 - t) * tex_su + t * tex_eu;
tex_v = (1.0 - t) * tex_sv + t * tex_ev;
Color background = Color.black;
Color col = new Color(img.getRGB(
(int)Math.max(0,tex_u*(img.getWidth()-1)),
(int)Math.max(0,tex_v*(img.getHeight()-1))
));
col = blend(background, col,(float)visibility);
if(fog)
{
g2.setColor(col);
}
else
{
g2.setColor(new Color(img.getRGB(
(int)Math.max(0,tex_u*(img.getWidth()-1)),
(int)Math.max(0,tex_v*(img.getHeight()-1))
)));
}
g2.drawLine(j, i, j+1, i+1);
t += tstep;
}
}
}
dy1 = y3 - y2;
dx1 = x3 - x2;
dv1 = v3 - v2;
du1 = u3 - u2;
if (dy1 != 0) dax_step = dx1 / (float)Math.abs(dy1);
if (dy2 != 0) dbx_step = dx2 / (float)Math.abs(dy2);
du1_step = 0; dv1_step = 0;
if (dy1 != 0) du1_step = du1 /(float)Math.abs(dy1);
if (dy1 != 0) dv1_step = dv1 / (float)Math.abs(dy1);
if(dy1 != 0)
{
for(int i = y2; i <= y3; i++)
{
int ax = (int)(x2 + (float)(i - y2) * dax_step);
int bx = (int)(x1 + (float)(i - y1) * dbx_step);
double tex_su = u2 + (float)(i - y2) * du1_step;
double tex_sv = v2 + (float)(i - y2) * dv1_step;
double tex_eu = u1 + (float)(i - y1) * du2_step;
double tex_ev = v1 + (float)(i - y1) * dv2_step;
if(ax > bx)
{
int temp = ax;
ax = bx;
bx = temp;
double temps = tex_su;
tex_su = tex_eu;
tex_eu = temps;
double tempv = tex_sv;
tex_sv = tex_ev;
tex_ev = tempv;
}
tex_u = tex_su;
tex_v = tex_sv;
double tstep = 1.0/ (float)(bx-ax);
double t = 0.0;
for(int j = ax; j < bx; j++)
{
tex_u = (1.0 - t) * tex_su + t * tex_eu;
tex_v = (1.0 - t) * tex_sv + t * tex_ev;
Color background = Color.black;
Color col = new Color(img.getRGB(
(int)Math.max(0,tex_u*(img.getWidth()-1)),
(int)Math.max(0,tex_v*(img.getHeight()-1))
));
col = blend(background, col,(float)visibility);
if(fog)
{
g2.setColor(col);
}
else
{
g2.setColor(new Color(img.getRGB(
(int)Math.max(0,tex_u*(img.getWidth()-1)),
(int)Math.max(0,tex_v*(img.getHeight()-1))
)));
}
g2.drawLine(j, i, j+1, i+1);
t += tstep;
}
}
}
}
public static Color blend( Color c1, Color c2, float ratio )
{
if ( ratio > 1f ) ratio = 1f;
else if ( ratio < 0f ) ratio = 0f;
float iRatio = 1.0f - ratio;
int i1 = c1.getRGB();
int i2 = c2.getRGB();
int a1 = (i1 >> 24 & 0xff);
int r1 = ((i1 & 0xff0000) >> 16);
int g1 = ((i1 & 0xff00) >> 8);
int b1 = (i1 & 0xff);
int a2 = (i2 >> 24 & 0xff);
int r2 = ((i2 & 0xff0000) >> 16);
int g2 = ((i2 & 0xff00) >> 8);
int b2 = (i2 & 0xff);
int a = (int)((a1 * iRatio) + (a2 * ratio));
int r = (int)((r1 * iRatio) + (r2 * ratio));
int g = (int)((g1 * iRatio) + (g2 * ratio));
int b = (int)((b1 * iRatio) + (b2 * ratio));
return new Color( a << 24 | r << 16 | g << 8 | b );
}
}

Forcing a square to fit in a grid

The method is supposed to draw a square on a 10x10 grid using the length and x,y coordinate an user inputs and adjust the length in case the square doesn't fit.
I'm having trouble figuring out the math for adjusting the length to fit the grid.
For example, if the user inputs (x-7, y-2, length-4) my square goes out of the grid by 1.
Example
public static void drawSquare(int x, int y, int len) {
if(x+len>10)
len = Math.max(x, len)-Math.min(x, len);
if(y+len>10)
len = Math.max(y, len)-Math.min(y, len);
System.out.println("side length = " + len + ", area = " + len*len);
drawLine(x, y, x+len, y);
drawLine(x+len,y,x+len,y-len);
drawLine(x+len, y-len, x, y-len);
drawLine(x, y-len, x, y);
}
This should do the trick. Just think about how the drawsquare method should call another method drawLine. Think about how to find each point in a square using the two coordinates and the given length of the square, also using if statements to make sure it fits the graph
public class unit3frq {
public void drawSquare(int x, int y, int len) {
// first check whether it fits on the grid
int xsum = x + len; int ydiff = y - len;
if (xsum > 10) xsum = 10 - x; if (ydiff < 0) ydiff = 0 - y;
if ((x - xsum) > (y - ydiff)) xsum = ydiff+x-y;
else ydiff = xsum+y-x;
drawLine(x, y, x, ydiff); // go down
drawLine(x, y, xsum, y); // go right
drawLine(x, ydiff, xsum, ydiff); // down then right
drawLine(xsum, y, xsum, ydiff); // right then down
int side = xsum - x;
System.out.println("side length = " + side + ", area = " + Math.pow(side, 2));
}
public void drawLine(int x1, int y1, int x2, int y2) {
int xdiff = x2 - x1; int ydiff = y2 - y1;
if (xdiff < 0) xdiff = 0 - xdiff; if (ydiff < 0) ydiff = 0 - ydiff;
if (xdiff > ydiff) {
int x = x1; int y = y1;
while (x <= x2) {
System.out.println("(" + x + ", " + y + ")");
x++;
if (ydiff != 0) y += ydiff / xdiff;
}
} else {
int x = x1; int y = y1;
while (y <= y2) {
System.out.println("(" + x + ", " + y + ")");
y++;
if (xdiff != 0) x += xdiff / ydiff;
}
}
}
public static void main(String[] args) {
unit3frq u3 = new unit3frq();
u3.drawSquare(0, 0, 10);
}
}

StackOverflowError when using Flood Fill Algorithm

I'm trying to implement flood fill algorithm using to fill the closed shape with specific color.
I think my code is worked out, but i don't know why are"StackOverflowError" rising up !!
i looked for the solution more and more but without finding the perfect answer.
public void paintComponent(Graphics g){
indecies.clear();
float x1 = 20;
float y1 = 20;
float x2 = 350;
float y2 = 20;
/* put the points of first line in ArraList */
for(int i = (int) x1; i < x2 ; i++){
index = (int) (i + y1 * img.getWidth());
list.add(index);
}
/***************************************************/
x1 = 350;
y1 = 20;
x2 = 100;
y2 = 100;
/* put the points of second line in ArraList */
for(int i = (int) y1; i <= y2 ; i++){
index = (int) (x1 * img.getWidth());
list.add(index);
}
/***************************************************/
x1 = 100;
y1 = 100;
x2 = 20;
y2 = 100;
/* put the points of the third line in ArraList */
for(int i = (int) x2; i < x1 ; i++){
index = (int) (i + y1 * img.getWidth());
list.add(index);
}
/*****************************************************/
x1 = 20;
y1 = 100;
x2 = 20;
y2 = 20;
/* put the points of the forth line in ArraList */
for(int i = (int) y2; i < y1 ; i++){
index = (int) (x1 * img.getWidth());
list.add(index);
}
/**************************************************/
/* Get each pixel from ArrayList of indecies then print into data raster of image */
for (Integer integer : indecies) {
pixels[integer] = Color.yellow.getRGB();
}
/* Flood fill recursive algorithm */
/* border color is yellow */
/* green is the new colow must be filled inside the shape */
fill(50, 50, Color.yellow.getRGB(), Color.green.getRGB());
g.drawImage(img, 0, 0, this);
}
Here is the fill method !!
public void fill(int x, int y, int borderColor, int newColor){
if(x >= 0 && x < width && y >= 0 && y < height){
int index = x + y * width;
if(pixels[index] != borderColor && pixels[index] != newColor){
pixels[index] = newColor;
fill(x, y - 1, borderColor, newColor);
fill(x, y + 1, borderColor, newColor);
fill(x + 1, y, borderColor, newColor);
fill(x - 1, y, borderColor, newColor);
}
}
}
Exception Details ..
java.lang.StackOverflowErrorjava.lang.StackOverflowErrorjava.lang.StackOverflowErrorjava.lang.StackOverflowErrorjava.lang.StackOverflowErrorjava.lang.StackOverflowError
at java.nio.Buffer.limit(Buffer.java:274)
at java.nio.Buffer.<init>(Buffer.java:201)
at java.nio.CharBuffer.<init>(CharBuffer.java:281)
at java.nio.HeapCharBuffer.<init>(HeapCharBuffer.java:70)
at java.nio.CharBuffer.wrap(CharBuffer.java:373)
at sun.nio.cs.StreamEncoder.implWrite(StreamEncoder.java:265)
at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:125)
at java.io.OutputStreamWriter.write(OutputStreamWriter.java:207)
at java.io.BufferedWriter.flushBuffer(BufferedWriter.java:129)
at java.io.PrintStream.write(PrintStream.java:526)
at java.io.PrintStream.print(PrintStream.java:669)
at java.io.PrintStream.println(PrintStream.java:823)
at java.lang.Throwable$WrappedPrintStream.println(Throwable.java:748)
at java.lang.Throwable.printStackTrace(Throwable.java:655)
at java.lang.Throwable.printStackTrace(Throwable.java:643)
at java.lang.Throwable.printStackTrace(Throwable.java:634)
at FillColorAlgorithm.fill(FillColorAlgorithm.java:170)
at FillColorAlgorithm.fill(FillColorAlgorithm.java:162)
......... etc
public void floodFill(int x, int y, int borderColor, int fillColor, int imgWidth, int imgHeight){
Queue<java.awt.Point> nodesList = new LinkedList<>();
if(borderColor == fillColor) return;
if(x >= 0 && x < imgWidth && y >= 0 && y < imgHeight){
int index = x + y * imgWidth;
if(pixels[index] == fillColor) return;
nodesList.add(new java.awt.Point(x, y));
}
while(!nodesList.isEmpty()) {
java.awt.Point currentNode = nodesList.element();
int index = currentNode.x + currentNode.y * imgWidth;
if(pixels[index] != fillColor){
java.awt.Point westNode = currentNode;
java.awt.Point eastNode = currentNode;
westNode = MoveWest(westNode, borderColor);
eastNode = MoveEast(eastNode, borderColor);
for (int j = westNode.x + 1; j < eastNode.x; j++) {
index = j + currentNode.y * imgWidth;
pixels[index] = fillColor;
java.awt.Point northNode = new java.awt.Point(j, currentNode.y - 1);
java.awt.Point southNode = new java.awt.Point(j, currentNode.y + 1);
index = northNode.x + northNode.y * imgWidth;
if(northNode.y >= 0 && pixels[index] != fillColor && pixels[index] != borderColor) nodesList.add(northNode);
index = southNode.x + southNode.y * imgWidth;
if(southNode.y < imgHeight && pixels[index] != fillColor && pixels[index] != borderColor) nodesList.add(southNode);
}
}
nodesList.remove();
}
}
java.awt.Point MoveWest(java.awt.Point w, int borderColor){
int index;
do{
--w.x;
index = w.x + w.y * width;
}
while(w.x >= 0 && pixels[index] != borderColor);
return new java.awt.Point(w.x, w.y);
}
java.awt.Point MoveEast(java.awt.Point e, int borderColor){
int index;
do{
++e.x;
index = e.x + e.y * width;
}
while( e.x < width && pixels[index] != borderColor);
return new java.awt.Point(e.x, e.y);
}

Redrawing graph with new inputs, java graphics

I've been trying for hours to find the solution but with no results, so I have nowhere else to turn. I have a program that gathers data from user input and uses it to draw a graph. Every time the user changes the data in the text fields and presses submit I want a new graph drawn and get rid of the old one.
Currently nothing happens with the graph when I press submit with new inputs even though the inputs do change in both classes. For debugging purposes I had a
System.out.println(graphPoints.size());
in my DrawComponent class. I noticed that for everytime I press submit the amount of times graphPoints.size() gets printed out increases with one, so I assume thats no good. I really dont know where to go from here though.
Here is my actionlistener where I call the GraphPanel class:
query.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
textarea1.setText("");
textarea1.append(run(tickerInput,tickerInput2,startInput,slutInput,valuta));
Mainpanel.repaint();
if(testx != null)
testx.removeAll();
testx = new GraphPanel(first,second);
addItem(Mainpanel, testx, 0,20, 20,20, GridBagConstraints.SOUTH);
minframe.setVisible(true);
minframe.repaint();
minframe.pack();
testx.repaint();
And here is my GraphPanel class:
public GraphPanel(ArrayList<Double> first, ArrayList<Double> second) {
first1 = first;
Collections.reverse(first1);
second1 = second;
Collections.reverse(second1);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
double xScale = ((double) getWidth() - (2 * padding) - labelPadding) / (first1.size() - 1);
double yScale = ((double) getHeight() - 2 * padding - labelPadding) / (getMaxScore() - getMinScore());
ArrayList<Point> graphPoints = new ArrayList<>();
for (int i = 0; i < first1.size(); i++) {
int x1 = (int) (i * xScale + padding + labelPadding);
int y1 = (int) ((getMaxScore() - first1.get(i)) * yScale + padding);
graphPoints.add(new Point(x1, y1));
}
ArrayList<Point> graphPoints2 = new ArrayList<>();
graphPoints2.clear();
for (int i = 0; i < second1.size(); i++) {
int x1 = (int) (i * xScale + padding + labelPadding);
int y1 = (int) ((getMaxScore() - second1.get(i)) * yScale + padding);
graphPoints2.add(new Point(x1, y1));
}
g2.setColor(Color.WHITE);
g2.fillRect(padding + labelPadding, padding, getWidth() - (2 * padding) - labelPadding, getHeight() - 2 * padding - labelPadding);
g2.setColor(Color.BLACK);
for (int i = 0; i < numberYDivisions + 1; i++) {
int x0 = padding + labelPadding;
int x1 = pointWidth + padding + labelPadding;
int y0 = getHeight() - ((i * (getHeight() - padding * 2 - labelPadding)) / numberYDivisions + padding + labelPadding);
int y1 = y0;
if (first1.size() > 0) {
g2.setColor(gridColor);
g2.drawLine(padding + labelPadding + 1 + pointWidth, y0, getWidth() - padding, y1);
g2.setColor(Color.BLACK);
String yLabel = ((int) ((getMinScore() + (getMaxScore() - getMinScore()) * ((i * 1.0) / numberYDivisions)) * 100)) / 100.0 + "";
FontMetrics metrics = g2.getFontMetrics();
int labelWidth = metrics.stringWidth(yLabel);
g2.drawString(yLabel, x0 - labelWidth - 5, y0 + (metrics.getHeight() / 2) - 3);
}
g2.drawLine(x0, y0, x1, y1);
}
g2.drawLine(padding + labelPadding, getHeight() - padding - labelPadding, padding + labelPadding, padding);
g2.drawLine(padding + labelPadding, getHeight() - padding - labelPadding, getWidth() - padding, getHeight() - padding - labelPadding);
Graphics g3 = g2;
Stroke oldStroke = g2.getStroke();
g2.setColor(lineColor);
g2.setStroke(GRAPH_STROKE);
System.out.println(graphPoints.size());
for (int i = 0; i < graphPoints.size() - 1; i++) {
int x1 = graphPoints.get(i).x;
int y1 = graphPoints.get(i).y;
int x2 = graphPoints.get(i + 1).x;
int y2 = graphPoints.get(i + 1).y;
g2.drawLine(x1, y1, x2, y2);
}
g3.setColor(Color.PINK);
for (int i = 0; i < graphPoints2.size() - 1; i++) {
int x1 = graphPoints2.get(i).x;
int y1 = graphPoints2.get(i).y;
int x2 = graphPoints2.get(i + 1).x;
int y2 = graphPoints2.get(i + 1).y;
g3.drawLine(x1, y1, x2, y2);
}
g2.setStroke(oldStroke);
g2.setColor(pointColor);
for (int i = 0; i < graphPoints.size(); i++) {
int x = graphPoints.get(i).x - pointWidth / 2;
int y = graphPoints.get(i).y - pointWidth / 2;
int ovalW = pointWidth;
int ovalH = pointWidth;
g2.fillOval(x, y, ovalW, ovalH);
}
for (int i = 0; i < graphPoints2.size(); i++) {
int x = graphPoints2.get(i).x - pointWidth / 2;
int y = graphPoints2.get(i).y - pointWidth / 2;
int ovalW = pointWidth;
int ovalH = pointWidth;
g3.fillOval(x, y, ovalW, ovalH);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(width, heigth);
}
private double getMinScore() {
double minScore =0;
if (Collections.min(first1)<=Collections.max(second1)){
minScore= Collections.min(first1)-10;
}
else{
minScore = Collections.min(second1)-10;
}
return minScore;
}
private double getMaxScore() {
double maxScore =0;
if (Collections.max(first1)>=Collections.max(second1)){
maxScore= Collections.max(first1)+10;
}
else{
maxScore = Collections.max(second1)+10;
}
return maxScore;
}
Sorry for the wall of code, I couldn't decide what was relevant and what isn't.
The main clue here is the repeated messages. Either paintComponent is getting called a bunch of times, or you have a bunch of components getting painted. From this block in the action listener, it looks like the later:
if(testx != null)
testx.removeAll();
testx = new GraphPanel(first,second);
addItem(Mainpanel, testx, 0,20, 20,20, GridBagConstraints.SOUTH);
It removes all of the children from testx, then makes a new one and adds it to Mainpanel. What it doesn't do is remove the old testx from Mainpanel, so they're building up.

Android Math does not work

private void gotoPos()
{
spaceX = x2 - x;
spaceY = y2 - y;
if (Math.abs(spaceX) >= Math.abs(spaceY)) {
xSpeed = Math.round(spaceX * (3/Math.abs(spaceX)));
ySpeed = Math.round(spaceY * (3/Math.abs(spaceX)));
}
With this code I want to move an object to the position x2 and y2. x and y is the current position of the object. spaceX is the space that is between the object and the x position it should go to. The same for spaceY.
But I don't want the object to move more than 3 Pixels per draw.
Example: object position: x = 35, y = 22
Point it should go to: x2 = 79, y2 = 46
space between them: spaceX = 79-35 = 44, spaceY = 46-22 = 24
spaceX is bigger then spaceY so:
xSpeed = 44 * (3/44) = 3, ySpeed = 24 * (3/44) = 1.63 = 2
But it does not work like this. When I start the app the object does not go to x2 and y2.
If I change
xSpeed = spaceX;
ySpeed = spaceY;
The object moves to the position but I do not want it to go there instantly
Complete Code:
public class Sprite
{
private boolean walking = true;
private int actionWalk = 0;
private Random rnd;
private int checkIfAction;
private int nextAction = 0;
static final private int BMP_COLUMNS = 4;
static final private int BMP_ROWS = 4;
private int[] DIRECTION_TO_SPRITE_SHEET = { 1, 0, 3, 2 };
public int x=-1;
private int y=-1;
public int xSpeed;
private int ySpeed;
private int width;
private int height;
private int bottomSpace;
private Bitmap bmp;
private GameView theGameView;
private int currentFrame=0;
private int x2, y2;
private boolean isTouched;
private int spaceX, spaceY;
D
public Sprite(GameView theGameView, Bitmap bmp)
{
this.theGameView = theGameView;
this.bmp = bmp;
this.width = bmp.getWidth() / BMP_COLUMNS;
this.height = bmp.getHeight() / BMP_ROWS;
rnd = new Random();
xSpeed = 0;
ySpeed = 0;
}
public void shareTouch(float xTouch, float yTouch)
{
x2 = (int) xTouch;
y2 = (int) yTouch;
isTouched = true;
}
private void gotoPos()
{
spaceX = x2 - x;
spaceY = y2 - y;
if (Math.abs(spaceX) >= Math.abs(spaceY)) {
xSpeed = Math.round(spaceX * (3/Math.abs(spaceX)));
ySpeed = Math.round(spaceY * (3/Math.abs(spaceX)));
}
else {
xSpeed = spaceX;
ySpeed = spaceY;
}
}
D
private void bounceOff()
{
bottomSpace = theGameView.getHeight() - y;
if (x > theGameView.getWidth() - (width * theGameView.getDensity()) - xSpeed - bottomSpace / 2 || x + xSpeed < bottomSpace / 2)
{
xSpeed = -xSpeed;
}
x = x + xSpeed;
if (y > theGameView.getHeight() - (height * theGameView.getDensity()) - ySpeed || y + ySpeed < theGameView.getHeight() / 2)
{
ySpeed = -ySpeed;
}
y = y + ySpeed;
currentFrame = ++currentFrame % BMP_COLUMNS;
}
d
public void onDraw(Canvas canvas)
{
if (x == -1)
{
x = (theGameView.getWidth() / 2);
y = (theGameView.getHeight() / 2 + theGameView.getHeight() / 4);
}
if (isTouched == true)
{
gotoPos();
}
/* if (nextAction == 100)
{
action();
nextAction = 0;
}
nextAction += 1;*/
bounceOff();
int sourceX, sourceY;
if (walking == true)
{
sourceX = currentFrame * width;
}
else
{
sourceX = 0;
}
sourceY = getAnimationRow() * height;
Rect source = new Rect(sourceX, sourceY, sourceX + width, sourceY + height);
Rect destine = new Rect(x, y, (int) (x + (width * theGameView.getDensity())), (int) (y + (height * theGameView.getDensity())));
canvas.drawBitmap(bmp, source, destine, null);
}
d
private int getAnimationRow()
{
double directionDouble = (Math.atan2(xSpeed, ySpeed) / (Math.PI / 2) + 2);
int spriteDir = (int) Math.round(directionDouble) % BMP_ROWS;
return DIRECTION_TO_SPRITE_SHEET[spriteDir];
}
}
Simple problem: you use integer arithmetic and don't understand this:
spaceX * (3/Math.abs(spaceX))
The result will be 0 in nearly all cases as 3/x with x > 3 is 0 all the time.
To make your program working use either floating point arithmetic or rewrite your formulas to work as expected.
To use floating point arithetic you have to change to
spaceX * (3.0/Math.abs(spaceX))
assuming that you variable spaceX is also floating point.
Also you can use
(spaceX * 3) / Math.abs(spaceX)
if you want to stay with integers (what I suppose).
Given points a Vector2d(x, y) and b Vector2d(x2, y2)-
Create a vector V from a to b by subtracting b from a as you did. Normalize vector V into a unit vector and multiply it with the distance you want. Then add the resulting vector to point a.
On update:
a.add(b.subtract(a).norm().multiply(d));
Depending on your vector implementation, modify properly the above pseudo code.
There is a logical fallacy in your code: what if Math.abs(spaceX) < Math.abs(spaceY))? Then your object would not move at all.
What you calculate, 'x-distance / y-distance', is usually considered angle, not speed. Speed is 'distance / time'. You can calculate the distance, and you should decide on a reasonable speed for your object. Since you know your fps -- 20 --, you can then calculate how many pixels your object needs to move in each frame.

Categories