【项目实训】多段线扩充为平行线

线条的变换处理较为容易,通过增加关键点的位置即可,其svg格式即将关键点顺序连接。

关键点分为透明和不透明两种,二者均可以拖动,透明关键点与不透明关键点交叉出现,而且透明关键点位于其相邻的不透明关键点的中点。端点始终是不透明关键点

 

在拖动关键点时,分为端点和内部的关键点。若是端点,则可以直接改变坐标,若是内部的关键点,则在改变关键点后并多出来两个内部关键点,新的关键点出现在中点处。

而且在拖动内部关键点时,可能会与其相邻的左右关键点成为一条直线,此时要将其删除。

std::string res = "M " + std::to_string(startPoint->getX()) + " "
                              + std::to_string(startPoint->getY()) + " ";

            for (int i = 2; i < (int) pointList.size(); i += 2) {
                res += "L " + std::to_string(pointList[i]->getX()) + " " + std::to_string(pointList[i]->getY()) + " ";
            }
            return res;

将线条扩充为平行线,首先要记录线条的形状,然后再向外扩充。

主要找各种转折点,然后顺序连线即可,起点和终点都算一种特殊转折点
这样每个线段也就有了对应的2条等距平行线的描述方程,相近的2条等距平行线有且只有1个交点,就是对应的等距平行线上的转折点。

std::vector<Lewzen::Point2D> Line::offsetCoords(std::vector<Lewzen::Point2D> coords, double offset) {
        std::vector<Lewzen::Point2D> path;

        int N = coords.size() - 1;
        int max = N;
        double mi, mi1, li, li1, ri, ri1, si, si1, Xi1, Yi1;
        Lewzen::Point2D p0(0, 0), p1(0, 0), p2(0, 0);
        int isClosed = (coords[0].get_x() == coords[N].get_x() &&
                        coords[0].get_y() == coords[N].get_y());
        if (!isClosed) {
            p0 = coords[0];
            p1 = coords[1];
            p2 = Lewzen::Point2D(p0.get_x() + (p1.get_y() - p0.get_y()) / dist2d(p0, p1) * offset,
                                 p0.get_y() - (p1.get_x() - p0.get_x()) / dist2d(p0, p1) * offset);

            path.push_back(p2);
            coords.push_back(coords[N]);
            N++;
            max--;
        }
        for (int i = 0; i < max; i++) {
            p0 = coords[i];
            p1 = coords[(i + 1) % N];
            p2 = coords[(i + 2) % N];
            mi = (p1.get_y() - p0.get_y()) / (p1.get_x() - p0.get_x());
            mi1 = (p2.get_y() - p1.get_y()) / (p2.get_x() - p1.get_x());
            // Prevent alignements
            if (fabs(mi - mi1) > 1e-10) {
//            li = Math.sqrt((p1[0] - p0[0])*(p1[0] - p0[0])+(p1[1] - p0[1])*(p1[1] - p0[1]));
//            li1 = Math.sqrt((p2[0] - p1[0])*(p2[0] - p1[0])+(p2[1] - p1[1])*(p2[1] - p1[1]));
                li = dist2d(p1, p0);
                li1 = dist2d(p2, p1);
                ri = p0.get_x() + offset * (p1.get_y() - p0.get_y()) / li;
                ri1 = p1.get_x() + offset * (p2.get_y() - p1.get_y()) / li1;
                si = p0.get_y() - offset * (p1.get_x() - p0.get_x()) / li;
                si1 = p1.get_y() - offset * (p2.get_x() - p1.get_x()) / li1;
                Xi1 = (mi1 * ri1 - mi * ri + si - si1) / (mi1 - mi);
                Yi1 = (mi * mi1 * (ri1 - ri) + mi1 * si - mi * si1) / (mi1 - mi);
                // Correction for vertical lines
                if (p1.get_x() - p0.get_x() == 0) {
                    Xi1 = p1.get_x() + offset * (p1.get_y() - p0.get_y()) / fabs(p1.get_y() - p0.get_y());
                    Yi1 = mi1 * Xi1 - mi1 * ri1 + si1;
                }
                if (p2.get_x() - p1.get_x() == 0) {
                    Xi1 = p2.get_x() + offset * (p2.get_y() - p1.get_y()) / fabs(p2.get_y() - p1.get_y());
                    Yi1 = mi * Xi1 - mi * ri + si;
                }
                path.push_back(Lewzen::Point2D(Xi1, Yi1));
            }
        }
        if (isClosed) {
            path.push_back(path[0]);
        } else {
            coords.pop_back();
            p0 = coords[coords.size() - 1];
            p1 = coords[coords.size() - 2];
            p2 = Lewzen::Point2D(p0.get_x() - (p1.get_y() - p0.get_y()) / dist2d(p0, p1) * offset,
                                 p0.get_y() + (p1.get_x() - p0.get_x()) / dist2d(p0, p1) * offset);
            path.push_back(p2);
        }
        return path;
    }

折线扩充后的形状

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值