# sec_interp.core.utils package

## Submodules

- sec_interp.core.utils.drillhole module
  - `calculate_drillhole_trajectory()`
  - `project_trajectory_to_section()`
  - `interpolate_intervals_on_trajectory()`
- sec_interp.core.utils.geology module
  - `calculate_apparent_dip()`
- sec_interp.core.utils.geometry module
  - `create_memory_layer()`
  - `extract_all_vertices()`
  - `get_line_vertices()`
  - `run_processing_algorithm()`
  - `run_geometry_operation()`
  - `create_buffer_geometry()`
  - `filter_features_by_buffer()`
  - `densify_line_by_interval()`
- sec_interp.core.utils.io module
  - `create_shapefile_writer()`
- sec_interp.core.utils.parsing module
  - `parse_strike()`
  - `parse_dip()`
  - `cardinal_to_azimuth()`
- sec_interp.core.utils.rendering module
  - `calculate_bounds()`
  - `create_coordinate_transform()`
  - `calculate_interval()`
- sec_interp.core.utils.sampling module
  - `sample_elevation_along_line()`
  - `prepare_profile_context()`
  - `interpolate_elevation()`
- sec_interp.core.utils.spatial module
  - `calculate_line_azimuth()`
  - `calculate_step_size()`
  - `get_line_start_point()`
  - `create_distance_area()`

## Module contents

Core Utilities Package.

Organized by functionality: - geometry: Spatial geometry operations - spatial: Distance and azimuth calculations - sampling: Elevation sampling and profiling - parsing: Structural data parsing - rendering: Visualization utilities - io: File I/O and user messages - geology: Geological calculations

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.

  Return type:

    float

sec_interp.core.utils.calculate_drillhole_trajectory(collar_point: qgis.core.QgsPointXY, 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 3D trajectory of a drillhole using survey data.

  Uses the tangential method for trajectory calculation with densification to generate intermediate points for continuous interval projection.

  Parameters:

    - collar_point – QgsPointXY of collar location (X, Y).

    - collar_z – Elevation of collar (Z).

    - survey_data – List of tuples (depth, azimuth, inclination) sorted by depth.

    - section_azimuth – Azimuth of the section line in degrees.

    - densify_step – Distance in meters between interpolated points (default 1.0m).

    - total_depth – Optional total depth. If greater than last survey depth, trajectory will be extrapolated using last orientation.

  Returns:

    - depth: Depth along the hole.

    - x, y, z: 3D coordinates.

    - dist_along_section: Distance along the section line (initialized to 0.0).

    - offset_from_section: Perpendicular distance from section line (initialized to 0.0).

  Return type:

    List of tuples (depth, x, y, z, dist_along_section, offset_from_section)

sec_interp.core.utils.project_trajectory_to_section(trajectory: List[Tuple], line_geom: qgis.core.QgsGeometry, line_start: qgis.core.QgsPointXY, distance_area: qgis.core.QgsDistanceArea) → List[Tuple[float, float, float, float, float, float]]

  Project drillhole trajectory points onto section line.

  Parameters:

    - trajectory – List of (depth, x, y, z, _, _) from calculate_drillhole_trajectory.

    - line_geom – QgsGeometry of the section line.

    - line_start – QgsPointXY of the section line start.

    - distance_area – QgsDistanceArea for geodesic measurements.

  Returns:

    - depth: Original depth.

    - x, y, z: Original 3D coordinates.

    - dist_along: Projected distance along the section line.

    - offset: Perpendicular offset from the section line.

  Return type:

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

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]]]]

  Interpolate interval attributes along drillhole trajectory.

  Filters and maps geological intervals onto the 3D trajectory points that fall within the specified section buffer.

  Parameters:

    - trajectory – List of (depth, x, y, z, dist_along, offset) tuples.

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

    - buffer_width – Maximum perpendicular offset to include a point.

  Returns:

    - attribute: The metadata/geology associated with the interval.

    - points: List of (distance, Z) coordinates for rendering.

  Return type:

    List of (attribute, list of (dist_along, elevation)) tuples

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.

  Return type:

    Dict[str, float]

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.

  Return type:

    float

