package com.sundablog.clipper;

import com.sundablog.clipper.Path.OutRec;
import com.sundablog.clipper.Point.LongPoint;

import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

/**
 * Clipper基础抽象类,实现了Clipper接口的核心功能
 * 提供了多边形裁剪算法的基础框架和通用方法
 */
public abstract class ClipperBase implements Clipper {
    /**
     * 局部极小值类,用于表示多边形边缘的局部最低点
     */
    protected class LocalMinima {
        long y;             // 局部极小值的Y坐标
        Edge leftBound;     // 左边界边
        Edge rightBound;    // 右边界边
        LocalMinima next;   // 指向下一个局部极小值
    }

    /**
     * 扫描线类,用于表示扫描线算法中的扫描线位置
     */
    protected class Scanbeam {
        long y;          // 扫描线的Y坐标
        Scanbeam next;   // 指向下一条扫描线
    }

    /**
     * 局部极大值类,用于表示多边形边缘的局部最高点
     */
    protected class Maxima {
        long x;        // 局部极大值的X坐标
        Maxima next;   // 指向下一个局部极大值
        Maxima prev;   // 指向上一个局部极大值
    }

    /**
     * 初始化边的基本信息
     * @param e 当前要初始化的边
     * @param eNext 下一条边
     * @param ePrev 上一条边
     * @param pt 当前边的起点
     */
    private static void initEdge(Edge e, Edge eNext, Edge ePrev, LongPoint pt) {
        e.next = eNext;
        e.prev = ePrev;
        e.setCurrent(new LongPoint(pt));
        e.outIdx = Edge.UNASSIGNED;
    }

    /**
     * 初始化边的高级信息,设置边的上下端点和属性
     * @param e 要初始化的边
     * @param polyType 多边形类型(主体或裁剪)
     */
    private static void initEdge2(Edge e, PolyType polyType) {
        if (e.getCurrent().getY() >= e.next.getCurrent().getY()) {
            e.setBot(new LongPoint(e.getCurrent()));
            e.setTop(new LongPoint(e.next.getCurrent()));
        } else {
            e.setTop(new LongPoint(e.getCurrent()));
            e.setBot(new LongPoint(e.next.getCurrent()));
        }
        e.updateDeltaX();
        e.polyTyp = polyType;
    }

    /**
     * 检查坐标点是否在允许的范围内
     * @param Pt 要检查的坐标点
     * @throws IllegalStateException 如果坐标超出允许范围
     */
    private static void rangeTest(LongPoint Pt) {
        if (Pt.getX() > LOW_RANGE || Pt.getY() > LOW_RANGE || -Pt.getX() > LOW_RANGE || -Pt.getY() > LOW_RANGE) {
            if (Pt.getX() > HI_RANGE || Pt.getY() > HI_RANGE || -Pt.getX() > HI_RANGE || -Pt.getY() > HI_RANGE) {
                throw new IllegalStateException("Coordinate outside allowed range");
            }
        }
    }

    /**
     * 从双向链表中移除边(但不从内存中删除)
     * @param e 要移除的边
     * @return 返回下一条边
     */
    private static Edge removeEdge(Edge e) {
        //removes e from double_linked_list (but without removing from memory)
        e.prev.next = e.next;
        e.next.prev = e.prev;
        final Edge result = e.next;
        e.prev = null; //flag as removed (see ClipperBase.Clear)
        return result;
    }

    // 坐标值的低范围限制(防止溢出)
    private final static long LOW_RANGE = 0x3FFFFFFF;
    // 坐标值的高范围限制
    private final static long HI_RANGE = 0x3FFFFFFFFFFFFFFFL;

    protected LocalMinima minimaList;    // 局部极小值列表
    protected LocalMinima currentLM;     // 当前处理的局部极小值
    protected Scanbeam scanbeam;         // 扫描线列表
    protected final List<OutRec> polyOuts = new ArrayList<>(); // 输出多边形记录列表
    protected Edge activeEdges;          // 活动边列表
    protected boolean hasOpenPaths;      // 是否包含开放路径
    protected final boolean preserveCollinear; // 是否保留共线点
    private final static Logger LOGGER = Logger.getLogger(Clipper.class.getName()); // 日志记录器

    /**
     * 构造函数,初始化ClipperBase实例
     * @param preserveCollinear 是否保留共线点
     */
    protected ClipperBase(boolean preserveCollinear) //constructor (nb: no external instantiation)
    {
        this.preserveCollinear = preserveCollinear;
        minimaList = null;
        currentLM = null;
        hasOpenPaths = false;
    }

    /**
     * 添加单个路径到裁剪器中
     * @param pg 要添加的路径
     * @param polyType 路径的多边形类型(主体或裁剪)
     * @param Closed 是否为闭合路径
     * @return 添加是否成功
     */
    @Override
    public boolean addPath(Path pg, PolyType polyType, boolean Closed) {
        // 检查参数有效性:开放路径只能是主体路径
        if (!Closed && polyType == PolyType.CLIP) {
            throw new IllegalStateException("AddPath: Open paths must be subject.");
        }

        // 移除重复的端点(闭合路径)和相邻重复点
        int highI = pg.size() - 1;
        if (Closed) {
            while (highI > 0 && pg.get(highI).equals(pg.get(0))) {
                --highI;
            }
        }
        while (highI > 0 && pg.get(highI).equals(pg.get(highI - 1))) {
            --highI;
        }
        // 检查路径是否有效:闭合路径至少需要3个点,开放路径至少需要2个点
        if (Closed && highI < 2 || !Closed && highI < 1) {
            return false;
        }

        // 创建边数组
        final List<Edge> edges = new ArrayList<>(highI + 1);
        for (int i = 0; i <= highI; i++) {
            edges.add(new Edge());
        }

        boolean IsFlat = true; // 标记路径是否完全平坦(所有点在同一水平线上)

        // 第一阶段:基本边初始化
        edges.get(1).setCurrent(new LongPoint(pg.get(1)));
        rangeTest(pg.get(0));
        rangeTest(pg.get(highI));
        initEdge(edges.get(0), edges.get(1), edges.get(highI), pg.get(0));
        initEdge(edges.get(highI), edges.get(0), edges.get(highI - 1), pg.get(highI));
        for (int i = highI - 1; i >= 1; --i) {
            rangeTest(pg.get(i));
            initEdge(edges.get(i), edges.get(i + 1), edges.get(i - 1), pg.get(i));
        }
        Edge eStart = edges.get(0);

        // 第二阶段:移除重复顶点和(对于闭合路径)共线边
        Edge e = eStart, eLoopStop = eStart;
        for (;;) {
            // 允许开放路径的起点和终点相同
            if (e.getCurrent().equals(e.next.getCurrent()) && (Closed || !e.next.equals(eStart))) {
                if (e == e.next) {
                    break;
                }
                if (e == eStart) {
                    eStart = e.next;
                }
                e = removeEdge(e);
                eLoopStop = e;
                continue;
            }
            if (e.prev == e.next) {
                break; // 只有两个顶点
            }
            // 处理闭合路径中的共线边
            else if (Closed && Point.slopesEqual(e.prev.getCurrent(), e.getCurrent(), e.next.getCurrent())
                    && (!isPreserveCollinear() || !Point.isPt2BetweenPt1AndPt3(e.prev.getCurrent(), e.getCurrent(), e.next.getCurrent()))) {
                // 开放路径允许共线边,但闭合路径默认合并相邻共线边
                // 如果启用了PreserveCollinear属性,则只移除重叠的共线边(如尖刺)
                if (e == eStart) {
                    eStart = e.next;
                }
                e = removeEdge(e);
                e = e.prev;
                eLoopStop = e;
                continue;
            }
            e = e.next;
            if (e == eLoopStop || !Closed && e.next == eStart) {
                break;
            }
        }

        // 检查路径是否仍然有效
        if (!Closed && e == e.next || Closed && e.prev == e.next) {
            return false;
        }

        // 标记开放路径
        if (!Closed) {
            hasOpenPaths = true;
            eStart.prev.outIdx = Edge.SKIP;
        }

        // 第三阶段:边的第二阶段初始化
        e = eStart;
        do {
            initEdge2(e, polyType);
            e = e.next;
            if (IsFlat && e.getCurrent().getY() != eStart.getCurrent().getY()) {
                IsFlat = false;
            }
        } while (e != eStart);

        // 第四阶段:将边界添加到局部极小值列表

        // 完全平坦的路径需要特殊处理,以避免无限循环等问题
        if (IsFlat) {
            if (Closed) {
                return false;
            }
            e.prev.outIdx = Edge.SKIP;
            final LocalMinima locMin = new LocalMinima();
            locMin.next = null;
            locMin.y = e.getBot().getY();
            locMin.leftBound = null;
            locMin.rightBound = e;
            locMin.rightBound.side = Edge.Side.RIGHT;
            locMin.rightBound.windDelta = 0;
            for (;;) {
                if (e.getBot().getX() != e.prev.getTop().getX()) {
                    e.reverseHorizontal();
                }
                if (e.next.outIdx == Edge.SKIP) break;
                e.nextInLML = e.next;
                e = e.next;
            }
            insertLocalMinima(locMin);
            return true;
        }

        boolean leftBoundIsForward;
        Edge EMin = null;

        // 避免开放路径起点和终点相同时的无限循环
        if (e.prev.getBot().equals(e.prev.getTop())) {
            e = e.next;
        }

        // 处理所有局部极小值
        for (;;) {
            e = e.findNextLocMin();
            if (e == EMin) {
                break;
            } else if (EMin == null) {
                EMin = e;
            }

            // E和E.Prev共享一个局部极小值(水平时左对齐)
            // 比较斜率确定哪个开始哪个边界
            final LocalMinima locMin = new LocalMinima();
            locMin.next = null;
            locMin.y = e.getBot().getY();
            if (e.deltaX < e.prev.deltaX) {
                locMin.leftBound = e.prev;
                locMin.rightBound = e;
                leftBoundIsForward = false; // Q.nextInLML = Q.prev
            } else {
                locMin.leftBound = e;
                locMin.rightBound = e.prev;
                leftBoundIsForward = true; // Q.nextInLML = Q.next
            }
            locMin.leftBound.side = Edge.Side.LEFT;
            locMin.rightBound.side = Edge.Side.RIGHT;

            // 设置环绕数变化
            if (!Closed) {
                locMin.leftBound.windDelta = 0;
            } else if (locMin.leftBound.next == locMin.rightBound) {
                locMin.leftBound.windDelta = -1;
            } else {
                locMin.leftBound.windDelta = 1;
            }
            locMin.rightBound.windDelta = -locMin.leftBound.windDelta;

            // 处理边界
            e = processBound(locMin.leftBound, leftBoundIsForward);
            if (e.outIdx == Edge.SKIP) {
                e = processBound(e, leftBoundIsForward);
            }

            Edge E2 = processBound(locMin.rightBound, !leftBoundIsForward);
            if (E2.outIdx == Edge.SKIP) {
                E2 = processBound(E2, !leftBoundIsForward);
            }

            // 处理跳过的边
            if (locMin.leftBound.outIdx == Edge.SKIP) {
                locMin.leftBound = null;
            } else if (locMin.rightBound.outIdx == Edge.SKIP) {
                locMin.rightBound = null;
            }
            insertLocalMinima(locMin);
            if (!leftBoundIsForward) {
                e = E2;
            }
        }
        return true;
    }

    /**
     * 添加多个路径到裁剪器中
     * @param paths 要添加的路径集合
     * @param polyType 路径的多边形类型(主体或裁剪)
     * @param closed 是否为闭合路径
     * @return 至少有一个路径添加成功则返回true
     */
    @Override
    public boolean addPaths(Paths paths, PolyType polyType, boolean closed) {
        boolean result = false;
        for (Path path : paths) {
            if (addPath(path, polyType, closed)) {
                result = true;
            }
        }
        return result;
    }

    /**
     * 清除裁剪器中的所有路径和数据
     */
    @Override
    public void clear() {
        disposeLocalMinimaList();
        hasOpenPaths = false;
    }

    /**
     * 释放局部极小值列表资源
     */
    private void disposeLocalMinimaList() {
        while (minimaList != null) {
            final LocalMinima tmpLm = minimaList.next;
            minimaList = null;
            minimaList = tmpLm;
        }
        currentLM = null;
    }

    /**
     * 按Y坐标降序插入局部极小值到列表中
     * @param newLm 要插入的新局部极小值
     */
    private void insertLocalMinima(LocalMinima newLm) {
        if (minimaList == null) {
            minimaList = newLm;
        } else if (newLm.y >= minimaList.y) {
            newLm.next = minimaList;
            minimaList = newLm;
        } else {
            LocalMinima tmpLm = minimaList;
            while (tmpLm.next != null && newLm.y < tmpLm.next.y) {
                tmpLm = tmpLm.next;
            }
            newLm.next = tmpLm.next;
            tmpLm.next = newLm;
        }
    }

