完全填充自定义几何图形

9

我正在尝试找出如何完全填充自定义几何图形。这似乎是一个常见的问题,但我并没有真正找到任何解决方案。

我有以下示例几何图形:

    <Path Fill="White" Stretch="Fill" Stroke="Black" StrokeThickness="2">
        <Path.Data>
            <PathGeometry
                Figures="M112,296C112,296 136,296 136,320 M112,344C112,344 136,344 136,320 M112,296L112,296 96,296 96,344 112,344"/>
        </Path.Data>
    </Path>

这将产生以下结果:

不希望的填充结果

这是我想要看到的结果:

期望的填充结果

有什么想法吗?我知道我可以制作一个单一的弧线来解决这个特定的情况,但在我的应用程序中,用户可以绘制任何类型的几何图形,因此结果可能由任何数量的“基元”(PolyLineSegments、EllipseGeometries、ArcSegments 等)组成,并且如果所得到的几何图形包含某种类型的封闭区域,则我希望能够准确地填充该区域。

编辑:

这是一个示例,如果我确保所有三个相邻的几何图形重叠并使用以下代码创建联合 CombinedGeometry,则会看到 CombinedGeometry 的样子:

        <Path Grid.Row="2" Fill="White" Stretch="Fill" Stroke="Black" StrokeThickness="2">
        <Path.Data>
            <CombinedGeometry GeometryCombineMode="Union">
                <CombinedGeometry.Geometry1>
                    <CombinedGeometry GeometryCombineMode="Union">
                        <CombinedGeometry.Geometry1>
                            <PathGeometry
                                Figures="M111,293C111,296 136,293 136,325"/>
                        </CombinedGeometry.Geometry1>
                        <CombinedGeometry.Geometry2>
                            <PathGeometry
                                Figures="M111,346C111,344 136,344 136,320"/>
                        </CombinedGeometry.Geometry2>
                    </CombinedGeometry>
                </CombinedGeometry.Geometry1>
                <CombinedGeometry.Geometry2>
                    <PathGeometry
                        Figures="M125,296L115,296 96,296 96,344 120,344"/>
                </CombinedGeometry.Geometry2>
            </CombinedGeometry>
        </Path.Data>
    </Path>

以下是结果:

组合几何

我希望它可以将笔画联合起来,并自动找出新连续多边形的正确填充方式,但这并没有实现。

编辑2:

嗯,我想我想出了一些可能的解决方案,但都不像我希望的那么简单。第一个选项是使用CombineGeometry结构将所有几何图形组合在一起,然后在结果的"CombineGeometry"上调用"GetFlattenedPathGeometry"以获取PathGeometry。接下来,我遍历PathGeometry中的每个Figure,并仅删除那些是孔洞的(我认为您应该通过去掉所有完全被另一个包含的图形或孔洞可能有顺时针或逆时针坐标的约定来实现..),如果一切顺利,您应该得到一个完全填充的几何图形。

第二个选项是再次在结果路径上调用"GetFlattenedPathGeometry",以获取基于顶点的路径近似表示(不包括所有曲线、弧线、椭圆等符号,我们只需要包含点和线的路径)。之后,您只需将所有结果的figures/segments组合成一个图形,其线段按顺时针或逆时针排序。

我已经测试了这两种方法,并且它们似乎可以处理至少上面概述的简单测试用例,但它们无法处理更复杂的形状(自相交、凹形等).. 我需要支持.. 因此问题仍然存在,我该怎么做?

编辑3:

这里有一个更复杂的几何图形,其中排序/组合变得更加困难:

        <Path Fill="White" Stretch="Fill" Stroke="Black" StrokeThickness="2">
        <Path.Data>
            <PathGeometry
            Figures="M104,160C104,160 72,160 72,136
                M104,128C104,128 72,128 72,152
                M152,232L152,232 152,216 120,216 120,160 128,160
                M152,232L152,232 72,232 104,216 104,160 96,160
                M104,128L104,128 168,128
                M128,160L128,160 168,160
                M165,160L168,160 200,128
                M200,160L200,160 200,128
                M200,160L200,160 168,128 152,128"/>
        </Path.Data>
    </Path>

这将产生:

在此输入图片描述

3个回答

5
您的示例几何图形是由三个相邻的形状组合而成,它们不重叠。描边是绘制在外边缘上的,因为这些形状没有闭合,不存在内部描边线。虽然看起来形状正在合并并且描边应用于整个几何图形,但实际情况并非如此。
关闭空洞变成了一个更复杂的问题,需要使用编程方式检测空洞并使用适当的形状将其关闭,或者通过检测和跟踪外部点来创建一个新的组合形状,该形状没有空洞。我不知道 WPF 中是否有任何功能可帮助您完成此任务。存在一个 CombinedGeometry 类,可以生成两个重叠形状的联合。但是,此示例中的形状并不重叠。
如果没有上下文,很难推荐解决方案。如果这是一个自由绘图程序,也许用户只需在中间画另一个形状来关闭几何图形。