sec_interp.core.utils.calculate_line_azimuth(line_geom: qgis.core.QgsGeometry) → float

  Calculate the azimuth (compass bearing) of a line geometry.

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

  Parameters:

    line_geom – The QGIS line geometry.

  Returns:

    Azimuth in degrees (0-360).

  Return type:

    float

sec_interp.core.utils.calculate_step_size(geom: qgis.core.QgsGeometry, raster_lyr) → float

  Calculate step size based on slope and raster resolution.

  Deprecated since version Use: densify_line_by_interval() instead for better precision and simpler code. This function is kept for backward compatibility but may be removed in future versions.

  Ensures that sampling occurs at approximately one pixel intervals, accounting for the slope of the line relative to the raster grid.

  Parameters:

    - geom – The geometry to sample along.

    - raster_lyr – The raster layer being sampled.

  Returns:

    Calculated step size in map units.

  Return type:

    float

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.

  Return type:

    Optional[float]

sec_interp.core.utils.create_buffer_geometry(geometry: qgis.core.QgsGeometry, crs: qgis.core.QgsCoordinateReferenceSystem, distance: float, segments: int = 25) → qgis.core.QgsGeometry

  Create buffer geometry using native QGIS processing algorithm.

  Parameters:

    - geometry – Input geometry to buffer.

    - crs – Coordinate reference system.

    - distance – Buffer distance in CRS units.

    - segments – Number of segments for curves (default: 25).

  Returns:

    Buffered geometry.

  Return type:

    QgsGeometry

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).

  Return type:

    Callable[[float, float], Tuple[float, float]]

sec_interp.core.utils.create_distance_area(crs: qgis.core.QgsCoordinateReferenceSystem) → qgis.core.QgsDistanceArea

  Helper to create and configure a QgsDistanceArea object.

  Configures the distance area with the provided CRS, project transform context, and associated ellipsoid for geodesic calculations.

  Parameters:

    crs – The Coordinate Reference System to use.

  Returns:

    The configured distance calculation object.

  Return type:

    QgsDistanceArea

sec_interp.core.utils.create_memory_layer(geometry: qgis.core.QgsGeometry, crs: qgis.core.QgsCoordinateReferenceSystem, name: str = 'temp', fields: qgis.core.QgsFields | None = None) → qgis.core.QgsVectorLayer

  Create a temporary QGIS memory layer with a single geometry feature.

  Parameters:

    - geometry – The QGIS geometry to add to the layer.

    - crs – The Coordinate Reference System for the new layer.

    - name – Internal name for the layer (default: “temp”).

    - fields – Optional field definitions for attributes.

  Returns:

    A valid (but potentially empty on failure) QGIS memory layer.

  Return type:

    QgsVectorLayer

  Raises:

    - ValueError – If the input geometry is null or invalid.

    - RuntimeError – If the memory layer cannot be initialized.

sec_interp.core.utils.create_shapefile_writer(output_path: str | Path, crs: qgis.core.QgsCoordinateReferenceSystem, fields: qgis.core.QgsFields, geometry_type: qgis.core.QgsWkbTypes.GeometryType = qgis.core.QgsWkbTypes.LineString) → qgis.core.QgsVectorFileWriter

  Helper to create and initialize a QgsVectorFileWriter for Shapefiles.

  Uses the modern create static method for QGIS 3.38+ compatibility.

  Parameters:

    - output_path – File system path where the shapefile will be created.

    - crs – The Coordinate Reference System for the new file.

    - fields – The attribute fields definition.

    - geometry_type – The mapping geometry type (default: LineString).

  Returns:

    An initialized writer object.

  Return type:

    QgsVectorFileWriter

  Raises:

    OSError – If the writer cannot be created or has an initialization error.

sec_interp.core.utils.densify_line_by_interval(geometry: qgis.core.QgsGeometry, interval: float) → qgis.core.QgsGeometry

  Densify line geometry by adding vertices at regular intervals.

  Parameters:

    - geometry – Line geometry to densify.

    - interval – Distance between vertices in geometry units.

  Returns:

    Densified line geometry.

  Return type:

    QgsGeometry

  Raises:

    ValueError – If geometry is not a line.

