Source code for rayoptics.mpl.interactivelayout

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright © 2019 Michael J. Hayford
""" Interactive layout figure with paraxial editing

.. Created on Thu Mar 14 10:20:33 2019

.. codeauthor: Michael J. Hayford
"""

import numpy as np

import rayoptics
from rayoptics.mpl.interactivefigure import InteractiveFigure
from rayoptics.gui.util import bbox_from_poly, scale_bounds


[docs] class InteractiveLayout(InteractiveFigure): """ Editable version of optical system layout, aka Live Layout Attributes: opt_model: parent optical model refresh_gui: function to be called on refresh_gui event offset_factor: how much to draw rays before first surface do_draw_parts: if True, draw parts that pass the part_filter part_filter: include only parts with the specified tags do_draw_rays: if True, draw edge rays do_draw_beams: draw a filled in area for each field point do_draw_edge_rays: draw the boundary rays for each field point do_draw_ray_fans: draw ray fans from each field point num_rays_in_fan: number of rays to include in ray fans (default: 11) clip_rays: if True, rays clipping by apertures is checked do_paraxial_layout: if True, draw editable paraxial axial and chief ray entity_factory_list: list of drawable entity factories. Allows new drawables to be added to the layout. """ def __init__(self, opt_model, refresh_gui=None, offset_factor=0.05, do_draw_parts=True, part_filter='#element#dummyifc#space#airgap', do_draw_rays=True, do_draw_beams=True, do_draw_edge_rays=True, do_draw_ray_fans=False, num_rays_in_fan=11, clip_rays=False, do_paraxial_layout=False, entity_factory_list=None, **kwargs): self.refresh_gui = refresh_gui is_dark = kwargs['is_dark'] if 'is_dark' in kwargs else False self.layout = rayoptics.elem.layout.LensLayout(opt_model, is_dark=is_dark) self.do_draw_parts = do_draw_parts self.part_filter = part_filter if do_draw_rays: self.do_draw_beams = do_draw_beams self.do_draw_edge_rays = do_draw_edge_rays else: self.do_draw_beams = False self.do_draw_edge_rays = False self.do_draw_ray_fans = do_draw_ray_fans self.num_rays_in_fan = num_rays_in_fan self.do_paraxial_layout = do_paraxial_layout self.clip_rays = clip_rays self.offset_factor = offset_factor if entity_factory_list is None: self.entity_factory_list = [] else: self.entity_factory_list = entity_factory_list super().__init__(**kwargs)
[docs] def sync_light_or_dark(self, is_dark, **kwargs): self.layout.sync_light_or_dark(is_dark) super().sync_light_or_dark(is_dark, **kwargs)
[docs] def update_data(self, **kwargs): self.artists = [] concat_bbox = [] layout = self.layout build = kwargs.get('build', 'rebuild') if self.do_draw_parts: if build == 'rebuild': self.ele_shapes = [] e_nodes = layout.renderable_pt_nodes(part_filter=self.part_filter) e_node_set = {e.id for e in e_nodes} ele_shapes_set = {ele.e for ele in self.ele_shapes} to_remove = list(ele_shapes_set - e_node_set) self.ele_shapes = [ele for ele in self.ele_shapes if ele.e not in to_remove] to_add = list(e_node_set - ele_shapes_set) for e in to_add: ele = layout.create_oe(e) self.ele_shapes.append(ele) self.ele_bbox = self.update_patches(self.ele_shapes) concat_bbox.append(self.ele_bbox) # if self.do_draw_beams # or self.do_draw_edge_rays # or self.do_draw_ray_fans: self.sl_so = layout.system_length(self.ele_bbox, offset_factor=self.offset_factor) system_length, start_offset = self.sl_so if self.do_draw_beams or self.do_draw_edge_rays: if build == 'rebuild': self.ray_shapes = layout.create_ray_entities( self, start_offset, clip_rays=self.clip_rays) self.ray_bbox = self.update_patches(self.ray_shapes) if self.do_draw_ray_fans: if build == 'rebuild': self.rayfan_shapes = layout.create_ray_fan_entities( self, start_offset, num_rays=self.num_rays_in_fan, clip_rays=self.clip_rays) self.rayfan_bbox = self.update_patches(self.rayfan_shapes) if self.do_paraxial_layout: if build == 'rebuild': self.parax_shapes = layout.create_paraxial_ray_entities(self) self.parax_bbox = self.update_patches(self.parax_shapes) for ef in self.entity_factory_list: # each entity factory is a tuple of callable, args, and kwargs # the callable signature includes the current figure. if build == 'rebuild': ef_fct, ef_args, ef_kwargs = ef self.ef_shapes = ef_fct(self, *ef_args, **ef_kwargs) ef_bbox = self.update_patches(self.ef_shapes) sys_bbox = np.concatenate(concat_bbox) self.sys_bbox = scale_bounds(bbox_from_poly(sys_bbox), self.offset_factor) return self
[docs] def action_complete(self): super().action_complete() self.do_action = self.do_shape_action
[docs] def fit_axis_limits(self): return self.sys_bbox