padne.ui

Attributes

Classes

BaseSpatialIndex

VertexSpatialIndex

Spatial index for fast vertex value lookups within a layer.

FaceSpatialIndex

Spatial index for fast face value lookups within a layer.

BaseTool

Helper class that provides a standard way to create an ABC using

PanTool

Helper class that provides a standard way to create an ABC using

SetMinValueTool

Helper class that provides a standard way to create an ABC using

SetMaxValueTool

Helper class that provides a standard way to create an ABC using

ToolManager

AppToolBar

ShaderProgram

RenderedMesh

RenderedPoints

SliderScale

Maps a 0..1 slider fraction to a value in [lo, hi] and back.

LinearScale

Maps a 0..1 slider fraction to a value in [lo, hi] and back.

LogScale

Fraction 0 is exactly lo, (0, 1] spans decades decades below hi

ColorScaleState

Snapshot of a rendering mode's color scale, as shown by ColorScaleWidget.

MeshViewer

EditableValueLabel

A QLabel that turns into a QLineEdit on double-click for in-place value editing.

ColorScaleWidget

Color scale with min/max sliders and a percentile cap toggle.

PreparedUI

GL-free UI preparation for a solution (see prepare_ui_data).

MainWindow

Functions

prepare_ui_data(→ PreparedUI)

Build the GL-free UI data for solution: per-mode spatial indices and the

configure_opengl(→ None)

Configure OpenGL settings for the application.

main(→ int)

Main entry point for the UI application.

Module Contents

padne.ui.log[source]
padne.ui.VERTEX_SHADER_MESH = Multiline-String[source]
Show Value
"""
#version 330 core
layout(location = 0) in vec2 position;
layout(location = 1) in float color;
out float frag_value;
uniform mat4 mvp;

void main() {
    gl_Position = mvp * vec4(position, 0.0, 1.0);
    frag_value = color;
}
"""
padne.ui.FRAGMENT_SHADER_MESH = Multiline-String[source]
Show Value
"""
#version 330 core
in float frag_value;
out vec4 out_color;

#define COLOR_COUNT 256
uniform float v_max = 1.0;
uniform float v_min = 0.0;
uniform vec3 color_map[COLOR_COUNT];

void main() {
    float t = (frag_value - v_min) / (v_max - v_min);
    float rescaled = t * COLOR_COUNT;
    int idx = clamp(int(rescaled), 0, COLOR_COUNT - 1);

    out_color = vec4(color_map[idx], 1.0);
}
"""
padne.ui.VERTEX_SHADER_DISCONNECTED = Multiline-String[source]
Show Value
"""
#version 330 core
layout(location = 0) in vec2 position;
layout(location = 1) in float color;  // We still have the color attribute but ignore it
uniform mat4 mvp;

void main() {
    gl_Position = mvp * vec4(position, 0.0, 1.0);
}
"""
padne.ui.FRAGMENT_SHADER_DISCONNECTED = Multiline-String[source]
Show Value
"""
#version 330 core
out vec4 out_color;

void main() {
    // Render disconnected copper in a subdued gray
    out_color = vec4(0.1, 0.1, 0.1, 1.0);
}
"""
padne.ui.VERTEX_SHADER_EDGES = Multiline-String[source]
Show Value
"""
#version 330 core
layout(location = 0) in vec2 position;
layout(location = 1) in vec3 color;
out vec3 frag_color;
uniform mat4 mvp;

void main() {
    gl_Position = mvp * vec4(position, 0.0, 1.0);
    frag_color = color;
}
"""
padne.ui.FRAGMENT_SHADER_EDGES = Multiline-String[source]
Show Value
"""
#version 330 core
in vec3 frag_color;
out vec4 out_color;

void main() {
    out_color = vec4(frag_color, 1.0);
}
"""
padne.ui.VERTEX_SHADER_POINTS = Multiline-String[source]
Show Value
"""
#version 330 core
layout(location = 0) in vec2 position;
layout(location = 1) in vec3 vertex_color;
out vec3 frag_color;
uniform mat4 mvp;
uniform float point_size = 5.0;

void main() {
    gl_Position = mvp * vec4(position, 0.0, 1.0);
    gl_PointSize = point_size;
    frag_color = vertex_color; // Pass color to fragment shader
}
"""
padne.ui.FRAGMENT_SHADER_POINTS = Multiline-String[source]
Show Value
"""
#version 330 core
in vec3 frag_color; // Input color from vertex shader
out vec4 out_color;

void main() {
    out_color = vec4(frag_color, 1.0);
}
"""
class padne.ui.BaseSpatialIndex[source]
tree: scipy.spatial.cKDTree | None[source]
values: numpy.ndarray[source]
shape: shapely.geometry.MultiPolygon[source]
classmethod from_layer_data(layer: padne.solver.problem.Layer, layer_solution: padne.solver.LayerSolution, value_transform: Callable[[numpy.ndarray], numpy.ndarray] | None = None) → BaseSpatialIndex[source]
query_nearest(x: float, y: float) → float | None[source]

Find nearest value to given coordinates.

class padne.ui.VertexSpatialIndex[source]

Bases: BaseSpatialIndex

Spatial index for fast vertex value lookups within a layer.

class padne.ui.FaceSpatialIndex[source]

Bases: BaseSpatialIndex

Spatial index for fast face value lookups within a layer.

class padne.ui.BaseTool(mesh_viewer: MeshViewer, tool_manager: ToolManager)[source]

Bases: abc.ABC

Helper class that provides a standard way to create an ABC using inheritance.

mesh_viewer[source]
tool_manager[source]
property name: str[source]
Abstractmethod:

Returns the display name of the tool.

property status_tip: str[source]
Abstractmethod:

Returns the status tip for the tool.

property shortcut: tuple[PySide6.QtCore.Qt.Key, PySide6.QtCore.Qt.KeyboardModifier] | None[source]
on_shortcut_press(world_point: padne.mesh.Point)[source]

Handles a shortcut press event.

on_mesh_click(world_point: padne.mesh.Point, event: PySide6.QtGui.QMouseEvent)[source]

Handles a click event on the mesh.

on_screen_drag(dx: float, dy: float, event: PySide6.QtGui.QMouseEvent)[source]

Handles a screen drag event.

class padne.ui.PanTool(mesh_viewer: MeshViewer, tool_manager: ToolManager)[source]

Bases: BaseTool

Helper class that provides a standard way to create an ABC using inheritance.

property name: str[source]

Returns the display name of the tool.

property status_tip: str[source]

Returns the status tip for the tool.

on_screen_drag(dx: float, dy: float, event: PySide6.QtGui.QMouseEvent)[source]

Handles a screen drag event.

class padne.ui.SetMinValueTool(mesh_viewer: MeshViewer, tool_manager: ToolManager)[source]

Bases: PanTool

Helper class that provides a standard way to create an ABC using inheritance.

property name: str[source]

Returns the display name of the tool.

property status_tip: str[source]

Returns the status tip for the tool.

property shortcut[source]
on_mesh_click(world_point: padne.mesh.Point, event: PySide6.QtGui.QMouseEvent)[source]

Handles a click event on the mesh.

on_shortcut_press(world_point: padne.mesh.Point)[source]

Handles a shortcut press event.

class padne.ui.SetMaxValueTool(mesh_viewer: MeshViewer, tool_manager: ToolManager)[source]

Bases: PanTool

Helper class that provides a standard way to create an ABC using inheritance.

property name: str[source]

Returns the display name of the tool.

property status_tip: str[source]

Returns the status tip for the tool.

property shortcut[source]
on_mesh_click(world_point: padne.mesh.Point, event: PySide6.QtGui.QMouseEvent)[source]

Handles a click event on the mesh.

on_shortcut_press(world_point: padne.mesh.Point)[source]

Handles a shortcut press event.

class padne.ui.ToolManager(mesh_viewer: MeshViewer, parent=None)[source]

Bases: PySide6.QtCore.QObject

mesh_viewer[source]
available_tools: list[BaseTool][source]
active_tool: BaseTool[source]
activate_tool(tool_to_activate: BaseTool)[source]
handle_mesh_click(world_point: padne.mesh.Point, event: PySide6.QtGui.QMouseEvent)[source]
handle_screen_drag(dx: float, dy: float, event: PySide6.QtGui.QMouseEvent)[source]
handle_key_press_in_mesh(world_point: padne.mesh.Point, key: PySide6.QtCore.Qt.Key, modifiers: PySide6.QtCore.Qt.KeyboardModifiers)[source]
class padne.ui.AppToolBar(tool_manager: ToolManager, mesh_viewer: MeshViewer, parent=None)[source]

Bases: PySide6.QtWidgets.QToolBar

tool_manager[source]
mesh_viewer[source]
updateLayerSelectionMenu(layer_names: list[str])[source]
updateActiveLayerInMenu(active_layer_name: str)[source]
updateActiveModeInMenu(active_mode_name: str)[source]

Update which mode action is checked.

