Draw Camera Range with Postgis - postgresql

i am working on some camera data. I have some points which consist of azimuth, angle, distance, and of course coordinate field attributes. In postgresql postgis I want to draw shapes like this with functions.
how can i draw this pink range shape?
at first should i draw 360 degree circle then extracting out of my shape... i dont know how?

I would create a circle around the point(x,y) with your radius distance, then use the info below to create a triangle that has a larger height than the radius.
Then using those two polygons do an ST_Intersection between the two geometries.
NOTE: This method only works if the angle is less than 180 degrees.
Note, that if you extend the outer edges and meet it with a 90 degree angle from the midpoint of your arc, you have a an angle, and an adjacent side. Now you can SOH CAH TOA!
Get Points B and C
Let point A = (x,y)
To get the top point:
point B = (x + radius, y + (r * tan(angle)))
to get the bottom point:
point C = (x + radius, y - (r * tan(angle)))
Rotate your triangle to you azimouth
Now that you have the triangle, you need to rotate it to your azimuth, with a pivot point of A. This means you need point A at the origin when you do the rotation. The rotation is the trickiest part. Its used in computer graphics all the time. (Actually, if you know OpenGL you could get it to do the rotation for you.)
NOTE: This method rotates counter-clockwise through an angle (theta) around the origin. You might have to adjust your azimuth accordingly.
First step: translate your triangle so that A (your original x,y) is at 0,0. Whatever you added/subtracted to x and y, do the same for the other two points.
(You need to translate it because you need point A to be at the origin)
Second step: Then rotate points B and C using a rotation matrix. More info here, but I'll give you the formula:
Your new point is (x', y')
Do this for points B and C.
Third step: Translate them back to the original place by adding or subtracting. If you subtracted x last time, add it this time.
Finally, use points {A,B,C} to create a triangle.
And then do a ST_Intersection(geom_circle,geom_triangle);
Because this takes a lot of calculations, it would be best to write a program that does all these calculations and then populates a table.

PostGIS supports curves, so one way to achieve this that might require less math on your behalf would be to do something like:
SELECT ST_GeomFromText('COMPOUNDCURVE((0 0, 0 10), CIRCULARSTRING(0 10, 7.071 7.071, 10 0), (10 0, 0 0))')
This describes a sector with an origin at 0,0, a radius of 10 degrees (geographic coordinates), and an opening angle of 45°.
Wrapping that with additional functions to convert it from a true curve into a LINESTRING, reduce the coordinate precision, and to transform it into WKT:
SELECT ST_AsText(ST_SnapToGrid(ST_CurveToLine(ST_GeomFromText('COMPOUNDCURVE((0 0, 0 10), CIRCULARSTRING(0 10, 7.071 7.071, 10 0), (10 0, 0 0))')), 0.01))
Gives:
This requires a few pieces of pre-computed information (the position of the centre, and the two adjacent vertices, and one other point on the edge of the segment) but it has the distinct advantage of actually producing a truly curved geometry. It also works with segments with opening angles greater than 180°.
A tip: the 7.071 x and y positions used in the example can be computed like this:
x = {radius} cos {angle} = 10 cos 45 ≈ 7.0171
y = {radius} sin {angle} = 10 sin 45 ≈ 7.0171
Corner cases: at the antimeridian, and at the poles.

Related

Cheapest way to find Vector magnitude from a given point and angle

