Rotating body from spherical coordinates - graphics

Is it possible to rotate body which has its vertices defined in spherical coordinates.
Currently I am doing collage project in VHDL and is about rotating dodecahedron and presenting over VGA.
I applied pinhole camera model equations and that required just two sin/cos calculation and two multiplication per vertice.
I was just thinking about rotating around 3rd axis using 3 steps over two angles but i am unable to figure out proper equations and even if this is possible.
Edit
I think I got it.
Rotating over 3rd axis which is in same direction as camera is just 2D transform of camera coordinates once you you compute them. That mean than for rotating in 3 axes (ok two axis and one inclination) you need to apply total of 4 sin/cos computations and 4 multiplications. If somebody came up whit something better, fell free to post answer.

You can rotate around the y-axis by changing θ, and rotate around the z-axis by changing φ. Rotating around the x-axis, though, is a bit tougher.
One simple way would be to convert everything to catesian coordinates, perform the rotation, and convert back.
The equations for (x,y,z) (spherical-to-cartesian) are
x = r sin θ cos φ
y = r sin θ sin φ
z = r cos θ
The equations for rotating (x,y,z) to new points (x', y', z') around the x-axis by an angle α are
x' = x
= r sin θ cos φ
y' = y cos α - z sin α
= (r sin θ sin φ) cos α - (r cos θ) sin α
z' = y sin α + z cos α
= (r sin θ sin φ) sin α + (r cos θ) cos α
The equations for (r, θ, φ) (cartesian-to-spherical) are
r' = sqrt(x'2 + y'2 + z'2)
= r
θ' = cos-1(z'/r')
= cos-1(sin θ sin φ sin α + cos θ cos α)
φ' = tan-1(y'/x')
= tan-1(tan φ cos α - cotan θ sin α sec φ)
I don't know if there is a way to reduce that any further, but it should work.

Hopefully this will be helpful to someone in the future, but there is a small mistake in the above answer. It should be:
φ' = tan-1(y'/x')
= tan-1(tan φ cos α - cotan θ sin α sec φ)
I don't have the rep points to post this in the comment, but thought it would be useful.

Related

Why does foldl' use a lot of RAM with complex data structures?

