Итак, у меня есть простой фрагмент кода, в котором я пытаюсь нарисовать линию переменной ширины с помощью UIBezierPath. Из коробки у нас нет такой возможности. Мы можем использовать только stati c ширину линии для каждого сегмента. Я нашел хороший учебник, в котором объясняется, как мы можем сделать это по-другому. Поэтому я изменил этот код и застрял в ситуации, когда моя изогнутая линия перекрывается.
Я знаю, почему это произошло, потому что у нас нет дополнительных точек, потому что наш угол может быть более плавным.
Я добавил красные кружки, чтобы увидеть, где мы получили точки касания из осыпи.
И вопрос. Есть идеи, как я могу "нормализовать" эти углы, добавив дополнительные точки или убрав лишние точки?
Пример кода:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .lightGray
}
var pts = Array(repeating: CGPoint.zero, count: 5)
var ctr = 0
var pointsBuffer = Array(repeating: CGPoint.zero, count: 100)
var dispatchQue: DispatchQueue!
var bufIdx = 0
var isFirstTouchPoint: Bool = false
var lastSegmentOfPrev: LineSegment!
struct LineSegment {
var firstPoint: CGPoint = .zero
var secondPoint: CGPoint = .zero
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let point = touches.first?.location(in: view) else {return}
ctr = 0
bufIdx = 0;
pts[0] = point
isFirstTouchPoint = true
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let point = touches.first?.location(in: view) else {return}
let circleLayer = CAShapeLayer()
let radius: CGFloat = 2.0
circleLayer.path = UIBezierPath(roundedRect: CGRect(x: point.x, y: point.y, width: 1.0 * radius, height: 1.0 * radius), cornerRadius: radius).cgPath
circleLayer.fillColor = UIColor.red.cgColor
self.view.layer.addSublayer(circleLayer)
ctr += 1
pts[ctr] = point
if ctr == 4 {
pts[3] = CGPoint(x: (pts[2].x + pts[4].x)/2.0,
y: (pts[2].y + pts[4].y)/2.0)
for i in 0..<4 {
pointsBuffer[bufIdx + i] = pts[i]
}
bufIdx += 4
dispatchQue = DispatchQueue(label: "some.queue")
dispatchQue.async {
let offsetPath = UIBezierPath()
if self.bufIdx == 0 {
return
}
var ls = [LineSegment](repeating: LineSegment(), count: 4)
for i in stride(from: 0, to: self.bufIdx, by: 4) {
if self.isFirstTouchPoint {
ls[0] = LineSegment(firstPoint: self.pointsBuffer[0], secondPoint: self.pointsBuffer[0])
offsetPath.move(to: ls[0].firstPoint)
self.isFirstTouchPoint = false
} else {
ls[0] = self.lastSegmentOfPrev
}
ls[1] = self.lineSegmentPerpendicular(to: LineSegment(firstPoint: self.pointsBuffer[i],
secondPoint: self.pointsBuffer[i + 1]), ofRelativeLength: 5)
ls[2] = self.lineSegmentPerpendicular(to: LineSegment(firstPoint: self.pointsBuffer[i + 1],
secondPoint: self.pointsBuffer[i + 2]), ofRelativeLength: 5)
ls[3] = self.lineSegmentPerpendicular(to: LineSegment(firstPoint: self.pointsBuffer[i + 2],
secondPoint: self.pointsBuffer[i + 3]), ofRelativeLength: 5)
offsetPath.move(to: ls[0].firstPoint)
offsetPath.addCurve(to: ls[3].firstPoint, controlPoint1: ls[1].firstPoint, controlPoint2: ls[2].firstPoint)
offsetPath.addLine(to: ls[3].secondPoint)
offsetPath.addCurve(to: ls[0].secondPoint, controlPoint1: ls[2].secondPoint, controlPoint2: ls[1].secondPoint)
offsetPath.close()
self.lastSegmentOfPrev = ls[3]
}
DispatchQueue.main.async {
self.bufIdx = 0
let newLayer = CAShapeLayer()
newLayer.strokeColor = UIColor.black.cgColor
newLayer.fillColor = UIColor.clear.cgColor
newLayer.path = offsetPath.cgPath
self.view.layer.addSublayer(newLayer)
}
}
pts[0] = pts[3]
pts[1] = pts[4]
ctr = 1
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
}
func lineSegmentPerpendicular(to pp: LineSegment, ofRelativeLength fraction: CGFloat) -> LineSegment {
let x0 = pp.firstPoint.x
let y0 = pp.firstPoint.y
let x1 = pp.secondPoint.x
let y1 = pp.secondPoint.y
var xa: CGFloat
var ya: CGFloat
var xb: CGFloat
var yb: CGFloat
let x0x1 = x1 - x0
let y0y1 = y1 - y0
let ab = sqrt(x0x1 * x0x1 + y0y1 * y0y1)
let la = fraction / ab
let lb = fraction / ab
xa = x1 + la * (y0 - y1)
ya = y1 + la * (x1 - x0)
xb = x1 - lb * (y0 - y1)
yb = y1 - lb * (x1 - x0)
return LineSegment(firstPoint: CGPoint(x: xa, y: ya), secondPoint: CGPoint(x: xb, y: yb))
}
}