Skip to main content

Zemax OpticStudio ZOS-API 2026 R1

File PrepareForLMx.cs

Last update: 13.03.2026

Source

using System;
using System.Collections.Generic;
using ZOSAPI.Tools.General;

namespace ZOSAPI.Tools.LMx
{
    /*
       * 
       * Material   
  Index of Refraction (nd)  nd = _____ ± ___
  Abbe Number (vd)  vd = _____ ± ___%
  Thickness     lens units
  Clear Aperture – Surface 1    Øe = _____ lens units
  Clear Aperture – Surface 2    Øe = _____ lens units
  Radius – Surface 1    lens units
  Radius – Surface 2    lens units
  (λ)Functional Tolerances of Wavelength – Surface 1    Ravg <__% for __< λ < __nm
  (λ)Functional Tolerances of Wavelength – Surface 2    Ravg <__% for __< λ < __nm
  (λ)Surface Coating – Surface 1    
  (λ)Surface Coating – Surface 2    
  (0/) Stress Birefringence     0/ A  or  00/ A  or  10/ A
  (1/) Bubbles and inclusions   1/ NxA  or  01/ NxA  or 11/ NxA
  (2/) Inhomogeneity & Striae   2/ A;B  or  02/ A;B  or  12/ A;B
  (3/) Power & Irregularity – Surface 1     3/ A;B(C) fringes or ____ microns
  (3/) Power & Irregularity – Surface 2 3/ A; B(C) fringes or ____ microns
  (4/)  Tilt (wedge) – Surface 1    __ arc minutes
  (4/)  Tilt (wedge) – Surface 2    __ arc minutes
  (5/)  Scratch/ Dig    __ / __
  (5/) Surface Imperfection Tolerances – Surface 1  Ng x Ag
  (5/) Surface Imperfection Tolerances – Surface 2  Ng x Ag
  (6/) Reference Wavelength     λ = ____nm
  (13/) Transmitted Wavefront   13/ A(B/C); λ = E
  Protection Chamfer  - Surface 1   lens units
  Protection Chamfer  - Surface 2   lens units
  Paint notes   
  Surface texture   __ Å
  Spherical tab should be activated for non-aspheric tolerances 
  Even Aspheric Equation  (this equation is for reference in the document and can appear as an image)   
  Coefficients table    
  Sag Table (increment values by .5mm or an integer)    __mm
  Vertex Radius X, Y, Z position in lens units
  Irregularity (Form Error) ±__
  Slope Error   ____ µm/mm
  Centration/Decentration   ____minutes and/or seconds
       * 
       * 
       * */

    [Serializable]
    public class DrawingSurfaceData
    {
        public DrawingSurfaceData()
        {
        }

        public DrawingSurfaceData(DrawingSurfaceData data)
        {
            if (data != null)
            {
                ClearAperture = data.ClearAperture;
                ClearApertureTolerance = data.ClearApertureTolerance;
                Radius = data.Radius;
                RadiusTolerance = data.RadiusTolerance;
                Conic = data.Conic;
                //FTWPct = data.FTWPct;
                //FTWMin = data.FTWMin;
                //FTWMax = data.FTWMax;
                Coating = data.Coating;
                PowerIrr = data.PowerIrr;
                TiltWedge = data.TiltWedge;
                ImperfectionTolerance = data.ImperfectionTolerance;
                ProtectionChamfer = data.ProtectionChamfer;
                PaintNotes = data.PaintNotes;
                SurfaceTexture = data.SurfaceTexture;
                VertexRadius = data.VertexRadius;
                VertexRadiusTolerance = data.VertexRadiusTolerance;
                IrregularityFormError = data.IrregularityFormError;
                SlopeError = data.SlopeError;
                CentrationDecentration = data.CentrationDecentration;
                AsphereCoefficients = (double[])data.AsphereCoefficients?.Clone();
                SagData = (double[])data.SagData?.Clone();
                SagDataSemiDiameter = data.SagDataSemiDiameter;
                SagTable = (double[,])data.SagTable?.Clone();
                SagTableWidth = data.SagTableWidth;
                SagTableHeight = data.SagTableHeight;
                SurfaceName = data.SurfaceName;
                LaserPowerDamage = data.LaserPowerDamage;
                ReferenceWavelengthNM = data.ReferenceWavelengthNM;
            }
        }

