How to enlarge the difference between large values that have small variation? - algorithm

I have four values: [A B C D]
and I have four graphical lines where each ones height is to represent the sizes of A B C and D. I dont want to scale the heights of each line to the exact values but instead a percentage relative to the other values. The minimum line height should be 1 and the max height should be 4. I'm having trouble as the differences between the values are very small.
I have
a_height = 1+(a/a+b+c+d)
b_height = 1+(b/a+b+c+d)
c_height = 1+(c/a+b+c+d)
d_height = 1+(d/a+b+c+d)
But the difference between A B C D are very small for example:
A = 14500
B = 14510
C = 14496
D = 14507
(Collectively all four values will vary together from 10,000-20,000 during simulation but the variation between each will remain small)
So all the heights end up being roughly the same and so visually you cant tell the difference. What can be done here to scale up the differences in the values so the heights of each line are clearly different to eachother but still proportional.

Related

Algorithm for distributing images to form a square

I'm building an application that creates a spritesheet from a series of images. Currently the application requires to indicate the number of columns by the user but I would like to add an option that suggests this parameter automatically which allows to obtain an almost square spritesheet.
If the images were square, a square root of the total number of images would suffice but this is not the case.
The images must all be the same size but may be taller than wide or the opposite.
For example: the sprite sheet has a walking character and each image is 331 high and 160 wide. The number of frames is 25.
I should find an algorithm that suggests the number of columns (and rows) that allows me to obtain a sheet that is as square as possible.
Unfortunately I have no code to present just because I have no idea what kind of reasoning to do.
Do you have any suggestions to work on?
The basic idea is that, if the image height is twice the width, you will need twice more columns than rows.
If:
q is the image ratio (width/height)
c is the number of columns
r is the number of rows
n is the total number of images
then we have:
r / c = q and r * c = n
After a few substitutions:
c = sqrt(n / q)
r = q * c
In your case, q = 160 / 331 = 0.48
c = sqrt(25 / 0.48) = 7.2
r = 0.48 * c = 3.5
So (after rounding) the answer is 4 rows and 7 columns.
Mathematically, this is an interesting question.
I don't have time to think about it extensively, but here are my two cents:
Let the width and height of the sprites be w and h, respectively, and let the number of sprites be n.
If you put these in a grid consisting of c columns and r rows, the total width of the grid will be cw and the total height rh. You want the quotient cw/rh to be as close to 1 as possible.
Now, if you chose c and r freely, the number of grid cells, N := cr, might well be slightly larger than n. In most cases, I would expect you to accept a partially empty last row.
Since N is close to n,
Hence, we want to find c such that
is as small as possible. Clearly this happens when
Hence, if you let the number of columns be √(nh/w) rounded to the nearest integer, you will probably get a fairly square grid.

Is there a way to create a summed-are table of a matrix with just one iteration?

Constrains:
You can't iterate the matrix more than once.
If we name the matrix A then there are two of those matrices available, one is 'read-only' and the other is 'read/write'. We will use the 'read/write' matrix to construct the summed-area table.
For example this code here:
http://www.geeksforgeeks.org/submatrix-sum-queries/
Iterares 2 times: 1) summing all columns
2) summing all rows
Useful picture for summed area tables from Wikipedia:
During construction, we already have A, B and C (for the edges, they would be zero), and want to compute D. The area spanned by that rectangle is 1x1 in this case, so we know the sum of the rectangle is X where X is the number from the original matrix at the position of D, so D = C + B - A + X. A is subtracted because the areas belonging to C and B both contain the area of A.
Simply iterating over the matrix and filling every cell using that formula iterates over the matrix only once, and could even be done in-place (replacing the original matrix by its SAT) if your matrix was not read-only.

find all points within a range to any point of an other set

I have two sets of points A and B.
I want to find all points in B that are within a certain range r to A, where a point b in B is said to be within range r to A if there is at least one point a in A whose (Euclidean) distance to b is equal or smaller to r.
Each of the both sets of points is a coherent set of points. They are generated from the voxel locations of two non overlapping objects.
In 1D this problem fairly easy: all points of B within [min(A)-r max(A)+r]
But I am in 3D.
What is the best way to do this?
I currently repetitively search for every point in A all points in B that within range using some knn algorithm (ie. matlab's rangesearch) and then unite all those sets. But I got a feeling that there should be a better way to do this. I'd prefer a high level/vectorized solution in matlab, but pseudo code is fine too :)
I also thought of writing all the points to images and using image dilation on object A with a radius of r. But that sounds like quite an overhead.
You can use a k-d tree to store all points of A.
Iterate points b of B, and for each point - find the nearest point in A (let it be a) in the k-d tree. The point b should be included in the result if and only if the distance d(a,b) is smaller then r.
Complexity will be O(|B| * log(|A|) + |A|*log(|A|))
I archived further speedup by enhancing #amit's solution by first filtering out points of B that are definitely too far away from all points in A, because they are too far away even in a single dimension (kinda following the 1D solution mentioned in the question).
Doing so limits the complexity to O(|B|+min(|B|,(2r/res)^3) * log(|A|) + |A|*log(|A|)) where res is the minimum distance between two points and thus reduces run time in the test case to 5s (from 10s, and even more in other cases).
example code in matlab:
r=5;
A=randn(10,3);
B=randn(200,3)+5;
roughframe=[min(A,[],1)-r;max(A,[],1)+r];
sortedout=any(bsxfun(#lt,B,roughframe(1,:)),2)|any(bsxfun(#gt,B,roughframe(2,:)),2);
B=B(~sortedout,:);
[~,dist]=knnsearch(A,B);
B=B(dist<=r,:);
bsxfun() is your friend here. So, say you have 10 points in set A and 3 points in set B. You want to have them arrange so that the singleton dimension is at the row / columns. I will randomly generate them for demonstration
A = rand(10, 1, 3); % 10 points in x, y, z, singleton in rows
B = rand(1, 3, 3); % 3 points in x, y, z, singleton in cols
Then, distances among all the points can be calculated in two steps
dd = bsxfun(#(x,y) (x - y).^2, A, B); % differences of x, y, z in squares
d = sqrt(sum(dd, 3)); % this completes sqrt(dx^2 + dy^2 + dz^2)
Now, you have an array of the distance among points in A and B. So, for exampl, the distance between point 3 in A and point 2 in B should be in d(3, 2). Hope this helps.

How to check if selected cells on a grid form a 'tunnel'?

Given a grid map where each cell can be described by a pair (x, y), and a vector of such cells, how can I (nicely) check if the cells in that vector form a 'tunnel', ie. they are all lined up either vertically or horizontally? But what if I only want to see if most of them are lined up (and not all)?
All are lines up Most are lined up Not lined up
C C C C
C C C C C C C C C C C C C C C C C C C C
C C C C C
C C
You could do a histogram of the x and y coordinates of the cells.
If all cells are lined up horizontally, you get only one y-value in your histogramm and lots of consecutive x-values, which all occur only one times. Vertically is the same with x and y flipped.
If you want to check, if most of them are lined up, search for the value in the histogram, which has the most occurences (longest possible tunnel) and check the cells with that x or y-coordinate, if they are lined up (that is: their y or x-coordinates (depending on wheter x or y was used in the previous step) are consecutive without a gap (maybe sort them first))
If they are not, search for the second highest occurrence value, ...
You could calculate the standard deviation of both the X and Y coordinates. The more 'tunnelled' your cells are, the lower the std deviation will be for either X or Y.
For example, in Python:
import numpy
def is_tunnelled(cells):
# given cells=[(x,y), (x,y),...]
x_values, y_values = zip(*cells)
lowest_std_dev = min(numpy.std(x_values), numpy.std(y_values))
return lowest_std_dev < STD_DEVIATION_THRESHOLD
It's up to you to determine what the value of STD_DEVIATION_THRESHOLD should be.
You can check if they make a horizontal tunnel by first checking that their y coordinates are all equal, then sort by the x coordinate and traverse from left to right to check for gaps. Use the opposite coordinates to check for vertical tunnels.
For the approximate check you will have to clarify what you mean by "most".

Generate a random point within a rectangle (uniformly)

Generate a random point within a rectangle (uniformly)
This suppose to be a simple problem.
However, in RANDOM_DATA homepage I found the following note:
However, we will not achieve uniform distribution in the simple case
of a rectangle of nonequal sides [0,A] x [0,B], if we naively scale
the random values (u1,u2) to (A*u1,B*u2). In that case, the expected
point density of a wide, short region will differ from that of a
narrow tall region. The absence of uniformity is most obvious if the
points are plotted.
I found it quite of strange... I can't figure out why such scaling will affect the uniformity.
What am I missing?
Edit:
Thank you Patrick87 and missingno. I was searching for a theoretical reason for the statement. I now understand that the reason is not theoretical, but practical - the granularity of floating-point values.
If I'll generate two uniform floating-points between 0 and 1 (which is an issue by itself due to the nature of floating-point value representation. Look here for an algorithm) - the granularity will be limited.
Suppose that there are X different values between 0 and 1. By scaling (u1,u2) to (u1,2*u2) we'll have X different values in the range [0,u1] and X different values in the range [0,2*u2]. For area uniformity we should have twice as many different values in [0,2*u2] than in [0,u1].
Given that, Allow me to change my question:
How should I generate a random point within a rectangle (with uniform distribution by area)?
That statement is incorrect, direct product of two independent uniform measures is a uniform measure. This can be shown as follows:
A probability for a random point to hit a rectangle with sides a and b is equal to probability for the first coordinate to hit the segment with the length a and the second coordinate to hit the segment with the length b. (We are talking about projections of a rectangle to axes).
First probability is a / A, the second one is b / B.
As these variables are independent, the probabilities multiply, so the resulting probability is ab / AB, so we have a uniform 2D distribution as the probability is proportional to the area of the rectangle. This formula is symmetric with respect to a and b, so the observation in the quote is wrong about narrow and wide rectangles.
How should I generate a random point within a rectangle (with uniform distribution by area)?
This should work:
// given A, B, dimensions of rectangle
// given g, granularity of shorter side
if A > B then
bm := g
am := floor(g * A / B)
else then
am := g
bm := floor(g * B / A)
for i := 1 to n do
av := A * RandomInt(0..am) / am
bv := B * RandomInt(0..bm) / bm
print (av, bb)
EDIT: A simpler alternative would be to simply scale random floating point values by the same factor, choose points at random, and throw away points that fall outside your rectangle. However, you don't know how many trials you'd need before you got N points in the rectangle...
Ascii art:
Take a 3x3 rectangle:
***
***
***
And spread one of the sides by 3x:
*..*..*..*
*..*..*..*
*..*..*..*
You can kind of see here that the points are more densely packed vertically than they are horizontaly. What you actually want instead is uniform distribution by area
The most straightforward way to handle this is through rejection sampling:
http://en.wikipedia.org/wiki/Rejection_sampling
// Given dimensions of the rectangle A, B where A <= B
boolean flag = true
while (flag) do:
double a = NextRandomDouble(0,B)
double b = NextRandomDouble(0,B)
if (a <= A)
return(a, b)
else
next
You essentially generate uniform numbers from a square that fits the original rectangle (of length B, in this example). If the number falls in the rectangle, keep the pair. If it does not, throw it away and try again!

Resources