Related
Given sum of A and B let S
i have to find maximum product of A*B
but there is one condition value of A will be in range [P,Q]
How to proceed for it ?
If there is no range then task is pretty simple.
Using derivation method .
How to find Maximum product for eg.
A+B=99
value of A will be range [10,20]
then what will be the maximum product of A and B.
O(N) will not sufficient for the problem
Clearly, B = S - A and you need to maximize A * (S - A).
You know from algebra that A * (S - A) achieves a maximum when A = S / 2.
If S / 2 falls in the allowed range [P Q], then the maximum value is A^2 / 4.
Otherwise, by monotonicity the maximum value is reached at one of the bounds and is the largest of P * (S - P) and Q * (S - Q).
This is an O(1) solution.
This is actually a maths question, nothing to do with programming
Even if you are given it as a programming question, You should first understand it mathematically.
You can think of it geometrically as "if the perimeter of my rectangle is fixed at S, how can I achieve the maximum area?"
The answer is by making sides of equal length, and turning it into a square. If you're constrained, you have to get as close to a square as possible.
You can use calculus to show it formally:
A+B = S, so B = S-A
AB therefore = A(S-A)
A is allowed to vary, so write it as x
y = x(S-x) = -x^2 + Sx
This is a quadratic, its graph Will look like an upsidedown parabola
You want the maximum, so you're looking for the top of the parabola
dy/dx = 0
-2x + S = 0
x = S/2
A better way of looking at it would be to start with our rectangle Pq = A, and say P is the longer edge.
So now make it more oblique, by making the longer edge P slightly longer and the shorter edge q slightly shorter, both by the same amount, so P+q does not change, and we can show that the area goes down:
Pq = A
(P+delta) * (q-delta)
= Pq + (q-P)*delta + delta^2
= A + (q-P)delta
and I throw away the delta^2 as it vanishes as delta shrinks to 0
= A + (something negative)*delta
= A - something positive
i.e. < A
What is a formula to get a three dimensional vector B lying on the plane perpendicular to a vector A?
That is, given a vector A, what is a formula f(angle,modulus) which gives a vector that is perpendicular to A, with said modulus and rotated through an angle?
If the two vectors are perpendicular then their dot product is zero.
So: v1(x1, y1, z1), v2(x2, y2, z2).
=> x1 * x2 + y1 * y2 + z1 * z2 = 0
You know (x1, y1, z1). Put arbitrary x2 andy2 and you will receive the corresponding z2:
z1 * z2 = -x1 * x2 - y1 * y2
=> z2 = (-x1 * x2 - y1 * y2) / z1
Be aware if z1 is 0. Then you are in the plane.
function (a,b,c)
{
return (-b,a,0)
}
But this answer is not numerical stable when a,b are close to 0.
To avoid that case, use:
function (a,b,c)
{
return c<a ? (b,-a,0) : (0,-c,b)
}
The above answer is numerical stable, because in case c < a then max(a,b) = max(a,b,c), then vector(b,-a,0).length() > max(a,b) = max(a,b,c) , and since max(a,b,c) should not be close to zero, so is the vector. The c > a case is similar.
Calculate the cross product AxC with another vector C which is not collinear with A.
There are many possible directions in the plane perpendicular to A. If you don't really care, which one to pick, just create an arbitrary vector C not collinear with A:
if (A2 != 0 || A3 != 0)
C = (1, 0, 0);
else
C = (0, 1, 0);
B = A x C;
I believe that this should produce an arbitrary vector that is perpendicular to the given vector vec while remaining numerically stable regardless of the angle of vec (assuming that the magnitude of vec is not close to zero). Assume that Vec3D is a three dimensional vector of arbitrary numerical type.
Vec3D arbitrary_orthogonal(Vec3D vec)
{
bool b0 = (vec[0] < vec[1]) && (vec[0] < vec[2]);
bool b1 = (vec[1] <= vec[0]) && (vec[1] < vec[2]);
bool b2 = (vec[2] <= vec[0]) && (vec[2] <= vec[1]);
return cross(vec, Vec3D(int(b0), int(b1), int(b2)));
}
Informal explanation
Exactly 1 and only 1 of the bools get set; bN gets set if dimension N has magnitude strictly less than all subsequent dimensions and not greater than all previous dimensions. We then have a unit vector with a single non-zero dimension that corresponds to a dimension of minimum magnitude in vec. The cross product of this with vec is orthogonal to vec by defn of cross product. Consider now that the cross product is numerically unstable only when the two vectors are very closely aligned. Consider that our unit vector is large in only a single dimension and that that dimension corresponds to the dimension where vec was small. It's thus guaranteed to be loosely orthogonal to vec before taking the cross product, with least orthogonality in the case where all dimensions of vec are equal. In this least-orthogonal case, we're still quite orthogonal given that our unit vector has all but one dimension 0 whereas vec has all equal. We thus avoid the unstable case of taking the cross product of two nearly-aligned vectors.
q4w56's is almost there for a robust solution. Problems: 1) Doesn't take in account scaling. 2) Doesn't compare the magnitude between two variables when it should.
scale = |x| + |y| + |z|
if scale == 0:
return (0,0,0)
x = x/scale
y = y/scale
z = z/scale
if |x| > |y|:
return (z, 0,-x)
else:
return (0, z,-y)
Scaling is important when dealing with very large or very small numbers. Plus in general you are better off doing floating point operations on values between 0 and 1.
One way would be to find a rotation transform from the positive z-axis (or any other axis) to your given vector. Then transform <modulus * cos(angle), modulus * sin(angle), 0> using this transform.
def getPerpendicular(v1,modulus,angle):
v2 = vector(0,0,1)
v1_len = v2.length()
axis = v1.cross_product(v2)
sinAngle = axis.length() / v1_len # |u x v| = |u| * |v| * sin(angle)
cosAngle = v1.dot_product(v2) / v1_len # u . v = |u| * |v| * cos(angle)
axis = axis.normalize()
# atan2(sin(a), cos(a)) = a, -pi < a < pi
angle = math.atan2(sinAngle, cosAngle)
rotationMatrix = fromAxisAngle(axis, angle)
# perpendicular to v2
v3 = vector(modulus*cos(angle),modulus*sin(angle),0)
return rotationMatrix.multiply(v3);
To calculate the rotation matrix, see this article: WP: Rotation matrix from axis and angle
Another method would be to use quaternion rotation. It's a little more to wrap your head around, but it's less numbers to keep track of.
I'm developing a simple 2D board game using hexagonal tile maps, I've read several articles (including the gamedev one's, which are linked every time there's a question on hexagonal tiles) on how to draw hexes on the screen and how to manage the movement (though much of it I had already done before). My main problem is finding the adjacent tiles based on a given radius.
This is how my map system works:
(0,0) (0,1) (0,2) (0,3) (0,4)
(1,0) (1,1) (1,2) (1,3) (1,4)
(2,0) (2,1) (2,2) (2,3) (2,4)
(3,0) (3,1) (3,2) (3,3) (3,4)
etc...
What I'm struggling with is the fact that I cant just 'select' the adjacent tiles by using for(x-range;x+range;x++); for(y-range;y+range;y++); because it selects unwanted tiles (in the example I gave, selecting the (1,1) tile and giving a range of 1 would also give me the (3,0) tile (the ones I actually need being (0,1)(0,2)(1,0)(1,2)(2,1)(2,2) ), which is kinda adjacent to the tile (because of the way the array is structured) but it's not really what I want to select. I could just brute force it, but that wouldn't be beautiful and would probably not cover every aspect of 'selecting radius thing'.
Can someone point me in the right direction here?
What is a hexagonal grid?
What you can see above are the two grids. It's all in the way you number your tiles and the way you understand what a hexagonal grid is. The way I see it, a hexagonal grid is nothing more than a deformed orthogonal one.
The two hex tiles I've circled in purple are theoretically still adjacent to 0,0. However, due to the deformation we've gone through to obtain the hex-tile grid from the orthogonal one, the two are no longer visually adjacent.
Deformation
What we need to understand is the deformation happened in a certain direction, along a [(-1,1) (1,-1)] imaginary line in my example. To be more precise, it is as if the grid has been elongated along that line, and squashed along a line perpendicular to that. So naturally, the two tiles on that line got spread out and are no longer visually adjacent. Conversely, the tiles (1, 1) and (-1, -1) which were diagonal to (0, 0) are now unusually close to (0, 0), so close in fact that they are now visually adjacent to (0, 0). Mathematically however, they are still diagonals and it helps to treat them that way in your code.
Selection
The image I show illustrates a radius of 1. For a radius of two, you'll notice (2, -2) and (-2, 2) are the tiles that should not be included in the selection. And so on. So, for any selection of radius r, the points (r, -r) and (-r, r) should not be selected. Other than that, your selection algorithm should be the same as a square-tiled grid.
Just make sure you have your axis set up properly on the hexagonal grid, and that you are numbering your tiles accordingly.
Implementation
Let's expand on this for a bit. We now know that movement along any direction in the grid costs us 1. And movement along the stretched direction costs us 2. See (0, 0) to (-1, 1) for example.
Knowing this, we can compute the shortest distance between any two tiles on such a grid, by decomposing the distance into two components: a diagonal movement and a straight movement along one of the axis.
For example, for the distance between (1, 1) and (-2, 5) on a normal grid we have:
Normal distance = (1, 1) - (-2, 5) = (3, -4)
That would be the distance vector between the two tiles were they on a square grid. However we need to compensate for the grid deformation so we decompose like this:
(3, -4) = (3, -3) + (0, -1)
As you can see, we've decomposed the vector into one diagonal one (3, -3) and one straight along an axis (0, -1).
We now check to see if the diagonal one is along the deformation axis which is any point (n, -n) where n is an integer that can be either positive or negative.
(3, -3) does indeed satisfy that condition, so this diagonal vector is along the deformation. This means that the length (or cost) of this vector instead of being 3, it will be double, that is 6.
So to recap. The distance between (1, 1) and (-2, 5) is the length of (3, -3) plus the length of (0, -1). That is distance = 3 * 2 + 1 = 7.
Implementation in C++
Below is the implementation in C++ of the algorithm I have explained above:
int ComputeDistanceHexGrid(const Point & A, const Point & B)
{
// compute distance as we would on a normal grid
Point distance;
distance.x = A.x - B.x;
distance.y = A.y - B.y;
// compensate for grid deformation
// grid is stretched along (-n, n) line so points along that line have
// a distance of 2 between them instead of 1
// to calculate the shortest path, we decompose it into one diagonal movement(shortcut)
// and one straight movement along an axis
Point diagonalMovement;
int lesserCoord = abs(distance.x) < abs(distance.y) ? abs(distance.x) : abs(distance.y);
diagonalMovement.x = (distance.x < 0) ? -lesserCoord : lesserCoord; // keep the sign
diagonalMovement.y = (distance.y < 0) ? -lesserCoord : lesserCoord; // keep the sign
Point straightMovement;
// one of x or y should always be 0 because we are calculating a straight
// line along one of the axis
straightMovement.x = distance.x - diagonalMovement.x;
straightMovement.y = distance.y - diagonalMovement.y;
// calculate distance
size_t straightDistance = abs(straightMovement.x) + abs(straightMovement.y);
size_t diagonalDistance = abs(diagonalMovement.x);
// if we are traveling diagonally along the stretch deformation we double
// the diagonal distance
if ( (diagonalMovement.x < 0 && diagonalMovement.y > 0) ||
(diagonalMovement.x > 0 && diagonalMovement.y < 0) )
{
diagonalDistance *= 2;
}
return straightDistance + diagonalDistance;
}
Now, given the above implemented ComputeDistanceHexGrid function, you can now have a naive, unoptimized implementation of a selection algorithm that will ignore any tiles further than the specified selection range:
int _tmain(int argc, _TCHAR* argv[])
{
// your radius selection now becomes your usual orthogonal algorithm
// except you eliminate hex tiles too far away from your selection center
// for(x-range;x+range;x++); for(y-range;y+range;y++);
Point selectionCenter = {1, 1};
int range = 1;
for ( int x = selectionCenter.x - range;
x <= selectionCenter.x + range;
++x )
{
for ( int y = selectionCenter.y - range;
y <= selectionCenter.y + range;
++y )
{
Point p = {x, y};
if ( ComputeDistanceHexGrid(selectionCenter, p) <= range )
cout << "(" << x << ", " << y << ")" << endl;
else
{
// do nothing, skip this tile since it is out of selection range
}
}
}
return 0;
}
For a selection point (1, 1) and a range of 1, the above code will display the expected result:
(0, 0)
(0, 1)
(1, 0)
(1, 1)
(1, 2)
(2, 1)
(2, 2)
Possible optimization
For optimizing this, you can include the logic of knowing how far a tile is from the selection point (logic found in ComputeDistanceHexGrid) directly into your selection loop, so you can iterate the grid in a way that avoids out of range tiles altogether.
Simplest method i can think of...
minX = x-range; maxX = x+range
select (minX,y) to (maxX, y), excluding (x,y) if that's what you want to do
for each i from 1 to range:
if y+i is odd then maxX -= 1, otherwise minX += 1
select (minX, y+i) to (maxX, y+i)
select (minX, y-i) to (maxX, y-i)
It may be a little off; i just worked it through in my head. But at the very least, it's an idea of what you need to do.
In C'ish:
void select(int x, int y) {
/* todo: implement this */
/* should ignore coordinates that are out of bounds */
}
void selectRange(int x, int y, int range) {
int minX = x - range, maxX = x + range;
for (int i = minX; i <= maxX; ++i) {
if (i != x) select(i, y);
}
for (int yOff = 1; yOff <= range; ++yOff) {
if ((y+yOff) % 2 == 1) --maxX; else ++minX;
for (int i=minX; i<=maxX; ++i) {
select(i, y+yOff);
select(i, y-yOff);
}
}
}
I have been wracking my brain to come up with a solution to this problem.
I have a lookup table that returns height values for various points (x,z) on the grid. For instance I can calculate the height at A, B, C and D in Figure 1. However, I am looking for a way to interpolate the height at P (which has a known (x,z)). The lookup table only has values at the grid intervals, and P lies between these intervals. I am trying to calculate values s and t such that:
A'(s) = A + s(C-A)
B'(t) = B + t(P-B)
I would then use the these two equations to find the intersection point of B'(t) with A'(s) to find a point X on the line A-C. With this I can calculate the height at this point X and with that the height at point P.
My issue lies in calculating the values for s and t.
Any help would be greatly appreciated.
Try also bilinear interpolation or bicubic interpolation.
Depending on if you want to interpolate between ABC or ABCD the algorithm will change.
To interpolate between ABC (which I assume is what you want to do since you draw the diagonal) you will need to find the barycentric coordinates of P relative to ABC x and y positions then apply the barycentric coordinate to the height (z is assumed here) component of those triangles.
What about going this way: find u and v so that
P = B + u(A-B) + v(C-B)
If you write this out, you'll see that this is a 2x2 linear system with unknowns u and v, so I guess you know how to go on from there.
Oh, and once you have u and v you use the same exact formula as above for the height, only this time A,B,C,P will be the heights at these points.
Considering points value are available at four corners of a square of unit length, interpolated value at any point(x,y) inside the square is given by:
f(x,y) = [ (1-y)f(0,0) + yf(0,1) ](1-x) + [ (1-y)f(1,0)+y(f(1,1)) ]x
If square has length other than 1,say L then f(x,y) is given by:
f(x,y) = [ (L-y)f(0,0) + yf(0,L) ](L-x)/L^2 + [ (L-y)f(L,0)+y(f(L,L)) ]x/L^2
image
Here's an explicit example based on shape functions.
Consider the functions:
u1(x,z) = (x-x_b)/(x_c-x_b)
One has u1(x_b,z_b) = u1(x_a,z_a) = 0 (because x_a = x_b) and u1(x_c,z_c) = u1(x_d,z_d) = 1
u2(x,z) = 1 - u1(x,z)
Now we have u2(x_b,z_b) = u2(x_a,z_a) = 1 and u2(x_c,z_c) = u2(x_d,z_d) = 0
v1(x,z) = (z-z_b)/(z_a-z_b)
This function satisfies v1(x_a,z_a) = v1(x_d,z_d) = 1 and v1(x_b,z_b) = v1(x_c,z_c) = 0
v2(x,z) = 1 - v1(x,z)
We have v2(x_a,z_a) = v2(x_d,z_d) = 0 and v2(x_b,z_b) = v2(x_c,z_c) = 1
Now let's build new functions as follows:
S_D(x,z) = u1(x,z) * v1(x,z)
We get S_D(x_d, z_d) = 1 and S_D(x_a,z_a) = S_D(x_b,z_b) = S_D(x_c,z_c) = 0
S_C(x,z) = u1(x,z) * v2(x,z)
We get S_C(x_c, z_c) = 1 and S_C(x_a,z_a) = S_C(x_b,z_b) = S_C(x_d,z_d) = 0
S_A(x,z) = u2(x,z) * v1(x,z)
We get S_A(x_a, z_a) = 1 and S_A(x_b,z_b) = S_A(x_c,z_c) = S_A(x_d,z_d) = 0
S_B(x,z) = u2(x,z) * v2(x,z)
We get S_B(x_b, z_b) = 1 and S_B(x_a,z_a) = S_B(x_c,z_c) = S_B(x_d,z_d) = 0
Now define your interpolating function as
H(x,z) = h_a * S_A(x,z) + h_b * S_B(x,z) + h_c * S_C(x,z) + h_d * S_D(x,z),
where h_a is the heigh at point A, h_b is the height at point B, and so on.
You can easily verify that H is indeed an interpolating function:
H(x_a,z_a) = h_a, H(x_b,z_b) = h_b, H(x_c,z_c) = h_c and H(x_d,z_d) = h_d.
Now, in order to approximate the height at P, all you need to do is evaluate H at this point:
h_p = H(x_p, z_p)
The functions S are normally referred to as "shape functions". There's one such function for each node you want your interpolated value to depend on, and in this case they all satisfy Kronecker's delta property (they take the value one at one node and zero at all other nodes).
There are many ways to build shape functions for a given set of nodes. If I remember correctly, the construction of 2D shape functions by multiplication of 1D shape functions (as we've done in this case) is called "tensor product of functions" (easy in this case because the grid is rectangular). We have ended up with four functions (one per node), all of them linear combinations of {1, x, z, xz}.
If you want to use only three points for your interpolation, then you should be able to easily build three shape functions as linear combinations of {1, x, z} only, but you will loose a 25% of the height information provided by the grid and your interpolant will not be smooth inside the rectangle when h_b != h_d.
I'm writing iPhone code that fuzzily recognizes whether a swiped line is straight-ish. I get the bearing of the two end points and compare it to 0, 90, 180 and 270 degrees with a tolerance of 10 degrees plus or minus. Right now I do it with a bunch of if blocks, which seems super clunky.
How to write a function that, given the bearing 0..360, the tolerance percentage (say 20% = (-10° to +10°)) and a straight angle like 90 degrees, returns whether the bearing is within the tolerance?
Update: I am, perhaps, being too specific. I think a nice, general function that determines whether a number is within a percentage of another number has utility in many areas.
For instance: Is the number swipeLength within 10% of maxSwipe? That would be useful.
BOOL isNumberWithinPercentOfNumber(float firstN, float percent, float secondN) {
// dunno how to calculate
}
BOOL result;
float swipeLength1 = 303;
float swipeLength2 = 310;
float tolerance = 10.0; // from -5% to 5%
float maxSwipe = 320.0;
result = isNumberWithinPercentOfNumber(swipeLength1, tolerance, maxSwipe);
// result = NO
result = isNumberWithinPercentOfNumber(swipeLength2, tolerance, maxSwipe);
// result = YES
Do you see what I'm getting at?
int AngularDistance (int angle, int targetAngle)
{
int diff = 0;
diff = abs(targetAngle - angle)
if (diff > 180) diff = 360 - diff;
return diff;
}
This should work for any two angles.
20% as a decimal is equal to 0.2. Just divide by 100.0 to get the decimal. Divide by 2.0 to get half of the acceptable range. (Combined into 200.0 divisor)
From there, add and subtract from 1.0 to get the 90%, and 110% values.
If the first number is between the ranges, then there you have it.
BOOL isNumberWithinPercentOfNumber(float firstN, float percent, float secondN) {
float decimalPercent = percent / 200.0;
float highRange = secondN * (1.0 + decimalPercent);
float lowRange = secondN * (1.0 - decimalPercent);
return lowRange <= firstN && firstN <= highRange;
}
Note: there's no error checking here for NaN or negative values. You'll want to add that for production code.
Update: to make percent to include both +/- range.
Answer to your refined/new question:
bool isNumberWithinPercentOfNumber (float n1, float percentage, float n2)
{
if (n2 == 0.0) //check for div by zero, may not be necessary for float
return false; //default for a target value of zero is false
else
return (percentage > abs(abs(n2 - n1)/n2)*100.0);
}
To explain, you take the absolute difference between your test and target value, and divide it by the target value (the two 'abs'olute calls make sure this works with negative target and test numbers too, but not with negative percentages/tolerances). This gives you the percentage of the difference expressed as decimal fraction, multiplies it with 100 to give the 'common' expression of percentage (10% = 0.10),