cutWithLine(line) {
        let newPoly = this.clone();

        let multiline = new Multiline([line]);

        // smart intersections
        let intersections = {
            int_points1: [],
            int_points2: [],
            int_points1_sorted: [],
            int_points2_sorted: []
        };

        // intersect line with each edge of the polygon
        // and create smart intersections
        for (let edge of newPoly.edges) {
            let ip = intersectEdge2Line(edge, line);
            // for each intersection point
            for (let pt of ip) {
                addToIntPoints(multiline.first, pt, intersections.int_points1);
                addToIntPoints(edge, pt, intersections.int_points2);
            }
        }

        // No intersections - return a copy of the original polygon
        if (intersections.int_points1.length === 0)
            return newPoly;

        // sort smart intersections
        intersections.int_points1_sorted = getSortedArrayOnLine(line, intersections.int_points1);
        intersections.int_points2_sorted = getSortedArray(intersections.int_points2);

        // split by intersection points
        splitByIntersections(multiline, intersections.int_points1_sorted);
        splitByIntersections(newPoly, intersections.int_points2_sorted);

        // filter duplicated intersection points
        filterDuplicatedIntersections(intersections);

        // sort intersection points again after filtering
        intersections.int_points1_sorted = getSortedArrayOnLine(line, intersections.int_points1);
        intersections.int_points2_sorted = getSortedArray(intersections.int_points2);

        // initialize inclusion flags for edges of multiline incident to intersections
        initializeInclusionFlags(intersections.int_points1);

        // calculate inclusion flag for edges of multiline incident to intersections
        calculateInclusionFlags(intersections.int_points1, newPoly);

        // filter intersections between two edges that got same inclusion flag
        for (let int_point1 of intersections.int_points1_sorted) {
            if (int_point1.edge_before.bv === int_point1.edge_after.bv) {
                intersections.int_points2[int_point1.id] = -1;   // to be filtered out
                int_point1.id = -1;                              // to be filtered out
            }
        }
        intersections.int_points1 = intersections.int_points1.filter( int_point => int_point.id >= 0);
        intersections.int_points2 = intersections.int_points2.filter( int_point => int_point.id >= 0);

        // No intersections left after filtering - return a copy of the original polygon
        if (intersections.int_points1.length === 0)
            return newPoly;

        // sort intersection points 3d time after filtering
        intersections.int_points1_sorted = getSortedArrayOnLine(line, intersections.int_points1);
        intersections.int_points2_sorted = getSortedArray(intersections.int_points2);

        // Add 2 new inner edges between intersection points
        let int_point1_prev = intersections.int_points1[0];
        let new_edge;
        for (let int_point1_curr of intersections.int_points1_sorted) {
            if (int_point1_curr.edge_before.bv === INSIDE) {
                new_edge = new Flatten.Edge(new Flatten.Segment(int_point1_prev.pt, int_point1_curr.pt));    // (int_point1_curr.edge_before.shape);
                insertBetweenIntPoints(intersections.int_points2[int_point1_prev.id], intersections.int_points2[int_point1_curr.id], new_edge);
                newPoly.edges.add(new_edge);

                new_edge = new Flatten.Edge(new Flatten.Segment(int_point1_curr.pt, int_point1_prev.pt));    // (int_point1_curr.edge_before.shape.reverse());
                insertBetweenIntPoints(intersections.int_points2[int_point1_curr.id], intersections.int_points2[int_point1_prev.id], new_edge);
                newPoly.edges.add(new_edge);
            }
            int_point1_prev = int_point1_curr;
        }

        // Recreate faces
        newPoly.recreateFaces();
        return newPoly;
    }
/**
     * Return a result of cutting polygon with line
     * @param {Line} line - cutting line
     * @returns {Polygon} newPoly - resulted polygon
     */
Return a result of cutting polygon with line
@param {Line} line - cutting line
@returns {Polygon} newPoly - resulted polygon
Return a result of cutting polygon with line @param { Line } line - cutting line @returns { Polygon } newPoly - resulted polygon
cutWithLine(line) {
        let newPoly = this.clone();
        let multiline = new Multiline([line]);
        let intersections = {
            int_points1: [],
            int_points2: [],
            int_points1_sorted: [],
            int_points2_sorted: []
        };
        for (let edge of newPoly.edges) {
            let ip = intersectEdge2Line(edge, line);
            for (let pt of ip) {
                addToIntPoints(multiline.first, pt, intersections.int_points1);
                addToIntPoints(edge, pt, intersections.int_points2);
            }
        }
        if (intersections.int_points1.length === 0)
            return newPoly;
        intersections.int_points1_sorted = getSortedArrayOnLine(line, intersections.int_points1);
        intersections.int_points2_sorted = getSortedArray(intersections.int_points2);
        splitByIntersections(multiline, intersections.int_points1_sorted);
        splitByIntersections(newPoly, intersections.int_points2_sorted);
        filterDuplicatedIntersections(intersections);
        intersections.int_points1_sorted = getSortedArrayOnLine(line, intersections.int_points1);
        intersections.int_points2_sorted = getSortedArray(intersections.int_points2);
        initializeInclusionFlags(intersections.int_points1);
        calculateInclusionFlags(intersections.int_points1, newPoly);
        for (let int_point1 of intersections.int_points1_sorted) {
            if (int_point1.edge_before.bv === int_point1.edge_after.bv) {
                intersections.int_points2[int_point1.id] = -1;   
                int_point1.id = -1;                              
            }
        }
        intersections.int_points1 = intersections.int_points1.filter( int_point => int_point.id >= 0);
        intersections.int_points2 = intersections.int_points2.filter( int_point => int_point.id >= 0);
        if (intersections.int_points1.length === 0)
            return newPoly;
        intersections.int_points1_sorted = getSortedArrayOnLine(line, intersections.int_points1);
        intersections.int_points2_sorted = getSortedArray(intersections.int_points2);
        let int_point1_prev = intersections.int_points1[0];
        let new_edge;
        for (let int_point1_curr of intersections.int_points1_sorted) {
            if (int_point1_curr.edge_before.bv === INSIDE) {
                new_edge = new Flatten.Edge(new Flatten.Segment(int_point1_prev.pt, int_point1_curr.pt));    
                insertBetweenIntPoints(intersections.int_points2[int_point1_prev.id], intersections.int_points2[int_point1_curr.id], new_edge);
                newPoly.edges.add(new_edge);
                new_edge = new Flatten.Edge(new Flatten.Segment(int_point1_curr.pt, int_point1_prev.pt));    
                insertBetweenIntPoints(intersections.int_points2[int_point1_curr.id], intersections.int_points2[int_point1_prev.id], new_edge);
                newPoly.edges.add(new_edge);
            }
            int_point1_prev = int_point1_curr;
        }
        newPoly.recreateFaces();
        return newPoly;
    }
