Properly scaling x-axis in accordance with pixels (Java) - java

I am working on plotting a sin(x) graph for a school project. Currently I have everything working the way I want it to besides one thing: the scaling of the x axis.
Here is the code I am currently using:
int xStart = xShift;
int xEnd = xShift;
int yStart = getHeight() / 2;
int yEnd = getHeight() / 2;
int scale = getHeight() / 2;
double constraint = 0.80;
for (double i = Math.PI / 32; i <= Math.PI * 2; i+= Math.PI / 32){
xEnd += (getWidth() - (2 * xShift) / 64);
yEnd = (scale - ((int) Math.round(Math.sin(i) * scale * constraint))) ;
g.drawLine(xStart, yStart, xEnd, yEnd);
xStart = xEnd;
yStart = yEnd;
}
Which produces something that looks like this:
As you can see the red line indicating the sin graph ends short of where I need it to. For some reason I am unable to get the x coordinate of my 500x250 JFrame window to properly increment to the point where it will end at the proper position. I need it to stop where I have drawn the blue arrow, at the end of the gray line. What can I do to fix this? Thank you for your time and I appreciate any help offered.

The problem is,remove your Math.round() function,you see it is rounding of the values of the sin() function.This I know will generate error in the drawLine functionas it takes only integer arguments,to solve that type cast that to prevent lossy conversion.Like this:
g.drawLine((int) xStart,(int) yStart, (int) xEnd, (int) yEnd);

Related

Rotate player towards mouse

I want my player rotate towards mouse. Here's the code calculating the angle:
float angle = (float) Math.atan2(MouseInput.getMousePos().y - transform.position.y + transform.size.y / 2,
MouseInput.getMousePos().x - transform.position.x + transform.size.x / 2);
angle = (float) (angle * (180 / Math.PI));
if (angle < 0) {
angle = 360 + angle;
}
transform.rotation = 180 + angle;
And getMousePos() method (it just returns mouse pos relative to window):
public static Vector2 getMousePos() {
Point p = MouseInfo.getPointerInfo().getLocation();
return new Vector2(p.x - Game.w.getAccessToWindow(Acces.WINDOW_JFRAME_ACCES).getLocation().x,
p.y - Game.w.getAccessToWindow(Acces.WINDOW_JFRAME_ACCES).getLocation().y);
}
Can you tell me what's wrong with this code? Player isn't rotating properly.
I tried following this article: https://gamefromscratch.com/gamedev-math-recipes-rotating-to-face-a-point/
Update:
I found this post: Java 2d rotation in direction mouse point
Now I've updated my code to this:
int centerX = (int) (transform.size.x / 2);
int centerY = (int) (transform.size.x / 2);
int mouseX = (int) MouseInput.getMousePos().x;
int mouseY = (int) MouseInput.getMousePos().y;
double angle = Math.atan2(centerY - mouseY, centerX - mouseX) - Math.PI / 2;
transform.rotation = angle;
But still something is off. Try this code for yourself. Maybe I did something wrong somewhere else.

How do I do anti-aliasing in java? (WITHOUT built in methods)

I am going to try my best to give context for the below code. This is a method used to draw a circle and its center point in a 50x50 white square background. The following variables were used:
xc,yx - the center coordinates used to compute the circle
r - the radius of the circle
STEP - how often a new point is drawn on the circumference of the circle
x,y - the coordinates of each point that will make up the circle
Right now, my method uses a for loop to compute each points R,G, and B coordinates along the circumference of the circle based on the center point and the radius. What I am trying to do is anti-alias my output circle so that the round parts are not as jagged. However, I want to do this using only math and variables and I do not want to use any of Java's build in methods. Thank you to anyone who can help or point me in the right direction.
Below is my routine:
protected void proc_21() {
info = "Draw anti-aliased circle";
int xc = (int) rand(1, imgW - 2);
int yc = (int) rand(1, imgH - 2);
int r = (int) rand(4, 0.35f * (imgW + imgH));
int STEP = (2 * (int) Math.PI * r) * 57;
System.out.printf("circle centered at (%d,%d), radius = %d, draw in %d steps. \n", xc,yc,r,STEP);
for (int i = 0; i < STEP; i++) {
int x = (int) Math.round(xc + r * Math.cos(i));
int y = (int) Math.round(yc + r * Math.sin(i));
if (0 <= x && x < imgW) {
if ( 0 <= y && y < imgH) {
imgNew.setR(x, y, 0);
imgNew.setG(x, y, 0);
imgNew.setB(x, y, 1);
}
}
}
// set center to red
imgNew.setR(xc, yc, 1);
imgNew.setG(xc, yc, 0);
imgNew.setB(xc, yc, 0);
}

Processing, making an analog clock, the numbers

