This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Pack squares into a rectangle
i need to calculate the most efficient size of squares will fill the the screen,
if you look at the below images, there are different screen sizes and square count.
I need a algorithm to calculate x axis square count and y axis square count which will fill the screen most efficiently (minimum empty area will be left after filling with squares).
i looked at the below post but it is not the answer that solves my question
Pack squares into a rectangle
1 - Square count can be changed (3-5-10 so on ...)
2 - Screen size can be different
For examples ,
on 1280 x 800 with 15 square ?
on 800 x 480 with 12 square ?
on 600x1024 with 9 square ?
on 720x1280 with 45 square ?
** I need a algorith which calculate the squares width (height is same with width) **
If you look at differencies beetween image 3 and Image 3-1 you will see that Image 3-1 uses the screen more efective because there are less unused area.
Image 3
Or maybe this is a better way to fill:
Image 3-1
If you look at differencies beetween image 4 and Image 4-1 you will see that Image 4-1 uses the screen more efective because there are less unused area.
Image 4
** 4. Image must be like below , because there are less unused area on the screen **
Image 4-1
I believe what you suggest by "efficient" is the larger the area covered by the squares the better.
let :
a : x axis square count
b : y axis square count
s : size of a square (length of one side)
w : width of screen
h : height of screen
c : number of squares to put
then we have
a * s <= w
b * s <= h
a * b >= c
With these inequalities it is possible to find an upper bound for s.
Examining the forth example given where c = 20, w = 1280 and h = 800
a * s <= 1280
b * s <= 800
a * b >= 20
a * b = (1280 / s) * (800 / s) >= 20 ---> s^2 <= (1280*800) / 20 ---> s <= 226,27..
With an upper bound for s, we can estimate a and b as;
a * s <= 1280 ---> a ~= 5,6568
b * s <= 800 ---> b ~= 3,53
with these values the inequality a * b >= 20 does not hold.
But both a and b must be whole numbers. Then we try the 4 possibilities that a and b can get :
a = 5, b = 3 // round down both
a = 5, b = 4 // one down, one up
a = 6, b = 3 // one down, one up
a = 6, b = 4 // round up both
since a * b >= 20 the first and third cases are eliminated to be a valid answer.
Choosing the answer where a = 5, b = 4 follows as the next step since their product is more close to the desired number of squares.
What you're looking for is the greatest common factor between the width and the height of the display.
Since most displays have a ratio of 4:3 or 16:9, the greatest common factor will give you the biggest square that you can use to fill the display area.
In your 400 x 400 pixel display, the greatest common factor is 400, and one square will fill the display.
In your 1280 X 800 pixel display, the greatest common factor is 160. You'll need 40 squares (8 x 5) to fill the display.
if you want to calculate one greatest common factor for all display sizes, the answer is 1. Every pixel is a square. You should calculate a separate greatest common factor for each display size you want to support.
Related
This is the expression given as solution in the book I referred to but it seems to be beyond my understanding. Please anyone help to understand how are we exactly writing this angle? Why subtract pi/2? I really have no idea
xs=(int)(Math.cos(s*3.14f/30-3.14f/2)*45+xcentre);
ys=(int)(Math.sin(s*3.14f/30-3.14f/2)*45+ycentre);
xm=(int)(Math.cos(m*3.14f/30-3.14f/2)*40+xcentre);
ym=(int)(Math.sin(m*3.14f/30-3.14f/2)*40+ycentre);
xh=(int)(Math.cos((h*30+m/2)*3.14f/180-3.14f/2)*30+xcentre);
yh=(int)(Math.sin((h*30+m/2)*3.14f/180-3.14f/2)*30+ycentre);
Seems like it's giving the cartesian coordinates of the ends of the three hands of a clock centered at the origin, with up being negative y, and right being positive x. I can say this just by trying some values.
I wrapped your basic code like this:
static class ClockCoords {
int xs, ys;
int xm, ym;
int xh, yh;
public String toString() {
return String.format("h: %3d,%3d m: %3d,%3d s: %3d,%3d", xh, yh, xm, ym, xs, ys);
}
}
public static ClockCoords coords(int h, int m, int s) {
ClockCoords r = new ClockCoords();
int xcentre = 0;
int ycentre = 0;
r.xs = (int) (Math.cos(s * 3.14f / 30 - 3.14f / 2) * 45 + xcentre);
r.ys = (int) (Math.sin(s * 3.14f / 30 - 3.14f / 2) * 45 + ycentre);
r.xm = (int) (Math.cos(m * 3.14f / 30 - 3.14f / 2) * 40 + xcentre);
r.ym = (int) (Math.sin(m * 3.14f / 30 - 3.14f / 2) * 40 + ycentre);
r.xh = (int) (Math.cos((h * 30 + m / 2) * 3.14f / 180 - 3.14f / 2) * 30 + xcentre);
r.yh = (int) (Math.sin((h * 30 + m / 2) * 3.14f / 180 - 3.14f / 2) * 30 + ycentre);
return r;
}
public static void main(String[] args) throws IOException {
System.out.println(coords(0, 0, 0));
System.out.println(coords(0, 0, 45));
System.out.println(coords(6, 0, 0));
System.out.println(coords(6, 30, 0));
}
which gives me this:
h: 0,-29 m: 0,-39 s: 0,-44
h: 0,-29 m: 0,-39 s: -44, 0
h: 0, 29 m: 0,-39 s: 0,-44
h: -7, 28 m: 0, 39 s: 0,-44
So, if I haven't messed this up, the hour hand is 29 units long, the minute hand is 39 units long, and the second hand is 44 units long. At the start of the day, the first entry, they're all pointing straight up. 45 seconds into the day, the second entry, sees the second hand pointing off to the left, but the other two hands are still point straight up given integer granularity and hands that aren't too long. The third entry, 6:00, just flips the hour hand to point down. The fourth entry is interesting, 6:30, in that it points the minute hand down, but also moves the hour hand a little to the left and up...our first hand in a position not at a 90 degree angle to center. Interesting stuff. As to the WHY of all of this...I assume it's all basic trig and cartesian math.
Wait a sec...there one thing strange I don't get...I see in the formulas where each hand is given a different length. Why are the hand lengths I see off by 1 from what's in the formulas? My guess is that it has to do with the very rough approximation of PI that's used. I think those hands aren't pointing quite straight up. That's all I can think of. Maybe tomorrow I'll try plugging in a better value for PI.
Let me provide you some background information as well.
Trigonometry
is all about a circle, having a radius of 1 unit, centered in the origo, that is, point (0, 0). The coordinates of a point on the circle can be calculated as x = cos(alpha), y = sin(alpha), where alpha is the angle. Since all the points of the circle are of equal distance from the center, you only need to know the angle to compute the coordinates, which are (cos(alpha), sin(alpha)).
Reason: Look at Pythagoras's theorem, which is, by the way, a consequence of the law of cosines, where the largest angle of the triangle is of 90 degree.
Pythagoras's theorem states that
where a, b and c are lengths of sides of the triangle, the triangle being perpendicular and a < c > b is true. So, the cos and sin is due to trigonometrical coordinates.
Radians, PI/2
Units of angle can be measured in degrees (360 degrees being the full circle) or radians (2 PI being the full circle). Let's talk in radians. In math, 0 radians is the angle of the upmost point of the circle. pi/2 is the left-most. pi is the downmost. 3pi/2 is the rightmost. Notice, that as the angle increases your point moves counter-clockwise.
Since this is periodic, it is true that
2 * k * pi + alpha = alpha
On screens, y points downwards, by contrast to the standard in math, where y vertex points upwards. So, if you start from 0 radians, that will be the downmost point when shown on the screen and due to the invert y, as you increase the angle, you move to the clockwise direction. Removing pi / 2 from 0 points you to the rightmost point.
Variables
(xh, yh) are the hour coordinates
(xm, ym) are the minute coordinates
(xs, ys) are the second coordinates
They are the hands of a traditional clock.
h is the hour angle
m is the minute angle
s is the second angle
(xcentre, ycentre) are the coordinates of the center. They might be different from (0, 0), so coordinate moving, the so-called translation is supported.
Step sizes
There are 60 seconds in a minute and there are 60 minutes in an hour, so the angle step needs to be the same for them, even though, the frequency of steps is different, while there are 24 hours in a day, so the angle step of hour needs to be both less frequent and larger (12 positions on a traditional clock).
Length of hands
Hour, minute and second hands (no pun intended) differ in their length, this is why the unit of the trigonometric circle is multiplied by 45, 40 and 30, respectively.
As time passes, presumably the angles are changed and subsequently their coordinates change.
A less-exhaustive explanation, looking only at seconds:
xs = (int)(Math.cos(s*3.14f/30-3.14f/2)*45+xcentre);
ys = (int)(Math.sin(s*3.14f/30-3.14f/2)*45+ycentre);
As Steve's answer notes, drawing a line from (xcentre, ycentre) to (xs, ys) would display a seconds-hand, with "up" being "y = 0" -- so that axis is reversed compare to traditional plots. This actually works in our favor: normally, as angles grow, they are displayed as going anti-clockwise. Since the y axis is reversed in screen coordinates, this is fine for us: our hands will advance clockwise, as expected.
Let us look at the maths, using xs:
xs = Math.cos(s*3.14f/30-3.14f/2)*45; // removed rounding & using xcentre=0
xs = Math.cos((s/30)*PI - PI/2) * sHandLength; // use PI=3.14..., sHandLength=45
Now, at time 0, we want the seconds-hand to look straight up. But normally cos(0) = 1. If we substract 90º (PI/2), it will be looking straight up:
xs = Math.cos((s/30)*PI - zeroIsUp) * sHandLength;
We can undo this to keep on reasoning about the remaining expression:
xs = Math.cos((s/30)*PI); // sHandlength of 1, time 0 is left
All that is missing is that mysterious s/30*PI. Let's make a small table:
seconds(s) radians(argument to Math.cos())
0 0
15 PI/2 -- a quarter-turn of the hand
30 PI -- a half-turn
45 3*PI/2 -- a three-quarters turn
60 2*PI, or 0 -- a full turn
So it seems that it is simply that (s/30) * PI is short for (s/60) * (2*PI).
For a book on Java, I would have expected a much clearer way of writing this. My personal preference would have been:
xs = (int)(Math.cos(base60toRadians(s) - zeroIsUp) * secondHandLength + xCentre);
ys = (int)(Math.sin(base60toRadians(s) - zeroIsUp) * secondHandLength + yCentre);
// ... somewhere else
private float base60toRadians(int b60) { return (b60 / 60) * (2 * Math.PI); }
The coordinates of the clock's centre are (xcentre, ycentre).
With a geometric affine translation to the centre you can calculate like from (0, 0).
The hands are rotating clock wise, in the negative direction.
Now the hands of a clock start at the top, and (0, 1), which has an angle π/2 (90°). (1, 0) being where the angle starts, (-1, 0) halfways having angle π (180°).
The full 360° angle being 2π, 1/60th thereof becomes:
Seconds: 60 seconds = 2π; angle 2π / 60 = π / 30
double startAngle = Math.PI / 2; // Value 0 has angle π/2
double rs = 45;
xs = (int)(Math.cos(-s * Math.PI / 30 - startAngle) * rs + xcentre);
ys = ... sin ...
Hours: 24 hours = 2π; angle 2π / 24 = π / 12
I am trying to perform PCA reducing 900 dimensions to 10. So far I have:
covariancex = cov(labels);
[V, d] = eigs(covariancex, 40);
pcatrain = (trainingData - repmat(mean(traingData), 699, 1)) * V;
pcatest = (test - repmat(mean(trainingData), 225, 1)) * V;
Where labels are 1x699 labels for chars (1-26). trainingData is 699x900, 900-dimensional data for the images of 699 chars. test is 225x900, 225 900-dimensional chars.
Basically I want to reduce this down to 225x10 i.e. 10 dimensions but am kind of stuck at this point.
The covariance is supposed to implemented in your trainingData:
X = bsxfun(#minus, trainingData, mean(trainingData,1));
covariancex = (X'*X)./(size(X,1)-1);
[V D] = eigs(covariancex, 10); % reduce to 10 dimension
Xtest = bsxfun(#minus, test, mean(trainingData,1));
pcatest = Xtest*V;
From your code it seems like you are taking the covariance of the labels, not the trainingData. I believe the point of PCA is in determining the greatest variance in some N (N = 10 here) number of subspaces of your data.
Your covariance matrix should be 900x900 (if 900 is the dimension of each image, a result of having 30x30 pixel images I assume.) Where the diagonal elements [i,i] of covaraincex gives the variance of that pixel for all training samples, and off diagonal [i,j] give the covariance between pixel i and pixel j. This should be a diagonal matrix as [i,j] == [j,i].
Furthermore when calling eigs(covariancex,N), N should be 10 instead of 40 if you want to reduce the dimension to 10.
I'm trying to create a function that will translate float values to a color. I created a simple linear scale:
float value;
float maxValue;
float scaleStep = maxValue / 5;
if (value < scaleStep) {
color = blue
}
if (value > scaleStep && value <= scaleStep * 2) {
color = green
}
if (value > scaleStep * 2 && value <= scaleStep * 3) {
color = yellow
}
if (value > scaleStep * 3 && value <= scaleStep * 4) {
color = orange
}
if (value > scaleStep * 4 && value <= scaleStep * 5) {
color = red
}
but since most (but not all) of the values from the sets that I'm trying to represent are in close proximity from one particular value, graphical representation using linear scale isn't very useful (almost everything is translated to one color).
How can I create a non-linear scale so that differences between the values are more visible?
Interpolation is what you want. Interpolation generates samples between known samples in a dataset.
Here, your known samples are your colors; blue, green, yellow, orange, and red. The colors between those known colors are what you're looking for.
Here's a link to a nice visualizer of interpolation functions.
And here's a few interpolation functions for your convenience. Play with them, find the one that works best for you!
public float linearInterpolation(float start, float end, float normalizedValue) {
return start + (end - start) * normalizedValue;
}
public float sinInterpolation(float start, float end, float normalizedValue){
return (start+(end-start)* (1 - Math.cos(normalizedValue * Math.PI)) / 2;
}
//usage
linearInterpolation(red, green, .5f);//halfway between red and green.
//same with other demonstrations.
Edit:
Here, start and end refer to a starting and ending sample. The normalizedValue is some value between [0, 1] inclusive (that means it can equal exactly 0 or 1, or any value in between 0 and 1. That's what the term normalized means typically.)
So, for you, start and end will be two colors, and normalizedValue will represent how near you are to the starting or ending color.
Take linearInterpolation for example.
red = 1;
green = 2;
float midway = 1 + (2 - 1) * .5;
//midway = 1.5, which is halfway between red and green.
float allRed = 1 + (2 - 1) * 0;
//allRed = 1, which is the value of red (or start)
float allGreen = 1 + (2 - 1) * 1;
//allGreen = 2, which is the value of green (or end)
So, for linear interpolation, the closer the normalizedValue is to 1, the nearer the returned value it is to end. The closer normalizedValue is to 0, the closer the returned value is to start.
This isn't necessarily true for other interpolation functions. You can think linear interpolation as a simple line segment connecting values. Want a value halfway between those segments? Use a normalized value of .5, viola!
Other functions might have steeper slopes, or even oscillate between start and end!
Try and stop thinking in terms of color, and start thinking more abstractly. Colors are a certain distance apart. Interpolation helps you define what values lie in the distance between them.
Since the float values are in a set, you know how many there are and can calculate a color interval. You can then iterate over them, assigning colors and incrementing by the color interval.
Edit: The downside of this approach is that the same float value will not map to the same color when the number of values changes.
I suggest a logarithmic scale. If you use base 10 logs, the range will be from -39 to +39.
Depending on your distribution, a double or triple log can be better. I made a very quick test, and for the sample { 1.00, 1.20, 1.10, 1.05, 1.15, 9.70, 1.20, 2.00, 1.01, 1.03, 1.16, 1.02, 9.00, 1.20, 1.10, 1.50, 1.05, 1.15, 2.00, 3.00 }, function
int f(float x) {
return (int)(Math.log(Math.log(x)*100+1)*2.5) ;
}
Produces the following distribution:
f(x) color count
0 blue 4
1 green 4
2 yellow 6
3 orange 3
4 red 3
Not bad for 5 minutes of work. However, if you post a reasonable sample of numbers (say 100), a distribution graph, or, much better, a distribution histogram, we could help you better. The trick is to find the distribution function of the data. From that function it is very easy to come with a second function that makes the distribution uniform ("flat").
A second alternative in your case (which is relatively simple as you want to use just a few colors), is to use scaleSteps of different "width".
if( value < greenMin ) color= blue ;
else if( value < yellowMin ) color= green ;
else if( value < orangeMin ) color= yellow ;
else if( value < redMin ) color = orange ;
else color= red ;
I took the liberty of condensing the code a bit. Let me know if it's not clear. You need to determine the values of greenMin, yellowMin, orangeMin, and redMin, of course. For that, grab a big, representative data sample, sort it, and divide it in 5 groups of equal size. The first value of the second group is greenMin, first value of the third is yellowMin, and so on. You can use an office spreadsheet program to do this, as it's a one-time activity.
I am trying to program a joystick in which the user only sends his coordinates if he stopped moving his thumb (or at least only a little, shaking for example).
I cannot find an touchevent for that.
Further explanation: brown = thumb, red is the area/circle that gets tolerated (moving in that space the next 2 seconds will count as 1 coordinate)
int actionType = event.getAction();
if (actionType == MotionEvent.ACTION_MOVE){}
This is how i retrieve my toucheventdata. i would need something like ACTION_HOLD and a timer. Am i missing something?
Try to round the coordinates.
Divide the coordinates with an integer (ex. 10),
Cast the result into an integer (or round it) and multiply with the same integer in the next Step.
Example:
5,30 / 10 = 0,53
(int) 0,53 = 0
0 * 10 = 0
14,4 / 10 = 1,44
(int) 1,44 = 1
1 * 10 = 10
I know how to rotate an entire 2d array by 90 degrees around the center(My 2d array lengths are always odd numbers), but I need to find an algorithm that rotates specific indices of a 2d array of known length. For example I know that the 2d array is a 17 by 17 grid and I want the method to rotate the indices [4][5] around the center by 90 degrees and return the new indices as two separate ints(y,x); Please point me in the right direction or if your feeling charitable I would very much appreciate some bits of code - preferably in java. Thanks!
Assuming cartesian coordinates (i.e. x points right, and y points up) and that your coordinates are in the form array[y][x] the center [cx, cy] of your 17x17 grid is [8, 8].
Calculate the offset [dx, dy] of your point [px, py] being [4, 5] from there, i.e. [-4, -3]
For a clockwise rotation, the new location will be [cx - dy, cy + dx]
If your array uses the Y axis pointing "downwards" then you will need to reverse some of the signs in the formulae.
For a non-geometric solution, consider that the element [0][16] needs to get mapped to [16][16], and [0][0] mapped to [0][16]. i.e. the first row maps to the last column, the second row maps to the second last column, etc.
If n is one less than the size of the grid (i.e. 16) that just means that point [y][x] will map to [x][n - y]
In theory, the geometric solution should provide the same answer - here's the equivalence:
n = 17 - 1;
c = n / 2;
dx = x - c;
dy = y - c;
nx = c - dy = c - (y - c) = 2 * c - y = n - y
ny = c + dx = c + (x - c) = x
If you have a square array with N elements in each row/column a 90deg turn anti-/counter-clockwise sends (x,y) to (N+1-y,x) doesn't it ?
That is, if like me, you think that the top-left element in a square array is (1,1) and row numbers increase down and column numbers to the right. I guess someone who counts from 0 will have to adjust the formula somewhat.
The point in Cartesian space x,y rotated 90 degrees counterclockwise maps to -y,x.
An array with N columns and M rows would map to an array of M columns and N rows. The new "x" index will be non-positive, and will be made zero-based by adding M:
a[x][y] maps to a[M-y][x]