Skip to content

Add optical component abstraction layer to Optic class #490

@RFerraciniAlves

Description

@RFerraciniAlves

Checklist

  • I have searched the existing issues and discussions for a similar question or feature request.
  • I have read the documentation and tried to find an answer there.
  • I am using the latest version of Optiland.
  • I have included all necessary context.

Feature Request

This feature request description is co-authored with copilot.

Is your feature request related to a problem? Please describe.

Currently, optiland requires users to build optical systems by manually defining and managing individual surfaces with explicit indexing. While this low-level approach provides fine-grained control, it creates several challenges:

  • Verbose and error-prone code: Defining a simple lens requires manually creating two surfaces with correct indices and managing the relationship between them
  • Reduced code readability: It's not immediately clear what optical elements a system contains by looking at surface definitions
  • No abstraction for complete optical elements: Common components like doublets, mirrors, or prisms must be manually constructed from raw surfaces every time
  • Harder positioning and transformations of surface groups: Requires adding coordinate breaks
  • Cumbersome index manipulation: Need to keep track manually of surface indexes.
  • No edge surfaces definition: This could make it less straight forward to implement non-sequential ray tracing.

Describe the solution you'd like

Introduce a component-based API that provides high-level abstractions for complete optical elements (lenses, mirrors, doublets, triplets, etc.) alongside the existing surface-based API. This new system would:

Core Architecture:

  • OpticalComponent base class: Foundation for all optical components with local coordinate systems for 3D positioning and rotation

  • Component library: Pre-built implementations of common optical elements (Singlet/Lens, Doublet, Triplet, Mirror, BeamSplitter, Window, Prism, Grating, Eye, ...)

  • ComponentGroup manager: Handles collections of components and converts them to surface sequences for ray tracing
    Seamless integration: Should work alongside existing surface-based API with no breaking changes.

Key Features:

  • Intuitive design workflow: Work with complete optical elements instead of raw surfaces
  • Automatic index management: No need to manually track surface indices ( for sequential we can build the
  • 3D coordinate systems: Each component has position and rotation for easy placement
  • Encapsulation: Components internally manage their surfaces and relationships
  • Composition: Complex components (like Doublet) composed from simpler ones (Singlets)
  • Backward compatible: Existing surface-based code continues to work unchanged
  • Example API:
from optiland import optic
from optiland.components import Lens, Doublet, Mirror

# Create optical system
system = optic.Optic(name="Camera Lens")

# Add components with intuitive parameters
lens1 = Lens(
    radius1=50.0,      # Front surface radius
    radius2=-50.0,     # Back surface radius
    thickness=5.0,     # Center thickness
    material="N-BK7",  # Glass material
    diameter=25.0,     # Clear aperture
    position=(0, 0, 0) # 3D position
)

# Add achromatic doublet
doublet = Doublet(
    radius1=62.0,
    radius2=-45.0,
    radius3=-129.0,
    thickness1=6.0,
    thickness2=2.5,
    material1="N-BK7",  # Crown glass
    material2="N-SF5",  # Flint glass
    diameter=25.4,
    position=(0, 0, 10)  # 10mm after lens1
)

# Add folding mirror
mirror = Mirror(
    radius=100.0,
    diameter=30.0,
    position=(0, 0, 50),
    rotation=(0, 45, 0)  # 45° tilt
)

# Add to system (no index management!)
system.add_component(lens1)
system.add_component(doublet)
system.add_component(mirror)

# Configure and trace as usual
system.set_aperture(aperture_type="EPD", value=20.0)
system.set_field_type(field_type="angle")
system.add_field(y=0)
system.add_wavelength(value=0.588, is_primary=True)

# Surfaces automatically generated for ray tracing
system.build_surface_group_from_components()

# Access component properties
print(f"Lens focal length: {lens1.focal_length:.2f} mm")

Describe alternatives you've considered

Keep only surface-based API

Additional context

  • Backward compatibility: The surface-based API remains unchanged and fully supported. Users can gradually adopt components or mix both approaches.
  • Easier implementation of features such as ISO 10110 Drawing Generator #458, and any other operation that targets optical components not surfaces.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions