package com.sundablog.clipper;

import java.util.ArrayList;

/**
 * 多边形路径集合类,扩展自ArrayList<Path>,用于存储和处理多个多边形路径
 * 提供从PolyTree转换、清理多边形、获取边界框等功能
 */
public class Paths extends ArrayList<Path> {

    /**
     * 从PolyTree中提取所有闭合路径
     * @param polytree 多边形树结构
     * @return 包含所有闭合路径的Paths集合
     */
    public static Paths closedPathsFromPolyTree(PolyTree polytree ) {
        final Paths result = new Paths();
        //        result.Capacity = polytree.Total;
        result.addPolyNode( polytree, PolyNode.NodeType.CLOSED ); // 递归添加所有闭合节点
        return result;
    }

    /**
     * 将完整的PolyTree转换为Paths集合,包含所有类型的路径
     * @param polytree 多边形树结构
     * @return 包含所有路径的Paths集合
     */
    public static Paths makePolyTreeToPaths(PolyTree polytree ) {

        final Paths result = new Paths();
        //        result.Capacity = polytree.Total;
        result.addPolyNode( polytree, PolyNode.NodeType.ANY ); // 递归添加所有节点
        return result;
    }

    /**
     * 从PolyTree中提取所有开放路径
     * @param polytree 多边形树结构
     * @return 包含所有开放路径的Paths集合
     */
    public static Paths openPathsFromPolyTree(PolyTree polytree ) {
        final Paths result = new Paths();
        //        result.Capacity = polytree.ChildCount;
        for (final PolyNode c : polytree.getChilds()) {
            if (c.isOpen()) { // 检查是否为开放路径
                result.add( c.getPolygon() ); // 添加开放路径的多边形
            }
        }
        return result;
    }

    /**
     * 序列化版本ID
     */
    private static final long serialVersionUID = 1910552127810480852L;

    /**
     * 默认构造函数,创建一个空的Paths集合
     */
    public Paths() {
        super();
    }

    /**
     * 创建具有指定初始容量的Paths集合
     * @param initialCapacity 初始容量
     */
    public Paths( int initialCapacity ) {
        super( initialCapacity );
    }

    /**
     * 递归地将PolyNode及其子节点添加到Paths集合中
     * @param polynode 要添加的多边形节点
     * @param nt 节点类型过滤器,指定添加开放/闭合/所有类型的节点
     */
    public void addPolyNode(PolyNode polynode, PolyNode.NodeType nt ) {
        boolean match = true;
        switch (nt) {
            case OPEN:
                return; // 如果需要开放节点但该方法不处理,直接返回
            case CLOSED:
                match = !polynode.isOpen(); // 检查节点是否为闭合节点
                break;
            default: // ANY类型,匹配所有节点
                break;
        }

        if (polynode.getPolygon().size() > 0 && match) { // 如果节点有多边形且匹配类型条件
            add( polynode.getPolygon() ); // 添加多边形到集合
        }
        // 递归处理所有子节点
        for (final PolyNode pn : polynode.getChilds()) {
            addPolyNode( pn, nt );
        }
    }

    /**
     * 清理所有多边形路径,移除冗余点,使用默认距离阈值
     * @return 清理后的Paths集合
     */
    public Paths cleanPolygons() {
        return cleanPolygons( 1.415 ); // 使用默认距离阈值约为√2
    }

    /**
     * 清理所有多边形路径,移除冗余点
     * @param distance 清理距离阈值,小于此距离的相邻点将被合并
     * @return 清理后的Paths集合
     */
    public Paths cleanPolygons(double distance ) {
        final Paths result = new Paths( size() ); // 创建与原集合大小相同的结果集合
        for (int i = 0; i < size(); i++) {
            result.add( get( i ).cleanPolygon( distance ) ); // 对每个多边形应用清理操作
        }
        return result;
    }

    /**
     * 计算所有路径的边界框
     * @return 包含所有路径的最小矩形边界
     */
    public LongRect getBounds() {
        int i = 0;
        final int cnt = size();
        final LongRect result = new LongRect();
        // 跳过空路径,找到第一个非空路径
        while (i < cnt && get( i ).isEmpty()) {
            i++;
        }
        if (i == cnt) { // 如果所有路径都为空,返回空边界框
            return result;
        }

        // 初始化边界框为第一个有效路径的第一个点
        result.left = get( i ).get( 0 ).getX();
        result.right = result.left;
        result.top = get( i ).get( 0 ).getY();
        result.bottom = result.top;
        // 遍历所有路径的所有点,更新边界框
        for (; i < cnt; i++) {
            for (int j = 0; j < get( i ).size(); j++) {
                if (get( i ).get( j ).getX() < result.left) {
                    result.left = get( i ).get( j ).getX();
                }
                else if (get( i ).get( j ).getX() > result.right) {
                    result.right = get( i ).get( j ).getX();
                }
                if (get( i ).get( j ).getY() < result.top) {
                    result.top = get( i ).get( j ).getY();
                }
                else if (get( i ).get( j ).getY() > result.bottom) {
                    result.bottom = get( i ).get( j ).getY();
                }
            }
        }
        return result;
    }

    /**
     * 反转所有路径的顶点顺序
     * 这会改变多边形的方向(顺时针变为逆时针,反之亦然)
     */
    public void reversePaths() {
        for (final Path poly : this) {
            poly.reverse(); // 调用每个路径的reverse方法
        }
    }

}
最后修改:2025 年 12 月 03 日
如果觉得我的文章对你有用,请随意赞赏