Lazy fold uses a lot of RAM. In Data.List, foldl' provides a left fold that uses strict evaluation. For example, the following computes the sum of 10 million zeros with little increase in RAM usage.
sum0 = foldl' (+) 0 (replicate 10000000 0)
However, this does not seem to hold with complex data structures. For example, if we define addition for pairs of numbers and compute the sum of zero pairs, there is significant increase in RAM usage:
(x1,y1) <+> (x2,y2) = (x1 + x2,y1 + y2)
sum00 = foldl' (<+>) (0,0) (replicate 10000000 (0,0))
Why does that happen? Is there a way to decrease RAM usage?
foldl' only evaluates the intermediate state to weak head normal form—i.e. up to the first constructor. That's the most a generic function can do, and what functions that are called "strict" generally do. Evaluating (x1, y1) <+> (x2, y2) until it looks like a constructor gives (x1 + x2, y1 + y2), where the parts are still unevaluated (they have been "protected" by the (,)). Through the iteration, foldl' being strict keeps the state in the form (_, _) instead of (_, _) <+> (_, _) <+> ..., but the _s grow into huge unevaluated terms of form _ + _ + _ + ....
Modify <+> to evaluate the additions before it exposes the constructor.
(x1, y1) <+> (x2, y2) = x `seq` y `seq` (x, y)
where x = x1 + x2; y = y1 + y2
-- or
(x1, y1) <+> (x2, y2) = ((,) $! x1 + y1) $! x2 + y2
-- or (with deepseq package)
(x1, y1) <+> (x2, y2) = force (x1 + x2, y1 + y2)
-- x `seq` y = y, but only if x reaches WHNF
-- usually, evaluating x `seq` y to WHNF evaluates x (to WHNF) before it returns the result of evaluating y to WHNF
-- though that's not the official definition of `seq`, since Haskell nominally doesn't have an evaluation strategy
-- (and GHC's actual `seq` may do something different if GHC is feeling smart)

Alpha equivalence between variables in lambda calculus

Just a fairly simple question (so it seems to me). If two variables (x)(x) are alpha equivalent. Is (x1x2)(x2x1) alpha equivalent?
Two terms are alpha-equivalent iff one can be converted into the other purely by renaming bound variables.
A variable is considered to be a bound variable if it matches the parameter name of some enclosing lambda. Otherwise it's a free variable. Here are a few examples:
λx. x -- x is bound
λx. y -- y is free
λf. λx. f x y -- f and x are bound, y is free
f (λf. f x) -- the first f is free; the second is bound. x is free
z -- z is free
Basically, "bound" and "free" roughly correspond to the notions of "in scope" and "out of scope" in procedural languages.
Alpha-equivalence basically captures the idea that it's safe to rename a variable in a program if you also fix all the references to that variable. That is, when you change the parameter of a lambda term, you also have to go into the lambda's body and change the usages of that variable. (If the name is re-bound by another lambda inside the first lambda, you'd better make sure not to perform the renaming inside the inner lambda.)
Here are some examples of alpha-equivalent terms:
λx. x <-> λy. y <-> λberp. berp
λx. λf. f x <-> λx. λg. g x <-> λf. λx. x f <-> λx1. λx2. x2 x1
λf. λf. f f <-> λg. λf. f f <-> λf. λg. g g
So is x x alpha-equivalent to x1x2 x1x2? No! x is free in the first term, because it's not bound by an enclosing lambda. (Perhaps it's a reference to a global variable.) So it's not safe to rename it to x1x2.
I suspect your tutor really meant to say that λx. x x is alpha-equivalent to λx1x2. x1x2 x1x2. Here the x is bound by the lambda, so you can safely rename it.
Is x1 x2 alpha-equivalent to x2 x1? For the same reason, no.
And is λx1. λx2. x1 x2 equivalent to λx1. λx2. x2 x1? Again, no, because this isn't just a renaming - the x1 and x2 variables moved around.
However, λx1. λx2. x1 x2 is alpha-equivalent to λx2. λx1. x2 x1:
rename x1 to some temporary name like z: λz. λx2. z x2
rename x2 to x1: λz. λx1. z x1
rename z back to x2: λx2. λx1. x2 x1
Getting renaming right in a language implementation is a fiddly enough problem that many compiler writers opt for a nameless representation of terms called de Bruijn indices. Rather than using text, variables are represented as a number measuring how many lambdas away the variable was bound. A nameless representation of λx2. λx1. x2 x1 would look like λ. λ. 2 1. Note that that's exactly the same as the de Bruijn representation of λx1. λx2. x1 x2. de Bruijn indices thoroughly solve the problem of alpha-equivalence (although they are quite hard to read).

Recursion and parallelism in Haskell

I'm trying to understand how paralleling in Haskell works and I've found following example in Control.Parallel docs.
import Control.Parallel
-- Equation for the upper hemisphere of the unit circle
circle :: Double -> Double
circle x = sqrt (abs(1 - x^2))
-- Calculate the area of a right-handed Riemann rectangle
area :: Double -> Double -> Double
area x1 x2 = (x2 - x1) * circle x2
-- Recursively add the areas of the Riemann rectangles
parEstimate :: [Double] -> Double
parEstimate (x:[]) = 0
parEstimate (x:y:[]) = area x y
parEstimate (x:y:xs) =
smaller `par` (larger `pseq` smaller + larger)
where smaller = area x y
larger = parEstimate (y:xs)
But I couldn't find an explanation of how this recursion works: parEstimate (x:y:xs), cause all examples I've found contains only two arguments.
That's why I cannot find out how to run this function. That's how I do:
main = print (parEstimate [1.0, 2.0])
but not sure, if it's correct.
Also I would like to implement function calculating definite integral based on this example.
The recursion, essentially, is a simple fold-like recursion scheme; if this were purely sequential, you might write it as
seqEstimate :: [Double] -> Double
seqEstimate (x:[]) = 0
seqEstimate (x:y:[]) = area x y
seqEstimate (x:y:xs) = smaller + larger
where smaller = area x y
larger = seqEstimate (y:xs)
(In fact, you would probably just use zipWith instead: seqEstimate xs = sum (zipWith area xs (tail xs)).)
The parallelized version is similar. This time, though, par is used to indicate that the left-hand side (smaller) can be evaluated in parallel with the right-hand side (pseq larger (smaller + larger)). Whether or not the compiler chooses to do so, and regardless of whether smaller completes before or after larger, the sum of smaller + larger will be correctly computed.

How to compute coordinates of start/end points of a ArcByCenterPoint?

Given an ArcByCenterPoint, defined by:
center position (lat,lon in WGS84)
radius (meters)
startAngle (degrees)
endAngle (degrees)
how can we compute the position (lat, lon) of start/end points? I'm looking for a formula.
You can find appropriate formulas in the section Destination point given distance and bearing from start point here
Excerpt:
Formula:
φ2 = asin( sin φ1 ⋅ cos δ + cos φ1 ⋅ sin δ ⋅ cos θ )
λ2 = λ1 + atan2( sin θ ⋅ sin δ ⋅ cos φ1, cos δ − sin φ1 ⋅ sin φ2 )
where
φ is latitude, λ is longitude,
θ is the bearing (clockwise from north),
δ is the angular distance d/R;
d being the distance travelled, R the earth’s radius
If you want extreme accuracy try using GeographicLib and the formula in the source code under the hood of the Direct Problem at the "Geodesic calculations for an ellipsoid done right" web page.

What's wrong with my Graham Scan function?

I almost finish the chapter 3 of Real World Haskell. The last exercise blocks me. My code will crash while running. Does anyone can tell me which part is wrong in my code? Thanks.
Question:
Using the code from the preceding three exercises, implement Graham's scan algorithm for the convex hull of a set of 2D points. You can find good description of what a convex hull is, and how the Graham scan algorithm should work, on Wikipedia.
Answer:
-- Graham Scan, get the convex hull.
-- Implement the algorithm on http://en.wikipedia.org/wiki/Graham_scan
import Data.List
import Data.Ord
data Direction = TurnLeft | TurnRight | GoStraight deriving (Eq, Show)
-- Determine if three points constitute a "left turn" or "right turn" or "go straight".
-- For three points (x1,y1), (x2,y2) and (x3,y3), simply compute the direction of the cross product of the two vectors defined by points (x1,y1), (x2,y2) and (x1,y1), (x3,y3), characterized by the sign of the expression (x2 − x1)(y3 − y1) − (y2 − y1)(x3 − x1). If the result is 0, the points are collinear; if it is positive, the three points constitute a "left turn", otherwise a "right turn".
direction a b c = case compare ((x2 - x1) * (y3 - y1)) ((y2 - y1) * (x3 - x1)) of
EQ -> GoStraight
GT -> TurnLeft
LT -> TurnRight
where x1 = fst a
y1 = snd a
x2 = fst b
y2 = snd b
x3 = fst c
y3 = snd c
grahamScan points = scan (sort points)
-- For each point, it is determined whether moving from the two previously considered points to this point is a "left turn" or a "right turn". If it is a "right turn", this means that the second-to-last point is not part of the convex hull and should be removed from consideration. This process is continued for as long as the set of the last three points is a "right turn". As soon as a "left turn" is encountered, the algorithm moves on to the next point in the sorted array. (If at any stage the three points are collinear, one may opt either to discard or to report it, since in some applications it is required to find all points on the boundary of the convex hull.)
where scan (a : (b : (c : points)))
| (direction a b c) == TurnRight = scan (a : (c : points))
| otherwise = a : (scan (b : (c : points)))
scan (a : (b : [])) = []
-- Put prime to the head.
sort points = prime : (reverse (sortBy (compareByCosine prime) rest))
-- Sort a list to compute. The first step is to find a point whose y-coordinate is lowest. If there are more than one points with lowest y-coordinate, take the one whose x-coordinate is lowest. I name it prime.
where compareByYAndX a b
| compareByY == EQ = comparing fst a b
| otherwise = compareByY
where compareByY = comparing snd a b
prime = minimumBy compareByYAndX points
-- Delete prime from the candidate points. Sort the rest part by the cosine value of the angle between each vector from prime to each point. Reverse it and put prime to the head.
rest = delete prime points
compareByCosine p a b = comparing cosine pa pb
where pa = (fst a - fst p, snd a - snd p)
pb = (fst b - fst p, snd b - snd p)
cosine v = x / sqrt (x ^ 2 + y ^ 2)
where x = fst v
y = snd v
When doing the scan on the sorted set of points, when you finish, you throw away points that are supposed to be in the hull. In this line
scan (a : (b : [])) = []
you are deleting the last two points in the hull. Really it should be
scan (a : (b : [])) = [a, b]
or even better,
scan ps = ps
which covers cases with only one point.

Resources