如何在使用几何形状的几何形状中围绕多个多边形绘制大纲。

发布于 2025-02-08 09:26:12 字数 1364 浏览 5 评论 0原文

因此,目前,我正在使用一系列的多边形,我想勾勒出一个轮廓并将其放入“ in”循环中,然后将其发送一个轮廓抽屉scipt。鳕鱼看起来像是如此:

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()

结果结果是这样的,所以我想知道是否有一种方法可以调整此代码以合并多边形,因此没有线路触摸的行盘旋的区域?所有的帮助都非常感谢! 结果的图片

So currently I'm taking the array of polygons I want to have an outline around and putting it in a "for in" loop, then sending it an outline drawer scipt. The cod looks like so:

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

And here is the code for the outline drawer:

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()

The results turn out like this so I'm wondering if there is a way to adapt this code to merge the polygons so there is no line where they touch like in the circled area? All help is much appreciated!
Picture of the results

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

夏九 2025-02-15 09:26:12

方法geomy.merge_polygons_2d将返回多边形的array(每个多边形都是pool> poolvector2array)。

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

  • 多边形根本没有触摸。在这种情况下,geome.merge_polygons_2d将返回原始边界。
  • 多边形触摸,但是当您合并它们时,它们会留下一个洞或孔。因此,戈多将返回外部的边界,然后再漏洞。

孔是多边形,其点顺时针顺时针序。边界是多边形,其点逆时针排序。


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

对于每个多边形:

  • 将其与先前的边界合并。 产生新的边界和孔。
  • 夹子(从先前的孔中减去)。 可能导致消除孔。

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

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


再一次。

我们有:

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

对于每个多边形:

  • 对于一个边界中的每个边界:
    • 合并它们。这为我们提供了新的边界和洞。将孔添加到一组孔中。
    • 如果结果中只有一个边界:
      • 从边界集中删除边界。
      • 用结果边界替换多边形。
    • 其他(它们不重叠):
      • 什么都不做(我们在最后将多边形添加到边界)。
  • 对于一组孔中的每个孔。
    • 将多边形从孔中夹住。
    • 如果结果为空:
      - 从孔组中取下孔。
    • 如果结果是单个项目(多边形和孔不重叠,则它们会部分重叠):
      - 用结果孔更换孔。
    • 其他(事实证明多边形完全在孔内):
      - 什么都不做(我们将多边形添加到末端的边界)。
  • 将多边形添加到边界集中。

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


最大的变化是,我们将与循环的操作不同。因为:

  • 我们在迭代时不应从集合中删除它们。因此,我们将添加到一个数组中要删除的元素,因此我们可以在末端删除它们。

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

  • 另外,由于边界部分可以增加孔,因此,如果我们在做孔部分之前添加这些孔,我们会浪费努力。

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

我们将使用geome.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

您可能拥有您认为处于同一行的事物,但实际上不是。而且我相信浮点错误会导致这一点。我希望这不是问题。

The method Geometry.merge_polygons_2d is going to return an Array of polygons (each polygon is a PoolVector2Array).

The reason that merging two polygons might not result in a polygon. There are two cases to note:

  • The polygons do not touch at all. In which case, Geometry.merge_polygons_2d will return the original boundaries.
  • The polygons touch, but when you merge them, they leave a hole, or holes. So Godot will return a boundaries for the outside, and then the holes.

The holes are polygons with their points ordered clockwise. The boundaries are polygons with their points ordered counterclockwise.


To merge multiple polygons properly, we need to keep track boundaries and holes. Considering that a third polygon might cover, or partially cover a hole, we have to…

For each polygon:

  • Merge it with the prior boundaries. Which results in new boundaries and holes.
  • Clip (subtract) it from the prior holes. Which might result in eliminating the hole.

Of course, there is also the case in which the third polygon bridges the gap between existing boundaries. We need to handle that case too. To do so, we will need to check if it merged or not, which I'll do by checking that there is only one boundary in the result.

To make this work we need to start with a boundary. So we could directly take the first one we will merge… But I'll use an empty polygon.


One more time.

We have:

  • A set of boundaries (initialized with an empty polygon).
  • A set of holes.

For each polygon:

  • For each boundary in the set of boundaries:
    • Merge them. This gives us new boundaries and holes. Add the holes to the set of holes.
    • If there is only one boundary in the result:
      • Remove the boundary from the set of boundaries.
      • Replace the polygon with the result boundary.
    • Else (they do not overlap):
      • Do nothing (we are adding the polygon to the boundaries at the end).
  • For each hole in the set of holes.
    • Clip the polygon from the hole.
    • If the result in empty:
      - Remove the hole from the set of holes.
    • If the result is single item (either the polygon and hole don't overlap, of they overlap partially):
      - Replace the hole with the result hole.
    • Else (turns out the polygon is entirely inside the hole):
      - Do nothing (we are adding the polygon to the boundaries at the end).
  • Add the polygon to the set of boundaries.

Hey, that almost looks like source code. We are getting there.


The big change is that we will be differing the operating past the loops. Because:

  • We should not remove from the sets while we are iterating over them. So we will instead add to an array the elements we want to remove, so we can remove them at the end.

  • Similarly, we will not exactly replace the hole either. We will remove the old one, and add the new one.

  • Also, since the boundaries part can add holes, we would be wasting effort comparing those holes if we add them before doing the holes part.

I'm converting the polygons to global coordinates before doing the operations.

We will be using Geometry.is_polygon_clockwise to tell holes from boundaries in the results.

And of course, we don't need to write the "Do nothing" branches.

Aside form that, this is the same as above:

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)

Ah, right. We should draw the outlines. Hmm… I guess both holes and boundaries would have them, right? This should do:

    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

You may have things that you believe are on the same line, but in practice aren't. And I believe floating point errors can cause that. I hope that is not an issue.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文