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.
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)
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) :)
Related
How do I find the two opposite x coordinates at the edge of a circle for a specific y coordinate?
A y coordinate of zero means the center of the circle so the two x coordinates would be +- radius
A y coordinate equaling the radius would give two x coordinates of zero.
I'm using Javascript but any language solution is fine.
Assuming you're talking about circle placed at (0,0) (described by equation x²+y²=R²) and you need to return pair of (symmetric) x coordinates based on y and R, that would be something, like:
const getX = (y, R) => [1, -1].map(n => n*(R**2-y**2)**0.5)
Following is a quick proof-of-a-concept live-demo:
const getX = (y, R) => [1, -1].map(n => n*(R**2-y**2)**0.5)
console.log(getX(0,1))
console.log(getX(1,1))
console.log(getX(-1,1))
console.log(getX(0.7071,1))
.as-console-wrapper{min-height:100%;}
If arbitrary circle center ((x0,y0)) is considered ((x-x0)²+(y-y0)²=R²), more generic solution should work:
const getX = (y, R, x0, y0) => [1, -1].map(n => n*(R**2-(y-y0)**2)**0.5+x0)
The existing answer though technically correct is hugely inefficient. The pattern used creates 2 Arrays every call, and repeats the full calculation twice even though the second result is a simple negative of the first (2 rather than 1 square root operations).
The following is 14 times (1400%) faster
const circleXForY = (y, r) => [y = (1 - (y / r) ** 2) ** 0.5 * r, -y];
If you include the fact that the result can also be NaN when y > r then the above function is a staggering 196 times (19,600%) quicker when y > r || y < -r.
A further slight improvement is to just use the positive result
const circleXForY = (y, r) => (1 - (y / r) ** 2) ** 0.5 * r;
The reason I posted a faster version is that this function is very often used when scanning lining circles for graphical like content presentation. I such cases performance is critical.
There is a spiral rise effect as showed bellow: A demo can be found here: http://openlayers.org/en/latest/examples/dynamic-data.html
In the bottom of the demo page, an algorithm is used to implement this effect. But I can not figure out how does it work.
var t = theta + 2 * Math.PI * i / n;
var x = (R + r) * Math.cos(t) + p * Math.cos((R + r) * t / r);
var y = (R + r) * Math.sin(t) + p * Math.sin((R + r) * t / r);
What does R, r and p means? And how to understand the formula above? Can someone explain detail for me? Any help is appreciated.
I can recognize that code draws epicycloid curve (+ it's phase theta permanently changes to provide moving effect).
You can refer to R as radius of inner (here bigger) circle, p and r (equal values here) as radius of outer (here smaller) circle. Here r looks like radius of coil of toroidal spring.
The first summands correspond to the center of outer circle, the second ones - to the second-order rotation about outer circle center.
Play with these values and observe effects
Note that if you change p to make it not equal to r, you'll get epitrochoid curve (more general kind of epicycloid)
Lets say I have 10 objects. The first object is placed at x75, y0, z0. Now lets say I wanted to orient the objects so they form a circle with x0, y0, z0 at it's center. And each object is an equal distance from each other. Is there a formula I can use to generate the coordinates? I should mention the number of objects wont always be 10. It's a variable so some times it might be 15 or 20 or any other number.
You can use some formula like:
x = x0 + r * cos(theta * pi / 180);
y = y0 + r * sin(theta * pi / 180);
so x0 = 0 and y0 = 0.
For theta, it will be the degree, which depends on the number of objects. So if you have 10 objects, theta will be a multiple of 36. So basically it is a multiple of 360/num of objects.
r is the radius of the circle, so if the first one is at (75, 0, 0), then r = 75.
I'm trying to develop a small application using html5 and canvas/KineticJS. I'd like to trace a number of rays that start from a 2d point to infinite, just setting a custom angle degree. For example, if I set 90° the app should render four rays (two straight lines, one vertical and one horizontal that meet in my 2d point). If I set 60° I should see 3 straight lines, like an asterisk *
The longest line you'll ever have to draw is the size of the canvas's diagonal:
var r = Math.sqrt(Math.pow(canvas.width, 2) + Math.pow(canvas.height, 2));
Use sin and cos to calculate each of your end points at that radius:
var theta = delta * Math.PI / 180.0;
var dx = r * Math.cos(n * theta);
var dy = r * Math.sin(n * theta);
Then, just draw lines from (x, y) to (x + dx, y + dy). Simples.
All,
I THINK that I'm looking for a function for Trilinear interpolation.
Here's the details:
I have a three dimensional dataset:
Dimension 1 varies from 0 to 100 in increments of 5
Dimension 2 varies from 0 to 100 in increments of 5
Dimension 3 varies from 0 to 1 in increments of 0.1
So, I have 4851 total values (21 x 21 x 11).
If I need to find the value for (10, 25, 0.3) - that's easy - I can just look it up in the 3-dimensional array.
But, I need to be able to come up with the best approximation, given dimensional values of (17,48,0.73), for example.
So, I think that what I'm looking for is a trilinear interpolation (although I'd definitely appreciate any suggestions for a better method, or a hint that I'm on the wrong topic altogether...)
A quick google search turns up this formula:
Vxyz =
V000(1-x)(1-y)(1-z) +
V100x(1-y)(1-z) +
V010(1-x)y(1-z) +
V001(1-x)(1-y)z +
V101x(1-y)z +
V011(1-x)yz +
V110xy(1-z) +
V111xyz
Which looks like what I'm looking for, but I'm not sure what x, y, and z represent. If I had to guess, x is a ratio - the distance of my "target" first dimension value from the nearest two values I have, y is the ratio for the second dimension, and z is the ratio for the third dimension.
Of course, since I don't really know what I'm talking about, I wouldn't know if this is right or wrong.
So, ideally, I'd like a bit of Javascript or pseudo-code that shows exactly how to accomplish this.
Many thanks in advance!
The code you are looking at is trying to do a weighted average of the 8 points of the cube with vertices that are in your dataset, and which encloses the point you are trying to find a value for.
For a point p
// Find the x, y and z values of the
// 8 vertices of the cube that surrounds the point
x0 = Math.floor(p.x / 5);
x1 = Math.floor(p.x / 5) + 1;
y0 = Math.floor(p.y / 5);
y1 = Math.floor(p.y / 5) + 1;
z0 = Math.floor(p.z / .1);
z1 = Math.floor(p.z / .1) + 1;
// Look up the values of the 8 points surrounding the cube
p000 = dataset[x0][y0][z0];
p001 = dataset[x0][y0][z1];
// ...
// Find the weights for each dimension
x = (x - x0) / 5;
y = (y - y0) / 5;
z = (z - z0) / .1;
// Compute the guess using the method you found
// ...