Source code for jitxlib.symbols.diode.led
"""
LED and PhotoDiode symbols for JITX Standard Library
This module provides LED and PhotoDiode symbol definitions with arrow indicators.
"""
from __future__ import annotations
from dataclasses import dataclass
from typing import TYPE_CHECKING, override
from ..arrow import Arrow, ArrowConfigurable
from .diode import DiodeConfig, DiodeSymbol
if TYPE_CHECKING:
from ..context import SymbolStyleContext
# LED/PhotoDiode constants
DEF_LED_ARROW_MARGIN = 0.3
DEF_LED_ARROW_PITCH = 0.4
DEF_LED_ARROW_ANGLE = 30.0
DEF_PHOTODIODE_ARROW_ANGLE = 150.0
[docs]
@dataclass
class LEDConfig(DiodeConfig, ArrowConfigurable):
"""
Configuration for LED symbols
Extends DiodeConfig with arrow parameters for light emission indicators.
"""
arrow_margin: float = DEF_LED_ARROW_MARGIN
"""Distance from diode body to arrows"""
arrow_pitch: float = DEF_LED_ARROW_PITCH
"""Vertical spacing between arrows"""
arrow_angle: float = DEF_LED_ARROW_ANGLE
"""Angle of outgoing light arrows in degrees"""
[docs]
class LEDSymbol(DiodeSymbol[LEDConfig]):
"""
LED symbol with arrows indicating light emission.
The LED symbol consists of a standard diode with two arrows
pointing outward to indicate light emission.
Pins: 'a' (anode), 'c' (cathode)
"""
arrows: tuple[Arrow, Arrow]
@override
def _symbol_style_config(
self, context: SymbolStyleContext | None = None
) -> LEDConfig:
"""Symbol style config for LED symbol."""
if context is None:
return LEDConfig()
return context.led_config
@override
def _build_diode_glyphs(self) -> None:
"""Build LED glyphs including arrows."""
super()._build_diode_glyphs()
self._build_arrows()
def _build_arrows(self) -> None:
"""Build the light emission arrows."""
bw2 = self.body_width / 2.0
h = self._get_body_height() / 2.0
angle = self.arrow_angle
arrow_config = self.config.get_arrow_config()
if arrow_config is None:
from ..arrow import ArrowConfig
# Use diode's line width for arrows to ensure consistency
arrow_config = ArrowConfig(line_width=self.line_width)
shaft = arrow_config.shaft_length
# Position arrows to the left of the body
# X position based on shaft length (not margin)
x_off = -(bw2 + 1.2 * shaft)
# Y positions: first arrow at h/-2, second arrow offset by y_adj
y_off = h / -2.0
y_adj = 1.5 * y_off
self.arrows = (
Arrow((x_off, y_off), angle, arrow_config),
Arrow((x_off, y_off + y_adj), angle, arrow_config),
)
@property
def arrow_margin(self) -> float:
"""See :attr:`~.LEDConfig.arrow_margin`."""
return self.config.arrow_margin
@property
def arrow_pitch(self) -> float:
"""See :attr:`~.LEDConfig.arrow_pitch`."""
return self.config.arrow_pitch
@property
def arrow_angle(self) -> float:
"""See :attr:`~.LEDConfig.arrow_angle`."""
return self.config.arrow_angle
[docs]
@dataclass
class PhotoDiodeConfig(DiodeConfig, ArrowConfigurable):
"""
Configuration for PhotoDiode symbols
Extends DiodeConfig with arrow parameters for light absorption indicators.
"""
arrow_margin: float = DEF_LED_ARROW_MARGIN
"""Distance from diode body to arrows"""
arrow_pitch: float = DEF_LED_ARROW_PITCH
"""Vertical spacing between arrows"""
arrow_angle: float = DEF_PHOTODIODE_ARROW_ANGLE
"""Angle of incoming light arrows in degrees (pointing toward diode)"""
[docs]
class PhotoDiodeSymbol(DiodeSymbol[PhotoDiodeConfig]):
"""
PhotoDiode symbol with arrows indicating light absorption.
The PhotoDiode symbol consists of a standard diode with two arrows
pointing inward to indicate light absorption.
Pins: 'a' (anode), 'c' (cathode)
"""
arrows: tuple[Arrow, Arrow]
@override
def _symbol_style_config(
self, context: SymbolStyleContext | None = None
) -> PhotoDiodeConfig:
"""Symbol style config for PhotoDiode symbol."""
if context is None:
return PhotoDiodeConfig()
return context.photo_diode_config
@override
def _build_diode_glyphs(self) -> None:
"""Build PhotoDiode glyphs including arrows."""
super()._build_diode_glyphs()
self._build_arrows()
def _build_arrows(self) -> None:
"""Build the light absorption arrows."""
bw2 = self.body_width / 2.0
h = self._get_body_height() / 2.0
angle = self.arrow_angle
arrow_config = self.config.get_arrow_config()
if arrow_config is None:
from ..arrow import ArrowConfig
# Use diode's line width for arrows to ensure consistency
arrow_config = ArrowConfig(line_width=self.line_width)
# Position arrows to the left of the body, pointing inward
x_off = -(1.2 * bw2)
# Y positions: arrows positioned symmetrically with adjustment
y_off = h / -2.0
y_adj = 0.3 * y_off
self.arrows = (
Arrow((x_off, y_adj + y_off), angle, arrow_config),
Arrow((x_off, y_adj - y_off), angle, arrow_config),
)
@property
def arrow_margin(self) -> float:
"""See :attr:`~.PhotoDiodeConfig.arrow_margin`."""
return self.config.arrow_margin
@property
def arrow_pitch(self) -> float:
"""See :attr:`~.PhotoDiodeConfig.arrow_pitch`."""
return self.config.arrow_pitch
@property
def arrow_angle(self) -> float:
"""See :attr:`~.PhotoDiodeConfig.arrow_angle`."""
return self.config.arrow_angle