I am trying to determine a players depth position on a plane, which defines the walkable ground in a 2D brawler game. The problem is depictured in the following drawing:
C represents the players current position. I need to find the magnitude of vector V. Since I am not strong on linear algebra, the one thing I can think of is: determining the intersection point P of L1 and L2, and then take the magnitude from AP. However, I get the feeling there must be an easier way to find V, since I already know the angle the vector should have, given by vector from AB.
Any input would be appreciated, since I am looking forward to step up my linear algebra game.
Edit: As it is unclear thanks to my lack of drawing skills: the geometry depicted above is a parallelogram. The vector V I am looking for is parallel to the left and right side of the parallelogram. Depth does not mean, that I am looking for the vector perpendicular to the top side, but it refers to the fake depth of a purely 2D game. The parallelogram is therefore used as a means for creating the feeling of walking along a z axis.
The depth of your player (length of V) as measured from the top line in your drawing, is just the difference between A.y and C.y. This is seperate from the slant in the parralelogram, as we're just looking at depth.
example:
float v;
Vector2 a = new Vector2(100, 100); //The point you're measuring from
Vector2 c = new Vector2(150, 150); //Your character position
v = c.y - a.y; // This is the length of V.
//In numbers: 50 = 150 - 100
Illustrated: image not to scale
This works for any coördinate in your plane.
Now if you'd want to get the length of AC is when you'd need to apply some pythagoras, which is a² + b² = c². In the example that would mean in code:
Vector2 a = new Vector2(100, 100);
Vector2 c = new Vector2(150, 150);
float ac1 = Mathf.Sqrt(Mathf.Pow(c.x - a.x, 2) + Mathf.Pow(c.y - a.y, 2));
Now that is quite a sore to have to type out every time, and looks quite scary. But Unity has you covered! There is a Vector method called Distance
float ac2 = Vector2.Distance(a, c);
Which both return 70.71068 which is the length of AC.
This works because for any point c in your area you can draw a right angled triangle from a to c.
Edit as per comment:
If you want your "depth" vector to be parallel with the sides of the paralellogram we can just create a triangle in the parallelogram of which we calculate the hypotenuse.
Since we want the new hypotenuse of our triangle to be parallel to the parallelogram we can use the same angle θ as point B has in your drawing (indicated by pink in mine), of which I understood you know the value.
We also know the length of the adjacent (indicated in blue) side of this new triangle, as that is the height we calculated earlier (c.y - a.y).
Using these two values we can use cosine to find the length of hypotenuse (indicated in red) of the triangle, which is equal to the vector V, in parallel with the parallelogram.
the formula for that is: hypotenuse = adjacent/cos(θ)
Now if we were to put some numbers in this, and for my example I took 55 for the angle θ. It would look like this
float v = 50/(cos(55));
image not to scale
Let's call the lower right vertex of the parallelogram D.
If the long sides of the parallelogram are horizontal, you can find magnitude of V vector by:
V.magnitude = (c.y - a.y) / sin(BAD)
Or if you prefer:
V.magnitude = AB.magnitude * (c.y - a.y)/(b.y - a.y)

PostgreSQL - Rotate geometric type giving unexpected results

I'm using PostgresSQL 9.5 to generate a rectangle (geometric type BOX).
That works fine
SELECT Box(Point(-50, -100), Point(50, 100)) ; -- this works
Then I try to rotate that box around the origin (its center point). The rotation function is both
* Scaling/rotation box '((0,0),(1,1))' * point '(2.0,0)'
/ Scaling/rotation box '((0,0),(2,2))' / point '(2.0,0)'
where the x-point is the scaling factor (2.0 in this example) and the y-point is the rotation radians (0 in this example).
To check that the rotation is correct, I calculate the height, width and area of the box for each angle.
SELECT
xx.deg, -- angle in degrees
xx.geom, -- geometry of box
Area(xx.geom),
Center(xx.geom),
Height(xx.geom),
Width(xx.geom)
FROM
(SELECT deg,
Box(Point(-5, -10), Point(5, 10)) / Point(1, Radians(deg)) -- scale box by factor 1 and rotate by radians(degrees)
AS geom
FROM Generate_series(0, 360, 90) AS deg -- generate list of degrees from 0 to 360 by 90
) xx;
The results, which don't change between using * or / functions,
deg;geom;area;center;height;width
0;"(5,10),(-5,-10)";200;"(0,0)";20;10
90;"(5.97218570021291,0.618912639168559),(-5.97218570021291,-0.618912639168559)";14.785044853294;"(0,0)";1.23782527833712;11.9443714004258
180;"(3.35025316397424,0.525130727607429),(-3.35025316397424,-0.525130727607429)";7.03728352666753;"(0,0)";1.05026145521486;6.70050632794848
270;"(2.24607945852279,0.584400089411209),(-2.24607945852279,-0.584400089411209)";5.25043614554159;"(0,0)";1.16880017882242;4.49215891704558
360;"(1.67575357650576,0.529070250354662),(-1.67575357650576,-0.529070250354662)";3.5463654570185;"(0,0)";1.05814050070932;3.35150715301153
show that the box is being rotated but also scaled - the height, width and area are all not constant. I read somewhere that a rotation needs to take into account scaling, but I don't understand what scaling factor should be used to compsenate for the rotation. The documentation doesn't give any examples, and most of the resources online are for PostGIS (i.e. ST_Rotate).
UPDATE
I have a working solution that is not the fastest but gives correct results. See here
https://stackoverflow.com/a/39680955/2327328
TL/DR: You cannot rotate boxes
The two operators * and / can be confusing. The idea is that they treat the two dimensional points as complex numbers and perform multiply (or divide) them as complex numbers. So for example point '(2,3)' * point '(1,-1)' returns (5,1) because (2+3i)*(1-i)=5+i or point '(0,1)' * point '(0,1)' returns (-1,0) because i*i=-1.
So if you want to use * to rotate by an angle say φ, you have to multiply by the complex number exp(i*φ) which is equal to cos(φ)+i*sin(φ). For example:
SELECT point '(1,0)' * point(cos(radians(45)),sin(radians(45)));
=> (0.707106781186548,0.707106781186547)
rotates the point (1,0) by 45 degrees counter clockwise.
Unfortunately, this doesn't work very well with boxes. If you do
SELECT box '((0,0),(1,1))' * point(cos(radians(45)),sin(radians(45)));
=> (1.11022302462516e-16,1.41421356237309),(0,0)
which means that postgres rotated the two points as individual points and not the whole box. The problem is that a box is a rectangle with sides parallel to the x and y axes. By that definition, if you rotate a box by 45 degrees, what you get is not a box. So you cannot rotate boxes.
In theory, it should be possible to rotate polygons. Unfortunatelly, it seems that this has not been implemented (yet?) in postgresql:
$ SELECT polygon(box '((0,0),(1,1))') * point(1,0);
ERROR: operator does not exist: polygon * point
LINE 1: SELECT polygon(box '((0,0),(1,1))') * point(1,0);