        public double? ClearAperture { get; set; }
        public double? ClearApertureTolerance { get; set; }
        public double? Radius { get; set; }
        public double? RadiusTolerance { get; set; }
        public double? Conic { get; set; }
        [Obsolete]
        public double? FTWPct { get; set; }
        [Obsolete]
        public double? FTWMin { get; set; }
        [Obsolete]
        public double? FTWMax { get; set; }
        public string Coating { get; set; }
        public string PowerIrr { get; set; }
        public double? TiltWedge { get; set; }
        public string ImperfectionTolerance { get; set; }
        public double? ProtectionChamfer { get; set; }
        public string PaintNotes { get; set; }
        public string SurfaceTexture { get; set; }

        // Aspheric Data
        public bool IsAspheric { get { return AsphereCoefficients != null; } }
        public double? VertexRadius { get; set; }
        public double? VertexRadiusTolerance { get; set; }
        public string IrregularityFormError { get; set; }
        public double? SlopeError { get; set; }
        public double? CentrationDecentration { get; set; }
        public double[] AsphereCoefficients { get; set; }
        public double[] SagData { get; set; }
        public double? SagDataSemiDiameter { get; set; }

        // Non-rotationally-symmetric data
        public double[,] SagTable { get; set; }
        public double? SagTableWidth { get; set; }
        public double? SagTableHeight { get; set; }

        public string SurfaceName { get; set; }

        public string SurfaceType { get; set; }

        public bool IsDrawingInputsSupported
        {
            get
            {
                switch (SurfaceType)
                {
                case nameof(Editors.LDE.SurfaceType.Standard):
                case nameof(Editors.LDE.SurfaceType.EvenAspheric):
                    return true;

                default:
                    return false;
                }
            }
        }

        public string LaserPowerDamage { get; set; }
        public double? ReferenceWavelengthNM { get; set; }

        public static string GetInvariantSurfaceTypeName(Editors.LDE.ILDERow surface)
        {
            return surface.Type.ToString();
        }

        public double GetAsphericSagAtRadius(double r)
        {
            double c, c2kp1;
            double[] ac;
            GetAsphereParams(out c, out c2kp1, out ac);
            return CalcAsphericSag(c, c2kp1, ac, r);
        }

        public List<double> GetAsphericSag(IEnumerable<double> radii)
        {
            double c, c2kp1;
            double[] ac;
            GetAsphereParams(out c, out c2kp1, out ac);
            List<double> sag = new List<double>();
            foreach (double r in radii)
                sag.Add(CalcAsphericSag(c, c2kp1, ac, r));
            return sag;
        }

        private void GetAsphereParams(
            out double c,
            out double c2kp1,
            out double[] ac)
        {
            c = this.Radius ?? 0.0;
            if (c != 0.0) c = 1.0 / c;
            double k = this.Conic ?? 0.0;
            c2kp1 = (1.0 + k) * c * c;
            ac = this.AsphereCoefficients;
            if (ac != null && ac[ac.Length - 1] == 0.0)
            {
                // trim trailing zeros
                List<double> coeffs = new List<double>(ac);
                while (coeffs.Count > 0 && coeffs[coeffs.Count - 1] == 0.0)
                {
                    coeffs.RemoveAt(coeffs.Count - 1);
                }
                ac = coeffs.ToArray();
            }
            //if (ac == null)
            //    ac = new double[0];
        }

        public static IEnumerable<double> CreateRange(double rMin, double rMax, int numR)
        {
            double dr = (rMax - rMin) / (numR - 1);
            for (int i = 0; i < numR; ++i)
            {
                yield return (rMin + dr * i);
            }
        }


