js 切割三角形

在这里插入图片描述

前面我说过怎么切割圆形
三角形的切割就是每一条边(注意是线段)与另一个线段的交点的问题
我们把三角形的每一条边看成一个向量,切割的线段也是一个向量,这样就是两个向量求交点问题
image.png

现有向量AB 与向量CD 相交于P点
设A(x1,y1) , B(x2, y2),C(x3,y3) , D(x4, y4) ,P(x,y)
因为向量CP // 向量DP ,向量AP // 向量BP
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CaQmMvSD-1588848232447)(https://upload-images.jianshu.io/upload_images/4169630-4e53bbbaa80d4049.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)]

向量CP = ( x - x3 ,y - y3 )
向量DP = ( x - x4 ,y - y4 )
所以 (x - x3(y - y4) - (y - y3)(x - x4) = 0
x(y3 - y4) + y(x4 - x3) = x4y3 - x3y4
至此方程1出来了,下面求出方程2

向量AP = ( x - x1 ,y - y1 )
向量BP = ( x - x2 ,y - y2 )
(x - x1(y - y2) - (y - y1)(x - x2) = 0

x(y1 - y2) + y(x2 - x1) = x2y1 - x1y2
两个方程组成方程组
x(y3 - y4) + y(x4 - x3) = x4y3 - x3y4
x(y1 - y2) + y(x2 - x1) = x2y1 - x1y2
用行列式求解

在这里插入图片描述

需要判断D不能等于0

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

这样就求出交点

但是有这种情况
在这里插入图片描述

线段没有相交,但是用向量计算时还是会计算出交点,此时可以用CP+ PD = CD 并且
AP + PB = AB来排除这个点

class TriangleShape extends Shape {

        points = null;
        strokeColor = "#098231";
        fillColor = "#098231";
        cutFillColor = "#098231";
        strokeWidth = 0;


        constructor(option) {
            super(option);
            this.strokeColor = option.strokeColor;
            this.fillColor = option.fillColor;
            this.cutFillColor = option.cutFillColor;
            this.strokeWidth = option.strokeWidth;
            this.points = option.points;
        }

        reset(ctx) {
            this.hitChild = null;
            this.child.length = 0;
            this.isCut = false;
            this.drawSelf(ctx);
        }

        drawSelf(ctx) {
            ctx.beginPath();
            ctx.fillStyle = this.fillColor;
            ctx.moveTo(this.points[0], this.points[1]);
            ctx.lineTo(this.points[2], this.points[3]);
            ctx.lineTo(this.points[4], this.points[5]);
            ctx.closePath();
            ctx.fill();
            ctx.beginPath();
            ctx.strokeStyle = this.strokeColor;
            ctx.lineWidth = this.strokeWidth;
            ctx.moveTo(this.points[0], this.points[1]);
            ctx.lineTo(this.points[2], this.points[3]);
            ctx.lineTo(this.points[4], this.points[5]);
            ctx.closePath();
            ctx.stroke();

            this.drawText("a", this.points[0], this.points[1]);
            this.drawText("b", this.points[2], this.points[3]);
            this.drawText("c", this.points[4], this.points[5]);
        }


        drawText(text, x, y) {
            ctx.beginPath();
            ctx.font = "40px Arial";
            ctx.fillText(text, x, y);
            ctx.stroke();
        }


        onTouchUp(event, ctx) {
            super.onTouchUp(event, ctx);
            this.hitChild = null;
            if (this.isCut) {
                this.drawChild(ctx);
                return;
            }

            const points = this.getPoint();
            if (points && points.length === 2) {
                this.isCut = true;
                const p1 = points[0];
                const p2 = points[1];

                const a = {x: this.points[0], y: this.points[1]};
                const b = {x: this.points[2], y: this.points[3]};
                const c = {x: this.points[4], y: this.points[5]};

                const left = Math.min(Math.min(a.x, b.x), c.x);
                const top = Math.min(Math.min(a.y, b.y), c.y);
                const right = Math.max(Math.max(a.x, b.x), c.x);
                const bottom = Math.max(Math.max(a.y, b.y), c.y);

                const images = this.cutShape(p1, p2);
                this.child.push(new ChildShape(left, top, right - left, bottom - top, images[0]));
                this.child.push(new ChildShape(left, top, right - left, bottom - top, images[1]));
                this.drawChild(ctx);
            } else {
                this.drawSelf(ctx);
            }
        }


        cutShape(p1, p2) {
            const a = {x: this.points[0], y: this.points[1]};
            const b = {x: this.points[2], y: this.points[3]};
            const c = {x: this.points[4], y: this.points[5]};
            return Utils.toTriangleDataURL(a, b, c, p1, p2, this.fillColor, this.cutFillColor, this.strokeColor, this.strokeWidth);
        }

        getPoint() {
            const p = {x: this.cutLine.sx, y: this.cutLine.sy};
            const m = {x: this.cutLine.ex, y: this.cutLine.ey};

            const a = {x: this.points[0], y: this.points[1]};
            const b = {x: this.points[2], y: this.points[3]};
            const c = {x: this.points[4], y: this.points[5]};

            const array = [];
            const point1 = this.crossPoint(a, b, p, m);
            if (point1) {
                array.push(point1);
            }
            const point2 = this.crossPoint(b, c, p, m);
            if (point2) {
                array.push(point2);
            }
            const point3 = this.crossPoint(c, a, p, m);
            if (point3) {
                array.push(point3);
            }
            return array;

        }

         crossPoint(a, b, p, m) {
            const D = (a.y - b.y) * (m.x - p.x) - (b.x - a.x) * (p.y - m.y);
            if (D === 0) {
                //无解
                return;
            }
            const D1 = (b.x * a.y - a.x * b.y) * (m.x - p.x) - (b.x - a.x) * (m.x * p.y - p.x * m.y);
            const D2 = (a.y - b.y) * (m.x * p.y - p.x * m.y) - (p.y - m.y) * (b.x * a.y - a.x * b.y);
            const point = {x: D1 / D, y: D2 / D};
            if (Math.sqrt(Math.pow(point.x - a.x, 2) + Math.pow(point.y - a.y, 2)) + Math.sqrt(Math.pow(point.x - b.x, 2) + Math.pow(point.y - b.y, 2)) > Math.sqrt(Math.pow(b.x - a.x, 2) + Math.pow(b.y - a.y, 2)) ||
                Math.sqrt(Math.pow(point.x - p.x, 2) + Math.pow(point.y - p.y, 2)) + Math.sqrt(Math.pow(point.x - m.x, 2) + Math.pow(point.y - m.y, 2)) > Math.sqrt(Math.pow(p.x - m.x, 2) + Math.pow(p.y - m.y, 2))) {
                return;
            }
            return point;
        }
    }

Demo

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值