繁体   English   中英

在 godot 中使用 Geometry.merge_polygons_2d() 时,如何在接触多边形共享边界的同时围绕多个多边形绘制轮廓?

[英]How to draw an outline around multiple polygons while having touching polygons share a border in using Geometry.merge_polygons_2d() in godot?

所以目前我正在获取我想要有一个轮廓的多边形数组并将它放在一个“for in”循环中,然后向它发送一个轮廓抽屉脚本。 鳕鱼看起来像这样:

func _ready():
var provs = [$Polygon2D4,$Polygon2D,$Polygon2D3]
var outline_drawer = $outline_drawer
outline_drawer.color = Color(0.06,0.71,0.74) / Color(2,2,2)
var merge := []
var merged_provs := []
for p in range(provs.size()):
    var poly = provs[p]
    var points = poly.global_transform.xform(poly.polygon)
    merged_provs.append(points) 
var outlines_local := []
var global_to_local: Transform2D = outline_drawer.global_transform.affine_inverse()
for outline_global in merged_provs:
    outlines_local.append(global_to_local.xform(outline_global))
outline_drawer.outlines = outlines_local

这是大纲抽屉的代码:

export(Color) var color = Color(0,0,0) setget set_color
export(float) var width = 1.5 setget set_width

var outlines = [] setget set_outlines

func _draw():
    for outline in outlines:
        for i in outline.size():
            draw_line(outline[i-1] , outline[i], color, width)

func set_color(value):
    color = value
    update()

func set_width(value):
    width = value
    update()

func set_outlines(value):
    outlines = value
    update()

结果是这样的,所以我想知道是否有办法调整这段代码来合并多边形,这样在圆圈区域中就没有它们接触的线? 非常感谢所有帮助! 结果图片

Geometry.merge_polygons_2d方法将返回一个多边形Array (每个多边形都是一个PoolVector2Array )。

合并两个多边形可能不会产生多边形的原因。 有两种情况需要注意:

  • 多边形根本不接触。 在这种情况下, Geometry.merge_polygons_2d将返回原始边界。
  • 多边形接触,但是当你合并它们时,它们会留下一个或多个洞。 所以 Godot 会为外部返回一个边界,然后是洞。

这些孔是多边形,其点按顺时针方向排列。 边界是多边形,其点按逆时针方向排列。


要正确合并多个多边形,我们需要保持轨道边界和孔洞。 考虑到第三个多边形可能会覆盖或部分覆盖一个洞,我们必须……

对于每个多边形:

  • 将其与先前的边界合并。 这会导致新的边界和漏洞。
  • 从先前的孔中剪辑(减去)它。 这可能会导致消除孔。

当然,也有第三个多边形在现有边界之间架起桥梁的情况。 我们也需要处理这种情况。 为此,我们需要检查它是否合并,我将通过检查结果中是否只有一个边界来做到这一点。

为了完成这项工作,我们需要从边界开始。 所以我们可以直接取第一个我们将合并的...但我将使用一个空多边形。


再一次。

我们有:

  • 一组边界(以空多边形初始化)。
  • 一组孔。

对于每个多边形:

  • 对于边界集中的每个边界:
    • 合并它们。 这给了我们新的界限和漏洞。 将孔添加到孔集。
    • 如果结果中只有一个边界:
      • 从边界集中移除边界。
      • 用结果边界替换多边形。
    • 否则(它们不重叠):
      • 什么都不做(我们将多边形添加到最后的边界)。
  • 对于孔组中的每个孔。
    • 从孔中剪下多边形。
    • 如果结果为空: - 从孔组中删除孔。
    • 如果结果是单个项目(多边形和孔不重叠,它们部分重叠): - 用结果孔替换孔。
    • 否则(原来多边形完全在孔内): - 什么都不做(我们将多边形添加到最后的边界)。
  • 将多边形添加到边界集。

嘿,这几乎看起来像源代码。 我们正在到达那里。


最大的变化是我们将在循环之后进行不同的操作。 因为:

  • 在迭代它们时,我们不应该从集合中删除。 因此,我们将改为将要删除的元素添加到数组中,这样我们就可以在最后删除它们。

  • 同样,我们也不会完全替换孔。 我们将删除旧的,并添加新的。

  • 此外,由于边界部分可以添加孔,如果我们在做孔部分之前添加它们,我们将浪费精力比较这些孔。

在进行操作之前,我将多边形转换为全局坐标。

我们将使用Geometry.is_polygon_clockwise来区分结果中的孔和边界。

当然,我们不需要编写“什么都不做”分支。

除此之外,这与上面的相同:

func _ready() -> void:
    # We have
    # - A set of boundaries (initialized with an empty polygon).
    var boundaries := [PoolVector2Array()]
    # - A set of holes.
    var holes := []

    # For each polygon:
    var polygons := [
        $Polygon1.global_transform.xform($Polygon1.polygon),
        $Polygon2.global_transform.xform($Polygon2.polygon),
        $Polygon3.global_transform.xform($Polygon3.polygon)
    ]
    for polygon in polygons:
        var boundaries_to_remove := []
        var holes_to_remove := []
        var holes_to_add := []

        # BOUNDARIES

        # - For each boundary in the set of boundaries:
        for boundary in boundaries:
            # - Merge them.
            var result := Geometry.merge_polygons_2d(polygon, boundary)
            var result_boundaries := []
            for result_polygon in result:
                if Geometry.is_polygon_clockwise(result_polygon):
                    # Hole
                    # Add the holes to the set of holes.
                    holes_to_add.append(result_polygon)
                else:
                    # Boundary
                    result_boundaries.append(result_polygon)

            # - If there is only one boundary in the result:
            if result_boundaries.size() == 1:
                # They merged
                # - Remove the boundary from the set of boundaries. (AFTER THE LOOP)
                boundaries_to_remove.append(boundary)
                # - Replace the polygon with the result boundary.
                polygon = result_boundaries[0]

        for boundary_to_remove in boundaries_to_remove:
            boundaries.erase(boundary_to_remove)

        # HOLES

        # - For each hole in the set of holes.
        for hole in holes:
            # - Clip the polygon from the hole.
            var result := Geometry.clip_polygons_2d(polygon, hole)
            # - If the result in empty:
            if result.size() == 0:
                # - Remove the hole from the set of holes. (AFTER THE LOOP)
                holes_to_remove.append(hole)
            
            # - If the result is single item
            if result.size() == 1:
                # - Replace the hole with the result hole. (AFTER THE LOOP)
                holes_to_remove.append(hole)
                holes_to_add.append(result[0])

        for hole_to_remove in holes_to_remove:
            holes.erase(hole_to_remove)

        for hole_to_add in holes_to_add:
            holes.append(hole_to_add)

        # ---

        # - Add the polygon to the set of boundaries.
        boundaries.append(polygon)

啊,对。 我们应该画出轮廓。 嗯……我猜洞和边界都会有它们,对吧? 这应该这样做:

    var outline_drawer := $outline_drawer
    var outlines_local := []
    var global_to_local:Transform2D = outline_drawer.global_transform.affine_inverse()
    for outline_global in holes:
        outlines_local.append(global_to_local.xform(outline_global))

    for outline_global in boundaries:
        outlines_local.append(global_to_local.xform(outline_global))

    outline_drawer.outlines = outlines_local

你可能有一些你认为在同一条线上的东西,但实际上并非如此。 而且我相信浮点错误会导致这种情况。 我希望这不是问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM