package com.sundablog.clipper;

import com.sundablog.clipper.Clipper.EndType;
import com.sundablog.clipper.Clipper.JoinType;
import com.sundablog.clipper.Point.LongPoint;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * 多边形节点类,用于构建多边形树结构
 * 表示多边形裁剪结果中的一个节点,可以包含子节点(表示孔或嵌套多边形)
 */
public class PolyNode {

    /**
     * 节点类型枚举
     * ANY:任意类型节点
     * OPEN:开放路径节点
     * CLOSED:闭合路径节点
     */
    enum NodeType {
        ANY, OPEN, CLOSED
    }

    /**
     * 父节点引用
     */
    private PolyNode parent;

    /**
     * 存储当前节点的多边形路径
     */
    private final Path polygon = new Path();

    /**
     * 在父节点的子节点列表中的索引位置
     */
    private int index;

    /**
     * 多边形连接类型
     */
    private Clipper.JoinType joinType;

    /**
     * 多边形端点类型
     */
    private EndType endType;

    /**
     * 子节点列表,存储嵌套的多边形(如孔)
     */
    final List<PolyNode> childs = new ArrayList<>();

    /**
     * 标识当前节点是否为开放路径
     */
    private boolean isOpen;

    /**
     * 添加子节点到当前节点
     * @param child 要添加的子节点
     */
    public void addChild( PolyNode child ) {
        final int cnt = childs.size();
        childs.add( child );
        child.parent = this; // 设置子节点的父引用
        child.index = cnt; // 记录子节点在列表中的索引
    }

    /**
     * 获取子节点数量
     * @return 子节点数量
     */
    public int getChildCount() {
        return childs.size();
    }

    /**
     * 获取不可修改的子节点列表
     * @return 子节点列表的不可修改视图
     */
    public List<PolyNode> getChilds() {
        return Collections.unmodifiableList( childs );
    }

    /**
     * 获取多边形轮廓(顶点列表)
     * @return 多边形顶点列表
     */
    public List<LongPoint> getContour() {
        return polygon;
    }

    /**
     * 获取端点类型
     * @return 端点类型
     */
    public EndType getEndType() {
        return endType;
    }

    /**
     * 获取连接类型
     * @return 连接类型
     */
    public JoinType getJoinType() {
        return joinType;
    }

    /**
     * 获取遍历树结构的下一个节点
     * 优先返回第一个子节点,如果没有子节点则返回兄弟节点或向上查找
     * @return 下一个要遍历的节点,如果是最后一个节点则返回null
     */
    public PolyNode getNext() {
        if (!childs.isEmpty()) {
            return childs.get( 0 ); // 优先返回第一个子节点
        }
        else {
            return getNextSiblingUp(); // 查找兄弟节点或向上遍历
        }
    }

    /**
     * 递归查找下一个兄弟节点
     * 如果当前节点是父节点的最后一个子节点,则递归查找父节点的下一个兄弟节点
     * @return 下一个兄弟节点,如果没有则返回null
     */
    private PolyNode getNextSiblingUp() {
        if (parent == null) {
            return null; // 如果是根节点,没有父节点,返回null
        }
        else if (index == parent.childs.size() - 1) {
            // 如果是父节点的最后一个子节点,递归查找父节点的兄弟节点
            return parent.getNextSiblingUp();
        }
        else {
            // 返回父节点的下一个子节点
            return parent.childs.get( index + 1 );
        }
    }

    /**
     * 获取父节点
     * @return 父节点引用
     */
    public PolyNode getParent() {
        return parent;
    }

    /**
     * 获取多边形路径对象
     * @return 多边形路径
     */
    public Path getPolygon() {
        return polygon;
    }

    /**
     * 判断当前节点是否表示一个孔
     * 通过计算嵌套层级确定,奇数层为孔,偶数层为外部轮廓
     * @return 如果是孔返回true,否则返回false
     */
    public boolean isHole() {
        return isHoleNode();
    }

    /**
     * 判断节点是否为孔的内部实现
     * 通过向上遍历父节点链,切换孔状态标志
     * @return 如果是孔返回true,否则返回false
     */
    private boolean isHoleNode() {
        boolean result = true; // 初始假设为孔
        PolyNode node = parent;
        while (node != null) {
            result = !result; // 每向上一层切换一次状态
            node = node.parent;
        }
        return result; // 最终结果取决于嵌套深度
    }

    /**
     * 判断多边形是否为开放路径
     * @return 如果是开放路径返回true,否则返回false
     */
    public boolean isOpen() {
        return isOpen;
    }

    /**
     * 设置端点类型
     * @param value 要设置的端点类型
     */
    public void setEndType( EndType value ) {
        endType = value;
    }

    /**
     * 设置连接类型
     * @param value 要设置的连接类型
     */
    public void setJoinType( JoinType value ) {
        joinType = value;
    }

    /**
     * 设置多边形是否为开放路径
     * @param isOpen 开放路径标志
     */
    public void setOpen( boolean isOpen ) {
        this.isOpen = isOpen;
    }

    /**
     * 设置父节点
     * @param n 父节点引用
     */
    public void setParent( PolyNode n ) {
        parent = n;
    }

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