In the last few days I try to solve this problem. I even have the solution but I can't figure it out. Can someone help me?
Here the problem:
You are given two rectangles on a plane.
The centers of both rectangles are located in the origin of coordinates
(meaning the center of the rectangle's symmetry).
The first rectangle's sides are parallel to the coordinate axes:
the length of the side that is parallel to the Ox axis, equals w,
the length of the side that is parallel to the Oy axis, equals h.
The second rectangle can be obtained by rotating the first rectangle
relative to the origin of coordinates by angle α.
Example:
http://i.imgur.com/qi1WQVq.png
Your task is to find the area of the region which belongs to both
given rectangles. This region is shaded in the picture.
Input
The first line contains three integers w, h, α (1 ≤ w, h ≤ 106; 0 ≤ α ≤ 180). Angle α is given in degrees.
Output
In a single line print a real number — the area of the region which belongs to both given rectangles.
The answer will be considered correct if its relative or absolute error doesn't exceed 10 - 6.
Sample test(s)
input
1 1 45
output
0.828427125
input
6 4 30
output
19.668384925
Here a possible implementation:
<?php
list($w, $h, $alphaInt) = explode(' ', '34989 23482 180');
if ($alphaInt == 0 || $alphaInt == 180) {
$res = $h * $w;
}
else if ($alphaInt == 90) {
$res = $h * $h;
}
else {
if ($alphaInt > 90) $alphaInt = 180 - $alphaInt;
$alpha = $alphaInt / 180.0 * M_PI;
//echo '$alpha:' . $alpha . "\n";
$cos = cos($alpha);
$sin = sin($alpha);
//echo '$cos: ' . $cos . "\n";
//echo '$sin: ' . $sin . "\n";
$c = $w / 2 * $cos + $h / 2 * $sin - $w / 2;
//echo '$c: ' . $c . "\n";
$r1 = $c / $cos;
$r2 = $c / $sin;
//echo '$r1: ' . $r1 . "\n";
//echo '$r2: ' . $r2 . "\n";
$c = $w / 2 * $sin + $h / 2 * $cos - $h / 2;
//echo '$c: ' . $c . "\n";
$r3 = $c / $cos;
$r4 = $c / $sin;
//echo '$r3: ' . $r3 . "\n";
//echo '$r4: ' . $r4 . "\n";
if ($r1 < 0 || $r2 < 0 || $r3 < 0 || $r4 < 0) {
$res = $h * $h / $sin; //$res = $w * $w / $cos;
}
else {
$res = $h * $w - $r1 * $r2 - $r3 * $r4;
}
}
echo '$res: ' . $res . "\n";
Small alpha
When w*sin(alpha) < h*(1+cos(alpha)) (i.e., before the vertices of the new rectangle meet the vertices of the old one for the first time), the area of the intersection is the area of the original rectangle (w * h) minus 4 triangles (2 pairs of identical ones). Let the bigger triangle have hypotenuse a and the smaller hypotenuse b, then the area is
A = w * h - a*a*cos(alpha)*sin(alpha) - b*b*cos(alpha)*sin(alpha)
The sides of the original rectangle satisfy a system of equations:
a + a * cos(alpha) + b * sin(alpha) = w
a * sin(alpha) + b + b * cos(alpha) = h
Using the half-angle formulas,
a * cos(alpha/2) + b * sin(alpha/2) = w/(2*cos(alpha/2))
a * sin(alpha/2) + b * cos(alpha/2) = h/(2*cos(alpha/2))
thus (the matrix on the LHS is a rotation!)
a^2 + b^2 = (w^2 + h^2) / (2*cos(alpha/2))^2
and
A = h * w - (w^2 + h^2) * cos(alpha)* sin(alpha) / (2*cos(alpha/2))^2
(this can be simplified further a little bit)
Bigger alpha
When alpha is bigger (but still alpha<pi/2), the intersection is a parallelogram (actually, a rhombus) whose 2 altitudes are h and 4 sides h/sin(alpha) and the area is, thus, h*h/sin(alpha) (yes, it does not depend on w!)
Other alpha
Use symmetry to reduce alpha to [0;pi/2] and use one of the two cases above.
You might try describing both rectangles as solutions to a system of four linear insqualities.
The set of points in their intersection is the set of solutions to both sets of linear inequalities.
You want the area of that set of solutions. You can find all points at which at least two of your eight inequalities are tight. Filter out those that don't satisfy all of the inequalities. Then take their convex hull using Graham's scan and compute the area using the surveyor's formula.
This method works to find the intersection of any two convex polygons. Slightly modified, it generalises (in the form of Fourier-Motzkin elimination and the double description method for computing the intersection and determinants for volume calculation) to convex polyhedra in any dimension.
Related
This code represents the plot of the function g with two horizontal lines and one vertical line:
function y = g(x)
if x < 5 | 50 < x then
error("Out of range");
elseif x <= 11 then
y = -59.535905 + 24.763399 * x - 3.135727 * x^2 + 0.1288967 * x^3;
return;
elseif x <= 12 then
y = 1023.4465 - 270.59543 * x + 23.715076 * x^2 - 0.684764 * x^3;
return;
elseif x <= 17 then
y = -307.31448 + 62.094807 *x - 4.0091108 * x^2 + 0.0853523 * x^3;
return;
else
y = 161.42601 - 20.624104 * x + 0.8567075 * x^2 - 0.0100559 * x^3;
end
endfunction
**//this represents the vertical line**
a=linspace(45,45,60)
b=linspace(0,70,60)
plot(a,b,style='r')
**//this represents the first horizontal line**
a=linspace(0,60,60)
b=linspace(30,30,60)
plot(a,b,style='g')
//this represents the second horizontal line
a=linspace(0,60,60)
b=linspace(40,40,60)
plot(a,b,style='g')
//this is the graph of function "g"
t = [5:50];
plot(t, feval(t, g));
// the part of code is for to find the solution of fsolve
//plot(t, feval(t, g)-30);
//plot(t, feval(t, g)-60);
//deff('[y] = g2(x)', 'y = g(x)-30');
//deff('[y] = g3(x)', 'y = g(x)-40');
The problem is that I want to find the four points of intersection between the curve and the three lines and calculate the colored surface. and how can I colorful this area in Scilab because I used paint to better explain the figure. and welcome any help.
you just have to integrate max(0,min(g(x),40)-30) between x=45 and x=50.
integrate('max(0,min(g(x),40)-30)','x',45,50)
Before testing please change the first test of your g function to if 50 < x then (there is currently a bug in integrate, which calls the function to integrate with 1 as argument regardless of integration domain)
I'm trying to calculate the distance from a lat, lon using haversine formula. For some reason this only works in the northern hemisphere and I'm suspecting its because of the abs. Once I remove the absolute value, the code works fine. So I was just wondering what is the purpose of using it?
'(3956 * 2 * ASIN(SQRT( POWER(SIN((' . $latitude . ' - abs(r.latitude)) *
pi()/180 / 2),2) + COS(' . $latitude . ' * pi()/180 ) * COS(abs(r.latitude) *
pi()/180) * POWER(SIN((' . $longitude . '-r.longitude) * pi()/180 / 2), 2) )))
< ' . $radius;
I am working with Latitude / Longitude coordinates in a google map.
I have two lines :
Line A : 48.31508162629726, -2.591741396838972 to 48.40216156645915, -2.2218462112093404
Line B : 48.383816077371215, -2.274292940053768 to 48.66103546935337, -1.7066197241571377
I then use the following formula to find the point where they cross.
var XAsum = A.LngStart - A.LngEnd;
var XBsum = B.LngStart - B.LngEnd;
var YAsum = A.LatStart - A.LatEnd;
var YBsum = B.LatStart - B.LatEnd;
var LineDenominator = XAsum * YBsum - YAsum * XBsum;
if(LineDenominator == 0.0)
return false;
var a = A.LngStart * A.LatEnd - A.LatStart * A.LngEnd;
var b = B.LngStart * B.LatEnd - B.LatStart * B.LngEnd;
var x = (a * XBsum - b * XAsum) / LineDenominator;
var y = (a * YBsum - b * YAsum) / LineDenominator;
This tells me that the lines do indeed cross and returns the x and y values.
However, when I plot the returned point, it is offset (not much) from the real intersection.
Is there a better and just as fast algorithm I could use which will return me the correct intersection point ?
It needs to be fast as I am iterating over a large number of lines (~1000).
EDIT : Note this is giving me an error offset of around 7.5 meters
I'm assuming the algorithm you're using is the one for finding line intersections on a Cartesian coordinate system (i.e. a plane). Unfortunately, the earth is not a plane (or even a sphere) so using that algorithm will introduce error. Google Maps uses an ellipsoid (specifically WGS84) to approximate the surface of the earth, so you'll need an algorithm for finding the intersections of arcs on an ellipsoid.
This page might contains some helpful information:
http://mathhelpforum.com/calculus/90196-point-intersection-two-lines.html
After searching and trying to use your code, I discover the main problem came from the fact you're not checking for intersection of segment. In many case the coord of the intersection are outside of the segment, meanig you're checking for intersection of line.
Here is a piece of PHP code. Assuming you have 2 lines in GPS Coord (x1y1-x2y2 for the first one and x3y3-x4y4 for the second one)
$x1 = deg2rad($x1);
$y1 = deg2rad($y1);
$x2 = deg2rad($x2);
$y2 = deg2rad($y2);
$x3 = deg2rad($x3);
$y3 = deg2rad($y3);
$x4 = deg2rad($x4);
$y4 = deg2rad($y4);
$denom = (($y4 - $y3) * ($x2 - $x1)) - (($x4 - $x3) * ($y2 - $y1));
// Id denom = 0 -> parallele line
if ($denom != 0)
{
$ua = (($x4 - $x3) * ($y1 - $y3) - ($y4 - $y3) * ($x1 - $x3))/$denom;
$ub = (($x2 - $x1) * ($y1 - $y3) - ($y2 - $y1) * ($x1 - $x3))/$denom;
if ($ua >= 0 && $ua <= 1 && $ub >= 0 && $ub <= 1)
{
$intersection_x = ($x1 + $ua*($x2 - $x1));
$intersection_y = ($y1 + $ua*($y2 - $y1));
echo "<br><b>Intersection: ".round(rad2deg($intersection_x),6).",".round(rad2deg($intersection_y),6)."</b>";
}
else
{
echo "<br>No intersection";
}
}
I need to calculate the volume of a tetrahedron given the coordinates of its four corner points.
Say if you have 4 vertices a,b,c,d (3-D vectors).
Now, the problem comes down to writing code which solves cross product and dot product of vectors. If you are from python, you can use NumPy or else you can write code on your own.
The Wikipedia link should definitely help you. LINK
One way to compute this volume is this:
1 [ax bx cx dx]
V = --- det [ay by cy dy]
6 [az bz cz dz]
[ 1 1 1 1]
This involves the evaluation of a 4×4 determinant. It generalizes nicely to simplices of higher dimensions, with the 6 being a special case of n!, the factorial of the dimension. The resulting volume will be oriented, i.e. may be negative depending on the order of points. If you don't want that, take the absolute value of the result.
If you have a math library at hand, the above formulation might be among the easiest to write down, and the software can take it from there. If not, you might simplify things first by subtracting the d coordinates from a through c. This will not change the volume but turn the rightmost column into (0, 0, 0, 1). As a result, you can compute the value of the matrix simply as the determinant of the upper left 3×3 submatrix. And using the equation
det(a, b, c) = a · (b × c)
you end up with the formula from Surya's answer.
In case you don't have coordinates for the points, but just distances between them, look at Tartaglia's Formula which is essentually a squared version of the above, although it's not as straight-forward as it would seem at first glance.
Ivan Seidel's example, in Python (answer is 1.3333...)
def determinant_3x3(m):
return (m[0][0] * (m[1][1] * m[2][2] - m[1][2] * m[2][1]) -
m[1][0] * (m[0][1] * m[2][2] - m[0][2] * m[2][1]) +
m[2][0] * (m[0][1] * m[1][2] - m[0][2] * m[1][1]))
def subtract(a, b):
return (a[0] - b[0],
a[1] - b[1],
a[2] - b[2])
def tetrahedron_calc_volume(a, b, c, d):
return (abs(determinant_3x3((subtract(a, b),
subtract(b, c),
subtract(c, d),
))) / 6.0)
a = [0.0, 0.0, 0.0]
d = [2.0, 0.0, 0.0]
c = [0.0, 2.0, 0.0]
b = [0.0, 0.0, 2.0]
print(tetrahedron_calc_volume(a, b, c, d))
Here is the code, in PHP, that calculates the Volume of any Tetrahedron given 4 points:
class Math{
public static function determinant(array $vals){
$s = sizeof($vals);
$sum = 0.0;
for( $i=0; $i < $s ; $i++ ){
$mult = 1.0;
for($j=0; $j < $s ; $j++ ){
$mult *= $vals[$j][ ($i+$j)%$s ];
}
$sum += $mult;
}
for( $i=0; $i < $s ; $i++ ){
$mult = 1;
for($j=0; $j < $s ; $j++ ){
$mult *= $vals[$j][ ($i-$j < 0? $s - ($j-$i) :($i-$j)) ];
}
$sum -= $mult;
}
return $sum;
}
public static function subtract(array $a, array $b){
for($i = 0; $i < sizeof($a); $i++)
$a[$i] -= $b[$i];
return $a;
}
}
// TEST CASE
$a = array(0,0,0);
$d = array(2,0,0);
$c = array(0,2,0);
$b = array(0,0,2);
echo abs(Math::determinant(array(
Math::subtract($a, $b),
Math::subtract($b, $c),
Math::subtract($c, $d),
)))/6;
Ok,
I have a projectile that has its position defined such that:
a.x = initialX + initialDX * time;
a.y = initialY + initialDY * time + 0.5 * gravtiy * time^2;
I want to be able to predict which obstacles in my environment this projectile will collide with. I plan on checking the distance from A the closest point on the curve to the point P.
I figure that at the point A the tangent to the curve will be perpendicular to the vector AP, and that the tangent to the curve at A will simply be the velocity V of the projectile at that point.
AP dot V = 0
ap.x = initialX + initialDX * time - p.x;
ap.y = initialY + initialDY * time + gravity * time^2 - p.y;
v.x = initialDX;
v.y = initialDY + gravity * time;
=>
AP dot V =
( 0.5 * gravity^2 ) * t^3 +
( 1.5 * gravity * initialDY ) * t^2 +
( initialDX^2 + initialDY^2 + gravity * ( initialY - p.y ) ) * t +
( initialDX * ( initialX - p.x ) + initialDY * ( initialY - p.y ) )
From here I can see that this is a cubic function. I have spent some time researching online and found that there is a general equation that seems to work for certain values for finding the roots.
This is the process I have attempted to implement.
http://www.sosmath.com/algebra/factor/fac11/fac11.html
a = 0.5 * gravity^2;
b = 1.5 * gravity * initialDY;
c = initialDX^2 + initialDY^2 + gravity * ( initialY - p.y );
d = initialDX * ( initialX - p.x ) + initialDY * ( initialY - p.y );
A = ( c - ( b * b ) / ( 3 * a ) ) / a;
B = -( d + ( 2 * b * b * b ) / ( 27 * a * a ) - ( b * c ) / ( 3 * a ) ) / a;
workingC = -Math.pow( A, 3 ) / 27;
u = ( -B + Math.sqrt( B * B - 4 * workingC ) ) / 2; // Quadratic formula
s = Math.pow( u + B, 1 / 3 );
t = Math.pow( u, 1 / 3 );
y = s - t;
x = y - b / ( 3 * a );
When I plug x back into my original equations for the curve as the time, this should give me A. This seems to work well for certain values, however when p.y is above a certain value, I don't have a positive to take a square root of in the quadratic equation.
I don't have a full enough understanding of the math to understand why this is happening, or what I can do to resolve the issue.
Any help on this would be much appreciated.
UPDATE:
I have adjusted my algorithm to deal with complex roots, however I am still having trouble.
This is what I do now if the discriminant is negative:
a = 0.5 * gravity^2;
b = 1.5 * gravity * initialDY;
c = initialDX^2 + initialDY^2 + gravity * ( initialY - p.y );
d = initialDX * ( initialX - p.x ) + initialDY * ( initialY - p.y );
A = ( c - ( b * b ) / ( 3 * a ) ) / a;
B = -( d + ( 2 * b * b * b ) / ( 27 * a * a ) - ( b * c ) / ( 3 * a ) ) / a;
workingC = -Math.pow( A, 3 ) / 27;
discriminant = B * B - 4 * workingC;
then if discriminant < 0;
uc = new ComplexNumber( -B / 2, Math.sqrt( -discriminant ) / 2 );
tc = uc.cubeRoot( );
uc.a += B;
sc = uc.cubeRoot( );
yc = sc - tc;
yc.a -= b / ( 3 * a );
x = -d / ( yc.a * yc.a + yc.b * yc.b );
For some reason, this is still not giving me the results I expect. Is there anything that stands out as being wrong here?
Real polynomials can have complex number roots and if the roots are not real, they occur in conjugate pairs.
This implies cubics always have at least one real root.
Now if you get a complex root using your method, you can try to get the conjugate, mutiply and divide the constant of the cubic, take reciprocal to get the real root.
So if you had to take the square root of a -ve number, then it is same as multiplying the square root of its modulus by the imaginary number 'i'.
So if you represent your root as (m,n) denoting the complex number m + in. Then the other root is m - in = (m, -n) and m and n are real numbers.
The cubic can then be written as P(x) = (x^2 - 2m + (m^2 + n^2))(x-r).
So if P(x) = x^3 - a_1 *x^2 + a_2*x - a_3, then we have that r = a_3/(m^2 + n^2) (a_3 is the product of the roots, which is r(m^2+n^2))
A simpler way to get r would be to use the formula r = a_1 - 2m (a_1 is the sum of the roots, which is r+2m).
Check out: http://en.wikipedia.org/wiki/Complex_number