Coordinates system (PHP an array) - php

I have point A(x,y) and B(x,y). they listed as array (a => array(x,y), b => array(x,y))
How get lenght between point A and B. Please help in php. :)

Well, remember your high-school geometry.
r = square_root((x2 - x1)^2 + (y2 - y1)^2)
So in php:
$dx = $points['b'][0] - $points['a'][0];
$dy = $points['b'][1] - $points['a'][1];
$r = sqrt(pow($dx, 2) + pow($dy, 2));

Related

Get Random XYZ on surface of Sphere from Sphere Loc and Radius

I am trying to get random X Y Z coordinates on the surface of a sphere, based on the spheres center in X Y Z, and it's radius in PHP. Currently, my system is just purely random, hoping for a position on the planets center. I'm inept in math so please bear with me (dyscalculia and dyslexia).
Right now I have just random chaos as follows (note randint is a custom function that checks for rand_int, mt_rand and rand and uses the newest.
$nx = randint( abs( $poo['x'] - $max_distance_x ), abs( $poo['x'] + $max_distance_x ) );
$ny = randint( abs( $poo['y'] - $max_distance_y ), abs( $poo['y'] + $max_distance_y ) );
$nz = randint( abs( $poo['z'] - $max_distance_z ), abs( $poo['z'] + $max_distance_z ) );
but I have the planet radius $pradius, and planet XYZ center array $poo poo(x, y, z), and I think I can get random surface X Y Z, just not sure. I've looked at other languages but am having trouble understanding anything to port.
Update
Based on the two methods provided in an answer I have come up with the following two functions. However both to not function correctly.
The following function only produces craters (points) on the top of the planetoid (north pole), even though it should be calculating from planetoid center at it's radius.
function basic_spheroid_point( $cx, $cy, $cz, $r ) {
$x = randint(-$r, $r);
$y = randint(-$r, $r);
$z = randint(-$r, $r);
$dx = $x - $cx;
$dy = $y - $cy;
$dz = $z - $cz;
$dd = sqrt( ( $dx * $dx ) + ( $dy * $dy ) + ( $dz * $dz ) );
if ( $dd > $r )
return basic_spheroid_point( $cx, $cy, $cz, $r );
$dx = $r * $dx / $dd;
$dy = $r * $dy / $dd;
$dz = $r * $dz / $dd;
return array( $cx + $dx, $cy + $dy, $cz + $dz );
}
This function bunches craters at the North Pole of the planet, though there is also global coverage craters so it is working partially.
function uniform_spheroid_point($cx, $cy, $cz, $r) {
$ap = randint( 0, 359 );
$aq = randint( 0, 359 );
$dx = $r* cos( $ap ) * cos( $aq );
$dy = $r * sin( $aq );
$dz = $r * sin( $ap ) * cos( $aq );
return array( $cx + $dx, $cy + $dy, $cz + $dz );
}
You're currently selecting a point at random from the interior of a parallelepiped with side lengths 2*max_distance_x, 2*max_distance_y and 2*max_distance_z. Let us assume that these are all the same and equivalent to the radius r of the sphere on whose surface you'd like to randomly select points. Then, your method would select randomly from a cube of side length 2r. Essentially none of your random points will actually be on the surface of the sphere of radius r when selected in this way.
However - given a point in the cube, what you can do is this:
calculate the vector from the center point to your random point (the "delta"). For example, if your center point is 100,100,100 and your radius is 100 and you randomly pick point 50,100,150, the vector you're looking for is -50,0,50.
calculate the length of the vector from step 1. This uses the formula for the distance between two points, extended so that it contemplates the point's three coordinates: sqrt(dx^2 + dy^2 +dz^2). For example, our distance is sqrt((-50)^2 + 0^2 + 50^2) = sqrt(2500 + 0 + 2500) = 50sqrt(2).
scale the vector from step 1 by a factor equal to r/d where d is the vector's length as determined in step 2. For our example, we will scale the vector by a factor of r/d = 100/(50sqrt(2)) = 2/sqrt(2) = sqrt(2). This gives -50sqrt(2), 0, 50sqrt(2).
Now, add the scaled vector from step 3 to the center point to get a point on the surface of the sphere of radius r. In our example, the point on the surface of the sphere is 100-50sqrt(2), 100, 100+50sqrt(2).
Now the only issue with this is that some points are more likely to be chosen than others. The reason for this is that some points on the surface of the sphere have more of the cube outside them than other points do. Specifically, a point of the sphere lying on the bounding cube has no points further outside it, but the point on the sphere that intersects a line connecting the center of the cube and one of its corners has a lot of space outside the sphere). To get a truly uniform distribution of points, you'd need to exclude any points selected at random which do not lie inside or on the surface of the sphere. If you do that, you will get a uniform distribution of points by the above method. Because the volume of the cube is 8r^3 and the volume of the sphere is 4/3pir^3, and because 4/3pi ~ 4, you have about a 50% chance at each draw of getting a point that you have to throw away. On average, you'd expect to get one good point in every two draws. You should not typically need many random draws to get a good one, but it is technically unbounded.
If you want to make sure every random draw is a good one, I might suggest selecting two angles uniformly at random from 0 to 360 degrees. Then, use those angles to identify a point on the sphere. So, for instance, suppose you first draw angle p and then angle q. Angle p can determine the plain from which the point will be taken. This plane will intersect the sphere in a circular cross section. Angle q can then determine which point on this intersected circle is returned as the random point. Suppose these angles give point (x', y', z'). Well...
y' = r*sin(q) … since nothing else determines the y coordinate except q
x' = r*cos(p)*cos(q)
z' = r*sin(p)*cos(q)
This has the advantage of not needing to reject any random samples, and the disadvantage of requiring relatively more costly trigonometric operations.
EDIT: Pseudocode for each method
Method 1:
RandomPointOnSphere(centerX, centerY, centerZ, radius)
1. x = random(-radius, radius)
2. y = random(-radius, radius)
3. z = random(-radius, radius)
4. dx = x - centerX
5. dy = y - centerY
6. dz = z - centerZ
7. dd = sqrt(dx*dx + dy*dy + dz*dz)
8. if dd > radius then return RandomPointOnSphere(centerX, centerY, centerZ, radius)
9. dx = radius * dx / dd
10. dy = radius * dy / dd
11. dz = radius * dz / dd
12. return (centerX + dx, centerY + dy, centerZ + dz)
Method 2:
RandomPointOnSphere(centerX, centerY, centerZ, radius)
1. angleP = random(0, 359)
2. angleQ = random(0, 359)
3. dx = radius* cos(angleP) * cos(angleQ)
4. dy = radius * sin(angleQ)
5. dz = radius * sin(angleP) * cos(angleQ)
6. return (centerX + dx, centerY + dy, centerZ + dz)

Co-ordinates of the 3rd point in a triangle

Given :
Point A (a1,b1)
Point B (a2,b2)
Distance between A and B
Distance between A and C
Angle between AB and AC = 90deg
Have to find :
C(a3,b3)
I have the co-ordinates of 2 points A(x,y) and B(p,q) but want to find the co-ordinates of a third point C(m,n).
I know the distance between A and B, A and C, and the angle between A and C which is 90deg. I know this is simple Pythagoras theorem. But how do I implement it in php and what would be the formula?
Let $x,$y and $p,$q be the given coordinates of A and B, furthermore call $d the known distance between A and C and $d0 the known distance between A and B. By doing a little math you get the following formulae (here I'm directly implementing it in PHP):
$m = $x + ($q - $y) * $d / $d0;
$n = $y - ($p - $x) * $d / $d0;
There is also a second solution:
$m = $x - ($q - $y) * $d / $d0;
$n = $y + ($p - $x) * $d / $d0;
EDIT: Here is how I got the equations: I rotated the vector AB, which has the coordinates ($p - $x, $q - $y), by 90 degrees to obtain ($q - $y, -($p - $x)) and (-($q - $y), $p - $x) (depending whether clockwise or counter-clockwise) and then got the vector AC by scaling it with $d / $d0 (the ratio of their lengths). Now I just translated the vector by ($x, $y) to get ($m, $n).
Maybe this can be implemented more elegantly by using a vector class in PHP or even a whole library, but I think for this simple calculation it is much easier to implement it "by hand".

tan(deg2rad()) returns odd values for degrees between 180 to 360

$degree = 179;
$aX = $valueB + ($valueA - $aY)/tan(deg2rad($degree));
returns 742.710038369 as $aX
but when $degree is 180;
$degree = 180;
$aX = $valueB + ($valueA - $aY)/tan(deg2rad($degree));
returns -8.1656196766E+15 as $aX
and similar values all the way to 361 when it completes a full turn and returns 857.289961631 as $aX again.
How do I fix this, do I need to convert the different value or change something else?
Thanks in advance for your answers!
EDIT;
$degree = 180;
$valueA = 800;
$valueB = 800;
$aY = ($valueB/64) * (64) -1;
$aX = $valueB + ($valueA - $aY)/tan(deg2rad($degree));
$aY = round($aY/64,0);
$aX = round($aX/64,0);
As other comments have pointed out, dividing by 0 either does give or should give an error when the result should be an ordinary number. The present code snippet, if indeed there's a possible motivation for it, looks like an application for homogeneous coordinates, which represent directions in projective geometry. Representing a direction as the slope of a line with a linear expression only works when the slope is not vertical. In homogeneous coordinates, you can represent such directions easily, and you get numerical stability near such directions to boot.
That said, I cannot puzzle out what application the present code snippet might be part of, and thus whether this answer is relevant.

n random numbers within parameters

Let's say I have a number, such as 100, and I want to have 5 different random numbers generated, but they all must add up to 100, how would I do that? (preferably in PHP. For math wizards/statisticians, I don't need truly random numbers, but something that looks random).
So this function, would produce something like this:
5, 51, 9, 18, 19 = 100
34, 52, 3, 7, 4 =100
And so forth.
Ideally, something that takes 5, 100 and produces the rest:
generateRandom(100,5)
a = RandomInteger[{1, 96}]
b = RandomInteger[{1, 97 - a}]
c = RandomInteger[{1, 98 - a - b}]
d = RandomInteger[{1, 99 - a - b - c}]
e = 100 - a - b - c - d
Samples:
{34,25,26,3,12,Sum =,100}
{90,5,1,1,3,Sum =,100}
{29,16,21,9,25,Sum =,100}
{4,13,71,10,2,Sum =,100}
The numbers are no equally distributed, of course.
Edit
Here is a more homogeneous distribution:
a = RandomInteger[{1, 20}];
b = RandomInteger[{1, 40 - a}];
c = RandomInteger[{1, 60 - a - b}];
d = RandomInteger[{1, 80 - a - b - c}];
e = 100 - a - b - c - d;
Output:
{5,33,2,8,52,Sum =,100}
{14,9,50,5,22,Sum =,100}
{3,23,12,34,28,Sum =,100}
{1,16,4,5,74,Sum =,100}
{6,28,6,9,51,Sum =,100}
{11,25,7,1,56,Sum =,100}
{4,34,12,18,32,Sum =,100}
{6,13,25,26,30,Sum =,100}
{8,27,14,5,46,Sum =,100}
{17,13,23,25,22,Sum =,100}
Here are the frequencies for the numbers:
Edit
Perhaps a better one:
a = Max[#, 1] & /# Evaluate[RandomInteger[{1, 20}, 5] - 1];
b = 100 - Total#a;
c = Mod[b, 5];
d = (b - c)/ 5;
a = a + d + {c, 0, 0, 0, 0};
Distribution:
Edit
In Mathematica you can easily generate all 5-Tuples that add up 100 as:
IntegerPartitions[100, {5}]
There are 38225 different beasts, without counting permutations
Length#IntegerPartitions[100, {5}]
(* -> 38225 *)
The frequency for each number in those quintuplets is:
Histogram#Flatten#IntegerPartitions[100, {5}]
The curve is very similar if one take permutations into account:
t = Tally#Flatten#(Permutations[#] & /# IntegerPartitions[100, {5}]);
ListLinePlot#SortBy[t, #[[1]] &][[All, 2]]
Along the lines of belisarius:
// Generates an array (of $elements elements) full of random numbers whose
// total is equal to the $total_sum
function generate_random_array($elements = 5, $total_sum = 100)
{
// build result array
$result = Array();
// iterate over all elements (except for the last, last will be the delta)
for ($_ = 0; $_ < ($elements - 1); $_++)
{
// typical low value (non-zero)
$low_value = 1;
// high value, skewed to have high results first
//$high_value = ($total_sum - ($elements - $_) - array_sum($result));
// high value, non-skewed
$step = (int)floor($total_sum / $elements); // give "not-to-exceed" ranges
$high_value = (($_ + 1) * $step) - array_sum($result);
// produce the result and add it
$result[] = rand($low_value,$high_value);
//$result[] = rand(1,65535) % $high_value + 1; // alternate to make rand a little smoother
}
// add the final result as the remainder
$result[] = $total_sum - array_sum($result);
// now return it
return $result;
}

Perspective transformation with GD

How can I apply a perspective transformation on an image
using only the PHP GD library?
I don't want to use a function someone else made I want to UNDERSTAND what's going on
I honestly don't know how to describe mathematically a perspective distortion. You could try searching the literature for that (e.g. Google Scholar). See also in the OpenGL documentation, glFrustum.
EDIT: Interestingly, starting with version 8, Mathematica has a ImagePerspectiveTransformation. In the relevant part, it says:
For a 3*3 matrix m, ImagePerspectiveTransformation[image,m] applies LinearFractionalTransform[m] to image.
This is a transformation that, for some a (matrix), b (vector), c (vector) and d (scalar), transforms the vector r to (a.r+b)/(c.r+d). In a 2D situation, this gives the homogeneous matrix:
a_11 a_12 b_1
a_21 a_22 b_2
c_1 c_2 d
To apply the transformation, you multiply this matrix by the column vector extended with z=1 and then take the first two elements of the result and divide them by the third:
{{a11, a12, b1}, {a21, a22, b2}, {c1, c2, d}}.{{x}, {y}, {1}} // #[[
1 ;; 2, All]]/#[[3, 1]] & // First /# # &
which gives:
{(b1 + a11 x + a12 y)/(d + c1 x + c2 y),
(b2 + a21 x + a22 y)/(d + c1 x + c2 y)}
With the example:
a = {{0.9, 0.1}, {0.3, 0.9}}
b = {0, -0.1}
c = {0, 0.1}
d = 1
You get this transformation:
im = Import["/home/cataphract/Downloads/so_q.png"];
orfun = BSplineFunction[ImageData[im], SplineDegree -> 1];
(*transf=TransformationFunction[{{0.9, 0.1, 0.}, {0.3,
0.9, -0.1}, {0., 0.1, 1.}}] -- let's expand this:*)
transf = {(0.9 x + 0.1 y)/(1.+ 0.1 y), (-0.1 + 0.3 x + 0.9 y)/(
1. + 0.1 y)} /. {x -> #[[1]], y -> #[[2]]} &;
ParametricPlot[transf[{x, y}], {x, 0, 1}, {y, 0, 1},
ColorFunction -> (orfun[1 - #4, #3] &),
Mesh -> None,
FrameTicks -> None,
Axes -> False,
ImageSize -> 200,
PlotRange -> All,
Frame -> False
]
Once you have a map that describes the position of a point of the final image in terms of a point in the original image, it's just a matter of finding its value for each of the points in the new image.
There's one additional difficulty. Since an image is discrete, i.e., has pixels instead of continuous values, you have to make it continuous.
Say you have a transformation that doubles the size of an image. The function to calculate a point {x,y} in the final image will look for point {x/2, y/2} in the original. This point doesn't exist, because images are discrete. So you have to interpolate this point. There are several possible strategies for this.
In this Mathematica example, I do a simple 2D rotation and use a degree-1 spline function to interpolate:
im = Import["d:\\users\\cataphract\\desktop\\img.png"]
orfun = BSplineFunction[ImageData[im], SplineDegree -> 1];
transf = Function[{coord}, RotationMatrix[20. Degree].coord];
ParametricPlot[transf[{x, y}], {x, 0, 1}, {y, 0, 1},
ColorFunction -> (orfun[1 - #4, #3] &), Mesh -> None,
FrameTicks -> None, Axes -> None, ImageSize -> 200,
PlotRange -> {{-0.5, 1}, {0, 1.5}}]
This gives:
PHP:
For the interpolation, google for "B-spline". The rest is as follows.
First choose a referential for the original image, say if the image is 200x200, pixel (1,1) maps (0,0) and pixel (200,200) maps to (1,1).
Then you have to guess where your final image will land when the transformation is applied. This depends on the transformation, you can e.g. apply it to the corners of the image or just guess.
Say you consider the mapped between (-.5,0) and (1, 1.5) like I did and that your final image should be 200x200 also. Then:
$sizex = 200;
$sizey = 200;
$x = array("min"=>-.5, "max" => 1);
$y = array("min"=>0, "max" => 1.5);
// keep $sizex/$sizey == $rangex/$rangey
$rangex = $x["max"] - $x["min"];
$rangey = $y["max"] - $y["min"];
for ($xp = 1; $xp <= $sizex; $xp++) {
for ($yp = 1; $yp <= $sizey; $yp++) {
$value = transf(
(($xp-1)/($sizex-1)) * $rangex + $x["min"],
(($yp-1)/($sizey-1)) * $rangey + $y["min"]);
/* $value should be in the form array(r, g, b), for instance */
}
}

Categories