我有一个应用程序,您可以在其中使用点进行绘制,需要下面提供的代码,以便当一条线(已绘制)与当前线相交时,当前线被删除。
当我尝试在
DragGesture().onChanged
中执行此操作时,CPU 过载,并且线条绘制有延迟。
如何解决这个问题?
import SwiftUI
import CoreGraphics
struct Drawing1 {
var points1: [CGPoint] = [CGPoint]()
}
struct Drawing2 {
var points2: [CGPoint] = [CGPoint]()
}
struct ContentView: View {
@State private var currentDrawing1: Drawing1 = Drawing1()
@State private var drawings1: [Drawing1] = [Drawing1]()
@State private var currentDrawing2: Drawing2 = Drawing2()
@State private var drawings2: [Drawing2] = [Drawing2]()
var body: some View {
GeometryReader { geo in
Path { path1 in
for drawings1 in self.drawings1 {
self.add1(drawings1: drawings1, toPath1: &path1)
}
self.add1(drawings1: self.currentDrawing1, toPath1: &path1)
}
.stroke(Color.orange, style: StrokeStyle(lineWidth: 10, lineCap: .round, lineJoin: .round))
Path { path2 in
for drawings2 in self.drawings2 {
self.add2(drawings2: drawings2, toPath2: &path2)
}
self.add2(drawings2: self.currentDrawing2, toPath2: &path2)
}
.stroke(Color.black, style: StrokeStyle(lineWidth: 10, lineCap: .round, lineJoin: .round))
Image("example1")
.resizable( resizingMode: .stretch)
.scaledToFit()
.clipped()
.position(x:200, y:200)
.frame(width: 100, height:100)
.gesture(
DragGesture()
.onChanged({ value1 in
let currentPoint1 = value1.location
self.currentDrawing1.points1.append(currentPoint1)
} )
.onEnded({ value1 in
self.drawings1.append(self.currentDrawing1)
self.currentDrawing1 = Drawing1()
}
)
)
Image("example2")
.resizable( resizingMode: .stretch)
.scaledToFit()
.clipped()
.position(x:100, y:100)
.frame(width: 100, height:100)
.gesture(
DragGesture()
.onChanged({ value2 in
let currentPoint2 = value2.location
self.currentDrawing2.points2.append(currentPoint2)
if drawings1.count > 0
{
let points2 = currentDrawing2.points2
let points1 = drawings1[0].points1
if points2.count > 0
{
for i in 0..<points2.count-1 {
let current2 = points2[i]
let next2 = points2[i+1]
for i in 0..<points1.count-1 {
let current = points1[i]
let next = points1[i+1]
let delta1x = next.x - current.x
let delta1y = next.y - current.y
let delta2x = next2.x - current2.x
let delta2y = next2.y - current2.y
// create a 2D matrix from our vectors and calculate the determinant
let determinant = delta1x * delta2y - delta2x * delta1y
if abs(determinant) < 0.0001 {
// if the determinant is effectively zero then the lines are parallel/colinear
//return nil
}
// if the coefficients both lie between 0 and 1 then we have an intersection
let ab = ((current.y - current2.y) * delta2x - (current.x - current2.x) * delta2y) / determinant
if ab > 0 && ab < 1 {
let cd = ((current.y - current2.y) * delta1x - (current.x - current2.x) * delta1y) / determinant
if cd > 0 && cd < 1 {
// lines cross
self.currentDrawing2.points2.removeAll()
}
}
}
}
}
}
}
)
.onEnded( { value2 in
self.drawings2.append(self.currentDrawing2)
self.currentDrawing2 = Drawing2()
})
)
}
}
private func add1(drawings1: Drawing1, toPath1 path1: inout Path) {
let points1 = drawings1.points1
if points1.count > 1 {
for i in 0..<points1.count-1 {
let current = points1[i]
let next = points1[i+1]
path1.move(to: current)
path1.addLine(to: next)
}
}
}
private func add2(drawings2: Drawing2, toPath2 path2: inout Path) {
let points2 = drawings2.points2
if points2.count > 1 {
for i in 0..<points2.count-1 {
let current = points2[i]
let next = points2[i+1]
path2.move(to: current)
path2.addLine(to: next)
}
}
}
}
我尝试在
.onEnded
中实现这一点。这里一切正常,但我需要它实时工作。
lineIntersection(_:eoFill:)
检测相交路径
例如,让我们创建两个路径:
var pth1 = Path()
var pth2 = Path()
pth1.move(to: .init(x: 200.0, y: 300.0))
pth1.addLine(to: .init(x: 150.0, y: 350.0))
pth1.addLine(to: .init(x: 120.0, y: 320.0))
pth1.addLine(to: .init(x: 80.0, y: 250.0))
pth2.move(to: .init(x: 180.0, y: 200.0))
pth2.addLine(to: .init(x: 180.0, y: 240.0))
pth2.addLine(to: .init(x: 140.0, y: 260.0))
pth2.addLine(to: .init(x: 160.0, y: 300.0))
如果我们画它们,它看起来像这样:
所以,让我们检查一下:
let iPath = pth1.lineIntersection(pth2)
// we need to check the .cgPath
if iPath.cgPath.isEmpty {
print("Paths do NOT Intersect")
} else {
print("Paths Intersect!")
}
调试控制台输出将是:
Paths do NOT Intersect
如果我们向
pth2
添加另一条线段:
pth2.addLine(to: .init(x: 220.0, y: 340.0))
现在看起来像这样:
输出将是:
Paths Intersect!
因此,我们不要在拖动时跟踪所有点,而是更新一个
Path
:
struct Drawing {
var thePath: Path = Path()
}
并且在
.onChanged
中,我们可以使用 .move(to:)
和 .addLine(to:)
,这样我们就不会在每个周期都重新构建路径。
我们还定义另外两个属性:
struct Drawing {
var thePath: Path = Path()
var theColor: Color = Color.black
var canDraw: Bool = true
}
目前尚不清楚您要如何处理“绘图”数组,因此我们将稍微简化一下:
@State private var currentDrawing1: Drawing = Drawing(theColor: Color.red)
@State private var currentDrawing2: Drawing = Drawing(theColor: Color.blue)
这是您可以检查和尝试的完整视图结构(应该有足够的注释):
struct DrawIntersectView: View {
@State private var currentDrawing1: Drawing = Drawing(theColor: Color.red)
@State private var currentDrawing2: Drawing = Drawing(theColor: Color.blue)
var body: some View {
GeometryReader { geo in
currentDrawing1.thePath
.stroke(currentDrawing1.theColor, style: StrokeStyle(lineWidth: 10, lineCap: .round, lineJoin: .round))
currentDrawing2.thePath
.stroke(currentDrawing2.theColor, style: StrokeStyle(lineWidth: 10, lineCap: .round, lineJoin: .round))
Image("example1")
.resizable( resizingMode: .stretch)
.scaledToFit()
.clipped()
.position(x:200, y:200)
.frame(width: 100, height:100)
.opacity(0.5) // so we can see the line start
.gesture(
DragGesture()
.onChanged({ value in
let currentPoint = value.location
// if the path has no points yet, move to
// else, addLine to
if self.currentDrawing1.thePath.isEmpty {
self.currentDrawing1.thePath.move(to: currentPoint)
} else {
self.currentDrawing1.thePath.addLine(to: currentPoint)
}
})
.onEnded({ value in
})
)
Image("example2")
.resizable( resizingMode: .stretch)
.scaledToFit()
.clipped()
.position(x:100, y:100)
.frame(width: 100, height:100)
.opacity(0.5) // so we can see the line start
.gesture(
DragGesture()
.onChanged({ value in
// if we haven't yet drawn from currentDrawing2
// just return
if self.currentDrawing1.thePath.isEmpty {
return
}
// if we've crossed the first line, we don't want to
// draw until the user has lifted the touch (ended the current drag)
if !self.currentDrawing2.canDraw {
return
}
let currentPoint = value.location
// if the path has no points yet, move to
// else, addLine to
if self.currentDrawing2.thePath.isEmpty {
self.currentDrawing2.thePath.move(to: currentPoint)
} else {
self.currentDrawing2.thePath.addLine(to: currentPoint)
}
// get lineIntersection of the paths from drawing 1 and drawing 2
let t = self.currentDrawing1.thePath.lineIntersection(self.currentDrawing2.thePath)
if !t.cgPath.isEmpty {
print("intersects")
self.currentDrawing2.canDraw = false
self.currentDrawing2.thePath = Path()
}
})
.onEnded({ value in
// allow drawing again
self.currentDrawing2.canDraw = true
})
)
}
}
}
值得注意:因为您使用的路径线宽为 10...如果我们像这样绘制线条/路径:
它们确实不相交!那是因为实际的线路路径是: