Skip to main content
Question

Rotation Matrix to Tilt XYZ problem

  • December 2, 2025
  • 4 replies
  • 31 views

Sean Turner
Fully Spectral
Forum|alt.badge.img+1

@MichaelH ​I have a discrepancy when converting from a rotation matrix to tilt XYZ values when I use your ZPL19 macro compared to a macro I wrote. The values in my macro agree with tilt values calculated using ATAN2 in excel.

I can’t share the file, but here is the merit function showing the rotation matrix for a given surface. Also shown are the 3 outputs of the ZPL19 macro. 

The tilt Z value of 180° does not agree with a macro I wrote or ATAN2 in excel. I even used some if statements to match your ZPL19 macro steps in excel, but even this disagrees with the macro in Zemax. See below.

Any thoughts? 

Also, this is one more request for a built-in ZPL function or merit function operand to report tilt X, Y, Z values for a given surface.

-Sean

4 replies

Sean Turner
Fully Spectral
Forum|alt.badge.img+1
  • Author
  • Fully Spectral
  • December 2, 2025

I should add the prescription report also disagrees with the ZPL19 output.

 


MichaelH
Ansys Staff
Forum|alt.badge.img+2
  • Ansys Staff
  • December 2, 2025

Hey Sean,

I think the issue might be a round-off error in the ATAN2 subroutine of the ZPL macro, namely the ATAN2 is checking exactly for equaling 0 rather than looking at a tolerance.  I would look at changing the nested IF statements that are checking when x = 0:

SUB ATAN2
IF x > 0
val = ATAN(y/x)
ELSE
IF x < 0 & y >= 0
# this is where TiltZ is incorrectly calculated in your file
val = ATAN(y/x) + pi
ELSE
IF x < 0 & y < 0
val = ATAN(y/x) - pi
ELSE
IF ABSO(x) < 1e-10 & y > 0
# this is where the TiltZ should be calculated
val = pi / 2
ELSE
IF ABSO(x) < 1e-10 & y < 0
val = -pi / 2
ELSE
val = 9e9
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
RETURN

Basically, in your scenario, the ATAN2 function has x = 0 (R11) and y = 0.2181550273 (-R12).  Going through this logic, the ATAN2 should be calculated in the 4th IF statement where val = pi / 2.  It appears that your system is in the 2nd IF statement and y = 0 (so ATAN = pi) and then the macro is returning pi.

I tried to recreate your file with a simple Coordinate Break and optimizing for your global rotation matrix, but I’m unable to reproduce your results.  I used GLCR operands with the Target values set to your file & the Weight equal to 1, then optimized on TiltX, TiltY, TiltZ.  This gives me the 90deg for TiltZ:

 

P.S. after reviewing the logic in ATAN2, I have 2 mistakes when checking for x == 0...there should be a second equal sign to check for equality rather than the single equal sign that is used for assignment.  This still shouldn’t give the error you’re seeing because this logic is farther down the multi-part IF statements but it should still be updated.  


Sean Turner
Fully Spectral
Forum|alt.badge.img+1
  • Author
  • Fully Spectral
  • December 2, 2025

Hi Michael,

Thanks for the reply. I was able to recreate the issue with the sample file from the knowledgebase article. I copied the tilt Y value from my file and pasted it into the sample file. You can see the tilt Z value in the merit function editor does not agree with the multi configuration editor or the prescription report. Maybe this is due to a rounding error in the ZPL code?

Here are all the digits that I pasted in if you want to try it yourself. 

7.739930805223027E+001

 


MichaelH
Ansys Staff
Forum|alt.badge.img+2
  • Ansys Staff
  • December 3, 2025

Hey Sean,

Thanks for providing this feedback.  Yes, it is a roundoff error because if you look at which “case” the ATAN2 function is returning for the TiltZ, it’s the temp=2.2 case, so the ZPL is thinking that x<0 when in reality, x=0.  Since x=0 is a singular case, this should actually be checked first, and we should also rely on a threshold value as I originally mentioned.  

Here is the modified ATAN2 function that you should be able to copy & paste into your macro and have it work:

SUB ATAN2
val = 9e9
IF ABSO(x) < 1e-10
IF y > 0
val = pi / 2
ELSE
val = -pi / 2
ENDIF
ELSE
IF x > 0
val = ATAN(y / x)
ELSE
IF y < 0
val = ATAN(y / x) - pi
ELSE
val = ATAN(y / x) + pi
ENDIF
ENDIF
ENDIF
RETURN