    /**
     * 检查是否保留共线点
     * @return 是否保留共线点
     */
    private boolean isPreserveCollinear() {
        return preserveCollinear;
    }

    /**
     * 弹出指定Y坐标的局部极小值
     * @param y Y坐标
     * @param current 当前局部极小值引用数组
     * @return 是否成功弹出
     */
    protected boolean popLocalMinima(long y, LocalMinima[] current) {
        LOGGER.entering(ClipperBase.class.getName(), "popLocalMinima");
        current[0] = currentLM;
        if (currentLM != null && currentLM.y == y) {
            currentLM = currentLM.next;
            return true;
        }
        return false;
    }

    /**
     * 处理边界边,设置下一个局部极小值边链接
     * @param e 要处理的边
     * @param LeftBoundIsForward 是否为前向左边界
     * @return 处理后的边
     */
    private Edge processBound(Edge e, boolean LeftBoundIsForward) {
        Edge EStart, result = e;
        Edge Horz;

        // 处理跳过的边
        if (result.outIdx == Edge.SKIP) {
            e = result;
            if (LeftBoundIsForward) {
                while (e.getTop().getY() == e.next.getBot().getY()) {
                    e = e.next;
                }
                while (e != result && e.deltaX == Edge.HORIZONTAL) {
                    e = e.prev;
                }
            } else {
                while (e.getTop().getY() == e.prev.getBot().getY()) {
                    e = e.prev;
                }
                while (e != result && e.deltaX == Edge.HORIZONTAL) {
                    e = e.next;
                }
            }
            // 根据处理结果设置返回值
            if (e == result) {
                if (LeftBoundIsForward) {
                    result = e.next;
                } else {
                    result = e.prev;
                }
            } else {
                // 创建新的局部极小值
                if (LeftBoundIsForward) {
                    e = result.next;
                } else {
                    e = result.prev;
                }
                final LocalMinima locMin = new LocalMinima();
                locMin.next = null;
                locMin.y = e.getBot().getY();
                locMin.leftBound = null;
                locMin.rightBound = e;
                e.windDelta = 0;
                result = processBound(e, LeftBoundIsForward);
                insertLocalMinima(locMin);
            }
            return result;
        }

        // 处理水平边
        if (e.deltaX == Edge.HORIZONTAL) {
            if (LeftBoundIsForward) {
                EStart = e.prev;
            } else {
                EStart = e.next;
            }
            // 处理相邻的水平边
            if (EStart.deltaX == Edge.HORIZONTAL) {
                if (EStart.getBot().getX() != e.getBot().getX() && EStart.getTop().getX() != e.getBot().getX()) {
                    e.reverseHorizontal();
                }
            } else if (EStart.getBot().getX() != e.getBot().getX()) {
                e.reverseHorizontal();
            }
        }

        EStart = e;
        // 处理前向边界
        if (LeftBoundIsForward) {
            while (result.getTop().getY() == result.next.getBot().getY() && result.next.outIdx != Edge.SKIP) {
                result = result.next;
            }
            // 处理顶部的水平边
            if (result.deltaX == Edge.HORIZONTAL && result.next.outIdx != Edge.SKIP) {
                Horz = result;
                while (Horz.prev.deltaX == Edge.HORIZONTAL) {
                    Horz = Horz.prev;
                }
                if (Horz.prev.getTop().getX() > result.next.getTop().getX()) {
                    result = Horz.prev;
                }
            }
            // 设置下一个局部极小值边链接
            while (e != result) {
                e.nextInLML = e.next;
                if (e.deltaX == Edge.HORIZONTAL && e != EStart && e.getBot().getX() != e.prev.getTop().getX()) {
                    e.reverseHorizontal();
                }
                e = e.next;
            }
            if (e.deltaX == Edge.HORIZONTAL && e != EStart && e.getBot().getX() != e.prev.getTop().getX()) {
                e.reverseHorizontal();
            }
            result = result.next; // 移动到当前边界之后的边
        }
        // 处理后向边界
        else {
            while (result.getTop().getY() == result.prev.getBot().getY() && result.prev.outIdx != Edge.SKIP) {
                result = result.prev;
            }
            // 处理顶部的水平边
            if (result.deltaX == Edge.HORIZONTAL && result.prev.outIdx != Edge.SKIP) {
                Horz = result;
                while (Horz.next.deltaX == Edge.HORIZONTAL) {
                    Horz = Horz.next;
                }
                if (Horz.next.getTop().getX() == result.prev.getTop().getX() ||
                        Horz.next.getTop().getX() > result.prev.getTop().getX()) {
                    result = Horz.next;
                }
            }

            // 设置下一个局部极小值边链接
            while (e != result) {
                e.nextInLML = e.prev;
                if (e.deltaX == Edge.HORIZONTAL && e != EStart && e.getBot().getX() != e.next.getTop().getX()) {
                    e.reverseHorizontal();
                }
                e = e.prev;
            }
            if (e.deltaX == Edge.HORIZONTAL && e != EStart && e.getBot().getX() != e.next.getTop().getX()) {
                e.reverseHorizontal();
            }
            result = result.prev; // 移动到当前边界之后的边
        }
        return result;
    }

