实现凹凸多边形外扩与内缩, 无内缩外扩混乱问题

19 篇文章 0 订阅

效果

在这里插入图片描述

代码



bool isClockwise(const QPolygonF& poly)
{
    qreal sum = 0;
    int len = poly.size();

    for (int i = 0; i < len; ++i)
    {
        QPointF p1 = poly[i];
        QPointF p2 = poly[(i + 1) % len];  // 循环到第一个点

        sum += (p2.x() - p1.x()) * (p2.y() + p1.y());
    }

    return sum > 0;  // 如果结果大于0,多边形是顺时针的,否则是逆时针的
}

double norm(double x, double y)
{
    return sqrt(x * x + y * y);
}


QPolygonF shrinkPolygon(const QPolygonF& poly, double expand)
{
    if (isClockwise(poly)) expand = -expand;

    QList<QVector3D> polygon;
    foreach(auto p, poly) {
        QVector3D v3d(p.x(), p.y(), 0);
        if (!polygon.contains(v3d))
            polygon << v3d;
    }

    QList<QVector3D> new_polygon;
    int len = polygon.length();
    if(len<3) return poly;
    for (int i = 0; i < len; i++)
    {
        QVector3D p = polygon[i];
        QVector3D p1 = polygon[i == 0 ? len - 1 : i - 1];
        QVector3D p2 = polygon[i == len - 1 ? 0 : i + 1];
        float v1x = p1.x() - p.x();
        float v1y = p1.y() - p.y();
        float n1 = norm(v1x, v1y);
        float vv1x = v1x / n1;
        float vv1y = v1y / n1;
        float v2x = p2.x() - p.x();
        float v2y = p2.y() - p.y();
        float n2 = norm(v2x, v2y);
        float vv2x = v2x / n2;
        float vv2y = v2y / n2;
        float vectorLen = -expand / sqrt((1 - (vv1x * vv2x + vv1y * vv2y)) / 2.0f);
        float judge = v1x * v2y - v2x * v1y;
        if (judge > 0) vectorLen *= -1;
        float vx = vv1x + vv2x;
        float vy = vv1y + vv2y;
        vectorLen = vectorLen / norm(vx, vy);
        vx *= vectorLen;
        vy *= vectorLen;
        new_polygon.append(QVector3D(vx + p.x(), vy + p.y(), 0));
    }

    QPolygonF new_poly;
    foreach(auto p, new_polygon) new_poly << QPointF(p.x(), p.y());
    if (new_poly.first() != new_poly.back()) new_poly.append(new_poly.first());
    return new_poly;
}
  • 5
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 14
    评论
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值