我目前正在将MKPolyline转换为BezierPath然后转换为CAShapeLayer,然后将该图层作为子图层添加到UIView中。目前正努力确保路径不会超出UIView的范围。我不想掩盖并使路径的一部分消失,而是确保每个点都被调整大小并定位在UIView的中心。
func addPathToView() {
guard let path = createPath(onView: polylineView) else { return }
path.fit(into: polylineView.bounds).moveCenter(to: polylineView.center).fill()
path.lineWidth = 3.0
path.lineJoinStyle = .round
guard let layer = createCAShapeLayer(fromBezierPath: path) else { return }
layer.path = getScaledPath(fromPath: path, layer: layer)
layer.frame = polylineView.bounds
layer.position.x = polylineView.bounds.minX
layer.position.y = polylineView.bounds.minY
polylineView.layer.addSublayer(layer)
}
func createCAShapeLayer( fromBezierPath path: UIBezierPath? ) -> CAShapeLayer? {
guard let path = path else { print("No Path"); return nil }
let pathLayer = CAShapeLayer(path: path, lineColor: UIColor.red, fillColor: UIColor.clear)
return pathLayer
}
func createPath( onView view: UIView? ) -> UIBezierPath? {
guard let polyline = Polyline().createPolyline(forLocations: locations) else { print("No Polyline"); return nil }
guard let points = convertMapPointsToCGPoints(fromPolyline: polyline) else { print("No CGPoints"); return nil }
let path = UIBezierPath(points: points)
return path
}
func convertMapPointsToCGPoints( fromPolyline polyline: MKPolyline? ) -> [CGPoint]? {
guard let polyline = polyline else { print( "No Polyline"); return nil }
let mapPoints = polyline.points()
var points = [CGPoint]()
for point in 0..<polyline.pointCount {
let coordinate = MKCoordinateForMapPoint(mapPoints[point])
points.append(mapView.convert(coordinate, toPointTo: view))
}
return points
}
func getScaledPath( fromPath path: UIBezierPath, layer: CAShapeLayer ) -> CGPath? {
let boundingBox = path.cgPath.boundingBoxOfPath
let boundingBoxAspectRatio = boundingBox.width / boundingBox.height
let viewAspectRatio = polylineView.bounds.size.width / polylineView.bounds.size.height
let scaleFactor: CGFloat
if (boundingBoxAspectRatio > viewAspectRatio) {
// Width is limiting factor
scaleFactor = polylineView.bounds.size.width / boundingBox.width
} else {
// Height is limiting factor
scaleFactor = polylineView.bounds.size.height/boundingBox.height
}
var affineTransorm = CGAffineTransform(scaleX: scaleFactor, y: scaleFactor)
let transformedPath = path.cgPath.copy(using: &affineTransorm)
guard let tPath = transformedPath else { print ("nope"); return nil }
return tPath
}
extension UIBezierPath
{
func moveCenter(to:CGPoint) -> Self{
let bound = self.cgPath.boundingBox
let center = bounds.center
let zeroedTo = CGPoint(x: to.x-bound.origin.x, y: to.y-bound.origin.y)
let vector = center.vector(to: zeroedTo)
offset(to: CGSize(width: vector.dx, height: vector.dy))
return self
}
func offset(to offset:CGSize) -> Self{
let t = CGAffineTransform(translationX: offset.width, y: offset.height)
applyCentered(transform: t)
return self
}
func fit(into:CGRect) -> Self{
let bounds = self.cgPath.boundingBox
let sw = into.size.width/bounds.width
let sh = into.size.height/bounds.height
let factor = min(sw, max(sh, 0.0))
return scale(x: factor, y: factor)
}
func scale(x:CGFloat, y:CGFloat) -> Self{
let scale = CGAffineTransform(scaleX: x, y: y)
applyCentered(transform: scale)
return self
}
func applyCentered(transform: @autoclosure () -> CGAffineTransform ) -> Self{
let bound = self.cgPath.boundingBox
let center = CGPoint(x: bound.midX, y: bound.midY)
var xform = CGAffineTransform.identity
xform = xform.concatenating(CGAffineTransform(translationX: -center.x, y: -center.y))
xform = xform.concatenating(transform())
xform = xform.concatenating( CGAffineTransform(translationX: center.x, y: center.y))
apply(xform)
return self
}
}
extension UIBezierPath
{
convenience init(points:[CGPoint])
{
self.init()
//connect every points by line.
//the first point is start point
for (index,aPoint) in points.enumerated()
{
if index == 0 {
self.move(to: aPoint)
}
else {
self.addLine(to: aPoint)
}
}
}
}
//2. To create layer use this extension
extension CAShapeLayer
{
convenience init(path:UIBezierPath, lineColor:UIColor, fillColor:UIColor)
{
self.init()
self.path = path.cgPath
self.strokeColor = lineColor.cgColor
self.fillColor = fillColor.cgColor
self.lineWidth = path.lineWidth
self.opacity = 1
self.frame = path.bounds
}
}
答案 0 :(得分:1)
这是我用来扩展UIBezierPath的方法: 我将使用原始(您的MKPolyline大小,我的原始数据)和final(接收视图大小,它将如何显示)。
1.计算原始振幅(对我而言,它只是高度,但对你来说也是宽度)
2.编写一个函数将原始数据缩放到新的X和Y轴刻度(对于点位置,它看起来像这样):
func scaleValueToYAxis(_ value: Double) -> CGFloat {
return finalHeight - CGFloat(value) / originalYAmplitude) * finalHeight
}
func scaleValueToXAxis(_ value: Double) -> CGFloat {
return finalWidth - CGFloat(value) / originalXAmplitude) * finalWidth
}
3.开始绘图
let path = UIBezierPath()
let path.move(to: CGPoint(x: yourOriginForDrawing, y: yourOriginForDrawing)) // final scale position
path.addLine(to: CGPoint(x: nextXPoint, y: nextYPoint)) // this is not relevant for you as you don't draw point by point
// what is important here is the fact that you take your original
//data X and Y and make them go though your scale functions
let layer = CAShapeLayer()
let layer.path = path.cgPath
let layer.lineWidth = 1.0
let layer.strokeColor = UIColor.black
yourView.layer.addSublayer(layer)
正如您所看到的,关于从MKPolyline绘图的逻辑仍有待完成。重要的是,当你&#34;复制&#34;折线你move(to: )
正确的做法。这就是为什么我认为你没有正确的抵消
答案 1 :(得分:0)
可以使用UIBezierPath
像CGRect
,CGPoint
或'CGSize'那样缩放CGAffineTransform
。
?
// calculate the scale
//
let scaleWidth = toSize.width / fromSize.width
let scaleHeight = toSize.height / fromSize.height
// re-scale the path
//
path.apply(CGAffineTransform(scaleX: scaleWidth, y: scaleHeight))