sec_interp.core.utils.filter_features_by_buffer(features_layer: qgis.core.QgsVectorLayer, buffer_geometry: qgis.core.QgsGeometry, buffer_crs: qgis.core.QgsCoordinateReferenceSystem | None = None) → List[qgis.core.QgsFeature]

  Filter features that intersect with buffer using spatial index.

  Parameters:

    - features_layer – Layer containing features to filter.

    - buffer_geometry – Buffer geometry to use for spatial filter.

    - buffer_crs – CRS of the buffer geometry (optional, for compatibility).

  Returns:

    Features that intersect the buffer.

  Return type:

    List[QgsFeature]

  Raises:

    ValueError – If inputs are invalid.

sec_interp.core.utils.get_line_start_point(geometry: qgis.core.QgsGeometry) → qgis.core.QgsPointXY

  Helper to get the start point of a line geometry.

  Handles both singlepart and multipart line geometries.

  Parameters:

    geometry – The line geometry.

  Returns:

    The first vertex of the first part.

  Return type:

    QgsPointXY

sec_interp.core.utils.get_line_vertices(geometry: qgis.core.QgsGeometry) → List[qgis.core.QgsPointXY]

  Extract vertices specifically from a line or multiline geometry.

  Parameters:

    geometry – A QGIS geometry of type LineGeometry.

  Returns:

    A flat list of vertices.

  Return type:

    List[QgsPointXY]

  Raises:

    ValueError – If the geometry is null, not a line, or contains no vertices.

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

  Interpolate elevation at given distance.

  Parameters:

    - topo_data – List of (distance, elevation) tuples.

    - distance – Distance at which to interpolate elevation.

  Returns:

    Interpolated elevation value.

  Return type:

    float

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”).

  Parameters:

    value – The raw dip value.

  Returns:

    A tuple (dip_angle, dip_direction_azimuth).

      Values are None if parsing fails.

  Return type:

    Tuple[Optional[float], Optional[float]]

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”).

  Parameters:

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

  Returns:

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

  Return type:

    Optional[float]

sec_interp.core.utils.prepare_profile_context(line_lyr: qgis.core.QgsVectorLayer) → Tuple[qgis.core.QgsGeometry, qgis.core.QgsPointXY, qgis.core.QgsDistanceArea]

  Prepare a common context for profile calculation operations.

  Parameters:

    line_lyr – The cross-section line vector layer.

  Returns:

    (line_geom, line_start, distance_area)

      - line_geom (QgsGeometry): The geometry of the section line.

      - line_start (QgsPointXY): The starting point of the line.

      - distance_area (QgsDistanceArea): Fully configured distance object.

  Return type:

    Tuple

  Raises:

    ValueError – If the input layer is empty or has invalid geometry.

sec_interp.core.utils.run_processing_algorithm(algorithm: str, parameters: dict, silent: bool = True) → dict

  Execute a QGIS processing algorithm with consistent error handling.

  Parameters:

    - algorithm – The provider:algorithm ID (e.g., “native:buffer”).

    - parameters – A dictionary of algorithm parameters.

    - silent – If True, uses a silent feedback object (default: True).

  Returns:

    The result dictionary returned by processing.run.

  Return type:

    dict

  Raises:

    RuntimeError – If the algorithm fails to execute or returns an error.

sec_interp.core.utils.sample_elevation_along_line(geometry: qgis.core.QgsGeometry, raster_layer: qgis.core.QgsRasterLayer, band_number: int, distance_area: qgis.core.QgsDistanceArea, reference_point: qgis.core.QgsPointXY | None = None) → List[qgis.core.QgsPointXY]

  Sample elevation values along a line geometry from a raster layer.

  Densifies the line at raster resolution and samples the elevation at each vertex.

  Parameters:

    - geometry – The line geometry to sample along.

    - raster_layer – The source DEM raster layer.

    - band_number – The raster band index to sample.

    - distance_area – Object for geodesic distance calculations.

    - reference_point – Optional start point for distance measurements.

  Returns:

    A list where x is distance along section and y is elevation.

  Return type:

    List[QgsPointXY]