    

 ## On this page

  

 

 # Example 23 - C++ 

 Last update: 17.07.2025 

# <a class="anchor" id="ex23_s2"></a>C++

// CppStandaloneApplication.cpp : Defines the entry point for the console application.

 

\#include "stdafx.h"

\#include &lt;stdlib.h&gt;

\#include &lt;stdio.h&gt;

\#include &lt;iostream&gt;

\#include &lt;string&gt;

\#include &lt;ctime&gt;

\#include &lt;functional&gt;

\#include &lt;assert.h&gt;

\#include &lt;fstream&gt;

\#include &lt;iomanip&gt;

\#include &lt;vector&gt;

\#include &lt;cstdlib&gt;

 

// Note - .tlh files will be generated from the .tlb files (above) once the project is compiled.

// Visual Studio will incorrectly continue to report IntelliSense error messages however until it is restarted.

\#include "zosapi.h"

 

using namespace std;

using namespace [ZOSAPI](namespace_z_o_s_a_p_i.xhtml);

using namespace ZOSAPI_Interfaces;

 

void handleError(std::string msg);

void logInfo(std::string msg);

void finishStandaloneApplication(IZOSAPI_ApplicationPtr TheApplication);

 

int RunApplication()

{

 CoInitialize(NULL);

 

 // Create the initial connection class

 IZOSAPI_ConnectionPtr TheConnection(__uuidof([ZOSAPI\_Connection](class_z_o_s_a_p_i_1_1_z_o_s_a_p_i___connection.xhtml)));

 

 

 // Attempt to create a Standalone connection

 IZOSAPI_ApplicationPtr TheApplication = TheConnection-&gt;CreateNewApplication();

 if (TheApplication == nullptr)

 {

 handleError("An unknown error occurred!");

 return -1;

 }

 

 // Check the connection status

 if (!TheApplication-&gt;IsValidLicenseForAPI)

 {

 handleError("License check failed!");

 return -1;

 }

 if (TheApplication-&gt;Mode != ZOSAPI_Mode::ZOSAPI_Mode_Server)

 {

 handleError("Standlone application was started in the incorrect mode!");

 return -1;

 }

 

 

 // Add your custom code here...

 

 // creates a new API directory

 CreateDirectory(_bstr_t(TheApplication-&gt;SamplesDir + "\\\\API"), NULL);

 CreateDirectory(_bstr_t(TheApplication-&gt;SamplesDir + "\\\\API\\\\CPP"), NULL);

 

 // Set up primary optical system

 IOpticalSystemPtr TheSystem = TheApplication-&gt;CreateNewSystem(SystemType_Sequential);

 _bstr_t sampleDir = TheApplication-&gt;SamplesDir;

 _bstr_t testFile = sampleDir + "\\\\Sequential\\\\Objectives\\\\Double Gauss 28 degree field.zos";

 TheSystem-&gt;LoadFile(testFile, false);

 

 fstream textfile;

 string filepath = sampleDir + "\\\\API\\\\CPP\\\\e23\_ray\_fan\_native\_manual\_comparison.txt";

 textfile.open(filepath, fstream::trunc | ios::out);

 

 int max_rays = 150;

 int max_num_field = TheSystem-&gt;SystemData-&gt;Fields-&gt;NumberOfFields;

 int max_wave = TheSystem-&gt;SystemData-&gt;Wavelengths-&gt;NumberOfWavelengths;

 int max_field = 0;

 for (int i = 1; i &lt; max_num_field; i++)

 if (TheSystem-&gt;SystemData-&gt;Fields-&gt;GetField(i)-&gt;Y &gt; max_field)

 max_field = (int)TheSystem-&gt;SystemData-&gt;Fields-&gt;GetField(i)-&gt;Y;

 

 // Set up timer.

 double duration1, duration2;

 std::clock_t start;

 start = std::clock();

 

 cout &lt;&lt; "Section 1: Batch Ray trace\\n\\n";

 textfile &lt;&lt; "Section 1: Batch Ray trace\\n\\n";

 

 // Set up Batch Ray Trace

 IBatchRayTracePtr raytrace = TheSystem-&gt;Tools-&gt;OpenBatchRayTrace();

 int nsur = TheSystem-&gt;LDE-&gt;NumberOfSurfaces;

 IRayTraceNormUnpolDataPtr normUnPolData = raytrace-&gt;CreateNormUnpol(max_rays + 1, RaysType_Real, nsur);

 

 // define batch ray trace constants (hx, hy, px, py)

 double hx = 0, px = 0;

 std::vector&lt;double&gt; py_ary(max_rays + 1);

 for (int i = 0; i &lt; max_rays + 1; i++) {

 py_ary[i] = (double)i / max_rays * 2 - 1;

 }

 

 // image surface number and primary wavelength

 //

 int pwav = 0;

 for (int a = 1; a &lt;= TheSystem-&gt;SystemData-&gt;Wavelengths-&gt;NumberOfWavelengths; a++) {

 if (TheSystem-&gt;SystemData-&gt;Wavelengths-&gt;GetWavelength(a)-&gt;IsPrimary)

 pwav = a;

 }

 

 // creates array of Y coordinate chief ray values

 double *chief_ary = new double[max_num_field];

 for (int field = 1; field &lt;= max_num_field; field++) {

 double hy = TheSystem-&gt;SystemData-&gt;Fields-&gt;GetField(field)-&gt;Y / max_field;

 // gets single value without using MFE(see ZPL OPEV)

 chief_ary[field - 1] = TheSystem-&gt;MFE-&gt;GetOperandValue(MeritOperandType_REAY, nsur, pwav, 0, hy, 0, 0, 0, 0);

 }

 

 // initialize x / y image plane arrays

 std::vector&lt;vector&lt;vector&lt;double&gt;&gt;&gt; y_ary(max_num_field, vector&lt;vector&lt;double&gt;&gt;(max_wave, std::vector&lt;double&gt;((max_rays + 1) * (max_rays + 1), 0)));

 

 // setup plot

 for (int field = 1; field &lt; max_num_field + 1; field++) {

 double hy = TheSystem-&gt;SystemData-&gt;Fields-&gt;GetField(field)-&gt;Y / max_field;

 for (int wave = 1; wave &lt; max_wave + 1; wave++) {

 // Adding Rays to Batch, varying normalised object height hy

 normUnPolData-&gt;ClearData();

 for (int i = 0; i &lt; max_rays + 1; i++) {

 double py = py_ary[i];

 normUnPolData-&gt;AddRay(wave, hx, hy, px, py, OPDMode_None);

 }

 

 // Run Batch Ray Trace

 ISystemToolPtr baseTool = raytrace;

 baseTool-&gt;RunAndWaitForCompletion();

 

 // Read and display results

 normUnPolData-&gt;StartReadingResults();

 long rayNumber, errCode, vigCode;

 double rayX, rayY, rayZ, rayL, rayM, rayN, rayl2, raym2, rayn2, rayopd, rayintensiry;

 textfile &lt;&lt; "Field \[" &lt;&lt; field &lt;&lt; "\] and Wave# \[" &lt;&lt; wave &lt;&lt; "\]\\n";

 textfile &lt;&lt; "Ray# Py REAY\\n";

 VARIANT_BOOL success = normUnPolData-&gt;ReadNextResult(&amp;rayNumber, &amp;errCode, &amp;vigCode, &amp;rayX, &amp;rayY, &amp;rayZ, &amp;rayL, &amp;rayM, &amp;rayN, &amp;rayl2, &amp;raym2, &amp;rayn2, &amp;rayopd, &amp;rayintensiry);

 while (success) {

 if ((errCode == 0) &amp;&amp; (vigCode == 0)) {

 textfile &lt;&lt; setw(7) &lt;&lt; rayNumber &lt;&lt; setw(15) &lt;&lt; left &lt;&lt; py_ary[rayNumber - 1] &lt;&lt; setw(15) &lt;&lt; left &lt;&lt; ((rayY - chief_ary[field - 1]) * 1000) &lt;&lt; "\\n";

 y_ary[field - 1][wave - 1][rayNumber - 1] = rayY;

 }

 success = normUnPolData-&gt;ReadNextResult(&amp;rayNumber, &amp;errCode, &amp;vigCode, &amp;rayX, &amp;rayY, &amp;rayZ, &amp;rayL, &amp;rayM, &amp;rayN, &amp;rayl2, &amp;raym2, &amp;rayn2, &amp;rayopd, &amp;rayintensiry);

 }

 textfile &lt;&lt; endl;

 }

 }

 

 duration1 = (std::clock() - start) / (double)CLOCKS_PER_SEC;

 cout &lt;&lt; "Elapsed Time(Batch): " &lt;&lt; duration1 &lt;&lt; "\\n\\n";

 textfile &lt;&lt; "Elapsed Time(Batch): " &lt;&lt; duration1 &lt;&lt; "\\n\\n";

 

 cout &lt;&lt; "Section 2: Ray Fan data" &lt;&lt; endl;

 textfile &lt;&lt; "Section 2: Ray Fan data" &lt;&lt; endl;

 

 // Set up Ray Fan analysis

 IA_Ptr ray = TheSystem-&gt;Analyses-&gt;New_Analysis(AnalysisIDM_RayFan);

 IAS_Ptr ray_set = ray-&gt;GetSettings();

 IAS_FanPtr ray_fanset = ray_set;

 ray_fanset-&gt;NumberOfRays = max_rays / 2;

 ray_fanset-&gt;Field-&gt;UseAllFields();

 ray_fanset-&gt;Wavelength-&gt;UseAllWavelengths();

 ray-&gt;ApplyAndWaitForCompletion();

 IAR_Ptr ray_results = ray-&gt;GetResults();

 

 

 cout &lt;&lt; "Number Of Series: \[" &lt;&lt; ray_results-&gt;NumberOfDataSeries &lt;&lt; "\]\\n" &lt;&lt; endl;

 textfile &lt;&lt; "Number Of Series: \[" &lt;&lt; ray_results-&gt;NumberOfDataSeries &lt;&lt; "\]\\n" &lt;&lt; endl;

 

 for (int field = 1; field &lt; max_num_field + 1; field++) {

 

 // COM will return a SAFEARRAY, use SafeArrayAccessData() to retrieve data

 double *xdata, *ydata;

 SAFEARRAY *xData = ray_results-&gt;GetDataSeries(field * 2 - 1)-&gt;XData-&gt;Data;

 SAFEARRAY *yData = ray_results-&gt;GetDataSeries(field * 2 - 1)-&gt;YData-&gt;Data;

 HRESULT hrx = SafeArrayAccessData(xData, (void**)&amp;xdata);

 HRESULT hry = SafeArrayAccessData(yData, (void**)&amp;ydata);

 

 int XData_Length = ray_results-&gt;GetDataSeries(field * 2 - 1)-&gt;XData-&gt;Length;

 int YData_Rows = ray_results-&gt;GetDataSeries(field * 2 - 1)-&gt;YData-&gt;Rows;

 int YData_Cols = ray_results-&gt;GetDataSeries(field * 2 - 1)-&gt;YData-&gt;Cols;

 int YData_TolLen = ray_results-&gt;GetDataSeries(field * 2 - 1)-&gt;YData-&gt;TotalLength;

 

 if (SUCCEEDED(hrx &amp;&amp; hry)) {

 textfile &lt;&lt; "Series \[" &lt;&lt; (field * 2 - 1) &lt;&lt; "\]: Tangential Ray Fan of Field# \[" &lt;&lt; field &lt;&lt; "\]\\n";

 textfile &lt;&lt; "Each series has properties XData and YData.\\n";

 textfile &lt;&lt; "XData :1D vector, the length is \[" &lt;&lt; XData_Length &lt;&lt; "\]\\n";

 textfile &lt;&lt; "YData :2D matrix with \[" &lt;&lt; YData_Rows &lt;&lt; "\] rows, \[" &lt;&lt; YData_Cols &lt;&lt; "\] columns and total Length of \[" &lt;&lt; YData_TolLen &lt;&lt; "\]\\n" &lt;&lt; endl;

 for (int i = 0; i &lt; YData_Cols; i++) {

 textfile &lt;&lt; "\\nData for Field \[" &lt;&lt; field &lt;&lt; "\] and Wave# \[" &lt;&lt; i + 1 &lt;&lt; "\]\\n";

 textfile &lt;&lt; "Ray# Px Ey\\n";

 for (int j = 0; j &lt; XData_Length; j++) {

 textfile &lt;&lt; setw(7) &lt;&lt; i * XData_Length + j &lt;&lt; setw(15) &lt;&lt; left &lt;&lt; xdata[j] &lt;&lt; setw(15) &lt;&lt; left &lt;&lt; ydata[i * XData_Length + j] &lt;&lt; "\\n";

 }

 }

 textfile &lt;&lt; endl;

 // Cleanup safearray when finished

 SafeArrayUnaccessData(xData);

 }

 }

 duration2 = (std::clock() - start) / (double)CLOCKS_PER_SEC - duration1;

 cout &lt;&lt; "Elapsed Time(RayFan): " &lt;&lt; duration2 &lt;&lt; "\\n\\n\\n\\n";

 textfile &lt;&lt; "Elapsed Time(RayFan): " &lt;&lt; duration2 &lt;&lt; "\\n\\n\\n\\n";

 

\#if defined(\_DEBUG)

 // keeps console open when in debug mode

 system("pause");

\#endif

 

 // Clean up

 finishStandaloneApplication(TheApplication);

 

 return 0;

}

 

void handleError(std::string msg)

{

 throw new exception(msg.c_str());

}

 

void logInfo(std::string msg)

{

 printf("%s", msg.c_str());

}

 

void finishStandaloneApplication(IZOSAPI_ApplicationPtr TheApplication)

{

 // Note - TheApplication will close automatically when this application exits, so this isn't strictly necessary in most cases

 if (TheApplication != nullptr)

 {

 TheApplication-&gt;CloseApplication();

 }

}

 

int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)

{

 return RunApplication();

}

 

int _tmain(int argc, _TCHAR* argv[])

{

 return RunApplication();

}

[ZOSAPI.ZOSAPI\_Connection](class_z_o_s_a_p_i_1_1_z_o_s_a_p_i___connection.xhtml)

**Definition:** ZemaxService.cs:198



[ZOSAPI](namespace_z_o_s_a_p_i.xhtml)

The ZOSAPI namespace contains classes for initially connecting to zemax. See also ZOSAPI_Connection,...

**Definition:** IAS_FieldCurvatureAndDistortion.cs:5