sec_interp.core.utils package

sec_interp.core.utils.calculate_apparent_dip(true_strike: float, true_dip: float, line_azimuth: float) → float

Convert true dip to apparent dip in section plane.

The apparent dip is the inclination of a plane measured in a direction not perpendicular to the strike. In a vertical cross-section, the apparent dip depends on the angle between the strike of the plane and the azimuth of the cross-section line.

Formula:

tan(apparent_dip) = tan(true_dip) * sin(alpha)

Where alpha is the angle between the strike of the plane and the direction of the cross-section (section azimuth). alpha = strike - section_azimuth

Parameters:
  • true_strike – Strike of the geological plane (0-360 degrees).

  • true_dip – True dip of the geological plane (0-90 degrees).

  • line_azimuth – Azimuth of the cross-section line (0-360 degrees).

Returns:

Apparent dip in degrees. Positive values indicate dip, negative values might occur depending on quadrant but are typically normalized.

sec_interp.core.utils.calculate_bounds(topo_data: list[tuple[float, float]], geol_data: list[GeologySegment] | None = None) → dict[str, float]

Calculate the bounding box for all profile data with padding.

Calculates the minimum and maximum distance and elevation across topography and optional geological segments.

Parameters:
  • topo_data – List of (distance, elevation) tuples for topography.

  • geol_data – Optional list of geological segments.

Returns:

Bounds containing ‘min_d’, ‘max_d’, ‘min_e’, ‘max_e’ with 5% padding.

sec_interp.core.utils.calculate_drillhole_trajectory(collar_point: Any, collar_z: float, survey_data: list[tuple[float, float, float]], section_azimuth: float, densify_step: float = 1.0, total_depth: float = 0.0) → list[tuple[float, float, float, float, float, float]]

Calculate the 3D trajectory of a drillhole using survey data.

Calculates X, Y, Z positions along the hole using minimum curvature or tangential approximation based on survey readings (depth, azimuth, dip).

Parameters:
  • collar_point – Starting point (QgsPointXY or tuple).

  • collar_z – Starting elevation.

  • survey_data – List of (depth, azimuth, inclination) tuples.

  • section_azimuth – Azimuth of the section line (for relative calcs).

  • densify_step – Distance between interpolated points in meters.

  • total_depth – Total depth of the hole.

Returns:

List of (depth, x, y, z, 0.0, 0.0) trajectory points.

sec_interp.core.utils.calculate_interval(data_range: float) → float

Calculate a ‘nice’ interval for axis labels based on the data range.

Parameters:

data_range – The total range of data values (e.g., max_d - min_d).

Returns:

A human-readable interval (e.g., 1, 2, 5, 10, etc.) for grid lines.

sec_interp.core.utils.calculate_line_azimuth(points: list[tuple[float, float]]) → float

Calculate the azimuth (compass bearing) of a line.

Calculates the azimuth based on the first two points of the line. Returns 0 for points or single-vertex lines.

Parameters:

points – List of (x, y) tuples defining the line.

Returns:

Azimuth in degrees (0-360).

sec_interp.core.utils.cardinal_to_azimuth(text: str) → float | None

Convert a cardinal direction string to its equivalent azimuth.

Supports: N, NE, E, SE, S, SW, W, NW.

Parameters:

text – The cardinal direction string.

Returns:

The azimuth in degrees (0-360), or None if invalid.

sec_interp.core.utils.create_coordinate_transform(bounds: dict[str, float], view_w: int, view_h: int, margin: int, vert_exag: float = 1.0) → Callable[[float, float], tuple[float, float]]

Create a coordinate transformation function for screen projection.

Returns a function that transforms data coordinates (distance, elevation) to pixel coordinates (x, y) based on the provided view dimensions.

Parameters:
  • bounds – Dictionary with ‘min_d’, ‘max_d’, ‘min_e’, ‘max_e’.

  • view_w – Screen/view width in pixels.

  • view_h – Screen/view height in pixels.

  • margin – Plot margin in pixels.

  • vert_exag – Vertical exaggeration multiplier (default 1.0).

Returns:

A function transform(dist, elev) -> (x, y) converting data to pixels.

sec_interp.core.utils.extract_feature_attributes(feature: Any) → dict[str, Any]

Extract attributes from a QgsFeature into a pure Python dictionary.

Ensures all values are converted to standard Python primitives to avoid threading issues with QVariant objects in QGIS 4/Qt6.

Parameters:

feature – The QgsFeature object.

Returns:

A dictionary mapping field names to sanitized attribute values.

sec_interp.core.utils.interpolate_elevation(topo_data: list[tuple[float, float]], distance: float) → float

Interpolate elevation at a given distance along the topography profile.

Uses linear interpolation between the two nearest sampled points.

Parameters:
  • topo_data – List of (distance, elevation) tuples.

  • distance – Horizontal distance along the section.

Returns:

The interpolated elevation value (Z) at that distance.

sec_interp.core.utils.interpolate_intervals_on_trajectory(trajectory: list[tuple], intervals: list[tuple[float, float, Any]], buffer_width: float) → list[tuple[Any, list[tuple[float, float]], list[tuple[float, float, float]], list[tuple[float, float, float]]]]

Interpolate interval attributes along drillhole trajectory.

Ensures that even short intervals have at least two points by interpolating at the exact from/to depths on the trajectory segments.

Parameters:
  • trajectory – List of (depth, x, y, z, dist_along, offset, nx, ny) tuples.

  • intervals – List of (from_depth, to_depth, attribute) tuples.

  • buffer_width – Maximum perpendicular offset to include a point.

Returns:

List of tuples (attribute, points_2d, points_3d, points_3d_proj).

sec_interp.core.utils.parse_dip(value: Any) → tuple[float | None, float | None]

Parse a dip value from various formats.

Supports numeric dip (“45”) and field notation with direction (“45 NE”, “22 SW”). Also supports finding the dip part in combined strings (e.g. “N30E, 45NW”).

Parameters:

value – The raw dip value.

Returns:

A tuple of (dip_angle, dip_direction_azimuth). Values are None if parsing fails.

sec_interp.core.utils.parse_strike(value: Any) → float | None

Parse a strike value from various formats into an azimuth (0-360).

Supports numeric values, strings, and quadrant notation (e.g., “N 30 E”, “S 45 W”). Also handles combined strike/dip strings by splitting them.

Parameters:

value – The raw strike value (string, int, float, or None).

Returns:

Strike in azimuth degrees (0-360) or None if parsing fails.

sec_interp.core.utils.project_trajectory_to_section(trajectory: list[tuple], line_points: list[tuple[float, float]]) → list[tuple[float, float, float, float, float, float, float, float]]

Project drillhole trajectory points onto the section line.

Calculates the 2D projection (distance along section) and the offset (distance from section) for each point in a 3D trajectory using planar math.

Parameters:
  • trajectory – List of 3D trajectory points (depth, x, y, z, …).

  • line_points – Section line vertices as (x, y) tuples.

Returns:

List of (depth, x, y, z, dist_along, offset, proj_x, proj_y) tuples.

sec_interp.core.utils.smooth_profile_by_distance(data: list[tuple[float, float]], window_m: float, passes: int = 1) → list[tuple[float, float]]

Smooth a profile with a centered moving average over a distance window.

Averages the elevation of every point within window_m / 2 of each station. The first and last elevations are preserved so the ends do not drift. Returns the input unchanged when there is nothing to smooth or the window is non-positive.

Parameters:
  • data – List of (distance, elevation) tuples, sorted by distance.

  • window_m – Window width in distance units (map units, e.g. metres).

  • passes – Number of smoothing passes (>= 1).

Returns:

A new list of (distance, elevation) tuples of the same length.

Subpackages

Submodules