Approximating relative angle between two line segments on sphere surface

I am in need of an idea! I want to model the vascular network on the eye in 3D. I have made statistics on the branching behaviour in relation to vessel diameter, length etc. What I am stuck at right now is the visualization:
The eye is approximated as a sphere E with center in origo C = [0, 0, 0] and a radius r.
What I want to achieve is that based on the following input parameters, it should be able to draw a segment on the surface/perimeter of E:
Input:
Cartesian position of previous segment ending: P_0 = [x_0, y_0, z_0]
Segment length: L
Segment diameter: d
Desired angle relative to the previous segment: a (1)
Output:
Cartesian position of resulting segment ending: P_1 = [x_1, y_1, z_1]
What I do now, is the following:
From P_0, generate a sphere with radius L, representing all the points we could possibly draw to with the correct length. This set is called pool.
Limit pool to only include points with a distance to C between r*0.95 and r, so only the points around the perimeter of the eye are included.
Select only the point that would generate a relative angle (2) closest to the desired angle a.
The problem is, that whatever angle a I desire, is actually not what is measured by the dot product. Say I want an angle at 0 (i.e. that the new segment is following the same direction as the previous`, what I actually get is an angle around 30 degrees because of the curvature of the sphere. I guess what I want is more the 2D angle when looking from an angle orthogonal from the sphere to the branching point. Please take a look at the screenshots below for a visualization.
Any ideas?
(1) The reason for this is, that the child node with the greatest diameter is usually follows the path of the previous segment, whereas smaller child nodes tend to angle differently.
(2) Calculated by acos(dot(v1/norm(v1), v2/norm(v2)))
Screenshots explaining the problem:
Yellow line: previous segment
Red line: "new" segment to one of the points (not neccesarily the correct one)
Blue x'es: Pool (text=angle in radians)
I will restate the problem with my own notation:
Given two points P and Q on the surface of a sphere centered at C with radius r, find a new point T such that the angle of the turn from PQ to QT is A and the length of QT is L.
Because the segments are small in relation to the sphere, we will use a locally-planar approximation of the sphere at the pivot point Q. (If this isn't an okay assumption, you need to be more explicit in your question.)
You can then compute T as follows.
// First compute an aligned orthonormal basis {U,V,W}.
// - {U,V} should be a basis for the plane tangent at Q.
// - W should be normal to the plane tangent at Q.
// - U should be in the direction PQ in the plane tangent at Q
W = normalize(Q - C)
U = normalize(Q - P)
U = normalize(U - W * dotprod(W, U))
V = normalize(crossprod(W, U))
// Next compute the next point S in the plane tangent at Q.
// In a regular plane, the parametric equation of a unit circle
// centered at the origin is:
// f(A) = (cos A, sin A) = (1,0) cos A + (0,1) sin A
// We just do the same thing, but with the {U,V} basis instead
// of the standard basis {(1,0),(0,1)}.
S = Q + L * (U cos A + V sin A)
// Finally project S onto the sphere, obtaining the segment QT.
T = C + r * normalize(S - C)

point projection into yx rotated plane

I want to simulate depth in a 2D space, If I have a point P1 I suppose that I need to project that given point P1 into a plane x axis rotated "theta" rads clockwise, to get P1'
It seems that P1'.x coord has to be the same as the P1.x and the P1'.y has to b shorter than P1.y. In a 3D world:
cosa = cos(theta)
sina = sin(theta)
P1'.x = P1.x
P1'.y = P1.y * cosa - P1.z * sina
P1'.z = P1.y * sina + P1.z * cosa
Is my P1.z = 0? I tried it and P1'.y = P1.y * cosa doesn't result as expected
Any response would be appreciated, Thanks!
EDIT: What I want, now I rotate camera and translate matrix
EDIT 2: an example of a single line with a start1 point and a end1 point (it's an horizontal line, result expected is a falling line to the "floor" as long as tilt angle increases)
I think it's a sign error or an offset needed (java canvas drawing (0,0) is at top-left), because my new line with a tilt of 0 is the one below of all and with a value of 90º the new line and the original one match
The calculation you are performing is correct if you would like to perform a rotation around the x axis clockwise. If you think of your line as a sheet of paper, a rotation of 0 degrees is you looking directly at the line.
For the example you have given the line is horizontal to the x axis. This will not change on rotation around the x axis (the line and the axis around which it is rotating are parallel to one another). As you rotate between 0 and 90 degrees the y co-ordinates of the line will decrease with P1.y*cos(theta) down to 0 at 90 degrees (think about the piece of paper we have been rotating around it's bottom edge, the x axis, at 90 degrees the paper is flat, and the y axis is perpendicular to the page, thus both edges of the page have the same y co-ordinate, both the side that is the "x-axis" and the opposite parallel side will have y=0).
Thus as you can see for your example this has worked correctly.
EDIT: The reason that multiplying by 90 degrees does not give an exactly zero answer is simply floating point rounding

Objective-C: How do I calculate the x/y coordinates of a given distance on 2 different circle sizes, inside one another?

iPhone SDK and Objective-C
Goal:
I'm trying to calculate the 'x' and 'y' coordinates of 2 circles. I have the inner circle dimensions and want to calculate what the 'x' and 'y' coordinates of the larger outer circle circumference would be to match the same width (distance) along the edge of the larger circle as it does with the inner circle.
In the end, I just need to figure out what the edge x/y points would be for the large circles edge. So that it matches the same as the inner smaller circle. If the width is 10 high on the inner circle, I need to know the x/y points to make it 10 high to the larger circle. To make a rectangle that will extend. Perpendicular lines.
Example:
I'm using the following to calculate the first 2 sets of x/y for the arc on the inner circle to plot points:
- (CGPoint)coordinatePoints:(CGFloat)radius angleDegrees:(CGFloat)degrees xAxis:(CGFloat)x yAxis:(CGFloat)y {
CGFloat pointX = (CGFloat) ((radius * cos((degrees * M_PI) / 180.0f)) + x);
CGFloat pointY = (CGFloat) ((radius * sin((degrees * M_PI) / 180.0f)) + y);
CGPoint points = CGPointMake(pointX, pointY);
return points;
}
I call it for the first 2 positions on the inner circle. I need to figure out how to make it have the distance on the outer circle as well.
CGPoint innerPoints1 = [self coordinatePoints:innerRadius angleDegrees:startingPoint xAxis:x yAxis:y];
CGPoint innerPoints2 = [self coordinatePoints:innerRadius angleDegrees:endingPoint xAxis:x yAxis:y];
If the inner circle radius is 200, and the outer circle radius is 500, I want it to still be the same thickness from the inner circle to the larger outer circle when I plot the points.
// I have these calculated.
CGContextMoveToPoint(context, innerPoints1.x, innerPoints1.y);
CGContextAddLineToPoint(context, innerPoints2.x, innerPoints2.y);
// I need to find the solution for making innerPoints3 and innerPoints4 correctly.
CGContextAddLineToPoint(context, innerPoints3.x, innerPoints3.y);
CGContextAddLineToPoint(context, innerPoints4.x, innerPoints4.y);
I have the coordinates for the inner circle lines for spaced out x/y points. I need to find the proper way to get the same width plotted for the larger circle locations. Circle sizes will always change. Lengths of the lines will be dynamic. As I'm trying to create a polygon, I need to find 2 coordinates on the larger circles, for each segment.
Any help with this would be greatly appreciated.
Information graphics: a comprehensive illustrated reference
Page 74: In the section "Circular Column Graph", my end goal is to be able to produce the same result as displayed in the 3 images.
If the spokes are not too thick, then the arc length is a good approximation of the spoke width:
So first you construct your 2 inner points, with 2 angles (a1 and a2) centered around a main spoke angle (a).
Then you calculate the distance D between these points (or you approximate it by R1*(a2-a1))
Then you take the points on the outer circle with angle values centered around the same main spoke angle: a-0.5*D/R2 and a+0.5*D/R2. These points will be D apart (measured on the arc)