Math Parrallelogram Level Generation - math

I am currently developing a mobile runner. Therefore i need platforms allow the transition from one height to another (2D).
Given: Triangle AFB has a rectangle alpha, Triangle CDE has a rectangle at delta, Line BC = EF, Line ED = AB and the height of the Parralelogram is ED(=AB)
Looking for: AF = CD (any of both)
I can't find a solution.
Tip: I have a formula for a case where when you can give me a parralel line to the long sides of the parrallelogram I will be able to work out the rest. Couldn't find a parrall line though.

I'll try a re-interpretation as a "planar mechanism" that is possibly still not right in the input description.
Input: the solid fixed triangle at the bottom with short perpendicular sides length a and c. The top triangle is the same, rotated by 180°, but not fixed. The triangles are connected by bars of length b that are rotationally flexible and fixed by giving the angle phi.
bottom triangle: A=(0,0), F=(c,0), B=(0,a)
lower bar: F=(c,0), E=(c,0)+b*(cos(phi), sin(phi))
upper bar: B=(0,a), C=(0,a)+b*(cos(phi), sin(phi))
upper triangle: E=(c,0)+b*(cos(phi), sin(phi)), D=(c,a)+b*(cos(phi), sin(phi)), C=(0,a)+b*(cos(phi), sin(phi))
If not the angle is given, but the total height at the segment CD,
h=a+b*sin(phi),
then the horizontal component can be calculated via trigonometric identity
b*cos(phi) = sqrt( b^2 - (h-a)^2 )
Set bsin=b*sin(phi)=h-a, bcos=sqrt(b*b-bsin*bsin) then
C=( bcos, a+bsin)
D=(c+bcos, a+bsin)
E=(c+bcos, bsin)

Related

Snap dragged mouse position perpendicular to start edge in 3D

I'm drawing a line as I drag my mouse from an edge AB in 3D, using the vector that the mouse's path creates to draw the line CD - see the image. I need to determine whether the line CD is perpendicular to AB and if not how I move it to a position where it is perpendicular CE.
Perpendicular Problem
I can determine the angle of the mouse's path in relation to the edge but I'm struggling to determine where the mouse should be snapped to, to be perpendicular to the edge.
In 2D I could simply determine two vectors that would be perpendicular to the edge (1 on either side of the edge) and compare my mouse path to those but in 3D the possible vectors are infinite, so I need to limit the options somehow.
I can create a triangular plane between points CBD but I still don't know the best way to use this to determine a perpendicular vector from the edge FG, I only know that my mouse path is or is not perpendicular.
I might be approaching this all wrong, so any help would be appreciated.
Thanks.
Edit:
I'm not sure if I need to write a new question for this but thought it seemed reasonable to carry on this thread.
I can now drag perpendicular lines from any edge on my geometry using the below answer from MBo. However, I now have the issue of infinite perpendicular directions for any given edge.
Is there an easy way to limit these to four directions (see image - green dashed line is mouse path)? I'm showing a cube in the image but it could be any edge geometry in 3D space. Perpendicular Dragging
My current thinking is that the best way is to take the edge that the mouse is dragging from and use any connected edges to create a plane, then using the plane's normal limit perpendiculars to that but if there's a better way, please let me know. Thanks.
Find projection of point D onto line A-B using vector algebra:
AB = B - A //(AB.x = B.x-A.x and so on)
AD = D - A
P = A + AB * (AB.dot.AD) / (AB.dot.AB)
//(AB.dot.AD) = AB.x * AD.x + AB.y * AD.y + AB.z * AD.z
Now shift D by difference of C and P
E = D + (C - P)
Note that when value t=(AB.dot.AD) / (AB.dot.AB) is not in range 0..1, projection point lies outside of AB segment

How to fix zoom towards mouse routine?

