import { RadialGlyph, RadialGlyphView } from "./radial_glyph";
import { minmax2 } from "../../core/util/arrayable";
import { edge_intersection, point_in_poly, vertex_overlap } from "../../core/hittest";
import * as p from "../../core/properties";
import { Selection } from "../selections/selection";
function ngon(x, y, r, n, angle) {
    const xs = new Float32Array(n);
    const ys = new Float32Array(n);
    const alpha_i = 2 * Math.PI / n;
    for (let i = 0; i < n; i++) {
        const alpha = i * alpha_i + angle;
        xs[i] = x + r * Math.sin(alpha);
        ys[i] = y + r * -Math.cos(alpha);
    }
    return [xs, ys];
}
export class NgonView extends RadialGlyphView {
    static __name__ = "NgonView";
    async load_glglyph() {
        const { NgonGL } = await import("./webgl/ngon");
        return NgonGL;
    }
    _paint(ctx, indices, data) {
        const { sx, sy, sradius, angle, n } = { ...this, ...data };
        for (const i of indices) {
            const sx_i = sx[i];
            const sy_i = sy[i];
            const sradius_i = sradius[i];
            const angle_i = angle.get(i);
            const n_i = n.get(i);
            if (n_i < 3 || !isFinite(sx_i + sy_i + sradius_i + angle_i + n_i)) {
                continue;
            }
            const [sxs, sys] = ngon(sx_i, sy_i, sradius_i, n_i, angle_i);
            ctx.beginPath();
            ctx.moveTo(sxs[0], sys[0]);
            for (let i = 1; i <= n_i; i++) {
                ctx.lineTo(sxs[i], sys[i]);
            }
            ctx.closePath();
            this.visuals.fill.apply(ctx, i);
            this.visuals.hatch.apply(ctx, i);
            this.visuals.line.apply(ctx, i);
        }
    }
    _ngon(index) {
        const { sx, sy, sradius, angle, n } = { ...this };
        const sx_i = sx[index];
        const sy_i = sy[index];
        const sradius_i = sradius[index];
        const angle_i = angle.get(index);
        const n_i = n.get(index);
        return ngon(sx_i, sy_i, sradius_i, n_i, angle_i);
    }
    _hit_point(geometry) {
        const x = this.renderer.xscale.invert(geometry.sx);
        const y = this.renderer.yscale.invert(geometry.sy);
        const candidates = this.index.indices({ x0: x, y0: y, x1: x, y1: y });
        const indices = [];
        for (const index of candidates) {
            const [sxs, sys] = this._ngon(index);
            if (point_in_poly(geometry.sx, geometry.sy, sxs, sys)) {
                indices.push(index);
            }
        }
        return new Selection({ indices });
    }
    _hit_span(geometry) {
        const { sx, sy } = geometry;
        const { x0, x1, y0, y1 } = this.bounds();
        const [val, dim, candidates] = (() => {
            switch (geometry.direction) {
                case "v": {
                    const y = this.renderer.yscale.invert(sy);
                    const candidates = this.index.indices({ x0, y0: y, x1, y1: y });
                    return [sy, 1, candidates];
                }
                case "h": {
                    const x = this.renderer.xscale.invert(sx);
                    const candidates = this.index.indices({ x0: x, y0, x1: x, y1 });
                    return [sx, 0, candidates];
                }
            }
        })();
        const indices = [];
        for (const index of candidates) {
            const coords = this._ngon(index)[dim];
            for (let i = 0; i < coords.length - 1; i++) {
                if ((coords[i] <= val && val <= coords[i + 1]) || (coords[i + 1] <= val && val <= coords[i])) {
                    indices.push(index);
                    break;
                }
            }
        }
        return new Selection({ indices });
    }
    _hit_poly(geometry) {
        const { sx: gsx, sy: gsy } = geometry;
        const candidates = (() => {
            const xs = this.renderer.xscale.v_invert(gsx);
            const ys = this.renderer.yscale.v_invert(gsy);
            const [x0, x1, y0, y1] = minmax2(xs, ys);
            return this.index.indices({ x0, x1, y0, y1 });
        })();
        const indices = [];
        for (const index of candidates) {
            const [sxs, sys] = this._ngon(index);
            if (vertex_overlap(sxs, sys, gsx, gsy)) {
                indices.push(index);
                continue;
            }
            if (edge_intersection(sxs, sys, gsx, gsy)) {
                indices.push(index);
                continue;
            }
        }
        return new Selection({ indices });
    }
    _hit_rect(geometry) {
        const { sx0, sx1, sy0, sy1 } = geometry;
        const sxs = [sx0, sx1, sx1, sx0];
        const sys = [sy0, sy0, sy1, sy1];
        return this._hit_poly({ type: "poly", sx: sxs, sy: sys });
    }
}
export class Ngon extends RadialGlyph {
    static __name__ = "Ngon";
    constructor(attrs) {
        super(attrs);
    }
    static {
        this.prototype.default_view = NgonView;
        this.define(() => ({
            angle: [p.AngleSpec, 0],
            n: [p.NumberSpec, { field: "n" }],
        }));
    }
}
//# sourceMappingURL=ngon.js.map