Error in plotting graphs with discontinuities in Java? - java

I am trying to create a graphing calculator applet using Java. I am having trouble plotting graphs that contain discontinuities such as holes and asymptotes. Here is the code I have for graphs with asymptotes so far:
for (int i = 1; i < size; i++) {
x1 = round((startX + ((graphdata.get(i - 1)).getX()) * scale));
y1 = round((startY - ((graphdata.get(i - 1)).getY()) * scale));
x2 = round((startX + ((graphdata.get(i)).getX()) * scale));
y2 = round((startY - ((graphdata.get(i)).getY()) * scale));
for (int j = 0; j < VertAsympArray.size(); j++)
{
if(Math.abs((round(graphdata.get(i).getX(),3)) - (VertAsympArray.get(j))) > epsilon && Math.abs((round(graphdata.get(i-1).getX(),3)) - (VertAsympArray.get(j))) > epsilon ){
System.out.println("Drawing points : x1 : " + round(graphdata.get(i-1).getX(),3) + ", y1 :" + round(graphdata.get(i-1).getY(),3) + "; x2 : " + round(graphdata.get(i).getX(),3) + ", y2 : " + round(graphdata.get(i).getY(),3) );
g.drawLine(x1, y1, x2, y2);
}
else
System.out.println("VertAsympArray : " + VertAsympArray.get(j) + "; Function x value : " + round(graphdata.get(i).getX(),3));
}
}
Even though I removed the values that make the function the user inputs undefined, for some reason a straight line is drawn connecting the last lowest point on the graph to the next highest point. Here is how a graph looks like for ((x-1)(x+3))/((x+1)(x-6)) around the x = 6 asymptote:
The straight red line is not any asymptote I drew in, it is showing up as part of the function, which is wrong. How do I get rid of it/is there a better way to graph asymptotes?

Related

How do I apply a mathematical equation to each number in a for loop?

I've done some searching around and tried some solutions I've found, but a lot of them result in the same problem I am having. I'd like to apply a mathematical equation to each number of a for loop. The problem I am having is that the equation only occurs on the last number in that for loop. For example:
for (int i = 3; i <= 5; i++)
{
radius = i;
area = (Math.PI * (radius * radius));
System.out.println (radius)
}
My code is much more extensive than this, but this is the part I am having issues with. It prints:
3
4
5
Radius: 5
Area: 78.53981633974483
I tried using for each loop, while loop, putting the numbers in a variable to pull from, I'm kind of at my wits end on what to try myself without asking. I'd like the for loop to look like:
3
Radius: 3
Area: //... the area with radius 3...
4
Radius: 4
Area: //... the area with radius 4...
5
Radius: 5
Area: //...area with radius 5...
How would I go about going through each iteration of the for loop and apply the mathematical equation to it?
You did not post the full code, but from your output one can guess you have something like this:
int radius = 0;
double area = 0.0;
for (int i = 3; i <= 5; i++)
{
radius = i;
area = (Math.PI * (radius * radius));
System.out.println (radius)
}
System.out.println("Radius: " + radius);
System.out.println("Area: " + area);
With that your program loops over i = 3, 4, 5; for each i it calculates the area and prints the radius.
Only when the loop is over it prints radius and area - and exactly that is what you see in the output.
Change your code as commented by Federico to look like this:
int radius = 0;
double area = 0.0;
for (int i = 3; i <= 5; i++)
{
radius = i;
area = (Math.PI * (radius * radius));
System.out.println("Radius: " + radius);
System.out.println("Area: " + area);
}
Then it will loop over the same values, and for each perform the calculation and print the result.
Assuming you are using java 8, take advantage of it.
IntStream
.range(3, 6)
.forEach(radius -> {
float area = (float) (Math.PI * (radius * radius));
System.out.println("Radius: " + radius);
System.out.println("Area: " + area);
});

Attempting to return a float[] from a method in Java

