"""Point cloud section: read a SiteScape or Polycam point cloud, decimate it, cut a section, and draw the section line.
    Inputs:
        file_path: path to an XYZ / PTS / TXT / CSV point cloud file
        decimate: keep every Nth point (1 = keep all)
        axis: X, Y, or Z - the axis the cutting plane is normal to
        section_pos: coordinate of the cutting plane along that axis
        tolerance: half-thickness of the section slab, in model units
    Outputs:
        cloud_pts: the decimated cloud, for display
        section_pts: points inside the section slab
        section_line: polyline drawn through the section points
        status: message about what was read"""

import Rhino.Geometry as rg

cloud_pts = []
section_pts = []
section_line = None
status = "run"

if file_path is None or str(file_path).strip() == "":
    status = "No file path. Connect an XYZ or PTS file to the file_path input."
else:
    try:
        raw = []
        fp = str(file_path)
        ext = fp.lower().rsplit(".", 1)[-1]
        if ext in ("xyz", "pts", "txt", "csv", "asc"):
            with open(fp, "r") as f:
                for line in f:
                    line = line.strip()
                    if not line or line.startswith("#"):
                        continue
                    parts = line.replace(",", " ").split()
                    nums = []
                    for p in parts:
                        try:
                            nums.append(float(p))
                        except ValueError:
                            break
                    if len(nums) >= 3:
                        raw.append(rg.Point3d(nums[0], nums[1], nums[2]))
        else:
            try:
                from Rhino.FileIO import FilePointCloud
                pc = FilePointCloud.Read(fp)
                if pc is not None:
                    raw = list(pc.GetPoints())
            except Exception:
                raw = []

        if not raw:
            status = "No points read. Export an XYZ or PTS file from SiteScape or Polycam, then try again."
        else:
            step = decimate if decimate is not None else 1
            step = max(1, int(step))
            cloud_pts = raw[0::step]

            ax = str(axis).upper() if axis is not None else "X"

            def coord(pt):
                if ax == "Y":
                    return pt.Y
                if ax == "Z":
                    return pt.Z
                return pt.X

            sp = float(section_pos) if section_pos is not None else 0.0
            tol = float(tolerance) if tolerance is not None else 0.25
            section_pts = [p for p in cloud_pts if abs(coord(p) - sp) <= tol]

            if section_pts:
                if ax == "Z":
                    section_pts.sort(key=lambda p: (p.X, p.Y))
                elif ax == "Y":
                    section_pts.sort(key=lambda p: (p.X, p.Z))
                else:
                    section_pts.sort(key=lambda p: (p.Y, p.Z))
                section_line = rg.PolylineCurve(section_pts)

            status = "read {0}, kept {1}, {2} in section".format(len(raw), len(cloud_pts), len(section_pts))
    except Exception as e:
        status = "Error: {0}".format(e)
