我可以为折线绘制缩略图吗?
Can I draw a thumbnail for a polyline?
如果我有一个保存为 string
、
的多段线路径
来自 google 地图 sdk:path.encodedPath()
或者我有一系列的latlng
s点,
我可以为该路径绘制缩略图吗?
我不想在 mapView
上绘制它,我想知道我是否可以在 imageView
或类似的任何其他视图中绘制它。
我创建了 swift 3 代码,您只需将其复制并粘贴到 playground 中即可立即查看结果
代码在这里:
import UIKit
import PlaygroundSupport
var str = "Hello, playground"
//All you need is to create a path with that points and create image or layer with that path
//To perpare for this let make some extensions with helper code
//Extension for UIBeziePath to easily create it from points
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)
}
}
}
}
//to create image from path you can use this class function
extension UIImage
{
class func imageFrom(path:UIBezierPath,lineColor:UIColor,fillColor:UIColor)->UIImage
{
//create context to draw in use path bounds as context size. assume that path is inzide of rect with start corener at 0,0 coordinate
UIGraphicsBeginImageContextWithOptions(path.bounds.size, false, 0)
print("path bounds \(path.bounds) lineWidth:\(path.lineWidth)")
let context = UIGraphicsGetCurrentContext()
//set fill color
context?.setFillColor(fillColor.cgColor)
//set line coolor
context?.setStrokeColor(lineColor.cgColor)
context?.setLineWidth(path.lineWidth)
//draw a path
context?.addPath(path.cgPath)
context?.drawPath(using: .fillStroke)
//get image from context
let image = UIGraphicsGetImageFromCurrentImageContext()!
//finish context
UIGraphicsEndImageContext()
return image
}
}
//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
}
}
//how to use:
//1. assume you recieved points
let points:[CGPoint] = [CGPoint(x: 0, y: 0),CGPoint(x: 150, y: 50),CGPoint(x: 75, y:140),CGPoint(x: 0, y: 80)]
//2. create path
let path = UIBezierPath(points: points)
//3. you can specify path line width
path.lineWidth = 2
//4. as a joinstyle too
path.lineJoinStyle = .round
//5. a)now you can create image from path with helper function
let image = UIImage.imageFrom(path: path, lineColor: UIColor.purple, fillColor: UIColor.red)
print(image)
//and set it to imageView
let imageView = UIImageView(image: image)
imageView.frame.origin = CGPoint(x: 200, y: 200)
imageView.backgroundColor = UIColor.green
//5. Maybe you will need to specify content mode for imageView
imageView.contentMode = .scaleAspectFit
//5 b.) Or you can create a Layer. Add add it to someone's layer layter
//if you need, you can apply transform to path - this is special way to
//adjust scale, rotation an lots of other cool stuff on layers, paths.
//Create special struct which descripbes transformation
//Identity is a special case which does not make any transformations at all
var transform = CGAffineTransform.identity
//scale it by 0.5 for x and 0.5 for y. if you need to increse scale by
//100 times, just pass 100 for x and y arguments
transform = transform.scaledBy(x: 0.5, y: 0.5)
//no apply transform to path.
path.apply(transform)
let layer = CAShapeLayer(path: path, lineColor: UIColor.blue, fillColor: UIColor.brown)
//6. let see results
let container = UIView(frame: CGRect(x: 0, y: 0, width: 400, height: 400))
container.backgroundColor = UIColor.white
//for imageView
container.addSubview(imageView)
//for CAShapeLayer
container.layer.addSublayer(layer)
//for playGround you can set this to see result there
//Do not forget to select from menu
//View -> Assistant Editor-> Show Assistance Editor
PlaygroundPage.current.liveView = container
PlaygroundPage.current.needsIndefiniteExecution = true
//我还必须提到 CAShapeLayer 解决方案占用的内存更少,这对于真正的大图像至关重要
//但是 UIImage 更容易使用
棕色图是路径缩放0.5的层,红色是imageView
如果你有一系列经纬度,你可以知道最大和最小经纬度,假设它们是:maxLat, maxLong, minLat, minLong
。请注意,两个最大值不必属于同一坐标。两个最小值相同。
你可以用它来得到一个矩形:
let rect = CGRect(x: minLng , y: minLat, width: (maxLng - minLng), height: (maxLat - minLat))
现在,所有其他经纬度都是此矩形中的点。可以通过
得到每个coordinate
对应的CGPoint值
let point = CGPoint(x: maxLng - coordinate.longitude, y: maxLat - coordinate.latitude)
使用此矩形和您创建的一系列 CGPoints,您可以在视图(如您在答案中提到的图像视图)上绘制路径(通过从第一个点开始并向其添加所有后续点)或创建图形上下文只是为了创建路径的缩略图并将其另存为图像。
如果您不熟悉在 CGContexts 中绘图,请参阅 drawing and printing guide。
但是,如果您打算将这个相当于路径的缩略图放置在图像上,真正的挑战是您如何知道位置。一个简单的技巧是获取您要在其上叠加路径缩略图的图像的地图等效最小最大坐标,并使用这些最小最大值来创建路径和上下文。然后您可以将缩略图居中放置在图像上。
你的项目听起来很有趣。祝你好运。
如果我有一个保存为 string
、
来自 google 地图 sdk:path.encodedPath()
或者我有一系列的latlng
s点,
我可以为该路径绘制缩略图吗?
我不想在 mapView
上绘制它,我想知道我是否可以在 imageView
或类似的任何其他视图中绘制它。
我创建了 swift 3 代码,您只需将其复制并粘贴到 playground 中即可立即查看结果
代码在这里:
import UIKit
import PlaygroundSupport
var str = "Hello, playground"
//All you need is to create a path with that points and create image or layer with that path
//To perpare for this let make some extensions with helper code
//Extension for UIBeziePath to easily create it from points
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)
}
}
}
}
//to create image from path you can use this class function
extension UIImage
{
class func imageFrom(path:UIBezierPath,lineColor:UIColor,fillColor:UIColor)->UIImage
{
//create context to draw in use path bounds as context size. assume that path is inzide of rect with start corener at 0,0 coordinate
UIGraphicsBeginImageContextWithOptions(path.bounds.size, false, 0)
print("path bounds \(path.bounds) lineWidth:\(path.lineWidth)")
let context = UIGraphicsGetCurrentContext()
//set fill color
context?.setFillColor(fillColor.cgColor)
//set line coolor
context?.setStrokeColor(lineColor.cgColor)
context?.setLineWidth(path.lineWidth)
//draw a path
context?.addPath(path.cgPath)
context?.drawPath(using: .fillStroke)
//get image from context
let image = UIGraphicsGetImageFromCurrentImageContext()!
//finish context
UIGraphicsEndImageContext()
return image
}
}
//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
}
}
//how to use:
//1. assume you recieved points
let points:[CGPoint] = [CGPoint(x: 0, y: 0),CGPoint(x: 150, y: 50),CGPoint(x: 75, y:140),CGPoint(x: 0, y: 80)]
//2. create path
let path = UIBezierPath(points: points)
//3. you can specify path line width
path.lineWidth = 2
//4. as a joinstyle too
path.lineJoinStyle = .round
//5. a)now you can create image from path with helper function
let image = UIImage.imageFrom(path: path, lineColor: UIColor.purple, fillColor: UIColor.red)
print(image)
//and set it to imageView
let imageView = UIImageView(image: image)
imageView.frame.origin = CGPoint(x: 200, y: 200)
imageView.backgroundColor = UIColor.green
//5. Maybe you will need to specify content mode for imageView
imageView.contentMode = .scaleAspectFit
//5 b.) Or you can create a Layer. Add add it to someone's layer layter
//if you need, you can apply transform to path - this is special way to
//adjust scale, rotation an lots of other cool stuff on layers, paths.
//Create special struct which descripbes transformation
//Identity is a special case which does not make any transformations at all
var transform = CGAffineTransform.identity
//scale it by 0.5 for x and 0.5 for y. if you need to increse scale by
//100 times, just pass 100 for x and y arguments
transform = transform.scaledBy(x: 0.5, y: 0.5)
//no apply transform to path.
path.apply(transform)
let layer = CAShapeLayer(path: path, lineColor: UIColor.blue, fillColor: UIColor.brown)
//6. let see results
let container = UIView(frame: CGRect(x: 0, y: 0, width: 400, height: 400))
container.backgroundColor = UIColor.white
//for imageView
container.addSubview(imageView)
//for CAShapeLayer
container.layer.addSublayer(layer)
//for playGround you can set this to see result there
//Do not forget to select from menu
//View -> Assistant Editor-> Show Assistance Editor
PlaygroundPage.current.liveView = container
PlaygroundPage.current.needsIndefiniteExecution = true
//我还必须提到 CAShapeLayer 解决方案占用的内存更少,这对于真正的大图像至关重要 //但是 UIImage 更容易使用
棕色图是路径缩放0.5的层,红色是imageView
如果你有一系列经纬度,你可以知道最大和最小经纬度,假设它们是:maxLat, maxLong, minLat, minLong
。请注意,两个最大值不必属于同一坐标。两个最小值相同。
你可以用它来得到一个矩形:
let rect = CGRect(x: minLng , y: minLat, width: (maxLng - minLng), height: (maxLat - minLat))
现在,所有其他经纬度都是此矩形中的点。可以通过
得到每个coordinate
对应的CGPoint值
let point = CGPoint(x: maxLng - coordinate.longitude, y: maxLat - coordinate.latitude)
使用此矩形和您创建的一系列 CGPoints,您可以在视图(如您在答案中提到的图像视图)上绘制路径(通过从第一个点开始并向其添加所有后续点)或创建图形上下文只是为了创建路径的缩略图并将其另存为图像。
如果您不熟悉在 CGContexts 中绘图,请参阅 drawing and printing guide。
但是,如果您打算将这个相当于路径的缩略图放置在图像上,真正的挑战是您如何知道位置。一个简单的技巧是获取您要在其上叠加路径缩略图的图像的地图等效最小最大坐标,并使用这些最小最大值来创建路径和上下文。然后您可以将缩略图居中放置在图像上。
你的项目听起来很有趣。祝你好运。