如何通过集合操作组合形状?
How to combine shapes via set operations?
我想从一个形状中减去另一个形状,然后将生成的形状与另一个形状组合。在我的例子中,一个正方形被剪成两半,被剪掉的版本将向右延伸半个圆圈。
因此,我通过 difference
从另一个正方形中减去一个正方形,并假设重叠区域只会合并,并用整个圆制作一个 union
。
我在考虑 ({1,2,3,4} / {3,4}) U {2,3}
等于 {1,2,3}
的集合操作,但在我的实现中它等于 {1,3}
:
import Diagrams.Backend.SVG.CmdLine
{-# LANGUAGE NoMonomorphismRestriction #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeFamilies #-}
import Diagrams.Prelude
import qualified Diagrams.TwoD.Path.Boolean as B
main = mainWith (combination # fc red # bgFrame 0.1 white)
where
combination :: QDiagram B V2 Double Any
combination = strokePath plusCircle
shorterSquare = B.difference Winding (square 2) (square 2 # translateX 1)
plusCircle = B.union Winding (circle 1 <> shorterSquare)
但我明白了:
这不是我想要的,我想要半圆和矩形合并,结果只填充红色,里面没有线。
我不是图表方面的专家,但看起来您是在组合笔划路径而不是它们所代表的形状。 Fill Rules 关于缠绕填充规则如何针对自身重叠的笔划路径表现,有一些有趣的事情要说,这似乎与解释为什么会得到这样的结果有关。
相反,我建议使用 Composing diagrams 中的技术,例如 atop
,来组合完整的形状。
B.difference
的这种特殊用法反转了 shorterSquare
路径的方向,因此您需要 re-reverse it:
shorterSquare = B.difference Winding (square 2) (square 2 # translateX 1)
# reversePath
因为这很微妙,所以花点时间描述一下我是如何诊断它的是值得的。首先,这种古怪的填充规则感觉很像由路径(或面等)方向引起的那种问题。其次,将 shorterSquare
重新定义为...
shorterSquare = square 2 # scaleX 0.5 # translateX 0.5
... 给出了预期的结果。这意味着问题与 B.difference
和 shorterSquare
的定义有关,而不是 B.union
。可以通过pathVertices
:
获取确认
GHCi> -- Counterclockwise.
GHCi> pathVertices $ square 2 # scaleX 0.5 # translateX 0.5
[[P (V2 1.0 (-1.0)),P (V2 0.9999999999999999 1.0),P (V2 (-1.1102230246251565e-16) 1.0),P (V2 (-2.220446049250313e-16) (-1.0))]]
GHCi> -- Clockwise.
GHCi> pathVertices $ B.difference Winding (square 2) (square 2 # translateX 1)
[[P (V2 (-1.0) 1.0),P (V2 0.0 1.0),P (V2 0.0 (-1.0)),P (V2 (-1.0) (-1.0))]]
我想从一个形状中减去另一个形状,然后将生成的形状与另一个形状组合。在我的例子中,一个正方形被剪成两半,被剪掉的版本将向右延伸半个圆圈。
因此,我通过 difference
从另一个正方形中减去一个正方形,并假设重叠区域只会合并,并用整个圆制作一个 union
。
我在考虑 ({1,2,3,4} / {3,4}) U {2,3}
等于 {1,2,3}
的集合操作,但在我的实现中它等于 {1,3}
:
import Diagrams.Backend.SVG.CmdLine
{-# LANGUAGE NoMonomorphismRestriction #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeFamilies #-}
import Diagrams.Prelude
import qualified Diagrams.TwoD.Path.Boolean as B
main = mainWith (combination # fc red # bgFrame 0.1 white)
where
combination :: QDiagram B V2 Double Any
combination = strokePath plusCircle
shorterSquare = B.difference Winding (square 2) (square 2 # translateX 1)
plusCircle = B.union Winding (circle 1 <> shorterSquare)
但我明白了:
我不是图表方面的专家,但看起来您是在组合笔划路径而不是它们所代表的形状。 Fill Rules 关于缠绕填充规则如何针对自身重叠的笔划路径表现,有一些有趣的事情要说,这似乎与解释为什么会得到这样的结果有关。
相反,我建议使用 Composing diagrams 中的技术,例如 atop
,来组合完整的形状。
B.difference
的这种特殊用法反转了 shorterSquare
路径的方向,因此您需要 re-reverse it:
shorterSquare = B.difference Winding (square 2) (square 2 # translateX 1)
# reversePath
因为这很微妙,所以花点时间描述一下我是如何诊断它的是值得的。首先,这种古怪的填充规则感觉很像由路径(或面等)方向引起的那种问题。其次,将 shorterSquare
重新定义为...
shorterSquare = square 2 # scaleX 0.5 # translateX 0.5
... 给出了预期的结果。这意味着问题与 B.difference
和 shorterSquare
的定义有关,而不是 B.union
。可以通过pathVertices
:
GHCi> -- Counterclockwise.
GHCi> pathVertices $ square 2 # scaleX 0.5 # translateX 0.5
[[P (V2 1.0 (-1.0)),P (V2 0.9999999999999999 1.0),P (V2 (-1.1102230246251565e-16) 1.0),P (V2 (-2.220446049250313e-16) (-1.0))]]
GHCi> -- Clockwise.
GHCi> pathVertices $ B.difference Winding (square 2) (square 2 # translateX 1)
[[P (V2 (-1.0) 1.0),P (V2 0.0 1.0),P (V2 0.0 (-1.0)),P (V2 (-1.0) (-1.0))]]