I have a bug somewhere in my code, was wondering if this is incorrect.
I have a 2D view matrix in my code, but to display my world to the screen I need to convert the 2D view matrix to a 3D one. This is the process that I am using:
| a b c | | a b c 0 |
| d e f | => | d e f 0 |
| g h i | | g h i 0 |
| 0 0 0 1 |
It works when I use an identity matrix for the 2D matrix, but as soon as I apply any transforms to the 2D matrix all my objects being drawn disappear.
For drawing in 2D using 3D, I use this projection matrix:
_basicEffect.Projection = Matrix.CreateOrthographicOffCenter(0, graphicsDevice.Viewport.Width, graphicsDevice.Viewport.Height, 0, 0, 1);
What is the correct way to transform the 2D matrix to 3D?
Affine transformations use the extra row/column of the transformation matrix for translation. So I think what you want to do is to move the last row/column down/right and then for the new axis simply insert the identity transformation.
| a b c | | a b 0 c |
| d e f | => | d e 0 f |
| g h i | | 0 0 1 0 |
| g h 0 i |
I'm not sure, but give it a try at least.
Related
I am trying to make a little GUI library in c#, but after doing some research on matrix transformations I found out that I need a Matrix3x3 to store rotation, scale, and translation of a Vector2. But in the C# System.Numerics there is only a Matrix3x2 or Matrix4x4? Could I use one of those instead? If so how would I go about it? And why isnt there a Matrix3x3 in the standard library?
I am very new to Matrix and Vector programming, So sorry if this is a stupid question.
Thanks in advance.
You can use Matrix4x4. Start with an identity matrix and fill the top left 3×3 elements with your matrix.
For example to solve a 3×3 system of equations:
// Find the barycentric coordinates
//
// Solve for (wA,wB,wC):
// | px | | ax bx cx | | wA |
// | py | = | ay by cy | | wB |
// | pz | | az bz cz | | wC |
var m = new Matrix4x4(
A.X, B.X, C.X, 0,
A.Y, B.Y, C.Y, 0,
A.Z, B.Z, C.Z, 0,
0, 0, 0, 1);
if (Matrix4x4.Invert(m, out Matrix4x4 u))
{
var w = new Vector3(
u.M11*P.X + u.M12*P.Y + u.M13*P.Z,
u.M21*P.X + u.M22*P.Y + u.M23*P.Z,
u.M31*P.X + u.M32*P.Y + u.M33*P.Z);
// ...
}
As for the reasons, the intent of System.Numerics has to be related to computer graphics since it utilizes Homogeneous Coordinates in which 3D vectors contain 4 elements. Three regular coordinates and a scalar weight factor. The math with homogeneous coordinates for computer graphics is vastly simplified. The only reason there is a Vector3 is because a Vector4 should be treated as a vector of 3 elements plus a scalar, and thus Vector3 should be used in composition and decomposition of the homogeneous coordinates. It means that not all 4 elements can be treated equally, and sometimes you need to do things with the vector (first three elements) separately from the scalar value (fourth element).
Also System.Numerics uses single precision float elements, which are almost never used in scientific computing, but universally applied to computer graphics for their speed. Hopefully one day when the CLR supports AVX512 there will be double precision numeric intrinsics that scientists can actually use.
I have a 3x3 matrix I'm using to track movement in 2D. I need to extract from that the translation, rotation and scale matrices. Can anyone suggest how I would do this? I've had no luck searching online so far (possibly I'm using the wrong terms).
This is just off the top of my head so there may be an error in here, but:
Assuming your matrix is row-major (just transpose everything if you're using column major):
| cos(t) -sin(t) 0 |
| sin(t) cos(t) 0 |
| tx ty 1 |
The translation vector will be the last row in the matrix [tx ty 1]. Extracting scale and rotation in a composed matrix is a bit trickier.
Looking at a 3x3 rotation matrix,
| cos(t) -sin(t) 0 |
| sin(t) cos(t) 0 |
| 0 0 1 |
And a scale matrix
| vx 0 0 |
| 0 vy 0 |
| 0 0 1 |
The combined rotation & scale matrix might look like (ct = cos(t), st = sin(t))
| vx*ct -vx*st 0 |
| vy*st vy*ct 0 |
| 0 0 1 |
For uniform scaling, vx=vy.
| v*ct -v*st 0 |
| v*st v*ct 0 |
| 0 0 1 |
Remembering the trig identity
ct^2 + st^2 = 1
We can see that the
(v*ct)^2 + (v*st)^2 = v^2
or
v^2*ct^2 + v^2*st^2 = v^2
... all the terms of which are in the composite (scale,rotation,translation or SRT for short) matrix,
So,
v = sqrt((v*ct)^2 + (v*st)^2)
or
v = sqrt(M[0,0]^2 + M[0,1]^2);
Theta, then is just
t = acos(vct/v)
or
t = acos(M[0,0]/v)
or, this might work much easier but I haven't tried it:
theta = atan2(vst,vct),
scale = sqrt(vst^2+vct^2)
where ^ is an exponent, not an XOR.
... and you can work out the rest.
It would be wiser to keep your scale, rotation and translation values around and use those values both to build the matrix and for whatever other tasks you require. Relying on the matrix as the only container for that information will eventually lead to compound floating-point errors and other drama.
Some notes:
Theta is an angle. It's a fun, easy-to-draw Greek symbol, and all us engineers love greek characters. It's mostly Stockholm syndrome since some of them look like 5's, and some of them are impossible to draw unless you're Greek.
This works great for 2D, where there is only one possible rotation axis. If you're working in three (or higher! It's a thing now!) dimensions, the concept is the same but the implementation becomes much, much messier.
st, ct, vst, vct, etc. are all contained in the composite matrix you have available. (Composite == concatenated == combined. The terminology in use depends on who you're reading.) The non-intuitive part is extracting the elements that you need from the matrix. This requires understanding what is in the matrix, where, and why.
This is a solvable problem. Normally, I'm a sit-down-and-start-coding kind of guy, and in 25 years of professional development, I'd have to say that it's worked out pretty well so far. But, there are times where a whiteboard or a notebook and a mechanical pencil are better friends than your keyboard.
For a column major matrix, given:
X vector of < Xx, Xy >;
Y vector of < Yx, Yy > and
Translation/position of < Tx, Ty >,
The corresponding column major transformation matrix is:
The translation is:
For the Scaling, the scale factors for the X and Y vectors are:
The scaling transformation is then:
For Rotation, the normalized vectors are:
X Vector: < Xx/Sx, Xy/Sx >
Y Vector: < Yx/Sy, Yy/Sy >
And the rotation transformation "R" is:
RECOMPOSITION:
Given translation "T", rotation "R", and scaling "S" transformation in column major order, the original matrix/transform can be recreated with:
T * R * S
Assumption, the original transformation has X and Y vectors that are:
Not parallel;
Not a length of zero;
Not mirrored; and
Not skewed/sheared.
The rotation can be further decomposed into an angle as described by 3Dave (which is row major, and needs to be transposed to be column major).
By default, the Y axis will start from bottom in ZedGraph.
Now, I want to have a chart will look:
y
0 |
10 |
20 |
30 |
40 |--------------x
Is it possible to reverse Y asix?
It can be achieved by setting YAxis.Scale.IsReverse = true;
Supposing that I have two labels with variable text. Label 1 is in the center of the screen. I can position Label 2 on the right side of Label 1:
label1.Location = (WIDTH / 2, Height / 2)
label2.Location = new Point(label1.Right, label1.Top);
Form output:
_______________
| |
| 100 200 |
|_______________|
Now I want do the same, but position Label 2 on the left side of Label 1. How can I do this?
Form output:
_______________
| |
| 200 100 |
|_______________|
If label2 is already sized correctly, you can just subtract its width from the left side of label1:
label2.Location = new Point(label1.Left - label2.Width, label1.Top)
Diagram:
-----(label1.Left - label2.Width)
|
| -----label1.Left
_|___|_________
| v v |
| +---+---+ <--------label1.Top
| |200|100| |
| +---+---+ |
| '---' |
|___|__________|
|
-----label2.Width
Position the second label starting from the left point of the first label and subtracting the witdh of the one to be placed
label2.Location = new Point(label1.Left - label2.Width, label1.Top);
By the way, the value used for your first label should consider the width and height of the label to be really at the center of the label container.
So assuming you want the first label at the center of its containing form you should use a formula like this
int leftPos = (this.Width / 2) - (label1.Width / 2);
int topPos = (this.Height / 2) - (label1.height / 2);
label1.Location = new Point(leftPos, topPos)
I'm looking for a simple algorithm that, given a rectangle with width w and height h, splits the rectangle into n more or less equal sized and shape rectangles and calculates the center of these rectangles.
EDIT: Forgot to mention that the shapes should be as similar as possible to a square.
Any hints how to start?
A simple algorithm is to split vertically into n equal sized strips of height h and width w/n.
If you assume that the initial rectangle has corners (0,0) and (w,h) then using this algorithm the ith rectangle would have center (w / n * (i + ½), h/2), for 0 <= i < n.
Update: try finding all the factorizations of the number n into factor pairs (i, j) such that i * j = n, and find the factor pair such that the ratio of the factors is closest to the ratio of the sides of the rectangle. Then use the two factors to create a regular grid of smaller rectangles.
For example when n is 10, you can choose between (1, 10), (2, 5), (5, 2) and (10, 1). Here is an example grid using the factors (5, 2):
------------------------------------
| | | | | |
| | | | | |
------------------------------------
| | | | | |
| | | | | |
------------------------------------
If your initial rectangle has width 60 and height 20 then using the factor pair (5, 2) will give ten rectangles of size (60/5, 20/2) = (12, 10) which is close to square.