    /**
     * 重置裁剪器状态,准备新的裁剪操作
     */
    protected void reset() {
        currentLM = minimaList;
        if (currentLM == null) {
            return; // 没有要处理的内容
        }

        // 重置所有边
        scanbeam = null;
        LocalMinima lm = minimaList;
        while (lm != null) {
            insertScanbeam(lm.y);
            Edge e = lm.leftBound;
            if (e != null) {
                e.setCurrent(new LongPoint(e.getBot()));
                e.outIdx = Edge.UNASSIGNED;
            }
            e = lm.rightBound;
            if (e != null) {
                e.setCurrent(new LongPoint(e.getBot()));
                e.outIdx = Edge.UNASSIGNED;
            }
            lm = lm.next;
        }
        activeEdges = null;
    }

    /**
     * 按Y坐标降序插入扫描线到列表中(忽略重复)
     * @param y 扫描线的Y坐标
     */
    protected void insertScanbeam(long y) {
        LOGGER.entering(ClipperBase.class.getName(), "insertScanbeam");

        // 单链表:降序排序,忽略重复
        if (scanbeam == null) {
            scanbeam = new Scanbeam();
            scanbeam.next = null;
            scanbeam.y = y;
        } else if (y > scanbeam.y) {
            final Scanbeam newSb = new Scanbeam();
            newSb.y = y;
            newSb.next = scanbeam;
            scanbeam = newSb;
        } else {
            Scanbeam sb2 = scanbeam;
            while (sb2.next != null && (y <= sb2.next.y)) {
                sb2 = sb2.next;
            }
            if (y == sb2.y) {
                return; // 忽略重复
            }
            final Scanbeam newSb = new Scanbeam();
            newSb.y = y;
            newSb.next = sb2.next;
            sb2.next = newSb;
        }
    }

    /**
     * 弹出下一条扫描线
     * @param y Y坐标数组,用于存储弹出的扫描线Y坐标
     * @return 是否成功弹出
     */
    protected boolean popScanbeam(long[] y) {
        if (scanbeam == null) {
            y[0] = 0;
            return false;
        }
        y[0] = scanbeam.y;
        scanbeam = scanbeam.next;
        return true;
    }

    /**
     * 检查是否有等待处理的局部极小值
     * @return 是否有等待处理的局部极小值
     */
    protected final boolean localMinimaPending() {
        return currentLM != null;
    }

    /**
     * 创建输出记录
     * @return 新创建的输出记录
     */
    protected OutRec createOutRec() {
        OutRec result = new OutRec();
        result.Idx = Edge.UNASSIGNED;
        result.isHole = false;
        result.isOpen = false;
        result.firstLeft = null;
        result.setPoints(null);
        result.bottomPt = null;
        result.polyNode = null;
        polyOuts.add(result);
        result.Idx = polyOuts.size() - 1;
        return result;
    }

    /**
     * 释放输出记录资源
     * @param index 要释放的输出记录索引
     */
    protected void disposeOutRec(int index) {
        OutRec outRec = polyOuts.get(index);
        outRec.setPoints(null);
        outRec = null;
        polyOuts.set(index, null);
    }

