"""Coordinate Point Extractor for KIT system.""" # Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. import re from collections import OrderedDict from os import SEEK_CUR, PathLike from pathlib import Path import numpy as np from ..._fiff._digitization import _make_dig_points from ...channels.montage import ( _check_dig_shape, read_custom_montage, read_dig_polhemus_isotrak, read_polhemus_fastscan, ) from ...transforms import ( Transform, als_ras_trans, apply_trans, get_ras_to_neuromag_trans, ) from ...utils import _check_fname, _check_option, warn from .constants import FIFF, KIT INT32 = " KIT.DIG_POINTS: hsp = _decimate_points(hsp, res=0.005) n_new = len(hsp) warn( f"The selected head shape contained {n_pts} points, which is more than " f"recommended ({KIT.DIG_POINTS}), and was automatically downsampled to " f"{n_new} points. The preferred way to downsample is using FastScan." ) if isinstance(elp, (str, Path, PathLike)): elp_points = _read_dig_kit(elp) if len(elp_points) != 8: raise ValueError( f"File {repr(elp)} should contain 8 points; got shape " f"{elp_points.shape}." ) elp = elp_points if len(bad_coils) > 0: elp = np.delete(elp, np.array(bad_coils) + 3, 0) # check we have at least 3 marker coils (whether read from file or # passed in directly) if len(elp) not in (6, 7, 8): raise ValueError(f"ELP should contain 6 ~ 8 points; got shape {elp.shape}.") if isinstance(mrk, (str, Path, PathLike)): mrk = read_mrk(mrk) if len(bad_coils) > 0: mrk = np.delete(mrk, bad_coils, 0) if len(mrk) not in (3, 4, 5): raise ValueError(f"MRK should contain 3 ~ 5 points; got shape {mrk.shape}.") mrk = apply_trans(als_ras_trans, mrk) nasion, lpa, rpa = elp[:3] nmtrans = get_ras_to_neuromag_trans(nasion, lpa, rpa) elp = apply_trans(nmtrans, elp) hsp = apply_trans(nmtrans, hsp) eeg = OrderedDict((k, apply_trans(nmtrans, p)) for k, p in eeg.items()) # device head transform trans = fit_matched_points(tgt_pts=elp[3:], src_pts=mrk, out="trans") nasion, lpa, rpa = elp[:3] elp = elp[3:] dig_points = _make_dig_points(nasion, lpa, rpa, elp, hsp, dig_ch_pos=eeg) dev_head_t = Transform("meg", "head", trans) hpi_results = [ dict( dig_points=[ dict( ident=ci, r=r, kind=FIFF.FIFFV_POINT_HPI, coord_frame=FIFF.FIFFV_COORD_UNKNOWN, ) for ci, r in enumerate(mrk) ], coord_trans=dev_head_t, ) ] return dig_points, dev_head_t, hpi_results def _read_dig_kit(fname, unit="auto"): # Read dig points from a file and return ndarray, using FastSCAN for .txt fname = _check_fname(fname, "read", must_exist=True, name="hsp or elp file") assert unit in ("auto", "m", "mm") _check_option("file extension", fname.suffix, (".hsp", ".elp", ".mat", ".txt")) if fname.suffix == ".txt": unit = "mm" if unit == "auto" else unit out = read_polhemus_fastscan(fname, unit=unit, on_header_missing="ignore") elif fname.suffix in (".hsp", ".elp"): unit = "m" if unit == "auto" else unit mon = read_dig_polhemus_isotrak(fname, unit=unit) if fname.suffix == ".hsp": dig = [d["r"] for d in mon.dig if d["kind"] != FIFF.FIFFV_POINT_CARDINAL] else: dig = [d["r"] for d in mon.dig] if ( dig and mon.dig[0]["kind"] == FIFF.FIFFV_POINT_CARDINAL and mon.dig[0]["ident"] == FIFF.FIFFV_POINT_LPA ): # LPA, Nasion, RPA -> NLR dig[:3] = [dig[1], dig[0], dig[2]] out = np.array(dig, float) else: assert fname.suffix == ".mat" out = np.array([d["r"] for d in read_custom_montage(fname).dig]) _check_dig_shape(out) return out