Calculating the scale factor for "bar rectangles" of Chart app - java

I have an array of integer values
String[] values={3100,7500,8000,4200,88000,71000,32000};
that need to be scaled into a known height of my JComponent , the question is how to scale these values into e.g. h=600px?
Here is a pic just for more clarification of what i want to achieve:
Thanks

bar_height = chart_height*(value/max_value)
To determine bar_height, you scale (multiply) chart_height by (value/max_value), where:
bar_height is the height of the a bar in pixels.
value is the value to be charted.
max_value is the maximum value on the y-axis.
chart_height is the height of the chart in pixels (600 in your example).
For example:
88000/88000 = 1.0, or 100% of the chart height (600px)
0/88000 = 0, or 0% of the chart's height ( 0px)
3100/88000 = ~0.035, or ~3.53% of the chart's height (~21px)

Related

custom Zoom in/out on JPanel is not linear

To avoid wasting your time I will make it short:
My project: a graphical presentation of the Mandelbrot set.
My progress: finished except a bug in the zoom in/zoom out feature
The bug: The zoom in scale is smaller (slower) than the zoom out scale
The shorter version: how can I simulate a zoom in/out by a factor on a jpanel.
In the end a small section of the jPanel should be enlarged to the whole jPanel.
Every pixel in the jPanel represents an integer number, but you don't have to worry about a lack of integers after the zoom in.
The longer version (only if you need more information):
the zoom-function in the Mandelbrot set:
public void recalculate(int x, int y, int width, int height, double scale){
downright=new Complex(upleft.getReal()+stepwidth*(x+width/scale),upleft.getImg()-stepwidth*(y+height/scale));
upleft=new Complex(upleft.getReal()+stepwidth*(x-width/scale), upleft.getImg()-stepwidth*(y-height/scale));
stepwidth=(downright.getReal()-upleft.getReal())/width;
calc(lastrep);
}
A short terminology:
downright is the bottom-right complex number, the last pixel to be painted on the jpanel
upleft is, therefore, the top-left complex-number, the first pixel to be painted on the jpanel
stepwidth is the distance between each complex number represented by one pixel
calc is finally the function that calculates every color for each pixel according to the Mandelbrot set rules
the width and height parameters are the pixel width/height of the jpanel, x and y are the coordination where to zoom in and scale the factor for the zoom.
When I call this function mandelbrot.recalculate(x,y, getWidth(), getHeight(), 10); than this should zoom in on the point (x,y) so that the new represented image is 1/5 of the actual image.
1/5 should be because the start of the image (upleft) is 1/10 of the amount of pixels of the full width and height shifted to the up and left of the point (x,y) and the end of the image (downright) is 1/10 of the amount of pixels of the full width and height shifted down and right.
So if I call the function after the zoom in like this: mandelbrot.recalculate(x,y, getWidth(), getHeight(), 0.1);
it should reverse the whole process, but it doesn't
this is the intended zoom:
The Solution was rather simple.
The Problem was the attempt to calculate the zoom in as well as the shift to a new midpoint in one go.
Since the shift to the new midpoint is dependent on the zoom in, you can't put that into one equation, or at least only with a lot of effort.
I changed my code like shown below, so that I first calculate the zoom in and then shift the anchor to the wanted position. Sometimes the longer way is the better way.
//The new midpoint needs the old stepwith to calculate correctly
Complex newmidpoint = new Complex(upleft.getReal()+x*stepwidth, upleft.getImg()-y*stepwidth);
//zooming in
double distwidth = downright.getReal()-upleft.getReal();
double distheight = upleft.getImg()-downright.getImg();
double newreal = upleft.getReal()+(1/scale)*distwidth;
double newimg = upleft.getImg()-(1/scale)*distheight;
downright=new Complex(newreal, newimg);
stepwidth=(downright.getReal()-upleft.getReal())/width;
//the old midpoint is actually the already zoomed in midpoint, it needs the new stepwidth
Complex oldmidpoint = new Complex(upleft.getReal()+width/2.0*stepwidth,upleft.getImg()-height/2.0*stepwidth);
Complex diffmidpoint = newmidpoint.subtract(oldmidpoint);
upleft=new Complex(upleft.getReal()+diffmidpoint.getReal(),upleft.getImg()+diffmidpoint.getImg());
downright=new Complex(downright.getReal()+diffmidpoint.getReal(), downright.getImg()+diffmidpoint.getImg());
calc(lastrep);

libGDX change my system from pixels to units