    /**
     * 更新边到活动边列表(AEL)
     * @param e 要更新的边
     * @throws IllegalStateException 如果调用无效
     */
    protected void updateEdgeIntoAEL(Edge e) {
        if (e.nextInLML == null) {
            throw new IllegalStateException("UpdateEdgeIntoAEL: invalid call");
        }
        final Edge aelPrev = e.prevInAEL;
        final Edge aelNext = e.nextInAEL;
        e.nextInLML.outIdx = e.outIdx;
        if (aelPrev != null) {
            aelPrev.nextInAEL = e.nextInLML;
        } else {
            activeEdges = e.nextInLML;
        }
        if (aelNext != null) {
            aelNext.prevInAEL = e.nextInLML;
        }
        e.nextInLML.side = e.side;
        e.nextInLML.windDelta = e.windDelta;
        e.nextInLML.windCnt = e.windCnt;
        e.nextInLML.windCnt2 = e.windCnt2;
        e = e.nextInLML;
        e.setCurrent(e.getBot());
        e.prevInAEL = aelPrev;
        e.nextInAEL = aelNext;
        if (e.isHorizontal()) {
            insertScanbeam(e.getTop().getY());
        }
    }

    /**
     * 在活动边列表中交换两个边的位置
     * @param edge1 第一个边
     * @param edge2 第二个边
     */
    protected void swapPositionsInAEL(Edge edge1, Edge edge2) {
        LOGGER.entering(ClipperBase.class.getName(), "swapPositionsInAEL");

        // 检查边是否已从AEL中移除
        if (edge1.nextInAEL == edge1.prevInAEL || edge2.nextInAEL == edge2.prevInAEL) {
            return;
        }

        // 处理相邻边的情况
        if (edge1.nextInAEL == edge2) {
            final Edge next = edge2.nextInAEL;
            if (next != null) {
                next.prevInAEL = edge1;
            }
            final Edge prev = edge1.prevInAEL;
            if (prev != null) {
                prev.nextInAEL = edge2;
            }
            edge2.prevInAEL = prev;
            edge2.nextInAEL = edge1;
            edge1.prevInAEL = edge2;
            edge1.nextInAEL = next;
        } else if (edge2.nextInAEL == edge1) {
            final Edge next = edge1.nextInAEL;
            if (next != null) {
                next.prevInAEL = edge2;
            }
            final Edge prev = edge2.prevInAEL;
            if (prev != null) {
                prev.nextInAEL = edge1;
            }
            edge1.prevInAEL = prev;
            edge1.nextInAEL = edge2;
            edge2.prevInAEL = edge1;
            edge2.nextInAEL = next;
        } else {
            // 处理非相邻边的情况
            final Edge next = edge1.nextInAEL;
            final Edge prev = edge1.prevInAEL;
            edge1.nextInAEL = edge2.nextInAEL;
            if (edge1.nextInAEL != null) {
                edge1.nextInAEL.prevInAEL = edge1;
            }
            edge1.prevInAEL = edge2.prevInAEL;
            if (edge1.prevInAEL != null) {
                edge1.prevInAEL.nextInAEL = edge1;
            }
            edge2.nextInAEL = next;
            if (edge2.nextInAEL != null) {
                edge2.nextInAEL.prevInAEL = edge2;
            }
            edge2.prevInAEL = prev;
            if (edge2.prevInAEL != null) {
                edge2.prevInAEL.nextInAEL = edge2;
            }
        }

        // 更新活动边列表的头部
        if (edge1.prevInAEL == null) {
            activeEdges = edge1;
        } else if (edge2.prevInAEL == null) {
            activeEdges = edge2;
        }

        LOGGER.exiting(ClipperBase.class.getName(), "swapPositionsInAEL");
    }

    /**
     * 从活动边列表中删除边
     * @param e 要删除的边
     */
    protected void deleteFromAEL(Edge e) {
        LOGGER.entering(ClipperBase.class.getName(), "deleteFromAEL");

        Edge aelPrev = e.prevInAEL;
        Edge aelNext = e.nextInAEL;
        // 检查边是否已被删除
        if (aelPrev == null && aelNext == null && (e != activeEdges)) {
            return; // already deleted
        }
        // 更新链表引用
        if (aelPrev != null) {
            aelPrev.nextInAEL = aelNext;
        } else {
            activeEdges = aelNext;
        }
        if (aelNext != null) {
            aelNext.prevInAEL = aelPrev;
        }
        // 清除边的AEL引用
        e.nextInAEL = null;
        e.prevInAEL = null;

        LOGGER.exiting(ClipperBase.class.getName(), "deleteFromAEL");
    }
}
最后修改:2025 年 12 月 01 日
如果觉得我的文章对你有用,请随意赞赏