I'm writing a game and working on collisions. Currently, I'm trying to use the tileCollision function to return a 1-dimensional array containing 2 numbers; the coordinates of the corner. (represented in the program by cX and cY)
I expected this to run smoothly: that is, to return {-999, -999} if it wasn't colliding, and to return a valid set of coordinates otherwise. Unfortunately, IntelliJ tells me that the goodCX and goodCY variables "might not have been initialised" which I do not know how to solve. Running the program gives me the same error.
The Tile class can be treated as a class containing an X value, a Y value, and a texture. The t.texture.width & t.texture.height should be set to 50 to make it simpler to understand. Entity can be assumed as a class containing variables named x, y, vx, vy, and a "texture" whose dimensions should be 20x20. I use Java with the Processing 3 library to render my code and am happy to provide extra info if needed.
The main problem is less with those rather than the "might not have been initialised" problem, though.
Please, go easy on me, and if possible, don't use anything wildly outside the realm of what is demonstrated in my code. I am an amateur programmer, and while I have been programming for a while, am not exactly professional.
Here's my code:
public float[] tileCollision(Tile t)
{
boolean isCollide = false;
float tX = t.eX;
float tX2 = t.eX + t.texture.width;
float tY = t.eY;
float tY2 = t.eY + t.texture.height;
float[] cX = new float[]{this.x + this.vx, this.x + this.texture.width + this.vx};
float[] cY = new float[]{this.y + this.vy, this.y + this.texture.height + this.vy};
float[] bad = new float[]{-999, -999};
float goodCX, goodCY;
System.out.println("\nCollisions Testing Names:");
System.out.println(this);
System.out.println(t);
for(int i = 0; i < 2; i ++)
{
for(int i_ = 0; i_ < 2; i_ ++)
{
System.out.println("\nCollisions Testing:");
System.out.println("Entity X: " + cX[i]);
System.out.println("Entity Y: " + cY[i_]);
System.out.println("Tile Xs: " + tX + ", " + tX2);
System.out.println("Tile Ys: " + tY + ", " + tY2);
if( ( (tX <= cX[i]) && (cX[i] <= tX2) ) && ( (tY <= cY[i_]) && (cY[i_] <= tY2) ) )
{
isCollide = true;
goodCX = cX[i];
goodCY = cY[i_];
}
}
}
System.out.println("Am I colliding?\n>>> " + isCollide);
if(isCollide)
{
return new float[]{goodCX, goodCY};
}
else { return(bad); }
}
The problem resides in the fact that you only assign (and first-assign, and hence, initialize) your goodCX and goodCY variables inside a complex if nested inside your for loops. Then, if(isCollide), you will attempt to return them, but there is no way the compiler can infer any kind of connection between the complex if condition you have, and the isCollide condition, so you may be returning unassigned references.
To resolve this, simply make a default initialization of your float references at the top, as follows:
float goodCX = 0.0;
float goodCY = 0.0;
If the collision check do not evaluate true GoodCX and GoodCY will never be initialized. You will have problems trying to return "new float[]{goodCX, goodCY}". Try initializing your GoodCX and GoodCY with -999. You will also be able to simplify your code with that:
public float[] tileCollision(Tile t)
{
boolean isCollide = false;
float tX = t.eX;
float tX2 = t.eX + t.texture.width;
float tY = t.eY;
float tY2 = t.eY + t.texture.height;
float[] cX = new float[]{this.x + this.vx, this.x + this.texture.width + this.vx};
float[] cY = new float[]{this.y + this.vy, this.y + this.texture.height + this.vy};
float goodCX = -999;
float goodCY = -999;
System.out.println("\nCollisions Testing Names:");
System.out.println(this);
System.out.println(t);
for(int i = 0; i < 2; i ++)
{
for(int i_ = 0; i_ < 2; i_ ++)
{
System.out.println("\nCollisions Testing:");
System.out.println("Entity X: " + cX[i]);
System.out.println("Entity Y: " + cY[i_]);
System.out.println("Tile Xs: " + tX + ", " + tX2);
System.out.println("Tile Ys: " + tY + ", " + tY2);
if( ( (tX <= cX[i]) && (cX[i] <= tX2) ) && ( (tY <= cY[i_]) && (cY[i_] <= tY2) ) )
{
goodCX = cX[i];
goodCY = cY[i_];
}
}
}
return new float[]{goodCX, goodCY};
}
Intellij is giving you that response because the variables are declared but not initialized. You need to define them with some default state or modify the code that follows to ensure they're initialized.

