Запутался на Clipper в C#

Я создаю 2D игру в Unity, в которой процедурно размещены плитки. Я хочу упростить геометрию столкновений, используя библиотеку Клипера Ангуса Джонсона (в частности, функцию объединения), но у меня возникла проблема с библиотекой, возвращающей пустые решения, и я не уверен, почему.

Для справки вот полигональные коллайдеры, которые я использовал для тестирования. эталонное изображение

А вот упрощенная версия функции, которую я использую для объединения геометрии:

    List<List<Vector2>> unitedPolygons = new List<List<Vector2>>();
    Clipper clipper = new Clipper();
    Paths solution = new Paths();
    ClipperOffset offset = new ClipperOffset();

    //Use a scaling factor for floats and convert the Polygon Colliders' points to Clipper's desired format
    int scalingFactor = 10000;
    for (int i = 0; i < polygons.Count; i++)
    {
        Path allPolygonsPath = new Path(polygons[i].points.Length);

        for (int j = 0; j < polygons[i].points.Length; j++)
        {
            allPolygonsPath.Add(new IntPoint(Mathf.Floor(polygons[i].points[j].x * scalingFactor), Mathf.Floor(polygons[i].points[j].y * scalingFactor)));
        }
        bool succeeded = clipper.AddPath(allPolygonsPath, PolyType.ptSubject, true);
    }

    //Execute the union
    bool success = clipper.Execute(ClipType.ctUnion, solution);
    Debug.Log("Polygons after union: " + solution.Count);

    //Offset the polygons
    offset.AddPaths(solution, JoinType.jtMiter, EndType.etClosedPolygon);
    offset.Execute(ref solution, 5f);

    //Convert back to a format Unity can use
    foreach (Path path in solution)
    {
        List<Vector2> unitedPolygon = new List<Vector2>();
        foreach (IntPoint point in path)
        {
            unitedPolygon.Add(new Vector2(point.X / (float)scalingFactor, point.Y / (float)scalingFactor));
        }
        unitedPolygons.Add(unitedPolygon);
    }

    return unitedPolygons;

Благодаря отладке я обнаружил, что первый Execute (для объединения) возвращает пустое решение. Я выяснил, что функция "BuildResult" в классе "Clipper" действительно работает, и в "m_PolyOuts" есть данные, но свойство "Pts" для "OutRec" в этом списке все равно NULL. Я не могу понять, где это происходит или были ли они когда-либо установлены в первую очередь.

Я убежден, что это правильное поведение, и я просто неправильно использую библиотеку, но я не могу найти какую-либо документацию или примеры, объясняющие, что мне нужно изменить, чтобы объединение было успешным.

Благодарю.

РЕДАКТИРОВАТЬ: я сузил это немного больше. Во время "ExecuteInteral" в классе Clipper списки "Pts" не равны нулю, пока не будет запущена функция "FixupOutPolygon". После этого все списки будут нулевыми. "JoinCommonEdges" также делает несколько списков нулевыми, но не все из них.

1 ответ

Я также работал над своим собственным игровым проектом и наткнулся на похожую проблему с Clipper. В этом случае у меня получилось вместо того, чтобы написать это:

clipper.Execute(ClipType.ctUnion, solution);

... Я указал PolyFillType для метода Execute:

clipper.Execute(ClipType.ctUnion, solution, PolyFillType.pftNonZero, PolyFillType.pftNonZero);

Я не уверен, почему это сработало для меня, но я думаю, что это связано с тем, что некоторые контуры могут иметь общие ребра, поэтому с правилом заполнения pftEvenOdd по умолчанию это исключено.

Другие вопросы по тегам