        private static double CalcAsphericSag(
            double c, 
            double c2kp1, //(1+k)c^2
            double[] ac,
            double r)
        {
            double r2 = r * r;
            double term = 1.0 - c2kp1 * r2;
            if (term < 0.0)
                return Double.NaN;
            double sag = (c * r2) / (1.0 + Math.Sqrt(term));

            if (ac != null)
            {
                double rn = 1.0;
                for (int i = 0; i < ac.Length; ++i)
                {
                    rn *= r;
                    sag += ac[i] * rn;
                }
            }

            return sag;
        }
    }

    [Serializable]
    public class DrawingMaterialData
    {
        public DrawingMaterialData()
        {
        }

        public DrawingMaterialData(DrawingMaterialData material)
        {
            if (material != null)
            {
                Material = material.Material;
                IndexOfRefraction = material.IndexOfRefraction;
                IndexTolerance = material.IndexTolerance;
                AbbeNumber = material.AbbeNumber;
                AbbeTolerance = material.AbbeTolerance;
                Thickness = material.Thickness;
                ThicknessTolerance = material.ThicknessTolerance;
                StressBirefringence = material.StressBirefringence;
                BubblesInclusions = material.BubblesInclusions;
                InhomogeneityStriae = material.InhomogeneityStriae;
                Scratch = material.Scratch;
                Dig = material.Dig;
                ReferenceWL = material.ReferenceWL;
                TransmittedWavefront = material.TransmittedWavefront;
                WavefrontDeformTol = material.WavefrontDeformTol;
                TestWavelengthNM = material.TestWavelengthNM;
            }
        }

        public string Material { get; set; }
        public double? IndexOfRefraction { get; set; }
        public double? IndexTolerance { get; set; }
        public double? AbbeNumber { get; set; }
        public double? AbbeTolerance { get; set; }
        public double? Thickness { get; set; }
        public double? ThicknessTolerance { get; set; }
        public double? StressBirefringence { get; set; }
        public string BubblesInclusions { get; set; }
        public string InhomogeneityStriae { get; set; }
        public double? Scratch { get; set; }
        public double? Dig { get; set; }
        public double? ReferenceWL { get; set; }
        public string TransmittedWavefront { get; set; }
        public string WavefrontDeformTol { get; set; }
        public double? TestWavelengthNM { get; set; }

    }

    [Serializable]
    public class DrawingCementData
    {
        public DrawingCementData()
        {
        }

        public DrawingCementData(DrawingCementData cement)
        {
            if (cement != null)
            {
                CementType = cement.CementType;
                CementWedge = cement.CementWedge;
                SurfaceImpTol = cement.SurfaceImpTol;
                TransmitWavefront = cement.TransmitWavefront;
                RotationalInvariant = cement.RotationalInvariant;
                LocalizedImpTol = cement.LocalizedImpTol;
            }
        }

        public string CementType { get; set; }
        public double? CementWedge { get; set; }
        public double? SurfaceImpTol { get; set; }
        public double? TransmitWavefront { get; set; }
        public double? RotationalInvariant { get; set; }
        public double? LocalizedImpTol { get; set; }
    }

    [Serializable]
    public class DrawingComponentData
    {
        private readonly bool isSequentialMode;

        public int FrontSurfaceNumber { get; set; }
        public int BackSurfaceNumber { get; set; }
        public int ObjectNumber { get; set; }
        public DrawingSurfaceData FrontSurface { get; set; }
        public DrawingSurfaceData BackSurface { get; set; }
        public DrawingMaterialData Material { get; set; }
        // Singlet = 0
        // Doublet = 1
        // Triplet = 2,
        // ...
        public int ElementType { get; set; }
        public bool IsLeadElement { get; set; }
        public DrawingCementData CementData { get; set; }

        public DrawingComponentData(bool isSequentialMode)
        {
            this.isSequentialMode = isSequentialMode;

            ElementType = 0;
            IsLeadElement = true;
            CementData = new DrawingCementData();
        }

        public DrawingComponentData(DrawingComponentData component, bool isSequentialMode)
        {
            this.isSequentialMode = isSequentialMode;

            if (component != null)
            {
                FrontSurfaceNumber = component.FrontSurfaceNumber;
                BackSurfaceNumber = component.BackSurfaceNumber;
                ObjectNumber = component.ObjectNumber;
                FrontSurface = new DrawingSurfaceData(component.FrontSurface);
                BackSurface = new DrawingSurfaceData(component.BackSurface);
                Material = new DrawingMaterialData(component.Material);
                ElementType = component.ElementType;
                IsLeadElement = component.IsLeadElement;
                CementData = new DrawingCementData(component.CementData);
            }
        }