Making a circle in an array (Tile based game light map)

I am making a tiled based game in java and I want to make a light map.
I am having some issues. I have the lightmap array that has lights placed on it that affect the array. Lights emit in a circle shape. It seems ok so far but its not exactly what I wanted.
Here is my code so far:
for(float i = 0; i < strength + 1; i++){
for(double u = 0.0f; u < 360; u += 0.5){
double angle = u * Math.PI / 180;
int x2 = (int)(x + i * Math.cos(angle));
int y2 = (int)(y + i * Math.sin(angle));
if(map[y2][x2] > 1 - 1 / i)
map[y2][x2] = 1 - 1 / i;
}
}
Result:
As you can see in the result, it seems as though the light is expanding too much on the bottom left side (red x's). How do I fix this?
Background info:
Strength:
The radius of how far the light reaches. This also
determines how bright the light will be at each tile of the array.
The Array "map" is a 2D float array. The engine I am using uses float
values for the alpha channel. The range is 0 (completely transparent)
to 1 (completely opaque).
Solution (Thanks to Gene):
for(int x2 = -strength; x2 <= strength; x2++){
for (int y2 = -strength; y2 <= strength; y2++) {
double r = Math.sqrt(x2 * x2 + y2 * y2);
double inv_rad = r <= strength + 1 ? 1 / r : 0;
if(map[y + y2][x + x2] > 1 - (float) inv_rad)
map[y + y2][x + x2] = 1 - (float) inv_rad;
}
}
Your algorithm suffers from integer truncation of the map indicies. Try it the other away around. Compute the distance from each pixel in a square surrounding the center to the center. From this distance calculate what the intensity ought to be. It will be something like this:
for (x = -R; x <= R; x++)
for (y = -R; y <= R; y++) {
double r = Math.sqrt(x * x + y * y);
double inv_rad = r <= R ? 1 / r : 0; // truncate outside radius R
map[yc + y][xc + x] = 1 - inv_rad;
}
Here xc and yc are the integer center coordinates. R is the half-size of the box around the center.
when i try to add this to my project i only get o.o back
the values i entered where 500, 500,50
private float map[][] = new float[1000][1000];
public void test(int x, int y, float strength){
public void addLight(int x,int y,int strength ){
for(int x2 = -strength; x2 <= strength; x2++){
for (int y2 = -strength; y2 <= strength; y2++) {
double r = Math.sqrt(x2 * x2 + y2 * y2);
double inv_rad = r <= strength + 1 ? 1 / r : 0;
if(map[y + y2][x + x2] > 1 - (float) inv_rad)
map[y + y2][x + x2] = 1 - (float) inv_rad;
System.out.println(map[y + y2][x + x2]);
}
}
}

Compare two screenshots doesn't work correctly-java

i am trying to make two screenshots with 6 seconds difference, to see if there is some changes on the website.
But my code says me that the screenshots are always different, even if i test it without any changing on the screen.
what am i doing wrong?
Toolkit toolkit = Toolkit.getDefaultToolkit();
Dimension screensize = toolkit.getScreenSize();
Rectangle rectangle = new Rectangle(0,0,screensize.width,screensize.height);
Robot robot = new Robot();
BufferedImage image1 = robot.createScreenCapture(rectangle);
System.out.println("screenshot "+i+"");
Thread.sleep(6000);
BufferedImage image2 = robot.createScreenCapture(rectangle);
System.out.println("screenshot "+(i+10)+"");
int x1 = image1.getWidth();
int x2 = image2.getWidth();
if ( x1 != x2 ) {
System.out.println( "Widths are different: " + x1 + " != " + x2 );
return;
}
int y1 = image1.getHeight();
int y2 = image2.getHeight();
if ( y1 != y2 ) {
System.out.println( "Heights are different: " + y1 + " != " + y2 );
return;
}
for ( int x = 0; x < x1; x++ ) {
for ( int y = 0; y < y1; y++ ){
int p1 = image1.getRGB( x, y );
int p2 = image2.getRGB( x, y );
if ( p1 != p2 ) {
System.out.println("Pixel is different at x/y " + x + "/" + y + ": " + p1 + " != " + p2 );
return;
}
}
}
System.out.println( "Images are identical" );
I tried your code and my pixel is different because of a blinking cursor in Eclipse Console.
Then I had a problem with an animated icon (process explorer in task bar)
Finally it said Image identical.
Note : Mouse isn't part of the thing :
Creates an image containing pixels read from the screen. This image does not include the mouse cursor.

Trouble calculating the distance function in bezier clipping

I'm attempting to implement a curve interesection algorithm known as bezier clipping, which is described in a section towards the end of this article (though the article calls it "fat line clipping"). I've been following through the article and source code of the example (available here).
Note: Additional sources include this paper. More will be posted if I can find them.
A central part of this algorithm is calculating a "distance function" between curve1 and a "baseline" of curve2 (which is a line from one end point of curve2 to another). So I'd have something to compare my results to, I used the curves from the source code of the first example. I managed to replicate the shape of the distance function from the example, but the distance location of the function was off. Upon trying another curve, the distance function was nowhere near the other two curves, despite both clearly intersecting. I might be naive to the workings of this algorithm, but I think that would result in no intersection being detected.
From what I understand (which could quite possibly be wrong), the process of defining the distance function involves expressing the baseline of curve 2 in the form xa + yb + c = 0, where a2 + b2 = 1. The coefficients were obtained by rearranging the terms of the line in the form y = ux + v, where u is equal to the slope, and x and y are any points on the baseline. The formula can be rearranged to give v: v = y - ux. Rearranging the formula again, we obtain -u*x + 1*y - v = 0, where a = -u, b = 1, and c = -v. To assure the condition a2 + b2 = 1, the coefficients are divided by a scalar of Math.sqrt(uu + 1). This representation of the line is then substituted into the function of the other curve (the one the baseline isn't associated with) to get the distance function. This distance function is represented as a bezier curve, with yi = aPi x + b*Pi y + c and xi = (1 - t)x1 + tx2, where t is equal to 0, 1/3, 2/3, and 3m x1 and x2 are the endpoints of the baseline, and Pi are the control points of the curve1.
Below are a few cuts of the source code of the example program (written in the language processing) involved with calculating the distance function, which, oddly, uses a slightly different approach to the above paragraph for calculating the alternative representation of the baseline.
/**
* Set up four points, to form a cubic curve, and a static curve that is used for intersection checks
*/
void setupPoints()
{
points = new Point[4];
points[0] = new Point(85,30);
points[1] = new Point(180,50);
points[2] = new Point(30,155);
points[3] = new Point(130,160);
curve = new Bezier3(175,25, 55,40, 140,140, 85,210);
curve.setShowControlPoints(false);
}
...
flcurve = new Bezier3(points[0].getX(), points[0].getY(),
points[1].getX(), points[1].getY(),
points[2].getX(), points[2].getY(),
points[3].getX(), points[3].getY());
...
void drawClipping()
{
double[] bounds = flcurve.getBoundingBox();
// get the distances from C1's baseline to the two other lines
Point p0 = flcurve.points[0];
// offset distances from baseline
double dx = p0.x - bounds[0];
double dy = p0.y - bounds[1];
double d1 = sqrt(dx*dx+dy*dy);
dx = p0.x - bounds[2];
dy = p0.y - bounds[3];
double d2 = sqrt(dx*dx+dy*dy);
...
double a, b, c;
a = dy / dx;
b = -1;
c = -(a * flcurve.points[0].x - flcurve.points[0].y);
// normalize so that a² + b² = 1
double scale = sqrt(a*a+b*b);
a /= scale; b /= scale; c /= scale;
// set up the coefficients for the Bernstein polynomial that
// describes the distance from curve 2 to curve 1's baseline
double[] coeff = new double[4];
for(int i=0; i<4; i++) { coeff[i] = a*curve.points[i].x + b*curve.points[i].y + c; }
double[] vals = new double[4];
for(int i=0; i<4; i++) { vals[i] = computeCubicBaseValue(i*(1/3), coeff[0], coeff[1], coeff[2], coeff[3]); }
translate(0,100);
...
// draw the distance Bezier function
double range = 200;
for(float t = 0; t<1.0; t+=1.0/range) {
double y = computeCubicBaseValue(t, coeff[0], coeff[1], coeff[2], coeff[3]);
params.drawPoint(t*range, y, 0,0,0,255); }
...
translate(0,-100);
}
...
/**
* compute the value for the cubic bezier function at time=t
*/
double computeCubicBaseValue(double t, double a, double b, double c, double d) {
double mt = 1-t;
return mt*mt*mt*a + 3*mt*mt*t*b + 3*mt*t*t*c + t*t*t*d; }
And here is the class (an extension of javax.swing.JPanel) I wrote to recreate the above code:
package bezierclippingdemo2;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JPanel;
public class ReplicateBezierClippingPanel extends JPanel {
CubicCurveExtended curve1, curve2;
public ReplicateBezierClippingPanel(CubicCurveExtended curve1, CubicCurveExtended curve2) {
this.curve1 = curve1;
this.curve2 = curve2;
}
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setStroke(new BasicStroke(1));
g2d.setColor(Color.black);
drawCurve1(g2d);
drawCurve2(g2d);
drawDistanceFunction(g2d);
}
public void drawCurve1(Graphics2D g2d) {
double range = 200;
double t = 0;
double prevx = curve1.x1*(1 - t)*(1 - t)*(1 - t) + 3*curve1.ctrlx1*(1 - t)*(1 - t)*t + 3*curve1.ctrlx2*(1 - t)*t*t + curve1.x2*t*t*t;
double prevy = curve1.y1*(1 - t)*(1 - t)*(1 - t) + 3*curve1.ctrly1*(1 - t)*(1 - t)*t + 3*curve1.ctrly2*(1 - t)*t*t + curve1.y2*t*t*t;
for(t += 1.0/range; t < 1.0; t += 1.0/range) {
double x = curve1.x1*(1 - t)*(1 - t)*(1 - t) + 3*curve1.ctrlx1*(1 - t)*(1 - t)*t + 3*curve1.ctrlx2*(1 - t)*t*t + curve1.x2*t*t*t;
double y = curve1.y1*(1 - t)*(1 - t)*(1 - t) + 3*curve1.ctrly1*(1 - t)*(1 - t)*t + 3*curve1.ctrly2*(1 - t)*t*t + curve1.y2*t*t*t;
g2d.draw(new LineExtended(prevx, prevy, x, y));
prevx = x;
prevy = y;
}
}
public void drawCurve2(Graphics2D g2d) {
double range = 200;
double t = 0;
double prevx = curve2.x1*(1 - t)*(1 - t)*(1 - t) + 3*curve2.ctrlx1*(1 - t)*(1 - t)*t + 3*curve2.ctrlx2*(1 - t)*t*t + curve2.x2*t*t*t;
double prevy = curve2.y1*(1 - t)*(1 - t)*(1 - t) + 3*curve2.ctrly1*(1 - t)*(1 - t)*t + 3*curve2.ctrly2*(1 - t)*t*t + curve2.y2*t*t*t;
for(t += 1.0/range; t < 1.0; t += 1.0/range) {
double x = curve2.x1*(1 - t)*(1 - t)*(1 - t) + 3*curve2.ctrlx1*(1 - t)*(1 - t)*t + 3*curve2.ctrlx2*(1 - t)*t*t + curve2.x2*t*t*t;
double y = curve2.y1*(1 - t)*(1 - t)*(1 - t) + 3*curve2.ctrly1*(1 - t)*(1 - t)*t + 3*curve2.ctrly2*(1 - t)*t*t + curve2.y2*t*t*t;
g2d.draw(new LineExtended(prevx, prevy, x, y));
prevx = x;
prevy = y;
}
}
public void drawDistanceFunction(Graphics2D g2d) {
double a = (curve1.y2 - curve1.y1)/(curve1.x2 - curve1.x1);
double b = -1;
double c = -(a*curve1.x1 - curve1.y1);
double scale = Math.sqrt(a*a + b*b);
a /= scale;
b /= scale;
c /= scale;
double y1 = a*curve2.x1 + b*curve2.y1 + c;
double y2 = a*curve2.ctrlx1 + b*curve2.ctrly1 + c;
double y3 = a*curve2.ctrlx1 + b*curve2.ctrly2 + c;
double y4 = a*curve2.x2 + b*curve2.y2 + c;
double range = 200;
double t = 0;
double prevx = t*range;
double prevy = (1 - t)*(1 - t)*(1 - t)*y1 + 3*(1 - t)*(1 - t)*t*y2 + 3*(1 - t)*t*t*y3 + t*t*t*y4;
for(t += 1.0/range; t < 1.0; t += 1.0/range) {
double x = t*range;
double y = (1 - t)*(1 - t)*(1 - t)*y1 + 3*(1 - t)*(1 - t)*t*y2 + 3*(1 - t)*t*t*y3 + t*t*t*y4;
g2d.draw(new LineExtended(prevx, prevy, x, y));
prevx = x;
prevy = y;
}
}
}
Where CubicCurveExtended and LineExtended are minor extensions of java.awt.geom.CubicCurve2D.Double and java.awt.geom.Line2D.Double. Before the curves are passed into the constructor, the curves are rotated uniformly so curve1's endpoints are level, resulting in a slope of zero for the baseline.
For an input of (485, 430, 580, 60, 430, 115, 530, 160) for curve 1 and (575, 25, 455, 60, 541, 140, 486, 210) for curve2 (keep in mind that these values are rotated by the negative angle between the endpoints of curve1), the result is shown below (the distance function is the relatively smooth looking curve off in the distance):
I'm really not sure what I got wrong. The y values seem to be arranged in the right pattern, but are distant from the two curves it's based on. I realize it's possible I have the x values might be arranged at intervals along the curve rather than the baseline, but the y values are what I'm really confused about. If someone can take a look at this and explain what I got wrong, I'd really appreciate it. Thanks for taking the time to read this rather lengthy question. If more details are needed, feel free to tell me in comments.
Update: I've tested the representation of the line I've calculated. The ax + by + c = 0 representation apparently still represents the same line, as I can still plug in x1 and get y1. Additionally, for any two coordinate pairs plugged into the function, f(x, y) = 0 holds. Furthermore, I've found both the representation described in the article and the one actually used in the source code interchangeably represent the same line. From all this, I can assume the problem doesn't lie in calculating the line. An additional point of interest
Your distance function should not necessarily be anywhere near your two original curves: It's using a completely different coordinate system, i.e. t vs D, as opposed to your original curves using x and y. [edit] i.e. t only goes up to 1.0, and measures how far along, as a ratio of the total length, you are along your curve, and D measuring the distance your curve2 is from curve1's baseline.
Also, when you say ""distance function" between curve1 and a "baseline" of curve2" I think you've mixed up curve1 and curve2 here as in your code you are clearly using the baseline of curve1.
Also the algorithm assumes that "every Bézier curve is fully contained by the polygon that connects all the start/control/end points, known as its "convex hull"" which [edit] in your case for curve1 is a triangle, where the control point for the second starting value is not a vertex. I'm not sure how this affects the algorithm though.
Otherwise, it looks like your distance calculations are fine (although you could really do with optimising things a bit :) ).

Categories

Resources