so, as an assaignment i want to make an analog clock, and i am pretty far. I only need the numbers around the clock, but i cant figure out how to make these. I have made some dots right now, but i want to replace theese with the numbers 1-12.. does any1 know an easy and fast way of doing this? my code is as following:
int cx, cy;
float secondsRadius;
float minutesRadius;
float hoursRadius;
float clockDiameter;
void setup() {
size(1366,768);
stroke(255);
float radius = min(width/1.2, height/1.2) / 2;
secondsRadius = radius * 0.72;
minutesRadius = radius * 0.60;
hoursRadius = radius * 0.50;
clockDiameter = radius * 1.8;
cx = width / 2;
cy = height / 2;
}
void draw() {
background(random(0,255),random(0,255),random(0,255));
// Draw the clock background
fill(0);
noStroke();
ellipse(cx, cy, clockDiameter, clockDiameter);
// Angles for sin() and cos() start at 3 o'clock;
// subtract HALF_PI to make them start at the top
float s = map(second(), 0, 60, 0, TWO_PI) - HALF_PI;
float m = map(minute() + norm(second(), 0, 60), 0, 60, 0, TWO_PI) - HALF_PI;
float h = map(hour() + norm(minute(), 0, 60), 0, 24, 0, TWO_PI * 2) - HALF_PI;
// Draw the hands of the clock
stroke(255);
strokeWeight(1);
line(cx, cy, cx + cos(s) * secondsRadius, cy + sin(s) * secondsRadius);
strokeWeight(2);
line(cx, cy, cx + cos(m) * minutesRadius, cy + sin(m) * minutesRadius);
strokeWeight(4);
line(cx, cy, cx + cos(h) * hoursRadius, cy + sin(h) * hoursRadius);
// Draw the dots arround the clock
strokeWeight(2);
beginShape(POINTS);
for (int a = 0; a < 360; a+=30) {
float angle = radians(a);
float x = cx + cos(angle) * secondsRadius;
float y = cy + sin(angle) * secondsRadius;
vertex(x, y);
}
endShape();
textSize(40);
text("Dank Clock", 570,40);
}
You already have a loop that goes around the clock and places dots at the clock positions. Now all you need is some logic that draws the hour at those positions.
Processing has a text() function that allows you to draw text (or numbers) to the screen. You can just call that instead of vertex() to draw the hours.
To get the hours to draw, just use an int variable that you increment each time through the loop. Something like this:
int hour = 3;
for (int a = 0; a < 360; a+=30) {
float angle = radians(a);
float x = cx + cos(angle) * secondsRadius;
float y = cy + sin(angle) * secondsRadius;
vertex(x, y);
fill(255);
text(hour, x, y);
hour++;
if(hour > 12){
hour = 1;
}
}
Notice that I'm starting at 3 because your angle starts at 0, which points all the way to the right. When the loop goes over the 12, I just start hour back over at 1.
You could probably also figure out a simple formula that maps from a to an hour, that way you don't have to do the incrementing yourself.

How to move waves(made with sine) from top of the picture to the bottom?

I'm trying to draw waves onto the sea, but I got no idea how to moves those from top to bottom. No matter what I change, they stay at the top of the picture.
Here's the code I'm using to draw the waves:
Dimension d = getSize();
int x, y, winWidth = d.width, winHeight = d.height;
int halfHeight = 10;
int lastX = 0, lastY = halfHeight;
double trajectory = 2 * Math.PI;
double factor = trajectory / 100;
for (x = 1; x <= winWidth; x++) {
double sine = Math.sin (x * factor) * halfHeight;
y = halfHeight - (int)sine;
graafika.drawLine (x, y, lastX, lastY);
lastX = x; lastY = y;
}
Here's a picture, how it looks at the moment.
Thanks for the help!
Use height?
graafika.drawLine (x, y+winHeight-20, lastX, lastY+winHeight-20);
You can just "mirror" the placement of the wave by replacing
y = halfHeight - (int)sine;
with
y = winHeight - (halfHeight - (int)sine);
This first places your sine wave at the very bottom, then moving it up a half sine wave, allowing the whole wave to be visible.

Barrel distortion correction algorithm to correct FishEye lens - failing to implement with Java