I want everyone to see the same things on their screen regardless of their screen size and aspect ratio so this is the code I am currently using. (also I am sending net data across with the coordinates of where the other players are on the screen)
int width = 1920, height = 1080;
public OrthographicCamera camera;
Viewport viewport;
//constructor
camera = new OrthographicCamera();
viewport = new ScalingViewport(Scaling.stretch, width, height, camera);
viewport.apply();
camera.position.set(camera.viewportWidth / 2, camera.viewportHeight / 2, 0);
camera.update();
public void resize(int width, int height) {
viewport.update(width, height);
camera.position.set(camera.viewportWidth / 2, camera.viewportHeight / 2, 0);
}
now for example I wanted 10 perfect squares going across the middle of the screen so I made then 192 pixels by 192 pixels so I could have 10 perfect squares going across the middle of the screen my system right now works perfect except for the fact that it is rendered internally 1920x1080 on all devices big and small. How would I convert my camera to units and get the size needed for 10 perfect squares to go across the screen? Is that even possible?
Here is my code to draw 10 squares across the screen
float size = 192;
for(int i = 0; i<10; i++){
walls.add(new Stuff(i*size,height/2-size/2,size,size,"middle",1,1,0,1));
}
How would I convert all this code to say units? Or is this an acceptable approach?
You are already using units, they just aren't very meaningful (and it certainly aren't pixels). If you want to use meaningful units (e.g. SI units), then the only thing you have to change in this code are the values. E.g. if the size of your stuff (wall?) is, say 2 meter, then use the value 2 instead of 192. And if you want your users screen to be, say 20 meters (10 walls e.g.) in width and 16:9 aspect ratio, then use that for the Viewport worldWidth and worldHeight.
float worldWidth = 20;
float worldHeight = worldWidth * 9f / 16f;
...
viewport = new StretchViewport(worldWidth, worldHeight, camera);
Make sure to understand that these "pixels" you are talking about only exist in your imagination. See also: http://blog.xoppa.com/pixels/.
You created your ScalingViewport with a width of 1920, so the width in world units will be 1920 on all screens, no matter what. Also, your scene will be distorted on any screen that is not 16:9, since you are stretching to fit whatever the screen is. (Because of the distortion, I personally would never use ScalingViewport with Scaling.stretch, aka StretchViewport.)
If you want your squares to look square on all screens with this type of viewport, you'll have to do some math to change their height (but their width should always be 192 if you want exactly ten to fit across the screen).
public void resize(int width, int height){
float viewportAspect = 1920f / 1080f;
float screenAspect = (float)width / (float)height; //Make sure you cast to floats
boxHeight = 192 * screenAspect / viewportAspect;
viewport.update(width, height, true);
}
The camera always shows the scene in world units, so there's no conversion to do.

Set button size with pixels

In my application I control the size of my button proportionally with the screen size:
int screenWidth = displaymetrics.widthPixels;
int screenHeight = displaymetrics.heightPixels;
int buttonWidth = (int) (screenWidth * 0.07);
int buttonHeight = (int) (buttonWidth * 1.2);
The button takes the same space (for example 5 %) of the device's screen size. What I want now is that the button's text takes the same space of the button area on every device.
I tried this:
int textSize = (int) (buttonHeight * 0.145);
myButton.setTextSize((float) (textSize));
I don't know why but on bigger screens (such as tablets) the text uses a lot less space of the button than on smaller screens.
Thanks !
Maybe
Try specifying the unit of measurement like this:
myButton.setTextSize(TypedValue.COMPLEX_UNIT_PX, (float) (textSize));
setTextSize uses sp units by default instead of px, so that might be causing your issue!

resizing an image issue

I have a problem with resizing an image.
First of all at the start I have an image for example in 1920x1080. The user input is the percentage of resizing the current image, for example when input is 25% the final resolution of the image is 960x540.
Explanation:
1920x1080 = 2 073 600
25% from 2 073 600 = 518 400
960x540 = 518 400
I already have the function for resizing an image , but i dont know how to CALCULATE the values WIDTH and HEIGHT for an resized image.
I the example it is 960x540. (if it can help you, images has ratio 3:2,4:3,16:9 ....)
Any help ?
You have the following information given to you:
width = 1920
height = 1080
area = 2073600
ratio = width / height =~ 1.77778
Now, suppose for example that you want to calculate a new width and height when the area shrinks to 25% of its current size. Well then we know the following things:
area = 0.25 * 2073600 = 518400
height = h (Variable, because it is unknown at the moment)
width = w (Variable, because it is unknown at the moment)
ratio = 1.77778 (Ratio should stay the same or image becomes warped/stretched)
So you have
w / h = 1.77778 (Your unknown new width divided by unknown height equals ratio)
w * h = 518400 (Your unknown width times unknown height equals area)
Now you can solve it relatively easily mathematically. It is simply two equations with two variables.
w = 1.77778 * h (from first equation)
(1.77778 * h) * h) = 518400 (by plugging above into second equation)
h =~ 540
w =~ 960
Does that make sense?

Containing drawing to a panel area

I want to draw an array of X and Y integers to a panel in a Java frame.
What is the best way to draw the line (currently I'm using Graphic's drawPolyline)?
How can I efficiently scale the integer values so they all fit in the panel area without knowing the max (Y) value?
Update, for example
public void paint(Graphics g)
{
int height = panel.getHeight();
int width = panel.getWidth();
int[] xPoints = { ... values ... };
int[] yPoints = { ... values ... };
int nPoints = dataLength;
// Scale xPoints and yPoints so they fit in the area of width and height
// and draw line
g.drawPolyline(xPoints, yPoints, nPoints);
g.dispose();
}
Without knowing both the x and y maximum values, I don't think this can be done, since you can't then calculate the scale needed. But if you have an array of points, then you can certainly search it to find the minimum and maximum x and y values.
If you have a means of getting the maximum values, read on (and for the benefit of others with a similar problem).
Find the maximum difference between any two x values between any two y values; call them max(dx) and max(dy) - these are max(x)-min(x) and max(y)-min(y) respectively.
Take the greater of width/max(dx) and height/max(dy). That number provides your scale; just modify every x value using ((x-min(x))/scale) and each y value using ((y-min(y))/scale)
You should now have the largest shape that will fit oriented relative 0,0.
Note: I have have negative coordinates, you will have to adjust them into the positive coordinate range before applying these formulas.

Categories