I'm trying to learn how to zoom towards mouse using Orthographic projection and so far I've got this:
def dolly(self, wheel, direction, x, y, acceleration_enabled):
v = vec4(*[float(v) for v in glGetIntegerv(GL_VIEWPORT)])
w, h = v[2], v[3]
f = self.update_zoom(direction, acceleration_enabled) # [0.1, 4]
aspect = w/h
x,y = x-w/2, y-h/2
K1 = f*10
K0 = K1*aspect
self.left = K0*(-2*x/w-1)
self.right = K0*(-2*x/w+1)
self.bottom = K1*(2*y/h-1)
self.top = K1*(2*y/h+1)
x/y: mouse screen coordinates
w/h: window width/height
f: factor which goes from 0.1 to 4 when scrolling down/up
left/right/bottom/top: values used to compute the new orthographic projection
The results I'm getting are really strange but I don't know which part of the formulas I've messed up.
Could you please spot which part of my maths are wrong or just post a clear pseudocode I can try? Just for the record, I've read&tested quite a lot of versions out there on the internet but haven't found yet any place where this subject is explained properly.
Ps. You don't need to post any SO link related to this subject as I've read all of them already :)
I'm going to answer this in a general way, based on the following set of assumptions:
You use a matrix P for the (ortho) projection describing the actual mapping of your eye space view volume onto the standard view volume [-1,1]^3 OpenGL will clip against (see also assumption 2) and a matrix V for the view transformtation, that is postion and orientation of the "camera" (if there is such a thing, especially in ortho projections) and basically establishing an eye space where your view volume will be defined relative to.
I will ignore the homogeneous clip space, as you work with completely affine ortho projections only, that means NDC coordinates and clip space will be identical, and no tricks to any w coordinate are applied.
I assume default GL conventions for eye space and projection matrices, notably eye space origin is camera location and camera lookat direction is -z
The viewport is filling the window completely.
Windows Space is default OpenGL convention where the origin is at the bottom left.
Mouse coordinates are in some window-specific coordinate frame where the origin is at top left, mouse is at integer pixel coordinates.
I assume that the view volume defined by P is symmetrical: right = -left and top = -bottom, and it is also supposed to stay symmetrical after the zoom operation, therefore, to compensate for any movement, the view matrix V must be adjusted, too.
What you want to get is a zoom such that the object point under the mouse cursor does not move, so becomes the center of the scale operation. The mouse cursor itself is only 2D and a whole straight line in the 3D space will be mapped to the same pixel location. However, in an ortho projection, that line will be orthogonal to the image plane, so we don't need to bother much with the third dimension.
So what we want is to scale the current situation with P_old (defined by the ortho parameters l_old, r_old, b_old, t_old, n_old and f_old) and V_old (defined by "camera" position c_old and ortientation o_old) by a zoom factor s at mouse position (x,y) (in the space from assumption 6).
We can see a few things directly:
the near and far plane of the projection should be unaffected by the operation, so n_new = n_old and f_new = f_old.
the actual camera orientation (or lookat direction) should also be unaffected: o_new = o_old
If we zoom in by a factor of s, the actual view volume must be scaled by 1/s, since when we zoom in, a smaller part of the complete world is mapper on the screen than before (and appears bigger). So we can simply scale the frustum parameters we had:
l_new = l_old / s, r_new = r_old / s, b_new = b_old / s, t_new = t_old / s
If new only replace P_old by P_new, we get the zoom, but the world point under the mouse cursor will move (except the mouse is exactly in the center of the view). So we have to compensate for that by modifying the camera position.
Let's first put the mouse coords (x,y) into OpenGL window space (assumptions 5 and 6):
x_win = x + 0.5
y_win = height - 0.5 - y
Note that besides mirroring y, I also shift the coordinates by half a pixels. That's because in OpenGL window space, pixel centers are at half-inter coordinates, while I assume that your integer mouse coordinates are to represent the center of the pixel you click onto (will not make a big difference visually, but still)
Now let's further put the coords into Normalized Device Space (relying on assumption 4 here):
x_ndc = 2.0 * x_win / width - 1
y_ndc = 2.0 * y_win / height - 1
By assumption 2, clip and NDC coordiantes will be identical, and we can call the vector v our NDC/space mouse coordinates: v = (x_ndc, y_ndc, 0, 1)^T
We can now state our "point under mouse must not move" condition:
inverse(V_old) * inverse(P_old) * v = inverse(V_new) * inverse(P_new) * v
But let's just go into eye space and let's look at what happened:
Let a = inverse(P_old) * v be the eye space location of the point under the mouse cursor before we scaled.
Let b = inverse(P_new) * v be the eye space location of the pointer under the mouse cursor after we scaled.
Since we assumed a symmetrical view volume, we already know that for the x and y coordinates, b = (1/s) *a holds (assumption 7. if that assumption does not hold, you need to do the actual calculation for b too, which isn't hard either).
So, we can set up an 2D eye space offset vector d which describes how our point of interest was moved by the scale:
d = b - a = (1 / s) *a - a = a (1/s - 1)
To compensate for that movement, we have to move our camera inversely, so by -d.
If you keep the camera position separate as I did in assumption 1, you simply need to update the camera position c accordingly. You just have to take care about the fact that c is the world space postion, while d is an eye space offset:
c_new = c_old - inverse(V_old) * (d_x, d_y, 0, 0)^T
Not that if you do not keep the camera position as a separate variable, but keep the view matrix directly, you can simply pre-multiply the translation: V_new = translate(-d_x, -d_y, 0) * V_old
Update
What I wrote so far is correct, but I took a shortcut which is numerically a very bad idea when working with not-infinite precision data types. The error in camera position accumulates very fast if one zooms out a lot. So after #BPL implemted this, this it what he got:
The main issue seems to be that I directly calculated the offset vector d in eye space, which does not take the current view matrix V_old (and its small errors into account). So a more stable approach is to calculate all of this directly in world space:
a = inverse(P_old * V_old) * v
b = inverse(P_new * V_old) * v
d = b - a
c_new = c_old - d
(doing so makes assumption 7 not needed anymore as a by product, so it directly works in the general case of arbitrary ortho matrices).
Using this approach, the zoom operation worked as expected:

how to get the triangle vector coordinate if the triangle area is known

i have a triangle, the vector is A(x1,y1), B(x2,y2), C(x3,y3), these are all known
,then i want to move up the Vector A to a new Position D(x1, y4)--just change the coordinate y, if the new triangle(BCD)'s area is known, how can i caculate the y4?
thanks to SaiBot, him share a solution like this:
Geometrically thinking this can be solved in two steps.
move A perpendicular to BC to the upper left until the triangle has the correct size. The size of a triangle is calculated by 1/2 * base * height.
move A parallel to BC until A.x = D.x1. This will not change the area of the rectangle.

How do I find the dimensions of a rotated rectangle within an unrotated rectangle such that area is maximized?

I have a rectangle that is W x H.
Within that rectangle is another rectangle that is rotated by ϴ degrees which is always between -45 and 45 degrees, and shares the same center as the outer rectangle. I need to find w and h such that the area of the inner rectangle is maximized.
Here's a (ghetto) image to illustrate a bit. Though, the corners of the rectangles should probably be touching, I assume?
Here is the prototype of the function I'm looking to write:
SizeD GetMaxRectangleSize(double outerWidth, double outerHeight, float angle)
SizeD is just a struct that has a width and height in doubles.
Thanks to the comments for steering me in the right direction!
My solution, though perhaps not mathematically optimal, was to assume that if all four corners of the inner rectangle fall on the outer rectangle then area will be maximized.
Therefore:
H = wSin(ϴ) + hCos(ϴ)
W = wCos(ϴ) + hSin(ϴ)
Solving for w and h and substituting gives:
h = (HCos(ϴ) - WSin(ϴ))/(cos(ϴ)^2 - sin(ϴ)^2)
w = (WCos(ϴ) - HSin(ϴ))/(cos(ϴ)^2 - sin(ϴ)^2)
Which happens to work for ϴ = [0,45), and (-45,0] should act the same.
The tricky part of this question isn't how to calculate the area of an interior rectangle, but which of all the possible interior rectangles has maximum area?
To start with, observe that the box in your image is the same area regardless of how it is slid around horizontally, and if it is slid to the rightmost wall, it allows for an easy parameterization of the problem as follows:
I find it a bit easier to think of this problem, with the fixed box rotated by the offset angle so that the interior box lines up in a standard orientation. Here's a figure (I've changed theta to beta just because I can type it easily on a mac, and also left off the left most wall for reasons that will be clear):
So think of this constructed as follows: Pick a point on the right side of the exterior rectangle (shown here by a small circle), note the distance a from this point to the corner, and construct the largest possible interior with a corner at this point (by extending vertical and horizontal lines to the exterior rectangle). Clearly, then, the largest possible rectangle is one of the rectangles derived from the different values for a, and a is a good parameter for this problem.
So given that, then the area of the interior rectangle is:
A = (a * (H-a))/(cosß * sinß)
or, A = c * a * (H-a)
where I've folded the constant trig terms into the constant c. We need to maximize this, and to do that the derivative is useful:
dA/da = c * (H - 2a)
That is, starting at a=0 (ie, the circle in the figure is in the lower corner of the exterior rectangle, resulting in a tall and super skin interior rectangle), then the area of the interior rectangle increases monotonically until a=H/2, and then the area starts to decrease again.
That is, there are two cases:
1) If, as a increase from 0 to H/2, the far interior corner hits the opposite wall of the exterior, then the largest possible rectangle is when this contact occurs (and you know it's the largest due to the monotonic increase -- ie, the positive value of the derivative). This is your guess at the solution.
2) If the far corner never touches a wall, then the largest interior rectangle will be at a=H/2.
I haven't explicitly solved here for the area of the interior rectangle for each case, since that's a much easier problem than the proof, and anyone who could follow the proof, I assume could easily calculate the areas (and it does take a long time to write these things up).

