"""Read .hc files.""" # Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. import numpy as np from ..._fiff.constants import FIFF from ...utils import logger from .constants import CTF from .res4 import _make_ctf_name _kind_dict = { "nasion": CTF.CTFV_COIL_NAS, "left ear": CTF.CTFV_COIL_LPA, "right ear": CTF.CTFV_COIL_RPA, "spare": CTF.CTFV_COIL_SPARE, } _coord_dict = { "relative to dewar": FIFF.FIFFV_MNE_COORD_CTF_DEVICE, "relative to head": FIFF.FIFFV_MNE_COORD_CTF_HEAD, } def _read_one_coil_point(fid): """Read coil coordinate information from the hc file.""" # Descriptor one = "#" while len(one) > 0 and one[0] == "#": one = fid.readline() if len(one) == 0: return None one = one.strip().decode("utf-8") if "Unable" in one: raise RuntimeError("HPI information not available") # Hopefully this is an unambiguous interpretation p = dict() p["valid"] = "measured" in one for key, val in _coord_dict.items(): if key in one: p["coord_frame"] = val break else: p["coord_frame"] = -1 for key, val in _kind_dict.items(): if key in one: p["kind"] = val break else: p["kind"] = -1 # Three coordinates p["r"] = np.empty(3) for ii, coord in enumerate("xyz"): sp = fid.readline().decode("utf-8").strip() if len(sp) == 0: # blank line continue sp = sp.split(" ") if len(sp) != 3 or sp[0] != coord or sp[1] != "=": raise RuntimeError(f"Bad line: {one}") # We do not deal with centimeters p["r"][ii] = float(sp[2]) / 100.0 return p def _read_hc(directory): """Read the hc file to get the HPI info and to prepare for coord trans.""" fname, found = _make_ctf_name(directory, "hc", raise_error=False) if not found: logger.info(" hc data not present") return None s = list() with open(fname, "rb") as fid: while True: p = _read_one_coil_point(fid) if p is None: # First point bad indicates that the file is empty if len(s) == 0: logger.info("hc file empty, no data present") return None # Returns None if at EOF logger.info(" hc data read.") return s if p["valid"]: s.append(p)