Translate SVG matrix transform values into x,y coordinates - math

I'm working on an SVG map, which contains a lot of text elements. The problem is, the old/source file has been generated years ago in Adobe Illustrator, which for some reason printed these elements as, e.g.:
<text transform="matrix(1 0 0 1 604.9754 765.0283)">4</text>
(First four arguments (1, 0, 0, 1) never change.)
What I want to achieve is to translate it into something like
<text x='123' y='456'>4</text>
I've already managed to collect all values needed using regex (text content and the two last transform arguments), but I have no idea what should I do next. I've also found out, that
The matrix( ) transform function specifies a transformation in the form of a transformation matrix of six values. matrix(a,b,c,d,e,f) is equivalent to applying the transformation matrix:
\begin{pmatrix} a & c & e \\ b & d & f \\ 0 & 0 & 1 \end{pmatrix}
which maps coordinates from a previous coordinate system into a new coordinate system by the following matrix equalities:
\begin{pmatrix} x_{\mathrm{newCoordSys}} \\ y_{\mathrm{newCoordSys}} \\ 1 \end{pmatrix} = \begin{pmatrix} a & c & e \\ b & d & f \\ 0 & 0 & 1 \end{pmatrix} \begin{pmatrix} x_{\mathrm{prevCoordSys}} \\ y_{\mathrm{prevCoordSys}} \\ 1 \end{pmatrix} = \begin{pmatrix} a x_{\mathrm{prevCoordSys}} + c y_{\mathrm{prevCoordSys}} + e \\ b x_{\mathrm{prevCoordSys}} + d y_{\mathrm{prevCoordSys}} + f \\ 1 \end{pmatrix}
So my question is:
how can I translate these matrix transform values into X,Y coordinates?

I've found out, that matrix(1 0 0 1 100px 200px) is equivalent to translateX(100px) translateY(200px) which means, that these values are actually the exact values I've been looking for. The reason I didn't realize it earlier was because I didn't adjust them (multiply, add) to my new image. I've also used X as Y coordinates inversely (ouch). I hope it can help someone.

Related

Awk Floating-point Imprecision

I encountered a floating-point imprecision issue in Awk that I can't solve. Is there a simple solution to it?
Here is my example Awk script to replicate the floating-point imprecision issue.
BEGIN {
print "PREC = " PREC
print "OFMT = " OFMT
print "CONVFMT = " CONVFMT
a = 1.2 + 3.4
b = 8.9 - 4.3
print "a = " a
print "b = " b
if ( a == b )
print "a == b"
else
print "a != b"
c = 3.2 + 5.4
d = 9.8 - 1.2
print "c = " c
print "d = " d
if ( c == d )
print "c == d"
else
print "c != d"
}
Here is the output of the above script.
PREC = 53
OFMT = %.6g
CONVFMT = %.6g
a = 4.6
b = 4.6
a != b
c = 8.6
d = 8.6
c == d
Why is a != b even if both have same values? Yet, c == d works properly.
I assume Awk has some internal floating-point imprecision. FYI, I'm using Gawk 4.1.4.
I tried various values for PREC, OFMT & CONVFMT, but failed to find ones that would work.
E.g. Changed OFMT & CONVFMT to %.6f:
PREC = 53
OFMT = %.6f
CONVFMT = %.6f
a = 4.600000
b = 4.600000
a != b
c = 8.600000
d = 8.600000
c == d
E.g. Changed PREC to 16:
PREC = 16
OFMT = %.6g
CONVFMT = %.6g
a = 4.6
b = 4.6
a != b
c = 8.6
d = 8.6
c == d
Basically, I'm hoping for some settings inside BEGIN, instead of changing every expression where floating-point arithmetic & comparison are, since my actual Awk script is much longer than the example above.
E.g. I rather not having to use sprintf for each arithmetic & comparison expression, or to convert each input number to integer after scaling by 1e6 & convert each output number by 1e-6. Such approach would be very daunting.
FYI, floating-point numbers in input files will have maximum 6 decimal points, but they may be without decimal points, i.e. they range from 0 to 6 decimal points.
Thank you for your help.
HN
Here the higher precision is working against you. Since some of the decimal values cannot be represented exactly in binary you're just pushing the limits of number equivalence to higher precision numbers which will not be satisfied.
For example for 53 digit precision, you get
1.2 => 1.199999999999999955591079014993738383054733
3.4 => 3.399999999999999911182158029987476766109467
8.9 => 8.900000000000000355271367880050092935562134
4.3 => 4.299999999999999822364316059974953532218933
a = 4.599999999999999644728632119949907064437866
b = 4.600000000000000532907051820075139403343201
a != b
3.2 => 3.200000000000000177635683940025046467781067
5.4 => 5.400000000000000355271367880050092935562134
9.8 => 9.800000000000000710542735760100185871124268
1.2 => 1.199999999999999955591079014993738383054733
c = 8.600000000000001421085471520200371742248535
d = 8.600000000000001421085471520200371742248535
c==d
My suggestion is set the PREC to a more reasonable value (based on your input data precision). I think 10 would be a good tradeoff with minimal code change.
'BEGIN{PREC=10; ...
NB. If you ask why c,d matches, notice that they are all fractions are multiples of 0.2, whereas a,b has a 0.3.
Floating point numbers aren't exact, the answers displayed are rounded off and aren't exactly what the floating point representation is, but the test for equality counts every bit of the results.
As an example, try dividing 1 by 3 with pencil and paper, you get 0.3333333... until you run out of paper. Now multiplying should give you 1.0, right? No, you'll get 0.9999999999...
Similarly, floating point can't exactly represent 0.1.
What's generally done is to compare equality to be within a certain limit, called an "epsilon".
if absolute value of (a - b) < 0.0000001
then print "Equal"
https://www.youtube.com/watch?v=PZRI1IfStY0
GNU Awk's User's Guide - Setting precision says
If you need to represent a floating-point constant at a higher
precision than the default and cannot use a command-line assignment to
PREC, you should either specify the constant as a string, or as a
rational number, whenever possible.

How to factor polynomial with other polynomials?

This is a question on division algorithm. Consider polynomial f=-4x^4y^2z^2+y^6+3z^5 and polynomials G={y^6-z^5, x*z-y^2, x*y^4-z^4, x^2*y^2-z^3 *x^3-z^2}.
How can you factor f with respect to G computationally such that the linear combination f=\sum_i C_i*G_i is satisfied?
I know that the remainder is zero but not which are the coefficients C_i in the above formula, example with Macaulay2
This can be related to the more general mathematical question about ideals here.
This is a very late response. You probably already have the answer, but here it is anyway. "//" computes the coefficients using the division algorithm.
R=QQ[x,y,z,MonomialOrder=>Lex];
f=-4*x^2*y^2*z^2+y^6+3*z^5;
I=ideal(x*z-y^2,x^3-z^2);
G=gb(I);
f//(gens G)
o5 = {6} | 0 |
{2} | 3x2z2-xy2z-y4 |
{5} | 0 |
{4} | 0 |
{3} | -3z3 |
So
f=-4*x^2*y^2*z^2+y^6+3*z^5
=0*(y^6-z^5)+(3*x^2*z^2-x*y^2*z-y^4)(xz-y^2)+0*(xy^4-z^4)+0(x^2*y^2-z^3)+(-3*z^3)*(x^3-z^2).
Another tip is to copy and paste your code, so that others can copy and paste it. If you post an image then we have to type it out manually. If you put four spaces before each line then it will appear as code, as I have done here.
Maybe it's enough to just do a repeated polynomial division, something
like this (a rough pseudo code..)
order G lexicographically
total_rest = 0
coefficients = {g[0]:None, g[1]:None,...}
while f > 0:
for g in G:
quotient, reminder = f / g # polynomial division
coefficients[g] += quotient
if reminder == 0:
return # We are done. f was devisible by G.
f = reminder
total_rest += lt(f) # lt: leading term
f -= lt(f)
# Now it should hold that
# f = coefficient[g]*g + ... + total_rest

How does Matlab calculate the solution of underdetermined systems?

For solving rectangular linear systems Ax=b, where A is mxn and n>m, Matlab performs first a QR factorization then solves a triangular linear system by substitution. For example:
if A is a 4x6 matrix:
A =
0.8147 0.9058 0.1270 0.9134 0.6324 0.0975
0.2785 0.5469 0.9575 0.9649 0.1576 0.9706
0.9572 0.4854 0.8003 0.1419 0.4218 0.9157
0.7922 0.9595 0.6557 0.0357 0.8491 0.9340
and
b=
-0.9661
0.1590
-0.0391
-0.2491
to solve Ax=b we simply do:
x=A\b;
and the solution is:
x =
-0.4284
-0.6475
0
-0.1153
0
0.7662
The underlying steps in this computation are:
QR decomposition of A, then Ax=bwould be equivalent to Q*R*x=b.
As inv(Q)=Q'and R is upper triangular, solving the system would return to solving R*x=b1 where b1=Q'*b.
As R is upper triangular of size 6x4, we have to perform a back-substitution. How does Matlab perform the back substitution knowing that R is not square?
I'm porting this computation to C and have succesfully done it until R*x=b1, I'm lost with the back substitution and I want to find the same result as Matlab.
Edit:
For the above matrix A:
Solving Ax=bis equivalent to solving Rx=b1where:
R =
-1.5117 -1.3991 -1.0952 -0.7786 -1.0819 -1.3007
0 -0.5641 -0.2197 -0.6538 -0.2920 -0.2481
0 0 -0.8692 -0.2077 0.1422 -0.9295
0 0 0 -0.8426 0.2182 0.2125
and
b1 =
-0.9661
0.1590
-0.0391
-0.2491
This system is solved by back-substitution as R is upper triangular, this is straightforward in case of square triangular matrices (i.e m=n), However, R is not square. How does Matlab perform the back-substitution to find x?
So I'm not 100% sure what MATLAB does, but I can tell you the following:
For your underdetermined matrix A (nxm), we can take A' = QR. We also see that A = R'Q'. Note that now, R has n nonzero rows. We can then solve the system by recognizing R'Q'x=b, then Q'x=inv(R')*b. The RHS can be solved by back-substitution, we'll call it y. So Q'x=y. But Q is self-Hermitian, so x=Qy. And there you have the least squares solution.
Doing this in MATLAB we get:
>> [Q,R] = qr(A')
Q =
-0.4918 0.2143 -0.6131 -0.5675 -0.1086 0.0503
-0.5468 0.0638 0.0596 0.5238 -0.5922 -0.2614
-0.0767 -0.6389 -0.1919 -0.0733 0.2275 -0.7014
-0.5514 -0.2397 0.6743 -0.3550 0.1568 0.1821
-0.3818 0.2094 -0.1834 0.4750 0.7368 0.0904
-0.0589 -0.6637 -0.3090 0.2158 -0.1351 0.6291
R =
-1.6565 -1.1588 -1.0907 -1.3634
0 -1.3597 -0.8286 -0.6385
0 0 -0.9760 -0.9745
0 0 0 0.5972
0 0 0 0
0 0 0 0
>> Q*(R'\b)
ans =
-0.4256
-0.3057
0.3568
-0.2745
-0.2823
0.4249
>>
I used backslash above for R'\b, but it's clear you can back-substitute in your own routine.
We can verify this by computing the solution using the pseudo-inverse of A:
>> A'*inv(A*A')*b
ans =
-0.4256
-0.3057
0.3568
-0.2745
-0.2823
0.4249
You can easily check that this is a valid solution of course. This should be readily implementable in C.
Hope this helps.
How MATLAB implements in details the under-determined case only Mathworks know! But a way you can do it is as follow.
A*x = b
A' = Q*R
Now if you look at R you will have something of the form
R = [R1; zeros]
where R1 is square.
you can express the solution as:
x = Q * [inv(R1')*b; zeros]
as you indicates that you already solved the problem of inverting a square matrix that should be easy :)

Taylor series for cosinus return wrong result for 0

I want to write in Maple Taylor series for cosinus function. Here's my code:
better_cos := proc (x) options operator, arrow; sum((-1)^n*x^(2*n)/factorial(2*n), n = 0 .. 20) end proc;
better_cos(0) returns 0 instead of 1 (cos(0) == 1). It's probably because x^(2*n) return always 0 instead of 1. For example:
fun_sum := proc (x) options operator, arrow; sum(x^(2*n), n = 0 .. 0) end proc
return 0 for x == 1.
It's weird because 0^0 returns 1. Do you have any idea how can I correctly implement taylor series for cosinus?
You should be able to get what you want by using add instead of sum in your better_cos operator.
Using add is often more appropriate for adding up a finite number of terms of a numeric sequence, and also note that add has Maple's so-called special evaluation rules.
If you intend to take the sum of a fixed number of terms (ie. n from 0 to 20) then you should not write a procedure that computes the factorials for each input argument (ie. for each value of x). Instead, produce the truncated series just once, and then use unapply to produce an operator. This approach also happens to deal with your original problem, since the x^0 term becomes 1 because the symbol x is used.
You could also rearrange the polynomial (truncated series) so that it is in Horner form, to try and minimize arithmetic steps when evaluating subsequently at various numeric values of x.
For example, using 5 terms for brevity instead of 20 as you had it,
convert(add((-1)^n*x^(2*n)/factorial(2*n), n = 0 .. 5),horner);
/ 1 /1 / 1 / 1 1 2\ 2\ 2\ 2\ 2
1 + |- - + |-- + |- --- + |----- - ------- x | x | x | x | x
\ 2 \24 \ 720 \40320 3628800 / / / /
bc := unapply(%,x):
You can now apply the procedure bc as you wish, either with symbolic or numeric arguments.
expand(bc(x));
1 2 1 4 1 6 1 8 1 10
1 - - x + -- x - --- x + ----- x - ------- x
2 24 720 40320 3628800
bc(0);
1
bc(1.2);
0.3623577360
If you prefer to have your procedure better_cos take a pair of arguments, so that the number of terms is variable, then you could still consider using add to deal with your original problem. eg,
bc := (x,N)->add((-1)^n*x^(2*n)/(2*n)!, n = 0 .. N):
I suppose that this is a homework assignment, and that you realize that you could also use the existing system commands taylor or series to get the same results, ie.
convert(series(cos(x),x=0,10),polynom);
1 2 1 4 1 6 1 8
1 - - x + -- x - --- x + ----- x
2 24 720 40320
convert(taylor(cos(x),x=0,10),polynom);
1 2 1 4 1 6 1 8
1 - - x + -- x - --- x + ----- x
2 24 720 40320
Here's the Taylor series definition:
Don't start the loop with zero; initialize with one and start at two.
Factorial is inefficient, too.

How do I remove axis from a rotation matrix?

I have an opengl arbitrary rotation matrix and would like to remove the X & Y axis, leaving me with only the Z axis?
Is this possible? Any pointers on how to do it?
Just thinking out loud here, but can't you use the matrix to rotate a vector like (1,0,0), then do atan2(y,x) to see how much it's rotated and then build a new matrix to rotate through the Z axis by that much?
In a rotation that is only around the z-axis, the z axis should remain unchanged. So the above recommendation is sort of the reverse of what you want.
Let's assume you have an arbitrary OpenGL matrix:
| r_xx r_xy r_xz t_x |
| r_yx r_yy r_yz t_y |
M = | r_zx r_zy r_zz t_z |
| 0 0 0 1 |
Where the t_i elements are translations and the r_jk elements are components of rotation. You want a matrix that looks like this:
| cos(th) sin(th) 0 t_x |
|-sin(th) cos(th) 0 t_y |
| 0 0 1 t_z |
| 0 0 0 1 |
Unless the matrix has scaling factors or is close to a singularity, you should be able to get this by just zeroing out the z parts of the matrix and then re-normalizing the columns. Since an OpenGL matrix is column major order:
double xLen = sqrt(M[0]*M[0] + M[1]*M[1]); // Singularity if either of these
double yLen = sqrt(M[4]*M[4] + M[5]*M[5]); // is equal to zero.
M[0]/=xLen; M[1]/=xLen; M[2]=0; // Set the x column
M[4]/=yLen; M[5]/=yLen; M[6]=0; // Set the y column
M[8]=0; M[9]=0; M[10]=1; // Set the z column
//Don't change the translation column

Resources