cutWithLine ( line ) { let newPoly = this . clone ( ) ; let multiline = new Multiline ( [ line ] ) ; let intersections = { int_points1 : [ ] , int_points2 : [ ] , int_points1_sorted : [ ] , int_points2_sorted : [ ] } ; for ( let edge of newPoly . edges ) { let ip = intersectEdge2Line ( edge , line ) ; for ( let pt of ip ) { addToIntPoints ( multiline . first , pt , intersections . int_points1 ) ; addToIntPoints ( edge , pt , intersections . int_points2 ) ; } } if ( intersections . int_points1 . length === 0 ) return newPoly ; intersections . int_points1_sorted = getSortedArrayOnLine ( line , intersections . int_points1 ) ; intersections . int_points2_sorted = getSortedArray ( intersections . int_points2 ) ; splitByIntersections ( multiline , intersections . int_points1_sorted ) ; splitByIntersections ( newPoly , intersections . int_points2_sorted ) ; filterDuplicatedIntersections ( intersections ) ; intersections . int_points1_sorted = getSortedArrayOnLine ( line , intersections . int_points1 ) ; intersections . int_points2_sorted = getSortedArray ( intersections . int_points2 ) ; initializeInclusionFlags ( intersections . int_points1 ) ; calculateInclusionFlags ( intersections . int_points1 , newPoly ) ; for ( let int_point1 of intersections . int_points1_sorted ) { if ( int_point1 . edge_before . bv === int_point1 . edge_after . bv ) { intersections . int_points2 [ int_point1 . id ] = - 1 ; int_point1 . id = - 1 ; } } intersections . int_points1 = intersections . int_points1 . filter ( int_point => int_point . id >= 0 ) ; intersections . int_points2 = intersections . int_points2 . filter ( int_point => int_point . id >= 0 ) ; if ( intersections . int_points1 . length === 0 ) return newPoly ; intersections . int_points1_sorted = getSortedArrayOnLine ( line , intersections . int_points1 ) ; intersections . int_points2_sorted = getSortedArray ( intersections . int_points2 ) ; let int_point1_prev = intersections . int_points1 [ 0 ] ; let new_edge ; for ( let int_point1_curr of intersections . int_points1_sorted ) { if ( int_point1_curr . edge_before . bv === INSIDE ) { new_edge = new Flatten . Edge ( new Flatten . Segment ( int_point1_prev . pt , int_point1_curr . pt ) ) ; insertBetweenIntPoints ( intersections . int_points2 [ int_point1_prev . id ] , intersections . int_points2 [ int_point1_curr . id ] , new_edge ) ; newPoly . edges . add ( new_edge ) ; new_edge = new Flatten . Edge ( new Flatten . Segment ( int_point1_curr . pt , int_point1_prev . pt ) ) ; insertBetweenIntPoints ( intersections . int_points2 [ int_point1_curr . id ] , intersections . int_points2 [ int_point1_prev . id ] , new_edge ) ; newPoly . edges . add ( new_edge ) ; } int_point1_prev = int_point1_curr ; } newPoly . recreateFaces ( ) ; return newPoly ; }
Return a result of cutting polygon with line
 @param {Line} line - cutting line
 @returns {Polygon} newPoly - resulted polygon
Return a result of cutting polygon with line @param { Line } line - cutting line @returns { Polygon } newPoly - resulted polygon
// smart intersections // intersect line with each edge of the polygon // and create smart intersections // for each intersection point // No intersections - return a copy of the original polygon // sort smart intersections // split by intersection points // filter duplicated intersection points // sort intersection points again after filtering // initialize inclusion flags for edges of multiline incident to intersections // calculate inclusion flag for edges of multiline incident to intersections // filter intersections between two edges that got same inclusion flag // to be filtered out // to be filtered out // No intersections left after filtering - return a copy of the original polygon // sort intersection points 3d time after filtering // Add 2 new inner edges between intersection points // (int_point1_curr.edge_before.shape); // (int_point1_curr.edge_before.shape.reverse()); // Recreate faces