z = f(x, y)
In this article I will use Waterloo Maple to enter the required equations and produce the optimized C-code needed. In the following examples, red courier font represents data entered into Maple, blue font represents output from Maple, and text after the # symbol are comments.
In the following, the variable ka is the amplitude of a Gaussian function of fixed width, rr is the radial distance at which the amplitude has fallen to ka/100, and dx and dy are optional decentrations entered via the Lens Data Editor.

This function is then added to the normal Odd Asphere sag as defined in the ZEMAX manual. By using Maple this can be easily done with common math functions and procedures:

This equation must be converted to C code to implement adequate DLL for Zemax. Maple has very convenient tool for this action namely “Codegen”. Note, that array indexes are decreased by 1 when Maple performs C code generation – that’s why there is param[i+1] in the Maple code:

What's more, Maple can also optimize the C-code it produces:

This can then be copy-and-pasted into Case 5 of the DLL, with just a little hand editing.
Now we have the surface sag, the next step is to compute the direction cosines of the normal vector. The normal vector at a point (x0,y0) on a surface z = f(x,y) is given by

where fx = df/dx and fy = df/dy are partial derivatives. So, the direction cosines will be as follows:

In Maple, fx is given by:

The same actions are used to compute Fy.
The final stage is to copy all this code into the DLL, with minor edits so that the ZEMAX parameters are mapped correctly to the Maple ones, declare all needed variables, and to build the dll. The source code for this surface, and the associated Maple file, are provided in the zip file you can download from the last page of this article.
After the build is finished (and any compile-time error messages are corrected) it is time for the debugging stage. This may be most complicated and time-demanding part. I use DebugView freeware utility from Sysinternals. To monitor any variable while running your DLL in Zemax you just needed to add 3 strings into source code:
1. Declare variable:
char DebugString[200];
2. Add command for output in desired place and with needed format, for example:
sprintf(DebugString, "z=%f t=%f sag=%f",z,t,sag); //will print variables z, t and sag with format determined by text in quotes
OutputDebugString (DebugString );
This example is included into attached DLL code (lines 34, 224 and 225).
After compiling with such commands it is time to start DebugView. For convenience it is best to set up filter, and for the supplied file DebugView mwas set to catch string consisting “z=”:

After loading the DLL into Zemax, DebugView will display information like following:

Here the user can monitor the available variables and correct source, if needed.
This article has described some useful steps for compiling UDS DLLs:
References.
1. Eric W. Weisstein. "Normal Vector." From MathWorld--A Wolfram Web Resource. http://mathworld.wolfram.com/NormalVector.html
2. http://www.sysinternals.com/Utilities/DebugView.html