求解线段的包络线

包络(线)是在图形学中经常用到的一个概念,不严格的说法,是包含某个图形集的一个最小范围。对于多维空间,求解比较复杂,在二维空间中,对于普通的矩形较好处理,若不规则图形,则也比较复杂。下图给出一个二维矩形包络的情形,两个矩形的最小包含矩形。
____________________
|                          |                  |
+__________+        ____+
|                                   |         |
|_______________|____|

对于一维情形,就是普通的线段处理,比较简单。底下附上笔者用java编写的一个简单实现,供参考。可以考虑如何进行优化(算法改进,代码重构,指令优化等方向)。实际应用中,一些问题可以转化为求包络的问题。

package cn.itcast.client;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

// 线段描述对象[x1, x2]在数轴上的起止坐标
class Line implements Comparable {
    int x1;

    int x2;

    public Line(int x1, int x2) {
        this.x1 = x1;
        this.x2 = x2;
    }

    // 用'------'的形式模拟图形化输出线段
    public String toString() {
        //if (true) return x1 + ", " + x2;

        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < x1; i++) {
            sb.append(' ');
        }
        for (int i = x1; i < x2; i++) {
            sb.append('-');
        }

        return sb.toString();
    }

    public int getX1() {
        return x1;
    }

    public void setX1(int x1) {
        this.x1 = x1;
    }

    public int getX2() {
        return x2;
    }

    public void setX2(int x2) {
        this.x2 = x2;
    }

    public int compareTo(Object arg0) {
        Line l = (Line) arg0;
        return x1 - l.x1;

        /*
         * if (x1 <= l.x1) return -1; else return 1;
         */
    }
}

public class MaxLine {
    public static void main(String[] args) {
        // int[][] xy = {{1, 50}, {4, 60}};
        // System.out.println(xy[0][1]);
        MaxLine tst = new MaxLine();
       
        // 生成测试数据
        List lines = tst.generateLines();
        tst.printLines(lines);

        // 求解包络线并输出
        List list = tst.envelope(lines);
        System.out.println("output is:");
        tst.printLines(list);
    }

    // 求包络线
    public List envelope(List lines) {
        int len = lines.size();
        if (len == 1) return lines; // noop

        List res = new ArrayList();

        // 先对线段进行排序,按照x1升序排列
        Line[] arrLine = (Line[]) lines.toArray(new Line[len]);
        Arrays.sort(arrLine);

        // 两两合并
        for (int i = 0; i < len; i++) {
            if (i == len - 1) {
                res.add(arrLine[i]); // 加入最后一条线段到结果集中
                break;
            }
           
            // 取出尝试合并的两条线段
            Line l1 = arrLine[i];
            Line l2 = arrLine[i + 1];
           
            // 判断是否相交,即区间是否重叠
            int x1 = Math.max(l1.getX1(), l2.getX1());
            int x2 = Math.min(l1.getX2(), l2.getX2());
            if (x1 <= x2) { // 线段相交,l1合并到l2
                l2.setX1(Math.min(l1.getX1(), l2.getX1()));
                l2.setX2(Math.max(l1.getX2(), l2.getX2()));
            } else { // 线段不相交
                res.add(l1);
            }
        }

        return res;
    }

    public List generateLines() {
        List lines = new ArrayList();
        int maxLen = 20; // 最大线段长度
        int lineCount = 15; // 生成线段个数
        int start = 0; // 开始坐标x1
        int end = 100; // 结束坐标x2

        for (int i = 0; i < lineCount; i++) {
            int x1 = (int) (Math.random() * (end - maxLen));
            int x2 = x1 + (int) (Math.random() * maxLen);
       
            lines.add(new Line(x1, x2));
        }

        return lines;
    }

    // 命令行形式模拟线段输出
    public void printLines(List lines) {
        for (Iterator iter = lines.iterator(); iter.hasNext();) {
            Line l = (Line) iter.next();
            System.out.println(l);
        }
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值