    

 ## On this page

  

 

 # Example 08 - C++ 

 Last update: 17.07.2025 

# <a class="anchor" id="ex08_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;math.h&gt;

\#include &lt;fstream&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(nullptr);

 

 // 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;

 }

 

 IOpticalSystemPtr TheSystem = TheApplication-&gt;PrimarySystem;

 

 // Add your custom code here...

 

 /\*

 -. load \\Samples\\NS\\Scattering\\ABg scattering surface.zos

 1. delete object 3(specular ray blocking)

 2. insert detector polar positioned at same pos as object 2

 - retrieve obj 2 rotation matrix, match orientation

 - size = 20

 - remove material from obj 4

 -. run ray trace

 3/4. Save/Load Detector Data

 5/6. get detector data for detector polar

 - retrieve single value data with GetDetectorPolarData()

 - retrieve data grid (all pixels) with GetAllDetectorPolarData()

 7/8. get detector rectangle data

 - retrieve single value data with GetDetectorData()

 - retrieve data grid (all pixels) with GetAllDetectorData()

 9/10. get coherent detector data

 - retrieve single value data with GetCoherentData()

 - retrieve data grid (all pixels) with GetAllCoherentData()

 \*/

 

 _bstr_t file = "\\\\Samples\\\\Non-Sequential\\\\Scattering\\\\Abg scattering surface.zos";

 _bstr_t DataDir = TheApplication-&gt;ZemaxDataDir;

 _bstr_t filepath = DataDir + file;

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

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

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

 

 // Delete unnecessary object from NSCE

 bool success = TheSystem-&gt;NCE-&gt;RemoveObjectAt(3);

 // Add detector polar, change radial size to 20mm

 INCERowPtr obj3 = TheSystem-&gt;NCE-&gt;InsertNewObjectAt(3);

 IObjectTypeSettingsPtr [DetectorPolar](namespace_z_o_s_a_p_i_1_1_editors_1_1_n_c_e.xhtml#afaeb02568d1df3bbfabfe7d8f9b59285a139b274362a21679f442de10127b25ca) = obj3-&gt;GetObjectTypeSettings(ObjectType::ObjectType_DetectorPolar);

 obj3-&gt;ChangeType(DetectorPolar);

 // Set the detector polar radial size to 20

 ((IEditorRowPtr)obj3)-&gt;GetCellAt(12)-&gt;DoubleValue = 20; // cell 12 always corresponds to 'Par2' in the NSCE

 

 // Co-locate object 3 with object 2 (here, could alternatively use the 'Ref Object' flag)

 double R11, R12, R13, R21, R22, R23, R31, R32, R33, Xo, Yo, Zo;

 bool MatrixSuccess = TheSystem-&gt;NCE-&gt;GetMatrix(2, &amp;R11, &amp;R12, &amp;R13, &amp;R21, &amp;R22, &amp;R23, &amp;R31, &amp;R32, &amp;R33, &amp;Xo, &amp;Yo, &amp;Zo);

 obj3-&gt;XPosition = Xo;

 obj3-&gt;YPosition = Yo;

 obj3-&gt;ZPosition = Zo;

 // Conversion from rotation matrix to tilts described in KBA "Rotation matrix and Tilt About X/Y/Z in OpticStudio"

 obj3-&gt;TiltAboutX = atan2(-1 * R23, R33);

 obj3-&gt;TiltAboutY = asin(R13);

 obj3-&gt;TiltAboutZ = atan2(-1 * R12, R11);

 

 // Remove the ABSORB material from object 4

 TheSystem-&gt;NCE-&gt;GetObjectAt(4)-&gt;Material = "";

 // Run ray trace

 INSCRayTracePtr [RayTrace](namespace_z_o_s_a_p_i_1_1_analysis.xhtml#a0a5cf0f456b9510dd8070610bf696de7a143874eab0d95152e7ac0009deaefade) = TheSystem-&gt;Tools-&gt;OpenNSCRayTrace();

 [RayTrace](namespace_z_o_s_a_p_i_1_1_analysis.xhtml#a0a5cf0f456b9510dd8070610bf696de7a143874eab0d95152e7ac0009deaefade)-&gt;ClearDetectors(0); // clear the old detector data!

 [RayTrace](namespace_z_o_s_a_p_i_1_1_analysis.xhtml#a0a5cf0f456b9510dd8070610bf696de7a143874eab0d95152e7ac0009deaefade)-&gt;ScatterNSCRays = true;

 [RayTrace](namespace_z_o_s_a_p_i_1_1_analysis.xhtml#a0a5cf0f456b9510dd8070610bf696de7a143874eab0d95152e7ac0009deaefade)-&gt;UsePolarization = false;

 [RayTrace](namespace_z_o_s_a_p_i_1_1_analysis.xhtml#a0a5cf0f456b9510dd8070610bf696de7a143874eab0d95152e7ac0009deaefade)-&gt;SplitNSCRays = false;

 [RayTrace](namespace_z_o_s_a_p_i_1_1_analysis.xhtml#a0a5cf0f456b9510dd8070610bf696de7a143874eab0d95152e7ac0009deaefade)-&gt;IgnoreErrors = true;

 ((ISystemToolPtr)RayTrace)-&gt;RunAndWaitForCompletion();

 ((ISystemToolPtr)RayTrace)-&gt;Close();

 

 

 // The next two steps are technically unnecessary in this case; since we just ran the ray trace,

 // the results are already there. But we demonstrate usage here anyways

 // Save detector data -- allows ray trace results to be loaded later

 // For detector polar, the file type is .DDP; for detector rectangle, it is .DDR

 _bstr_t DetectorPolarFile = TheApplication-&gt;ZemaxDataDir + "\\\\Samples\\\\API\\\\CPP\\\\detector3polar.DDP";

 _bstr_t DetectorRectFile = TheApplication-&gt;ZemaxDataDir + "\\\\Samples\\\\API\\\\CPP\\\\detector4rect.DDR";

 TheSystem-&gt;NCE-&gt;SaveDetector(3, DetectorPolarFile);

 TheSystem-&gt;NCE-&gt;SaveDetector(4, DetectorRectFile);

 

 // Load detector data -- for analyzing previous ray trace results

 // For detector polar, the file type is .DDP; for detector rectangle, it's .DDR

 TheSystem-&gt;NCE-&gt;LoadDetector(3, TheApplication-&gt;ZemaxDataDir + "\\\\Samples\\\\API\\\\CPP\\\\detector3polar.DDP", false);

 TheSystem-&gt;NCE-&gt;LoadDetector(4, TheApplication-&gt;ZemaxDataDir + "\\\\Samples\\\\API\\\\CPP\\\\detector4rect.DDR", false);

 

 

 // Here we read in the detector polar data from ZOS

 // GetPolarDetectorData() is very similar to the MF operand NSDP;

 // can retrieve RMS (degrees), total power, chromatricity, etc. (see NSDP in OpticStudio help)

 // Note: GetPolarDetectorData() uses an enumeration for data type, shown here

 double DetPolarData_RadialRMS, DetPolarData_ChromX, DetPolarData_ChromY;

 [PolarDetectorDataType](namespace_z_o_s_a_p_i_1_1_editors_1_1_n_c_e.xhtml#af2e3d9a13b455eab749a70ec14b79b79) DataFlag_Power = PolarDetectorDataType::PolarDetectorDataType_Power;

 [PolarDetectorDataType](namespace_z_o_s_a_p_i_1_1_editors_1_1_n_c_e.xhtml#af2e3d9a13b455eab749a70ec14b79b79) DataFlag_ChromX = PolarDetectorDataType::PolarDetectorDataType_Cx;

 [PolarDetectorDataType](namespace_z_o_s_a_p_i_1_1_editors_1_1_n_c_e.xhtml#af2e3d9a13b455eab749a70ec14b79b79) DataFlag_ChromY = PolarDetectorDataType::PolarDetectorDataType_Cy;

 bool successRadialRMS = TheSystem-&gt;NCE-&gt;GetPolarDetectorData(3, -4, DataFlag_Power, &amp;DetPolarData_RadialRMS);

 bool successChromX = TheSystem-&gt;NCE-&gt;GetPolarDetectorData(3, 0, DataFlag_ChromX, &amp;DetPolarData_ChromX);

 bool successChromY = TheSystem-&gt;NCE-&gt;GetPolarDetectorData(3, 0, DataFlag_ChromY, &amp;DetPolarData_ChromY);

 

 // to retrieve the entire data array (power, tristim. X/Y/Z, etc. for each pixel)

 // can use GetAllPolarDetectorDataSafe(), or GetAllPolarDetectorData(). 

 // Safe arrays are cumbersome in C++, so use GetAllPolarDetectorData() here.

 // initialize output arrays

 // detector polar is known to have 181x180 pixels (the defaults); 181\*180=32580

 double* DetPolarData_TriX = new double[32580];

 double* DetPolarData_TriY = new double[32580];

 double* DetPolarData_TriZ = new double[32580];

 // Note: GetAllPolarDetectorData() uses an enumeration for data type, shown here

 [PolarDetectorDataType](namespace_z_o_s_a_p_i_1_1_editors_1_1_n_c_e.xhtml#af2e3d9a13b455eab749a70ec14b79b79) DataFlag_TriX = PolarDetectorDataType::PolarDetectorDataType_TriX;

 [PolarDetectorDataType](namespace_z_o_s_a_p_i_1_1_editors_1_1_n_c_e.xhtml#af2e3d9a13b455eab749a70ec14b79b79) DataFlag_TriY = PolarDetectorDataType::PolarDetectorDataType_TriY;

 [PolarDetectorDataType](namespace_z_o_s_a_p_i_1_1_editors_1_1_n_c_e.xhtml#af2e3d9a13b455eab749a70ec14b79b79) DataFlag_TriZ = PolarDetectorDataType::PolarDetectorDataType_TriZ;

 // now, retrieve the pixel data array

 bool SuccessTriX = TheSystem-&gt;NCE-&gt;GetAllPolarDetectorData(3, DataFlag_TriX, 32580, DetPolarData_TriX);

 bool SuccessTriY = TheSystem-&gt;NCE-&gt;GetAllPolarDetectorData(3, DataFlag_TriY, 32580, DetPolarData_TriY);

 bool SuccessTriZ = TheSystem-&gt;NCE-&gt;GetAllPolarDetectorData(3, DataFlag_TriZ, 32580, DetPolarData_TriZ);

 

 // Here we read in the detector rectangle data

 // GetDetectorData() is very similar to the operand NSDD

 // can retrieve RMS, # of rays, total power, etc.; data calculated over whole detector or individual pixel

 double StdDev;

 bool DetRectReturn = TheSystem-&gt;NCE-&gt;GetDetectorData(4, -4, 0, &amp;StdDev); // obj=4, pix=-4, data=0

 

 // To retrieve the entire data array (flux, flux/area, etc.) for all pixel data,

 // can use GetAllDetectorDataSafe() or GetAllDetectorData(). Allows external pixel data analysis.

 // Safe arrays are cumbersome in C++, so use GetAllDetectorData() here.

 // The 'Data' inputs for these functions(parameter 2) can be found in

 // the API syntax help, under the listing for GetAllDetectorData().

 // Detector dimensions known to be 120x120 pixels

 double* DetRectangleData_Flux = new double[14400]; // total flux on each pixel

 double* DetRectangleData_FluxArea = new double[14400]; // flux/area on each pixel

 double* DetRectangleData_FluxSAP = new double[14400]; // flux/solid angle\*area for each pixel

 // now, retrieve the pixel data array

 bool SuccessFlux = TheSystem-&gt;NCE-&gt;GetAllDetectorData(4, 0, 14400, DetRectangleData_Flux);

 bool SuccessFluxArea = TheSystem-&gt;NCE-&gt;GetAllDetectorData(4, 1, 14400, DetRectangleData_FluxArea);

 bool SuccessFluxSAP = TheSystem-&gt;NCE-&gt;GetAllDetectorData(4, 2, 14400, DetRectangleData_FluxSAP);

 

 // Finally, let's read coherent data.

 // The coherent data is meaningless in this example, but it serves to demonstrate API usage and functionality

 // !\[e08s09\_cp\]

 // Read in the detector rectangle coherent data

 // GetCoherentData() is very similar to the operand NSDC

 // Can retrieve real, imaginary, amplitude, power, with 'data' input

 // for pix = 0, get sum on detector; pix &gt; 0 gives single pixel data

 double TotalAmp, TotalPower;

 bool SuccessAmp = TheSystem-&gt;NCE-&gt;GetCoherentData(4, 0, DetectorDataType::DetectorDataType_Amplitude, &amp;TotalAmp); // obj=4, pix=0, data=2

 bool SuccessPower = TheSystem-&gt;NCE-&gt;GetCoherentData(4, 0, DetectorDataType::DetectorDataType_Power, &amp;TotalPower); // obj=4, pix=0, data=3

 

 // !\[e08s10\_cp\]

 // Retrieve whole data array with GetAllCoherentDataSafe(), or GetAllCoherentData().

 // Safe arrays are cumbersome in C++, so use GetAllCoherentData() here.

 // The 'Data' input functions similarly to NSDC(real, imaginary, amplitude, power)

 // Note: divide coherent power by pixel area to get coherent irradiance.

 double* DetRectangleData_CoherentPower = new double[14400]; // coherent power on each pixel

 bool SuccessCoherentPow = TheSystem-&gt;NCE-&gt;GetAllCoherentData(4, DetectorDataType::DetectorDataType_Power, 14400, DetRectangleData_CoherentPower);

 // !\[e08s10\_cp\]

 

 _bstr_t OutFile = "\\\\Samples\\\\API\\\\CPP\\\\CPP\_08\_NSCEDetectorData.zos";

 _bstr_t OutFilePath = DataDir + OutFile;

 TheSystem-&gt;SaveAs(OutFilePath);

 

 // from here, we can plot or analyze any detector data we want!

 

 // 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.Analysis.AnalysisIDM.RayTrace](namespace_z_o_s_a_p_i_1_1_analysis.xhtml#a0a5cf0f456b9510dd8070610bf696de7a143874eab0d95152e7ac0009deaefade)

@ RayTrace

Single Ray Trace.



[ZOSAPI.Editors.NCE.PolarDetectorDataType](namespace_z_o_s_a_p_i_1_1_editors_1_1_n_c_e.xhtml#af2e3d9a13b455eab749a70ec14b79b79)

PolarDetectorDataType

**Definition:** InterfacesNCE.cs:262



[ZOSAPI.Editors.NCE.ObjectType.DetectorPolar](namespace_z_o_s_a_p_i_1_1_editors_1_1_n_c_e.xhtml#afaeb02568d1df3bbfabfe7d8f9b59285a139b274362a21679f442de10127b25ca)

@ DetectorPolar



[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