感谢您的回复。您所说的“关闭漏洞”,是指填充中的漏洞,还是相邻几何图形之间的小间隙?如果您指的是几何图形之间的间隙,我将很快发布一个简单的CombinedGeometry示例,当相邻几何图形的描边重叠并与联合组合时,似乎存在相同的问题。再次感谢! - Craig
很高兴能够帮忙。我指的是您试图填补的大面积,而不是相邻几何体之间的小缝隙。正如您编辑后的实验所示,多个形状的联合并不能消除孔洞。我在WPF中找不到任何功能可以识别和删除包含在接触或重叠几何体内的孔洞。您的方法是将几何体组合起来,并删除完全被包围的图形,听起来是一个很好的开始。 - Scott

2
把它看作是一个“连接点”的问题 :)
你有5个点:
  • 96,296 - 左上角点
  • 112,296 - 顶部 - 贝塞尔曲线的起点
  • 136,320 - 右侧 - 第一条贝塞尔曲线的结束,第二条贝塞尔曲线的起点
  • 112,344 - 底部 - 第二条贝塞尔曲线的结束
  • 96,344 - 左下角点
现在,我们将它们连接起来。
<Path Fill="White" Stretch="Fill" Stroke="Black" StrokeThickness="2">
    <Path.Data>
        <PathGeometry Figures="M112,296 C112,296 136,296 136,320 C136,320 136,344 112,344 M112,344 96,344 96,296 112,296"/>
    </Path.Data>
</Path>

您也可以使用<GeometryGroup FillRule="Nonzero" ...>来填充您的自定义路径。默认值为FillRule="EvenOdd",这会产生与您的填充相似的效果。

有关路径迷你语言的更多信息,请参见Path Markup Syntax (http://msdn.microsoft.com/en-us/library/ms752293.aspx)。

  • 将<Path>更改为<GeometryGroup>

编辑1:

我稍微调整了您的路径:

<Path Fill="White" Stretch="Fill" Stroke="Black" StrokeThickness="2">
    <Path.Data>
        <PathGeometry Figures="M72,152 C72,152 72,128 104,128 L168,128 200,160 200,128 168,160 120,160 120,216 152,216 152,232 72,232 104,216 104,160 C104,160 72,160 72,136"/>
    </Path.Data>
</Path>

这段文字的翻译如下:

这给了我们:

新形状

绘制路径就像使用矢量编辑软件中的某种“绘制形状”工具一样,您必须选择下一个点,当您没有下一个点时,形状会自动关闭(最后一个点连接到第一个点,但仅用于填充形状 - 当我们看新形状的“鼻子”时,我们可以看到它是如何完成的)。 在您的示例中,您有9个单独的形状(每个形状在单独的行中,其中M指定了新图形的开始),并且它们都以上述方式填充。

当然,您可以使用GeometryGroup(带有FillRule)或CombinedGeometry(带有CombinedGeometryMode)来连接形状。


谢谢回复。按顺时针顺序排序图形是我尝试过并发现适用于简单形状的方法,但对于更复杂的形状(自相交、凹形等),同样的方法不起作用。此外,Path没有属性“FillRule”(至少在.NET 3.5中没有),但我尝试将几何图形放入一个FillRule为Nonzero的GeometryGroup中,但结果相同。我很快会发布一个更复杂的几何图形,希望你能证明我错了 :)。 - Craig
不错。那么你会如何建议我以编程方式对几何图形进行排序呢?我的工具允许用户使用任意组合的几何图形构建这些形状,因此最终结果类似于我上面发布的内容,其中几何图形按照用户将它们添加到画布中的顺序进行排序。我需要以编程方式重新排序这些几何图形,以便正确填充它们。我尝试过使用CombinedGeometry,但它不仅联合了描边,还联合了填充,因此最终结果与开始时相似。 - Craig
创建几何图形时,您可以尝试添加下一个形状(“原语”),而无需启动新的图形(Mxxx,xxx)-例如,对于贝塞尔曲线,第一个控制点应自动设置(坐标与上一个点相同)。您可以尝试以下内容(x,y是自定义坐标):PathGeometry geom = new PathGeometry(); PathFigure path = new PathFigure(); path.StartPoint = new Point(x,y); geom.Figures.Add(path); LineSegment line = new LineSegment(); line.Point = new Point(x,y); path.Segments.Add(line); 以此类推... 您还应将geom分配给_xamlPathObject_.Data。 - Paweł Halicki
很遗憾,我不确定能够将这种类型的约束放在我的应用程序用户身上。我需要一种方法来得到目标几何形状,以便处理复杂的输入。我想知道如果我对输入几何图形进行镶嵌并绘制结果三角形而不是描边填充,是否可行。 - Craig

1

我找到了一篇有趣的文章,关于使用类似Inkscape这样的图形工具创建SVG文件,并在WPF中创建形状。这可能会给您一些启示。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接