I have a large bulk of photographs taken with a fisheye lens. As I want to do some image-processing (e.g. edge detection) on the photos I want to remove the barrel distortion which effects my results heavily.
After some research and lots of read articles I found this page: They describe an algorithm (and some formulas) to solve this problem.
M = a *rcorr^3 + b * rcorr^2 + c * rcorr + d
rsrc = (a * rcorr^3 + b * rcorr^2 + c * rcorr + d) * rcorr
rsrc = distance of a pixel from the center of the source image
rcorr = distance of a pixel from the center in the corrected image
a,b,c = distortion of image
d = linear scaling of image
I used these formulas and tried to implement this in a Java application. Unfortunately it doesn't work and I failed to make it work. "Corrected" image look nothing like the original photograph and instead show some mysterious circles in the middle. Look here:
http://imageshack.us/f/844/barreldistortioncorrect.jpg/
(this used to be a photograph of a white cow in front a blue wall)
Here is my code:
protected int[] correction(int[] pixels) {
//
int[] pixelsCopy = pixels.clone();
// parameters for correction
double paramA = 0.0; // affects only the outermost pixels of the image
double paramB = -0.02; // most cases only require b optimization
double paramC = 0.0; // most uniform correction
double paramD = 1.0 - paramA - paramB - paramC; // describes the linear scaling of the image
//
for(int x = 0; x < dstView.getImgWidth(); x++) {
for(int y = 0; y < dstView.getImgHeight(); y++) {
int dstX = x;
int dstY = y;
// center of dst image
double centerX = (dstView.getImgWidth() - 1) / 2.0;
double centerY = (dstView.getImgHeight() - 1) / 2.0;
// difference between center and point
double diffX = centerX - dstX;
double diffY = centerY - dstY;
// distance or radius of dst image
double dstR = Math.sqrt(diffX * diffX + diffY * diffY);
// distance or radius of src image (with formula)
double srcR = (paramA * dstR * dstR * dstR + paramB * dstR * dstR + paramC * dstR + paramD) * dstR;
// comparing old and new distance to get factor
double factor = Math.abs(dstR / srcR);
// coordinates in source image
double srcXd = centerX + (diffX * factor);
double srcYd = centerY + (diffX * factor);
// no interpolation yet (just nearest point)
int srcX = (int)srcXd;
int srcY = (int)srcYd;
if(srcX >= 0 && srcY >= 0 && srcX < dstView.getImgWidth() && srcY < dstView.getImgHeight()) {
int dstPos = dstY * dstView.getImgWidth() + dstX;
pixels[dstPos] = pixelsCopy[srcY * dstView.getImgWidth() + srcX];
}
}
}
return pixels;
}
My questions are:
1) Is this formula correct?
2) Do I have made a mistake turning that formula into a piece of software?
3) There are other algorithms out there (e.g. How to simulate fisheye lens effect by openCV? or wiki/Distortion_(optics)), are they better?
Thanks for your help!
The main bug you have is that the algorithm specifies that r_corr and r_src are in units of min((xDim-1)/2, (yDim-1)/2). That needs to be done to normalise the calculation so that the parameter values are not dependent on the size of the source image. With the code as it is you'll need to use much smaller values for paramB, e.g. it worked ok for me with paramB = 0.00000002 (for an image with dimensions 2272 x 1704).
You also have a bug in calculating the difference from the center that causes the resulting image to be rotated 180 degree compared to the source image.
Fixing both these bugs should give you something like this:
protected static int[] correction2(int[] pixels, int width, int height) {
int[] pixelsCopy = pixels.clone();
// parameters for correction
double paramA = -0.007715; // affects only the outermost pixels of the image
double paramB = 0.026731; // most cases only require b optimization
double paramC = 0.0; // most uniform correction
double paramD = 1.0 - paramA - paramB - paramC; // describes the linear scaling of the image
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
int d = Math.min(width, height) / 2; // radius of the circle
// center of dst image
double centerX = (width - 1) / 2.0;
double centerY = (height - 1) / 2.0;
// cartesian coordinates of the destination point (relative to the centre of the image)
double deltaX = (x - centerX) / d;
double deltaY = (y - centerY) / d;
// distance or radius of dst image
double dstR = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
// distance or radius of src image (with formula)
double srcR = (paramA * dstR * dstR * dstR + paramB * dstR * dstR + paramC * dstR + paramD) * dstR;
// comparing old and new distance to get factor
double factor = Math.abs(dstR / srcR);
// coordinates in source image
double srcXd = centerX + (deltaX * factor * d);
double srcYd = centerY + (deltaY * factor * d);
// no interpolation yet (just nearest point)
int srcX = (int) srcXd;
int srcY = (int) srcYd;
if (srcX >= 0 && srcY >= 0 && srcX < width && srcY < height) {
int dstPos = y * width + x;
pixels[dstPos] = pixelsCopy[srcY * width + srcX];
}
}
}
return pixels;
}
With this version you can use parameter values from existing lens databases like LensFun (though you'll need to flip the sign of each parameter). The page describing the algorithm can now be found at http://mipav.cit.nih.gov/pubwiki/index.php/Barrel_Distortion_Correction
I think your circles are caused by this line:
double srcYd = centerY + (diffX * factor);
which I'm guessing should be:
double srcYd = centerY + (diffY * factor);
Probably your radial distortion parameters are too large, and the image became packed on a sphere. Try to put smaller values in a,b,c and d.
Your values are very extreme, so you see extreme results.
Try a=0, b=0, c=1. That describes no correction at all, if your program is correct you should see the original image. Then gradually change c and b. Changing in increments of 0.1 is a good start.

Categories