Swift CoreGraphics UIBezierPath 无法正确填充内部
Swift CoreGraphics UIBezierPath will not fill interior correctly
我正在尝试绘制国家并用某种颜色填充内部。我的数据源是一个 TopoJSON 文件,简而言之,它由引用弧形数组以创建形状的形状组成。我将其转换为 paths
数组,然后对其进行迭代以绘制国家/地区。正如您在下面的屏幕截图中看到的,我正在绘制国家(阿富汗)轮廓的正确线条。
然而,当我尝试使用 path.fill()
时,我最终得到以下结果。请注意黑线是如何正确的,但颜色随意地从外到内。
代码
var mapRegion = MapRegion()
var path = mapRegion.createPath()
var origin: CGPoint = .zero
geometry.paths
.enumerated()
.forEach { (geoIndex, shape) in
shape
.enumerated()
.forEach { (shapeIndex, coord) in
guard let coordPoint = coord.double else { return }
let values = coordinatesToGraphics(x: coordPoint.x, y: coordPoint.y)
let point = CGPoint(x: values.x, y: values.y)
if origin == .zero {
origin = point
}
// Shape is about to be closed
if shapeIndex != 0 && path.contains(point) {
// Close, save path (2)
path.addLine(to: origin)
// (3) path.close()
mapRegion.savePath()
// Add to map, reset process
canvas.layer.addSublayer(mapRegion)
mapRegions.append(mapRegion)
mapRegion = MapRegion()
path = mapRegion.createPath()
}
else {
if shapeIndex == 0 {
path.move(to: point)
} else {
path.addLine(to: point)
}
}
}
}
我已经尝试过彻底弄乱 usesEvenOddFillRule
(further reading),但什么都没有改变。我发现上面的评论 (1) 有助于解决不应该绘制边界的问题。 (2) 处的函数 savePath()
运行 setStroke()
、stroke()
、setFill()
、fill()
函数。
更新: path.close()
在形状的左下角绘制一条闭合路径的线,而不是它最初开始的左上角画画。该函数关闭 "most recently added subpath",但如何定义子路径?
我不能确定问题是我的逻辑还是某些 CoreGraphics 技巧。我有一系列路径需要拼接在一起并视为一个路径,我相信我正在这样做。我查看了数据点,一个弧的结尾到下一个弧的开头是相同的。我打印了缝合在一起的路径,我基本上 move(to:)
相同的点,所以当我 addLine(to:)
看模拟器给区域着色的方式时没有重复,我首先猜测可能是各个弧线被视为形状,但本例中只有 6 个圆弧,还有几个由内到外的颜色切换。
非常感谢您的帮助!
事实证明,使用 path.move(to:)
在 UIBezierPath()
中创建了一个 子路径 ,填充算法似乎将其视为单独的多路径( 导致发现)。解决方案是删除额外的、不必要的 move(to:)
调用。下面是工作代码和快乐的结果!谢谢!
var mapRegion = MapRegion()
var path = mapRegion.createPath()
path.move(to: .zero)
var pointsDictionary: [String: Bool] = [:]
geometry.paths
.enumerated()
.forEach { (geoIndex, shape) in
shape
.enumerated()
.forEach { (shapeIndex, coord) in
guard let coordPoint = coord.double else { return }
let values = coordinatesToGraphics(x: coordPoint.x, y: coordPoint.y)
let point = CGPoint(x: values.x, y: values.y)
// Move to start
if path.currentPoint == .zero {
path.move(to: point)
}
if shapeIndex != 0 {
// Close shape
if pointsDictionary[point.debugDescription] ?? false {
// Close path, set colors, save
mapRegion.save(path)
regionDrawer.drawPath(of: mapRegion)
// Reset process
canvas.layer.addSublayer(mapRegion)
mapRegions.append(mapRegion)
mapRegion = MapRegion()
path = mapRegion.createPath()
pointsDictionary = [:]
}
// Add to shape
else {
path.addLine(to: point)
}
}
}
}
我正在尝试绘制国家并用某种颜色填充内部。我的数据源是一个 TopoJSON 文件,简而言之,它由引用弧形数组以创建形状的形状组成。我将其转换为 paths
数组,然后对其进行迭代以绘制国家/地区。正如您在下面的屏幕截图中看到的,我正在绘制国家(阿富汗)轮廓的正确线条。
然而,当我尝试使用 path.fill()
时,我最终得到以下结果。请注意黑线是如何正确的,但颜色随意地从外到内。
代码
var mapRegion = MapRegion()
var path = mapRegion.createPath()
var origin: CGPoint = .zero
geometry.paths
.enumerated()
.forEach { (geoIndex, shape) in
shape
.enumerated()
.forEach { (shapeIndex, coord) in
guard let coordPoint = coord.double else { return }
let values = coordinatesToGraphics(x: coordPoint.x, y: coordPoint.y)
let point = CGPoint(x: values.x, y: values.y)
if origin == .zero {
origin = point
}
// Shape is about to be closed
if shapeIndex != 0 && path.contains(point) {
// Close, save path (2)
path.addLine(to: origin)
// (3) path.close()
mapRegion.savePath()
// Add to map, reset process
canvas.layer.addSublayer(mapRegion)
mapRegions.append(mapRegion)
mapRegion = MapRegion()
path = mapRegion.createPath()
}
else {
if shapeIndex == 0 {
path.move(to: point)
} else {
path.addLine(to: point)
}
}
}
}
我已经尝试过彻底弄乱 usesEvenOddFillRule
(further reading),但什么都没有改变。我发现上面的评论 (1) 有助于解决不应该绘制边界的问题。 (2) 处的函数 savePath()
运行 setStroke()
、stroke()
、setFill()
、fill()
函数。
更新: path.close()
在形状的左下角绘制一条闭合路径的线,而不是它最初开始的左上角画画。该函数关闭 "most recently added subpath",但如何定义子路径?
我不能确定问题是我的逻辑还是某些 CoreGraphics 技巧。我有一系列路径需要拼接在一起并视为一个路径,我相信我正在这样做。我查看了数据点,一个弧的结尾到下一个弧的开头是相同的。我打印了缝合在一起的路径,我基本上 move(to:)
相同的点,所以当我 addLine(to:)
看模拟器给区域着色的方式时没有重复,我首先猜测可能是各个弧线被视为形状,但本例中只有 6 个圆弧,还有几个由内到外的颜色切换。
非常感谢您的帮助!
事实证明,使用 path.move(to:)
在 UIBezierPath()
中创建了一个 子路径 ,填充算法似乎将其视为单独的多路径(move(to:)
调用。下面是工作代码和快乐的结果!谢谢!
var mapRegion = MapRegion()
var path = mapRegion.createPath()
path.move(to: .zero)
var pointsDictionary: [String: Bool] = [:]
geometry.paths
.enumerated()
.forEach { (geoIndex, shape) in
shape
.enumerated()
.forEach { (shapeIndex, coord) in
guard let coordPoint = coord.double else { return }
let values = coordinatesToGraphics(x: coordPoint.x, y: coordPoint.y)
let point = CGPoint(x: values.x, y: values.y)
// Move to start
if path.currentPoint == .zero {
path.move(to: point)
}
if shapeIndex != 0 {
// Close shape
if pointsDictionary[point.debugDescription] ?? false {
// Close path, set colors, save
mapRegion.save(path)
regionDrawer.drawPath(of: mapRegion)
// Reset process
canvas.layer.addSublayer(mapRegion)
mapRegions.append(mapRegion)
mapRegion = MapRegion()
path = mapRegion.createPath()
pointsDictionary = [:]
}
// Add to shape
else {
path.addLine(to: point)
}
}
}
}