Distance between hyperplanes

I'm trying to teach myself some machine learning, and have been using the MNIST database (http://yann.lecun.com/exdb/mnist/) do so. The author of that site wrote a paper in '98 on all different kinds of handwriting recognition techniques, available at http://yann.lecun.com/exdb/publis/pdf/lecun-98.pdf.
The 10th method mentioned is a "Tangent Distance Classifier". The idea being that if you place each image in a (NxM)-dimensional vector space, you can compute the distance between two images as the distance between the hyperplanes formed by each where the hyperplane is given by taking the point, and rotating the image, rescaling the image, translating the image, etc.
I can't figure out enough to fill in the missing details. I understand that most of these are indeed linear operators, so how does one use that fact to then create the hyperplane? And once we have a hyperplane, how do we take its distance with other hyperplanes?
I will give you some hints. You need some background knowledge in image processing. Please refer to 2,3 for details.
2 is a c implementation of tangent distance
3 is a paper that describes tangent distance in more details
Image Convolution
According to 3, the first step you need to do is to smooth the picture. Below we show the result of 3 different smooth operations (check section 4 of 3) (The left column shows the result images, the right column shows the original images and the convolution operators). This step is to map the discrete vector to continuous one so that it is differentiable. The author suggests to use a Gaussian function. If you need more background about image convolution, here is an example.
After this step is done, you have calculated the horizontal and vertical shift:
Calculating Scaling Tangent
Here I show you one of the tangent calculations implemented in 2 - the scaling tangent. From 3, we know the transformation is as below:
/* scaling */
for(k=0;k<height;k++)
for(j=0;j<width;j++) {
currentTangent[ind] = ((j+offsetW)*x1[ind] + (k+offsetH)*x2[ind])*factor;
ind++;
}
In the beginning of td.c in 2's implementation, we know the below definition:
factorW=((double)width*0.5);
offsetW=0.5-factorW;
factorW=1.0/factorW;
factorH=((double)height*0.5);
offsetH=0.5-factorH;
factorH=1.0/factorH;
factor=(factorH<factorW)?factorH:factorW; //min
The author is using images with size 16x16. So we know
factor=factorW=factorH=1/8,
and
offsetH=offsetW = 0.5-8 = -7.5
Also note we already computed
x1[ind] = ,
x2[ind] =
So that, we plug in those constants:
currentTangent[ind] = ((j-7.5)*x1[ind] + (k-7.5)*x2[ind])/8
= x1 * (j-7.5)/8 + x2 * (k-7.5)/8.
Since j(also k) is an integer between 0 and 15 inclusive (the width and the height of the image are 16 pixels), (j-7.5)/8 is just a fraction number between -0.9375 to 0.9375.
So I guess (j+offsetW)*factor is the displacement for each pixel, which is proportional to the horizontal distance from the pixel to the center of the image. Similarly you know the vertical displacement (k+offsetH)*factor.
Calculating Rotation Tangent
Rotation tangent is defined as below in 3:
/* rotation */
for(k=0;k<height;k++)
for(j=0;j<width;j++) {
currentTangent[ind] = ((k+offsetH)*x1[ind] - (j+offsetW)*x2[ind])*factor;
ind++;
}
Using the conclusion from previous, we know (k+offsetH)*factor corresponds to y. Similarly - (j+offsetW)*factor corresponds to -x. So you know that is exactly the formula used in 3.
You can find all other tangents described in 3 implemented at 2. I like the below image from 3, which clearly shows the displacements effect of different transformation tangents.
Calculating the tangent distance between images
Just follow the implementation in tangentDistance function:
// determine the tangents of the first image
calculateTangents(imageOne, tangents, numTangents, height, width, choice, background);
// find the orthonormal tangent subspace
numTangentsRemaining = normalizeTangents(tangents, numTangents, height, width);
// determine the distance to the closest point in the subspace
dist=calculateDistance(imageOne, imageTwo, (const double **) tangents, numTangentsRemaining, height, width);
I think the above should be enough to get you started and if anything is missing, please read 3 carefully and see corresponding implementations in 2. Good luck!

Resources