        public bool IsDrawingInputsSupportedForBackSurface => !isSequentialMode || BackSurface.IsDrawingInputsSupported;

        public bool IsDrawingInputsSupportedForFrontSurface => !isSequentialMode || FrontSurface.IsDrawingInputsSupported;
    }

    public enum LMXF_Platforms
    {
        Unknown = 0,
        SolidWorks = 1,
        Creo = 2,
    }

    [Serializable]
    public class LMXF_GeneralSettings
    {
        public bool IsEditable { get; set; }
        public bool ConvertStopToNSCAperture { get; set; }
        public double StopMechanicalHalfWidth { get; set; }
        public bool IncludeScatter { get; set; }
        public bool IncludeSplitting { get; set; }
        public int Precision { get; set; }
        public LMXF_Platforms TargetPlatform { get; set; }
        public string Notes { get; set; }     
    }

    [Serializable]
    public struct LMXF_OpticalAxisSurfaceData
    {
        // This is only accessible through configuration-specific data,
        // so it is (implicitly) already associated with a configuration.
        //public int Configuration;
        public int SurfaceNumber { get; set; }
        public bool AreCoordinatesGlobal { get; set; }
        public double X { get; set; }
        public double Y { get; set; }
        public double Z { get; set; }
        public double Nx { get; set; }
        public double Ny { get; set; }
        public double Nz { get; set; }
        public int ErrorCode { get; set; }
        public int VignetteCode { get; set; }
    }

    [Serializable]
    public class LMXF_SeqConfigData
    {
        public int OriginalConfigNumber { get; set; }
        public int[] FieldNumbers { get; set; }
        public string ZrdFileKey { get; set; }
        public string CrsFileKey { get; set; }
        public string FullFieldKey { get; set; }

        public double[] SeqSpotSizes { get; set; }
        public double[] NscSpotSizes { get; set; }
        public double[,] SeqMtfData { get; set; }
        public double[,] NscMtfData { get; set; }

        public string[] SeqSpotImageKeys { get; set; }
        public string[] NscSpotImageKeys { get; set; }
        public string[] DetectorDataKeys { get; set; }

        public int[] SourceObjects { get; set; }
        public int[] DetectorObjects { get; set; }
        public int[] ComponentSurfaces { get; set; }

        public double[,] ComponentPositions { get; set; }
        public int[][] IntendedPaths { get; set; }
        public double[] IntendedPathFlux { get; set; }
        //public double[] UnintendedPathFlux { get; set; }
        public double TotalFlux { get; set; }
        public LMXF_OpticalAxisSurfaceData[] OpticalAxisData { get; set; }
    }

    [Serializable]
    public class LMXF_SeqData
    {
        public static readonly double DefaultCriticalRayAngleTolerance = 0.001;
        public static readonly double DefaultCriticalRayPositionTolerance = 0.001;

        public string SEQFileName { get; set; }
        public string SEQFileKey { get; set; }
        public double DeltaSpotUM { get; set; }
        public double DeltaSpotPct { get; set; }
        public bool DeltaSpotUsePct { get; set; }
        public double DeltaBeamClipPct { get; set; }
        public double DeltaImgContPct { get; set; }
        public double MaxMtfFreq { get; set; }

        public LMXF_SeqConfigData[] ConfigData { get; set; }

        public bool IsCopiedData { get; set; }

        public double CriticalRayAngleTolerance { get; set; }

        public double CriticalRayPositionTolerance { get; set; }

        public int NumberOfAnalysisRays { get; set; }
    }

    [Serializable]
    public class LMXF_NscSourceData
    {
        public double[] NscSpotSizes { get; set; }
        public double[,] NscMtfData { get; set; }

        public string[] NscSpotImageKeys { get; set; }
        public string[] DetectorDataKeys { get; set; }

