Reputation: 10120
it's probably not the right place to post this but i don't know where else to post it.
i have 5 lines (d1 -> d5) equally distributed from each other in 3d perspective, i have the values of (a) angle, (d1) and (b5). i need to calculate (b2, b3, b4, d2, d3, d4, d5) with jquery.
i can calculate d5 with:
d5 = d1 - ( b5 * Math.tan(a))
but i have no idea how to calculate b2, b3 and b4. (d1 is divided into 4 identical segaments (s)) any help would be appreciated.
Upvotes: 6
Views: 738
Reputation: 2675
First we need to calculate what the length of the adjacent side of the whole triangle d1->v->c is (the left vertical side of it):
tan(Θ) = opposite / adjacent
opposite * tan(Θ) = adjacent
adjacent = opposite * tan(Θ)
adjacent = d1 * tan(a)
Next thing we need is to know how much off the ground each line from v is when it gets to line d1. Given that variable s is the same for all divisions and assuming N dividing segments (in this case 3), our counter is i that starts from 1 and goes to N:
opposite(i) = i * (d1 / N)
Now we need the angle that line from v to each marker s makes:
tan(Θi) = opposite / adjacent
Θi = arctan(opposite / adjacent)
Θi = arctan(opposite(i) / adjacent)
Θi = arctan((i * (d1 / N)) / (d1 * tan(a)))
Using some geometry/trig we can say that angle going from d1 through point c to top of d5 is (90° - a). We will call this angle a'
a' = 90° - a
Law of sines tells us that:
A' / sin(a') = opposite(i) / sin(b')
so now we solve for A' since we need some help with getting the dimensions of the orange square:
A' = (opposite(i) * sin (a')) / sin(b')
since b' = (a + Θi) this turns into:
A' = (opposite(i) * sin (90° - a)) / sin(a + Θi)
Same thing applied but solving for h in the orange triangle (see picture):
h / sin(90°-Θi) = A' / sin(90°)
h = (A' * sin(90°-Θi)) / sin(90°)
b2 = h
Putting it all together (hopefully without copy/paste mistakes on my part) and without simplifications:
b2 = (((( i * (d1 / N)) * sin (90° - a)) / sin(a + Θi)) * sin(90° - arctan((i * (d1 / N)) / (d1 * tan(a))))) / sin(90°)
Now rinse/repeat for each value of i and turn into code (I would have done that but I'm too tired) :)
Upvotes: 0
Reputation: 8298
What you're looking for is a projective scale. The easiest way to do this computationally is to use homogenous coordinates, take a rectangle (like the one in the first picture below) on which V is "infinitely far to the right" and find a projective transformation that maps this rectangle to the trapezium in the second picture. The vertices of the rectangle are (0|0), (0|d1), (b5|d1), (b5|0) and the corresponding vertices of the trapezium are (0|0), (0|d1), (b5|d5), (b5|0).
Since these are four points of which no three are collinear, we can find a unique matrix (up to scaling) M for this transformation. After some maths, it turns out that this matrix is:
[d1*b5,0,0]
[0,b5*d5,0]
[d1-d5,0,b5*d5]
If you want to find the coordinates b3 and d3, for instance, you can multiply this matrix with homogenous coordinates of the point in the middle of the line, i.e. the vector (0.5*b5,d1,1)^T and you get the homogenous coordinates of the point (b3|d3), which can be converted into Euclidean coordinates by dehomogenisation, i.e. dividing the first two components by the third.
In general, if you have two points (b1|d1) and (bn|dn) and want to know the coordinates of n-2 equidistant points inbetween on a projective scale like this, you can compute the coordinates bi and di as like this (in your case, n would be 5, of course):
let M := matrix [[d1*bn, 0, 0], [0, bn*dn, 0], [d1-dn, 0, bn*dn]]
let v := ((i-1)/(n-1)*bn, d1, 1)
let (x,y,z) := M*v
let bi := x/z and di := y/z
As you see, this is a simple algorithm for computing the coordinates of these projectively equidistant points, and it generalises nicely to arbitrary numbers of points.
If you'd rather have a closed formula, you can compute the bi and di directly as:
let bi := (bn*d1*(i-1))/(dn*n+(d1-dn)*i-d1)
let di := d1*dn*(n-1)/(dn*n+(d1-dn)*i-d1)
Upvotes: 2