class padne.ui.ShaderProgram[source]
shader_program: PySide6.QtOpenGL.QOpenGLShaderProgram[source]
classmethod from_source(vertex_source, fragment_source)[source]
set_mvp(mvp: numpy.ndarray)[source]
use()[source]
class padne.ui.RenderedMesh[source]
vao_triangles: int[source]
triangle_count: int[source]
vao_edges: int[source]
edge_count: int[source]
vao_boundary: int[source]
boundary_count: int[source]
class PreparedData[source]
triangle_vertices: numpy.ndarray[numpy.float32][source]
triangle_colors: numpy.ndarray[numpy.float32][source]
edge_vertices: numpy.ndarray[numpy.float32][source]
edge_colors: numpy.ndarray[numpy.float32][source]
boundary_vertices: numpy.ndarray[numpy.float32][source]
boundary_colors: numpy.ndarray[numpy.float32][source]
classmethod from_prepared_data(data: RenderedMesh) → RenderedMesh[source]
class PreparedGeometry[source]

Read-only CPU geometry shared by the two field rendering modes.

triangles: numpy.ndarray[source]
triangle_vertices: numpy.ndarray[source]
edge_vertices: numpy.ndarray[source]
edge_colors: numpy.ndarray[source]
boundary_vertices: numpy.ndarray[source]
boundary_colors: numpy.ndarray[source]
with_colors(colors: numpy.ndarray) → RenderedMesh[source]
classmethod prepare_geometry(msh: padne.mesh.Mesh) → RenderedMesh[source]

Extract face-ordered geometry without Python half-edge traversal.

Interior edges deliberately occur twice, matching the original drawing order. Boundary edges include both the exterior and any hole rims. Native extraction releases the GIL; each task owns its output arrays.

classmethod prepare_zero_form(msh: padne.mesh.Mesh, values: padne.mesh.ZeroForm, geometry: RenderedMesh | None = None) → RenderedMesh[source]
classmethod prepare_two_form(msh: padne.mesh.Mesh, values: padne.mesh.TwoForm, geometry: RenderedMesh | None = None) → RenderedMesh[source]
render_triangles()[source]
render_edges()[source]
render_boundary()[source]
classmethod prepare_mesh(msh: padne.mesh.Mesh, geometry: RenderedMesh | None = None) → RenderedMesh[source]

Prepare disconnected copper, with a zero-valued field.

class padne.ui.RenderedPoints[source]
vao_points: int[source]
point_count: int[source]
classmethod from_points(points_data: list[tuple[tuple[float, float], tuple[float, float, float]]])[source]
render()[source]
class padne.ui.SliderScale[source]

Bases: abc.ABC

Maps a 0..1 slider fraction to a value in [lo, hi] and back.

abstractmethod value_at(fraction: float, lo: float, hi: float) → float[source]
abstractmethod fraction_of(value: float, lo: float, hi: float) → float[source]
class padne.ui.LinearScale[source]

Bases: SliderScale

Maps a 0..1 slider fraction to a value in [lo, hi] and back.

value_at(fraction: float, lo: float, hi: float) → float[source]
fraction_of(value: float, lo: float, hi: float) → float[source]
class padne.ui.LogScale[source]

Bases: SliderScale

Fraction 0 is exactly lo, (0, 1] spans decades decades below hi logarithmically, so one slider step is a constant ratio.

decades: float = 4.0[source]
value_at(fraction: float, lo: float, hi: float) → float[source]
fraction_of(value: float, lo: float, hi: float) → float[source]
class padne.ui.ColorScaleState[source]

Snapshot of a rendering mode’s color scale, as shown by ColorScaleWidget.

min_value: float[source]
max_value: float[source]
slider_lo: float[source]
slider_hi: float[source]
slider_scale: SliderScale[source]
capped: bool[source]
cap_percentile: float[source]
unit: str[source]
color_map: padne.colormaps.UniformColorMap[source]
class padne.ui.MeshViewer(parent=None)[source]

Bases: PySide6.QtOpenGLWidgets.QOpenGLWidget

class BaseRenderingMode[source]
unit: str[source]
name: str[source]
color_map: padne.colormaps.UniformColorMap[source]
slider_scale: ClassVar[SliderScale][source]
cap_percentile: ClassVar[float] = 99.9[source]
min_value: float = 0.0[source]
max_value: float = 1.0[source]
capped: bool = False[source]
data_range: tuple[float, float] = (0.0, 1.0)[source]
percentile_max: float = 1.0[source]
solution: padne.solver.Solution | None = None[source]
spatial_indices: dict[str, BaseSpatialIndex][source]
rendered_meshes: dict[str, list[RenderedMesh]][source]
disconnected_rendered_meshes: dict[str, list[RenderedMesh]][source]
property slider_range: tuple[float, float][source]
autoscale() → None[source]

Set the color range to the whole slider range.

set_min(value: float) → None[source]

Set the color minimum, pushing the maximum up if needed.

set_max(value: float) → None[source]

Set the color maximum, pushing the minimum down if needed.

set_capped(capped: bool) → None[source]

Toggle the cap; only clamps the color range, never rescales it.

color_scale_state() → ColorScaleState[source]
abstractmethod set_solution(solution: padne.solver.Solution, geometries: dict[padne.mesh.Mesh, RenderedMesh] | None = None, disconnected: dict[str, list[RenderedMesh]] | None = None)[source]

Initialize this mode with solution data (build indices + meshes).

pick_nearest_value(layer_name: str, world_x: float, world_y: float) → float | None[source]

Pick value at coordinates using spatial index.

get_rendered_meshes_for_layer(layer_name: str) → list[RenderedMesh][source]

Get pre-built rendered meshes for a layer.

get_disconnected_rendered_meshes_for_layer(layer_name: str) → list[RenderedMesh][source]

Get pre-built disconnected rendered meshes for a layer.

class VoltageRenderingMode[source]

Bases: BaseRenderingMode

unit: str = 'V'[source]
name: str = 'Potential'[source]
color_map: padne.colormaps.UniformColorMap[source]
class PowerDensityRenderingMode[source]

Bases: BaseRenderingMode

unit: str = 'W/mm²'[source]
name: str = 'Power Density'[source]
color_map: padne.colormaps.UniformColorMap[source]
slider_scale: ClassVar[SliderScale][source]
capped: bool = True[source]
class CurrentDensityRenderingMode[source]

Bases: PowerDensityRenderingMode

unit: str = 'A/mm²'[source]
name: str = 'Current Density'[source]
color_map: padne.colormaps.UniformColorMap[source]
set_solution(solution: padne.solver.Solution, geometries: dict[padne.mesh.Mesh, RenderedMesh] | None = None, disconnected: dict[str, list[RenderedMesh]] | None = None)[source]

Initialize this mode with solution data (build indices + meshes).

colorScaleChanged[source]
currentLayerChanged[source]
availableLayersChanged[source]
currentModeChanged[source]
meshClicked[source]
screenDragged[source]
keyPressedInMesh[source]
mousePositionChanged[source]
visibilityChanged[source]
classmethod default_modes() → list[MeshViewer][source]

The rendering modes in menu order, constructible without a widget.

solution: None | padne.solver.Solution = None[source]
rendered_connection_points: dict[str, RenderedPoints][source]
connection_points_visible: bool = True[source]
modes[source]
current_mode_index = 0[source]
scale = 1.0[source]
offset_x = 0.0[source]
offset_y = 0.0[source]
needs_initial_autoscale = False[source]
last_mouse_screen_pos: PySide6.QtCore.QPointF | None = None[source]
last_mouse_position_change_ts[source]
current_layer_index = 0[source]
visible_layers = [][source]
mesh_shader = None[source]
disconnected_shader = None[source]
edge_shader = None[source]
points_shader = None[source]
edges_visible = True[source]
outline_visible = True[source]
property current_rendering_mode: BaseRenderingMode[source]

Get the currently active rendering mode.

property current_layer_name: str[source]

Get the name of the currently active layer.

property aspect_ratio: float[source]

Get the current aspect ratio (width/height).

autoscaleValue() → None[source]

Automatically adjust the min/max values for color scaling using the current rendering mode.

setCapped(capped: bool) → None[source]

Toggle the percentile cap of the current rendering mode.

autoscaleXY() → None[source]

Automatically adjust the offset and scale to fit all meshes in the view. Sets the view to display all meshes with a small margin around them.

setSolution(prepared: PreparedUI)[source]

Install a solution prepared by prepare_ui_data.

setupConnectionPointsData() → None[source]

Set up the connection points data for rendering.

initializeGL() → None[source]

Initialize OpenGL settings.

resizeGL(width: int, height: int) → None[source]

Handle window resizing.

paintGL() → None[source]

Render the mesh using shaders.

mousePressEvent(event: PySide6.QtGui.QMouseEvent) → None[source]

Handle mouse press events.

mouseMoveEvent(event: PySide6.QtGui.QMouseEvent) → None[source]

Handle mouse movement.

mouseReleaseEvent(event: PySide6.QtGui.QMouseEvent) → None[source]

Handle mouse release events.

panViewByScreenDelta(dx_screen: float, dy_screen: float) → None[source]

Pans the view based on a screen delta.

Args:

dx_screen: Change in x screen coordinate. dy_screen: Change in y screen coordinate.

setMinValue(value: float) → None[source]

Sets the minimum of the color scale; clamps max upward if needed.

setMaxValue(value: float) → None[source]

Sets the maximum of the color scale; clamps min downward if needed.

setMinValueFromWorldPoint(world_point: padne.mesh.Point) → None[source]

Sets the minimum value of the color scale from a world point. If the selected value is greater than the current maximum, both min and max are set to the selected value.

Args:

world_point: The point in world coordinates.

setMaxValueFromWorldPoint(world_point: padne.mesh.Point) → None[source]

Sets the maximum value of the color scale from a world point. If the selected value is less than the current minimum, both min and max are set to the selected value.

Args:

world_point: The point in world coordinates.

wheelEvent(event: PySide6.QtGui.QWheelEvent) → None[source]

Handle mouse wheel for zooming towards cursor position.

keyPressEvent(event: PySide6.QtGui.QKeyEvent) → None[source]

Handle keyboard events.

switchLayerBy(direction: int = 1) → None[source]

Switch to the next or previous layer in the cycle.

Args:

direction: 1 for next layer, -1 for previous layer

setEdgesVisible(visible: bool)[source]

Slot to set the visibility of mesh edges.

setOutlineVisible(visible: bool)[source]

Slot to set the visibility of outline edges.

setConnectionPointsVisible(visible: bool)[source]

Slot to set the visibility of connection points.

setCurrentLayerByName(layer_name: str)[source]

Sets the current layer by its name.

setCurrentModeByName(mode_name: str)[source]

Sets the current rendering mode by its name.

class padne.ui.EditableValueLabel(parent=None)[source]

Bases: PySide6.QtWidgets.QLabel

A QLabel that turns into a QLineEdit on double-click for in-place value editing.

valueEdited[source]
value = 0.0[source]
unit = ''[source]
setValue(value: float, unit: str) → None[source]
mouseDoubleClickEvent(event: PySide6.QtGui.QMouseEvent) → None[source]
eventFilter(watched, event)[source]
class padne.ui.ColorScaleWidget(parent=None)[source]

Bases: PySide6.QtWidgets.QWidget

Color scale with min/max sliders and a percentile cap toggle.

unitChanged[source]
minValueEdited[source]
maxValueEdited[source]
capToggled[source]
state[source]
delta_label: PySide6.QtWidgets.QLabel | None = None[source]
max_label: EditableValueLabel | None = None[source]
min_label: EditableValueLabel | None = None[source]
min_slider: PySide6.QtWidgets.QSlider | None = None[source]
max_slider: PySide6.QtWidgets.QSlider | None = None[source]
percentile_checkbox: PySide6.QtWidgets.QCheckBox | None = None[source]
setupUI() → None[source]

Set up the UI components.

setState(state: ColorScaleState) → None[source]

Show state; does not re-emit any edit signals.

updateLabels() → None[source]

Update the delta and range labels.

paintEvent(event: PySide6.QtGui.QPaintEvent) → None[source]

Paint the color gradient scale.

class padne.ui.PreparedUI[source]

GL-free UI preparation for a solution (see prepare_ui_data).

solution: padne.solver.Solution[source]
modes: list[MeshViewer][source]
padne.ui.prepare_ui_data(solution: padne.solver.Solution) → PreparedUI[source]

Build the GL-free UI data for solution: per-mode spatial indices and the prepared render arrays.

CPU-only native/numpy work – it never touches Qt or the OpenGL context, so it can run before the window exists. The GL side (VAO upload, shader compilation) still happens later, on the render thread.

class padne.ui.MainWindow(prepared: PreparedUI, warnings_list: list[warnings.WarningMessage] | None = None)[source]

Bases: PySide6.QtWidgets.QMainWindow

project_file_name[source]
warnings_list[source]
warnings_shown = False[source]
mesh_viewer[source]
tool_manager[source]
color_scale[source]
app_toolbar[source]
updateCurrentLayer(layer_name: str) → None[source]

Update the window title to show the current layer.

updateMousePosition(world_point: padne.mesh.Point, value)[source]

Update status bar with mouse position and value.

showEvent(event: PySide6.QtGui.QShowEvent) → None[source]

Override showEvent to display warnings after window is visible.

padne.ui.configure_opengl() → None[source]

Configure OpenGL settings for the application.

padne.ui.main(prepared: PreparedUI, warnings_list: list[warnings.WarningMessage] | None = None) → int[source]

Main entry point for the UI application.

prepared is the result of prepare_ui_data, which the caller runs (and times) before the window is created.