baselode 0.1.20 → 0.1.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/baselode.js +1524 -1354
- package/dist/baselode.js.map +1 -1
- package/dist/{baselode3dScene-qMfVRKxK.js → baselode3dScene-CLEvddGM.js} +299 -293
- package/dist/baselode3dScene-CLEvddGM.js.map +1 -0
- package/dist/style.css +1 -1
- package/dist/tool-ui.js +29 -29
- package/package.json +1 -1
- package/dist/baselode3dScene-qMfVRKxK.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"baselode3dScene-CLEvddGM.js","sources":["../src/data/datamodel.js","../src/data/dataErrorUtils.js","../src/data/columnMeta.js","../src/data/blockModelLoader.js","../src/data/structuralPositions.js","../src/viz/baselodeTemplate.js","../src/viz/baselodeDarkTemplate.js","../src/viz/colourMap.js","../src/viz/drillholeViz.js","../src/viz/assayColorScale.js","../src/viz/sceneSelectables.js","../src/viz/structuralScene.js","../src/viz/rasterOverlayScene.js","../src/viz/baselode3dCameraControls.js","../src/viz/drillholeScene.js","../src/viz/stripLogScene.js","../src/viz/selectionGlow.js","../src/viz/blockModelScene.js","../src/viz/sceneClickHandler.js","../src/viz/baselode3dScene.js"],"sourcesContent":["/*\n * Copyright (C) 2026 Darkmine Pty Ltd\n * SPDX-License-Identifier: GPL-3.0-or-later\n */\n\n/**\n * Baselode Open Data Model for JavaScript/TypeScript\n *\n * Provides a consistent schema for data handling throughout the library.\n *\n * Individual data loaders apply common column mapping, but also accept\n * user-provided column maps to handle variations in source data.\n *\n * Mirrors the Python module ``baselode.datamodel`` — keep the two in sync.\n */\n\n// --- Drilling and sampling primitives ---\nexport const DATASOURCE = \"datasource\";\n\nexport const HOLE_ID = \"hole_id\";\n// Internal join key used by some sources (e.g. raw_gswa); leading underscore\n// marks it as internal and signals downstream code to drop or hide it.\nexport const COLLAR_ID = \"_collar_id\";\nexport const DATASOURCE_HOLE_ID = \"datasource_hole_id\";\nexport const HOLE_TYPE = \"hole_type\";\nexport const MAX_DEPTH = \"max_depth\";\n\nexport const SURFACE_SAMPLE_ID = \"surface_sample_id\";\nexport const SURFACE_SAMPLE_TYPE = \"surface_sample_type\";\nexport const DATASOURCE_SURFACE_SAMPLE_ID = \"datasource_surface_sample_id\";\n\nexport const PROJECT_ID = \"project_id\";\nexport const REPORT_NUMBER = \"report_number\";\n\n// --- Collar and surface-sample locations ---\nexport const LATITUDE = \"latitude\";\nexport const LONGITUDE = \"longitude\";\nexport const ELEVATION = \"elevation\";\nexport const EASTING = \"easting\";\nexport const NORTHING = \"northing\";\nexport const CRS = \"crs\";\nexport const DATE_START = \"date_start\";\nexport const DATE_END = \"date_end\";\n\n// --- Drilling survey primitives ---\nexport const AZIMUTH = \"azimuth\";\nexport const DIP = \"dip\";\nexport const SURVEY_TYPE = \"survey_type\";\n\n// --- Sampling primitives ---\nexport const SAMPLE_ID = \"sample_id\";\nexport const DATASOURCE_SAMPLE_ID = \"datasource_sample_id\";\nexport const FROM = \"from\";\nexport const TO = \"to\";\nexport const MID = \"mid\";\nexport const DEPTH = \"depth\";\n\n// --- Structural geology primitives ---\nexport const STRIKE = \"strike\";\nexport const ALPHA = \"alpha\";\nexport const BETA = \"beta\";\nexport const GEOLOGY_CODE = \"geology_code\";\nexport const GEOLOGY_DESCRIPTION = \"geology_description\";\n\n// --- Generics ---\nexport const COMMENTS = \"comments\";\n/**\n * Catch-all column on every baselode-model object/row. Holds a per-row\n * dict of source-specific fields that don't map to the canonical schema.\n * Keeps the top-level columns predictable while preserving everything the\n * source provided. JS type marker is \"object\" (a plain JS object / Map).\n */\nexport const EXTRA = \"extra\";\n\n// --- Constants and defaults ---\n/** Standard null sentinel value in LAS-derived geophysics data. */\nexport const GEOPHYSICS_NULL_SENTINEL = -999.25;\n// Python alias for the same value, kept for naming parity.\nexport const GEOPHYSICS_NULL = -999.25;\n\n\n/**\n * Minimum expected columns for drillhole collars\n * The collar forms the basis for hole_id and spatial location, so it is\n * expected to exist in all datasets and be standardized as much as possible.\n */\nexport const BASELODE_DATA_MODEL_DRILL_COLLAR = {\n // A unique hole identifier across the entire dataset and all future data sets\n [HOLE_ID]: \"string\",\n // The hole ID from the original collar source\n [DATASOURCE_HOLE_ID]: \"string\",\n // The project ID or project code from the original collar source, if available\n [PROJECT_ID]: \"string\",\n // The latitude of the collar, in decimal degrees (WGS84)\n [LATITUDE]: \"number\",\n // The longitude of the collar, in decimal degrees (WGS84)\n [LONGITUDE]: \"number\",\n // The elevation of the collar, in meters above sea level (WGS84)\n [ELEVATION]: \"number\",\n // The easting coordinate of the collar, in meters (projected CRS)\n [EASTING]: \"number\",\n // The northing coordinate of the collar, in meters (projected CRS)\n [NORTHING]: \"number\",\n // The coordinate reference system of the collar coordinates for easting/northing,\n // as an EPSG code or proj string\n [CRS]: \"string\",\n // Internal join key used by source schemas (e.g. raw_gswa) — distinct from\n // the public hole_id.\n [COLLAR_ID]: \"string\",\n // Per-row dict of source-specific fields outside the canonical schema\n // (populated by `bundleExtras`; empty object when the source had nothing extra).\n [EXTRA]: \"object\"\n};\n\nexport const BASELODE_DATA_MODEL_DRILL_SURVEY = {\n // The unique hole id that maps to the collar and any other data tables\n [HOLE_ID]: \"string\",\n // The depth along the hole where the survey measurement was taken / started\n [DEPTH]: \"number\",\n // The depth along the hole where the survey measurement ended, if applicable\n // (some surveys are point measurements and may not have a 'to' depth)\n [TO]: \"number\",\n // The azimuth of the hole at the survey depth, in degrees from north\n [AZIMUTH]: \"number\",\n // The dip of the hole at the survey depth, in degrees from horizontal\n // (negative values indicate downward inclination)\n [DIP]: \"number\",\n // Per-row dict of source-specific fields outside the canonical schema.\n [EXTRA]: \"object\"\n};\n\nexport const BASELODE_DATA_MODEL_DRILL_ASSAY = {\n // The unique hole id that maps to the collar and any other data tables\n [HOLE_ID]: \"string\",\n // The depth along the hole where the assay interval starts\n [FROM]: \"number\",\n // The depth along the hole where the assay interval ends\n [TO]: \"number\",\n // The midpoint depth of the assay interval\n [MID]: \"number\",\n // assay value columns are variable and not standardized here.\n // Assays may be flattened (one column per assay type) or long\n // (one row per assay type with an additional 'assay_type' column).\n // Per-row dict of source-specific fields outside the canonical schema\n // (sample identifiers, lab metadata, detection-limit flags, etc.).\n [EXTRA]: \"object\"\n};\n\nexport const BASELODE_DATA_MODEL_DRILL_GEOLOGY = {\n [HOLE_ID]: \"string\",\n [FROM]: \"number\",\n [TO]: \"number\",\n [MID]: \"number\",\n [GEOLOGY_CODE]: \"string\",\n [GEOLOGY_DESCRIPTION]: \"string\",\n // Per-row dict of source-specific fields outside the canonical schema.\n [EXTRA]: \"object\"\n};\n\n/**\n * Structural point data model schema\n */\nexport const BASELODE_DATA_MODEL_STRUCTURAL_POINT = {\n [HOLE_ID]: \"string\",\n [DEPTH]: \"number\",\n [DIP]: \"number\",\n [AZIMUTH]: \"number\",\n [ALPHA]: \"number\",\n [BETA]: \"number\",\n [COMMENTS]: \"string\",\n // Per-row dict of source-specific fields outside the canonical schema.\n [EXTRA]: \"object\"\n};\n\n/**\n * Geophysics interval data model schema.\n * Value columns (gamma, density, resistivity, etc.) are variable and not standardized.\n * Null sentinels (e.g. -999.25 from LAS-derived sources) are replaced with null on load.\n */\nexport const BASELODE_DATA_MODEL_GEOPHYSICS = {\n [HOLE_ID]: \"string\",\n [FROM]: \"number\",\n [TO]: \"number\",\n [MID]: \"number\",\n // value columns are variable — not standardized here\n // Per-row dict of source-specific fields outside the canonical schema.\n [EXTRA]: \"object\"\n};\n\n/**\n * Surface-sample data model schema (point samples — soil, rock chip, stream\n * sediment, etc.). Mirrors the Python ``BASELODE_DATA_MODEL_SURFACE_SAMPLE``.\n */\nexport const BASELODE_DATA_MODEL_SURFACE_SAMPLE = {\n [SAMPLE_ID]: \"string\",\n [DATASOURCE_SURFACE_SAMPLE_ID]: \"string\",\n [REPORT_NUMBER]: \"string\",\n [LATITUDE]: \"number\",\n [LONGITUDE]: \"number\",\n [ELEVATION]: \"number\",\n [EASTING]: \"number\",\n [NORTHING]: \"number\",\n [CRS]: \"string\",\n [SURFACE_SAMPLE_TYPE]: \"string\",\n // Per-row dict of source-specific fields outside the canonical schema\n // (analyte values, lab metadata, detection-limit flags, anumber, ...).\n [EXTRA]: \"object\"\n};\n\n/**\n * This column map is used to make a 'best guess' for mapping common variations\n * in source column names to the baselode data model.\n * It is applied in the standardizeColumns function, but users can also provide\n * their own column map to override or extend this mapping as needed.\n * The keys from the input source are normalized to lowercase and stripped of\n * whitespace for more robust matching.\n * This dictionary is stored for human readability, then pivoted to make lookup\n * quicker in code.\n * Be cautious of not mapping a source column to multiple baselode columns,\n * as this can lead to unpredictable results.\n */\nexport const DEFAULT_COLUMN_MAP = {\n [HOLE_ID]: [\"hole_id\", \"holeid\", \"hole id\", \"hole-id\"],\n [DATASOURCE_HOLE_ID]: [\"datasource_hole_id\", \"datasourceholeid\", \"datasource hole id\", \"datasource-hole-id\", \"company_hole_id\", \"companyholeid\", \"company hole id\", \"company-hole-id\"],\n [PROJECT_ID]: [\"project_id\", \"projectid\", \"project id\", \"project-id\", \"project_code\", \"projectcode\", \"project code\", \"project-code\", \"companyId\", \"company_id\", \"companyid\", \"company id\", \"company-id\", \"dataset\", \"project\"],\n [LATITUDE]: [\"latitude\", \"lat\"],\n [LONGITUDE]: [\"longitude\", \"lon\"],\n [ELEVATION]: [\"elevation\", \"rl\", \"elev\", \"z\"],\n [EASTING]: [\"easting\", \"x\"],\n [NORTHING]: [\"northing\", \"y\"],\n [CRS]: [\"crs\", \"epsg\", \"projection\"],\n [FROM]: [\"from\", \"depth_from\", \"from_depth\", \"samp_from\", \"sample_from\", \"sampfrom\", \"fromdepth\"],\n [TO]: [\"to\", \"depth_to\", \"to_depth\", \"samp_to\", \"sample_to\", \"sampto\", \"todepth\"],\n [GEOLOGY_CODE]: [\n \"geology_code\",\n \"geologycode\",\n \"lith1\",\n \"lith1code\",\n \"lith1_code\",\n \"lithology\",\n \"plot_lithology\",\n \"rock1\"\n ],\n [GEOLOGY_DESCRIPTION]: [\n \"geology_description\",\n \"geologydescription\",\n \"geology_comment\",\n \"geologycomment\",\n \"geology comment\",\n \"lithology_comment\",\n \"lithology comment\",\n \"description\",\n \"comments\"\n ],\n [AZIMUTH]: [\"azimuth\", \"az\", \"dip_direction\", \"dipdir\", \"dip direction\", \"dipdrn\", \"dipdirection\", \"dip_dir\", \"computed_plane_azimuth\", \"calc_dipdir\", \"calc_dipdir_deg\", \"dipdir_calc\", \"dipdirect_calc\"],\n [DIP]: [\"dip\", \"computed_plane_dip\", \"calc_dip\", \"calc_dip_deg\", \"dip_calc\"],\n [ALPHA]: [\"alpha\", \"alpha_angle\", \"alpha_angle_deg\", \"alpha_2\"],\n [BETA]: [\"beta\", \"beta_angle\", \"beta_angle_deg\", \"beta_2\"],\n \"declination\": [\"declination\", \"dec\"],\n [DEPTH]: [\"depth\", \"survey_depth\", \"surveydepth\", \"md\", \"measured_depth\", \"dept\"],\n [STRIKE]: [\"strike\", \"str\"]\n};\n\n/**\n * Pivot the DEFAULT_COLUMN_MAP for efficient reverse lookup\n * Maps normalized column names -> standardized baselode column names\n * @private\n */\nexport const _COLUMN_LOOKUP = {};\nfor (const [standardCol, variations] of Object.entries(DEFAULT_COLUMN_MAP)) {\n for (const variation of variations) {\n const normalized = variation.toLowerCase().trim();\n _COLUMN_LOOKUP[normalized] = standardCol;\n }\n}\n","/*\n * Copyright (C) 2026 Darkmine Pty Ltd\n * SPDX-License-Identifier: GPL-3.0-or-later\n */\n\nconst DATA_LOG_PREFIX = '[baselode:data]';\n\n/**\n * Convert any value to an Error object\n * @param {*} error - Value to convert (Error, string, or other)\n * @param {string} fallbackMessage - Message to use if error is not Error or string\n * @returns {Error} Error object\n */\nexport function toError(error, fallbackMessage = 'Unknown error') {\n if (error instanceof Error) return error;\n const message = typeof error === 'string' && error.trim() ? error : fallbackMessage;\n return new Error(message);\n}\n\n/**\n * Wrap an error with contextual information about where it occurred\n * @param {string} context - Context description (e.g., function name)\n * @param {*} error - Original error\n * @param {string} fallbackMessage - Fallback message if error cannot be parsed\n * @returns {Error} Wrapped error with context and original as cause\n */\nexport function withDataErrorContext(context, error, fallbackMessage = 'Operation failed') {\n const baseError = toError(error, fallbackMessage);\n const wrapped = new Error(`${context}: ${baseError.message}`);\n wrapped.cause = baseError;\n return wrapped;\n}\n\n/**\n * Log a warning message with optional error object\n * @param {string} message - Warning message\n * @param {Error} [error] - Optional error object to log\n */\nexport function logDataWarning(message, error) {\n if (error !== undefined) {\n console.warn(`${DATA_LOG_PREFIX} ${message}`, error);\n return;\n }\n console.warn(`${DATA_LOG_PREFIX} ${message}`);\n}\n\n/**\n * Log an informational message\n * @param {string} message - Info message\n */\nexport function logDataInfo(message) {\n console.info(`${DATA_LOG_PREFIX} ${message}`);\n}","/*\n * Copyright (C) 2026 Darkmine Pty Ltd\n * SPDX-License-Identifier: GPL-3.0-or-later\n */\n\n/**\n * Column display type classification for strip log visualization.\n *\n * Every loaded column is assigned a display type that drives:\n * - which columns appear in strip log property dropdowns\n * - which chart type options are offered for a given column\n */\n\n/** Numeric measurement column — rendered as bar, marker, or line */\nexport const DISPLAY_NUMERIC = 'numeric';\n\n/** Categorical string column — rendered as coloured interval bands */\nexport const DISPLAY_CATEGORICAL = 'categorical';\n\n/** Free-text comment column — rendered as labelled interval boxes */\nexport const DISPLAY_COMMENT = 'comment';\n\n/** Hidden column — not shown in strip log dropdowns */\nexport const DISPLAY_HIDDEN = 'hidden';\n\n/** Tadpole log — dip head + azimuth tail, shows both dip and azimuth */\nexport const DISPLAY_TADPOLE = 'tadpole';\n\n/**\n * Available chart type options for each display type.\n * Used to populate the chart-type dropdown in TracePlot.\n */\nexport const CHART_OPTIONS = {\n [DISPLAY_NUMERIC]: [\n { value: 'bar', label: 'Bars' },\n { value: 'markers', label: 'Markers' },\n { value: 'markers+line', label: 'Markers + Line' },\n { value: 'line', label: 'Line only' },\n ],\n [DISPLAY_CATEGORICAL]: [\n { value: 'categorical', label: 'Categorical bands' },\n ],\n [DISPLAY_COMMENT]: [\n { value: 'comment', label: 'Comments' },\n ],\n [DISPLAY_TADPOLE]: [\n { value: 'tadpole', label: 'Tadpole' },\n ],\n [DISPLAY_HIDDEN]: [],\n};\n\n/**\n * Column names (lowercased) that are always hidden from strip log views.\n * Covers hole IDs, project codes, coordinates, depth/interval fields, and geometry.\n */\nexport const HIDDEN_COLUMNS = new Set([\n // Hole identifiers\n 'hole_id', 'holeid', 'id', 'holetype',\n 'datasource_hole_id',\n 'anumber', 'collarid', 'companyholeid', 'company_hole_id', 'company_id',\n // Project codes\n 'project_id', 'project_code', 'project', 'projectcode', 'projectid',\n // Geographic coordinates\n 'latitude', 'longitude', 'lat', 'lon', 'lng',\n 'easting', 'northing', 'x', 'y', 'z',\n 'elevation', 'elev', 'rl',\n // Depth / interval columns\n 'from', 'to', 'mid', 'depth', 'md',\n 'samp_from', 'samp_to', 'sample_from', 'sample_to',\n 'depth_from', 'depth_to', 'fromdepth', 'todepth',\n // Geometry / CRS\n 'shape', 'geometry', 'crs', 'epsg',\n // Internal / synthetic columns\n 'data_source', '_hole_key', '_hole_id_key',\n]);\n\n/**\n * Column names (lowercased) that map to the comment display type.\n * These are free-text description columns rendered as labelled interval boxes.\n */\nexport const COMMENT_COLUMN_NAMES = new Set([\n 'comments', 'comment', 'notes', 'note',\n 'description', 'remarks', 'remark',\n 'log_description', 'struct_comment', 'structcomment',\n 'geology_description',\n]);\n\n/**\n * Classify columns in a dataset by their display type.\n *\n * Rules applied in order:\n * 1. Columns in HIDDEN_COLUMNS → DISPLAY_HIDDEN\n * 2. Columns in COMMENT_COLUMN_NAMES with ≥1 non-empty value → DISPLAY_COMMENT\n * 3. All-null/empty columns → DISPLAY_HIDDEN (silently dropped)\n * 4. Columns with at least one finite number → DISPLAY_NUMERIC\n * 5. Remaining non-empty columns → DISPLAY_CATEGORICAL\n *\n * @param {Array<Object>} rows - Flat array of row objects (assay or structural points)\n * @returns {{\n * byType: Object<string, string>,\n * numericCols: string[],\n * categoricalCols: string[],\n * commentCols: string[],\n * }}\n */\nexport function classifyColumns(rows) {\n if (!rows?.length) {\n return { byType: {}, numericCols: [], categoricalCols: [], commentCols: [] };\n }\n\n // Collect all column names across all rows\n const allCols = new Set(rows.flatMap((r) => Object.keys(r || {})));\n const byType = {};\n\n for (const col of allCols) {\n const normalized = col.toLowerCase().trim();\n\n // Always hidden: ID / coordinate / depth columns\n if (HIDDEN_COLUMNS.has(normalized) || HIDDEN_COLUMNS.has(col)) {\n byType[col] = DISPLAY_HIDDEN;\n continue;\n }\n\n // Comment-type: named text-description columns\n if (COMMENT_COLUMN_NAMES.has(normalized)) {\n const hasValue = rows.some((r) => {\n const v = r[col];\n return v != null && String(v).trim() !== '' && String(v) !== 'null';\n });\n byType[col] = hasValue ? DISPLAY_COMMENT : DISPLAY_HIDDEN;\n continue;\n }\n\n // Classify by content: all-empty → hidden; numeric → numeric; else → categorical\n let hasNumeric = false;\n let hasValue = false;\n for (const r of rows) {\n const v = r[col];\n if (v == null || (typeof v === 'string' && v.trim() === '')) continue;\n hasValue = true;\n if (typeof v === 'number' && Number.isFinite(v)) {\n hasNumeric = true;\n break;\n }\n }\n\n if (!hasValue) {\n byType[col] = DISPLAY_HIDDEN;\n } else if (hasNumeric) {\n byType[col] = DISPLAY_NUMERIC;\n } else {\n byType[col] = DISPLAY_CATEGORICAL;\n }\n }\n\n return {\n byType,\n numericCols: Object.entries(byType).filter(([, t]) => t === DISPLAY_NUMERIC).map(([k]) => k),\n categoricalCols: Object.entries(byType).filter(([, t]) => t === DISPLAY_CATEGORICAL).map(([k]) => k),\n commentCols: Object.entries(byType).filter(([, t]) => t === DISPLAY_COMMENT).map(([k]) => k),\n };\n}\n\n/**\n * Get the available chart type options for a given display type.\n * Returns NUMERIC options as a fallback for unknown types.\n *\n * @param {string} displayType - One of the DISPLAY_* constants\n * @returns {Array<{value: string, label: string}>}\n */\nexport function getChartOptions(displayType) {\n return CHART_OPTIONS[displayType] ?? CHART_OPTIONS[DISPLAY_NUMERIC];\n}\n\n/**\n * Get the default chart type value for a display type.\n *\n * @param {string} displayType\n * @returns {string}\n */\nexport function defaultChartType(displayType) {\n const opts = getChartOptions(displayType);\n if (!opts.length) return 'markers+line';\n if (displayType === DISPLAY_NUMERIC) return 'line';\n return opts[0].value;\n}\n","/*\n * Copyright (C) 2026 Darkmine Pty Ltd\n * SPDX-License-Identifier: GPL-3.0-or-later\n */\nimport Papa from 'papaparse';\nimport { withDataErrorContext } from './dataErrorUtils.js';\n\n// ---------------------------------------------------------------------------\n// Column-name normalisation\n// ---------------------------------------------------------------------------\n\n/** Canonical geometry columns expected on every block row. */\nconst GEOMETRY_COLS = ['x', 'y', 'z', 'dx', 'dy', 'dz'];\n\n/** Maps accepted source column name variants to canonical names. */\nconst BLOCK_COL_MAP = {\n x: ['x', 'easting', 'center_x', 'xc', 'xcentre', 'xcenter', 'x_centre', 'x_center', 'cx'],\n y: ['y', 'northing', 'center_y', 'yc', 'ycentre', 'ycenter', 'y_centre', 'y_center', 'cy'],\n z: ['z', 'elevation', 'center_z', 'zc', 'zcentre', 'zcenter', 'z_centre', 'z_center', 'cz'],\n dx: ['dx', 'size_x', 'sx', 'sizex', 'dim_x', 'block_size_x'],\n dy: ['dy', 'size_y', 'sy', 'sizey', 'dim_y', 'block_size_y'],\n dz: ['dz', 'size_z', 'sz', 'sizez', 'dim_z', 'block_size_z'],\n};\n\n/** Reverse lookup: lower-cased source name → canonical name */\nconst _blockColLookup = {};\nObject.entries(BLOCK_COL_MAP).forEach(([canon, variants]) => {\n variants.forEach((v) => { _blockColLookup[v.toLowerCase()] = canon; });\n});\n\n/**\n * Rename a block row's keys from source column names to canonical names.\n * Unrecognised keys are kept as-is.\n * @param {Object} row - Raw parsed row object\n * @returns {Object} Row with canonical geometry key names\n */\nexport function normalizeBlockRow(row) {\n const out = {};\n Object.entries(row).forEach(([key, value]) => {\n const canon = _blockColLookup[key.toLowerCase().trim()] || key;\n out[canon] = value;\n });\n return out;\n}\n\n// ---------------------------------------------------------------------------\n// CSV parsing\n// ---------------------------------------------------------------------------\n\n/**\n * Parse block model CSV data.\n *\n * Accepts columns named ``x/y/z/dx/dy/dz`` (baselode canonical) or the\n * legacy ``center_x/center_y/center_z/size_x/size_y/size_z`` variants.\n * Both forms are normalised to the canonical names.\n *\n * @param {File|Blob|string} file - Block model CSV source\n * @returns {Promise<{data: Array<Object>, properties: Array<string>}>}\n * Parsed blocks (canonical column names) and property column names.\n */\nexport function parseBlockModelCSV(file) {\n return new Promise((resolve, reject) => {\n Papa.parse(file, {\n header: true,\n dynamicTyping: true,\n skipEmptyLines: true,\n complete: (results) => {\n const normalized = (results.data || []).map(normalizeBlockRow);\n const data = normalized.filter(\n (row) => row.x !== null && row.y !== null && row.z !== null\n );\n\n const propertyColumns = Object.keys(data[0] || {}).filter(\n (key) => !GEOMETRY_COLS.includes(key)\n );\n\n resolve({ data, properties: propertyColumns });\n },\n error: (error) => {\n reject(withDataErrorContext('parseBlockModelCSV', error));\n }\n });\n });\n}\n\n// ---------------------------------------------------------------------------\n// Metadata\n// ---------------------------------------------------------------------------\n\n/**\n * Parse a block model metadata JSON string or plain object.\n *\n * The metadata object may contain: ``name``, ``description``, ``crs``,\n * ``origin``, ``max_block_size``, ``min_block_size``, ``bbox_3d``,\n * ``outline_2d``, ``attributes``, ``extra``.\n *\n * @param {string|Object} source - JSON string or already-parsed object\n * @returns {Object} Parsed metadata object\n */\nexport function loadBlockModelMetadata(source) {\n if (typeof source === 'string') {\n try {\n return JSON.parse(source);\n } catch (err) {\n throw withDataErrorContext('loadBlockModelMetadata', err);\n }\n }\n if (source && typeof source === 'object') return source;\n throw withDataErrorContext('loadBlockModelMetadata', new Error('Invalid metadata source'));\n}\n\n// ---------------------------------------------------------------------------\n// Property statistics\n// ---------------------------------------------------------------------------\n\n/**\n * Calculate statistics for a property column in block model data.\n *\n * @param {Array<Object>} data - Block model data array\n * @param {string} property - Property column name to analyse\n * @returns {{type: 'numeric'|'categorical', min?: number, max?: number,\n * values: Array, categories?: Array}} Property statistics\n */\nexport function calculatePropertyStats(data, property) {\n const values = data\n .map((row) => row[property])\n .filter((v) => v !== null && v !== undefined);\n\n const isNumeric = values.length > 0 && values.every((v) => typeof v === 'number');\n\n if (isNumeric) {\n const min = Math.min(...values);\n const max = Math.max(...values);\n return { type: 'numeric', min, max, values };\n }\n\n const uniqueValues = [...new Set(values)];\n return { type: 'categorical', categories: uniqueValues, values };\n}\n\n/**\n * Compute per-property statistics for all non-geometry columns.\n *\n * @param {Array<Object>} data - Block model data array\n * @returns {Object} Map of ``propertyName → stats`` (same shape as\n * :func:`calculatePropertyStats` return value)\n */\nexport function getBlockStats(data) {\n if (!data || data.length === 0) return {};\n const propertyKeys = Object.keys(data[0]).filter(\n (key) => !GEOMETRY_COLS.includes(key)\n );\n const result = {};\n propertyKeys.forEach((key) => {\n result[key] = calculatePropertyStats(data, key);\n });\n return result;\n}\n\n// ---------------------------------------------------------------------------\n// Filtering and volume\n// ---------------------------------------------------------------------------\n\n/**\n * Filter block model rows by attribute criteria.\n *\n * @param {Array<Object>} data - Block model data array\n * @param {Object} criteria - Map of ``columnName → condition``.\n * Each condition may be:\n * - A scalar (exact equality)\n * - An object with operator keys: ``gt``, ``gte``, ``lt``, ``lte``,\n * ``eq``, ``ne``, ``in`` (array)\n * @returns {Array<Object>} Filtered array of block rows\n */\nexport function filterBlocks(data, criteria) {\n if (!criteria || typeof criteria !== 'object') return data;\n return data.filter((row) =>\n Object.entries(criteria).every(([col, condition]) => {\n const val = row[col];\n if (condition === null || condition === undefined) return true;\n if (typeof condition !== 'object' || Array.isArray(condition)) {\n return val === condition;\n }\n if ('gt' in condition && !(val > condition.gt)) return false;\n if ('gte' in condition && !(val >= condition.gte)) return false;\n if ('lt' in condition && !(val < condition.lt)) return false;\n if ('lte' in condition && !(val <= condition.lte)) return false;\n if ('eq' in condition && val !== condition.eq) return false;\n if ('ne' in condition && val === condition.ne) return false;\n if ('in' in condition && !condition.in.includes(val)) return false;\n return true;\n })\n );\n}\n\n/**\n * Calculate total block volume, optionally filtered by criteria.\n *\n * @param {Array<Object>} data - Block model data array (canonical column names)\n * @param {Object|null} [criteria] - Optional filter criteria (see :func:`filterBlocks`)\n * @returns {number} Sum of dx * dy * dz for matching blocks\n */\nexport function calculateBlockVolume(data, criteria = null) {\n const subset = criteria ? filterBlocks(data, criteria) : data;\n return subset.reduce((sum, row) => {\n const dx = Number(row.dx) || 0;\n const dy = Number(row.dy) || 0;\n const dz = Number(row.dz) || 0;\n return sum + dx * dy * dz;\n }, 0);\n}\n\n// ---------------------------------------------------------------------------\n// Colorisation\n// ---------------------------------------------------------------------------\n\n/**\n * Generate a color for a property value based on its statistics.\n *\n * @param {*} value - Property value to colourise\n * @param {{type: 'numeric'|'categorical', min?: number, max?: number,\n * categories?: Array}|null} stats - Property statistics\n * @param {Object} THREEInstance - THREE.js instance for creating Color objects\n * @returns {THREE.Color} Color object for the value\n */\nexport function getColorForValue(value, stats, THREEInstance) {\n if (!stats) return new THREEInstance.Color('#888888');\n\n if (stats.type === 'numeric') {\n const range = stats.max - stats.min;\n const normalized = range === 0 ? 0.5 : (value - stats.min) / range;\n const hue = (1 - normalized) * 240; // blue=240, red=0\n return new THREEInstance.Color().setHSL(hue / 360, 0.8, 0.5);\n }\n\n const index = stats.categories.indexOf(value);\n const hue = (index / Math.max(stats.categories.length, 1)) * 360;\n return new THREEInstance.Color().setHSL(hue / 360, 0.7, 0.5);\n}\n","/*\n * Copyright (C) 2026 Darkmine Pty Ltd\n * SPDX-License-Identifier: GPL-3.0-or-later\n */\n\n/**\n * Interpolate a 3D position and drill direction along a desurveyed trace.\n *\n * @param {Array<{hole_id: string, md: number, x: number, y: number, z: number, azimuth?: number, dip?: number}>} sortedTraceRows\n * Trace points sorted ascending by md.\n * @param {number} targetMd - Measured depth to interpolate at.\n * @returns {{x: number, y: number, z: number, dx: number, dy: number, dz: number}|null}\n * Position and unit drill direction (dz negative = downward), or null if not possible.\n */\nexport function interpolateTrace(sortedTraceRows, targetMd) {\n if (!sortedTraceRows || sortedTraceRows.length === 0) return null;\n if (!Number.isFinite(targetMd)) return null;\n\n const n = sortedTraceRows.length;\n\n if (n === 1) {\n const p = sortedTraceRows[0];\n return { x: Number(p.x), y: Number(p.y), z: Number(p.z), dx: 0, dy: 0, dz: -1 };\n }\n\n // Find enclosing segment\n let segIdx = -1;\n for (let i = 0; i < n - 1; i++) {\n const md0 = Number(sortedTraceRows[i].md);\n const md1 = Number(sortedTraceRows[i + 1].md);\n if (targetMd >= md0 && targetMd <= md1) {\n segIdx = i;\n break;\n }\n }\n\n let p0, p1, t;\n\n if (segIdx === -1) {\n if (targetMd < Number(sortedTraceRows[0].md)) {\n // Before first point — extrapolate using first segment\n p0 = sortedTraceRows[0];\n p1 = sortedTraceRows[1];\n } else {\n // Beyond last point — extend using last segment\n p0 = sortedTraceRows[n - 2];\n p1 = sortedTraceRows[n - 1];\n }\n const md0 = Number(p0.md);\n const md1 = Number(p1.md);\n const segLen = md1 - md0;\n t = segLen > 0 ? (targetMd - md0) / segLen : (targetMd < md0 ? 0 : 1);\n } else {\n p0 = sortedTraceRows[segIdx];\n p1 = sortedTraceRows[segIdx + 1];\n const md0 = Number(p0.md);\n const md1 = Number(p1.md);\n const segLen = md1 - md0;\n t = segLen > 0 ? (targetMd - md0) / segLen : 0;\n }\n\n const x = Number(p0.x) + t * (Number(p1.x) - Number(p0.x));\n const y = Number(p0.y) + t * (Number(p1.y) - Number(p0.y));\n const z = Number(p0.z) + t * (Number(p1.z) - Number(p0.z));\n\n // Compute drill direction: prefer azimuth/dip, fall back to finite differences\n let dx, dy, dz;\n const az0 = Number(p0.azimuth);\n const dip0 = Number(p0.dip);\n const az1 = Number(p1.azimuth);\n const dip1 = Number(p1.dip);\n\n if (Number.isFinite(az0) && Number.isFinite(dip0)) {\n const az = Number.isFinite(az1) && Number.isFinite(dip1)\n ? az0 + t * (az1 - az0)\n : az0;\n const dip = Number.isFinite(az1) && Number.isFinite(dip1)\n ? dip0 + t * (dip1 - dip0)\n : dip0;\n const azRad = (az * Math.PI) / 180;\n const dipRad = (dip * Math.PI) / 180;\n // Match directionCosines convention: dz = -sin(dip) (downward positive)\n dx = Math.cos(dipRad) * Math.sin(azRad);\n dy = Math.cos(dipRad) * Math.cos(azRad);\n dz = -Math.sin(dipRad);\n } else {\n // Finite difference from segment\n const ddx = Number(p1.x) - Number(p0.x);\n const ddy = Number(p1.y) - Number(p0.y);\n const ddz = Number(p1.z) - Number(p0.z);\n const len = Math.sqrt(ddx * ddx + ddy * ddy + ddz * ddz);\n if (len < 1e-10) return { x, y, z, dx: 0, dy: 0, dz: -1 };\n dx = ddx / len;\n dy = ddy / len;\n dz = ddz / len;\n }\n\n // Normalize direction\n const dlen = Math.sqrt(dx * dx + dy * dy + dz * dz);\n if (dlen < 1e-10) return { x, y, z, dx: 0, dy: 0, dz: -1 };\n return { x, y, z, dx: dx / dlen, dy: dy / dlen, dz: dz / dlen };\n}\n\n/**\n * Convert core-relative alpha/beta angles to a geographic plane normal.\n *\n * The drill frame:\n * D = unit drill direction (positive = downward along hole)\n * R = normalize(cross(U, D)) where U = (0,0,1) or fallback (0,1,0)\n * B = normalize(cross(D, R))\n *\n * Sanity checks:\n * alpha=90 → N perpendicular to D\n * alpha=0 → N parallel to D\n *\n * @param {number} alphaDeg - Alpha angle in degrees; 90 = plane perpendicular to drill axis.\n * @param {number} betaDeg - Beta angle in degrees; rotation of reference mark around drill axis.\n * @param {{dx: number, dy: number, dz: number}} drillDir - Unit drill direction vector.\n * @param {Object} [opts]\n * @param {'R'|'B'} [opts.betaZeroAxis='B'] - Frame axis corresponding to beta=0.\n * @param {number} [opts.betaHandedness=1] - +1 for right-hand rotation, -1 for left-hand.\n * @returns {{nx: number, ny: number, nz: number}} Unit normal vector in ENU coordinates.\n */\nexport function alphaBetaToNormal(alphaDeg, betaDeg, drillDir, opts = {}) {\n const { betaZeroAxis = 'B', betaHandedness = 1 } = opts;\n const { dx, dy, dz } = drillDir;\n const D = [dx, dy, dz];\n\n // Up vector with fallback when D is nearly vertical\n let U = [0, 0, 1];\n const dotDU = D[0] * U[0] + D[1] * U[1] + D[2] * U[2];\n if (Math.abs(dotDU) > 0.99) {\n U = [0, 1, 0];\n }\n\n // R = normalize(cross(U, D))\n const crossUD = [\n U[1] * D[2] - U[2] * D[1],\n U[2] * D[0] - U[0] * D[2],\n U[0] * D[1] - U[1] * D[0],\n ];\n const crossUDLen = Math.sqrt(crossUD[0] ** 2 + crossUD[1] ** 2 + crossUD[2] ** 2);\n const R = crossUDLen > 1e-10\n ? [crossUD[0] / crossUDLen, crossUD[1] / crossUDLen, crossUD[2] / crossUDLen]\n : [1, 0, 0];\n\n // B = normalize(cross(D, R))\n const crossDR = [\n D[1] * R[2] - D[2] * R[1],\n D[2] * R[0] - D[0] * R[2],\n D[0] * R[1] - D[1] * R[0],\n ];\n const crossDRLen = Math.sqrt(crossDR[0] ** 2 + crossDR[1] ** 2 + crossDR[2] ** 2);\n const B = crossDRLen > 1e-10\n ? [crossDR[0] / crossDRLen, crossDR[1] / crossDRLen, crossDR[2] / crossDRLen]\n : [0, 1, 0];\n\n // Starting axis for beta rotation\n const N_perp0 = betaZeroAxis === 'R' ? R : B;\n\n // Rodrigues rotation: rotate N_perp0 around D by (beta * betaHandedness) radians\n const betaRad = (betaDeg * Math.PI) / 180 * betaHandedness;\n const cosB = Math.cos(betaRad);\n const sinB = Math.sin(betaRad);\n const dotND = N_perp0[0] * D[0] + N_perp0[1] * D[1] + N_perp0[2] * D[2];\n const crossDN = [\n D[1] * N_perp0[2] - D[2] * N_perp0[1],\n D[2] * N_perp0[0] - D[0] * N_perp0[2],\n D[0] * N_perp0[1] - D[1] * N_perp0[0],\n ];\n const N_perp = [\n N_perp0[0] * cosB + crossDN[0] * sinB + D[0] * dotND * (1 - cosB),\n N_perp0[1] * cosB + crossDN[1] * sinB + D[1] * dotND * (1 - cosB),\n N_perp0[2] * cosB + crossDN[2] * sinB + D[2] * dotND * (1 - cosB),\n ];\n\n // theta = (90 - alpha) * pi/180; N = normalize(cos(theta)*N_perp + sin(theta)*D)\n const theta = ((90 - alphaDeg) * Math.PI) / 180;\n const cosT = Math.cos(theta);\n const sinT = Math.sin(theta);\n const Nx = cosT * N_perp[0] + sinT * D[0];\n const Ny = cosT * N_perp[1] + sinT * D[1];\n const Nz = cosT * N_perp[2] + sinT * D[2];\n\n const NLen = Math.sqrt(Nx * Nx + Ny * Ny + Nz * Nz);\n if (NLen < 1e-10) return { nx: 0, ny: 0, nz: 1 };\n return { nx: Nx / NLen, ny: Ny / NLen, nz: Nz / NLen };\n}\n\n/**\n * Compute 3D positions and plane normals for structural measurements.\n *\n * Prioritises alpha/beta core angles over geographic dip/azimuth.\n * Rows with no matching trace or missing required fields are excluded.\n *\n * @param {Array<Object>} structures - Flat rows with {hole_id, depth?, mid?, alpha?, beta?, dip?, azimuth?, ...}\n * @param {Array<Object>} traceRows - Flat rows with {hole_id, md, x, y, z, azimuth?, dip?}\n * @param {Object} [opts] - Options forwarded to alphaBetaToNormal.\n * @returns {Array<Object>} Structure rows enriched with {x, y, z, nx, ny, nz}.\n */\nexport function computeStructuralPositions(structures, traceRows, opts = {}) {\n if (!structures?.length || !traceRows?.length) return [];\n\n // Group trace rows by hole_id (lowercase) sorted ascending by md\n const tracesByHole = new Map();\n for (const row of traceRows) {\n const holeId = row.hole_id != null ? `${row.hole_id}`.trim().toLowerCase() : '';\n if (!holeId) continue;\n if (!tracesByHole.has(holeId)) tracesByHole.set(holeId, []);\n tracesByHole.get(holeId).push(row);\n }\n for (const [, rows] of tracesByHole) {\n rows.sort((a, b) => Number(a.md) - Number(b.md));\n }\n\n const result = [];\n for (const s of structures) {\n const holeId = s.hole_id != null ? `${s.hole_id}`.trim().toLowerCase() : '';\n if (!holeId) continue;\n\n const holeTrace = tracesByHole.get(holeId);\n if (!holeTrace || holeTrace.length === 0) continue;\n\n const depth = s.depth != null ? Number(s.depth) : (s.mid != null ? Number(s.mid) : null);\n if (!Number.isFinite(depth)) continue;\n\n const pos = interpolateTrace(holeTrace, depth);\n if (!pos) continue;\n\n const { x, y, z, dx, dy, dz } = pos;\n\n let nx, ny, nz;\n const alpha = s.alpha != null ? Number(s.alpha) : null;\n const beta = s.beta != null ? Number(s.beta) : null;\n\n if (Number.isFinite(alpha)) {\n const betaVal = Number.isFinite(beta) ? beta : 0;\n const n = alphaBetaToNormal(alpha, betaVal, { dx, dy, dz }, opts);\n nx = n.nx;\n ny = n.ny;\n nz = n.nz;\n } else {\n const dip = s.dip != null ? Number(s.dip) : null;\n const az = s.azimuth != null ? Number(s.azimuth) : null;\n if (!Number.isFinite(dip) || !Number.isFinite(az)) continue;\n // Geographic formula matching dipAzimuthToNormal in structuralScene.js\n const dipRad = (dip * Math.PI) / 180;\n const azRad = (az * Math.PI) / 180;\n nx = Math.sin(azRad) * Math.sin(dipRad);\n ny = Math.cos(azRad) * Math.sin(dipRad);\n nz = Math.cos(dipRad);\n }\n\n result.push({ ...s, x, y, z, nx, ny, nz });\n }\n\n return result;\n}\n","/*\n * Copyright (C) 2026 Darkmine Pty Ltd\n * SPDX-License-Identifier: GPL-3.0-or-later\n */\n\n/**\n * Baselode Light Plotly template.\n *\n * Defines the Baselode visual identity for Plotly charts. Apply this template\n * by including it in the layout object passed to Plotly:\n *\n * ```js\n * import { BASELODE_TEMPLATE } from 'baselode';\n * Plotly.react(el, data, { ...layout, template: BASELODE_TEMPLATE });\n * ```\n *\n * Baselode plotting helpers apply this template by default. Pass a different\n * template as an option to override the visual style.\n */\n\n/** @type {string} Name of the Baselode Plotly template. */\nexport const BASELODE_TEMPLATE_NAME = 'baselode';\n\n/** @type {string} Alias for the Baselode Light template name. */\nexport const BASELODE_LIGHT_TEMPLATE_NAME = BASELODE_TEMPLATE_NAME;\n\n/** @type {string[]} Default colorway used across Baselode charts. */\nexport const BASELODE_COLORWAY = [\n '#8b1e3f',\n '#2563eb',\n '#16a34a',\n '#f59e0b',\n '#7c3aed',\n '#0ea5e9',\n '#ef4444',\n '#10b981',\n '#f97316',\n '#8b5cf6',\n];\n\n/** @type {Object} Baselode Light colour palette. */\nexport const BASELODE_LIGHT = {\n bg: '#ffffff',\n panel: '#f8fafc',\n ink: '#1e293b',\n ink_soft: '#64748b',\n grid: '#e8e8e8',\n line: '#d0d0d0',\n accent: '#f59e0b',\n accent_2: '#fcd34d',\n muted_1: '#94a3b8',\n muted_2: '#cbd5e1',\n muted_3: '#e2e8f0',\n primary: '#8b1e3f',\n primary_2: '#a8324f',\n};\n\n/**\n * Baselode Plotly template object.\n *\n * This object can be passed directly as the ``template`` property of a Plotly\n * layout to apply Baselode's default visual style. Baselode plotting helpers\n * include this template in their returned layout objects automatically.\n *\n * @type {Object}\n */\nexport const BASELODE_TEMPLATE = {\n layout: {\n paper_bgcolor: BASELODE_LIGHT.bg,\n plot_bgcolor: BASELODE_LIGHT.bg,\n colorway: BASELODE_COLORWAY,\n font: {\n family: 'Inter, system-ui, sans-serif',\n size: 12,\n color: BASELODE_LIGHT.ink,\n },\n title: {\n font: { size: 14, color: BASELODE_LIGHT.ink },\n x: 0.05,\n },\n hovermode: 'x unified',\n hoverlabel: {\n bgcolor: BASELODE_LIGHT.bg,\n bordercolor: BASELODE_LIGHT.line,\n font: { size: 12, color: BASELODE_LIGHT.ink },\n },\n legend: {\n bgcolor: 'rgba(255,255,255,0.9)',\n bordercolor: BASELODE_LIGHT.muted_3,\n borderwidth: 1,\n font: { size: 11, color: BASELODE_LIGHT.ink },\n orientation: 'h',\n yanchor: 'bottom',\n y: 1.02,\n xanchor: 'left',\n x: 0.0,\n },\n xaxis: {\n showline: true,\n linewidth: 1,\n linecolor: BASELODE_LIGHT.line,\n mirror: false,\n ticks: 'outside',\n tickwidth: 1,\n tickcolor: BASELODE_LIGHT.line,\n ticklen: 4,\n showgrid: true,\n gridcolor: BASELODE_LIGHT.grid,\n gridwidth: 1,\n zeroline: false,\n title_font: { color: BASELODE_LIGHT.ink, size: 12 },\n tickfont: { color: BASELODE_LIGHT.ink_soft, size: 10 },\n },\n yaxis: {\n showline: true,\n linewidth: 1,\n linecolor: BASELODE_LIGHT.line,\n mirror: false,\n ticks: 'outside',\n tickwidth: 1,\n tickcolor: BASELODE_LIGHT.line,\n ticklen: 4,\n showgrid: true,\n gridcolor: BASELODE_LIGHT.grid,\n gridwidth: 1,\n zeroline: false,\n title_font: { color: BASELODE_LIGHT.ink, size: 12 },\n tickfont: { color: BASELODE_LIGHT.ink_soft, size: 10 },\n },\n modebar: {\n remove: ['select2d', 'lasso2d', 'autoScale2d'],\n },\n bargap: 0.18,\n bargroupgap: 0.08,\n },\n data: {\n scatter: [{\n mode: 'lines+markers',\n line: { width: 2, color: BASELODE_LIGHT.primary },\n marker: {\n size: 7,\n color: BASELODE_LIGHT.primary_2,\n line: { width: 1.5, color: BASELODE_LIGHT.bg },\n },\n }],\n bar: [{\n marker: {\n color: BASELODE_LIGHT.primary,\n line: { color: BASELODE_LIGHT.bg, width: 0 },\n },\n }],\n histogram: [{\n marker: {\n color: BASELODE_LIGHT.primary,\n line: { color: BASELODE_LIGHT.bg, width: 0 },\n },\n }],\n box: [{\n fillcolor: BASELODE_LIGHT.accent,\n line: { color: BASELODE_LIGHT.ink, width: 1.5 },\n marker: { color: BASELODE_LIGHT.ink },\n }],\n violin: [{\n fillcolor: BASELODE_LIGHT.accent,\n line: { color: BASELODE_LIGHT.ink, width: 1.5 },\n marker: { color: BASELODE_LIGHT.ink },\n }],\n heatmap: [{\n colorscale: [\n [0.00, '#ffffff'],\n [0.20, '#f1f5f9'],\n [0.40, '#cbd5e1'],\n [0.60, '#94a3b8'],\n [0.80, '#475569'],\n [1.00, '#1e293b'],\n ],\n colorbar: {\n outlinecolor: BASELODE_LIGHT.line,\n tickcolor: BASELODE_LIGHT.line,\n tickfont: { color: BASELODE_LIGHT.ink_soft },\n },\n }],\n contour: [{\n colorscale: [\n [0.00, '#ffffff'],\n [0.25, '#fef3c7'],\n [0.50, '#f59e0b'],\n [0.75, '#92400e'],\n [1.00, '#1e293b'],\n ],\n colorbar: {\n outlinecolor: BASELODE_LIGHT.line,\n tickcolor: BASELODE_LIGHT.line,\n tickfont: { color: BASELODE_LIGHT.ink_soft },\n },\n }],\n },\n};\n\n/** @type {Object} Alias for {@link BASELODE_TEMPLATE} — the Baselode Light theme. */\nexport const BASELODE_LIGHT_TEMPLATE = BASELODE_TEMPLATE;\n","/*\n * Copyright (C) 2026 Darkmine Pty Ltd\n * SPDX-License-Identifier: GPL-3.0-or-later\n */\n\n/**\n * Baselode Dark Plotly template.\n *\n * Applies the Baselode Dark visual identity: dark warm backgrounds, Inter\n * typography, subtle warm grid lines, and light ink primary colours accented\n * with the signature highlight yellow.\n *\n * ```js\n * import { BASELODE_DARK_TEMPLATE } from 'baselode';\n * Plotly.react(el, data, { ...layout, template: BASELODE_DARK_TEMPLATE });\n * ```\n */\n\n/** @type {Object} Baselode Dark colour palette. */\nexport const BASELODE_DARK = {\n bg: '#1b1b1f',\n panel: '#25252a',\n ink: '#f0f0e4',\n ink_soft: '#c8c8b8',\n grid: '#2a2a26',\n line: '#3a3a34',\n accent: '#ffffbb',\n accent_2: '#f3ef9b',\n muted_1: '#8a8a80',\n muted_2: '#5e5e56',\n muted_3: '#3a3a34',\n};\n\n/** @type {string} Name key for the Baselode Dark template. */\nexport const BASELODE_DARK_TEMPLATE_NAME = 'baselode-dark';\n\n/**\n * Baselode Dark Plotly template object.\n *\n * Pass directly as the ``template`` property of a Plotly layout to apply\n * the Baselode Dark visual style.\n *\n * @type {Object}\n */\nexport const BASELODE_DARK_TEMPLATE = {\n layout: {\n font: {\n family: 'Inter, system-ui, sans-serif',\n color: BASELODE_DARK.ink,\n size: 12,\n },\n title: {\n x: 0.05,\n font: {\n family: 'Inter, system-ui, sans-serif',\n size: 14,\n color: BASELODE_DARK.ink,\n },\n },\n paper_bgcolor: BASELODE_DARK.bg,\n plot_bgcolor: BASELODE_DARK.bg,\n colorway: [\n BASELODE_DARK.ink,\n BASELODE_DARK.accent,\n BASELODE_DARK.muted_1,\n BASELODE_DARK.accent_2,\n BASELODE_DARK.muted_2,\n BASELODE_DARK.muted_3,\n ],\n margin: { l: 70, r: 30, t: 70, b: 60 },\n hovermode: 'x unified',\n hoverlabel: {\n bgcolor: BASELODE_DARK.panel,\n bordercolor: BASELODE_DARK.accent,\n font: {\n family: 'Inter, system-ui, sans-serif',\n color: BASELODE_DARK.ink,\n size: 12,\n },\n },\n legend: {\n bgcolor: 'rgba(37,37,42,0.88)',\n bordercolor: BASELODE_DARK.line,\n borderwidth: 1,\n font: {\n family: 'Inter, system-ui, sans-serif',\n color: BASELODE_DARK.ink,\n size: 11,\n },\n orientation: 'h',\n yanchor: 'bottom',\n y: 1.02,\n xanchor: 'left',\n x: 0.0,\n },\n xaxis: {\n showline: true,\n linewidth: 1,\n linecolor: BASELODE_DARK.line,\n mirror: false,\n ticks: 'outside',\n tickwidth: 1,\n tickcolor: BASELODE_DARK.muted_1,\n ticklen: 6,\n showgrid: true,\n gridcolor: BASELODE_DARK.grid,\n gridwidth: 1,\n zeroline: false,\n title_font: { color: BASELODE_DARK.ink, size: 12 },\n tickfont: { color: BASELODE_DARK.ink_soft, size: 10 },\n },\n yaxis: {\n showline: true,\n linewidth: 1,\n linecolor: BASELODE_DARK.line,\n mirror: false,\n ticks: 'outside',\n tickwidth: 1,\n tickcolor: BASELODE_DARK.muted_1,\n ticklen: 6,\n showgrid: true,\n gridcolor: BASELODE_DARK.grid,\n gridwidth: 1,\n zeroline: false,\n title_font: { color: BASELODE_DARK.ink, size: 12 },\n tickfont: { color: BASELODE_DARK.ink_soft, size: 10 },\n },\n bargap: 0.18,\n bargroupgap: 0.08,\n },\n data: {\n scatter: [{\n mode: 'lines+markers',\n line: { width: 2.5, color: BASELODE_DARK.ink },\n marker: {\n size: 7,\n color: BASELODE_DARK.ink,\n line: { width: 1.5, color: BASELODE_DARK.bg },\n },\n }],\n bar: [{\n marker: {\n color: BASELODE_DARK.ink,\n line: { color: BASELODE_DARK.bg, width: 0 },\n },\n }],\n histogram: [{\n marker: {\n color: BASELODE_DARK.ink,\n line: { color: BASELODE_DARK.bg, width: 0 },\n },\n }],\n box: [{\n fillcolor: BASELODE_DARK.accent,\n line: { color: BASELODE_DARK.ink, width: 1.5 },\n marker: { color: BASELODE_DARK.ink },\n }],\n violin: [{\n fillcolor: BASELODE_DARK.accent,\n line: { color: BASELODE_DARK.ink, width: 1.5 },\n marker: { color: BASELODE_DARK.ink },\n }],\n heatmap: [{\n colorscale: [\n [0.00, '#1b1b1f'],\n [0.20, '#2e2e28'],\n [0.40, '#5e5e50'],\n [0.60, '#c8c89a'],\n [0.80, '#f3ef9b'],\n [1.00, '#ffffbb'],\n ],\n colorbar: {\n outlinecolor: BASELODE_DARK.ink,\n tickcolor: BASELODE_DARK.ink,\n tickfont: { color: BASELODE_DARK.ink_soft },\n },\n }],\n contour: [{\n colorscale: [\n [0.00, '#1b1b1f'],\n [0.25, '#2e2e28'],\n [0.50, '#6b6b50'],\n [0.75, '#f3ef9b'],\n [1.00, '#ffffbb'],\n ],\n colorbar: {\n outlinecolor: BASELODE_DARK.ink,\n tickcolor: BASELODE_DARK.ink,\n tickfont: { color: BASELODE_DARK.ink_soft },\n },\n }],\n },\n};\n","/*\n * Copyright (C) 2026 Darkmine Pty Ltd\n * SPDX-License-Identifier: GPL-3.0-or-later\n */\n\n/**\n * Semantic colour mapping system for Baselode graphs.\n *\n * This module provides the **semantic colour mapping** layer of Baselode graph\n * styling. Plotly templates handle overall chart appearance (fonts, layout,\n * backgrounds); this module maps *domain values* (commodities, lithologies,\n * categorical logging data) to specific colours.\n *\n * Built-in maps ship sensible defaults. Users can supply their own\n * dictionaries or override individual entries via {@link resolveColourMap}.\n *\n * @module colourMap\n */\n\n/**\n * Fallback colour used when a value is absent from any colour map.\n * @type {string}\n */\nexport const FALLBACK_COLOUR = '#7f7f7f';\n\n/**\n * Built-in semantic colours for common commodity / assay elements.\n * @type {Object.<string, string>}\n */\nexport const COMMODITY_COLOURS = {\n Au: '#FFD700', // gold\n Ag: '#C0C0C0', // silver\n Cu: '#B87333', // copper / orange-brown\n Fe: '#8B4513', // iron / rusty brown\n Ni: '#4CAF50', // nickel / green\n Zn: '#78909C', // zinc / blue-grey\n Pb: '#607D8B', // lead / slate\n Mo: '#9C27B0', // molybdenite / purple\n Co: '#2196F3', // cobalt / blue\n Li: '#FF5722', // lithium / deep orange\n Mn: '#795548', // manganese / brown\n Cr: '#009688', // chromium / teal\n V: '#673AB7', // vanadium / deep purple\n W: '#FF9800', // tungsten / amber\n Sn: '#9E9E9E', // tin / medium grey\n Ti: '#00BCD4', // titanium / cyan\n Al: '#FFEB3B', // aluminium / yellow\n U: '#8BC34A', // uranium / lime green\n};\n\n/**\n * Built-in semantic colours for common lithology categories.\n * @type {Object.<string, string>}\n */\nexport const LITHOLOGY_COLOURS = {\n // Sedimentary\n shale: '#607D8B',\n mudstone: '#78909C',\n siltstone: '#90A4AE',\n sandstone: '#F5CBA7',\n limestone: '#B0BEC5',\n dolomite: '#CFD8DC',\n conglomerate: '#D7CCC8',\n coal: '#212121',\n // Iron-formation\n BIF: '#8B4513',\n ironstone: '#A0522D',\n // Igneous – intrusive\n granite: '#EF9A9A',\n granodiorite: '#F48FB1',\n diorite: '#CE93D8',\n gabbro: '#546E7A',\n peridotite: '#33691E',\n pegmatite: '#FFF9C4',\n // Igneous – extrusive / volcanic\n basalt: '#37474F',\n andesite: '#78909C',\n rhyolite: '#FFCCBC',\n dacite: '#FFAB91',\n tuff: '#D7CCC8',\n breccia: '#BCAAA4',\n // Metamorphic\n schist: '#80CBC4',\n gneiss: '#4DB6AC',\n quartzite: '#E0F7FA',\n marble: '#F5F5F5',\n slate: '#455A64',\n phyllite: '#80DEEA',\n // Other\n quartz: '#ECEFF1',\n calcite: '#F9FBE7',\n vein: '#FFFFFF',\n unknown: '#9E9E9E',\n};\n\n/**\n * Registry of all built-in colour maps, keyed by lower-case name.\n * @type {Object.<string, Object.<string, string>>}\n */\nexport const BUILTIN_COLOUR_MAPS = {\n commodity: COMMODITY_COLOURS,\n lithology: LITHOLOGY_COLOURS,\n};\n\n/**\n * Return the colour for *value* from *colourMap*, or *fallback* if absent.\n *\n * The lookup is case-insensitive: both *value* and map keys are trimmed and\n * lower-cased before comparison.\n *\n * @param {string} value - Domain value to look up (e.g. `\"Cu\"`, `\"granite\"`).\n * @param {Object.<string, string>} colourMap - Mapping of domain values to CSS colour strings.\n * @param {string} [fallback=FALLBACK_COLOUR] - Colour to return when *value* is not found.\n * @returns {string} A CSS colour string.\n */\nexport function getColour(value, colourMap, fallback = FALLBACK_COLOUR) {\n if (!colourMap || value == null) return fallback;\n const key = String(value).trim();\n // Exact match first\n if (Object.prototype.hasOwnProperty.call(colourMap, key)) return colourMap[key];\n // Case-insensitive match\n const keyLower = key.toLowerCase();\n for (const [mapKey, mapColour] of Object.entries(colourMap)) {\n if (String(mapKey).trim().toLowerCase() === keyLower) return mapColour;\n }\n return fallback;\n}\n\n/**\n * Return a colour map object from a name or pass through a user-supplied object.\n *\n * @param {string|Object.<string, string>|null|undefined} nameOrMap\n * - `null` / `undefined`: returns an empty object.\n * - A `string`: looked up in {@link BUILTIN_COLOUR_MAPS}. Unknown names\n * throw a `RangeError`.\n * - An `object`: returned as-is (user-supplied mapping).\n * @returns {Object.<string, string>} Colour map object.\n * @throws {RangeError} If *nameOrMap* is a string that does not match any built-in map.\n * @throws {TypeError} If *nameOrMap* is not `null`, a string, or a plain object.\n */\nexport function resolveColourMap(nameOrMap) {\n if (nameOrMap == null) return {};\n if (typeof nameOrMap === 'string') {\n const key = nameOrMap.trim().toLowerCase();\n if (Object.prototype.hasOwnProperty.call(BUILTIN_COLOUR_MAPS, key)) {\n return BUILTIN_COLOUR_MAPS[key];\n }\n const available = Object.keys(BUILTIN_COLOUR_MAPS).sort().join(', ');\n throw new RangeError(\n `Unknown built-in colour map '${nameOrMap}'. Available maps: ${available}`\n );\n }\n if (\n typeof nameOrMap === 'object' &&\n Object.getPrototypeOf(nameOrMap) === Object.prototype\n ) return nameOrMap;\n throw new TypeError(\n `colourMap must be null, a string, or a plain object; got ${\n Array.isArray(nameOrMap) ? 'Array' : Object.prototype.toString.call(nameOrMap)\n }`\n );\n}\n","/*\n * Copyright (C) 2026 Darkmine Pty Ltd\n * SPDX-License-Identifier: GPL-3.0-or-later\n */\n// Shared drillhole 2D visualization helpers for reuse beyond the UI layer.\n// These helpers build Plotly-ready data/layout objects based on interval points.\n\nimport { getColour, resolveColourMap, COMMODITY_COLOURS } from './colourMap.js';\nimport { BASELODE_TEMPLATE } from './baselodeTemplate.js';\n\n/** Default color for numeric line traces */\nexport const NUMERIC_LINE_COLOR = '#8b1e3f';\n\n/** Default color for numeric markers */\nexport const NUMERIC_MARKER_COLOR = '#a8324f';\n\n/**\n * Auto-detect a commodity colour for a column name such as \"Au_ppm\" or \"Cu_eq\".\n * Splits on `_`, `-`, `/`, or whitespace and checks each token against\n * COMMODITY_COLOURS (exact match first, then case-insensitive).\n * Returns null when no commodity element is recognised.\n * @param {string} property\n * @returns {string|null}\n */\nfunction commodityColourForProperty(property) {\n if (!property) return null;\n const tokens = property.split(/[_\\-/\\s]+/);\n for (const token of tokens) {\n if (Object.prototype.hasOwnProperty.call(COMMODITY_COLOURS, token)) {\n return COMMODITY_COLOURS[token];\n }\n const low = token.toLowerCase();\n for (const [key, colour] of Object.entries(COMMODITY_COLOURS)) {\n if (key.toLowerCase() === low) return colour;\n }\n }\n return null;\n}\n\n/** Color for error bars */\nexport const ERROR_COLOR = '#6b7280';\n\n/** Default compact strip-log margins */\nexport const STRIPLOG_COMPACT_MARGIN = { l: 42, r: 4, t: 4, b: 36 };\n\n/** Default strip-log axis tick size */\nexport const STRIPLOG_AXIS_TICK_FONT_SIZE = 10;\n\n/** Default strip-log axis title size */\nexport const STRIPLOG_AXIS_TITLE_FONT_SIZE = 11;\n\n/** Spacing between the base x-axis tick labels and its title (pixels) */\nexport const STRIPLOG_XAXIS_TITLE_STANDOFF = 6;\n\nfunction normalizeAxisTitle(t) {\n if (!t) return {};\n return typeof t === 'string' ? { text: t } : t;\n}\n\nfunction applyStriplogLayoutDefaults(layout = {}) {\n const xTitle = normalizeAxisTitle(layout.xaxis && layout.xaxis.title);\n const yTitle = normalizeAxisTitle(layout.yaxis && layout.yaxis.title);\n return {\n ...layout,\n margin: STRIPLOG_COMPACT_MARGIN,\n autosize: true,\n width: undefined,\n xaxis: {\n ...(layout.xaxis || {}),\n tickfont: {\n ...((layout.xaxis && layout.xaxis.tickfont) || {}),\n size: STRIPLOG_AXIS_TICK_FONT_SIZE,\n },\n title: {\n ...xTitle,\n font: { ...(xTitle.font || {}), size: STRIPLOG_AXIS_TITLE_FONT_SIZE },\n standoff: xTitle.standoff ?? STRIPLOG_XAXIS_TITLE_STANDOFF,\n },\n },\n yaxis: {\n ...(layout.yaxis || {}),\n automargin: true,\n tickfont: {\n ...((layout.yaxis && layout.yaxis.tickfont) || {}),\n size: STRIPLOG_AXIS_TICK_FONT_SIZE,\n },\n title: {\n ...yTitle,\n font: { ...(yTitle.font || {}), size: STRIPLOG_AXIS_TITLE_FONT_SIZE },\n },\n },\n };\n}\n\n/**\n * Check if a hole has data for a specific property\n * @param {Object} hole - Hole object with points array\n * @param {string} property - Property name to check\n * @returns {boolean} True if hole has at least one valid value for the property\n */\nexport function holeHasData(hole, property) {\n if (!hole || !property) return false;\n const pts = hole.points || [];\n for (let i = 0; i < pts.length; i += 1) {\n const value = pts[i]?.[property];\n if (value === undefined || value === null) continue;\n if (typeof value === 'number' && Number.isFinite(value)) return true;\n if (typeof value === 'string' && value.trim() !== '') return true;\n }\n return false;\n}\n\n/**\n * Build array of interval points for visualization from hole data\n * Extracts depth intervals and property values, deduplicates, and sorts by depth\n * @param {Object} hole - Hole object with points array\n * @param {string} property - Property name to extract\n * @param {boolean} isCategorical - Whether property is categorical (vs numeric)\n * @returns {Array<{z: number, val: *, from: number, to: number, errorPlus: number, errorMinus: number}>} Array of interval points\n */\nexport function buildIntervalPoints(hole, property, isCategorical) {\n if (!hole || !property) return [];\n const rawPoints = hole?.points || [];\n const out = [];\n const seen = new Set();\n rawPoints.forEach((p) => {\n let fromVal = Number(\n p.from ??\n p.samp_from ??\n p.sample_from ??\n p.fromdepth ??\n p.from_depth ??\n p.depth_from\n );\n let toVal = Number(\n p.to ??\n p.samp_to ??\n p.sample_to ??\n p.todepth ??\n p.to_depth ??\n p.depth_to\n );\n // Fall back to depth for point-schema data (e.g. structural measurements)\n if (!Number.isFinite(fromVal) || !Number.isFinite(toVal)) {\n const depthVal = Number(p.depth ?? p.md);\n if (Number.isFinite(depthVal)) {\n fromVal = depthVal;\n toVal = depthVal;\n }\n }\n const rawVal = p?.[property];\n if (!Number.isFinite(fromVal) || !Number.isFinite(toVal) || toVal < fromVal) return;\n if (rawVal === undefined || rawVal === null || rawVal === '') return;\n if (isCategorical && typeof rawVal === 'string' && /^(nan|null|none)$/i.test(rawVal.trim())) return;\n const key = `${property}:${fromVal}-${toVal}:${String(rawVal)}`;\n if (seen.has(key)) return;\n seen.add(key);\n const mid = (fromVal + toVal) / 2;\n const val = isCategorical ? rawVal : Number(rawVal);\n if (!isCategorical && !Number.isFinite(val)) return;\n out.push({\n z: mid,\n val,\n from: fromVal,\n to: toVal,\n errorPlus: toVal - mid,\n errorMinus: mid - fromVal\n });\n });\n return out.sort((a, b) => b.z - a.z);\n}\n\n/**\n * Build Plotly configuration for categorical property visualization\n * @private\n * @param {Array<Object>} points - Interval points array\n * @param {string} property - Property name for title\n * @param {Object|string|null} [colourMap] - Optional semantic colour map (object or built-in name)\n * @param {Object} [template] - Plotly template to include in layout\n * @returns {{data: Array, layout: Object}} Plotly data and layout configuration\n */\nfunction buildCategoricalConfig(points, property, colourMap, template) {\n if (!points.length) return { data: [], layout: {} };\n const safe = points\n .filter((point) => Number.isFinite(point?.from) && Number.isFinite(point?.to) && point.to > point.from)\n .map((point) => ({ ...point, category: `${point?.val ?? ''}`.trim() }))\n .filter((point) => point.category !== '' && !/^(nan|null|none)$/i.test(point.category))\n .sort((a, b) => a.from - b.from || a.to - b.to);\n\n if (!safe.length) return { data: [], layout: {} };\n\n const resolvedCmap = resolveColourMap(colourMap);\n\n const fallbackPalette = [\n '#1f77b4', // blue\n '#ff7f0e', // orange\n '#2ca02c', // green\n '#d62728', // red\n '#9467bd', // purple\n '#17becf', // cyan\n '#bcbd22', // olive\n '#e377c2', // pink\n '#8c564b', // brown\n '#393b79', // indigo\n '#e6550d', // deep orange\n '#31a354', // deep green\n '#756bb1', // violet\n '#636363', // dark gray\n ];\n const uniqueCategories = [...new Set(safe.map((point) => point.category))];\n\n function pickColour(cat, idx) {\n if (resolvedCmap && Object.keys(resolvedCmap).length > 0) {\n const c = getColour(cat, resolvedCmap, null);\n if (c !== null) return c;\n }\n return fallbackPalette[idx % fallbackPalette.length];\n }\n\n const colorByCategory = new Map(\n uniqueCategories.map((category, idx) => [category, pickColour(category, idx)])\n );\n\n // One bar trace per unique category. Each bar starts at `base` (from depth)\n // and has height (to - from). barmode:'overlay' lets non-overlapping intervals\n // from different traces coexist at the same x position.\n const traces = uniqueCategories.map((cat) => {\n const intervals = safe.filter((seg) => seg.category === cat);\n return {\n type: 'bar',\n x: intervals.map(() => 0.5),\n y: intervals.map((s) => s.to - s.from),\n base: intervals.map((s) => s.from),\n width: 1,\n marker: { color: colorByCategory.get(cat), line: { width: 0 } },\n name: cat,\n showlegend: false,\n customdata: intervals.map((s) => [s.from, s.to]),\n hovertemplate: `${property}: ${cat}<br>from: %{customdata[0]:.3f} to: %{customdata[1]:.3f}<extra></extra>`,\n };\n });\n\n const layout = {\n barmode: 'overlay',\n bargap: 0,\n xaxis: { range: [0, 1], visible: false, fixedrange: true },\n yaxis: { title: 'Depth (m)', autorange: 'reversed', zeroline: false },\n showlegend: false,\n title: property || undefined,\n template: template !== undefined ? template : BASELODE_TEMPLATE,\n };\n\n return { data: traces, layout: applyStriplogLayoutDefaults(layout) };\n}\n\n/**\n * Build Plotly configuration for numeric property visualization\n * @private\n * @param {Array<Object>} points - Interval points array\n * @param {string} property - Property name for axis label\n * @param {string} chartType - Chart type ('bar', 'markers', 'line', 'markers+line')\n * @param {string} [color] - Override colour for line/markers (e.g. commodity colour)\n * @param {Object} [template] - Plotly template to include in layout\n * @returns {{data: Array, layout: Object}} Plotly data and layout configuration\n */\nfunction buildNumericConfig(points, property, chartType, color, template) {\n if (!points.length) return { data: [], layout: {} };\n const isBar = chartType === 'bar';\n const isMarkersOnly = chartType === 'markers';\n const isLineOnly = chartType === 'line';\n\n const lineColor = color || NUMERIC_LINE_COLOR;\n const markerColor = color || NUMERIC_MARKER_COLOR;\n\n const baseTrace = {\n x: points.map((p) => p.val),\n y: points.map((p) => p.z),\n hovertemplate: `${property}: %{x}<br>from: %{customdata[0]:.3f} to: %{customdata[1]:.3f}<extra></extra>`,\n customdata: points.map((p) => [Math.min(p.from, p.to), Math.max(p.from, p.to)])\n };\n\n const errorConfig = {\n type: 'data',\n symmetric: false,\n array: points.map((p) => p.errorPlus),\n arrayminus: points.map((p) => p.errorMinus),\n thickness: 1.5,\n width: 2,\n color: ERROR_COLOR\n };\n\n const trace = isBar\n ? {\n ...baseTrace,\n type: 'bar',\n orientation: 'h',\n marker: { color: lineColor },\n error_y: errorConfig\n }\n : {\n ...baseTrace,\n type: 'scatter',\n mode: isMarkersOnly ? 'markers' : isLineOnly ? 'lines' : 'lines+markers',\n line: { color: lineColor, width: 2 },\n marker: { size: 7, color: markerColor },\n error_y: isLineOnly ? undefined : errorConfig\n };\n\n const layout = {\n xaxis: { title: property, zeroline: false },\n yaxis: { title: 'Depth (m)', autorange: 'reversed', zeroline: false },\n barmode: 'overlay',\n showlegend: false,\n template: template !== undefined ? template : BASELODE_TEMPLATE,\n };\n\n return { data: [trace], layout: applyStriplogLayoutDefaults(layout) };\n}\n\n/**\n * Build complete Plotly configuration for property visualization\n * @param {Object} options - Configuration options\n * @param {Array<Object>} options.points - Interval points to visualize\n * @param {boolean} options.isCategorical - Whether property is categorical\n * @param {string} options.property - Property name\n * @param {string} options.chartType - Chart type ('bar', 'markers', 'line', 'categorical', etc.)\n * @param {Object|string|null} [options.colourMap] - Optional semantic colour map (object or built-in name)\n * @param {Object} [options.template] - Plotly template to apply. Defaults to the Baselode template.\n * @returns {{data: Array, layout: Object}} Complete Plotly configuration\n */\nexport function buildPlotConfig({ points, isCategorical, property, chartType, colourMap, template }) {\n if (!points || !points.length || !property) return { data: [], layout: {} };\n if (isCategorical || chartType === 'categorical') {\n return buildCategoricalConfig(points, property, colourMap, template);\n }\n const colour = commodityColourForProperty(property);\n return buildNumericConfig(points, property, chartType, colour, template);\n}\n\n/**\n * Build a categorical strip-log Plotly config directly from interval rows.\n * @param {Array<Object>} rows - Interval rows (e.g. geology)\n * @param {Object} options - Field mapping options\n * @param {string} options.fromCol - From-depth column\n * @param {string} options.toCol - To-depth column\n * @param {string} options.categoryCol - Category label column\n * @param {Object|string|null} [options.colourMap] - Optional semantic colour map (object or built-in name)\n * @param {Object} [options.template] - Plotly template to apply. Defaults to the Baselode template.\n * @returns {{data: Array, layout: Object}} Plotly configuration for strip-log rendering\n */\nexport function buildCategoricalStripLogConfig(\n rows = [],\n {\n fromCol = 'from',\n toCol = 'to',\n categoryCol = 'geology_code',\n colourMap = null,\n template = undefined,\n } = {}\n) {\n const points = [];\n rows.forEach((row) => {\n const from = Number(row?.[fromCol]);\n const to = Number(row?.[toCol]);\n const category = row?.[categoryCol];\n if (!Number.isFinite(from) || !Number.isFinite(to) || to <= from) return;\n if (category === undefined || category === null || `${category}`.trim() === '') return;\n const mid = (from + to) / 2;\n points.push({\n z: mid,\n val: `${category}`,\n from,\n to,\n errorPlus: to - mid,\n errorMinus: mid - from\n });\n });\n\n points.sort((a, b) => b.z - a.z);\n return buildPlotConfig({\n points,\n isCategorical: true,\n property: categoryCol,\n chartType: 'categorical',\n colourMap,\n template,\n });\n}\n","/*\n * Copyright (C) 2026 Darkmine Pty Ltd\n * SPDX-License-Identifier: GPL-3.0-or-later\n */\n\n/** Default 10-color palette for assay visualization (blue to red gradient) */\nexport const ASSAY_COLOR_PALETTE_10 = [\n '#313695',\n '#4575b4',\n '#74add1',\n '#abd9e9',\n '#e0f3f8',\n '#fee090',\n '#fdae61',\n '#f46d43',\n '#d73027',\n '#a50026'\n];\n\n/**\n * Build an equal-range color scale from numeric values\n * Uses percentile-based binning for better distribution with outliers\n * @param {Array<number>} values - Array of numeric values to analyze\n * @param {Array<string>} colors - Array of color hex strings to use for bins\n * @returns {{min: number|null, max: number|null, step: number|null, bins: Array<{index: number, min: number, max: number, label: string}>, colors: Array<string>}} Color scale object\n */\nexport function buildEqualRangeColorScale(values = [], colors = ASSAY_COLOR_PALETTE_10) {\n // Filter to finite values and sort\n const finiteValues = values.filter((v) => Number.isFinite(v));\n \n if (!finiteValues.length) {\n return {\n min: null,\n max: null,\n step: null,\n bins: [],\n colors\n };\n }\n\n const sorted = finiteValues.slice().sort((a, b) => a - b);\n const min = sorted[0];\n const max = sorted[sorted.length - 1];\n const binCount = colors.length;\n\n if (max === min) {\n const bins = colors.map((_, index) => ({\n index,\n min,\n max,\n label: `${min}`\n }));\n return {\n min,\n max,\n step: 0,\n bins,\n colors\n };\n }\n\n // Use percentile-based binning for better distribution\n const bins = colors.map((_, index) => {\n const percentileLow = index / binCount;\n const percentileHigh = (index + 1) / binCount;\n const idxLow = Math.floor(percentileLow * sorted.length);\n const idxHigh = Math.min(sorted.length - 1, Math.floor(percentileHigh * sorted.length));\n const lower = sorted[idxLow];\n const upper = index === binCount - 1 ? max : sorted[idxHigh];\n \n return {\n index,\n min: lower,\n max: upper,\n label: formatBinLabel(lower, upper)\n };\n });\n\n const step = (max - min) / binCount;\n\n return {\n min,\n max,\n step,\n bins,\n colors\n };\n}\n\n/**\n * Format bin label with appropriate precision\n * @private\n */\nfunction formatBinLabel(min, max) {\n const formatVal = (v) => {\n if (!Number.isFinite(v)) return 'n/a';\n if (Math.abs(v) >= 1000) return v.toFixed(0);\n if (Math.abs(v) >= 10) return v.toFixed(1);\n if (Math.abs(v) >= 0.1) return v.toFixed(2);\n return v.toFixed(3);\n };\n return `${formatVal(min)} – ${formatVal(max)}`;\n}\n\n/**\n * Get the bin index for a value in a color scale\n * @param {number} value - Value to find bin for\n * @param {Object} scale - Color scale object from buildEqualRangeColorScale\n * @returns {number} Bin index (0 to bins.length-1) or -1 if invalid\n */\nexport function getEqualRangeBinIndex(value, scale) {\n if (!Number.isFinite(value) || !scale || !Array.isArray(scale.bins) || !scale.bins.length) {\n return -1;\n }\n\n if (scale.max === scale.min) {\n return value === scale.min ? 0 : -1;\n }\n\n // Find the bin that contains this value\n for (let i = 0; i < scale.bins.length; i += 1) {\n const bin = scale.bins[i];\n if (value >= bin.min && (value <= bin.max || i === scale.bins.length - 1)) {\n return i;\n }\n }\n\n // Value is out of range\n return -1;\n}\n\n/**\n * Get the color for a value using an equal-range color scale\n * @param {number} value - Value to get color for\n * @param {Object} scale - Color scale object from buildEqualRangeColorScale\n * @param {string} fallbackColor - Color to use if value is invalid or out of range\n * @returns {string} Color hex string\n */\nexport function getEqualRangeColor(value, scale, fallbackColor = '#8b1e3f') {\n const index = getEqualRangeBinIndex(value, scale);\n if (index < 0) return fallbackColor;\n return scale.colors[index] || fallbackColor;\n}\n","/*\n * Copyright (C) 2026 Darkmine Pty Ltd\n * SPDX-License-Identifier: GPL-3.0-or-later\n */\n\n/**\n * Rebuild `sceneCtx.selectables` from all renderable mesh lists.\n * Called after any data-type module adds or removes objects from the scene.\n *\n * @param {object} sceneCtx - Baselode3DScene instance\n */\nexport function syncSelectables(sceneCtx) {\n sceneCtx.selectables = [\n ...sceneCtx.blocks,\n ...sceneCtx.drillMeshes,\n ...sceneCtx.structuralMeshes,\n ];\n}\n","/*\n * Copyright (C) 2026 Darkmine Pty Ltd\n * SPDX-License-Identifier: GPL-3.0-or-later\n */\nimport * as THREE from 'three';\nimport { AZIMUTH, DIP } from '../data/datamodel.js';\nimport { computeStructuralPositions } from '../data/structuralPositions.js';\nimport { syncSelectables } from './sceneSelectables.js';\n\nconst DEFAULT_COLOR_MAP = {\n bedding: '#2563eb',\n foliation: '#16a34a',\n joint: '#9333ea',\n fault: '#dc2626',\n vein: '#f59e0b',\n 'shear zone': '#0ea5e9',\n 'fault zone': '#ef4444',\n};\n\n/**\n * Resolve a color string for a structure type from a color map.\n * @private\n * @param {string|null} structureType\n * @param {Object|null} colorMap\n * @returns {number} THREE.js hex color integer\n */\nfunction resolveColor(structureType, colorMap) {\n const map = colorMap || DEFAULT_COLOR_MAP;\n const key = (structureType || '').toLowerCase().trim();\n const hex = map[key] || '#888888';\n return new THREE.Color(hex).getHex();\n}\n\n/**\n * Compute a disc plane normal vector from dip and azimuth in ENU coordinates.\n *\n * Convention: azimuth is clockwise from North, dip is measured from horizontal.\n * The normal points upward (positive Z in elevation-positive convention).\n *\n * @param {number} dip - Dip angle in degrees [0, 90]\n * @param {number} azimuth - Dip direction azimuth in degrees [0, 360)\n * @returns {THREE.Vector3} Unit normal vector in ENU coordinates\n */\nexport function dipAzimuthToNormal(dip, azimuth) {\n const dipRad = (dip * Math.PI) / 180;\n const azRad = (azimuth * Math.PI) / 180;\n return new THREE.Vector3(\n Math.sin(azRad) * Math.sin(dipRad), // East component\n Math.cos(azRad) * Math.sin(dipRad), // North component\n Math.cos(dipRad) // Up component\n ).normalize();\n}\n\n/**\n * Build Three.js disc meshes for structural measurements.\n *\n * Each structural measurement with valid 3D coordinates is rendered as a\n * thin cylinder (disc) oriented perpendicular to the plane normal derived\n * from the dip/azimuth values.\n *\n * userData is set on each mesh for hover/picking support.\n *\n * @param {Array<Object>} structures - Each row must have x/easting, y/northing, z/elevation,\n * dip, and azimuth fields.\n * @param {Object} opts\n * @param {number} [opts.radius=5] - Disc radius in scene units\n * @param {number} [opts.discThickness=0.2] - Disc thickness in scene units\n * @param {number} [opts.opacity=0.7] - Material opacity [0, 1]\n * @param {number} [opts.segments=32] - Cylinder radial segments (higher = smoother)\n * @param {Object|null} [opts.colorMap] - Map from defect string to hex color string\n * @returns {THREE.Group} Group containing one Mesh per valid measurement\n */\nexport function buildStructuralDiscs(structures, opts = {}) {\n const {\n radius = 5,\n discThickness = 0.2,\n opacity = 0.7,\n segments = 32,\n colorMap = null,\n } = opts;\n\n const group = new THREE.Group();\n const yAxis = new THREE.Vector3(0, 1, 0);\n\n for (const s of structures) {\n const xVal = s.x != null ? s.x : (s.easting != null ? s.easting : null);\n const yVal = s.y != null ? s.y : (s.northing != null ? s.northing : null);\n const zVal = s.z != null ? s.z : (s.elevation != null ? s.elevation : null);\n\n if (xVal == null || yVal == null || zVal == null) continue;\n if (!Number.isFinite(xVal) || !Number.isFinite(yVal) || !Number.isFinite(zVal)) continue;\n\n const dipVal = s[DIP] != null ? Number(s[DIP]) : null;\n const azVal = s[AZIMUTH] != null ? Number(s[AZIMUTH]) : null;\n\n let normal;\n if (s.nx != null && Number.isFinite(s.nx) && s.ny != null && Number.isFinite(s.ny) && s.nz != null && Number.isFinite(s.nz)) {\n normal = new THREE.Vector3(s.nx, s.ny, s.nz).normalize();\n } else {\n if (dipVal == null || azVal == null || !Number.isFinite(dipVal) || !Number.isFinite(azVal)) continue;\n normal = dipAzimuthToNormal(dipVal, azVal);\n }\n\n const geom = new THREE.CylinderGeometry(radius, radius, discThickness, segments, 1, false);\n const mat = new THREE.MeshStandardMaterial({\n color: resolveColor(s['structure_type'], colorMap),\n transparent: true,\n opacity,\n side: THREE.DoubleSide,\n });\n\n const mesh = new THREE.Mesh(geom, mat);\n mesh.position.set(xVal, yVal, zVal);\n\n // CylinderGeometry default axis is Y; rotate so Y aligns with normal\n mesh.quaternion.setFromUnitVectors(yAxis, normal);\n\n mesh.userData = {\n type: 'structure',\n hole_id: s.hole_id,\n depth: s.depth ?? s.mid,\n structure_type: s['structure_type'],\n dip: dipVal,\n azimuth: azVal,\n comments: s.comments,\n };\n\n group.add(mesh);\n }\n\n return group;\n}\n\n// ---------------------------------------------------------------------------\n// Scene-level functions (operate on a Baselode3DScene instance)\n// ---------------------------------------------------------------------------\n\n/**\n * Compute positions for structural measurements and add disc meshes to the scene.\n *\n * @param {object} sceneCtx - Baselode3DScene instance\n * @param {Array} structures - Structural measurement rows\n * @param {Array} holes - Desurveyed hole objects with `points`\n * @param {object} [opts]\n * @param {number} [opts.maxDiscs=3000] - Cap on rendered discs for performance\n */\nexport function setStructuralDiscs(sceneCtx, structures, holes, opts = {}) {\n if (!sceneCtx.scene) return;\n clearStructuralDiscs(sceneCtx);\n if (!structures?.length || !holes?.length) return;\n\n const { maxDiscs = 3000 } = opts;\n let input = structures;\n if (input.length > maxDiscs) {\n const step = input.length / maxDiscs;\n const sampled = [];\n for (let i = 0; i < maxDiscs; i++) {\n sampled.push(input[Math.floor(i * step)]);\n }\n input = sampled;\n }\n\n const traceRows = holes.flatMap(h => (h.points || []).map(p => ({ ...p, hole_id: h.id })));\n const enriched = computeStructuralPositions(input, traceRows, opts);\n if (!enriched.length) return;\n\n sceneCtx.structuralGroup = buildStructuralDiscs(enriched, opts);\n sceneCtx.scene.add(sceneCtx.structuralGroup);\n sceneCtx.structuralGroup.traverse(child => {\n if (child.isMesh) sceneCtx.structuralMeshes.push(child);\n });\n syncSelectables(sceneCtx);\n}\n\n/**\n * Remove all structural disc meshes from the scene and dispose GPU resources.\n *\n * @param {object} sceneCtx - Baselode3DScene instance\n */\nexport function clearStructuralDiscs(sceneCtx) {\n if (sceneCtx.structuralGroup) {\n sceneCtx.scene.remove(sceneCtx.structuralGroup);\n sceneCtx.structuralGroup.traverse(child => {\n if (child.isMesh) {\n child.geometry.dispose();\n child.material.dispose();\n }\n });\n sceneCtx.structuralGroup = null;\n }\n sceneCtx.structuralMeshes = [];\n syncSelectables(sceneCtx);\n}\n\n/**\n * Show or hide the structural discs group.\n *\n * @param {object} sceneCtx - Baselode3DScene instance\n * @param {boolean} visible\n */\nexport function setStructuralDiscsVisible(sceneCtx, visible) {\n if (sceneCtx.structuralGroup) {\n sceneCtx.structuralGroup.visible = Boolean(visible);\n }\n}\n","/*\n * Copyright (C) 2026 Darkmine Pty Ltd\n * SPDX-License-Identifier: GPL-3.0-or-later\n */\nimport * as THREE from 'three';\n\nlet _overlayIdCounter = 0;\n\n/**\n * Normalize caller-supplied bounds to the canonical { minX, minY, maxX, maxY } form.\n * Accepts either { minX, minY, maxX, maxY } or { x, y, width, height }.\n *\n * @param {object} bounds\n * @returns {{ minX: number, minY: number, maxX: number, maxY: number }}\n * @throws {Error} if the resulting width or height is zero or negative\n */\nexport function normalizeBounds(bounds) {\n let minX, minY, maxX, maxY;\n\n if ('width' in bounds || 'height' in bounds || ('x' in bounds && !('maxX' in bounds))) {\n const x = Number(bounds.x ?? 0);\n const y = Number(bounds.y ?? 0);\n const width = Number(bounds.width ?? 0);\n const height = Number(bounds.height ?? 0);\n minX = x;\n minY = y;\n maxX = x + width;\n maxY = y + height;\n } else {\n minX = Number(bounds.minX);\n minY = Number(bounds.minY);\n maxX = Number(bounds.maxX);\n maxY = Number(bounds.maxY);\n }\n\n if (maxX - minX <= 0) {\n throw new Error(\n `Invalid raster bounds: width must be positive (got minX=${minX}, maxX=${maxX})`\n );\n }\n if (maxY - minY <= 0) {\n throw new Error(\n `Invalid raster bounds: height must be positive (got minY=${minY}, maxY=${maxY})`\n );\n }\n\n return { minX, minY, maxX, maxY };\n}\n\n/**\n * Load a THREE.Texture from a source descriptor.\n *\n * Supported source types:\n * - `{ type: 'url', url: string }` – load from a URL or data URI\n * - `{ type: 'file', file: File }` – load from a browser File object\n * - `{ type: 'texture', texture: THREE.Texture }` – use a pre-built texture\n *\n * @param {{ type: string, url?: string, file?: File, texture?: THREE.Texture }} source\n * @returns {Promise<THREE.Texture>}\n */\nfunction loadTexture(source) {\n if (source.type === 'texture') {\n return Promise.resolve(source.texture);\n }\n\n let url;\n let createdObjectUrl = false;\n\n if (source.type === 'url') {\n url = source.url;\n } else if (source.type === 'file') {\n url = URL.createObjectURL(source.file);\n createdObjectUrl = true;\n } else {\n return Promise.reject(\n new Error(`Unsupported raster source type: \"${source.type}\"`)\n );\n }\n\n return new Promise((resolve, reject) => {\n const loader = new THREE.TextureLoader();\n loader.load(\n url,\n (texture) => {\n if (createdObjectUrl) URL.revokeObjectURL(url);\n resolve(texture);\n },\n undefined,\n (err) => {\n if (createdObjectUrl) URL.revokeObjectURL(url);\n reject(\n new Error(\n `Failed to load raster texture from \"${url}\": ${err?.message ?? err}`\n )\n );\n }\n );\n });\n}\n\n/**\n * Create a raster overlay layer from the supplied options.\n *\n * The overlay is returned as a self-contained layer descriptor object. Add it\n * to a scene with addRasterOverlay().\n *\n * Placement: the image is rendered as a flat plane on the X/Y axis at the\n * given elevation. The left edge aligns with minX, the right with maxX, the\n * bottom with minY, and the top with maxY. Image orientation follows\n * THREE.js default texture behaviour (flipY=true), so north-up map images\n * are placed correctly without any additional rotation.\n *\n * @param {object} options\n * @param {string} [options.id] - Unique identifier; auto-generated if omitted\n * @param {string} [options.name] - Human-readable display name\n * @param {{ type: string }} options.source - Image source descriptor\n * @param {object} options.bounds - Placement bounds\n * @param {number} [options.elevation=0] - Z position in scene units\n * @param {number} [options.opacity=1] - Initial opacity [0, 1]; clamped if out of range\n * @param {boolean} [options.visible=true] - Initial visibility\n * @param {number} [options.renderOrder=0] - THREE.js renderOrder for draw-order control\n * @returns {Promise<object>} Raster overlay layer descriptor\n */\nexport async function createRasterOverlay(options) {\n const { source, bounds, elevation = 0, visible = true, renderOrder = 0 } = options;\n\n const id = options.id ?? `raster-overlay-${++_overlayIdCounter}`;\n const name = options.name ?? id;\n\n let opacity = options.opacity ?? 1;\n if (opacity < 0 || opacity > 1) {\n console.warn(\n `[baselode] raster overlay \"${id}\": opacity ${opacity} is outside [0, 1] — clamped`\n );\n opacity = Math.max(0, Math.min(1, opacity));\n }\n\n if (!source) throw new Error('raster overlay: options.source is required');\n if (!bounds) throw new Error('raster overlay: options.bounds is required');\n\n const normalizedBounds = normalizeBounds(bounds);\n const { minX, minY, maxX, maxY } = normalizedBounds;\n\n const width = maxX - minX;\n const height = maxY - minY;\n const centerX = (minX + maxX) / 2;\n const centerY = (minY + maxY) / 2;\n\n const texture = await loadTexture(source);\n\n // PlaneGeometry lies in the XY plane by default. THREE.js TextureLoader sets\n // flipY=true, which means the image top-row maps to world maxY and the\n // image bottom-row maps to world minY — correct for north-up map images.\n const geometry = new THREE.PlaneGeometry(width, height);\n const material = new THREE.MeshBasicMaterial({\n map: texture,\n transparent: true,\n opacity,\n side: THREE.DoubleSide,\n depthWrite: false,\n });\n\n const mesh = new THREE.Mesh(geometry, material);\n mesh.position.set(centerX, centerY, elevation);\n mesh.renderOrder = renderOrder;\n mesh.visible = visible;\n\n return { id, name, mesh, texture, bounds: normalizedBounds, elevation, opacity, visible };\n}\n\n// ---------------------------------------------------------------------------\n// Scene-level helpers — all operate on a Baselode3DScene instance\n// ---------------------------------------------------------------------------\n\n/**\n * Add a raster overlay layer to the scene.\n *\n * The layer must have been created with createRasterOverlay(). Duplicate ids\n * replace the existing entry (the old mesh is removed and disposed first).\n *\n * @param {object} sceneCtx - Baselode3DScene instance\n * @param {object} layer - Layer returned by createRasterOverlay()\n */\nexport function addRasterOverlay(sceneCtx, layer) {\n if (!sceneCtx.scene) return;\n if (sceneCtx.rasterOverlays.has(layer.id)) {\n removeRasterOverlay(sceneCtx, layer.id);\n }\n sceneCtx.rasterOverlays.set(layer.id, layer);\n sceneCtx.scene.add(layer.mesh);\n}\n\n/**\n * Remove a raster overlay from the scene and dispose its GPU resources.\n *\n * @param {object} sceneCtx - Baselode3DScene instance\n * @param {string} id - Overlay id\n */\nexport function removeRasterOverlay(sceneCtx, id) {\n const layer = sceneCtx.rasterOverlays.get(id);\n if (!layer) return;\n sceneCtx.scene?.remove(layer.mesh);\n layer.mesh.geometry.dispose();\n layer.mesh.material.dispose();\n if (layer.texture) layer.texture.dispose();\n sceneCtx.rasterOverlays.delete(id);\n}\n\n/**\n * Set the opacity of a raster overlay at runtime without recreating geometry.\n *\n * @param {object} sceneCtx - Baselode3DScene instance\n * @param {string} id - Overlay id\n * @param {number} opacity - New opacity [0, 1]; clamped if out of range\n */\nexport function setRasterOverlayOpacity(sceneCtx, id, opacity) {\n const layer = sceneCtx.rasterOverlays.get(id);\n if (!layer) return;\n const clamped = Math.max(0, Math.min(1, Number(opacity)));\n layer.opacity = clamped;\n layer.mesh.material.opacity = clamped;\n layer.mesh.material.needsUpdate = true;\n}\n\n/**\n * Show or hide a raster overlay without destroying it.\n *\n * @param {object} sceneCtx - Baselode3DScene instance\n * @param {string} id - Overlay id\n * @param {boolean} visible\n */\nexport function setRasterOverlayVisibility(sceneCtx, id, visible) {\n const layer = sceneCtx.rasterOverlays.get(id);\n if (!layer) return;\n layer.visible = Boolean(visible);\n layer.mesh.visible = layer.visible;\n}\n\n/**\n * Update the elevation (Z position) of a raster overlay at runtime.\n *\n * @param {object} sceneCtx - Baselode3DScene instance\n * @param {string} id - Overlay id\n * @param {number} elevation\n */\nexport function setRasterOverlayElevation(sceneCtx, id, elevation) {\n const layer = sceneCtx.rasterOverlays.get(id);\n if (!layer) return;\n layer.elevation = Number(elevation);\n layer.mesh.position.setZ(layer.elevation);\n}\n\n/**\n * Get a raster overlay by id, or undefined if not found.\n *\n * @param {object} sceneCtx - Baselode3DScene instance\n * @param {string} id\n * @returns {object|undefined}\n */\nexport function getRasterOverlay(sceneCtx, id) {\n return sceneCtx.rasterOverlays.get(id);\n}\n\n/**\n * Return all raster overlay layers in insertion order.\n *\n * @param {object} sceneCtx - Baselode3DScene instance\n * @returns {object[]}\n */\nexport function listRasterOverlays(sceneCtx) {\n return Array.from(sceneCtx.rasterOverlays.values());\n}\n\n/**\n * Remove all raster overlays from the scene and dispose all GPU resources.\n *\n * @param {object} sceneCtx - Baselode3DScene instance\n */\nexport function clearRasterOverlays(sceneCtx) {\n for (const id of [...sceneCtx.rasterOverlays.keys()]) {\n removeRasterOverlay(sceneCtx, id);\n }\n}\n","/*\n * Copyright (C) 2026 Darkmine Pty Ltd\n * SPDX-License-Identifier: GPL-3.0-or-later\n */\n\n/**\n * Build a string signature from view state for comparison (to detect changes)\n * @param {Object} viewState - View state object with camera, target, up vectors\n * @returns {string} String signature representing the view state\n */\nexport function buildViewSignature(viewState) {\n if (!viewState) return '';\n const toNum = (v) => Number.isFinite(v) ? v.toFixed(3) : 'nan';\n return [\n toNum(viewState.camera?.x),\n toNum(viewState.camera?.y),\n toNum(viewState.camera?.z),\n toNum(viewState.target?.x),\n toNum(viewState.target?.y),\n toNum(viewState.target?.z),\n toNum(viewState.up?.x),\n toNum(viewState.up?.y),\n toNum(viewState.up?.z)\n ].join('|');\n}\n\n/**\n * Extract current view state from 3D scene state\n * @param {Object} state - Baselode3D scene state with camera and controls\n * @returns {Object|null} View state object or null if state invalid\n */\nexport function getViewState(state) {\n if (!state.camera || !state.controls) return null;\n return {\n camera: {\n x: state.camera.position.x,\n y: state.camera.position.y,\n z: state.camera.position.z\n },\n target: {\n x: state.controls.target.x,\n y: state.controls.target.y,\n z: state.controls.target.z\n },\n up: {\n x: state.camera.up.x,\n y: state.camera.up.y,\n z: state.camera.up.z\n }\n };\n}\n\n/**\n * Apply a view state to the 3D scene camera and controls\n * @param {Object} state - Baselode3D scene state\n * @param {Object} viewState - View state to apply\n * @returns {boolean} True if successfully applied\n */\nexport function setViewState(state, viewState) {\n if (!state.camera || !state.controls || !viewState) return false;\n const camera = viewState.camera || {};\n const target = viewState.target || {};\n const up = viewState.up || {};\n\n const values = [camera.x, camera.y, camera.z, target.x, target.y, target.z, up.x, up.y, up.z];\n if (!values.every(Number.isFinite)) return false;\n\n state.camera.position.set(camera.x, camera.y, camera.z);\n state.controls.target.set(target.x, target.y, target.z);\n state.camera.up.set(up.x, up.y, up.z);\n state.camera.lookAt(target.x, target.y, target.z);\n state.controls.update();\n state._lastViewSignature = buildViewSignature(viewState);\n return true;\n}\n\n/**\n * Emit view change event if view has changed (throttled to 250ms)\n * @param {Object} state - Baselode3D scene state with viewChangeHandler\n */\nexport function emitViewChangeIfNeeded(state) {\n if (!state.viewChangeHandler) return;\n const now = Date.now();\n if (now - state._lastViewEmitMs < 250) return;\n const viewState = getViewState(state);\n if (!viewState) return;\n const signature = buildViewSignature(viewState);\n if (signature === state._lastViewSignature) return;\n state._lastViewSignature = signature;\n state._lastViewEmitMs = now;\n state.viewChangeHandler(viewState);\n}\n\n/**\n * Fit camera to view all content within specified bounds\n * @param {Object} state - Baselode3D scene state\n * @param {Object} bounds - Bounding box {minX, maxX, minY, maxY, minZ, maxZ}\n */\nexport function fitCameraToBounds(state, { minX, maxX, minY, maxY, minZ, maxZ }) {\n const centerX = (minX + maxX) / 2;\n const centerY = (minY + maxY) / 2;\n const centerZ = (minZ + maxZ) / 2;\n const sizeX = maxX - minX;\n const sizeY = maxY - minY;\n const sizeZ = maxZ - minZ;\n const maxDim = Math.max(sizeX, sizeY, sizeZ, 1);\n const distance = maxDim * 2;\n\n state.controls.target.set(centerX, centerY, centerZ);\n state.camera.position.set(centerX + distance, centerY + distance, centerZ + distance);\n state.camera.lookAt(centerX, centerY, centerZ);\n state.controls.update();\n}\n\n/**\n * Recenter camera to origin at specified distance\n * @param {Object} state - Baselode3D scene state\n * @param {number} distance - Distance from origin\n */\nexport function recenterCameraToOrigin(state, distance = 1000) {\n if (!state.camera || !state.controls) return;\n state.controls.target.set(0, 0, 0);\n state.camera.position.set(distance, distance, distance);\n state.camera.lookAt(0, 0, 0);\n state.controls.update();\n}\n\n/**\n * Position camera looking straight down from above\n * @param {Object} state - Baselode3D scene state\n * @param {number} distance - Distance above origin\n */\nexport function lookDown(state, distance = 2000) {\n if (!state.camera || !state.controls) return;\n state.controls.target.set(0, 0, 0);\n state.camera.position.set(0, 0, distance);\n state.camera.up.set(0, 1, 0);\n state.camera.lookAt(0, 0, 0);\n state.controls.update();\n}\n\n/**\n * Pan the camera view by screen-space delta\n * @param {Object} state - Baselode3D scene state\n * @param {number} dx - Horizontal pan delta\n * @param {number} dy - Vertical pan delta\n */\nexport function pan(state, dx = 0, dy = 0) {\n if (!state.controls) return;\n if (typeof state.controls.pan === 'function') {\n state.controls.pan(dx, dy);\n state.controls.update();\n }\n}\n\n/**\n * Zoom camera in or out by scale factor\n * @param {Object} state - Baselode3D scene state\n * @param {number} scale - Scale factor (>1 zooms out, <1 zooms in)\n */\nexport function dolly(state, scale = 1.1) {\n if (!state.controls || typeof state.controls.dollyIn !== 'function' || typeof state.controls.dollyOut !== 'function') return;\n if (scale > 1) {\n state.controls.dollyOut(scale);\n } else {\n state.controls.dollyIn(1 / scale);\n }\n state.controls.update();\n}\n\n/**\n * Focus camera on last computed bounds with optional padding\n * @param {Object} state - Baselode3D scene state with lastBounds property\n * @param {number} padding - Padding multiplier for bounds (1.2 = 20% larger view)\n */\nexport function focusOnLastBounds(state, padding = 1.2) {\n if (!state.lastBounds) return;\n const {\n minX, maxX, minY, maxY, minZ, maxZ\n } = state.lastBounds;\n const sizeX = (maxX - minX) * padding;\n const sizeY = (maxY - minY) * padding;\n const sizeZ = (maxZ - minZ) * padding;\n const centerX = (minX + maxX) / 2;\n const centerY = (minY + maxY) / 2;\n const centerZ = (minZ + maxZ) / 2;\n const maxDim = Math.max(sizeX, sizeY, sizeZ, 1);\n const distance = maxDim * 2;\n state.controls.target.set(centerX, centerY, centerZ);\n state.camera.position.set(centerX + distance, centerY + distance, centerZ + distance);\n state.camera.lookAt(centerX, centerY, centerZ);\n state.controls.update();\n}\n\n/** Minimum and maximum permitted camera FOV in degrees. */\nexport const FOV_MIN_DEG = 1;\nexport const FOV_MAX_DEG = 120;\n\n/**\n * Change the camera field-of-view while keeping the visible scene the same apparent size.\n * Adjusts camera distance so the frustum height at the orbit target is preserved.\n * FOV is clamped to [FOV_MIN_DEG, FOV_MAX_DEG] to avoid numerical issues near 0° or 180°.\n * @param {Object} state - Baselode3D scene state with camera and controls\n * @param {number} fovDeg - Desired FOV in degrees\n * @returns {boolean} True if the FOV was applied, false if state is invalid\n */\nexport function setFov(state, fovDeg) {\n if (!state.camera || !state.controls) return false;\n if (!Number.isFinite(fovDeg)) return false;\n const clampedFov = Math.min(FOV_MAX_DEG, Math.max(FOV_MIN_DEG, fovDeg));\n\n const target = state.controls.target;\n const currentDist = state.camera.position.distanceTo(target);\n const currentFovRad = (state.camera.fov * Math.PI) / 180;\n const frustumHeight = 2 * currentDist * Math.tan(currentFovRad / 2);\n\n const newFovRad = (clampedFov * Math.PI) / 180;\n const newDist = frustumHeight / (2 * Math.tan(newFovRad / 2));\n\n const dir = state.camera.position.clone().sub(target).normalize();\n state.camera.position.copy(target).addScaledVector(dir, newDist);\n state.camera.fov = clampedFov;\n state.camera.updateProjectionMatrix();\n state.controls.update();\n return true;\n}\n\n/**\n * Switch between orbit and fly camera control modes\n * @param {Object} state - Baselode3D scene state with orbit and fly controls\n * @param {string} mode - Control mode ('orbit' or 'fly')\n */\nexport function setControlMode(state, mode = 'orbit') {\n state.controlMode = mode === 'fly' ? 'fly' : 'orbit';\n if (state.controlMode === 'fly') {\n if (state.controls) state.controls.enabled = false;\n if (state.flyControls) state.flyControls.enabled = true;\n } else {\n if (state.flyControls) state.flyControls.enabled = false;\n if (state.controls) {\n state.controls.enabled = true;\n state.camera.getWorldDirection(state._tmpDir);\n const target = state.camera.position.clone().addScaledVector(state._tmpDir, 10);\n state.controls.target.copy(target);\n state.controls.update();\n }\n }\n}","/*\n * Copyright (C) 2026 Darkmine Pty Ltd\n * SPDX-License-Identifier: GPL-3.0-or-later\n */\nimport * as THREE from 'three';\nimport { buildEqualRangeColorScale, getEqualRangeBinIndex, getEqualRangeColor } from './assayColorScale.js';\nimport { fitCameraToBounds } from './baselode3dCameraControls.js';\nimport { syncSelectables } from './sceneSelectables.js';\n\n/** Default color for low or zero assay values */\nconst LOW_ASSAY_GREY = '#9ca3af';\n\n/**\n * Get measured depth range for a segment between two points\n */\nexport function getMeasuredDepthRange(p1, p2) {\n const md1 = Number(p1?.md);\n const md2 = Number(p2?.md);\n if (!Number.isFinite(md1) || !Number.isFinite(md2)) return null;\n const segStart = Math.min(md1, md2);\n const segEnd = Math.max(md1, md2);\n if (segEnd <= segStart) return null;\n return { segStart, segEnd };\n}\n\n/**\n * Calculate weighted average assay value for a segment overlapping with assay intervals\n */\nexport function getWeightedIntervalValue(assayIntervals, segStart, segEnd) {\n let weightedSum = 0;\n let weightTotal = 0;\n\n for (let i = 0; i < assayIntervals.length; i += 1) {\n const candidate = assayIntervals[i];\n const from = Number(candidate?.from);\n const to = Number(candidate?.to);\n const value = Number(candidate?.value);\n if (!Number.isFinite(from) || !Number.isFinite(to) || !Number.isFinite(value) || to <= from) continue;\n const overlapStart = Math.max(segStart, from);\n const overlapEnd = Math.min(segEnd, to);\n const overlap = overlapEnd - overlapStart;\n if (overlap <= 0) continue;\n weightedSum += value * overlap;\n weightTotal += overlap;\n }\n\n if (weightTotal <= 0) return null;\n const value = weightedSum / weightTotal;\n return Number.isFinite(value) ? value : null;\n}\n\n/**\n * Get THREE.Color for an assay value based on color scale\n */\nexport function getAssaySegmentColor(value, assayScale) {\n if (!Number.isFinite(value)) return new THREE.Color(LOW_ASSAY_GREY);\n const binIndex = getEqualRangeBinIndex(value, assayScale);\n if (binIndex < 0) return new THREE.Color(LOW_ASSAY_GREY);\n const colorHex = getEqualRangeColor(value, assayScale, LOW_ASSAY_GREY);\n return new THREE.Color(colorHex);\n}\n\n/**\n * Get a deterministic hex color for a categorical value using FNV-1a hash → HSL\n */\nexport function getCategoryHexColor(category) {\n if (!category || !String(category).trim()) return LOW_ASSAY_GREY;\n const h = seededUnit(String(category).toLowerCase().trim());\n return '#' + new THREE.Color().setHSL(h, 0.70, 0.50).getHexString();\n}\n\n/**\n * Normalize drillhole rendering options with defaults\n */\nexport function normalizeDrillholeRenderOptions(options = {}) {\n return {\n preserveView: Boolean(options.preserveView),\n assayIntervalsByHole: options.assayIntervalsByHole || null,\n selectedAssayVariable: options.selectedAssayVariable || '',\n isCategoricalVariable: Boolean(options.isCategoricalVariable),\n };\n}\n\n/**\n * Collect all numeric assay values from interval data\n */\nexport function collectAssayValues(assayIntervalsByHole, selectedAssayVariable) {\n if (!assayIntervalsByHole || !selectedAssayVariable) return [];\n const allAssayValues = [];\n Object.values(assayIntervalsByHole).forEach((intervals) => {\n (intervals || []).forEach((interval) => {\n const value = Number(interval?.value);\n if (Number.isFinite(value)) allAssayValues.push(value);\n });\n });\n return allAssayValues;\n}\n\n/**\n * Build user data object for drillhole mesh\n */\nexport function buildHoleUserData(hole) {\n return {\n holeId: hole.id,\n project: hole.project\n };\n}\n\n/**\n * Normalize hole key to lowercase trimmed string for case-insensitive matching\n */\nexport function normalizeHoleKey(value) {\n return `${value ?? ''}`.trim().toLowerCase();\n}\n\n/**\n * Generate a deterministic per-segment color based on hole ID and segment index\n */\nexport function randomSegmentColor(holeId, segmentIndex) {\n const seed = `${holeId ?? ''}:${segmentIndex ?? 0}`;\n const base = seededUnit(seed);\n const band = ((segmentIndex ?? 0) % 14) / 14;\n const hue = (base * 0.15 + band * 0.85) % 1;\n const color = new THREE.Color();\n color.setHSL(hue, 1.0, 0.5);\n return color;\n}\n\n/**\n * Produce a deterministic float in [0, 1) from an input string (FNV-1a hash)\n */\nexport function seededUnit(input) {\n const text = `${input ?? ''}`;\n let hash = 2166136261;\n for (let i = 0; i < text.length; i += 1) {\n hash ^= text.charCodeAt(i);\n hash = Math.imul(hash, 16777619);\n }\n return (hash >>> 0) / 4294967295;\n}\n\n// ---------------------------------------------------------------------------\n// Private helpers (not exported)\n// ---------------------------------------------------------------------------\n\nfunction getDominantCategory(intervals, segStart, segEnd) {\n let best = null;\n let bestOverlap = 0;\n for (const iv of intervals) {\n const from = Number(iv?.from);\n const to = Number(iv?.to);\n if (!Number.isFinite(from) || !Number.isFinite(to)) continue;\n const overlap = Math.min(segEnd, to) - Math.max(segStart, from);\n if (overlap > bestOverlap) { bestOverlap = overlap; best = iv?.value; }\n }\n return best;\n}\n\nfunction resolveAssayIntervalsForHole(hole, assayIntervalsByHole) {\n if (!assayIntervalsByHole || !hole) return [];\n const holeId = hole.id || hole.holeId;\n if (!holeId) return [];\n\n const exact = assayIntervalsByHole[holeId];\n if (Array.isArray(exact) && exact.length) return exact;\n\n const normalized = normalizeHoleKey(holeId);\n if (normalized) {\n const byNormalized = assayIntervalsByHole[normalized];\n if (Array.isArray(byNormalized) && byNormalized.length) return byNormalized;\n }\n\n return [];\n}\n\nfunction getSegmentColor({ selectedAssayVariable, assayIntervals, assayScale, holeId, segmentIndex, p1, p2, isCategorical }) {\n if (!selectedAssayVariable) {\n return randomSegmentColor(holeId, segmentIndex);\n }\n if (selectedAssayVariable === '__HAS_ASSAY__') {\n if (!assayIntervals?.length) return new THREE.Color(LOW_ASSAY_GREY);\n const depthRange = getMeasuredDepthRange(p1, p2);\n if (!depthRange) return new THREE.Color(LOW_ASSAY_GREY);\n const hasData = assayIntervals.some((interval) => {\n const from = Number(interval?.from);\n const to = Number(interval?.to);\n if (!Number.isFinite(from) || !Number.isFinite(to)) return false;\n const overlapStart = Math.max(depthRange.segStart, from);\n const overlapEnd = Math.min(depthRange.segEnd, to);\n return overlapEnd > overlapStart;\n });\n return hasData ? new THREE.Color('#ff8c42') : new THREE.Color(LOW_ASSAY_GREY);\n }\n if (!assayIntervals?.length) return new THREE.Color(LOW_ASSAY_GREY);\n const depthRange = getMeasuredDepthRange(p1, p2);\n if (!depthRange) return new THREE.Color(LOW_ASSAY_GREY);\n if (isCategorical) {\n const cat = getDominantCategory(assayIntervals, depthRange.segStart, depthRange.segEnd);\n return new THREE.Color(getCategoryHexColor(cat));\n }\n const value = getWeightedIntervalValue(assayIntervals, depthRange.segStart, depthRange.segEnd);\n return getAssaySegmentColor(value, assayScale);\n}\n\n// ---------------------------------------------------------------------------\n// Public scene functions\n// ---------------------------------------------------------------------------\n\n/**\n * Build cylinder meshes for all drillholes and add them to the scene.\n *\n * @param {object} sceneCtx - Baselode3DScene instance\n * @param {Array} holes - Array of desurveyed hole objects with `points`\n * @param {object} [options]\n */\nexport function setDrillholes(sceneCtx, holes, options = {}) {\n if (!sceneCtx.scene) return;\n\n clearDrillholes(sceneCtx);\n if (!holes || holes.length === 0) return;\n\n const { preserveView, assayIntervalsByHole, selectedAssayVariable, isCategoricalVariable } = normalizeDrillholeRenderOptions(options);\n const allAssayValues = isCategoricalVariable ? [] : collectAssayValues(assayIntervalsByHole, selectedAssayVariable);\n const assayScale = buildEqualRangeColorScale(allAssayValues);\n\n let minX = Infinity, maxX = -Infinity;\n let minY = Infinity, maxY = -Infinity;\n let minZ = Infinity, maxZ = -Infinity;\n\n const tmpVec = new THREE.Vector3();\n const up = new THREE.Vector3(0, 1, 0);\n\n holes.forEach((hole, idx) => {\n const goldenAngle = 137.5;\n const hue = ((idx * goldenAngle) % 360) / 360;\n const defaultColor = new THREE.Color().setHSL(hue, 0.75, 0.55);\n const points = (hole.points || []).map((p) => {\n minX = Math.min(minX, p.x);\n maxX = Math.max(maxX, p.x);\n minY = Math.min(minY, p.y);\n maxY = Math.max(maxY, p.y);\n minZ = Math.min(minZ, p.z);\n maxZ = Math.max(maxZ, p.z);\n const point = new THREE.Vector3(p.x, p.y, p.z);\n point.md = p.md;\n return point;\n });\n\n if (points.length < 2) {\n if (points.length === 1) {\n const sphereGeom = new THREE.SphereGeometry(5, 12, 12);\n const sphereMat = new THREE.MeshLambertMaterial({\n color: defaultColor,\n emissive: defaultColor,\n emissiveIntensity: 0.2\n });\n const sphere = new THREE.Mesh(sphereGeom, sphereMat);\n sphere.position.copy(points[0]);\n sphere.userData = buildHoleUserData(hole);\n sceneCtx.scene.add(sphere);\n sceneCtx.drillLines.push(sphere);\n sceneCtx.drillMeshes.push(sphere);\n }\n return;\n }\n\n const group = new THREE.Group();\n group.userData = buildHoleUserData(hole);\n const assayIntervals = selectedAssayVariable\n ? resolveAssayIntervalsForHole(hole, assayIntervalsByHole)\n : [];\n\n for (let i = 0; i < points.length - 1; i += 1) {\n const p1 = points[i];\n const p2 = points[i + 1];\n const dir = tmpVec.subVectors(p2, p1);\n const len = dir.length();\n if (len <= 0.001) continue;\n const radius = 2.2;\n const cylinderGeom = new THREE.CylinderGeometry(radius, radius, len, 6, 1, true);\n const segmentColor = getSegmentColor({\n selectedAssayVariable,\n assayIntervals,\n assayScale,\n holeId: hole.id,\n segmentIndex: i,\n p1,\n p2,\n isCategorical: isCategoricalVariable,\n });\n const cylinderMat = new THREE.MeshLambertMaterial({\n color: segmentColor,\n flatShading: true,\n emissive: segmentColor,\n emissiveIntensity: 0.15\n });\n const mesh = new THREE.Mesh(cylinderGeom, cylinderMat);\n mesh.position.copy(p1.clone().addScaledVector(dir, 0.5));\n mesh.quaternion.setFromUnitVectors(up, dir.clone().normalize());\n mesh.userData = buildHoleUserData(hole);\n group.add(mesh);\n sceneCtx.drillMeshes.push(mesh);\n }\n\n sceneCtx.scene.add(group);\n sceneCtx.drillLines.push(group);\n });\n\n if (sceneCtx.camera && sceneCtx.controls) {\n sceneCtx.lastBounds = { minX, maxX, minY, maxY, minZ, maxZ };\n if (!preserveView) {\n fitCameraToBounds(sceneCtx, { minX, maxX, minY, maxY, minZ, maxZ });\n }\n }\n syncSelectables(sceneCtx);\n}\n\n/**\n * Remove all drillhole meshes from the scene and dispose GPU resources.\n *\n * @param {object} sceneCtx - Baselode3DScene instance\n */\nexport function clearDrillholes(sceneCtx) {\n sceneCtx.drillLines.forEach((line) => {\n sceneCtx.scene.remove(line);\n if (line.isGroup) {\n line.traverse((child) => {\n if (child.isMesh) {\n child.geometry.dispose();\n child.material.dispose();\n }\n });\n } else if (line.isMesh) {\n line.geometry.dispose();\n line.material.dispose();\n }\n });\n sceneCtx.drillLines = [];\n sceneCtx.drillMeshes = [];\n syncSelectables(sceneCtx);\n}\n","/*\n * Copyright (C) 2026 Darkmine Pty Ltd\n * SPDX-License-Identifier: GPL-3.0-or-later\n */\nimport * as THREE from 'three';\n\n/**\n * Default panel width in scene units.\n * @type {number}\n */\nexport const STRIP_LOG_DEFAULT_PANEL_WIDTH = 20;\n\n/**\n * Default lateral offset from the drillhole collar in scene units.\n * @type {number}\n */\nexport const STRIP_LOG_DEFAULT_LATERAL_OFFSET = 15;\n\n/**\n * Default line color for the strip log graph.\n * @type {string}\n */\nexport const STRIP_LOG_DEFAULT_COLOR = '#00bcd4';\n\n/**\n * Normalise strip log options with defaults.\n *\n * @param {object} [options]\n * @returns {{ panelWidth: number, lateralOffset: number, color: string, valueMin: number|null, valueMax: number|null }}\n */\nexport function normalizeStripLogOptions(options = {}) {\n return {\n panelWidth: options.panelWidth != null ? Number(options.panelWidth) : STRIP_LOG_DEFAULT_PANEL_WIDTH,\n lateralOffset: options.lateralOffset != null ? Number(options.lateralOffset) : STRIP_LOG_DEFAULT_LATERAL_OFFSET,\n color: options.color || STRIP_LOG_DEFAULT_COLOR,\n valueMin: options.valueMin != null ? Number(options.valueMin) : null,\n valueMax: options.valueMax != null ? Number(options.valueMax) : null,\n };\n}\n\n/**\n * Compute the vertical extent of a hole's points.\n *\n * Returns `{ topY, botY, height }` where `topY >= botY` (Y = elevation in the\n * scene's coordinate system). Returns `null` when the extent is degenerate.\n *\n * @param {Array<{x:number, y:number, z:number}>} points\n * @returns {{ topY: number, botY: number, height: number }|null}\n */\nexport function getHoleVerticalExtent(points) {\n if (!points || points.length < 2) return null;\n let topZ = -Infinity;\n let botZ = Infinity;\n for (const p of points) {\n if (p.z > topZ) topZ = p.z;\n if (p.z < botZ) botZ = p.z;\n }\n const height = topZ - botZ;\n if (height < 0.001) return null;\n return { topZ, botZ, height };\n}\n\n/**\n * Map depth/value data pairs onto panel-local 2D coordinates.\n *\n * Panel-local space: X runs left (min value) to right (max value); Y runs top\n * (shallow) to bottom (deep) along the hole direction. Z = 0.01 offsets the line\n * slightly in front of the panel face. The caller is responsible for applying the\n * panel's world-space quaternion to these local-space points.\n *\n * @param {number[]} depths - downhole measured depths for each sample\n * @param {number[]} values\n * @param {number} panelWidth\n * @param {number} panelHeight - total length of the panel (= hole measured depth at toe)\n * @param {number|null} valueMin - explicit min override (null = auto)\n * @param {number|null} valueMax - explicit max override (null = auto)\n * @param {number|null} depthScale - measured depth at toe used to anchor depth=0 at the\n * collar and scale positions correctly along the hole. When null the depths are\n * auto-scaled between their own min/max (legacy behaviour).\n * @returns {THREE.Vector3[]} panel-local points (Z = 0.01 to sit in front of the panel)\n */\nexport function buildStripLogLinePoints(depths, values, panelWidth, panelHeight, valueMin, valueMax, depthScale) {\n if (!Array.isArray(depths) || !Array.isArray(values)) return [];\n\n const len = Math.min(depths.length, values.length);\n const valid = [];\n for (let i = 0; i < len; i++) {\n if (Number.isFinite(depths[i]) && Number.isFinite(values[i])) {\n valid.push({ d: depths[i], v: values[i] });\n }\n }\n if (valid.length < 2) return [];\n\n // When depthScale is provided, depth 0 = collar and depthScale = toe, so each\n // sample lands at its true position along the hole axis. Otherwise fall back\n // to auto-scaling across the data's own depth range (legacy behaviour).\n const depthRef = (depthScale != null && depthScale > 0) ? depthScale : null;\n const minDepth = depthRef != null ? 0 : Math.min(...valid.map((p) => p.d));\n const maxDepth = depthRef != null ? depthRef : Math.max(...valid.map((p) => p.d));\n const depthRange = maxDepth - minDepth || 1;\n\n const autoMin = Math.min(...valid.map((p) => p.v));\n const autoMax = Math.max(...valid.map((p) => p.v));\n const vMin = valueMin != null ? valueMin : autoMin;\n const vMax = valueMax != null ? valueMax : autoMax;\n const valRange = vMax - vMin || 1;\n\n return valid.map(({ d, v }) => {\n const tDepth = (d - minDepth) / depthRange; // 0=collar → 1=toe\n const tVal = Math.max(0, Math.min(1, (v - vMin) / valRange));\n const localX = -panelWidth / 2 + tVal * panelWidth;\n // localY increases along +holeDir (downhole). Mesh origin is at the collar,\n // so localY = 0 → collar and localY = +panelHeight → toe.\n const localY = tDepth * panelHeight;\n return new THREE.Vector3(localX, localY, 0.01);\n });\n}\n\n/**\n * Build a flat ribbon BufferGeometry by extruding a polyline in the XY plane.\n *\n * For each consecutive pair of points a quad is generated perpendicular to the\n * segment direction, giving a solid filled line of the requested half-width.\n * Using a Mesh + MeshBasicMaterial avoids the WebGL line-width restriction and\n * the LineMaterial shader complexity.\n *\n * @param {THREE.Vector3[]} points - Line points in panel-local XY space\n * @param {number} halfWidth - Half the desired ribbon width\n * @returns {THREE.BufferGeometry|null}\n */\nfunction buildLineRibbonGeometry(points, halfWidth) {\n const n = points.length;\n if (n < 2) return null;\n\n const positions = [];\n const indices = [];\n let vi = 0;\n\n for (let i = 0; i < n - 1; i++) {\n const p1 = points[i];\n const p2 = points[i + 1];\n const dx = p2.x - p1.x;\n const dy = p2.y - p1.y;\n const len = Math.sqrt(dx * dx + dy * dy);\n if (len < 1e-6) continue;\n\n // Perpendicular unit vector in XY, scaled to half-width\n const nx = (-dy / len) * halfWidth;\n const ny = (dx / len) * halfWidth;\n const z = 0.01;\n\n positions.push(\n p1.x + nx, p1.y + ny, z,\n p1.x - nx, p1.y - ny, z,\n p2.x + nx, p2.y + ny, z,\n p2.x - nx, p2.y - ny, z,\n );\n indices.push(vi, vi + 1, vi + 2, vi + 1, vi + 3, vi + 2);\n vi += 4;\n }\n\n if (positions.length === 0) return null;\n const geom = new THREE.BufferGeometry();\n geom.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));\n geom.setIndex(indices);\n return geom;\n}\n\n/**\n * Build a Three.js Group containing the strip log trace for one hole.\n *\n * No backing panel or border — just a solid ribbon tracing the assay values\n * floating in scene space beside the hole. The trace is oriented parallel to\n * the collar→toe axis and offset laterally from the hole by `lateralOffset`\n * scene units.\n *\n * @param {object} hole - Hole object with `id` and `points`\n * @param {object} stripLog - Strip log definition (holeId, depths, values, options)\n * @returns {THREE.Group|null}\n */\nexport function buildStripLogGroup(hole, stripLog) {\n const points = hole.points || [];\n if (points.length < 2) return null;\n\n const collar = points[0];\n const toe = points[points.length - 1];\n\n // Hole axis: collar → toe\n const holeDirRaw = new THREE.Vector3(\n toe.x - collar.x,\n toe.y - collar.y,\n toe.z - collar.z,\n );\n const holeLength = holeDirRaw.length();\n if (holeLength < 0.001) return null;\n const holeDir = holeDirRaw.clone().normalize();\n\n const opts = normalizeStripLogOptions(stripLog.options);\n const { panelWidth, lateralOffset, color, valueMin, valueMax } = opts;\n\n // Lateral direction: perpendicular to hole axis, as horizontal as possible\n const worldZ = new THREE.Vector3(0, 0, 1);\n let lateralDir = new THREE.Vector3().crossVectors(holeDir, worldZ);\n if (lateralDir.lengthSq() < 1e-6) {\n lateralDir.set(1, 0, 0);\n } else {\n lateralDir.normalize();\n }\n\n const panelNormal = new THREE.Vector3().crossVectors(lateralDir, holeDir).normalize();\n\n // Origin of the trace: collar shifted laterally by the offset\n const traceOrigin = new THREE.Vector3(collar.x, collar.y, collar.z)\n .addScaledVector(lateralDir, lateralOffset);\n\n // Rotation: local X → lateralDir (value axis), local Y → holeDir (depth axis)\n const rotMatrix = new THREE.Matrix4().makeBasis(lateralDir, holeDir, panelNormal);\n const quaternion = new THREE.Quaternion().setFromRotationMatrix(rotMatrix);\n\n // Use the hole's measured depth at the toe as the depth scale so that each\n // sample's depth maps to its true position along the hole axis.\n const measuredDepths = points.map((p) => p.md).filter(Number.isFinite);\n const depthScale = measuredDepths.length > 0 ? Math.max(...measuredDepths) : holeLength;\n\n const linePoints = buildStripLogLinePoints(\n stripLog.depths,\n stripLog.values,\n panelWidth,\n holeLength,\n valueMin,\n valueMax,\n depthScale,\n );\n\n if (linePoints.length < 2) return null;\n\n const group = new THREE.Group();\n group.userData = { holeId: hole.id, isStripLog: true };\n\n const halfWidth = panelWidth * 0.025;\n const ribbonGeom = buildLineRibbonGeometry(linePoints, halfWidth);\n if (!ribbonGeom) return null;\n\n const ribbonMat = new THREE.MeshBasicMaterial({\n color: new THREE.Color(color),\n side: THREE.DoubleSide,\n });\n const ribbonMesh = new THREE.Mesh(ribbonGeom, ribbonMat);\n ribbonMesh.position.copy(traceOrigin);\n ribbonMesh.quaternion.copy(quaternion);\n group.add(ribbonMesh);\n\n return group;\n}\n\n/**\n * Add floating 2D strip log panels beside drillholes in the 3D scene.\n *\n * Each entry in `stripLogs` is matched to a hole by `holeId`. A flat\n * rectangular panel is created for each matched pair and added to the scene\n * beside the corresponding drillhole.\n *\n * @param {object} sceneCtx - Baselode3DScene instance\n * @param {Array<{id: string, points: Array<{x:number,y:number,z:number}>}>} holes\n * Hole objects already rendered in the scene (same array passed to setDrillholes).\n * @param {Array<object>} stripLogs - Strip log definitions. Each must contain:\n * - `holeId` {string} — must match a `hole.id`\n * - `depths` {number[]} — downhole depth positions for each sample\n * - `values` {number[]} — numeric value at each depth\n * - `options` {object} — optional display overrides:\n * - `panelWidth` {number} scene-unit width of the panel (default 20)\n * - `lateralOffset` {number} scene-unit offset from the hole (default 15)\n * - `color` {string} CSS/hex line colour (default '#00bcd4')\n * - `valueMin` {number} explicit minimum value for scaling\n * - `valueMax` {number} explicit maximum value for scaling\n */\nexport function setStripLogs(sceneCtx, holes, stripLogs) {\n if (!sceneCtx.scene) return;\n\n clearStripLogs(sceneCtx);\n if (!stripLogs || stripLogs.length === 0) return;\n if (!holes || holes.length === 0) return;\n\n const holeById = new Map();\n holes.forEach((hole) => {\n if (hole.id != null) holeById.set(hole.id, hole);\n });\n\n stripLogs.forEach((stripLog) => {\n const hole = holeById.get(stripLog.holeId);\n if (!hole) return;\n\n const group = buildStripLogGroup(hole, stripLog);\n if (!group) return;\n\n sceneCtx.scene.add(group);\n sceneCtx.stripLogGroups.push(group);\n });\n}\n\n/**\n * Remove all strip log panels from the scene and free GPU resources.\n *\n * @param {object} sceneCtx - Baselode3DScene instance\n */\nexport function clearStripLogs(sceneCtx) {\n if (!sceneCtx.stripLogGroups) return;\n sceneCtx.stripLogGroups.forEach((group) => {\n if (sceneCtx.scene) sceneCtx.scene.remove(group);\n group.traverse((child) => {\n if (child.geometry) child.geometry.dispose();\n if (child.material) child.material.dispose();\n });\n });\n sceneCtx.stripLogGroups = [];\n}\n","/*\n * Copyright (C) 2026 Darkmine Pty Ltd\n * SPDX-License-Identifier: GPL-3.0-or-later\n */\nimport * as THREE from 'three';\nimport { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer.js';\nimport { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass.js';\nimport { OutlinePass } from 'three/examples/jsm/postprocessing/OutlinePass.js';\n\n/** Glow colour for the selection outline (#ffffbb) */\nconst GLOW_COLOR = '#ffffbb';\n\n/** OutlinePass tuning: produces a soft ~3 px diffuse halo */\nconst EDGE_STRENGTH = 2.0;\nconst EDGE_THICKNESS = 1.5;\nconst EDGE_GLOW = 1.0;\n\n/**\n * Initialise an EffectComposer with a RenderPass and OutlinePass for\n * click-select glow. Attaches `_composer` and `_outlinePass` to sceneCtx.\n *\n * @param {object} sceneCtx - Baselode3DScene instance\n */\nexport function initSelectionGlow(sceneCtx) {\n const { renderer, scene, camera, container } = sceneCtx;\n if (!renderer || !scene || !camera) return;\n\n const width = container?.clientWidth || renderer.domElement.clientWidth || 1;\n const height = container?.clientHeight || renderer.domElement.clientHeight || 1;\n\n const composer = new EffectComposer(renderer);\n\n const renderPass = new RenderPass(scene, camera);\n composer.addPass(renderPass);\n\n const resolution = new THREE.Vector2(width, height);\n const outlinePass = new OutlinePass(resolution, scene, camera);\n outlinePass.visibleEdgeColor.set(GLOW_COLOR);\n outlinePass.hiddenEdgeColor.set(GLOW_COLOR);\n outlinePass.edgeStrength = EDGE_STRENGTH;\n outlinePass.edgeThickness = EDGE_THICKNESS;\n outlinePass.edgeGlow = EDGE_GLOW;\n outlinePass.pulsePeriod = 0;\n outlinePass.selectedObjects = [];\n composer.addPass(outlinePass);\n\n composer.setSize(width, height);\n\n sceneCtx._composer = composer;\n sceneCtx._outlinePass = outlinePass;\n}\n\n/**\n * Resize the effect composer and outline pass to match the new viewport\n * dimensions. Call this whenever the renderer is resized.\n *\n * @param {object} sceneCtx - Baselode3DScene instance\n * @param {number} width - New viewport pixel width\n * @param {number} height - New viewport pixel height\n */\nexport function resizeGlow(sceneCtx, width, height) {\n if (!sceneCtx._composer || !sceneCtx._outlinePass) return;\n sceneCtx._composer.setSize(width, height);\n sceneCtx._outlinePass.resolution.set(width, height);\n}\n\n/**\n * Apply or clear the glow selection highlight.\n *\n * @param {object} sceneCtx - Baselode3DScene instance\n * @param {THREE.Object3D|null} object - Object to highlight, or null to clear\n */\nexport function applySelection(sceneCtx, object) {\n if (!sceneCtx._outlinePass) return;\n sceneCtx._outlinePass.selectedObjects = object ? [object] : [];\n sceneCtx._selectedObject = object || null;\n}\n\n/**\n * Dispose the effect composer and free all GPU resources associated with the\n * selection glow.\n *\n * @param {object} sceneCtx - Baselode3DScene instance\n */\nexport function disposeSelectionGlow(sceneCtx) {\n if (sceneCtx._composer) {\n sceneCtx._composer.dispose();\n sceneCtx._composer = null;\n }\n sceneCtx._outlinePass = null;\n sceneCtx._selectedObject = null;\n sceneCtx.selectables = [];\n}\n","/*\n * Copyright (C) 2026 Darkmine Pty Ltd\n * SPDX-License-Identifier: GPL-3.0-or-later\n */\nimport * as THREE from 'three';\nimport { getColorForValue } from '../data/blockModelLoader.js';\nimport { fitCameraToBounds } from './baselode3dCameraControls.js';\nimport { syncSelectables } from './sceneSelectables.js';\n\n// Six face definitions. neibDir locates the neighbour in that direction.\n// verts are ±1 scale factors of the half-extents (dx/2 etc.).\nconst FACE_DEFS = [\n { normal: [ 1, 0, 0], neibDir: [ 1, 0, 0], verts: [[ 1,-1,-1],[ 1, 1,-1],[ 1, 1, 1],[ 1,-1, 1]] },\n { normal: [-1, 0, 0], neibDir: [-1, 0, 0], verts: [[-1,-1, 1],[-1, 1, 1],[-1, 1,-1],[-1,-1,-1]] },\n { normal: [ 0, 1, 0], neibDir: [ 0, 1, 0], verts: [[-1, 1, 1],[ 1, 1, 1],[ 1, 1,-1],[-1, 1,-1]] },\n { normal: [ 0,-1, 0], neibDir: [ 0,-1, 0], verts: [[ 1,-1, 1],[-1,-1, 1],[-1,-1,-1],[ 1,-1,-1]] },\n { normal: [ 0, 0, 1], neibDir: [ 0, 0, 1], verts: [[-1,-1, 1],[ 1,-1, 1],[ 1, 1, 1],[-1, 1, 1]] },\n { normal: [ 0, 0,-1], neibDir: [ 0, 0,-1], verts: [[ 1,-1,-1],[-1,-1,-1],[-1, 1,-1],[ 1, 1,-1]] },\n];\n\n/**\n * Render block model data as a single merged mesh of exterior faces only.\n *\n * Adjacent blocks' shared faces are skipped so there are no coincident\n * polygons and therefore no z-fighting. Vertex colours are used so the\n * entire model is a single draw call.\n *\n * @param {object} sceneCtx - Baselode3DScene instance\n * @param {Array<Object>} data - Block rows (canonical column names)\n * @param {string} selectedProperty - Attribute column used for colouring\n * @param {Object} stats - Property statistics\n * @param {Object} [options]\n * @param {Object} [options.offset] - Optional {x, y, z} translation\n * @param {number} [options.opacity=1.0] - Initial material opacity (0–1)\n * @param {boolean} [options.autoCenter=true] - Auto-centre blocks at scene origin\n */\nexport function setBlocks(sceneCtx, data, selectedProperty, stats, options = {}) {\n if (!sceneCtx.scene) return;\n\n clearBlocks(sceneCtx);\n\n if (!data || !selectedProperty || !stats) return;\n\n const { autoCenter = true, opacity = 1.0 } = options;\n\n let rawMinX = Infinity, rawMaxX = -Infinity;\n let rawMinY = Infinity, rawMaxY = -Infinity;\n let rawMinZ = Infinity, rawMaxZ = -Infinity;\n\n data.forEach((row) => {\n const x = Number(row.x ?? row.center_x ?? 0);\n const y = Number(row.y ?? row.center_y ?? 0);\n const z = Number(row.z ?? row.center_z ?? 0);\n const dx = Number(row.dx ?? row.size_x ?? 1);\n const dy = Number(row.dy ?? row.size_y ?? 1);\n const dz = Number(row.dz ?? row.size_z ?? 1);\n rawMinX = Math.min(rawMinX, x - dx / 2);\n rawMaxX = Math.max(rawMaxX, x + dx / 2);\n rawMinY = Math.min(rawMinY, y - dy / 2);\n rawMaxY = Math.max(rawMaxY, y + dy / 2);\n rawMinZ = Math.min(rawMinZ, z - dz / 2);\n rawMaxZ = Math.max(rawMaxZ, z + dz / 2);\n });\n\n let offX = 0, offY = 0, offZ = 0;\n if (options.offset) {\n offX = Number(options.offset.x ?? 0);\n offY = Number(options.offset.y ?? 0);\n offZ = Number(options.offset.z ?? 0);\n } else if (autoCenter) {\n offX = -((rawMinX + rawMaxX) / 2);\n offY = -((rawMinY + rawMaxY) / 2);\n offZ = -((rawMinZ + rawMaxZ) / 2);\n }\n\n const minX = rawMinX + offX, maxX = rawMaxX + offX;\n const minY = rawMinY + offY, maxY = rawMaxY + offY;\n const minZ = rawMinZ + offZ, maxZ = rawMaxZ + offZ;\n\n const bkey = (x, y, z) => `${Math.round(x)},${Math.round(y)},${Math.round(z)}`;\n const blockSet = new Set(\n data.map(row => bkey(Number(row.x ?? 0), Number(row.y ?? 0), Number(row.z ?? 0)))\n );\n\n const positions = [];\n const normals = [];\n const colors = [];\n const indices = [];\n const quadToBlock = [];\n let vi = 0;\n\n data.forEach((row) => {\n const bx = Number(row.x ?? row.center_x ?? 0);\n const by = Number(row.y ?? row.center_y ?? 0);\n const bz = Number(row.z ?? row.center_z ?? 0);\n const dx = Number(row.dx ?? row.size_x ?? 1);\n const dy = Number(row.dy ?? row.size_y ?? 1);\n const dz = Number(row.dz ?? row.size_z ?? 1);\n const cx = bx + offX, cy = by + offY, cz = bz + offZ;\n\n const color = getColorForValue(row[selectedProperty], stats, THREE);\n const { r, g, b } = color;\n\n FACE_DEFS.forEach((face) => {\n const nbx = bx + face.neibDir[0] * dx;\n const nby = by + face.neibDir[1] * dy;\n const nbz = bz + face.neibDir[2] * dz;\n if (blockSet.has(bkey(nbx, nby, nbz))) return;\n\n const vBase = vi;\n face.verts.forEach(([sx, sy, sz]) => {\n positions.push(cx + sx * dx / 2, cy + sy * dy / 2, cz + sz * dz / 2);\n normals.push(face.normal[0], face.normal[1], face.normal[2]);\n colors.push(r, g, b);\n vi++;\n });\n indices.push(vBase, vBase + 1, vBase + 2, vBase, vBase + 2, vBase + 3);\n quadToBlock.push(row);\n });\n });\n\n if (positions.length === 0) return;\n\n const geometry = new THREE.BufferGeometry();\n geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));\n geometry.setAttribute('normal', new THREE.Float32BufferAttribute(normals, 3));\n geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3));\n geometry.setIndex(indices);\n\n const material = new THREE.MeshLambertMaterial({\n vertexColors: true,\n transparent: opacity < 1,\n opacity,\n side: THREE.DoubleSide,\n });\n\n const mesh = new THREE.Mesh(geometry, material);\n mesh.userData._isMergedBlocks = true;\n mesh.userData._quadToBlock = quadToBlock;\n mesh.userData._offset = { x: offX, y: offY, z: offZ };\n sceneCtx.scene.add(mesh);\n sceneCtx.blocks.push(mesh);\n syncSelectables(sceneCtx);\n\n if (sceneCtx.camera && sceneCtx.controls) {\n sceneCtx.lastBounds = { minX, maxX, minY, maxY, minZ, maxZ };\n fitCameraToBounds(sceneCtx, { minX, maxX, minY, maxY, minZ, maxZ });\n }\n}\n\n/**\n * Remove all block meshes (and the highlight ghost mesh) from the scene.\n *\n * @param {object} sceneCtx - Baselode3DScene instance\n */\nexport function clearBlocks(sceneCtx) {\n sceneCtx.blocks.forEach((block) => {\n sceneCtx.scene.remove(block);\n block.geometry.dispose();\n block.material.dispose();\n });\n sceneCtx.blocks = [];\n if (sceneCtx._blockHighlightMesh) {\n sceneCtx.scene?.remove(sceneCtx._blockHighlightMesh);\n sceneCtx._blockHighlightMesh.geometry.dispose();\n sceneCtx._blockHighlightMesh.material.dispose();\n sceneCtx._blockHighlightMesh = null;\n }\n syncSelectables(sceneCtx);\n}\n\n/**\n * Update the opacity of all currently rendered blocks.\n *\n * @param {object} sceneCtx - Baselode3DScene instance\n * @param {number} opacity - New opacity value between 0 and 1\n */\nexport function setBlockOpacity(sceneCtx, opacity) {\n const clamped = Math.max(0, Math.min(1, Number(opacity)));\n sceneCtx.blocks.forEach((block) => {\n if (block.material) {\n block.material.opacity = clamped;\n block.material.transparent = clamped < 1;\n block.material.needsUpdate = true;\n }\n });\n}\n\n/**\n * Return (creating on first use) an invisible ghost box mesh positioned and\n * scaled to exactly cover one block. The OutlinePass uses its geometry\n * shape to draw the per-block glow; the box itself is invisible to the\n * normal render.\n *\n * @param {object} sceneCtx - Baselode3DScene instance\n * @param {object} blockRow - Block data row\n * @param {object} offset - Scene offset {x, y, z}\n * @returns {THREE.Mesh}\n */\nexport function getBlockHighlightMesh(sceneCtx, blockRow, offset) {\n const offX = offset?.x ?? 0;\n const offY = offset?.y ?? 0;\n const offZ = offset?.z ?? 0;\n const cx = Number(blockRow.x ?? blockRow.center_x ?? 0) + offX;\n const cy = Number(blockRow.y ?? blockRow.center_y ?? 0) + offY;\n const cz = Number(blockRow.z ?? blockRow.center_z ?? 0) + offZ;\n const dx = Number(blockRow.dx ?? blockRow.size_x ?? 1);\n const dy = Number(blockRow.dy ?? blockRow.size_y ?? 1);\n const dz = Number(blockRow.dz ?? blockRow.size_z ?? 1);\n if (!sceneCtx._blockHighlightMesh) {\n const geom = new THREE.BoxGeometry(1, 1, 1);\n const mat = new THREE.MeshBasicMaterial({ transparent: true, opacity: 0, depthWrite: false });\n sceneCtx._blockHighlightMesh = new THREE.Mesh(geom, mat);\n sceneCtx.scene.add(sceneCtx._blockHighlightMesh);\n }\n sceneCtx._blockHighlightMesh.position.set(cx, cy, cz);\n sceneCtx._blockHighlightMesh.scale.set(dx, dy, dz);\n return sceneCtx._blockHighlightMesh;\n}\n","/*\n * Copyright (C) 2026 Darkmine Pty Ltd\n * SPDX-License-Identifier: GPL-3.0-or-later\n */\nimport { applySelection } from './selectionGlow.js';\nimport { getBlockHighlightMesh } from './blockModelScene.js';\n\n/**\n * Raycast against `selectables` using the current pointer position and apply\n * the glow to the nearest hit object (or clear if nothing is hit).\n * For merged block meshes, redirects the glow to an invisible ghost box\n * sized and positioned to match only the hovered block.\n *\n * @param {object} sceneCtx - Baselode3DScene instance\n */\nexport function updateSelectionFromPointer(sceneCtx) {\n if (!sceneCtx._outlinePass || sceneCtx.selectables.length === 0) {\n if (sceneCtx._outlinePass) applySelection(sceneCtx, null);\n return;\n }\n const hits = sceneCtx.raycaster.intersectObjects(sceneCtx.selectables, true);\n if (hits.length === 0) {\n applySelection(sceneCtx, null);\n return;\n }\n const hit = hits[0];\n const obj = hit.object;\n if (obj?.userData?._isMergedBlocks) {\n const quadIndex = Math.floor(hit.faceIndex / 2);\n const blockRow = obj.userData._quadToBlock?.[quadIndex];\n if (blockRow) {\n applySelection(sceneCtx, getBlockHighlightMesh(sceneCtx, blockRow, obj.userData._offset));\n return;\n }\n }\n applySelection(sceneCtx, obj);\n}\n\n/**\n * Register a click listener on the renderer canvas. Handles block →\n * structural → drillhole priority. Stores the listener reference in\n * `sceneCtx.handleCanvasClick` for later removal in `dispose()`.\n *\n * @param {object} sceneCtx - Baselode3DScene instance\n */\nexport function attachCanvasClickHandler(sceneCtx) {\n const renderer = sceneCtx.renderer;\n if (!renderer) return;\n\n sceneCtx.handleCanvasClick = (event) => {\n if (event.button !== 0) return; // left click only\n\n // Ignore clicks inside the gizmo area\n if (sceneCtx.gizmo?.domElement) {\n const gizmoRect = sceneCtx.gizmo.domElement.getBoundingClientRect();\n if (\n event.clientX >= gizmoRect.left &&\n event.clientX <= gizmoRect.right &&\n event.clientY >= gizmoRect.top &&\n event.clientY <= gizmoRect.bottom\n ) {\n return;\n }\n }\n\n const rect = renderer.domElement.getBoundingClientRect();\n const localX = event.clientX - rect.left;\n const localY = event.clientY - rect.top;\n\n sceneCtx.pointer.x = ((localX / rect.width) * 2) - 1;\n sceneCtx.pointer.y = -((localY / rect.height) * 2) + 1;\n\n sceneCtx.raycaster.setFromCamera(sceneCtx.pointer, sceneCtx.camera);\n\n // Selection glow: raycast against registered selectables\n updateSelectionFromPointer(sceneCtx);\n\n // Check block clicks first (blocks take priority over drillholes)\n if (sceneCtx.blocks.length > 0) {\n const blockIntersects = sceneCtx.raycaster.intersectObjects(sceneCtx.blocks, false);\n if (blockIntersects.length > 0) {\n const hit = blockIntersects[0];\n const blockObj = hit.object;\n if (blockObj?.userData?._isMergedBlocks && sceneCtx.blockClickHandler) {\n const quadIndex = Math.floor(hit.faceIndex / 2);\n const blockData = blockObj.userData._quadToBlock[quadIndex];\n if (blockData) sceneCtx.blockClickHandler(blockData);\n }\n return;\n }\n }\n\n // Fall through to drillhole / structural click detection\n const drillHits = sceneCtx.raycaster.intersectObjects(sceneCtx.drillMeshes, true);\n const structHits = sceneCtx.raycaster.intersectObjects(sceneCtx.structuralMeshes, true);\n\n const drillDist = drillHits[0]?.distance ?? Infinity;\n const structDist = structHits[0]?.distance ?? Infinity;\n\n if (structDist < drillDist && structHits.length > 0) {\n const mesh = structHits[0].object;\n if (sceneCtx.drillholeClickHandler) {\n sceneCtx.drillholeClickHandler({ type: 'structure', ...mesh.userData });\n }\n return;\n }\n\n if (drillHits.length === 0) return;\n let obj = drillHits[0].object;\n while (obj && obj.parent && !obj.userData?.holeId) {\n obj = obj.parent;\n }\n const holeId = obj?.userData?.holeId;\n const project = obj?.userData?.project;\n if (holeId && sceneCtx.drillholeClickHandler) {\n sceneCtx.drillholeClickHandler({ holeId, project });\n }\n };\n\n renderer.domElement.addEventListener('click', sceneCtx.handleCanvasClick);\n}\n","/*\n * Copyright (C) 2026 Darkmine Pty Ltd\n * SPDX-License-Identifier: GPL-3.0-or-later\n */\nimport * as THREE from 'three';\nimport { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';\nimport { FlyControls } from 'three/examples/jsm/controls/FlyControls';\nimport { ViewportGizmo } from 'three-viewport-gizmo';\nimport {\n buildViewSignature,\n emitViewChangeIfNeeded,\n fitCameraToBounds,\n focusOnLastBounds,\n getViewState,\n lookDown,\n pan,\n dolly,\n recenterCameraToOrigin,\n setControlMode,\n setFov,\n setViewState\n} from './baselode3dCameraControls.js';\nimport {\n initSelectionGlow,\n resizeGlow,\n applySelection,\n disposeSelectionGlow\n} from './selectionGlow.js';\nimport { setDrillholes as _setDrillholes, clearDrillholes as _clearDrillholes } from './drillholeScene.js';\nimport { setStripLogs as _setStripLogs, clearStripLogs as _clearStripLogs } from './stripLogScene.js';\nimport { setBlocks as _setBlocks, clearBlocks as _clearBlocks, setBlockOpacity as _setBlockOpacity } from './blockModelScene.js';\nimport {\n setStructuralDiscs as _setStructuralDiscs,\n clearStructuralDiscs as _clearStructuralDiscs,\n setStructuralDiscsVisible as _setStructuralDiscsVisible\n} from './structuralScene.js';\nimport { attachCanvasClickHandler as _attachCanvasClickHandler, updateSelectionFromPointer as _updateSelectionFromPointer } from './sceneClickHandler.js';\nimport { syncSelectables } from './sceneSelectables.js';\nimport {\n addRasterOverlay as _addRasterOverlay,\n removeRasterOverlay as _removeRasterOverlay,\n setRasterOverlayOpacity as _setRasterOverlayOpacity,\n setRasterOverlayVisibility as _setRasterOverlayVisibility,\n setRasterOverlayElevation as _setRasterOverlayElevation,\n getRasterOverlay as _getRasterOverlay,\n listRasterOverlays as _listRasterOverlays,\n clearRasterOverlays as _clearRasterOverlays,\n} from './rasterOverlayScene.js';\n\n/**\n * Baselode 3D Scene Manager\n * Manages THREE.js scene for rendering drillholes and block models in 3D.\n * Supports orbit and fly camera controls, assay coloring, and interactive selection.\n *\n * Rendering logic lives in the domain-specific modules; this class is a thin\n * orchestrator that owns the WebGL context and delegates to those modules.\n */\nclass Baselode3DScene {\n constructor() {\n this.container = null;\n this.scene = null;\n this.camera = null;\n this.renderer = null;\n this.controls = null;\n this.flyControls = null;\n this.gizmo = null;\n this.blocks = [];\n this.drillLines = [];\n this.drillMeshes = [];\n this.structuralGroup = null;\n this.structuralMeshes = [];\n this.stripLogGroups = [];\n this.frameId = null;\n this.clock = new THREE.Clock();\n this.handleCanvasClick = null;\n this.raycaster = new THREE.Raycaster();\n this.pointer = new THREE.Vector2();\n this.drillholeClickHandler = null;\n this.blockClickHandler = null;\n this.controlMode = 'orbit';\n this._tmpDir = new THREE.Vector3();\n this.viewChangeHandler = null;\n this._lastViewSignature = '';\n this._lastViewEmitMs = 0;\n this.selectables = [];\n this._selectedObject = null;\n this._composer = null;\n this._blockHighlightMesh = null;\n this._outlinePass = null;\n this.rasterOverlays = new Map();\n }\n\n init(container) {\n if (!container) return;\n this.container = container;\n\n const width = container.clientWidth;\n const height = container.clientHeight;\n\n // Scene\n this.scene = new THREE.Scene();\n this.scene.background = new THREE.Color(0xffffff);\n\n // Camera — lower near plane allows ultra-close zoom without clipping;\n // far plane set large enough for ultra-low-FOV (near-ortho) modes where\n // the camera must retreat several hundred kilometres to show a km-scale scene.\n this.camera = new THREE.PerspectiveCamera(28, width / height, 0.001, 10_000_000);\n this.camera.up.set(0, 0, 1);\n this.camera.position.set(50, 50, 50);\n this.camera.lookAt(0, 0, 0);\n\n // Renderer\n this.renderer = new THREE.WebGLRenderer({ antialias: true });\n this.renderer.setSize(width, height);\n this.renderer.setPixelRatio(window.devicePixelRatio);\n this.renderer.autoClear = false;\n container.appendChild(this.renderer.domElement);\n\n // Lighting\n const ambientLight = new THREE.AmbientLight(0xffffff, 1.2);\n this.scene.add(ambientLight);\n const directionalLight = new THREE.DirectionalLight(0xffffff, 1.5);\n directionalLight.position.set(10, 10, 5);\n this.scene.add(directionalLight);\n\n // Axes helper\n const axesHelper = new THREE.AxesHelper(20);\n this.scene.add(axesHelper);\n\n // Orbit controls\n this.controls = new OrbitControls(this.camera, this.renderer.domElement);\n this.controls.enableDamping = false;\n this.controls.screenSpacePanning = true;\n this.controls.enableZoom = true;\n this.controls.zoomSpeed = 10;\n this.controls.minDistance = 0.0001;\n this.controls.maxDistance = 5_000_000;\n this.controls.mouseButtons = {\n LEFT: THREE.MOUSE.PAN,\n MIDDLE: THREE.MOUSE.DOLLY,\n RIGHT: THREE.MOUSE.ROTATE\n };\n this.controls.touches = {\n ONE: THREE.TOUCH.ROTATE,\n TWO: THREE.TOUCH.DOLLY_PAN\n };\n this.controls.maxPolarAngle = Math.PI;\n\n // Fly controls (disabled by default)\n this.flyControls = new FlyControls(this.camera, this.renderer.domElement);\n this.flyControls.movementSpeed = 2000;\n this.flyControls.rollSpeed = Math.PI / 12;\n this.flyControls.dragToLook = true;\n this.flyControls.enabled = false;\n\n // Viewport gizmo\n this.gizmo = new ViewportGizmo(this.camera, this.renderer, {\n container: this.container,\n placement: 'top-right',\n size: 110,\n offset: { top: 12, right: 12 },\n animated: true,\n speed: 1.5\n });\n this.gizmo.attachControls(this.controls);\n\n _attachCanvasClickHandler(this);\n\n // On macOS, Chrome latches wheel events to whichever element is under the\n // cursor at the start of a gesture. If that element is an overlaid UI panel\n // (zoom slider, controls buttons) rather than the canvas, OrbitControls never\n // receives the event. Relay any wheel event that bubbles up to the container\n // but did NOT originate from the canvas itself.\n this._wheelRelay = (e) => {\n if (e.target === this.renderer.domElement) return; // already going to OrbitControls\n e.preventDefault();\n this.renderer.domElement.dispatchEvent(new WheelEvent('wheel', {\n clientX: e.clientX,\n clientY: e.clientY,\n deltaX: e.deltaX,\n deltaY: e.deltaY,\n deltaZ: e.deltaZ,\n deltaMode: e.deltaMode,\n ctrlKey: e.ctrlKey,\n shiftKey: e.shiftKey,\n altKey: e.altKey,\n bubbles: false,\n }));\n };\n this.container.addEventListener('wheel', this._wheelRelay, { passive: false });\n\n // Selection glow post-processing\n initSelectionGlow(this);\n\n // Animation loop\n const animate = () => {\n this.frameId = requestAnimationFrame(animate);\n const delta = this.clock.getDelta();\n this.renderer.clear();\n if (this.controlMode === 'fly' && this.flyControls?.enabled) {\n this.flyControls.update(delta);\n } else if (this.controls) {\n this.controls.update();\n }\n this._emitViewChangeIfNeeded();\n if (this._composer) {\n this._composer.render(delta);\n } else {\n this.renderer.render(this.scene, this.camera);\n }\n if (this.gizmo) this.gizmo.render();\n };\n animate();\n }\n\n resize() {\n if (!this.container || !this.camera || !this.renderer) return;\n const width = this.container.clientWidth;\n const height = this.container.clientHeight;\n this.camera.aspect = width / height;\n this.camera.updateProjectionMatrix();\n this.renderer.setSize(width, height);\n if (this.gizmo) this.gizmo.update();\n resizeGlow(this, width, height);\n }\n\n dispose() {\n if (this.frameId) cancelAnimationFrame(this.frameId);\n if (this.renderer && this.handleCanvasClick) {\n this.renderer.domElement.removeEventListener('click', this.handleCanvasClick);\n }\n if (this.gizmo) {\n this.gizmo.dispose();\n this.gizmo = null;\n }\n this.viewChangeHandler = null;\n _clearBlocks(this);\n _clearDrillholes(this);\n _clearStripLogs(this);\n _clearStructuralDiscs(this);\n _clearRasterOverlays(this);\n disposeSelectionGlow(this);\n if (this.container && this._wheelRelay) {\n this.container.removeEventListener('wheel', this._wheelRelay);\n }\n if (this.controls) this.controls.dispose();\n if (this.flyControls) this.flyControls.dispose();\n if (this.renderer) {\n this.renderer.dispose();\n if (this.container && this.renderer.domElement) {\n this.container.removeChild(this.renderer.domElement);\n }\n }\n }\n\n // ---------------------------------------------------------------------------\n // Data renderers — delegate to domain modules\n // ---------------------------------------------------------------------------\n\n setDrillholes(holes, options = {}) { _setDrillholes(this, holes, options); }\n\n /**\n * Add floating 2D strip log panels beside drillholes in the 3D scene.\n * Each panel is a flat rectangle offset from the hole collar, depth-registered\n * to the hole's vertical extent and containing a line graph of numeric data.\n *\n * @param {Array<object>} holes - Hole objects (same array as passed to setDrillholes)\n * @param {Array<object>} stripLogs - Strip log definitions. Each must contain:\n * - `holeId` {string} — must match a hole id\n * - `depths` {number[]} — downhole depth positions for each sample\n * - `values` {number[]} — numeric value at each depth\n * - `options` {object} — optional: panelWidth, lateralOffset, color, valueMin, valueMax\n */\n setStripLogs(holes, stripLogs) { _setStripLogs(this, holes, stripLogs); }\n\n /**\n * Remove all strip log panels from the scene and free GPU resources.\n */\n clearStripLogs() { _clearStripLogs(this); }\n\n /**\n * Render block model data as a single merged mesh of exterior faces only.\n * @param {Array<Object>} data - Block rows (canonical column names)\n * @param {string} selectedProperty - Attribute column used for colouring\n * @param {Object} stats - Property statistics\n * @param {Object} [options]\n */\n setBlocks(data, selectedProperty, stats, options = {}) { _setBlocks(this, data, selectedProperty, stats, options); }\n\n /**\n * Update the opacity of all currently rendered blocks.\n * @param {number} opacity - New opacity value between 0 and 1\n */\n setBlockOpacity(opacity) { _setBlockOpacity(this, opacity); }\n\n setStructuralDiscs(structures, holes, opts = {}) { _setStructuralDiscs(this, structures, holes, opts); }\n\n setStructuralDiscsVisible(visible) { _setStructuralDiscsVisible(this, visible); }\n\n // ---------------------------------------------------------------------------\n // Click handlers\n // ---------------------------------------------------------------------------\n\n setDrillholeClickHandler(handler) {\n this.drillholeClickHandler = handler;\n }\n\n /**\n * Register a click handler for block selection.\n * @param {Function|null} handler - Callback ``(blockData) => void``, or null to clear\n */\n setBlockClickHandler(handler) {\n this.blockClickHandler = typeof handler === 'function' ? handler : null;\n }\n\n // ---------------------------------------------------------------------------\n // Camera controls — delegate to baselode3dCameraControls\n // ---------------------------------------------------------------------------\n\n setViewChangeHandler(handler) {\n this.viewChangeHandler = typeof handler === 'function' ? handler : null;\n }\n\n getViewState() { return getViewState(this); }\n setViewState(viewState) { return setViewState(this, viewState); }\n\n _buildViewSignature(viewState) { return buildViewSignature(viewState); }\n _emitViewChangeIfNeeded() { emitViewChangeIfNeeded(this); }\n\n _fitCameraToBounds({ minX, maxX, minY, maxY, minZ, maxZ }) {\n fitCameraToBounds(this, { minX, maxX, minY, maxY, minZ, maxZ });\n }\n\n recenterCameraToOrigin(distance = 1000) { recenterCameraToOrigin(this, distance); }\n lookDown(distance = 2000) { lookDown(this, distance); }\n pan(dx = 0, dy = 0) { pan(this, dx, dy); }\n dolly(scale = 1.1) { dolly(this, scale); }\n focusOnLastBounds(padding = 1.2) { focusOnLastBounds(this, padding); }\n\n /**\n * Change the camera field-of-view while keeping the visible scene the same apparent size.\n * @param {number} fovDeg - Desired FOV in degrees\n */\n setCameraFov(fovDeg) { setFov(this, fovDeg); }\n\n /**\n * Set the scene background colour.\n * @param {'white'|'black'} colour\n */\n setBackground(colour) {\n if (!this.scene) return;\n this.scene.background = new THREE.Color(colour === 'black' ? 0x000000 : 0xffffff);\n }\n\n setControlMode(mode = 'orbit') { setControlMode(this, mode); }\n\n // ---------------------------------------------------------------------------\n // Selection glow public API\n // ---------------------------------------------------------------------------\n\n _syncSelectables() { syncSelectables(this); }\n\n /**\n * Register the objects that are candidates for click-select glow.\n * @param {THREE.Object3D[]} objects\n */\n setSelectableObjects(objects) {\n this.selectables = Array.isArray(objects) ? objects.slice() : [];\n }\n\n /**\n * Programmatically select an object (or pass null to clear).\n * @param {THREE.Object3D|null} object\n */\n selectObject(object) { applySelection(this, object || null); }\n\n /**\n * Return the currently selected object, or null if nothing is selected.\n * @returns {THREE.Object3D|null}\n */\n getSelectedObject() { return this._selectedObject || null; }\n\n /**\n * Dispose the effect composer and all GPU resources used by the selection glow.\n */\n disposeGlow() { disposeSelectionGlow(this); }\n\n /** @private */\n _updateSelectionFromPointer() { _updateSelectionFromPointer(this); }\n\n // ---------------------------------------------------------------------------\n // Raster overlay API — delegate to rasterOverlayScene\n // ---------------------------------------------------------------------------\n\n /**\n * Add a raster overlay layer (created with createRasterOverlay) to the scene.\n * @param {object} layer - Layer descriptor returned by createRasterOverlay()\n */\n addRasterOverlay(layer) { _addRasterOverlay(this, layer); }\n\n /**\n * Remove a raster overlay from the scene and dispose its GPU resources.\n * @param {string} id - Overlay id\n */\n removeRasterOverlay(id) { _removeRasterOverlay(this, id); }\n\n /**\n * Set the opacity of a raster overlay at runtime.\n * @param {string} id - Overlay id\n * @param {number} opacity - New opacity [0, 1]\n */\n setRasterOverlayOpacity(id, opacity) { _setRasterOverlayOpacity(this, id, opacity); }\n\n /**\n * Show or hide a raster overlay.\n * @param {string} id - Overlay id\n * @param {boolean} visible\n */\n setRasterOverlayVisibility(id, visible) { _setRasterOverlayVisibility(this, id, visible); }\n\n /**\n * Update the elevation (Z position) of a raster overlay.\n * @param {string} id - Overlay id\n * @param {number} elevation\n */\n setRasterOverlayElevation(id, elevation) { _setRasterOverlayElevation(this, id, elevation); }\n\n /**\n * Return a raster overlay by id, or undefined if not found.\n * @param {string} id\n * @returns {object|undefined}\n */\n getRasterOverlay(id) { return _getRasterOverlay(this, id); }\n\n /**\n * Return all raster overlay layers in insertion order.\n * @returns {object[]}\n */\n listRasterOverlays() { return _listRasterOverlays(this); }\n}\n\nexport default Baselode3DScene;\n"],"names":["DATASOURCE","HOLE_ID","COLLAR_ID","DATASOURCE_HOLE_ID","HOLE_TYPE","MAX_DEPTH","SURFACE_SAMPLE_ID","SURFACE_SAMPLE_TYPE","DATASOURCE_SURFACE_SAMPLE_ID","PROJECT_ID","REPORT_NUMBER","LATITUDE","LONGITUDE","ELEVATION","EASTING","NORTHING","CRS","DATE_START","DATE_END","AZIMUTH","DIP","SURVEY_TYPE","SAMPLE_ID","DATASOURCE_SAMPLE_ID","FROM","TO","MID","DEPTH","STRIKE","ALPHA","BETA","GEOLOGY_CODE","GEOLOGY_DESCRIPTION","COMMENTS","EXTRA","GEOPHYSICS_NULL_SENTINEL","GEOPHYSICS_NULL","BASELODE_DATA_MODEL_DRILL_COLLAR","BASELODE_DATA_MODEL_DRILL_SURVEY","BASELODE_DATA_MODEL_DRILL_ASSAY","BASELODE_DATA_MODEL_DRILL_GEOLOGY","BASELODE_DATA_MODEL_STRUCTURAL_POINT","BASELODE_DATA_MODEL_GEOPHYSICS","BASELODE_DATA_MODEL_SURFACE_SAMPLE","DEFAULT_COLUMN_MAP","_COLUMN_LOOKUP","standardCol","variations","variation","normalized","DATA_LOG_PREFIX","toError","error","fallbackMessage","message","withDataErrorContext","context","baseError","wrapped","logDataWarning","logDataInfo","DISPLAY_NUMERIC","DISPLAY_CATEGORICAL","DISPLAY_COMMENT","DISPLAY_HIDDEN","DISPLAY_TADPOLE","CHART_OPTIONS","HIDDEN_COLUMNS","COMMENT_COLUMN_NAMES","classifyColumns","rows","allCols","byType","col","hasValue","r","v","hasNumeric","t","k","getChartOptions","displayType","defaultChartType","opts","GEOMETRY_COLS","BLOCK_COL_MAP","_blockColLookup","canon","variants","normalizeBlockRow","row","out","key","value","parseBlockModelCSV","file","resolve","reject","Papa","results","data","propertyColumns","loadBlockModelMetadata","source","err","calculatePropertyStats","property","values","min","max","getBlockStats","propertyKeys","result","filterBlocks","criteria","condition","val","calculateBlockVolume","sum","dx","dy","dz","getColorForValue","stats","THREEInstance","range","hue","interpolateTrace","sortedTraceRows","targetMd","p","segIdx","i","md0","md1","p0","p1","segLen","x","y","z","az0","dip0","az1","dip1","az","dip","azRad","dipRad","ddx","ddy","ddz","len","dlen","alphaBetaToNormal","alphaDeg","betaDeg","drillDir","betaZeroAxis","betaHandedness","D","U","dotDU","crossUD","crossUDLen","R","crossDR","crossDRLen","B","N_perp0","betaRad","cosB","sinB","dotND","crossDN","N_perp","theta","cosT","sinT","Nx","Ny","Nz","NLen","computeStructuralPositions","structures","traceRows","tracesByHole","holeId","b","s","holeTrace","depth","pos","nx","ny","nz","alpha","beta","betaVal","n","BASELODE_TEMPLATE_NAME","BASELODE_LIGHT_TEMPLATE_NAME","BASELODE_COLORWAY","BASELODE_LIGHT","BASELODE_TEMPLATE","BASELODE_LIGHT_TEMPLATE","BASELODE_DARK","BASELODE_DARK_TEMPLATE_NAME","BASELODE_DARK_TEMPLATE","FALLBACK_COLOUR","COMMODITY_COLOURS","LITHOLOGY_COLOURS","BUILTIN_COLOUR_MAPS","getColour","colourMap","fallback","keyLower","mapKey","mapColour","resolveColourMap","nameOrMap","available","NUMERIC_LINE_COLOR","NUMERIC_MARKER_COLOR","commodityColourForProperty","tokens","token","low","colour","ERROR_COLOR","STRIPLOG_COMPACT_MARGIN","STRIPLOG_AXIS_TICK_FONT_SIZE","STRIPLOG_AXIS_TITLE_FONT_SIZE","STRIPLOG_XAXIS_TITLE_STANDOFF","normalizeAxisTitle","applyStriplogLayoutDefaults","layout","xTitle","yTitle","holeHasData","hole","pts","_a","buildIntervalPoints","isCategorical","rawPoints","seen","fromVal","toVal","depthVal","rawVal","mid","buildCategoricalConfig","points","template","safe","point","a","resolvedCmap","fallbackPalette","uniqueCategories","pickColour","cat","idx","c","colorByCategory","category","intervals","seg","buildNumericConfig","chartType","color","isBar","isMarkersOnly","isLineOnly","lineColor","markerColor","baseTrace","errorConfig","buildPlotConfig","buildCategoricalStripLogConfig","fromCol","toCol","categoryCol","from","to","ASSAY_COLOR_PALETTE_10","buildEqualRangeColorScale","colors","finiteValues","sorted","binCount","bins","_","index","percentileLow","percentileHigh","idxLow","idxHigh","lower","upper","formatBinLabel","step","formatVal","getEqualRangeBinIndex","scale","bin","getEqualRangeColor","fallbackColor","syncSelectables","sceneCtx","DEFAULT_COLOR_MAP","resolveColor","structureType","colorMap","map","hex","THREE","dipAzimuthToNormal","azimuth","buildStructuralDiscs","radius","discThickness","opacity","segments","group","yAxis","xVal","yVal","zVal","dipVal","azVal","normal","geom","mat","mesh","setStructuralDiscs","holes","clearStructuralDiscs","maxDiscs","input","sampled","h","enriched","child","setStructuralDiscsVisible","visible","_overlayIdCounter","normalizeBounds","bounds","minX","minY","maxX","maxY","width","height","loadTexture","url","createdObjectUrl","texture","createRasterOverlay","options","elevation","renderOrder","id","name","normalizedBounds","centerX","centerY","geometry","material","addRasterOverlay","layer","removeRasterOverlay","setRasterOverlayOpacity","clamped","setRasterOverlayVisibility","setRasterOverlayElevation","getRasterOverlay","listRasterOverlays","clearRasterOverlays","buildViewSignature","viewState","toNum","_b","_c","_d","_e","_f","_g","_h","_i","getViewState","state","setViewState","camera","target","up","emitViewChangeIfNeeded","now","signature","fitCameraToBounds","minZ","maxZ","centerZ","sizeX","sizeY","sizeZ","distance","recenterCameraToOrigin","lookDown","pan","dolly","focusOnLastBounds","padding","FOV_MIN_DEG","FOV_MAX_DEG","setFov","fovDeg","clampedFov","currentDist","currentFovRad","frustumHeight","newFovRad","newDist","dir","setControlMode","mode","LOW_ASSAY_GREY","getMeasuredDepthRange","p2","md2","segStart","segEnd","getWeightedIntervalValue","assayIntervals","weightedSum","weightTotal","candidate","overlapStart","overlap","getAssaySegmentColor","assayScale","colorHex","getCategoryHexColor","seededUnit","normalizeDrillholeRenderOptions","collectAssayValues","assayIntervalsByHole","selectedAssayVariable","allAssayValues","interval","buildHoleUserData","normalizeHoleKey","randomSegmentColor","segmentIndex","seed","base","band","text","hash","getDominantCategory","best","bestOverlap","iv","resolveAssayIntervalsForHole","exact","byNormalized","getSegmentColor","depthRange","setDrillholes","clearDrillholes","preserveView","isCategoricalVariable","tmpVec","defaultColor","sphereGeom","sphereMat","sphere","cylinderGeom","segmentColor","cylinderMat","line","STRIP_LOG_DEFAULT_PANEL_WIDTH","STRIP_LOG_DEFAULT_LATERAL_OFFSET","STRIP_LOG_DEFAULT_COLOR","normalizeStripLogOptions","getHoleVerticalExtent","topZ","botZ","buildStripLogLinePoints","depths","panelWidth","panelHeight","valueMin","valueMax","depthScale","valid","depthRef","minDepth","autoMin","autoMax","vMin","valRange","d","tDepth","tVal","localX","localY","buildLineRibbonGeometry","halfWidth","positions","indices","vi","buildStripLogGroup","stripLog","collar","toe","holeDirRaw","holeLength","holeDir","lateralOffset","worldZ","lateralDir","panelNormal","traceOrigin","rotMatrix","quaternion","measuredDepths","linePoints","ribbonGeom","ribbonMat","ribbonMesh","setStripLogs","stripLogs","clearStripLogs","holeById","GLOW_COLOR","EDGE_STRENGTH","EDGE_THICKNESS","EDGE_GLOW","initSelectionGlow","renderer","scene","container","composer","EffectComposer","renderPass","RenderPass","resolution","outlinePass","OutlinePass","resizeGlow","applySelection","object","disposeSelectionGlow","FACE_DEFS","setBlocks","selectedProperty","clearBlocks","autoCenter","rawMinX","rawMaxX","rawMinY","rawMaxY","rawMinZ","rawMaxZ","offX","offY","offZ","bkey","blockSet","normals","quadToBlock","bx","by","bz","cx","cy","cz","g","face","nbx","nby","nbz","vBase","sx","sy","sz","block","setBlockOpacity","getBlockHighlightMesh","blockRow","offset","updateSelectionFromPointer","hits","hit","obj","quadIndex","attachCanvasClickHandler","event","gizmoRect","rect","blockIntersects","blockObj","blockData","drillHits","structHits","drillDist","project","Baselode3DScene","ambientLight","directionalLight","axesHelper","OrbitControls","FlyControls","ViewportGizmo","_attachCanvasClickHandler","e","animate","delta","_clearBlocks","_clearDrillholes","_clearStripLogs","_clearStructuralDiscs","_clearRasterOverlays","_setDrillholes","_setStripLogs","_setBlocks","_setBlockOpacity","_setStructuralDiscs","_setStructuralDiscsVisible","handler","objects","_updateSelectionFromPointer","_addRasterOverlay","_removeRasterOverlay","_setRasterOverlayOpacity","_setRasterOverlayVisibility","_setRasterOverlayElevation","_getRasterOverlay","_listRasterOverlays"],"mappings":"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"}
|