{"size": 3614, "ext": "js", "max_stars_repo_path": "src/Entities/Spline.js", "max_stars_repo_name": "tarikjabiri/js-dxf", "max_stars_repo_stars_event_min_datetime": "2021-01-10T17:03:48.000Z", "max_stars_repo_stars_event_max_datetime": "2021-01-10T17:03:48.000Z", "max_issues_repo_path": "src/Entities/Spline.js", "max_issues_repo_name": "tarikjabiri/js-dxf", "max_issues_repo_issues_event_min_datetime": null, "max_issues_repo_issues_event_max_datetime": null, "max_forks_repo_path": "src/Entities/Spline.js", "max_forks_repo_name": "tarikjabiri/js-dxf", "max_forks_repo_forks_event_min_datetime": null, "max_forks_repo_forks_event_max_datetime": null}
{"max_stars_count": 1, "max_issues_count": null, "max_forks_count": null, "avg_line_length": 30.8888888889, "max_line_length": 129, "alphanum_fraction": 0.4861649142}
const TagsManager = require("../TagsManager");
const Entity = require("./Entity");

class Spline extends Entity {
    /**
     * Creates a spline. See https://www.autodesk.com/techpubs/autocad/acad2000/dxf/spline_dxf_06.htm
     * @param {[Array]} controlPoints - Array of control points like [ [x1, y1], [x2, y2]... ]
     * @param {number} degree - Degree of spline: 2 for quadratic, 3 for cubic. Default is 3
     * @param {[number]} knots - Knot vector array. If null, will use a uniform knot vector. Default is null
     * @param {[number]} weights - Control point weights. If provided, must be one weight for each control point. Default is null
     * @param {[Array]} fitPoints - Array of fit points like [ [x1, y1], [x2, y2]... ]
     */
    constructor(
        controlPoints,
        degree = 3,
        knots = null,
        weights = null,
        fitPoints = []
    ) {
        super("SPLINE");
        if (controlPoints.length < degree + 1) {
            throw new Error(
                `For degree ${degree} spline, expected at least ${
                    degree + 1
                } control points, but received only ${controlPoints.length}`
            );
        }

        if (knots == null) {
            // Examples:
            // degree 2, 3 pts:  0 0 0 1 1 1
            // degree 2, 4 pts:  0 0 0 1 2 2 2
            // degree 2, 5 pts:  0 0 0 1 2 3 3 3
            // degree 3, 4 pts:  0 0 0 0 1 1 1 1
            // degree 3, 5 pts:  0 0 0 0 1 2 2 2 2

            knots = [];
            for (let i = 0; i < degree + 1; i++) {
                knots.push(0);
            }
            for (let i = 1; i < controlPoints.length - degree; i++) {
                knots.push(i);
            }
            for (let i = 0; i < degree + 1; i++) {
                knots.push(controlPoints.length - degree);
            }
        }

        if (knots.length !== controlPoints.length + degree + 1) {
            throw new Error(
                `Invalid knot vector length. Expected ${
                    controlPoints.length + degree + 1
                } but received ${knots.length}.`
            );
        }

        this.controlPoints = controlPoints;
        this.knots = knots;
        this.fitPoints = fitPoints;
        this.degree = degree;
        this.weights = weights;
        this.flag = 8;
    }

    tags() {
        const manager = new TagsManager();

        manager.addTags(super.tags());
        manager.addSubclassMarker("AcDbSpline");
        manager.addTagsByElements([
            [210, 0.0],
            [220, 0.0],
            [230, 1.0],
        ]);

        manager.addTag(70, this.flag);
        manager.addTag(71, this.degree);
        manager.addTag(72, this.knots.length);
        manager.addTag(73, this.controlPoints.length);
        manager.addTag(74, this.fitPoints.length);

        manager.addTagsByElements([
            [42, 1e-7],
            [43, 1e-7],
            [44, 1e-10],
        ]);

        this.knots.forEach((knot) => {
            manager.addTag(40, knot);
        });

        if (this.weights) {
            this.weights.forEach((weight) => {
                manager.addTag(41, weight);
            });
        }

        this.controlPoints.forEach((point) => {
            const [x, y] = point;
            manager.addPointTags(x, y);
        });

        this.fitPoints.forEach((point) => {
            const [x, y] = point;
            manager.addTagsByElements([
                [11, x],
                [21, y],
                [31, 0],
            ]);
        });

        return manager.tags();
    }
}

module.exports = Spline;