        public int[] SourceObjects { get; set; }
        public int[] DetectorObjects { get; set; }

        public int[][] IntendedPaths { get; set; }
        public double[] IntendedPathFlux { get; set; }
        public double TotalFlux { get; set; }
    }

    [Serializable]
    public class LMXF_NscConfigData
    {
        public int OriginalConfigNumber { get; set; }
        public int[] ComponentObjects { get; set; }
        public DrawingComponentData[] DrawingData { get; set; }
        public double[,] ComponentPositions { get; set; }
        // This is only generated when the file originates as NSC
        public LMXF_NscSourceData NscSourceData { get; set; }
    }

    [Serializable]
    public class LMXF_NscData
    {
        public bool IsNscSource { get; set; }
        public string NSCFileName { get; set; }
        public string NSCFileKey { get; set; }
        public LMXF_NscConfigData[] ConfigData { get; set; }
        public int StopObjectNumber { get; set; }
        public int StopObjectFace { get; set; }
    }

    public class LMXF_Wrapper
    {
        public const string GeneralSettingsKey = "GeneralSettings";
        public const string SeqDataKey = "SeqData";
        public const string NscDataKey = "NscData";
        public const string MetadataIdKey = "OB_GUID";

        private IDataDictionary DataFile;

        public LMXF_Wrapper(IDataDictionary dataFile)
        {
            this.DataFile = dataFile;
        }

        public LMXF_GeneralSettings GetGeneralSettings()
        {
            var entry = DataFile.GetEntry(GeneralSettingsKey);
            if (entry == null)
                return null;
            return entry.GetSerializableValue() as LMXF_GeneralSettings;
        }

        public LMXF_SeqData GetSeqData()
        {
            var entry = DataFile.GetEntry(SeqDataKey);
            if (entry == null)
                return null;
            return entry.GetSerializableValue() as LMXF_SeqData;
        }

        public LMXF_NscData GetNscData()
        {
            var entry = DataFile.GetEntry(NscDataKey);
            if (entry == null)
                return null;
            return entry.GetSerializableValue() as LMXF_NscData;
        }

        public void SaveSeqZAR(LMXF_SeqData seqData, string fileName)
        {
            var entry = DataFile.GetEntry(seqData.SEQFileKey);
            entry.GetFile(fileName);
        }

        public void SaveConfigZRD(LMXF_SeqConfigData cfgData, string fileName)
        {
            var entry = DataFile.GetEntry(cfgData.ZrdFileKey);
            entry.GetFile(fileName);
        }

        public void SaveConfigCRS(LMXF_SeqConfigData cfgData, string fileName)
        {
            var entry = DataFile.GetEntry(cfgData.CrsFileKey);
            entry.GetFile(fileName);
        }

        public void SaveConfigDetector(LMXF_SeqConfigData cfgData, int fieldIdx, string fileName)
        {
            var entry = DataFile.GetEntry(cfgData.DetectorDataKeys[fieldIdx]);
            entry.GetFile(fileName);
        }

        public void SaveConfigFullFieldDetector(LMXF_SeqConfigData cfgData, string fileName)
        {
            var entry = DataFile.GetEntry(cfgData.FullFieldKey);
            entry?.GetFile(fileName);
        }

        public void SaveSpotFile(LMXF_SeqConfigData cfgData, bool seqFile, int fieldIdx, string fileName)
        {
            string key = seqFile ? cfgData.SeqSpotImageKeys[fieldIdx] : cfgData.NscSpotImageKeys[fieldIdx];
            var entry = DataFile.GetEntry(key);
            entry.GetFile(fileName);
        }

        public bool SaveNscZAR(LMXF_NscData nscData, string fileName)
        {
            IDataEntry entry = null;
            if (nscData != null)
                entry = DataFile.GetEntry(nscData.NSCFileKey);
            if (entry == null)
                entry = DataFile.GetEntry("NSC_ZAR");

            if (entry == null)
            {
                return false;
            }
            else
            {
                entry.GetFile(fileName);
                return true;
            }
        }

    }
}

Connect with Ansys